@coopenomics/desktop 2025.11.13-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.13-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.13-alpha-1",
29
- "@coopenomics/notifications": "2025.11.13-alpha-1",
30
- "@coopenomics/sdk": "2025.11.13-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.13-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": "d0f73c32bb68d8f7451ecef3989bdff4629d71c4"
126
+ "gitHead": "dab94657557e501109b96a18e0e00db0c00d111e"
127
127
  }
@@ -147,8 +147,8 @@ export const useConnectionAgreementStore = defineStore(namespace, () => {
147
147
  }
148
148
  }
149
149
 
150
- const startInstanceAutoRefresh = (intervalMs = 30000) => { // 30 секунд по умолчанию
151
- loadCurrentInstance() // Первая загрузка
150
+ const startInstanceAutoRefresh = async (intervalMs = 30000) => { // 30 секунд по умолчанию
151
+ await loadCurrentInstance() // Первая загрузка
152
152
 
153
153
  const interval = setInterval(() => {
154
154
  loadCurrentInstance()
@@ -1,144 +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
- // Не показываем поздравление если идет загрузка или есть ошибка
49
- if (connectionAgreement.currentInstanceLoading || connectionAgreement.currentInstanceError) {
50
- return false
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' })
51
86
  }
87
+ wasInstallationCompleted = isCompleted
88
+ })
52
89
 
53
- const instance = connectionAgreement.currentInstance
54
- return instance?.progress === 100 && instance?.status === Zeus.InstanceStatus.ACTIVE
90
+ // Следим за показом степпера
91
+ watch(() => !isInstallationCompleted.value && !isLoading.value && !isOnCompletionRoute.value, (isShowingStepper) => {
92
+ if (isShowingStepper) {
93
+ hasShownStepper = true
94
+ }
55
95
  })
56
96
 
57
97
  const openProviderWebsite = () => {
58
- window.open('https://цифровой-кооператив.рф', '_blank')
59
- }
98
+ window.open('https://цифровой-кооператив.рф', '_blank');
99
+ };
60
100
 
61
101
  const init = async () => {
62
102
  // Инициализация имеет смысл только если провайдер доступен
63
- if (!system.info.is_providered) return
103
+ if (!system.info.is_providered) {
104
+ isLoading.value = false;
105
+ return;
106
+ }
64
107
 
65
108
  // Инициализируем persistent store если он еще не инициализирован
66
109
  if (!connectionAgreement.isInitialized) {
67
- connectionAgreement.setInitialized(true)
110
+ connectionAgreement.setInitialized(true);
68
111
  }
69
112
 
113
+ // Запускаем автообновление инстанса каждые 30 секунд (включает начальную загрузку)
114
+ stopInstanceRefresh = await connectionAgreement.startInstanceAutoRefresh(30000);
70
115
 
71
- // Загружаем текущий инстанс
72
- await connectionAgreement.loadCurrentInstance()
73
-
74
- // Запускаем автообновление инстанса каждые 30 секунд
75
- stopInstanceRefresh = connectionAgreement.startInstanceAutoRefresh(30000)
76
- }
116
+ // Скрываем лоадер после загрузки данных
117
+ isLoading.value = false;
118
+ };
77
119
 
78
120
  // Watch за изменением currentInstance для автоматического перехода между шагами
