@coopenomics/desktop 2025.11.10-alpha-1 → 2025.11.10-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.
Files changed (25) hide show
  1. package/package.json +6 -6
  2. package/src/app/layouts/default.vue +4 -0
  3. package/src/entities/CmdkMenu/index.ts +1 -0
  4. package/src/entities/CmdkMenu/model/index.ts +2 -0
  5. package/src/entities/CmdkMenu/model/store.ts +402 -0
  6. package/src/entities/CmdkMenu/model/types.ts +21 -0
  7. package/src/entities/ConnectionAgreement/index.ts +1 -0
  8. package/src/entities/ConnectionAgreement/model/index.ts +2 -0
  9. package/src/entities/ConnectionAgreement/model/store.ts +82 -0
  10. package/src/entities/ConnectionAgreement/model/types.ts +16 -0
  11. package/src/features/Union/AddCooperative/ui/AddCooperativeForm.vue +36 -7
  12. package/src/pages/Union/ConnectionAgreement/ConnectionAgreementPage.vue +95 -29
  13. package/src/widgets/ConnectionAgreementStepper/Steps/DomainValidationStep.vue +122 -0
  14. package/src/widgets/ConnectionAgreementStepper/Steps/FormStep.vue +12 -8
  15. package/src/widgets/ConnectionAgreementStepper/Steps/IntroStep.vue +3 -1
  16. package/src/widgets/ConnectionAgreementStepper/Steps/WaitingStep.vue +76 -126
  17. package/src/widgets/ConnectionAgreementStepper/Steps/index.ts +1 -0
  18. package/src/widgets/ConnectionAgreementStepper/Tariffs/TariffSelector.vue +5 -4
  19. package/src/widgets/ConnectionAgreementStepper/ui/ConnectionAgreementStepper.vue +31 -4
  20. package/src/widgets/Desktop/CmdkMenu/CmdkMenu.vue +392 -0
  21. package/src/widgets/Desktop/CmdkMenu/index.ts +1 -0
  22. package/src/widgets/Desktop/CmdkTrigger/CmdkTrigger.vue +83 -0
  23. package/src/widgets/Desktop/CmdkTrigger/index.ts +1 -0
  24. package/src/widgets/Desktop/LeftDrawerMenu/LeftDrawerMenu.vue +2 -2
  25. package/src/widgets/Desktop/index.ts +5 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coopenomics/desktop",
3
- "version": "2025.11.10-alpha-1",
3
+ "version": "2025.11.10-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.10-alpha-1",
29
- "@coopenomics/notifications": "2025.11.10-alpha-1",
30
- "@coopenomics/sdk": "2025.11.10-alpha-1",
28
+ "@coopenomics/controller": "2025.11.10-alpha-3",
29
+ "@coopenomics/notifications": "2025.11.10-alpha-3",
30
+ "@coopenomics/sdk": "2025.11.10-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.10-alpha-1",
62
+ "cooptypes": "2025.11.10-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": "634766a08edc036ccf4b08438b14251fa3a8ab73"
126
+ "gitHead": "637950d37f74f959a640d61891ef35d0ace9b858"
127
127
  }
@@ -52,12 +52,16 @@ q-layout(view='lHh LpR fff')
52
52
  WindowLoader(v-if='desktop?.isWorkspaceChanging')
53
53
  router-view(v-else)
54
54
 
55
+ // Глобальный CmdkMenu на уровне всего приложения
56
+ CmdkMenu
57
+
55
58
  </template>
56
59
 
57
60
  <script setup lang="ts">
58
61
  import { computed } from 'vue';
59
62
  import { Header } from 'src/widgets/Header/CommonHeader';
60
63
  import { LeftDrawerMenu } from 'src/widgets/Desktop/LeftDrawerMenu';
64
+ import { CmdkMenu } from 'src/widgets/Desktop/CmdkMenu';
61
65
  import { ContactsFooter } from 'src/shared/ui/Footer';
