hl-core 0.0.10-beta.7 → 0.0.10-beta.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +0 -2
  2. package/api/base.api.ts +425 -134
  3. package/api/interceptors.ts +162 -62
  4. package/components/Dialog/Dialog.vue +5 -1
  5. package/components/Dialog/DigitalDocumentsDialog.vue +129 -0
  6. package/components/Dialog/FamilyDialog.vue +15 -4
  7. package/components/Form/DigitalDocument.vue +52 -0
  8. package/components/Form/FormSource.vue +30 -0
  9. package/components/Form/ManagerAttachment.vue +85 -11
  10. package/components/Form/ProductConditionsBlock.vue +12 -6
  11. package/components/Input/Datepicker.vue +5 -0
  12. package/components/Input/FileInput.vue +1 -1
  13. package/components/Input/FormInput.vue +7 -0
  14. package/components/Input/OtpInput.vue +25 -0
  15. package/components/Input/RoundedInput.vue +2 -0
  16. package/components/Input/RoundedSelect.vue +2 -0
  17. package/components/Input/TextAreaField.vue +71 -0
  18. package/components/Input/TextHint.vue +13 -0
  19. package/components/Layout/SettingsPanel.vue +2 -1
  20. package/components/Menu/MenuNav.vue +2 -1
  21. package/components/Pages/Anketa.vue +207 -176
  22. package/components/Pages/Auth.vue +10 -3
  23. package/components/Pages/ContragentForm.vue +24 -18
  24. package/components/Pages/Documents.vue +488 -66
  25. package/components/Pages/MemberForm.vue +1009 -268
  26. package/components/Pages/ProductConditions.vue +1424 -273
  27. package/components/Panel/PanelHandler.vue +329 -126
  28. package/components/Utilities/Chip.vue +1 -1
  29. package/components/Utilities/JsonViewer.vue +1 -2
  30. package/composables/classes.ts +136 -20
  31. package/composables/constants.ts +168 -1
  32. package/composables/index.ts +467 -9
  33. package/composables/styles.ts +8 -24
  34. package/configs/i18n.ts +2 -0
  35. package/configs/pwa.ts +1 -7
  36. package/layouts/clear.vue +1 -1
  37. package/layouts/default.vue +2 -2
  38. package/layouts/full.vue +1 -1
  39. package/locales/kz.json +1239 -0
  40. package/locales/ru.json +133 -21
  41. package/nuxt.config.ts +8 -6
  42. package/package.json +14 -13
  43. package/plugins/head.ts +7 -1
  44. package/plugins/helperFunctionsPlugins.ts +1 -0
  45. package/store/data.store.ts +1080 -552
  46. package/store/member.store.ts +19 -8
  47. package/store/rules.ts +75 -8
  48. package/types/enum.ts +52 -2
  49. package/types/index.ts +143 -6
@@ -6,6 +6,67 @@
6
6
  <base-btn v-if="underDocumentsList && underDocumentsList.length" :loading="documentLoading" text="Загрузить" size="sm" class="mt-3" @click="uploadUnderFiles" />
7
7
  </base-animation>
8
8
  </base-form-section>
