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

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.
@@ -1,7 +1,7 @@
1
1
  import { markRaw } from 'vue';
2
2
  import { ProfilePage } from 'src/pages/User/ProfilePage';
3
3
  import { WalletPage } from 'src/pages/User/WalletPage';
4
- import { ConnectionAgreementPage } from 'src/pages/Union/ConnectionAgreement';
4
+ import { ConnectionAgreementPage, InstallationCompletedPage } from 'src/pages/Union/ConnectionAgreement';
5
5
  import { UserPaymentMethodsPage } from 'src/pages/User/PaymentMethodsPage';
6
6
  import { ContactsPage } from 'src/pages/Contacts';
7
7
  import { ListOfMeetsPage } from 'src/pages/Cooperative/ListOfMeets';
@@ -64,6 +64,21 @@ export default async function (): Promise<IWorkspaceConfig[]> {
64
64
  path: '/:coopname/connect',
65
65
  name: 'connect',
66
66
  component: markRaw(ConnectionAgreementPage),
67
+ children: [
68
+ {
69
+ path: 'completed',
70
+ name: 'installation-completed',
71
+ component: markRaw(InstallationCompletedPage),
72
+ meta: {
73
+ title: 'Установка завершена',
74
+ icon: 'fas fa-check-circle',
75
+ roles: ['user'],
76
+ conditions: 'isCoop === true && coopname === "voskhod"',
77
+ requiresAuth: true,
78
+ hidden: true,
79
+ },
80
+ },
81
+ ],
67
82
  },
68
83
  {
69
84
  meta: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coopenomics/desktop",
3
- "version": "2025.11.12-alpha-1",
3
+ "version": "2025.11.13-alpha-3",
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.12-alpha-1",
29
- "@coopenomics/notifications": "2025.11.12-alpha-1",
30
- "@coopenomics/sdk": "2025.11.12-alpha-1",
28
+ "@coopenomics/controller": "2025.11.13-alpha-3",
29
+ "@coopenomics/notifications": "2025.11.13-alpha-3",
30
+ "@coopenomics/sdk": "2025.11.13-alpha-3",
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.12-alpha-1",
62
+ "cooptypes": "2025.11.13-alpha-3",
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": "b261f505aa7897cdc82ce88ed770fe0f6aee7afc"
126
+ "gitHead": "dab94657557e501109b96a18e0e00db0c00d111e"
127
127
  }
@@ -139,14 +139,16 @@ export const useConnectionAgreementStore = defineStore(namespace, () => {
139
139
  console.log('Текущий инстанс загружен:', currentInstance.value)
140
140
  } catch (error: any) {
141
141
  currentInstanceError.value = error.message || 'Ошибка загрузки инстанса'
142
+ // Очищаем старые данные при ошибке - они больше не актуальны
143
+ currentInstance.value = null
142
144
  console.error('Ошибка при загрузке текущего инстанса:', error)
143
145
  } finally {
144
146
  currentInstanceLoading.value = false
145
147
  }
146
148
  }
147
149
 