62
66
 
63
67
  import { useDesktopStore } from 'src/entities/Desktop/model';
@@ -0,0 +1 @@
1
+ export * from './model';
@@ -0,0 +1,2 @@
1
+ export * from './store';
2
+ export * from './types';
@@ -0,0 +1,402 @@
1
+ import { defineStore } from 'pinia';
2
+ import { computed, ref, nextTick } from 'vue';
3
+ import { useRouter } from 'vue-router';
4
+ import { useCurrentUser } from 'src/entities/Session';
5
+ import { useDesktopStore } from 'src/entities/Desktop/model';
6
+ import { useSystemStore } from 'src/entities/System/model';
7
+ import type { PageItem, GroupedItem } from './types';
8
+
9
+ const namespace = 'cmdk-menu';
10
+
11
+ export const useCmdkMenuStore = defineStore(namespace, () => {
12
+ // Composables
13
+ const router = useRouter();
14
+ const user = useCurrentUser();
15
+ const desktop = useDesktopStore();
16
+ const { info } = useSystemStore();
17
+
18
+ // State
19
+ const showDialog = ref(false);
20
+ const searchQuery = ref('');
21
+ const selectedIndex = ref(0);
22
+ const selectedPageIndex = ref(-1);
23
+ const searchInput = ref<HTMLInputElement | null>(null);
24
+ const contentRef = ref<HTMLElement | null>(null);
25
+
26
+ // Функция для определения ОС и типа устройства
27
+ const getOSInfo = () => {
28
+ const userAgent = navigator.userAgent;
29
+ const isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(userAgent);
30
+
31
+ if (isMobile) {
32
+ return { os: 'mobile', shortcut: null };
33
+ }
34
+
35
+ // Определение ОС для desktop
36
+ if (userAgent.includes('Mac')) {
37
+ return { os: 'mac', shortcut: '⌘ + K' };
38
+ } else if (userAgent.includes('Windows')) {
39
+ return { os: 'windows', shortcut: 'Ctrl + K' };
40
+ } else {
41
+ // Linux или другие Unix-like системы
42
+ return { os: 'linux', shortcut: 'Ctrl + K' };
43
+ }
44
+ };
45
+
46
+ // Вычисляемое свойство для подсказки горячих клавиш
47
+ const shortcutHint = computed(() => getOSInfo().shortcut);
48
+
49
+ // Функция для оценки условий
50
+ const evaluateCondition = (condition: string, context: Record<string, any>): boolean => {
51
+ try {
52
+ const func = new Function(...Object.keys(context), `return ${condition};`);
53
+ return func(...Object.values(context));
54
+ } catch (error) {
55
+ console.error('Error evaluating condition:', error);
56
+ return false;
57
+ }
58
+ };
59
+
60
+ // Получение горячих клавиш для страниц
61
+ const getShortcut = (pageName: string): string | undefined => {
62
+ const shortcuts: Record<string, string> = {
63
+ 'projects-list': '⌘P',
64
+ 'capital-wallet': '⌘W',
65
+ 'tracker': '⌘T',
66
+ 'voting': '⌘V',
67
+ 'results': '⌘R',
68
+ };
69
+ return shortcuts[pageName];
70
+ };
71
+
72
+ // Группировка воркспейсов с их страницами
73
+ const groupedItems = computed<GroupedItem[]>(() => {
74
+ const userRole = user.isChairman
75
+ ? 'chairman'
76
+ : user.isMember
77
+ ? 'member'
78
+ : 'user';
79
+
80
+ return desktop.workspaceMenus
81
+ .filter(
82
+ (item) =>
83
+ item.meta?.roles?.includes(userRole) ||
84
+ item.meta?.roles === undefined ||
85
+ item.meta?.roles.length === 0
86
+ )
87
+ .map(workspace => ({
88
+ workspaceName: workspace.workspaceName,
89
+ title: workspace.title,
90
+ icon: workspace.icon,
91
+ isActive: desktop.activeWorkspaceName === workspace.workspaceName,
92
+ pages: (workspace.mainRoute?.children || [])
93
+ .filter((page: any) => {
94
+ // Фильтрация по ролям, условиям и скрытым страницам
95
+ const rolesMatch =
96
+ page.meta?.roles?.includes(user.isChairman ? 'chairman' : user.isMember ? 'member' : 'user') ||
97
+ !page.meta?.roles ||
98
+ page.meta.roles.length === 0;
99
+ const conditionMatch = page.meta?.conditions
100
+ ? evaluateCondition(page.meta.conditions, {
101
+ isCoop: user.privateAccount.value?.type === 'organization' &&
102
+ user.privateAccount.value?.organization_data?.type?.toUpperCase() === 'COOP',
103
+ userRole: user.isChairman ? 'chairman' : user.isMember ? 'member' : 'user',
104
+ userAccount: user.privateAccount.value,
105
+ coopname: info.coopname,
106
+ })
107
+ : true;
108
+ const hiddenMatch = page.meta?.hidden ? !page.meta.hidden : true;
109
+
110
+ return rolesMatch && conditionMatch && hiddenMatch;
111
+ })
112
+ .map((page: any) => ({
113
+ name: page.name,
114
+ meta: page.meta,
115
+ shortcut: getShortcut(page.name),
116
+ }))
117
+ }));
118
+ });
119
+
120
+ // Поиск и фильтрация
121
+ const filteredItems = computed(() => {
122
+ if (!searchQuery.value) {
123
+ return groupedItems.value;
124
+ }
125
+
126
+ const query = searchQuery.value.toLowerCase();
127
+
128
+ return groupedItems.value
129
+ .map(group => ({
130
+ ...group,
131
+ pages: group.pages.filter(page =>
132
+ page.meta.title.toLowerCase().includes(query) ||
133
+ page.name.toLowerCase().includes(query) ||
134
+ group.title.toLowerCase().includes(query) ||
135
+ group.workspaceName.toLowerCase().includes(query)
136
+ )
137
+ }))
138
+ .filter(group => group.pages.length > 0 || group.title.toLowerCase().includes(query));
139
+ });
140
+
141
+ // Методы
142
+ const openDialog = async () => {
143
+ showDialog.value = true;
144
+ await nextTick();
145
+ searchInput.value?.focus();
146
+ searchQuery.value = '';
147
+ selectedIndex.value = 0;
148
+ selectedPageIndex.value = -1;
149
+ };
150
+
151
+ const closeDialog = () => {
152
+ showDialog.value = false;
153
+ searchQuery.value = '';
154
+ };
155
+
156
+ const handleSearch = () => {
157
+ selectedIndex.value = 0;
158
+ selectedPageIndex.value = -1;
159
+ };
160
+
161
+ const selectCurrentItem = () => {
162
+ if (filteredItems.value.length === 0) return;
163
+
164
+ const currentGroup = filteredItems.value[selectedIndex.value];
165
+ if (!currentGroup) return;
166
+
167
+ // Если выбрана страница (selectedPageIndex >= 0), переходим на неё
168
+ if (selectedPageIndex.value >= 0 && selectedPageIndex.value < currentGroup.pages.length) {
169
+ const selectedPage = currentGroup.pages[selectedPageIndex.value];
170
+ selectPage(currentGroup.workspaceName, selectedPage);
171
+ } else {
172
+ // Если выбрана группа (selectedPageIndex === -1), переходим на группу
173
+ selectGroup(selectedIndex.value);
174
+ }
175
+ };
176
+
177
+ const selectFirstItem = () => {
178
+ if (filteredItems.value.length > 0) {
179
+ const firstGroup = filteredItems.value[0];
180
+ if (firstGroup.pages.length > 0) {
181
+ selectPage(firstGroup.workspaceName, firstGroup.pages[0]);
182
+ } else {
183
+ selectGroup(0);
184
+ }
185
+ }
186
+ };
187
+
188
+ const scrollToSelected = () => {
189
+ if (!contentRef.value) return;
190
+
191
+ const selectedElement = contentRef.value.querySelector('.selected');
192
+ if (!selectedElement) return;
193
+
194
+ // Используем requestAnimationFrame для надежного ожидания обновления DOM
195
+ requestAnimationFrame(() => {
196
+ const container = contentRef.value;
197
+ if (!container) return;
198
+
199
+ // Простая логика: всегда прокручиваем выбранный элемент в верхнюю часть видимой области
200
+ selectedElement.scrollIntoView({
201
+ behavior: 'smooth',
202
+ block: 'start', // элемент будет по центру видимой области
203
+ inline: 'nearest'
204
+ });
205
+ });
206
+ };
207
+
208
+ const navigateDown = async () => {
209
+ const totalGroups = filteredItems.value.length;
210
+ if (totalGroups === 0) return;
211
+
212
+ const currentGroup = filteredItems.value[selectedIndex.value];
213
+ const hasPages = currentGroup.pages.length > 0;
214
+
215
+ if (hasPages && selectedPageIndex.value < currentGroup.pages.length - 1) {
216
+ selectedPageIndex.value++;
217
+ } else if (selectedIndex.value < totalGroups - 1) {
218
+ selectedIndex.value++;
219
+ selectedPageIndex.value = -1;
220
+ } else {
221
+ selectedIndex.value = 0;
222
+ selectedPageIndex.value = -1;
223
+ }
224
+
225
+ // Ждем обновления DOM перед скроллом
226
+ await nextTick();
227
+ scrollToSelected();
228
+ };
229
+
230
+ const navigateUp = async () => {
231
+ const totalGroups = filteredItems.value.length;
232
+ if (totalGroups === 0) return;
233
+
234
+ if (selectedPageIndex.value > 0) {
235
+ selectedPageIndex.value--;
236
+ } else if (selectedIndex.value > 0) {
237
+ selectedIndex.value--;
238
+ const prevGroup = filteredItems.value[selectedIndex.value];
239
+ selectedPageIndex.value = prevGroup.pages.length > 0 ? prevGroup.pages.length - 1 : -1;
240
+ } else {
241
+ selectedIndex.value = totalGroups - 1;
242
+ const lastGroup = filteredItems.value[selectedIndex.value];
243
+ selectedPageIndex.value = lastGroup.pages.length > 0 ? lastGroup.pages.length - 1 : -1;
244
+ }
245
+
246
+ // Ждем обновления DOM перед скроллом
247
+ await nextTick();
248
+ scrollToSelected();
249
+ };
250
+
251
+ const selectGroup = (groupIndex: number) => {
252
+ const group = filteredItems.value[groupIndex];
253
+ if (!group) return;
254
+
255
+ closeDialog();
256
+
257
+ desktop.selectWorkspace(group.workspaceName);
258
+ setTimeout(() => {
259
+ desktop.goToDefaultPage(router);
260
+ }, 100);
261
+ };
262
+
263
+ const selectPage = (workspaceName: string, page: PageItem) => {
264
+ closeDialog();
265
+
266
+ // Если воркспейс не активен, переключаемся на него и ждем
267
+ if (desktop.activeWorkspaceName !== workspaceName) {
268
+ desktop.selectWorkspace(workspaceName);
269
+ // Ждем переключения воркспейса, затем переходим на страницу
270
+ setTimeout(() => {
271
+ router.push({
272
+ name: page.name,
273
+ params: { coopname: info.coopname },
274
+ });
275
+ // Сбрасываем состояние загрузки после перехода
276
+ setTimeout(() => {
277
+ desktop.setWorkspaceChanging(false);
278
+ }, 500);
279
+ }, 150);
280
+ } else {
281
+ // Воркспейс уже активен, переходим сразу
282
+ router.push({
283
+ name: page.name,
284
+ params: { coopname: info.coopname },
285
+ });
286
+ // Сбрасываем состояние загрузки после перехода
287
+ setTimeout(() => {
288
+ desktop.setWorkspaceChanging(false);
289
+ }, 500);
290
+ }
291
+ };
292
+
293
+ // Обработчик клавиш для диалога (навигация внутри панели)
294
+ const handleDialogKeydown = (event: KeyboardEvent) => {
295
+ // Предотвращаем обработку глобального обработчика для диалога
296
+ event.stopPropagation();
297
+
298
+ switch (event.key) {
299
+ case 'ArrowDown':
300
+ event.preventDefault();
301
+ navigateDown();
302
+ break;
303
+ case 'ArrowUp':
304
+ event.preventDefault();
305
+ navigateUp();
306
+ break;
307
+ case 'Enter':
308
+ event.preventDefault();
309
+ selectCurrentItem();
310
+ break;
311
+ case 'Escape':
312
+ event.preventDefault();
313
+ closeDialog();
314
+ break;
315
+ }
316
+ };
317
+
318
+ // Глобальные горячие клавиши
319
+ const handleGlobalKeydown = (event: KeyboardEvent) => {
320
+ // Определяем правильную клавишу-модификатор для текущей ОС
321
+ const isMac = navigator.userAgent.includes('Mac');
322
+ const modifierPressed = isMac ? event.metaKey : event.ctrlKey;
323
+
324
+ // Проверяем комбинацию Ctrl/Cmd + K
325
+ if (modifierPressed && event.key.toLowerCase() === 'k') {
326
+ event.preventDefault();
327
+ event.stopPropagation();
328
+
329
+ if (showDialog.value) {
330
+ closeDialog();
331
+ } else {
332
+ openDialog();
333
+ }
334
+ return;
335
+ }
336
+
337
+ // Escape для закрытия панели (только когда панель открыта)
338
+ if (event.key === 'Escape' && showDialog.value) {
339
+ event.preventDefault();
340
+ closeDialog();
341
+ }
342
+ };
343
+
344
+ // Инициализация глобальных обработчиков клавиш
345
+ const initGlobalKeydown = () => {
346
+ document.addEventListener('keydown', handleGlobalKeydown);
347
+ };
348
+
349
+ const destroyGlobalKeydown = () => {
350
+ document.removeEventListener('keydown', handleGlobalKeydown);
351
+ };
352
+
353
+ const setSearchInput = (input: HTMLInputElement | null) => {
354
+ searchInput.value = input as HTMLInputElement | null;
355
+ };
356
+
357
+ const setContentRef = (ref: HTMLElement | null) => {
358
+ contentRef.value = ref;
359
+ };
360
+
361
+ return {
362
+ // State
363
+ showDialog,
364
+ searchQuery,
365
+ selectedIndex,
366
+ selectedPageIndex,
367
+ searchInput,
368
+ contentRef,
369
+
370
+ // Computed
371
+ filteredItems,
372
+ shortcutHint,
373
+ activeWorkspaceIcon: computed(() => {
374
+ const activeWorkspace = desktop.workspaceMenus.find(
375
+ ws => ws.workspaceName === desktop.activeWorkspaceName
376
+ );
377
+ return activeWorkspace?.icon || 'fa-solid fa-desktop';
378
+ }),
379
+ activeWorkspaceTitle: computed(() => {
380
+ const activeWorkspace = desktop.workspaceMenus.find(
381
+ ws => ws.workspaceName === desktop.activeWorkspaceName
382
+ );
383
+ return activeWorkspace?.title || 'Рабочий стол';
384
+ }),
385
+
386
+ // Methods
387
+ openDialog,
388
+ closeDialog,
389
+ handleSearch,
390
+ handleDialogKeydown,
391
+ selectFirstItem,
392
+ selectCurrentItem,
393
+ navigateDown,
394
+ navigateUp,
395
+ selectGroup,
396
+ selectPage,
397
+ setSearchInput,
398
+ setContentRef,
399
+ initGlobalKeydown,
400
+ destroyGlobalKeydown,
401
+ };
402
+ });
@@ -0,0 +1,21 @@
1
+ export interface PageItem {
2
+ name: string;
3
+ meta: any;
4
+ shortcut?: string;
5
+ }
6
+
7
+ export interface GroupedItem {
8
+ workspaceName: string;
9
+ title: string;
10
+ icon: string;
11
+ isActive: boolean;
12
+ pages: PageItem[];
13
+ }
14
+
15
+ export interface CmdkMenuState {
16
+ showDialog: boolean;
17
+ searchQuery: string;
18
+ selectedIndex: number;
19
+ selectedPageIndex: number;
20
+ searchInput: HTMLInputElement | undefined;
21
+ }
@@ -0,0 +1 @@
1
+ export * from './model'
@@ -0,0 +1,2 @@
1
+ export { useConnectionAgreementStore } from './store'
2
+ export type { ITariff, IConnectionAgreementState } from './types'
@@ -0,0 +1,82 @@
1
+ import { defineStore } from 'pinia'
2
+ import { ref } from 'vue'
3
+ import type { ITariff, IConnectionAgreementState } from './types'
4
+
5
+
6
+ const namespace = 'connection-agreement'
7
+
8
+ export const useConnectionAgreementStore = defineStore(namespace, () => {
9
+ // State
10
+ const currentStep = ref<number>(1)
11
+ const selectedTariff = ref<ITariff | null>(null)
12
+ const isInitialized = ref<boolean>(false)
13
+ const document = ref<any>(null)
14
+ const signedDocument = ref<any>(null)
15
+
16
+ // Methods
17
+ const setCurrentStep = (step: number) => {
18
+ currentStep.value = step
19
+ }
20
+
21
+ const setSelectedTariff = (tariff: ITariff | null) => {
22
+ selectedTariff.value = tariff
23
+ }
24
+
25
+ const setInitialized = (initialized: boolean) => {
26
+ isInitialized.value = initialized
27
+ }
28
+
29
+ const setDocument = (doc: any) => {
30
+ document.value = doc
31
+ }
32
+
33
+ const setSignedDocument = (doc: any) => {
34
+ signedDocument.value = doc
35
+ }
36
+
37
+ const reset = () => {
38
+ currentStep.value = 1
39
+ selectedTariff.value = null
40
+ isInitialized.value = false
41
+ document.value = null
42
+ signedDocument.value = null
43
+ }
44
+
45
+ const initialize = (state: Partial<IConnectionAgreementState>) => {
46
+ if (state.currentStep !== undefined) {
47
+ currentStep.value = state.currentStep
48
+ }
49
+ if (state.selectedTariff !== undefined) {
50
+ selectedTariff.value = state.selectedTariff
51
+ }
52
+ if (state.isInitialized !== undefined) {
53
+ isInitialized.value = state.isInitialized
54
+ }
55
+ if (state.document !== undefined) {
56
+ document.value = state.document
57
+ }
58
+ if (state.signedDocument !== undefined) {
59
+ signedDocument.value = state.signedDocument
60
+ }
61
+ }
62
+
63
+ return {
64
+ // State
65
+ currentStep,
66
+ selectedTariff,
67
+ isInitialized,
68
+ document,
69
+ signedDocument,
70
+
71
+ // Methods
72
+ setCurrentStep,
73
+ setSelectedTariff,
74
+ setInitialized,
75
+ setDocument,
76
+ setSignedDocument,
77
+ reset,
78
+ initialize
79
+ }
80
+ }, {
81
+ persist: true
82
+ })
@@ -0,0 +1,16 @@
1
+ export interface ITariff {
2
+ id: string
3
+ name: string
4
+ description: string
5
+ price: string
6
+ features: string[]
7
+ additionalCosts?: string[]
8
+ }
9
+
10
+ export interface IConnectionAgreementState {
11
+ currentStep: number
12
+ selectedTariff: ITariff | null
13
+ isInitialized: boolean
14
+ document?: any
15
+ signedDocument?: any
16
+ }
@@ -1,5 +1,5 @@
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
2
+ Form(:handler-submit="addNow" :is-submitting="isSubmitting" :showCancel="false" :button-cancel-txt="'Отменить'" :button-submit-txt="'Продолжить'" @cancel="clear").q-gutter-md
3
3
  //- q-input(standout="bg-teal text-white" label="Имя аккаунта" v-model="data.coopname" :rules="[val => notEmpty(val)]")