9
+ <section class="w-full px-[10px] pt-[14px]" v-if="$dataStore.isPension && formStore.hasRepresentative">
10
+ <base-content-block :class="[$styles.textSimple]">
11
+ <div :class="[$styles.whiteBg, $styles.rounded]" class="p-2 h-12 flex items-center relative">
12
+ <span class="ml-2">{{ $dataStore.t('policyholdersRepresentative.informationDoc') }}</span>
13
+ <i
14
+ class="transition-all cursor-pointer mdi mdi-tray-arrow-down pl-2 mr-3 border-l-[1px] text-xl absolute right-0"
15
+ :class="[$styles.greenTextHover]"
16
+ @click="$dataStore.generatePDFDocument('All_Spokesman', '24', 'pdf')"
17
+ ></i>
18
+ </div>
19
+ </base-content-block>
20
+ </section>
21
+ <section
22
+ v-if="$dataStore.isPension && (showContract || formStore.applicationData.statusCode === 'PreparationDossierForm')"
23
+ class="w-full px-[10px] pt-[14px] flex flex-col gap-2"
24
+ >
25
+ <base-content-block v-if="showContract" :class="[$styles.textSimple]">
26
+ <h5 class="text-center font-medium mb-4">{{ $dataStore.t('labels.statements') }}</h5>
27
+ <div :class="[$styles.whiteBg, $styles.rounded]" class="p-2 h-12 flex items-center relative">
28
+ <span class="ml-2">Заявления на {{ processCode === 19 || processCode === 25 ? 'страхование' : 'возврат' }}</span>
29
+ <i
30
+ class="transition-all cursor-pointer mdi mdi-tray-arrow-down pl-2 mr-3 border-l-[1px] text-xl absolute right-0"
31
+ :class="[$styles.greenTextHover]"
32
+ @click="$dataStore.generatePDFDocument(processCode === 19 ? 'PA_Statement' : processCode === 25 ? 'PAJ_Statement' : 'PA_RefundStatement', '37')"
33
+ ></i>
34
+ </div>
35
+ </base-content-block>
36
+ <base-content-block v-if="showContract" :class="[$styles.textSimple]">
37
+ <h5 class="text-center font-medium mb-4">{{ $dataStore.t('labels.contract') }}</h5>
38
+ <div :class="[$styles.whiteBg, $styles.rounded]" class="p-2 h-12 flex items-center relative">
39
+ <span class="ml-2">Договор {{ processCode === 19 || processCode === 25 ? 'страхования' : 'возврата' }}</span>
40
+ <i
41
+ class="transition-all cursor-pointer mdi mdi-tray-arrow-down pl-2 mr-3 border-l-[1px] text-xl absolute right-0"
42
+ :class="[$styles.greenTextHover]"
43
+ @click="$dataStore.generatePDFDocument(processCode === 19 ? 'PA_Contract' : processCode === 25 ? 'PAJ_Contract' : 'PA_RefundAgreement', '38')"
44
+ ></i>
45
+ </div>
46
+ </base-content-block>
47
+ <base-content-block :class="[$styles.textSimple]" v-if="formStore.applicationData.statusCode !== 'StartForm' && showContract">
48
+ <h5 class="text-center font-medium mb-4">{{ $dataStore.t('pension.complianceFinMonitoring') }}</h5>
49
+ <div :class="[$styles.whiteBg, $styles.rounded]" class="p-2 h-12 flex items-center relative">
50
+ <span class="ml-2">{{ $dataStore.t('pension.complianceFinMonitoring') }}</span>
51
+ <i
52
+ class="transition-all cursor-pointer mdi mdi-tray-arrow-down pl-2 mr-3 border-l-[1px] text-xl absolute right-0"
53
+ :class="[$styles.greenTextHover]"
54
+ @click="$dataStore.generatePDFDocument('Compliance_FinMonitoring', '39')"
55
+ ></i>
56
+ </div>
57
+ </base-content-block>
58
+ <base-content-block :class="[$styles.textSimple]" v-if="formStore.applicationData.statusCode === 'PreparationDossierForm'">
59
+ <h5 class="text-center font-medium mb-4">{{ $dataStore.t('pension.dossierPA') }}</h5>
60
+ <div :class="[$styles.whiteBg, $styles.rounded]" class="p-2 h-12 flex items-center relative">
61
+ <span class="ml-2">{{ $dataStore.t('pension.dossierPA') }}</span>
62
+ <i
63
+ class="transition-all cursor-pointer mdi mdi-tray-arrow-down pl-2 mr-3 border-l-[1px] text-xl absolute right-0"
64
+ :class="[$styles.greenTextHover]"
65
+ @click="$dataStore.generatePDFDocument('PA_Dossier', '40', 'doc')"
66
+ ></i>
67
+ </div>
68
+ </base-content-block>
69
+ </section>
9
70
  <section class="w-full px-[10px] pt-[14px] flex flex-col gap-2" v-if="formStore.signedDocumentList && formStore.signedDocumentList.length">
10
71
  <base-content-block
11
72
  v-if="$dataStore.isInitiator() && !$dataStore.isPension && $dataStore.controls.hasChooseSign && formStore.applicationData.statusCode === 'ContractSignedFrom'"
@@ -17,7 +78,7 @@
17
78
  <base-form-input v-model="formStore.contractDate" :label="$dataStore.t('form.date')" :readonly="true" append-inner-icon="mdi mdi-calendar-blank-outline" />
18
79
  <base-file-input :readonly="isDisabled" @input.prevent="onFileChange($event)" />
19
80
  </base-content-block>
20
- <base-content-block v-for="document of formStore.signedDocumentList" :key="document.id" :class="[$styles.textSimple]">
81
+ <base-content-block v-for="document of documentListFiltered" :key="document.id" :class="[$styles.textSimple]">
21
82
  <h5 class="text-center font-medium mb-4">
22
83
  {{ document.fileTypeName }}
23
84
  </h5>
@@ -31,6 +92,123 @@
31
92
  </div>
32
93
  </base-content-block>
33
94
  </section>