148
- const startInstanceAutoRefresh = (intervalMs = 30000) => { // 30 секунд по умолчанию
149
- loadCurrentInstance() // Первая загрузка
150
+ const startInstanceAutoRefresh = async (intervalMs = 30000) => { // 30 секунд по умолчанию
151
+ await loadCurrentInstance() // Первая загрузка
150
152
 
151
153
  const interval = setInterval(() => {
152
154
  loadCurrentInstance()
@@ -1,134 +1,182 @@
1
1
  <template lang="pug">
2
2
  div.row.q-pa-md
3
3
  div.col-md-12.col-xs-12
4
- div(v-if="system.info.is_providered")
5
-
6
- //- Показываем дашборд если установка завершена
7
- ConnectionDashboard(
8
- v-if="isInstallationCompleted"
9
- )
10
-
11
- //- Показываем степпер если установка не завершена
12
- ConnectionAgreementStepper(v-else)
13
-
14
-
15
- div(v-else).row
16
- //- Заглушка для недоступного провайдера
17
- div.col-md-12.col-xs-12
18
- ColorCard(color="blue")
19
- .text-center.q-pa-md
20
- q-icon(name="fas fa-info-circle" size="2rem").q-mb-sm
21
- .text-h6.q-mb-md Информация о подключении
22
- p Для подключения к платформе Кооперативной Экономики обратитесь в ПК ВОСХОД.
23
- q-btn(
24
- color="primary"
25
- label="Перейти на сайт"
26
- @click="openProviderWebsite"
27
- size="md"
28
- ).q-mt-md
4
+ // Лоадер пока идет загрузка данных
5
+ WindowLoader(v-if="isLoading", text="Загрузка данных подключения...")
6
+
7
+ // Основной контент после загрузки
8
+ div(v-else)
9
+ div(v-if="system.info.is_providered")
10
+ //- Показываем дашборд если установка завершена и мы на основной странице
11
+ ConnectionDashboard(v-if="isInstallationCompleted && !isOnCompletionRoute")
12
+
13
+ //- Показываем степпер если идет процесс подключения
14
+ ConnectionAgreementStepper(v-else-if="!isOnCompletionRoute")
15
+
16
+ //- Router view для дочерних страниц (завершение установки) только на дочерних маршрутах
17
+ router-view(v-if="isOnCompletionRoute")
18
+
19
+ div(v-else).row
20
+ //- Заглушка для недоступного провайдера
21
+ div.col-md-12.col-xs-12
22
+ ColorCard(color="blue")
23
+ .text-center.q-pa-md
24
+ q-icon(name="fas fa-info-circle" size="2rem").q-mb-sm
25
+ .text-h6.q-mb-md Подключение к Кооперативной Экономике
26
+ p Для запуска вашего Цифрового Кооператива и подключения к платформе Кооперативной Экономики обратитесь в ПК ВОСХОД.
27
+ q-btn(
28
+ color="primary"
29
+ label="Перейти на сайт"
30
+ @click="openProviderWebsite"
31
+ size="md"
32
+ ).q-mt-md
29
33
 
30
34
  </template>
31
35
  <script setup lang="ts">
32
- import { computed, onMounted, onUnmounted, watch } from 'vue';
36
+ import { ref, computed, onMounted, onUnmounted, watch } from 'vue';
37
+ import { useRouter } from 'vue-router';
33
38
  import { useSystemStore } from 'src/entities/System/model';
34
39
  import { useConnectionAgreementStore } from 'src/entities/ConnectionAgreement';
35
40
  import { ConnectionAgreementStepper } from 'src/widgets/ConnectionAgreementStepper';
36
41
  import { ConnectionDashboard } from 'src/widgets/ConnectionDashboard';
37
42
  import { ColorCard } from 'src/shared/ui';
38
- import {Zeus} from '@coopenomics/sdk';
43
+ import { WindowLoader } from 'src/shared/ui/Loader';
44
+ import { Zeus } from '@coopenomics/sdk';
39
45
 
40
- const system = useSystemStore()
41
- const connectionAgreement = useConnectionAgreementStore()
46
+ const router = useRouter();
47
+ const system = useSystemStore();
48
+ const connectionAgreement = useConnectionAgreementStore();
49
+
50
+ // Лоадер состояния
51
+ const isLoading = ref(true);
42
52
 
43
53
  // Остановка автообновления при размонтировании компонента
44
- let stopInstanceRefresh: (() => void) | null = null
54
+ let stopInstanceRefresh: (() => void) | null = null;
55
+
56
+ // Редирект теперь делает только InstallationStep.vue
45
57
 
46
58
  // Проверка завершения установки
47
59
  const isInstallationCompleted = computed(() => {
48
- const instance = connectionAgreement.currentInstance
49
- return instance?.progress === 100 && instance?.status === Zeus.InstanceStatus.ACTIVE
60
+ // После загрузки данных проверяем статус установки
61
+ if (!isLoading.value) {
62
+ const instance = connectionAgreement.currentInstance;
63
+ return instance?.progress === 100 && instance?.status === Zeus.InstanceStatus.ACTIVE;
64
+ }
65
+ return false; // Во время загрузки считаем, что установка не завершена
66
+ });
67
+
68
+ // Проверка, находимся ли мы на маршруте завершения установки
69
+ const isOnCompletionRoute = computed(() => {
70
+ return router.currentRoute.value.name === 'installation-completed';
71
+ });
72
+
73
+ // Переменная для отслеживания предыдущего состояния завершения установки
74
+ let wasInstallationCompleted = false;
75
+
76
+ // Флаг для отслеживания, был ли уже показан степпер (означает, что пользователь видел процесс установки)
77
+ let hasShownStepper = false;
78
+
79
+ // Следим за завершением установки для редиректа
80
+ watch(isInstallationCompleted, (isCompleted) => {
81
+ // Редирект только при переходе из незавершенного состояния в завершенное
82
+ // и только если пользователь уже видел степпер (т.е. установка шла в реальном времени)
83
+ if (isCompleted && !wasInstallationCompleted && hasShownStepper && !isOnCompletionRoute.value) {
84
+ console.log('🎉 Установка завершена в реальном времени! → переадресация на страницу завершения')
85
+ router.push({ name: 'installation-completed' })
86
+ }
87
+ wasInstallationCompleted = isCompleted
88
+ })
89
+
90
+ // Следим за показом степпера
91
+ watch(() => !isInstallationCompleted.value && !isLoading.value && !isOnCompletionRoute.value, (isShowingStepper) => {
92
+ if (isShowingStepper) {
93
+ hasShownStepper = true
94
+ }
50
95
  })
51
96
 
52
97
  const openProviderWebsite = () => {
53
- window.open('https://цифровой-кооператив.рф', '_blank')
54
- }
98
+ window.open('https://цифровой-кооператив.рф', '_blank');
99
+ };
55
100
 
56
101
  const init = async () => {
57
102
  // Инициализация имеет смысл только если провайдер доступен
58
- if (!system.info.is_providered) return
103
+ if (!system.info.is_providered) {
104
+ isLoading.value = false;
105
+ return;
106
+ }
59
107
 
60
108
  // Инициализируем persistent store если он еще не инициализирован
61
109
  if (!connectionAgreement.isInitialized) {
62
- connectionAgreement.setInitialized(true)
110
+ connectionAgreement.setInitialized(true);
63
111
  }
64
112
 
113
+ // Запускаем автообновление инстанса каждые 30 секунд (включает начальную загрузку)
114
+ stopInstanceRefresh = await connectionAgreement.startInstanceAutoRefresh(30000);
65
115
 
66
- // Загружаем текущий инстанс
67
- await connectionAgreement.loadCurrentInstance()
68
-
69
- // Запускаем автообновление инстанса каждые 30 секунд
70
- stopInstanceRefresh = connectionAgreement.startInstanceAutoRefresh(30000)
71
- }
116
+ // Скрываем лоадер после загрузки данных
117
+ isLoading.value = false;
118
+ };
72
119
 
73
120
  // Watch за изменением currentInstance для автоматического перехода между шагами
74
- watch(() => connectionAgreement.currentInstance, (instance) => {
75
- if (!instance) return
76
-
77
- const currentStep = connectionAgreement.currentStep
78
-
79
- console.log('📊 Instance обновлен:', {
80
- step: currentStep,
81
- is_valid: instance.is_valid,
82
- is_delegated: instance.is_delegated,
83
- blockchain_status: instance.blockchain_status,
84
- progress: instance.progress,
85
- status: instance.status
86
- })
87
-
88
- // Логика автоматических переходов (только для шагов 4, 5, 6)
89
- if (currentStep === 4) {
90
- // Шаг 4: Проверка домена
91
- if (instance.is_valid && instance.is_delegated) {
92
- // Домен валиден и делегирован
121
+ watch(
122
+ () => connectionAgreement.currentInstance,
123
+ (instance) => {
124
+ // Не обрабатываем изменения если идет загрузка или есть ошибка
125
+ if (connectionAgreement.currentInstanceLoading || connectionAgreement.currentInstanceError) {
126
+ return;
127
+ }
128
+
129
+ if (!instance) return;
130
+
131
+ const currentStep = connectionAgreement.currentStep;
132
+
133
+ console.log('📊 Instance обновлен:', {
134
+ step: currentStep,
135
+ is_valid: instance.is_valid,
136
+ is_delegated: instance.is_delegated,
137
+ blockchain_status: instance.blockchain_status,
138
+ progress: instance.progress,
139
+ status: instance.status,
140
+ });
141
+
142
+ // Логика автоматических переходов (только для шагов 4, 5, 6)
143
+ if (currentStep === 4) {
144
+ // Шаг 4: Проверка домена
145
+ if (instance.is_valid && instance.is_delegated) {
146
+ // Домен валиден и делегирован
147
+ if (instance.blockchain_status === 'active') {
148
+ // Можно переходить сразу к установке
149
+ console.log('✅ Домен готов и blockchain_status активен → переход к шагу 6');
150
+ connectionAgreement.setCurrentStep(6);
151
+ } else {
152
+ // Ожидаем подтверждения от союза
153
+ console.log('⏳ Домен готов, но ожидаем подтверждения → переход к шагу 5');
154
+ connectionAgreement.setCurrentStep(5);
155
+ }
156
+ }
157
+ } else if (currentStep === 5) {
158
+ // Шаг 5: Ожидание подтверждения от союза
93
159
  if (instance.blockchain_status === 'active') {
94
- // Можно переходить сразу к установке
95
- console.log('✅ Домен готов и blockchain_status активен → переход к шагу 6')
96
- connectionAgreement.setCurrentStep(6)
97
- } else {
98
- // Ожидаем подтверждения от союза
99
- console.log('⏳ Домен готов, но ожидаем подтверждения → переход к шагу 5')
100
- connectionAgreement.setCurrentStep(5)
160
+ console.log('✅ Подтверждение получено переход к шагу 6');
161
+ connectionAgreement.setCurrentStep(6);
101
162
  }
102
163
  }
103
- } else if (currentStep === 5) {
104
- // Шаг 5: Ожидание подтверждения от союза
105
- if (instance.blockchain_status === 'active') {
106
- console.log('✅ Подтверждение получено → переход к шагу 6')
107
- connectionAgreement.setCurrentStep(6)
108
- }
109
- } else if (currentStep === 6) {
110
- // Шаг 6: Установка
111
- if (instance.progress === 100 && instance.status === Zeus.InstanceStatus.ACTIVE) {
112
- console.log('🎉 Установка завершена!')
113
- // Не переходим автоматически, просто покажется дашборд через computed
114
- }
115
- }
116
- }, { deep: true })
164
+ // Редирект на страницу завершения теперь делает только InstallationStep.vue
165
+ },
166
+ { deep: true }
167
+ );
117
168
 
118
169
  // Lifecycle хуки
119
170
  onMounted(() => {
120
- // Если провайдер доступен - делаем полную инициализацию
121
- if (system.info.is_providered) {
122
- init()
123
- }
124
- // Если провайдер недоступен - ничего не делаем, показываем заглушку
125
- })
171
+ // Делаем инициализацию при монтировании компонента
172
+ init();
173
+ });
126
174
 
127
175
  onUnmounted(() => {
128
176
  // Останавливаем автообновление инстанса при размонтировании компонента
129
177
  if (stopInstanceRefresh) {
130
- stopInstanceRefresh()
131
- stopInstanceRefresh = null
178
+ stopInstanceRefresh();
179
+ stopInstanceRefresh = null;
132
180
  }
133
- })
181
+ });
134
182
  </script>
