@coopenomics/desktop 2025.11.10-alpha-3 → 2025.11.12-alpha-1

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 (23) hide show
  1. package/package.json +6 -6
  2. package/src/entities/ConnectionAgreement/api/index.ts +26 -0
  3. package/src/entities/ConnectionAgreement/index.ts +1 -0
  4. package/src/entities/ConnectionAgreement/model/store.ts +158 -2
  5. package/src/entities/ConnectionAgreement/model/types.ts +11 -1
  6. package/src/features/Provider/model/index.ts +4 -1
  7. package/src/features/Union/AddCooperative/ui/AddCooperativeForm.vue +29 -20
  8. package/src/features/Union/CooperativeDataForm/index.ts +1 -0
  9. package/src/features/Union/CooperativeDataForm/ui/CooperativeDataForm.vue +69 -0
  10. package/src/features/Union/CooperativeDataForm/ui/index.ts +1 -0
  11. package/src/pages/Union/ConnectionAgreement/ConnectionAgreementPage.vue +69 -177
  12. package/src/widgets/ConnectionAgreementStepper/Steps/AgreementStep.vue +63 -10
  13. package/src/widgets/ConnectionAgreementStepper/Steps/ApprovalWaitingStep.vue +81 -0
  14. package/src/widgets/ConnectionAgreementStepper/Steps/DomainValidationStep.vue +345 -99
  15. package/src/widgets/ConnectionAgreementStepper/Steps/FormStep.vue +20 -25
  16. package/src/widgets/ConnectionAgreementStepper/Steps/InstallationStep.vue +94 -0
  17. package/src/widgets/ConnectionAgreementStepper/Steps/IntroStep.vue +9 -11
  18. package/src/widgets/ConnectionAgreementStepper/Steps/index.ts +2 -1
  19. package/src/widgets/ConnectionAgreementStepper/ui/ConnectionAgreementStepper.vue +41 -112
  20. package/src/widgets/ConnectionDashboard/index.ts +2 -0
  21. package/src/widgets/ConnectionDashboard/ui/ConnectionDashboard.vue +160 -0
  22. package/src/widgets/ConnectionDashboard/ui/index.ts +2 -0
  23. package/src/widgets/ConnectionAgreementStepper/Steps/WaitingStep.vue +0 -113
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coopenomics/desktop",
3
- "version": "2025.11.10-alpha-3",
3
+ "version": "2025.11.12-alpha-1",
4
4
  "description": "A Desktop Project",
5
5
  "productName": "Desktop App",
6
6
  "author": "Alex Ant <dacom.dark.sun@gmail.com>",
@@ -25,9 +25,9 @@
25
25
  "start": "node -r ./alias-resolver.js dist/ssr/index.js"
26
26
  },
27
27
  "dependencies": {
28
- "@coopenomics/controller": "2025.11.10-alpha-3",
29
- "@coopenomics/notifications": "2025.11.10-alpha-3",
30
- "@coopenomics/sdk": "2025.11.10-alpha-3",
28
+ "@coopenomics/controller": "2025.11.12-alpha-1",
29
+ "@coopenomics/notifications": "2025.11.12-alpha-1",
30
+ "@coopenomics/sdk": "2025.11.12-alpha-1",
31
31
  "@dicebear/collection": "^9.0.1",
32
32
  "@dicebear/core": "^9.0.1",
33
33
  "@editorjs/code": "^2.9.3",
@@ -59,7 +59,7 @@
59
59
  "@wharfkit/wallet-plugin-privatekey": "^1.1.0",
60
60
  "axios": "^1.2.1",
61
61
  "compression": "^1.7.4",
62
- "cooptypes": "2025.11.10-alpha-3",
62
+ "cooptypes": "2025.11.12-alpha-1",
63
63
  "dompurify": "^3.1.7",
64
64
  "dotenv": "^16.4.5",
65
65
  "email-regex": "^5.0.0",
@@ -123,5 +123,5 @@
123
123
  "npm": ">= 6.13.4",
124
124
  "yarn": ">= 1.21.1"
125
125
  },