95
+ <section class="w-full px-[10px] pt-[14px]" v-if="$dataStore.isPension && formStore.hasRepresentative">
96
+ <base-form-section
97
+ v-if="!formStore.signedDocumentList.find(i => i.fileTypeCode === '16')"
98
+ :title="$dataStore.t('policyholdersRepresentative.powerOfAttorneyDoc')"
99
+ class="mt-[14px] d-flex"
100
+ >
101
+ <base-file-input :loading="$dataStore.isLoading" @input="uploadAdditionalFile($event, '16')" />
102
+ </base-form-section>
103
+ <base-form-section
104
+ v-if="!formStore.signedDocumentList.find(i => i.fileTypeCode === '24')"
105
+ :title="$dataStore.t('policyholdersRepresentative.informationDoc')"
106
+ class="mt-[14px] d-flex"
107
+ >
108
+ <base-file-input :loading="$dataStore.isLoading" @input="uploadAdditionalFile($event, '24')" />
109
+ </base-form-section>
110
+ </section>
111
+ <section v-if="requiredSign">
112
+ <div v-for="(member, index) in jointMembers.filter(i => memberHasDocumentsToSign(i.iin))" :key="index">
113
+ <base-form-section :title="`${member.firstName} ${member.lastName}`" class="mx-[10px] mt-[14px] d-flex">
114
+ <base-file-input
115
+ v-if="
116
+ !formStore.signedDocumentList.find(i => i.fileTypeCode === '10' && i.iin === String(member.iin).replaceAll('-', '')) &&
117
+ formStore.requiredDocuments.some(i => i.code === '10' && i.iin === String(member.iin).replaceAll('-', ''))
118
+ "
119
+ :label="$dataStore.t('form.bankStatement')"
120
+ :loading="$dataStore.isLoading"
121
+ @input="uploadAdditionalFile($event, '10', member.iin)"
122
+ />
123
+ <base-file-input
124
+ v-if="!formStore.signedDocumentList.find(i => i.fileTypeCode === '9' && i.iin === String(member.iin).replaceAll('-', '')) && member.isDisability"
125
+ label="Справка об инвалидности"
126
+ :loading="$dataStore.isLoading"
127
+ @input="uploadAdditionalFile($event, '9', member.iin)"
128
+ />
129
+ <base-file-input
130
+ v-if="
131
+ processCode === 25 &&
132
+ !formStore.signedDocumentList.find(i => i.fileTypeCode === '8' && i.iin === String(member.iin).replaceAll('-', '')) &&
133
+ formStore.requiredDocuments.some(i => i.code === '8' && i.iin === String(member.iin).replaceAll('-', ''))
134
+ "
135
+ :label="$dataStore.t('pension.ENPFnote')"
136
+ :loading="$dataStore.isLoading"
137
+ @input="uploadAdditionalFile($event, '8', member.iin)"
138
+ />
139
+ <base-file-input
140
+ v-if="
141
+ !formStore.signedDocumentList.find(i => i.fileTypeCode === '40' && i.iin === String(member.iin).replaceAll('-', '')) &&
142
+ formStore.requiredDocuments.some(i => i.code === '40' && i.iin === String(member.iin).replaceAll('-', ''))
143
+ "
144
+ :label="$dataStore.t('pension.dossierPA')"
145
+ :loading="$dataStore.isLoading"
146
+ @input="uploadAdditionalFile($event, '40', member.iin)"
147
+ />
148
+ <base-file-input
149
+ v-if="
150
+ processCode === 25 &&
151
+ !formStore.signedDocumentList.find(i => i.fileTypeCode === '50' && i.iin === String(member.iin).replaceAll('-', '')) &&
152
+ formStore.requiredDocuments.some(i => i.code === '50' && i.iin === String(member.iin).replaceAll('-', ''))
153
+ "
154
+ :label="$dataStore.t('pension.oppvPaymentCertificate')"
155
+ :loading="$dataStore.isLoading"
156
+ @input="uploadAdditionalFile($event, '50', member.iin)"
157
+ />
158
+ <base-file-input
159
+ v-if="
160
+ formStore.signedDocumentList.filter(i => i.fileTypeCode === '29' && i.iin === String(member.iin).replaceAll('-', '')).length !==
161
+ formStore.requiredDocuments.filter(i => i.code === '29' && i.iin === String(member.iin).replaceAll('-', '')).length
162
+ "
163
+ :label="$dataStore.t('pension.KSJagreement')"
164
+ :loading="$dataStore.isLoading"
165
+ @input.prevent="uploadAdditionalFile($event, '29', member.iin)"
166
+ />
167
+ </base-form-section>
168
+ </div>
169
+ </section>
170
+ <section v-if="hasDigitalDocuments">
171
+ <base-digital-document
172
+ v-if="$route.params.taskId !== '0'"
173
+ :member="policyholderForm"
174
+ :title="$dataStore.t('policyholderForm')"
175
+ :disabled="isDigitalDocDisabled"
176
+ @openDigitalDocPanel="openDigitalDocPanel($event, 'Страхователя')"
177
+ @openPanel="openPanel"
178
+ />
179
+ <base-digital-document
180
+ v-if="$route.params.taskId !== '0' && slaveInsuredForm"
181
+ :member="slaveInsuredForm"
182
+ :title="$dataStore.t('policyholderForm') + ' 2'"
183
+ :disabled="isDigitalDocDisabled"
184
+ @openDigitalDocPanel="openDigitalDocPanel($event, 'Страхователя 2')"
185
+ @openPanel="openPanel"
186
+ />
187
+ <div v-if="insuredFiltered.length !== 0">
188
+ <base-digital-document
189
+ v-for="(member, index) in insuredFiltered"
190
+ :key="index"
191
+ :member="member"
192
+ :number="index + 1"
193
+ :title="$dataStore.t('insuredForm')"
194
+ :disabled="isDigitalDocDisabled"
195
+ @openDigitalDocPanel="openDigitalDocPanel($event, 'Застрахованного')"
196
+ @openPanel="openPanel"
197
+ />
198
+ </div>
199
+ <div v-if="beneficiaryFiltered.length !== 0">
200
+ <base-digital-document
201
+ v-for="(member, index) in beneficiaryFiltered"
202
+ :key="index"
203
+ :member="member"
204
+ :number="index + 1"
205
+ :title="$dataStore.t('beneficiaryForm')"
206
+ :disabled="isDigitalDocDisabled"
207
+ @openDigitalDocPanel="openDigitalDocPanel($event, 'Выгодоприобретателя')"
208
+ @openPanel="openPanel"
209
+ />
210
+ </div>
211
+ </section>
34
212
  <div v-if="noDocuments" class="h-[calc(90vh-70px)] flex flex-col items-center justify-center gap-6">
35
213
  <svg xmlns="http://www.w3.org/2000/svg" width="125" height="131" viewBox="0 0 125 131" fill="none" class="cursor-help">
36
214
  <path
@@ -51,63 +229,66 @@
51
229
  </svg>
52
230
  <p class="text-xl" :class="[$styles.mutedText]">{{ $dataStore.t('labels.noDocuments') }}</p>
53
231
  </div>