@@ -0,0 +1,221 @@
1
+ <template lang="pug">
2
+ div.row.q-pa-md
3
+ div.col-md-12.col-xs-12
4
+ .completion-container
5
+ .completion-card
6
+ .completion-header
7
+ .celebration-icon
8
+ q-icon(name="celebration" color="positive" size="80px")
9
+ .sparkle.sparkle-1
10
+ .sparkle.sparkle-2
11
+ .sparkle.sparkle-3
12
+ .completion-title.text-h5.text-positive.q-mt-lg Установка завершена!
13
+ .completion-subtitle.text-body1.text-grey-7.q-mt-sm
14
+ | Ваш Цифровой Кооператив успешно развернут и подключен к платформе
15
+
16
+ .completion-details.q-mt-xl
17
+ .detail-item
18
+ q-icon(name="check_circle" color="positive" size="24px").q-mr-md
19
+ .detail-text
20
+ .text-body2.text-weight-medium Серверная инфраструктура
21
+ .text-caption.text-grey-6 Полностью настроена и оптимизирована
22
+
23
+ .detail-item.q-mt-md
24
+ q-icon(name="check_circle" color="positive" size="24px").q-mr-md
25
+ .detail-text
26
+ .text-body2.text-weight-medium Блокчейн-узел
27
+ .text-caption.text-grey-6 Развернут, синхронизирован и подключен к сети
28
+
29
+ .detail-item.q-mt-md
30
+ q-icon(name="check_circle" color="positive" size="24px").q-mr-md
31
+ .detail-text
32
+ .text-body2.text-weight-medium Базы данных
33
+ .text-caption.text-grey-6 Инициализированы и готовы к работе
34
+
35
+ .detail-item.q-mt-md
36
+ q-icon(name="check_circle" color="positive" size="24px").q-mr-md
37
+ .detail-text
38
+ .text-body2.text-weight-medium Сервисы кооператива
39
+ .text-caption.text-grey-6 Запущены и функционируют
40
+
41
+ .next-steps.q-mt-xl
42
+ .text-subtitle2.text-weight-medium.q-mb-md Что дальше?
43
+ .text-body2.text-grey-8.q-mb-lg
44
+ | Для завершения настройки необходимо выполнить финальную конфигурацию на сайте вашего Цифрового Кооператива. Нажмите кнопку ниже, чтобы перейти к управлению подключением, где сможете просматривать статус подключения, управлять подписками и настраивать параметры платформы.
45
+
46
+ q-btn(
47
+ color="primary"
48
+ label="Перейти к управлению подключением"
49
+ @click="goToDashboard"
50
+ size="lg"
51
+ unelevated
52
+ no-caps
53
+ ).q-mt-md
54
+ </template>
55
+
56
+ <script setup lang="ts">
57
+ import { useRouter } from 'vue-router'
58
+
59
+ const router = useRouter()
60
+
61
+ const goToDashboard = () => {
62
+ router.push({ name: 'connect' })
63
+ }
64
+ </script>
65
+
66
+ <style scoped>
67
+ .completion-container {
68
+ display: flex;
69
+ justify-content: center;
70
+ align-items: center;
71
+ min-height: 80vh;
72
+ padding: 2rem 0;
73
+ }
74
+
75
+ .completion-card {
76
+ max-width: 600px;
77
+ width: 100%;
78
+ text-align: center;
79
+ padding: 3rem;
80
+ border-radius: 24px;
81
+ border: 1px solid rgba(76, 175, 80, 0.1);
82
+ box-shadow:
83
+ 0 12px 40px rgba(0, 0, 0, 0.08),
84
+ 0 4px 16px rgba(0, 0, 0, 0.04);
85
+ position: relative;
86
+ overflow: hidden;
87
+ }
88
+
89
+ .completion-card::before {
90
+ content: '';
91
+ position: absolute;
92
+ top: 0;
93
+ left: 0;
94
+ right: 0;
95
+ height: 4px;
96
+ background: linear-gradient(90deg, var(--q-positive) 0%, #4CAF50 50%, var(--q-positive) 100%);
97
+ background-size: 200% 100%;
98
+ animation: completion-shimmer 3s cubic-bezier(0.25, 0.46, 0.45, 0.94) infinite;
99
+ }
100
+
101
+ @keyframes completion-shimmer {
102
+ 0%, 100% { background-position: -100% 0; }
103
+ 50% { background-position: 100% 0; }
104
+ }
105
+
106
+ .completion-header {
107
+ position: relative;
108
+ }
109
+
110
+ .celebration-icon {
111
+ position: relative;
112
+ display: inline-block;
113
+ margin-bottom: 1rem;
114
+ }
115
+
116
+ .sparkle {
117
+ position: absolute;
118
+ width: 8px;
119
+ height: 8px;
120
+ background: var(--q-positive);
121
+ border-radius: 50%;
122
+ animation: sparkle 2s infinite ease-in-out;
123
+ }
124
+
125
+ .sparkle-1 {
126
+ top: -10px;
127
+ right: -10px;
128
+ animation-delay: 0s;
129
+ }
130
+
131
+ .sparkle-2 {
132
+ top: 20px;
133
+ left: -15px;
134
+ animation-delay: 0.5s;
135
+ }
136
+
137
+ .sparkle-3 {
138
+ bottom: -5px;
139
+ right: 15px;
140
+ animation-delay: 1s;
141
+ }
142
+
143
+ @keyframes sparkle {
144
+ 0%, 100% {
145
+ opacity: 0;
146
+ transform: scale(0);
147
+ }
148
+ 50% {
149
+ opacity: 1;
150
+ transform: scale(1);
151
+ }
152
+ }
153
+
154
+ .completion-title {
155
+ font-weight: 700;
156
+ letter-spacing: -0.5px;
157
+ margin-bottom: 0.5rem;
158
+ background: linear-gradient(135deg, var(--q-positive) 0%, #4CAF50 100%);
159
+ -webkit-background-clip: text;
160
+ -webkit-text-fill-color: transparent;
161
+ background-clip: text;
162
+ text-shadow: 0 2px 4px rgba(76, 175, 80, 0.3);
163
+ }
164
+
165
+ .completion-details {
166
+ margin-top: 2rem;
167
+ text-align: left;
168
+ }
169
+
170
+ .detail-item {
171
+ display: flex;
172
+ align-items: center;
173
+ padding: 1rem;
174
+ background: rgba(76, 175, 80, 0.02);
175
+ border-radius: 12px;
176
+ border: 1px solid rgba(76, 175, 80, 0.1);
177
+ transition: all 0.3s ease;
178
+ }
179
+
180
+ .detail-item:hover {
181
+ transform: translateX(4px);
182
+ background: rgba(76, 175, 80, 0.05);
183
+ box-shadow: 0 4px 12px rgba(76, 175, 80, 0.1);
184
+ }
185
+
186
+ .detail-text {
187
+ margin-left: 1rem;
188
+ }
189
+
190
+ .next-steps {
191
+ margin-top: 2rem;
192
+ text-align: left;
193
+ padding: 1.5rem;
194
+ background: rgba(0, 0, 0, 0.02);
195
+ border-radius: 12px;
196
+ }
197
+
198
+ /* Адаптивность */
199
+ @media (max-width: 768px) {
200
+ .completion-card {
201
+ padding: 2rem;
202
+ }
203
+
204
+ .detail-item {
205
+ flex-direction: column;
206
+ text-align: center;
207
+ gap: 0.5rem;
208
+ }
209
+
210
+ .completion-container {
211
+ min-height: 70vh;
212
+ padding: 1rem 0;
213
+ }
214
+ }
215
+
216
+ @media (max-width: 480px) {
217
+ .completion-card {
218
+ padding: 1.5rem;
219
+ }
220
+ }
221
+ </style>
@@ -1 +1,2 @@
1
1
  export {default as ConnectionAgreementPage} from './ConnectionAgreementPage.vue'
2
+ export {default as InstallationCompletedPage} from './InstallationCompletedPage.vue'
@@ -83,7 +83,7 @@ const handleBack = () => {
83
83
  <template lang="pug">
84
84
  q-step(
85
85
  :name="3"
86
- title="Соглашение о подключении"
86
+ title="Соглашение о подключении к платформе"
87
87
  icon="description"
88
88
  :done="isDone"
89
89
  )