79
- watch(() => connectionAgreement.currentInstance, (instance) => {
80
- // Не обрабатываем изменения если идет загрузка или есть ошибка
81
- if (connectionAgreement.currentInstanceLoading || connectionAgreement.currentInstanceError) {
82
- return
83
- }
84
-
85
- if (!instance) return
86
-
87
- const currentStep = connectionAgreement.currentStep
88
-
89
- console.log('📊 Instance обновлен:', {
90
- step: currentStep,
91
- is_valid: instance.is_valid,
92
- is_delegated: instance.is_delegated,
93
- blockchain_status: instance.blockchain_status,
94
- progress: instance.progress,
95
- status: instance.status
96
- })
121
+ watch(
122
+ () => connectionAgreement.currentInstance,
123
+ (instance) => {
124
+ // Не обрабатываем изменения если идет загрузка или есть ошибка
125
+ if (connectionAgreement.currentInstanceLoading || connectionAgreement.currentInstanceError) {
126
+ return;
127
+ }
97
128
 
98
- // Логика автоматических переходов (только для шагов 4, 5, 6)
99
- if (currentStep === 4) {
100
- // Шаг 4: Проверка домена
101
- if (instance.is_valid && instance.is_delegated) {
102
- // Домен валиден и делегирован
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: Ожидание подтверждения от союза
103
159
  if (instance.blockchain_status === 'active') {
104
- // Можно переходить сразу к установке
105
- console.log('✅ Домен готов и blockchain_status активен → переход к шагу 6')
106
- connectionAgreement.setCurrentStep(6)
107
- } else {
108
- // Ожидаем подтверждения от союза
109
- console.log('⏳ Домен готов, но ожидаем подтверждения → переход к шагу 5')
110
- connectionAgreement.setCurrentStep(5)
160
+ console.log('✅ Подтверждение получено переход к шагу 6');
161
+ connectionAgreement.setCurrentStep(6);
111
162
  }
112
163
  }
113
- } else if (currentStep === 5) {
114
- // Шаг 5: Ожидание подтверждения от союза
115
- if (instance.blockchain_status === 'active') {
116
- console.log('✅ Подтверждение получено → переход к шагу 6')
117
- connectionAgreement.setCurrentStep(6)
118
- }
119
- } else if (currentStep === 6) {
120
- // Шаг 6: Установка
121
- if (instance.progress === 100 && instance.status === Zeus.InstanceStatus.ACTIVE) {
122
- console.log('🎉 Установка завершена!')
123
- // Не переходим автоматически, просто покажется дашборд через computed
124
- }
125
- }
126
- }, { deep: true })
164
+ // Редирект на страницу завершения теперь делает только InstallationStep.vue
165
+ },
166
+ { deep: true }
167
+ );
127
168
 
128
169
  // Lifecycle хуки
129
170
  onMounted(() => {
130
- // Если провайдер доступен - делаем полную инициализацию
131
- if (system.info.is_providered) {
132
- init()
133
- }
134
- // Если провайдер недоступен - ничего не делаем, показываем заглушку
135
- })
171
+ // Делаем инициализацию при монтировании компонента
172
+ init();
173
+ });
136
174
 
137
175
  onUnmounted(() => {
138
176
  // Останавливаем автообновление инстанса при размонтировании компонента
139
177
  if (stopInstanceRefresh) {
140
- stopInstanceRefresh()
141
- stopInstanceRefresh = null
178
+ stopInstanceRefresh();
179
+ stopInstanceRefresh = null;
142
180
  }
143
- })
181
+ });
144
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
  )
@@ -5,46 +5,38 @@
5
5
  icon="schedule"
6
6
  :done="isDone"
7
7
  )
8
- .q-pa-md
9
- //- Успех - готово к установке
10
- .flex.column.items-center.q-pa-lg
11
- q-icon(name="check_circle" color="positive" size="64px").q-mb-md
12
- .text-h6.text-center.q-mb-md Техническая подготовка завершена
13
- .text-body1.text-center.text-grey-7.q-mb-xl
14
- | Ваш кооператив готов к установке
15
-
16
- //- Информационная карточка
17
- q-card(flat).q-mb-lg.bg-grey-1
18
- q-card-section.q-pa-lg
19
- .text-subtitle2.q-mb-md.text-weight-medium Ожидание подтверждения
20
- .text-body2.text-grey-8.q-mb-lg
21
- | Все готово к установке, но мы ожидаем поступления подтверждения от союза о вашем членстве.
22
-
23
- .text-body2.text-grey-7.q-mb-md
24
- | Как только союз подтвердит ваше членство, статус изменится автоматически и установка начнется.
25
-
26
- .text-body2.text-grey-7
27
- | Приблизительное время установки после получения подтверждения:
28
- strong.text-primary 60 минут
29
-
30
- //- Статус подтверждения
31
- .flex.justify-center.q-mb-lg
32
- q-chip(
33
- :color="getBlockchainStatusColor"
34
- text-color="white"
35
- size="md"
36
- :icon="instance?.blockchain_status === 'active' ? 'check_circle' : 'schedule'"
37
- )
38
- span {{ getBlockchainStatusText }}
39
-
40
- //- Навигация
41
- q-stepper-navigation.q-gutter-sm
42
- q-btn(
43
- color="grey-6"
44
- flat
45
- label="Назад"
46
- @click="handleBack"
47
- )
8
+ .approval-waiting-container.q-pa-md
9
+
10
+ //- Основная карточка ожидания
11
+ .waiting-card.bg-surface.q-mb-xl
12
+ .waiting-header
13
+ .waiting-icon-container
14
+ q-icon.waiting-icon(
15
+ :name="getWaitingIcon"
16
+ :color="getWaitingIconColor"
17
+ size="80px"
18
+ @click="refreshStatus"
19
+ clickable
20
+ )
21
+ .pulse-ring(v-if="instance?.blockchain_status !== 'active'")
22
+ .waiting-title.text-h5.text-weight-medium.text-primary Ожидание подтверждения союза
23
+
24
+ //- Статусная информация
25
+ .status-info.q-mt-lg
26
+ .status-description.text-body1.text-on-surface
27
+ | Все технические подготовки завершены. Ваш Цифровой Кооператив готов к установке и подключению к платформе Кооперативной Экономики.
28
+ br
29
+ | Теперь мы ожидаем официального подтверждения от союза кооперативов о вашем членстве.
30
+
31
+
32
+ //- Навигация
33
+ q-stepper-navigation.q-gutter-sm
34
+ q-btn(
35
+ color="grey-6"
36
+ flat
37
+ label="Назад"
38
+ @click="handleBack"
39
+ )
48
40
  </template>