54
- <section v-if="$dataStore.isPension && showContract" class="w-full px-[10px] pt-[14px] flex flex-col gap-2">
55
- <base-content-block :class="[$styles.textSimple]">
56
- <h5 class="text-center font-medium mb-4">{{ $dataStore.t('labels.statements') }}</h5>
57
- <div :class="[$styles.whiteBg, $styles.rounded]" class="p-2 h-12 flex items-center relative">
58
- <span class="ml-2">Заявления на {{ processCode == 19 ? 'страхование' : 'возврат' }}</span>
59
- <i
60
- class="transition-all cursor-pointer mdi mdi-paperclip pl-2 mr-3 border-l-[1px] text-xl absolute right-0"
61
- :class="[$styles.greenTextHover]"
62
- @click="$dataStore.generatePDFDocument(processCode == 19 ? 'PA_Statement' : 'PA_RefundStatement', '37')"
63
- ></i>
64
- </div>
65
- </base-content-block>
66
- <base-content-block :class="[$styles.textSimple]">
67
- <h5 class="text-center font-medium mb-4">{{ $dataStore.t('labels.contract') }}</h5>
68
- <div :class="[$styles.whiteBg, $styles.rounded]" class="p-2 h-12 flex items-center relative">
69
- <span class="ml-2">Договор {{ processCode == 19 ? 'страхования' : 'возврата' }}</span>
70
- <i
71
- class="transition-all cursor-pointer mdi mdi-paperclip pl-2 mr-3 border-l-[1px] text-xl absolute right-0"
72
- :class="[$styles.greenTextHover]"
73
- @click="$dataStore.generatePDFDocument(processCode == 19 ? 'PA_Contract' : 'PA_RefundAgreement', '38')"
74
- ></i>
75
- </div>
76
- </base-content-block>
77
- <base-content-block :class="[$styles.textSimple]" v-if="formStore.applicationData.statusCode !== 'StartForm' && processCode == 19">
78
- <h5 class="text-center font-medium mb-4">{{ $dataStore.t('pension.complianceFinMonitoring') }}</h5>
79
- <div :class="[$styles.whiteBg, $styles.rounded]" class="p-2 h-12 flex items-center relative">
80
- <span class="ml-2">{{ $dataStore.t('pension.complianceFinMonitoring') }}</span>
81
- <i
82
- class="transition-all cursor-pointer mdi mdi-paperclip pl-2 mr-3 border-l-[1px] text-xl absolute right-0"
83
- :class="[$styles.greenTextHover]"
84
- @click="$dataStore.generatePDFDocument('Compliance_FinMonitoring', '39')"
85
- ></i>
86
- </div>
87
- </base-content-block>
88
- <base-content-block :class="[$styles.textSimple]" v-if="formStore.applicationData.statusCode === 'PreparationDossierForm' && processCode == 19">
89
- <h5 class="text-center font-medium mb-4">{{ $dataStore.t('pension.dossierPA') }}</h5>
90
- <div :class="[$styles.whiteBg, $styles.rounded]" class="p-2 h-12 flex items-center relative">
91
- <span class="ml-2">{{ $dataStore.t('pension.dossierPA') }}</span>
92
- <i
93
- class="transition-all cursor-pointer mdi mdi-paperclip pl-2 mr-3 border-l-[1px] text-xl absolute right-0"
94
- :class="[$styles.greenTextHover]"
95
- @click="$dataStore.generatePDFDocument('PA_Dossier', '40', 'doc')"
96
- ></i>
97
- </div>
98
- </base-content-block>
99
- </section>
100
- <Teleport v-if="$dataStore.panelAction === null" to="#right-panel-actions">
232
+ <Teleport v-if="isPanelOpen" to="#right-panel-actions">
101
233
  <base-fade-transition>
102
234
  <div :class="[$styles.flexColNav]">
103
- <base-btn :disabled="documentLoading" :loading="documentLoading" text="Открыть" @click="getFile('view')" />
104
- <base-btn :disabled="documentLoading" :loading="documentLoading" text="Скачать" @click="getFile('download')" />
235
+ <base-animation>
236
+ <base-btn
237
+ v-if="currentDocument.fileName && currentDocument.fileName.includes('.') ? currentDocument.fileName.endsWith('.pdf') : true"
238
+ :disabled="documentLoading"
239
+ :loading="documentLoading"
240
+ text="Открыть"
241
+ @click="getDoc('view')"
242
+ />
243
+ </base-animation>
244
+ <base-btn :disabled="documentLoading" :loading="documentLoading" text="Скачать" @click="getDoc('download')" />
105
245
  <base-animation>
106
246
  <base-btn v-if="canDeleteFiles" :disabled="documentLoading" :loading="documentLoading" text="Удалить" @click="deletionDialog = true" />
107
247
  </base-animation>
108
248
  </div>
109
249
  </base-fade-transition>
110
250
  </Teleport>