4
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
5
 
@@ -21,7 +21,7 @@ Form(:handler-submit="addNow" :is-submitting="isSubmitting" :showCancel="false"
21
21
 
22
22
  </template>
23
23
  <script lang="ts" setup>
24
- import { computed, ref } from 'vue';
24
+ import { computed, ref, watch } from 'vue';
25
25
  import { useAddCooperative } from '../model';
26
26
  import { Form } from 'src/shared/ui/Form';
27
27
  import { notEmpty, isDomain } from 'src/shared/lib/utils';
@@ -41,6 +41,10 @@ const props = defineProps({
41
41
  document: {
42
42
  type: Object as () => IDocument,
43
43
  required: true,
44
+ },
45
+ cooperative: {
46
+ type: Object as () => any,
47
+ default: null,
44
48
  }
45
49
  })
46
50
 
@@ -48,17 +52,31 @@ const document = computed(() => props.document)
48
52
 
49
53
  const session = useSessionStore()
50
54
 
55
+ // Функция для извлечения числового значения из IAsset
56
+ const extractNumericValue = (asset: any): string => {
57
+ if (!asset) return ''
58
+ if (typeof asset === 'number') return asset.toString()
59
+ if (typeof asset === 'string') {
60
+ // Извлекаем число из строки типа "1000.0000 RUB" и убираем лишние нули
61
+ const match = asset.match(/^(\d+(?:\.\d+)?)/)
62
+ if (match) {
63
+ return parseFloat(match[1]).toString()
64
+ }
65
+ }
66
+ return ''
67
+ }
68
+
51
69
  const data = ref<RegistratorContract.Actions.RegisterCooperative.IRegisterCooperative>({
52
70
  coopname: session.username,
53
71
  params: {
54
72
  is_cooperative: true,
55
73
  coop_type: 'conscoop',
56
- announce: '',
74
+ announce: props.cooperative?.announce || '',
57
75
  description: '',
58
- initial: '',
59
- minimum: '',
60
- org_initial: '',
61
- org_minimum: ''
76
+ initial: extractNumericValue(props.cooperative?.initial),
77
+ minimum: extractNumericValue(props.cooperative?.minimum),
78
+ org_initial: extractNumericValue(props.cooperative?.org_initial),
79
+ org_minimum: extractNumericValue(props.cooperative?.org_minimum)
62
80
  },
63
81
  username: session.username,
64
82
  document: {
@@ -71,6 +89,17 @@ const data = ref<RegistratorContract.Actions.RegisterCooperative.IRegisterCooper
71
89
  }
72
90
  })
73
91
 
92
+ // Следим за изменениями cooperative и обновляем данные
93
+ watch(() => props.cooperative, (newCooperative) => {
94
+ if (newCooperative) {
95
+ data.value.params.announce = newCooperative.announce || ''
96
+ data.value.params.initial = extractNumericValue(newCooperative.initial)
97
+ data.value.params.minimum = extractNumericValue(newCooperative.minimum)
98
+ data.value.params.org_initial = extractNumericValue(newCooperative.org_initial)
99
+ data.value.params.org_minimum = extractNumericValue(newCooperative.org_minimum)
100
+ }
101
+ }, { immediate: true })
102
+
74
103
  const clear = () => {
75
104
  emit('finish')
76
105
  }