49
41
 
50
42
  <script setup lang="ts">
@@ -61,21 +53,181 @@ const instance = computed(() => connectionAgreement.currentInstance)
61
53
 
62
54
  const isDone = computed(() => props.isDone)
63
55
 
64
- // Цвет статуса блокчейна
65
- const getBlockchainStatusColor = computed(() => {
66
- if (instance.value?.blockchain_status === 'active') return 'positive'
67
- return 'info'
56
+ // Иконка ожидания
57
+ const getWaitingIcon = computed(() => {
58
+ if (instance.value?.blockchain_status === 'active') return 'check_circle'
59
+ return 'schedule'
68
60
  })
69
61
 
70
- // Текст статуса блокчейна
71
- const getBlockchainStatusText = computed(() => {
72
- if (instance.value?.blockchain_status === 'active') return 'Подтверждено'
73
- if (instance.value?.blockchain_status === 'pending') return 'Ожидание подтверждения'
74
- return 'Не подтверждено'
62
+ // Цвет иконки ожидания
63
+ const getWaitingIconColor = computed(() => {
64
+ if (instance.value?.blockchain_status === 'active') return 'positive'
65
+ return 'warning'
75
66
  })
76
67
 
68
+ // Функция обновления статуса
69
+ const refreshStatus = async () => {
70
+ try {
71
+ await connectionAgreement.loadCurrentInstance()
72
+ } catch (error) {
73
+ console.error('Ошибка обновления статуса:', error)
74
+ }
75
+ }
76
+
77
77
  const handleBack = () => {
78
- connectionAgreement.setCurrentStep(2)
78
+ connectionAgreement.setCurrentStep(4)
79
79
  }
80
80
  </script>
81
81
 
82
+ <style scoped>
83
+ .approval-waiting-container {
84
+ max-width: 900px;
85
+ margin: 0 auto;
86
+ position: relative;
87
+ }
88
+
89
+ /* Основная карточка ожидания */
90
+ .waiting-card {
91
+ border-radius: 20px;
92
+ padding: 2.5rem;
93
+ box-shadow:
94
+ 0 8px 32px rgba(0, 0, 0, 0.08),
95
+ 0 2px 8px rgba(0, 0, 0, 0.04);
96
+ position: relative;
97
+ overflow: hidden;
98
+ }
99
+
100
+ .waiting-card::before {
101
+ content: '';
102
+ position: absolute;
103
+ top: 0;
104
+ left: 0;
105
+ right: 0;
106
+ height: 4px;
107
+ background: linear-gradient(90deg, var(--q-primary) 0%, var(--q-secondary) 50%, var(--q-primary) 100%);
108
+ background-size: 200% 100%;
109
+ animation: shimmer 4s cubic-bezier(0.25, 0.46, 0.45, 0.94) infinite;
110
+ }
111
+
112
+ @keyframes shimmer {
113
+ 0% { background-position: -100% 0; }
114
+ 100% { background-position: 100% 0; }
115
+ }
116
+
117
+ /* Заголовок карточки */
118
+ .waiting-header {
119
+ text-align: center;
120
+ margin-bottom: 2rem;
121
+ }
122
+
123
+ .waiting-icon-container {
124
+ position: relative;
125
+ display: inline-block;
126
+ margin-bottom: 1.5rem;
127
+ }
128
+
129
+ .waiting-icon {
130
+ filter: drop-shadow(0 4px 12px rgba(0, 0, 0, 0.15));
131
+ animation: gentle-pulse 3s ease-in-out infinite;
132
+ cursor: pointer;
133
+ transition: all 0.3s ease;
134
+ }
135
+
136
+ .waiting-icon:hover {
137
+ transform: scale(1.1);
138
+ filter: drop-shadow(0 6px 20px rgba(0, 0, 0, 0.25));
139
+ }
140
+
141
+ @keyframes gentle-pulse {
142
+ 0%, 100% {
143
+ transform: scale(1);
144
+ opacity: 1;
145
+ }
146
+ 50% {
147
+ transform: scale(1.05);
148
+ opacity: 0.9;
149
+ }
150
+ }
151
+
152
+ .pulse-ring {
153
+ position: absolute;
154
+ top: 50%;
155
+ left: 50%;
156
+ transform: translate(-50%, -50%);
157
+ width: 90px;
158
+ height: 90px;
159
+ border: 1px solid rgba(255, 152, 0, 0.2);
160
+ border-radius: 50%;
161
+ animation: pulse-ring 2s cubic-bezier(0.455, 0.03, 0.515, 0.955) infinite;
162
+ }
163
+
164
+ @keyframes pulse-ring {
165
+ 0% {
166
+ transform: translate(-50%, -50%) scale(0.8);
167
+ opacity: 1;
168
+ }
169
+ 100% {
170
+ transform: translate(-50%, -50%) scale(1.4);
171
+ opacity: 0;
172
+ }
173
+ }
174
+
175
+ .waiting-title {
176
+ font-weight: 700;
177
+ letter-spacing: -0.5px;
178
+ }
179
+
180
+ /* Статусная информация */
181
+ .status-info {
182
+ padding: 1.5rem;
183
+ border-radius: 16px;
184
+ border: 1px solid rgba(255, 152, 0, 0.1);
185
+ }
186
+
187
+ .status-description {
188
+ line-height: 1.6;
189
+ text-align: center;
190
+ }
191
+
192
+
193
+
194
+
195
+ /* Адаптивность */
196
+ @media (max-width: 768px) {
197
+ .waiting-card {
198
+ padding: 2rem;
199
+ }
200
+
201
+
202
+
203
+ .pulse-ring {
204
+ width: 70px;
205
+ height: 70px;
206
+ }
207
+ }
208
+
209
+ @media (max-width: 480px) {
210
+ .approval-waiting-container {
211
+ padding: 1rem;
212
+ }
213
+
214
+ .waiting-card {
215
+ padding: 1.5rem;
216
+ }
217
+
218
+ .waiting-icon {
219
+ font-size: 60px;
220
+ }
221
+
222
+ .pulse-ring {
223
+ width: 60px;
224
+ height: 60px;
225
+ }
226
+
227
+ .status-info {
228
+ padding: 1rem;
229
+ }
230
+
231
+ }
232
+ </style>
233
+
@@ -55,7 +55,7 @@
55
55
  span.q-ml-xs {{ instance?.is_delegated ? 'Делегирован' : 'Ожидаем делегирования' }}
56
56
 
57
57
  .instruction-footer
58
- | Платформа автоматически проверит домен и активирует подключение
58
+ | Платформа Кооперативной Экономики автоматически проверит домен и активирует подключение вашего Цифрового Кооператива
59
59
 
60
60
  //- Навигация
61
61
  q-stepper-navigation.q-gutter-sm
@@ -206,12 +206,12 @@ const copyIpAddress = async () => {
206
206
  height: 3px;
207
207
  background: linear-gradient(90deg, #2196F3 0%, #21CBF3 50%, #2196F3 100%);
208
208
  background-size: 200% 100%;
209
- animation: shimmer 3s ease-in-out infinite;
209
+ animation: shimmer 3s cubic-bezier(0.25, 0.46, 0.45, 0.94) infinite;
210
210
  }
211
211
 
212
212
  @keyframes shimmer {
213
- 0% { background-position: -200% 0; }
214
- 100% { background-position: 200% 0; }
213
+ 0% { background-position: -100% 0; }
214
+ 100% { background-position: 100% 0; }
215
215
  }
216
216
 
217
217
  .instruction-header {
@@ -35,7 +35,7 @@ const handleBack = () => {
35
35
  <template lang="pug">
36
36
  q-step(
37
37
  :name="2"
38
- title="Сбор данных"
38
+ title="Параметры кооператива"
39
39
  icon="settings"
40
40
  :done="isDone"
41
41
  )
@@ -1,20 +1,20 @@
1
1
  <template lang="pug">
2
2
  q-step(
3
3
  :name="6"
4
- title="Установка платформы"
4
+ title="Установка Цифрового Кооператива"
5
5
  icon="cloud_download"
6
6
  :done="isDone"
7
7
  )
8
8
  .installation-container.q-pa-md
9
9
 
10
10
  //- Установка в процессе
11
- div(v-if="instance?.progress < 100")
12
-
11
+ div
13
12
  //- Заголовок с градиентом
13
+
14
14
  .installation-header
15
- .text-h6.installation-title Установка платформы
15
+ .text-h6.installation-title Установка Цифрового Кооператива
16
16
  .subtitle.text-body2.text-grey-7.q-mt-sm
17
- | Создание кооперативной цифровой экосистемы
17
+ | Подключение к платформе Кооперативной Экономики
18
18
 
19
19
  //- Основная карточка прогресса
20
20
  .progress-card.q-mb-xl
@@ -48,49 +48,6 @@
48
48
  .stage-description.text-body2.text-grey-7.q-mt-xs {{ currentStageDescription }}
49
49
 
50
50
 
51
- //- Установка завершена
52
- div(v-else)
53
- .completion-container
54
- .completion-card
55
- .completion-header
56
- .celebration-icon
57
- q-icon(name="celebration" color="positive" size="80px")
58
- .sparkle.sparkle-1
59
- .sparkle.sparkle-2
60
- .sparkle.sparkle-3
61
- .completion-title.text-h5.text-positive.q-mt-lg Установка завершена!
62
- .completion-subtitle.text-body1.text-grey-7.q-mt-sm
63
- | Ваш кооператив успешно развернут и готов к работе
64
-
65
- .completion-details.q-mt-xl
66
- .detail-item
67
- q-icon(name="check_circle" color="positive" size="24px").q-mr-md
68
- .detail-text
69
- .text-body2.text-weight-medium Серверная инфраструктура
70
- .text-caption.text-grey-6 Полностью настроена и оптимизирована
71
-
72
- .detail-item.q-mt-md
73
- q-icon(name="check_circle" color="positive" size="24px").q-mr-md
74
- .detail-text
75
- .text-body2.text-weight-medium Блокчейн интеграция
76
- .text-caption.text-grey-6 Подключена и протестирована
77
-
78
- .detail-item.q-mt-md
79
- q-icon(name="check_circle" color="positive" size="24px").q-mr-md
80
- .detail-text
81
- .text-body2.text-weight-medium База данных
82
- .text-caption.text-grey-6 Инициализирована и готова к работе
83
-
84
- .detail-item.q-mt-md
85
- q-icon(name="check_circle" color="positive" size="24px").q-mr-md
86
- .detail-text
87
- .text-body2.text-weight-medium Платформенные сервисы
88
- .text-caption.text-grey-6 Запущены и функционируют
89
-
90
- .next-steps.q-mt-xl
91
- .text-subtitle2.text-weight-medium.q-mb-md Что дальше?
92
- .text-body2.text-grey-8
93
- | Дашборд подключения откроется автоматически через несколько секунд. Здесь вы сможете управлять подписками, просматривать баланс кошелька AXON и настраивать параметры платформы.
94
51
 
95
52
  </template>
96
53
 
@@ -117,45 +74,50 @@ const currentStageInfo = computed(() => {
117
74
  icon: 'settings',
118
75
  color: 'primary',
119
76
  title: 'Подготовка серверного окружения',
120
- description: 'Настраиваем инфраструктуру для развертывания платформы'
77
+ description: 'Настраиваем инфраструктуру, разворачиваем серверные компоненты и настраиваем файервол'
121
78
  }
122
79
  } else if (progress < 40) {
123
80
  return {
124
81
  icon: 'download',
125
82
  color: 'info',
126
- title: 'Загрузка компонентов платформы',
127
- description: 'Устанавливаем необходимые компоненты и зависимости'
83
+ title: 'Загрузка компонентов Цифрового Кооператива',
84
+ description: 'Устанавливаем программное обеспечение и зависимости для работы платформы'
128
85
  }
129
86
  } else if (progress < 60) {
130
87
  return {
131
88
  icon: 'storage',
132
89
  color: 'warning',
133
- title: 'Настройка базы данных и хранилищ',
134
- description: 'Инициализируем базы данных и настраиваем хранилища'
90
+ title: 'Настройка баз данных и хранилищ',
91
+ description: 'Разворачиваем базы данных, инициализируем структуры и настраиваем резервное копирование'
135
92
  }
136
93
  } else if (progress < 80) {
137
94
  return {
138
95
  icon: 'security',
139
96
  color: 'secondary',
140
- title: 'Конфигурация блокчейн-интеграции',
141
- description: 'Подключаем и тестируем блокчейн функциональность'
97
+ title: 'Запуск блокчейн-узла',
98
+ description: 'Разворачиваем и синхронизируем блокчейн-узел для подключения к Кооперативной Экономике'
142
99
  }
143
100
  } else {
144
101
  return {
145
102
  icon: 'check_circle',
146
103
  color: 'positive',
147
104
  title: 'Финализация установки',
148
- description: 'Выполняем заключительные настройки и тестирование'
105
+ description: 'Выполняем заключительные настройки, проверяем работоспособность всех компонентов'
149
106
  }
150
107
  }
151
108
  })
152
109
 
110
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
153
111
  const currentStageIcon = computed(() => currentStageInfo.value.icon)
112
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
154
113
  const currentStageColor = computed(() => currentStageInfo.value.color)
114
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
155
115
  const currentStageTitle = computed(() => currentStageInfo.value.title)
116
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
156
117
  const currentStageDescription = computed(() => currentStageInfo.value.description)
157
118
 
158
119
  // Расчет оставшегося времени (общая установка 100 минут)
120
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
159
121
  const remainingTime = computed(() => {
160
122
  const progress = instance.value?.progress || 0
161
123
  const totalMinutes = 100
@@ -163,12 +125,8 @@ const remainingTime = computed(() => {
163
125
  return Math.max(0, remaining) // Не показываем отрицательные значения
164
126
  })
165
127
 
166
- // Реактивно следим за изменениями прогресса
167
- import { watch } from 'vue'
168
-
169
- watch(() => instance.value?.progress, () => {
170
- // Ничего не делаем, просто реактивно обновляем отображение
171
- }, { immediate: true })
128
+ // Редирект теперь обрабатывается в ConnectionAgreementPage через реактивность
129
+ // Здесь только отображение прогресса
172
130
  </script>
173
131
 
174
132
  <style scoped>
@@ -198,7 +156,6 @@ watch(() => instance.value?.progress, () => {
198
156
  .progress-card {
199
157
  border-radius: 20px;
200
158
  padding: 2.5rem;
201
- background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
202
159
  border: 1px solid rgba(0, 0, 0, 0.05);
203
160
  box-shadow:
204
161
  0 8px 32px rgba(0, 0, 0, 0.08),
@@ -216,12 +173,12 @@ watch(() => instance.value?.progress, () => {
216
173
  height: 4px;
217
174
  background: linear-gradient(90deg, var(--q-primary) 0%, var(--q-secondary) 50%, var(--q-accent) 100%);
218
175
  background-size: 200% 100%;
219
- animation: shimmer 4s ease-in-out infinite;
176
+ animation: shimmer 4s cubic-bezier(0.25, 0.46, 0.45, 0.94) infinite;
220
177
  }
221
178
 
222
179
  @keyframes shimmer {
223
- 0% { background-position: -200% 0; }
224
- 100% { background-position: 200% 0; }
180
+ 0% { background-position: 100% 0; }
181
+ 100% { background-position: -100% 0; }
225
182
  }
226
183
 
227
184
  .progress-header {
@@ -371,138 +328,6 @@ watch(() => instance.value?.progress, () => {
371
328
  }
372
329
 
373
330
 
374
- /* Экран завершения */
375
- .completion-container {
376
- display: flex;
377
- justify-content: center;
378
- align-items: center;
379
- min-height: 500px;
380
- }
381
-
382
- .completion-card {
383
- max-width: 600px;
384
- width: 100%;
385
- text-align: center;
386
- padding: 3rem;
387
- border-radius: 24px;
388
- background: linear-gradient(135deg, #ffffff 0%, #f8fff9 100%);
389
- border: 1px solid rgba(76, 175, 80, 0.1);
390
- box-shadow:
391
- 0 12px 40px rgba(0, 0, 0, 0.08),
392
- 0 4px 16px rgba(0, 0, 0, 0.04);
393
- position: relative;
394
- overflow: hidden;
395
- }
396
-
397
- .completion-card::before {
398
- content: '';
399
- position: absolute;
400
- top: 0;
401
- left: 0;
402
- right: 0;
403
- height: 4px;
404
- background: linear-gradient(90deg, var(--q-positive) 0%, #4CAF50 50%, var(--q-positive) 100%);
405
- background-size: 200% 100%;
406
- animation: completion-shimmer 3s ease-in-out infinite;
407
- }
408
-
409
- @keyframes completion-shimmer {
410
- 0%, 100% { background-position: -200% 0; }
411
- 50% { background-position: 200% 0; }
412
- }
413
-
414
- .completion-header {
415
- position: relative;
416
- }
417
-
418
- .celebration-icon {
419
- position: relative;
420
- display: inline-block;
421
- margin-bottom: 1rem;
422
- }
423
-
424
- .sparkle {
425
- position: absolute;
426
- width: 8px;
427
- height: 8px;
428
- background: var(--q-positive);
429
- border-radius: 50%;
430
- animation: sparkle 2s infinite ease-in-out;
431
- }
432
-
433
- .sparkle-1 {
434
- top: -10px;
435
- right: -10px;
436
- animation-delay: 0s;
437
- }
438
-
439
- .sparkle-2 {
440
- top: 20px;
441
- left: -15px;
442
- animation-delay: 0.5s;
443
- }
444
-
445
- .sparkle-3 {
446
- bottom: -5px;
447
- right: 15px;
448
- animation-delay: 1s;
449
- }
450
-
451
- @keyframes sparkle {
452
- 0%, 100% {
453
- opacity: 0;
454
- transform: scale(0);
455
- }
456
- 50% {
457
- opacity: 1;
458
- transform: scale(1);
459
- }
460
- }
461
-
462
- .completion-title {
463
- font-weight: 700;
464
- letter-spacing: -0.5px;
465
- margin-bottom: 0.5rem;
466
- background: linear-gradient(135deg, var(--q-positive) 0%, #4CAF50 100%);
467
- -webkit-background-clip: text;
468
- -webkit-text-fill-color: transparent;
469
- background-clip: text;
470
- text-shadow: 0 2px 4px rgba(76, 175, 80, 0.3);
471
- }
472
-
473
- .completion-details {
474
- margin-top: 2rem;
475
- text-align: left;
476
- }
477
-
478
- .detail-item {
479
- display: flex;
480
- align-items: center;
481
- padding: 1rem;
482
- background: rgba(76, 175, 80, 0.02);
483
- border-radius: 12px;
484
- border: 1px solid rgba(76, 175, 80, 0.1);
485
- transition: all 0.3s ease;
486
- }
487
-
488
- .detail-item:hover {
489
- transform: translateX(4px);
490
- background: rgba(76, 175, 80, 0.05);
491
- box-shadow: 0 4px 12px rgba(76, 175, 80, 0.1);
492
- }
493
-
494
- .detail-text {
495
- margin-left: 1rem;
496
- }
497
-
498
- .next-steps {
499
- margin-top: 2rem;
500
- text-align: left;
501
- padding: 1.5rem;
502
- background: rgba(0, 0, 0, 0.02);
503
- border-radius: 12px;
504
- }
505
-
506
331
  /* Адаптивность */
507
332
  @media (max-width: 768px) {
508
333
  .progress-card {
@@ -515,23 +340,12 @@ watch(() => instance.value?.progress, () => {
515
340
  text-align: center;
516
341
  }
517
342
 
518
-
519
343
  .stage-info {
520
344
  flex-direction: column;
521
345
  text-align: center;
522
346
  gap: 0.75rem;
523
347
  }
524
348
 
525
- .completion-card {
526
- padding: 2rem;
527
- }
528
-
529
- .detail-item {
530
- flex-direction: column;
531
- text-align: center;
532
- gap: 0.5rem;
533
- }
534
-
535
349
  .time-display {
536
350
  padding: 0.5rem 1rem;
537
351
  }
@@ -38,7 +38,7 @@ const handleContinue = () => {
38
38
  <template lang="pug">
39
39
  q-step(
40
40
  :name="1"
41
- title="Выберите тариф"
41
+ title="Выбор тарифа подключения"
42
42
  icon="info"
43
43
  :done="isDone"
44
44
  )