251
+ <Teleport v-if="isDigitalDocOpen" to="#right-panel-actions">
252
+ <div :class="[$styles.flexColNav]">
253
+ <base-form-section class="!mt-0">
254
+ <v-expansion-panels :flat="true">
255
+ <v-expansion-panel class="digital-doc-info !rounded-[8px]">
256
+ <v-expansion-panel-title class="!text-[12px]"> Как получить цифровой документ: </v-expansion-panel-title>
257
+ <v-expansion-panel-text class="text-[12px] text-[#464f60]">
258
+ 1. Выберите тип документа.<br /><br />
259
+ 2. Через приложение eGov mobile и другие приложения: <br />
260
+ • Откройте раздел "Цифровые документы". <br />
261
+ • Выберите нужный документ и откройте доступ. <br />
262
+ • Введите 6-значный код в поле «Код подтверждения». <br />
263
+ • Нажмите "Получить документ".<br /><br />
264
+ 3. Через SMS: <br />
265
+ • Нажмите "Отправить код". <br />
266
+ • Введите полученный SMS-код. <br />
267
+ • Нажмите "Получить документ".<br /><br />
268
+ 4. При ошибке нажмите <a href="javascript:void(0);" class="text-blue-600" @click="$dataStore.updateDigitalDocumentsProfile(currentIin)">обновить профиль</a><br />
269
+ </v-expansion-panel-text>
270
+ </v-expansion-panel>
271
+ </v-expansion-panels>
272
+ </base-form-section>
273
+ <div class="p-4 d-flex flex-col gap-0.5" :class="[$styles.blueBgLight, $styles.rounded]">
274
+ <base-rounded-select v-model="documentType" class="document-type-select" :items="documentItems" :label="$dataStore.t('form.documentType')" hide-details />
275
+ <div class="digital-document-otp flex flex-col">
276
+ <base-otp-input
277
+ v-model="otpCode"
278
+ @keyup.enter.prevent="otpCode.length === useMask().otpSixDigit.length && getCode()"
279
+ @input="otpCode.length === useMask().otpSixDigit.length && getDigitalDocument()"
280
+ />
281
+ <base-animation>
282
+ <span v-if="!documentLoading" class="text-center cursor-pointer" :class="[$styles.mutedText]" @click="getCode"
283
+ >Не получили код? <span class="underline underline-offset-2">Отправить код заново</span></span
284
+ >
285
+ </base-animation>
286
+ </div>
287
+ </div>
288
+ <base-btn :disabled="documentLoading" :loading="documentLoading" :btn="$styles.greenLightBtn" text="Отправить SMS-код" @click="getCode" />
289
+ <base-btn :disabled="documentLoading" :loading="documentLoading" text="Получить документ" @click="getDigitalDocument" />
290
+ </div>
291
+ </Teleport>
111
292
  <base-dialog
112
293
  v-model="deletionDialog"
113
294
  :title="$dataStore.t('dialog.confirmDelete')"
@@ -121,20 +302,49 @@
121
302
  </template>
122
303
 
123
304
  <script lang="ts">
124
- import { DocumentItem } from '../../composables/classes';
305
+ import { DocumentItem, Value } from '../../composables/classes';
306
+ import type { IDocument, Member } from '../../composables/classes';
125
307
  import { uuid } from 'vue-uuid';
126
- import type { FileActions } from '../../types';
308
+ import type { Base, FileActions } from '../../types';
127
309
 