126
- "gitHead": "637950d37f74f959a640d61891ef35d0ace9b858"
126
+ "gitHead": "b261f505aa7897cdc82ce88ed770fe0f6aee7afc"
127
127
  }
@@ -0,0 +1,26 @@
1
+ import { client } from 'src/shared/api/client';
2
+ import { Queries } from '@coopenomics/sdk';
3
+
4
+ /**
5
+ * Тип текущего инстанса из GraphQL API
6
+ */
7
+ export type CurrentInstance = Queries.System.GetCurrentInstance.IOutput[typeof Queries.System.GetCurrentInstance.name];
8
+
9
+ /**
10
+ * Получить текущий инстанс авторизованного пользователя
11
+ */
12
+ export async function getCurrentInstance(): Promise<CurrentInstance | null> {
13
+ try {
14
+ const { [Queries.System.GetCurrentInstance.name]: instance } =
15
+ await client.Query(Queries.System.GetCurrentInstance.query);
16
+
17
+ return instance;
18
+ } catch (error) {
19
+ console.error('Ошибка при получении текущего инстанса:', error);
20
+ return null;
21
+ }
22
+ }
23
+
24
+ export const api = {
25
+ getCurrentInstance
26
+ };
@@ -1 +1,2 @@
1
+ export * from './api'
1
2
  export * from './model'
@@ -1,6 +1,10 @@
1
1
  import { defineStore } from 'pinia'
2
2
  import { ref } from 'vue'
3
- import type { ITariff, IConnectionAgreementState } from './types'
3
+ import { DigitalDocument } from 'src/shared/lib/document'
4
+ import { useSessionStore } from 'src/entities/Session'
5
+ import { useLoadCooperatives } from 'src/features/Union/LoadCooperatives'
6
+ import { getCurrentInstance, type CurrentInstance } from '../api'
7
+ import type { ITariff, IConnectionAgreementState, ICooperativeFormData } from './types'
4
8
 
5
9
 
6
10
  const namespace = 'connection-agreement'
@@ -12,6 +16,17 @@ export const useConnectionAgreementStore = defineStore(namespace, () => {
12
16
  const isInitialized = ref<boolean>(false)
13
17
  const document = ref<any>(null)
14
18
  const signedDocument = ref<any>(null)
19
+ const currentInstance = ref<CurrentInstance | null>(null)
20
+ const currentInstanceLoading = ref<boolean>(false)
21
+ const currentInstanceError = ref<string | null>(null)
22
+ const coop = ref<any>(null)
23
+ const formData = ref<ICooperativeFormData>({
24
+ announce: '',
25
+ initial: '',
26
+ minimum: '',
27
+ org_initial: '',
28
+ org_minimum: ''
29
+ })
15
30
 
16
31
  // Methods
17
32
  const setCurrentStep = (step: number) => {
@@ -34,12 +49,132 @@ export const useConnectionAgreementStore = defineStore(namespace, () => {
34
49
  signedDocument.value = doc
35
50
  }
36
51
 
52
+ const setCoop = (coopData: any) => {
53
+ coop.value = coopData
54
+ }
55
+
56
+ const setFormData = (data: ICooperativeFormData) => {
57
+ formData.value = data
58
+ }
59
+
60
+ // Actions
61
+ const generateDocument = async () => {
62
+ console.log('🔄 Начинаем генерацию документа')
63
+ const session = useSessionStore()
64
+ const formDataValue = formData.value
65
+ console.log('📋 Данные формы:', formDataValue)
66
+
67
+ try {
68
+ console.log('📄 Создаем новый DigitalDocument')
69
+ const newDoc = new DigitalDocument()
70
+
71
+ const params: any = {
72
+ registry_id: 50,
73
+ coopname: 'voskhod',
74
+ username: session.username
75
+ }
76
+
77
+ // Передаем данные из формы в документ, если они есть
78
+ if (formDataValue) {
79
+ params.announce = formDataValue.announce
80
+ params.initial = formDataValue.initial
81
+ params.minimum = formDataValue.minimum
82
+ params.org_initial = formDataValue.org_initial
83
+ params.org_minimum = formDataValue.org_minimum
84
+ }
85
+
86
+ console.log('🔧 Генерируем документ с параметрами:', params)
87
+
88
+ await newDoc.generate(params)
89
+
90
+ console.log('✅ Документ успешно сгенерирован')
91
+ document.value = newDoc
92
+ return newDoc
93
+ } catch (error) {
94
+ console.error('❌ Ошибка при генерации документа:', error)
95
+ throw error
96
+ }
97
+ }
98
+
99
+ const signDocument = async () => {
100
+ const session = useSessionStore()
101
+ if (!document.value) {
102
+ throw new Error('Документ не найден')
103
+ }
104
+
105
+ await document.value.sign(session.username)
106
+ signedDocument.value = document.value.signedDocument
107
+ return signedDocument.value
108
+ }
109
+
110
+ const clearSignedDocument = async () => {
111
+ // Очищаем подписанный документ
112
+ signedDocument.value = null
113
+
114
+ // Регенерируем документ заново если есть данные формы
115
+ if (formData.value) {
116
+ await generateDocument()
117
+ }
118
+ }
119
+
120
+ const reloadCooperative = async () => {
121
+ const { loadOneCooperative } = useLoadCooperatives()
122
+ const session = useSessionStore()
123
+
124
+ try {
125
+ const coopData = await loadOneCooperative(session.username)
126
+ coop.value = coopData
127
+ return coopData
128
+ } catch (error) {
129
+ console.error('Ошибка при перезагрузке кооператива:', error)
130
+ throw error
131
+ }
132
+ }
133
+
134
+ const loadCurrentInstance = async () => {
135
+ try {
136
+ currentInstanceLoading.value = true
137
+ currentInstanceError.value = null
138
+ currentInstance.value = await getCurrentInstance()
139
+ console.log('Текущий инстанс загружен:', currentInstance.value)
140
+ } catch (error: any) {
141
+ currentInstanceError.value = error.message || 'Ошибка загрузки инстанса'
142
+ console.error('Ошибка при загрузке текущего инстанса:', error)
143
+ } finally {
144
+ currentInstanceLoading.value = false
145
+ }
146
+ }
147
+
148
+ const startInstanceAutoRefresh = (intervalMs = 30000) => { // 30 секунд по умолчанию
149
+ loadCurrentInstance() // Первая загрузка
150
+
151
+ const interval = setInterval(() => {
152
+ loadCurrentInstance()
153
+ }, intervalMs)
154
+
155
+ // Функция для остановки автообновления
156
+ const stop = () => clearInterval(interval)
157
+
158
+ return stop
159
+ }
160
+
37
161
  const reset = () => {
38
162
  currentStep.value = 1
39
163
  selectedTariff.value = null
40
164
  isInitialized.value = false
41
165
  document.value = null
42
166
  signedDocument.value = null
167
+ currentInstance.value = null
168
+ currentInstanceLoading.value = false
169
+ currentInstanceError.value = null
170
+ coop.value = null
171
+ formData.value = {
172
+ announce: '',
173
+ initial: '',
174
+ minimum: '',
175
+ org_initial: '',
176
+ org_minimum: ''
177
+ }
43
178
  }
44
179
 
45
180
  const initialize = (state: Partial<IConnectionAgreementState>) => {
@@ -58,6 +193,12 @@ export const useConnectionAgreementStore = defineStore(namespace, () => {
58
193
  if (state.signedDocument !== undefined) {
59
194
  signedDocument.value = state.signedDocument
60
195
  }
196
+ if (state.coop !== undefined) {
197
+ coop.value = state.coop
198
+ }
199
+ if (state.formData !== undefined && state.formData !== null) {
200
+ formData.value = state.formData
201
+ }
61
202
  }
62
203
 
63
204
  return {
@@ -67,6 +208,11 @@ export const useConnectionAgreementStore = defineStore(namespace, () => {
67
208
  isInitialized,
68
209
  document,
69
210
  signedDocument,
211
+ currentInstance,
212
+ currentInstanceLoading,
213
+ currentInstanceError,
214
+ coop,
215
+ formData,
70
216
 
71
217
  // Methods
72
218
  setCurrentStep,
@@ -74,8 +220,18 @@ export const useConnectionAgreementStore = defineStore(namespace, () => {
74
220
  setInitialized,
75
221
  setDocument,
76
222
  setSignedDocument,
223
+ setCoop,
224
+ setFormData,
77
225
  reset,
78
- initialize
226
+ initialize,
227
+
228
+ // Actions
229
+ generateDocument,
230
+ signDocument,
231
+ clearSignedDocument,
232
+ reloadCooperative,
233
+ loadCurrentInstance,
234
+ startInstanceAutoRefresh
79
235
  }
80
236
  }, {
81
237
  persist: true
@@ -7,10 +7,20 @@ export interface ITariff {
7
7
  additionalCosts?: string[]
8
8
  }
9
9
 
10
+ export interface ICooperativeFormData {
11
+ announce: string
12
+ initial: string
13
+ minimum: string
14
+ org_initial: string
15
+ org_minimum: string
16
+ }
17
+
10
18
  export interface IConnectionAgreementState {
11
19
  currentStep: number
12
20
  selectedTariff: ITariff | null
13
21
  isInitialized: boolean
14
22
  document?: any
15
23
  signedDocument?: any
16
- }
24
+ coop?: any
25
+ formData?: ICooperativeFormData
26
+ }
@@ -10,6 +10,7 @@ export interface HostingSubscriptionData {
10
10
  subscription_type_id: 1;
11
11
  progress: number;
12
12
  is_valid: boolean;
13
+ is_delegated: boolean;
13
14
  }
14
15
 
15
16
  /**
@@ -39,7 +40,7 @@ export function useProviderSubscriptions() {
39
40
  // Статус валидности домена для хостинг подписки (из specific_data)
40
41
  const domainValid = computed(() => {
41
42
  const specificData = hostingSubscription.value?.specific_data as SubscriptionSpecificData;
42
- return specificData?.is_valid ?? null;
43
+ return (specificData?.is_valid && specificData?.is_delegated) ?? null;
43
44
  });
44
45
 
45
46
  // Прогресс установки для хостинг подписки (из specific_data)
@@ -58,6 +59,7 @@ export function useProviderSubscriptions() {
58
59
  */
59
60
  const loadSubscriptions = async () => {
60
61
  // Проверяем доступность провайдера
62
+ console.log('system.info', system.info);
61
63
  if (!system.info.is_providered) {
62
64
  error.value = 'Функционал провайдера не доступен';
63
65
  return;
@@ -67,6 +69,7 @@ export function useProviderSubscriptions() {
67
69
  isLoading.value = true;
68
70
  error.value = null;
69
71
  subscriptions.value = await loadProviderSubscriptions();
72
+ console.log('subscriptions', subscriptions.value);
70
73
  } catch (err: any) {
71
74
  error.value = err.message || 'Ошибка загрузки подписок';
72
75
  console.error('Error loading provider subscriptions:', err);
@@ -1,29 +1,34 @@
1
1
  <template lang="pug">
2
- Form(:handler-submit="addNow" :is-submitting="isSubmitting" :showCancel="false" :button-cancel-txt="'Отменить'" :button-submit-txt="'Продолжить'" @cancel="clear").q-gutter-md
3
- //- q-input(standout="bg-teal text-white" label="Имя аккаунта" v-model="data.coopname" :rules="[val => notEmpty(val)]")
4
- q-input(standout="bg-teal text-white" hint="domovoy.com или coop.domovoy.com" label="Домен или поддомен для запуска" v-model="data.params.announce" :rules="[val => notEmpty(val), val => isDomain(val)]")
5
-
6
- q-input(standout="bg-teal text-white" hint="100 RUB" label="Вступительный взнос для физлиц и ИП" v-model="data.params.initial" type="number" :min="0" :rules="[val => notEmpty(val)]")
7
- template(#append)
8
- span.text-overline {{currency}}
9
-
10
- q-input(standout="bg-teal text-white" hint="300 RUB" label="Минимальный паевый взнос для физлиц и ИП" v-model="data.params.minimum" type="number" :min="0" :rules="[val => notEmpty(val)]")
11
- template(#append)
12
- span.text-overline {{currency}}
13
-
14
- q-input(standout="bg-teal text-white" hint="1000 RUB" label="Вступительный взнос для организаций" v-model="data.params.org_initial" type="number" :min="0" :rules="[val => notEmpty(val)]")
15
- template(#append)
16
- span.text-overline {{currency}}
17
-
18
- q-input(standout="bg-teal text-white" hint="3000 RUB" label="Минимальный паевый взнос для организаций" v-model="data.params.org_minimum" type="number" :min="0" :rules="[val => notEmpty(val)]")
19
- template(#append)
20
- span.text-overline {{currency}}
2
+ div
3
+ template(v-if="isSubmitting")
4
+ Loader(:text="'Создаем кооператив...'")
5
+ template(v-else)
6
+ Form(:handler-submit="addNow" :showCancel="false" :button-cancel-txt="'Отменить'" :button-submit-txt="'Продолжить'" @cancel="clear").q-gutter-md
7
+ //- q-input(standout="bg-teal text-white" label="Имя аккаунта" v-model="data.coopname" :rules="[val => notEmpty(val)]")
8
+ q-input(standout="bg-teal text-white" hint="domovoy.com или coop.domovoy.com" label="Домен или поддомен для запуска" v-model="data.params.announce" :rules="[val => notEmpty(val), val => isDomain(val)]")
9
+
10
+ q-input(standout="bg-teal text-white" hint="100 RUB" label="Вступительный взнос для физлиц и ИП" v-model="data.params.initial" type="number" :min="0" :rules="[val => notEmpty(val)]")
11
+ template(#append)
12
+ span.text-overline {{currency}}
13
+
14
+ q-input(standout="bg-teal text-white" hint="Минимальный паевый взнос для физлиц и ИП" v-model="data.params.minimum" type="number" :min="0" :rules="[val => notEmpty(val)]")
15
+ template(#append)
16
+ span.text-overline {{currency}}
17
+
18
+ q-input(standout="bg-teal text-white" hint="1000 RUB" label="Вступительный взнос для организаций" v-model="data.params.org_initial" type="number" :min="0" :rules="[val => notEmpty(val)]")
19
+ template(#append)
20
+ span.text-overline {{currency}}
21
+
22
+ q-input(standout="bg-teal text-white" hint="3000 RUB" label="Минимальный паевый взнос для организаций" v-model="data.params.org_minimum" type="number" :min="0" :rules="[val => notEmpty(val)]")
23
+ template(#append)
24
+ span.text-overline {{currency}}
21
25
 
22
26
  </template>
23
27
  <script lang="ts" setup>
24
28
  import { computed, ref, watch } from 'vue';
25
29
  import { useAddCooperative } from '../model';
26
30
  import { Form } from 'src/shared/ui/Form';
31
+ import { Loader } from 'src/shared/ui';
27
32
  import { notEmpty, isDomain } from 'src/shared/lib/utils';
28
33
  import { useSessionStore } from 'src/entities/Session';
29
34
  import { RegistratorContract } from 'cooptypes';
@@ -106,13 +111,17 @@ const clear = () => {
106
111
 
107
112
  const addNow = async () => {
108
113
  try {
114
+ isSubmitting.value = true
109
115
  data.value.document = {...document.value, meta: JSON.stringify(document.value.meta)}
110
116
  await addCooperative(data.value)
111
- SuccessAlert('Документ подписан и отправлен')
117
+ SuccessAlert('Заявка на создание кооператива отправлена!')
112
118
 
119
+ // После успешной отправки переходим к следующему шагу
113
120
  clear()
114
121
  } catch(e: any){
115
122
  FailAlert(e)
123
+ } finally {
124
+ isSubmitting.value = false
116
125
  }
117
126
  }
118
127
 
@@ -0,0 +1 @@
1
+ export * from './ui'
@@ -0,0 +1,69 @@
1
+ <template lang="pug">
2
+ div
3
+ Form(:handler-submit="saveData" :showCancel="false" :button-cancel-txt="'Отменить'" :button-submit-txt="'Продолжить'" @cancel="clear").q-gutter-md
4
+ q-input(standout="bg-teal text-white" hint="domovoy.com или coop.domovoy.com" label="Домен или поддомен для запуска" v-model="formData.announce" :rules="[val => notEmpty(val), val => isDomain(val)]")
5
+
6
+ q-input(standout="bg-teal text-white" placeholder="100" label="Вступительный взнос для физлиц и ИП" v-model="formData.initial" type="number" :min="0" :rules="[val => notEmpty(val)]")
7
+ template(#append)
8
+ span.text-overline RUB
9
+
10
+ q-input(standout="bg-teal text-white" label="Минимальный паевый взнос для физлиц и ИП" placeholder="300" v-model="formData.minimum" type="number" :min="0" :rules="[val => notEmpty(val)]")
11
+ template(#append)
12
+ span.text-overline RUB
13
+
14
+ q-input(standout="bg-teal text-white" placeholder="1000" label="Вступительный взнос для организаций" v-model="formData.org_initial" type="number" :min="0" :rules="[val => notEmpty(val)]")
15
+ template(#append)
16
+ span.text-overline RUB
17
+
18
+ q-input(standout="bg-teal text-white" placeholder="3000" label="Минимальный паевый взнос для организаций" v-model="formData.org_minimum" type="number" :min="0" :rules="[val => notEmpty(val)]")
19
+ template(#append)
20
+ span.text-overline RUB
21
+ </template>
22
+ <script lang="ts" setup>
23
+ import { ref, watch } from 'vue'
24
+ import { Form } from 'src/shared/ui/Form';
25
+ import { notEmpty, isDomain } from 'src/shared/lib/utils';
26
+ import { useConnectionAgreementStore } from 'src/entities/ConnectionAgreement';
27
+ import type { ICooperativeFormData } from 'src/entities/ConnectionAgreement/model/types';
28
+
29
+
30
+ const emit = defineEmits(['continue'])
31
+
32
+ const connectionAgreement = useConnectionAgreementStore()
33
+
34
+ // Локальное состояние формы для избежания проблем с реактивностью
35
+ const formData = ref<ICooperativeFormData>({
36
+ announce: connectionAgreement.formData.announce || '',
37
+ initial: connectionAgreement.formData.initial || '',
38
+ minimum: connectionAgreement.formData.minimum || '',
39
+ org_initial: connectionAgreement.formData.org_initial || '',
40
+ org_minimum: connectionAgreement.formData.org_minimum || ''
41
+ })
42
+
43
+ // Синхронизируем локальное состояние с изменениями в store
44
+ watch(() => connectionAgreement.formData, (newFormData) => {
45
+ formData.value = {
46
+ announce: newFormData.announce || '',
47
+ initial: newFormData.initial || '',
48
+ minimum: newFormData.minimum || '',
49
+ org_initial: newFormData.org_initial || '',
50
+ org_minimum: newFormData.org_minimum || ''
51
+ }
52
+ }, { deep: true })
53
+
54
+ // Синхронизируем локальное состояние с store при изменении
55
+ const syncFormData = () => {
56
+ connectionAgreement.setFormData(formData.value)
57
+ }
58
+
59
+ const clear = () => {
60
+ emit('continue')
61
+ }
62
+
63
+ const saveData = async () => {
64
+ console.log('📤 CooperativeDataForm: Данные формы:', formData.value)
65
+ // Синхронизируем данные с store перед отправкой
66
+ syncFormData()
67
+ emit('continue', formData.value)
68
+ }
69
+ </script>
@@ -0,0 +1 @@
1
+ export { default as CooperativeDataForm } from './CooperativeDataForm.vue'