128
310
  export default defineComponent({
129
311
  setup() {
312
+ type DigitalDocNames = 'Удостоверение личности' | 'Паспорт' | 'Вид на жительство иностранного гражданина';
313
+ type DigitalDocTypes = 'IdentityCard' | 'Passport' | 'Vnzh';
314
+
315
+ const route = useRoute();
130
316
  const dataStore = useDataStore();
131
317
  const formStore = useFormStore();
132
318
  const currentDocument = ref<DocumentItem>(new DocumentItem());
133
319
  const documentLoading = ref<boolean>(false);
134
320
  const deletionDialog = ref<boolean>(false);
321
+ const isPanelOpen = ref<boolean>(false);
322
+ const isDigitalDocOpen = ref<boolean>(false);
135
323
  const isDisabled = computed(() => !dataStore.isTask());
136
324
  const contractDict = computed(() => dataStore.dicFileTypeList.find(i => i.nameRu === 'Договор страхования' || i.nameRu === 'Договор'));
137
325
  const processCode = formStore.applicationData.processCode;
326
+ const requiredSign = computed(
327
+ () =>
328
+ !isDisabled.value &&
329
+ dataStore.isPension &&
330
+ formStore.applicationData &&
331
+ (formStore.applicationData.statusCode === 'StartForm' ||
332
+ formStore.applicationData.statusCode === 'EditForm' ||
333
+ formStore.applicationData.statusCode === 'PreparationDossierForm'),
334
+ );
335
+ const hasDigitalDocuments = computed(() => dataStore.isEfoParent && !dataStore.isGns && !dataStore.isLifeBusiness && !!formStore.applicationData);
336
+ const isDigitalDocDisabled = computed(
337
+ () => !dataStore.isTask() || route.params.taskId === '0' || !dataStore.isInitiator() || !dataStore.isProcessEditable(formStore.applicationData.statusCode),
338
+ );
339
+ const documentType = ref<DigitalDocNames | null>(null);
340
+ const otpCode = ref<string>('');
341
+ const currentIin = ref<string>('');
342
+ const deleteFilesId = ['1', '2', '3', '4', '46'];
343
+ const documentItems: Array<{ title: DigitalDocNames; value: DigitalDocTypes }> = [
344
+ { title: 'Удостоверение личности', value: 'IdentityCard' },
345
+ { title: 'Паспорт', value: 'Passport' },
346
+ { title: 'Вид на жительство иностранного гражданина', value: 'Vnzh' },
347
+ ];
138
348
  const signedContract = reactive<{
139
349
  processInstanceId: string | number;
140
350
  fileTypeId: string | number | null;
@@ -172,34 +382,50 @@ export default defineComponent({
172
382
  }),
173
383
  );
174
384
  const showContract = computed(
175
- () =>
176
- formStore.applicationData &&
177
- (formStore.applicationData.statusCode === 'Completed' || formStore.applicationData.statusCode === 'PreparationDossierForm' || dataStore.isActuary()),
385
+ () => formStore.applicationData && (dataStore.isAdmin() || dataStore.isSupport() || (dataStore.isActuary() && formStore.applicationData.statusCode === 'ActuaryForm')),
178
386
  );
179
387
  const noDocuments = computed(() => {
180
- if (dataStore.isPension) return !showContract.value;
388
+ if (dataStore.isPension && (!formStore.signedDocumentList || !formStore.signedDocumentList.length)) return !showContract.value;
181
389
  return !formStore.signedDocumentList || !formStore.signedDocumentList.length;
182
390
  });
183
391
  const isUnderwriterDocuments = computed(
184
392
  () =>
185
- (dataStore.isBaiterek || dataStore.isBolashak || dataStore.isLiferenta || dataStore.isKazyna || dataStore.isAmulet || dataStore.isGons) &&
393
+ (dataStore.isBaiterek || dataStore.isMycar || dataStore.isBolashak || dataStore.isLiferenta || dataStore.isKazyna || dataStore.isAmulet || dataStore.isGons) &&
186
394
  dataStore.isInitiator() &&
187
395
  formStore.applicationData &&
188
396
  (formStore.applicationData.statusCode === 'StartForm' || formStore.applicationData.statusCode === 'EditForm'),
189
397
  );
190
398
  const canDeleteFiles = computed(() => {
191
399
  const baseCondition = dataStore.isTask() && dataStore.isInitiator() && dataStore.isProcessEditable(formStore.applicationData.statusCode);
192
- if (dataStore.isBaiterek || dataStore.isBolashak || dataStore.isLiferenta || dataStore.isKazyna || dataStore.isAmulet || dataStore.isGons) {
193
- return baseCondition && (currentDocument.value ? currentDocument.value.fileTypeCode === '46' : false);
400
+ if (dataStore.isBaiterek || dataStore.isMycar || dataStore.isBolashak || dataStore.isLiferenta || dataStore.isKazyna || dataStore.isAmulet || dataStore.isGons) {
401
+ return baseCondition && (currentDocument.value ? deleteFilesId.includes(String(currentDocument.value.fileTypeCode)) : false);
402
+ }
403
+ if (dataStore.isPension) {
404
+ const canDeleteInPension = dataStore.isTask() && dataStore.isInitiator();
405
+ const canDeletePaperInPension = canDeleteInPension && currentDocument.value.signed === true && currentDocument.value.signedType === 2;
406
+ if (canDeleteInPension && dataStore.isProcessEditable(formStore.applicationData.statusCode))
407
+ return formStore.requiredDocuments.some(i => i.code === currentDocument.value.fileTypeCode);
408
+ if (formStore.applicationData.statusCode === 'AttachAppContractForm')
409
+ return canDeletePaperInPension && (currentDocument.value.fileTypeCode === '5' || currentDocument.value.fileTypeCode === '19');
410
+ if (formStore.applicationData.statusCode === 'ContractSignedFrom') return canDeletePaperInPension && currentDocument.value.fileTypeCode === '6';
194
411
  }
195
- if (dataStore.isPension) return baseCondition;
196
412
  return false;
197
413
  });
198
414
 
415
+ const policyholderForm = computed(() => formStore.policyholderForm as Base.Document.Digital);
416
+ const insuredFiltered = computed(() => formStore.insuredForm.filter(i => i.iin !== formStore.policyholderForm.iin) as Base.Document.Digital[]);
417
+ const beneficiaryFiltered = computed(() => formStore.beneficiaryForm.filter(i => i.iin !== formStore.policyholderForm.iin) as Base.Document.Digital[]);
418
+ const slaveInsuredForm = computed(() => formStore.slaveInsuredForm as Base.Document.Digital);
419
+ const documentListFiltered = computed(() => formStore.signedDocumentList.filter(i => !['1', '2', '3', '4'].includes(String(i.fileTypeCode))));
420
+ const jointMembers = ref<Member[]>([formStore.insuredForm[0]]);
421
+
199
422
  const openPanel = async (document: DocumentItem) => {
200
423
  dataStore.rightPanel.title = document.fileTypeName!;
201
424
  currentDocument.value = document;
202
425
  dataStore.rightPanel.open = true;
426
+ isDigitalDocOpen.value = false;
427
+ isPanelOpen.value = true;
428
+ dataStore.panelAction = null;
203
429
  };
204
430
 
205
431
  const onFileChange = async (event: InputEvent) => {
@@ -209,7 +435,7 @@ export default defineComponent({
209
435
  if (files[0].size >= 20_000_000) {
210
436
  return dataStore.showToaster('error', dataStore.t('toaster.fileOnlyBelow20mb'), 6000);
211
437
  }
212
- if (files[0].type !== 'application/pdf') {
438
+ if (files[0].type !== constants.fileTypes.pdf) {
213
439
  return dataStore.showToaster('error', dataStore.t('toaster.onlyPDF'), 6000);
214
440
  }
215
441
  signedContract.fileName = files[0].name;
@@ -264,6 +490,17 @@ export default defineComponent({
264
490
  }
265
491
  };
266
492
 
493
+ const openDigitalDocPanel = async (iin: string, title: string) => {
494
+ isPanelOpen.value = false;
495
+ isDigitalDocOpen.value = true;
496
+ dataStore.panelAction = null;
497
+ dataStore.rightPanel.open = true;
498
+ dataStore.rightPanel.title = `Получить ЦД ${title}`;
499
+ documentType.value = null;
500
+ otpCode.value = '';
501
+ currentIin.value = iin;
502
+ };
503
+
267
504
  watch(
268
505
  () => document_list.value,
269
506
  () => {
@@ -280,11 +517,11 @@ export default defineComponent({
280
517
  },
281
518
  );
282
519
 
283
- const getFile = async (type: FileActions) => {
520
+ const getDoc = async (type: FileActions) => {
284
521
  if (currentDocument.value) {
285
522
  documentLoading.value = true;
286
523
  const fileExtension = currentDocument.value.fileName!.match(/\.([0-9a-z]+)(?:[\?#]|$)/i)![1];
287
- await dataStore.getFile(currentDocument.value, type, fileExtension);
524
+ await dataStore.getDoc(currentDocument.value, type, fileExtension);
288
525
  documentLoading.value = false;
289
526
  }
290
527
  };
@@ -294,18 +531,154 @@ export default defineComponent({
294
531
  const data = {
295
532
  id: currentDocument.value.id,
296
533
  processInstanceId: currentDocument.value.processInstanceId,
534
+ iin: currentDocument.value.iin ?? '',
297
535
  };
298
536
  await dataStore.deleteFile(data);
299
537
  deletionDialog.value = false;
300
538
  dataStore.rightPanel.open = false;
301
539
  dataStore.panelAction = null;
302
540
  await dataStore.getSignedDocList(formStore.applicationData.processInstanceId);
541
+ if (
542
+ hasDigitalDocuments.value &&
543
+ (currentDocument.value.fileTypeCode === '1' ||
544
+ currentDocument.value.fileTypeCode === '2' ||
545
+ currentDocument.value.fileTypeCode === '3' ||
546
+ currentDocument.value.fileTypeCode === '4')
547
+ ) {
548
+ getDigitalDocs();
549
+ }
550
+ }
551
+ };
552
+
553
+ const getCode = async () => {
554
+ if (!documentType.value) {
555
+ dataStore.showToaster('error', 'Выберите тип документа', 3000);
556
+ return;
557
+ }
558
+ documentLoading.value = true;
559
+ const response = await dataStore.getOnlineAccess(currentIin.value, String(documentType.value));
560
+ if (response) {
561
+ dataStore.showToaster('success', dataStore.t('toaster.successOtp'), 3000);
562
+ }
563
+ documentLoading.value = false;
564
+ };
565
+
566
+ const getDigitalDocument = async () => {
567
+ if (!documentType.value) {
568
+ dataStore.showToaster('error', 'Выберите тип документа', 3000);
569
+ return;
570
+ }
571
+ if (!otpCode.value) {
572
+ dataStore.showToaster('error', 'Введите код подтверждения', 3000);
573
+ return;
574
+ }
575
+ documentLoading.value = true;
576
+ const response = await dataStore.getDigitalDocuments(currentIin.value, otpCode.value, String(formStore.applicationData.processInstanceId));
577
+ if (response?.digitalDocuments?.responseCode === 'SUCCESS' && response?.parsingResponseContent) {
578
+ await dataStore.getSignedDocList(formStore.applicationData.processInstanceId);
579
+ getDigitalDocs();
580
+ isDigitalDocOpen.value = false;
581
+ dataStore.panelAction = null;
582
+ dataStore.rightPanel.open = false;
583
+ documentType.value = null;
584
+ otpCode.value = '';
585
+ }
586
+ documentLoading.value = false;
587
+ };
588
+
589
+ const findCommonDocs = (members: Base.Document.Digital[]) => {
590
+ let commonDocs: IDocument[] = [];
591
+ for (let member of members) {
592
+ const matchingDoc = formStore.signedDocumentList.find(
593
+ doc =>
594
+ doc.iin === String(member.iin).replaceAll('-', '') && (doc.fileTypeCode === '1' || doc.fileTypeCode === '2' || doc.fileTypeCode === '3' || doc.fileTypeCode === '4'),
595
+ );
596
+ if (matchingDoc) commonDocs.push(matchingDoc);
597
+ }
598
+ return commonDocs;
599
+ };
600
+
601
+ const setDigitalDocuments = (members: Base.Document.Digital[]) => {
602
+ const commonDocs = findCommonDocs(members);
603
+ if (commonDocs.length !== 0) {
604
+ for (let member of members) {
605
+ const matchingDoc = commonDocs.find(doc => doc.iin === String(member.iin).replaceAll('-', ''));
606
+ if (matchingDoc) member.digitalDocument = matchingDoc;
607
+ }
608
+ }
609
+ };
610
+
611
+ const clearDigitalDocuments = (members: Base.Document.Digital[]) => {
612
+ for (let member of members) member.digitalDocument = null;
613
+ };
614
+
615
+ const getDigitalDocs = () => {
616
+ if (route.params.taskId !== '0') {
617
+ clearDigitalDocuments([formStore.policyholderForm as Base.Document.Digital]);
618
+ setDigitalDocuments([formStore.policyholderForm as Base.Document.Digital]);
619
+ if (processCode === 25 && formStore.slaveInsuredForm.iin !== null && formStore.slaveInsuredForm.id !== 0) {
620
+ clearDigitalDocuments([formStore.slaveInsuredForm as Base.Document.Digital]);
621
+ setDigitalDocuments([formStore.slaveInsuredForm as Base.Document.Digital]);
622
+ }
623
+ if (insuredFiltered.value.length !== 0) {
624
+ clearDigitalDocuments(insuredFiltered.value);
625
+ setDigitalDocuments(insuredFiltered.value);
626
+ }
627
+ if (beneficiaryFiltered.value.length !== 0) {
628
+ clearDigitalDocuments(beneficiaryFiltered.value);
629
+ setDigitalDocuments(beneficiaryFiltered.value);
630
+ }
631
+ }
632
+ };
633
+
634
+ const memberHasDocumentsToSign = (iin: string | null) => {
635
+ if (!iin) return false;
636
+ // TODO reformat logic
637
+ return (
638
+ formStore.signedDocumentList.filter(i => formStore.requiredDocuments.find(j => j.code === i.fileTypeCode) && i.iin === iin.replaceAll('-', '')).length !==
639
+ formStore.requiredDocuments.filter(i => i.iin === iin.replaceAll('-', '')).length
640
+ );
641
+ };
642
+
643
+ const uploadAdditionalFile = async (event: InputEvent, code: string, iin?: string | null) => {
644
+ if (event.target) {
645
+ const files = (event.target as HTMLInputElement).files;
646
+ if (files && files.length && files[0]) {
647
+ if (files[0].type !== constants.fileTypes.pdf && files[0].type !== constants.fileTypes.docx && files[0].type !== constants.fileTypes.doc) {
648
+ return dataStore.showToaster('error', dataStore.t('toaster.onlyWithFormat', { format: 'PDF, Word' }), 6000);
649
+ }
650
+ if (files[0].size >= 10_000_000) {
651
+ return dataStore.showToaster('error', dataStore.t('toaster.fileOnlyBelow10mb'), 6000);
652
+ }
653
+ const file = Object.assign(files[0]);
654
+ const formData = new FormData();
655
+ const information: any = [];
656
+ const uuidV4 = uuid.v4();
657
+ formData.append('file', file);
658
+ const ext = file.name.substring(file.name.lastIndexOf('.'));
659
+ const selectedDocument = dataStore.dicFileTypeList.find((i: Value) => i.code === code);
660
+ information.push({
661
+ identifier: `${uuidV4}${ext}`,
662
+ iin: iin ? iin.replaceAll('-', '') : null,
663
+ processInstanceId: formStore.applicationData.processInstanceId,
664
+ fileTypeCode: selectedDocument ? selectedDocument.code : null,
665
+ fileTypeId: selectedDocument ? selectedDocument.id : null,
666
+ fileName: file.name,
667
+ });
668
+ formData.append('fileData', JSON.stringify(information));
669
+ dataStore.isLoading = true;
670
+ await dataStore.uploadFiles(formData, false);
671
+ await dataStore.getSignedDocList(formStore.applicationData.processInstanceId);
672
+ }
673
+ dataStore.isLoading = false;
303
674
  }
304
675
  };
305
676
 
306
677
  const onInit = async () => {
307
678
  await dataStore.getDicFileTypeList();
308
679
  await dataStore.getSignedDocList(formStore.applicationData.processInstanceId);
680
+ if (hasDigitalDocuments.value) getDigitalDocs();
681
+ if (processCode === 25) jointMembers.value.push(slaveInsuredForm.value as Member);
309
682
  };
310
683
 
311
684
  onInit();
@@ -316,30 +689,79 @@ export default defineComponent({
316
689
 
317
690
  return {
318
691
  // State
692
+ otpCode,
319
693
  formStore,
320
- documentLoading,
694
+ currentIin,
695
+ processCode,
696
+ isPanelOpen,
697
+ jointMembers,
321
698
  DocumentItem,
699
+ documentType,
700
+ documentItems,
322
701
  signedContract,
323
702
  deletionDialog,
324
- processCode,
703
+ currentDocument,
704
+ documentLoading,
705
+ isDigitalDocOpen,
325
706
  underDocumentsList,
326
707
 
327
708
  // Computed
328
709
  isDisabled,
710
+ requiredSign,
329
711
  showContract,
330
712
  noDocuments,
331
713
  canDeleteFiles,
714
+ insuredFiltered,
715
+ policyholderForm,
716
+ slaveInsuredForm,
717
+ beneficiaryFiltered,
718
+ hasDigitalDocuments,
719
+ documentListFiltered,
720
+ isDigitalDocDisabled,
332
721
  isUnderwriterDocuments,
333
722
 
334
723
  // Functions
335
- getFile,
724
+ getCode,
725
+ getDoc,
336
726
  openPanel,
337
727
  deleteFile,
728
+ getDigitalDocument,
338
729
  onFileChange,
339
730
  onUnderFiles,
731
+ openDigitalDocPanel,
340
732
  uploadUnderFiles,
341
733
  onClearUnderFiles,
734
+ uploadAdditionalFile,
735
+ memberHasDocumentsToSign,
342
736
  };
343
737
  },
344
738
  });
345
739
  </script>
740
+
741
+ <style>
742
+ .document-type-select .v-field {
743
+ border: none !important;
744
+ border-radius: 4px;
745
+ height: 56px;
746
+ }
747
+ .digital-document-otp .base-otp-input .v-otp-input__content {
748
+ gap: 8px;
749
+ padding-right: 0px !important;
750
+ padding-left: 0px !important;
751
+ }
752
+ .digital-doc-info .v-expansion-panel-text__wrapper {
753
+ padding: 8px 14px !important;
754
+ }
755
+ .digital-doc-info .v-expansion-panel-title {
756
+ max-height: 40px !important;
757
+ min-height: 39px !important;
758
+ padding: 0px 14px !important;
759
+ color: #464f60 !important;
760
+ }
761
+ .document-type-select .v-field-label--floating {
762
+ top: 5px !important;
763
+ }
764
+ .document-type-select .v-field__input {
765
+ padding-top: 21px;
766
+ }
767
+ </style>