@coopenomics/desktop 2025.5.5 → 2025.5.13

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 (50) hide show
  1. package/package.json +5 -5
  2. package/src/entities/Registrator/model/store.ts +15 -11
  3. package/src/features/Agreementer/SignAgreementDialog/model/index.ts +5 -3
  4. package/src/features/Agreementer/SignAgreementDialog/ui/SignAgreementDialog.vue +1 -1
  5. package/src/features/Decision/AuthorizeAndExecDecision/model/index.ts +6 -9
  6. package/src/features/Decision/CreateProject/model/index.ts +1 -1
  7. package/src/features/Decision/VoteAgainstDecision/model/index.ts +14 -2
  8. package/src/features/Decision/VoteForDecision/model/index.ts +9 -5
  9. package/src/features/FreeDecision/CreateProject/model/index.ts +1 -1
  10. package/src/features/Meet/CloseMeetWithDecision/model/index.ts +13 -13
  11. package/src/features/Meet/CreateMeet/model/index.ts +1 -1
  12. package/src/features/Meet/RestartMeet/model/index.ts +6 -3
  13. package/src/features/Request/AcceptRequest/api/index.ts +3 -10
  14. package/src/features/Request/ConfirmRecieveOnRequest/api/index.ts +4 -9
  15. package/src/features/Request/ConfirmSupplyOnRequest/api/index.ts +6 -11
  16. package/src/features/Request/ConfirmSupplyOnRequest/ui/ConfirmSupplyOnRequestButton.vue +1 -1
  17. package/src/features/Request/CreateChildOrder/model/index.ts +35 -30
  18. package/src/features/Request/CreateChildOrder/ui/CreateChildOrderButton/CreateChildOrderButton.vue +20 -15
  19. package/src/features/Request/DisputeOnRequest/api/index.ts +19 -24
  20. package/src/features/Request/DisputeOnRequest/ui/DisputeOnRequestButton.vue +1 -1
  21. package/src/features/Request/RecieveOnRequest/api/index.ts +6 -11
  22. package/src/features/Request/RecieveOnRequest/ui/RecieveOnRequestButton.vue +1 -1
  23. package/src/features/Request/SupplyOnRequest/api/index.ts +18 -27
  24. package/src/features/Union/AddCooperative/ui/AddCooperativeForm.vue +7 -5
  25. package/src/features/User/CreateUser/api/index.ts +28 -10
  26. package/src/features/User/CreateUser/model/index.ts +39 -31
  27. package/src/pages/Cooperative/ListOfAgenda/ui/ListOfAgendaQuestions.vue +8 -8
  28. package/src/pages/Cooperative/ListOfParticipants/ui/ListOfParticipantsPage.vue +3 -3
  29. package/src/pages/Registrator/SignUp/EmailInput.vue +0 -7
  30. package/src/pages/Union/ConnectionAgreement/ConnectionAgreementPage.vue +1 -1
  31. package/src/processes/process-decisions/index.ts +32 -29
  32. package/src/processes/select-branch/index.ts +1 -1
  33. package/src/shared/api/indexDB.ts +0 -1
  34. package/src/shared/lib/document/model/const.ts +30 -0
  35. package/src/shared/lib/document/model/entity.ts +33 -21
  36. package/src/shared/lib/document/model/index.ts +1 -1
  37. package/src/shared/lib/document/model/types.ts +2 -3
  38. package/src/shared/lib/types/document/index.ts +11 -13
  39. package/src/shared/lib/types/user/IUserData.ts +5 -6
  40. package/src/shared/lib/types/user/index.ts +1 -11
  41. package/src/shared/store/index.ts +9 -5
  42. package/src/shared/ui/BaseDocument/BaseDocument.vue +43 -42
  43. package/src/shared/ui/ComplexDocument/ComplexDocument.vue +7 -5
  44. package/src/shared/ui/ZodForm/ZodForm.vue +1 -1
  45. package/src/widgets/Cooperative/Documents/ListOfDocuments/ui/DocumentsTable.vue +2 -2
  46. package/src/widgets/Meets/MeetDetailsVoting/model.ts +4 -4
  47. package/src/widgets/Participants/ui/ParticipantCard.vue +3 -3
  48. package/src/widgets/Participants/ui/ParticipantDetails.vue +6 -6
  49. package/src/widgets/Participants/ui/ParticipantsTable.vue +3 -3
  50. package/src/widgets/Questions/ui/QuestionsTable/QuestionsTable.vue +8 -8
@@ -10,6 +10,7 @@ import { useVoteAgainstDecision } from 'src/features/Decision/VoteAgainstDecisio
10
10
  import { computed } from 'vue'
11
11
  import { useAgendaStore } from 'src/entities/Agenda/model'
12
12
  import type { IAgenda } from 'src/entities/Agenda/model'
13
+ import { DigitalDocument } from 'src/shared/lib/document'
13
14
 
14
15
  /**
15
16
  * Процесс обработки решений
@@ -19,7 +20,7 @@ export function useDecisionProcessor() {
19
20
  const { info } = useSystemStore()
20
21
  const session = useSessionStore()
21
22
  const agendaStore = useAgendaStore()
22
-
23
+
23
24
  // Данные повестки и состояние загрузки
24
25
  const decisions = computed(() => agendaStore.agenda)
25
26
  const loading = computed(() => agendaStore.loading)
@@ -47,11 +48,11 @@ export function useDecisionProcessor() {
47
48
  if (row.documents?.statement?.documentAggregate?.rawDocument?.full_title) {
48
49
  return row.documents.statement.documentAggregate.rawDocument.full_title
49
50
  }
50
-
51
+
51
52
  if (row.documents?.decision?.documentAggregate?.rawDocument?.full_title) {
52
53
  return row.documents.decision.documentAggregate.rawDocument.full_title
53
54
  }
54
-
55
+
55
56
  // Поддержка исходного формата для таблицы
56
57
  if (row.table?.statement?.meta && typeof row.table.statement.meta === 'string') {
57
58
  try {
@@ -61,7 +62,7 @@ export function useDecisionProcessor() {
61
62
  // Игнорируем ошибку парсинга JSON
62
63
  }
63
64
  }
64
-
65
+
65
66
  return 'Вопрос без заголовка'
66
67
  }
67
68
 
@@ -85,16 +86,16 @@ export function useDecisionProcessor() {
85
86
  if (row.documents?.statement?.documentAggregate?.rawDocument?.hash) {
86
87
  return row.documents.statement.documentAggregate.rawDocument.hash
87
88
  }
88
-
89
+
89
90
  if (row.documents?.decision?.documentAggregate?.rawDocument?.hash) {
90
91
  return row.documents.decision.documentAggregate.rawDocument.hash
91
92
  }
92
-
93
+
93
94
  // Поддержка исходного формата для таблицы
94
95
  if (row.table?.statement?.hash) {
95
96
  return row.table.statement.hash
96
97
  }
97
-
98
+
98
99
  return null
99
100
  }
100
101
 
@@ -105,7 +106,7 @@ export function useDecisionProcessor() {
105
106
  if (!row.table?.id || !row.table?.username || !row.table?.type) {
106
107
  throw new Error('Некорректные данные решения')
107
108
  }
108
-
109
+
109
110
  const decision_id = Number(row.table.id)
110
111
  const username = row.table.username
111
112
  const type = row.table.type
@@ -157,27 +158,22 @@ export function useDecisionProcessor() {
157
158
  if (!row.table?.id) {
158
159
  throw new Error('Некорректные данные решения')
159
160
  }
160
-
161
+
161
162
  const decision_id = Number(row.table.id)
162
163
 
163
164
  // Генерируем документ решения
164
165
  const document = await generateDecisionDocument(row)
165
166
 
166
- // Подписываем документ
167
- const signed_hash_of_document = useGlobalStore().signDigest(document.hash)
168
- const chainDocument: Cooperative.Document.IChainDocument = {
169
- hash: document.hash,
170
- meta: JSON.stringify(document.meta),
171
- signature: signed_hash_of_document.signature,
172
- public_key: signed_hash_of_document.public_key,
173
- }
167
+ // Создаем экземпляр класса DigitalDocument и подписываем документ
168
+ const digitalDocument = new DigitalDocument(document)
169
+ const signedDocument = await digitalDocument.sign(session.username)
174
170
 
175
171
  // Подготавливаем данные для транзакций
176
172
  const authorizeData: SovietContract.Actions.Decisions.Authorize.IAuthorize = {
177
173
  coopname: info.coopname,
178
174
  chairman: session.username,
179
175
  decision_id,
180
- document: chainDocument,
176
+ document: {...signedDocument, meta: JSON.stringify(signedDocument.meta)},
181
177
  }
182
178
 
183
179
  const execData: SovietContract.Actions.Decisions.Exec.IExec = {
@@ -218,22 +214,29 @@ export function useDecisionProcessor() {
218
214
  /**
219
215
  * Голосовать "за" решение
220
216
  */
221
- async function voteForDecision(decision_id: number) {
222
- const { voteForDecision: vote } = useVoteForDecision()
223
- await vote(decision_id)
224
- return true
217
+ async function voteForDecision(row: IAgenda) {
218
+ if (!row.table?.id) {
219
+ throw new Error('Не удалось получить ID решения');
220
+ }
221
+
222
+ const decision_id = Number(row.table.id);
223
+ const { voteForDecision: vote } = useVoteForDecision();
224
+ await vote(decision_id);
225
+ return true;
225
226
  }
226
227
 
227
228
  /**
228
229
  * Голосовать "против" решения
229
230
  */
230
- async function voteAgainstDecision(decision_id: number) {
231
- await useVoteAgainstDecision().voteAgainstDecision({
232
- coopname: info.coopname,
233
- member: session.username,
234
- decision_id,
235
- })
236
- return true
231
+ async function voteAgainstDecision(row: IAgenda) {
232
+ if (!row.table?.id) {
233
+ throw new Error('Не удалось получить ID решения');
234
+ }
235
+
236
+ const decision_id = Number(row.table.id);
237
+ const { voteAgainstDecision } = useVoteAgainstDecision();
238
+ await voteAgainstDecision(decision_id);
239
+ return true;
237
240
  }
238
241
 
239
242
  /**
@@ -47,7 +47,7 @@ export function useSelectBranchProcess() {
47
47
  const sign = async () => {
48
48
  try {
49
49
  isSubmitting.value = true
50
- const doc = await digitalDocument.sign()
50
+ const doc = await digitalDocument.sign<Cooperative.Registry.SelectBranchStatement.Meta>(session.username)
51
51
 
52
52
  await selectBranch({
53
53
  braname: selectedBranch.value,
@@ -1,5 +1,4 @@
1
1
  import { openDB } from 'idb';
2
- import { env } from '../config';
3
2
 
4
3
  async function openIndexedDB(dbName: string, storeName: string) {
5
4
 
@@ -0,0 +1,30 @@
1
+ import type { IDocument } from '../../types/document';
2
+
3
+ export const fakeDocument: IDocument = {
4
+ version: '1.0.0',
5
+ hash: '33CBC662E606F23F332B442BAB84F2D05BD498B66EF61BC918740606B05BD565',
6
+ doc_hash: '33CBC662E606F23F332B442BAB84F2D05BD498B66EF61BC918740606B05BD565',
7
+ meta_hash: 'ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890ABCDEF1234567890',
8
+ meta: {
9
+ block_num: 1,
10
+ coopname: 'voskhod',
11
+ created_at: new Date().toISOString(),
12
+ generator: 'generator',
13
+ lang: 'ru',
14
+ links: [],
15
+ registry_id: 1,
16
+ timezone: 'Europe/Moscow',
17
+ title: 'Фейковый документ',
18
+ username: 'tester',
19
+ version: '1.0.0',
20
+ },
21
+ signatures: [{
22
+ id: 1,
23
+ signed_hash: '33CBC662E606F23F332B442BAB84F2D05BD498B66EF61BC918740606B05BD565',
24
+ signer: 'tester',
25
+ public_key: 'PUB_K1_8YWRWjCdUQubPoHzT5ndvfhGKDf1ZL7v7Ge9iHoLtNp7wnVfG1',
26
+ signature: 'SIG_K1_KWeGQ48n78ybpkuVDf1M7nuGnT8pkPXFbYYMUXtFTFv2dEReMEmwW89r19dKmAVSFZwHTdxdqkB3ZQJeAS9CcQwb92E398',
27
+ signed_at: new Date().toISOString(),
28
+ meta: ''
29
+ }]
30
+ };
@@ -1,28 +1,36 @@
1
1
  import type { IGenerate, IGeneratedDocument } from './types'
2
2
  import { api } from '../api';
3
3
  import { useGlobalStore } from 'src/shared/store';
4
- import type { IObjectedDocument } from 'src/shared/lib/types/document';
4
+ import type { IDocument, IMetaDocument } from 'src/shared/lib/types/document';
5
5
  import type { Cooperative } from 'cooptypes';
6
+ import { Classes } from '@coopenomics/sdk';
6
7
 
7
8
  export type ZGeneratedDocument = Cooperative.Document.ZGeneratedDocument
8
9
 
9
10
  export const useSignDocument = () => {
10
11
  const globalStore = useGlobalStore()
11
12
 
12
- const signDocument = async(document: ZGeneratedDocument): Promise<Cooperative.Document.ISignedDocument> => {
13
+ /**
14
+ * Подписывает документ
15
+ */
16
+ const signDocument = async(
17
+ document: ZGeneratedDocument,
18
+ account: string,
19
+ signatureId = 1,
20
+ ): Promise<Cooperative.Document.ISignedDocument2> => {
13
21
  if (!document)
14
22
  throw new Error('Документ на подпись не предоставлен')
15
23
 
16
- const digital_signature = await globalStore.signDigest(document.hash);
24
+ const wifKey = globalStore.wif?.toString();
25
+ if (!wifKey)
26
+ throw new Error('Приватный ключ не установлен');
17
27
 
18
- const doc = {
19
- hash: document.hash,
20
- meta: document.meta,
21
- public_key: digital_signature.public_key,
22
- signature: digital_signature.signature,
23
- }
28
+ // Используем класс из SDK для подписи
29
+ const docSigner = new Classes.Document(wifKey);
24
30
 
25
- return doc
31
+
32
+ // Получаем доступ к Document классу из SDK
33
+ return await docSigner.signDocument(document, account, signatureId);
26
34
  }
27
35
 
28
36
  return {
@@ -32,7 +40,7 @@ export const useSignDocument = () => {
32
40
 
33
41
  export class DigitalDocument {
34
42
  public data: IGeneratedDocument | undefined
35
- public signedDocument: IObjectedDocument | undefined
43
+ public signedDocument: IDocument | undefined
36
44
 
37
45
  constructor(document?: IGeneratedDocument){
38
46
  this.data = document
@@ -43,22 +51,26 @@ export class DigitalDocument {
43
51
  return this.data;
44
52
  }
45
53
 
46
- async sign(): Promise<Cooperative.Document.ISignedDocument> {
54
+ /**
55
+ * Подписывает документ
56
+ */
57
+ async sign<T extends IMetaDocument>(account: string, signatureId = 1): Promise<IDocument<T>> {
47
58
  const globalStore = useGlobalStore()
48
59
  if (!this.data)
49
60
  throw new Error('Ошибка генерации документа')
50
61
 
51
- const digital_signature = await globalStore.signDigest(this.data.hash);
62
+ const wifKey = globalStore.wif?.toString();
63
+ if (!wifKey)
64
+ throw new Error('Приватный ключ не установлен');
52
65
 
53
- this.signedDocument = {
54
- hash: this.data.hash,
55
- meta: this.data.meta,
56
- public_key: digital_signature.public_key,
57
- signature: digital_signature.signature,
58
- };
66
+ // Используем класс из SDK для подписи
67
+ const docSigner = new Classes.Document(wifKey);
59
68
 
60
- return this.signedDocument
69
+ // Подписываем документ с использованием SDK
70
+ const signedDoc = await docSigner.signDocument<T>(this.data, account, signatureId);
61
71
 
62
- }
72
+ this.signedDocument = signedDoc;
63
73
 
74
+ return signedDoc;
75
+ }
64
76
  }
@@ -1,2 +1,2 @@
1
- export * from './entity'
2
1
  export * from './types'
2
+ export * from './entity'
@@ -1,9 +1,8 @@
1
1
  import { Cooperative } from 'cooptypes';
2
2
 
3
- export type IGeneratedDocument = Cooperative.Document.IGeneratedDocument;
3
+ export type IGeneratedDocument = Cooperative.Document.ZGeneratedDocument;
4
4
  export type IGenerate = Cooperative.Document.IGenerate;
5
5
  export type IGenerateJoinCoop = Cooperative.Document.IGenerateJoinCoop;
6
6
  export type IGenerateJoinCoopDecision =
7
7
  Cooperative.Document.IGenerateJoinCoopDecision;
8
-
9
- // export type IGenerateWalletAgreement = Cooperative.Document.IGenerateWalletAgreement
8
+ export type IGenerateWalletAgreement = Cooperative.Document.IGenerateWalletAgreement;
@@ -1,15 +1,13 @@
1
- import type { Cooperative } from 'cooptypes';
1
+ import type { Zeus } from '@coopenomics/sdk/index';
2
2
 
3
- export interface IObjectedDocument {
4
- hash: string;
5
- meta: Cooperative.Document.IMetaDocument;
6
- public_key: string;
7
- signature: string;
8
- }
9
-
10
- export interface IDocument {
11
- hash: string;
12
- meta: string;
13
- public_key: string;
14
- signature: string;
3
+ // Добавляю реэкспорты типов документов
4
+ export type IChainDocument2 = Zeus.ModelTypes['SignedBlockchainDocument']
5
+ export type ISignedDocument = Zeus.ModelTypes['SignedDigitalDocumentInput']
6
+ export type ISignatureInfo = Zeus.ModelTypes['SignatureInfo']
7
+ export type IMetaDocument<T = any> = Zeus.ModelTypes['MetaDocumentInput'] & T
8
+ export type IComplexDocument = Zeus.ModelTypes['DocumentPackageAggregate']
9
+ export type IDocument<T = any> = Omit<Zeus.ModelTypes['SignedDigitalDocumentInput'], 'meta'> & {
10
+ meta: IMetaDocument<T>
15
11
  }
12
+ // Для обратной совместимости
13
+ export type IObjectedDocument = IDocument;
@@ -1,3 +1,4 @@
1
+ import type { Mutations } from '@coopenomics/sdk';
1
2
  import { Cooperative } from 'cooptypes';
2
3
 
3
4
  export type IEntrepreneurData = Cooperative.Users.IEntrepreneurData;
@@ -20,9 +21,7 @@ export interface IUserData {
20
21
 
21
22
 
22
23
 
23
- export interface ICreateUserData {
24
- type: 'individual' | 'entrepreneur' | 'organization';
25
- entrepreneur_data?: ICreateEntrepreneurData & {bank_account: Cooperative.Payments.IBankAccount};
26
- individual_data?: ICreateIndividualData;
27
- organization_data?: ICreateOrganizationData & {bank_account: Cooperative.Payments.IBankAccount};
28
- }
24
+ export type IRegisterAccount = Mutations.Accounts.RegisterAccount.IInput['data'];
25
+ export type IRegisteredAccountResult = Mutations.Accounts.RegisterAccount.IOutput[typeof Mutations.Accounts.RegisterAccount.name];
26
+
27
+
@@ -1,4 +1,3 @@
1
- import { IObjectedDocument } from '../document';
2
1
  import { Cooperative } from 'cooptypes';
3
2
 
4
3
  export interface IKeyPair {
@@ -12,7 +11,7 @@ export interface IGeneratedAccount extends IKeyPair {
12
11
 
13
12
  export interface IToken {
14
13
  token: string;
15
- expires: Date;
14
+ expires: unknown;
16
15
  }
17
16
 
18
17
  export interface ITokens {
@@ -42,12 +41,3 @@ export interface ICreatedUser {
42
41
  user: IUser;
43
42
  tokens: ITokens;
44
43
  }
45
-
46
- export interface ISendStatement {
47
- username: string;
48
- statement: IObjectedDocument;
49
- wallet_agreement: IObjectedDocument;
50
- privacy_agreement: IObjectedDocument;
51
- signature_agreement: IObjectedDocument;
52
- user_agreement: IObjectedDocument;
53
- }
@@ -4,7 +4,6 @@ import { defineStore } from 'pinia';
4
4
  import { ref, Ref } from 'vue';
5
5
  import { decrypt, encrypt, hashSHA256 } from '../api/crypto';
6
6
  import { IMessageSignature } from '../lib/types/crypto';
7
- import { useSessionStore } from 'src/entities/Session';
8
7
  import { TransactResult } from '@wharfkit/session';
9
8
  import { readBlockchain } from '../api';
10
9
  import { ITokens } from '../lib/types/user';
@@ -82,6 +81,9 @@ export const useGlobalStore = defineStore('global', (): IGlobalStore => {
82
81
  client.setToken(tokens.value.access.token)
83
82
  }
84
83
 
84
+ if (decryptedKey && decryptedUsername) {
85
+ client.setWif(decryptedUsername, decryptedKey)
86
+ }
85
87
 
86
88
  } catch (error: any) {
87
89
  await setToIndexedDB(info.coopname, 'store', 'encryptedKey', '');
@@ -161,16 +163,18 @@ export const useGlobalStore = defineStore('global', (): IGlobalStore => {
161
163
  };
162
164
 
163
165
  const sendAction = async (action: any, broadcast: boolean) => {
164
- const session = useSessionStore();
166
+ // Получаем хранилище сессии с помощью импорта, избегая циклической зависимости
167
+ const sessionStore = (await import('src/entities/Session')).useSessionStore();
165
168
  const formedAction = await formActionFromAbi(action);
166
169
 
167
- return session.session?.transact({
170
+ return sessionStore.session?.transact({
168
171
  action: formedAction,
169
172
  }, { broadcast });
170
173
  };
171
174
 
172
175
  const sendActions = async (actions: any[], broadcast: boolean) => {
173
- const session = useSessionStore();
176
+ // Получаем хранилище сессии с помощью импорта, избегая циклической зависимости
177
+ const sessionStore = (await import('src/entities/Session')).useSessionStore();
174
178
  const data: Action[] = [];
175
179
 
176
180
  for (const action of actions) {
@@ -178,7 +182,7 @@ export const useGlobalStore = defineStore('global', (): IGlobalStore => {
178
182
  data.push(formedAction);
179
183
  }
180
184
 
181
- return session.session?.transact({
185
+ return sessionStore.session?.transact({
182
186
  actions: data,
183
187
  }, { broadcast });
184
188
  };
@@ -4,55 +4,56 @@ q-card(:flat="isMobile" style="word-break: break-all !important; white-space: no
4
4
  div(v-if="loading").full-width.text-center
5
5
  div(style="margin:auto;").flex.q-pa-sm.full-width.text-center
6
6
  q-spinner
7
- span.q-ml-sm.text-grey подговка {{doc.meta.title}}
7
+ span.q-ml-sm.text-grey подговка {{doc?.meta?.title}}
8
8
  div(v-if="!loading")
9
9
  div(v-html="safeHtml").description.q-pa-xs
10
10
  div.row.q-mt-lg.q-pa-sm.justify-center
11
11
 
12
12
  q-card(style="word-break: break-all !important; text-wrap: pretty;" flat).col-md-8.col-xs-12.q-pa-sm.verify-card
13
13
  div.q-mr-lg.q-mt-md
14
- q-badge(:color="doc.hash == regeneratedHash ? 'teal' : 'red'").text-center.q-pa-xs
15
- q-icon(:name="doc.hash == regeneratedHash ? 'check_circle' : 'cancel'" ).q-mr-sm
14
+ q-badge(:color="documentAggregate?.document?.doc_hash == regeneratedHash ? 'teal' : 'red'").text-center.q-pa-xs
15
+ q-icon(:name="documentAggregate?.document?.doc_hash == regeneratedHash ? 'check_circle' : 'cancel'" ).q-mr-sm
16
16
  span контрольная сумма
17
- p.q-mr-lg.q-ml-lg.text-grey {{ doc.hash }}
17
+ p.q-mr-lg.q-ml-lg.text-grey {{ documentAggregate?.document?.doc_hash }}
18
18
 
19
19
  // Показываем все подписи (если это агрегат документа)
20
- template(v-if="documentAggregate && documentAggregate.signatures && documentAggregate.signatures.length > 0")
20
+ template(v-if="documentAggregate?.document?.signatures && documentAggregate.document.signatures.length > 0")
21
21
  div.q-mr-lg.q-mt-md
22
+
22
23
  q-badge(:color="hasInvalidSignature ? 'red' : 'teal'").text-center.q-pa-xs
23
24
  q-icon(:name="hasInvalidSignature ? 'cancel' : 'verified'").q-mr-sm
24
- span Подписи ({{ documentAggregate.signatures.length }})
25
+ span Подписи ({{ documentAggregate.document.signatures.length }})
25
26
 
26
27
  // Список всех подписей
27
28
  q-list(bordered separator dense)
28
29
  q-expansion-item(
29
- v-for="(signature, index) in documentAggregate.signatures"
30
+ v-for="(signature, index) in documentAggregate.document.signatures"
30
31
  :key="index"
31
- :label="`Подпись ${index + 1}: ${getSignerName(signature.signer)}`"
32
+ :label="`Подпись ${index + 1}: ${getSignerName(signature.signer_info)}`"
32
33
  header-class="signature-header"
33
34
  dense
34
35
  )
35
36
  q-card(flat)
36
37
  q-card-section
37
38
  div.q-mb-sm
38
- q-badge(:color="signatures_verified[index] ? 'teal' : 'red'").text-center.q-pa-xs
39
+ q-badge(:color="signature.is_valid ? 'teal' : 'red'").text-center.q-pa-xs
39
40
  span Подписант
40
- p.q-mt-sm.q-ml-lg {{ getSignerName(signature.signer) }}
41
+ p.q-mt-sm.q-ml-lg {{ getSignerName(signature.signer_info) }}
41
42
 
42
43
  div(v-if="signature.public_key").q-mb-sm
43
- q-badge(:color="signatures_verified[index] ? 'teal' : 'red'").text-center.q-pa-xs
44
+ q-badge(:color="signature.is_valid ? 'teal' : 'red'").text-center.q-pa-xs
44
45
  span Публичный ключ
45
46
  p.q-mt-sm.q-ml-lg {{ signature.public_key }}
46
47
 
47
48
  div(v-if="signature.signature").q-mb-sm
48
- q-badge(:color="signatures_verified[index] ? 'teal' : 'red'").text-center.q-pa-xs
49
+ q-badge(:color="signature.is_valid ? 'teal' : 'red'").text-center.q-pa-xs
49
50
  span Цифровая подпись
50
51
  p.q-mt-sm.q-ml-lg {{ signature.signature }}
51
52
 
52
53
  div.q-mt-md
53
- q-badge(:color="signatures_verified[index] ? 'teal' : 'red'").text-center.q-pa-xs
54
- q-icon(:name="signatures_verified[index] ? 'check_circle' : 'cancel'").q-mr-sm
55
- span Статус подписи: {{ signatures_verified[index] ? 'Верифицирована' : 'Не верифицирована' }}
54
+ q-badge(:color="signature.is_valid ? 'teal' : 'red'").text-center.q-pa-xs
55
+ q-icon(:name="signature.is_valid ? 'check_circle' : 'cancel'").q-mr-sm
56
+ span Статус подписи: {{ signature.is_valid ? 'Верифицирована' : 'Не верифицирована' }}
56
57
 
57
58
  div.text-center.q-gutter-sm.q-mt-md
58
59
  q-btn(size="sm" color="primary" icon="download" @click="download") скачать
@@ -63,24 +64,24 @@ q-card(:flat="isMobile" style="word-break: break-all !important; white-space: no
63
64
  </template>
64
65
  <script setup lang="ts">
65
66
  import { ref, computed, onMounted } from 'vue'
66
- import { Signature, PublicKey } from '@wharfkit/antelope';
67
67
  import { useGlobalStore } from 'src/shared/store';
68
68
  import DOMPurify from 'dompurify';
69
69
  import { DigitalDocument } from 'src/shared/lib/document';
70
70
  import { FailAlert, SuccessAlert } from 'src/shared/api';
71
71
  import { getNameFromUserData } from 'src/shared/lib/utils/getNameFromUserData';
72
72
  import { useWindowSize } from 'src/shared/hooks';
73
+ import type { IDocumentAggregate } from 'src/entities/Document/model';
73
74
 
74
75
  const props = defineProps({
75
76
  documentAggregate: {
76
- type: Object,
77
+ type: Object as () => IDocumentAggregate,
77
78
  required: true
78
79
  }
79
80
  })
80
81
 
81
82
  const doc = computed(() => props.documentAggregate.rawDocument)
83
+
82
84
  const loading = ref(false)
83
- const signatures_verified = ref<boolean[]>([])
84
85
  const { isMobile } = useWindowSize()
85
86
  const regeneratedHash = ref()
86
87
  const onRegenerate = ref(false)
@@ -90,7 +91,7 @@ const regenerate = async() => {
90
91
  try {
91
92
  onRegenerate.value = true
92
93
 
93
- regenerated.value = await new DigitalDocument().generate({...doc.value.meta}, {skip_save: true})
94
+ regenerated.value = await new DigitalDocument().generate({...doc.value?.meta}, {skip_save: true})
94
95
 
95
96
  if (regenerated.value.hash == regeneratedHash.value)
96
97
  SuccessAlert('Сверка прошла успешно: аналогичный документ восстановлен из исходных данных')
@@ -108,13 +109,13 @@ function sanitizeHtml(html: string) {
108
109
  return DOMPurify.sanitize(html);
109
110
  }
110
111
 
111
- const safeHtml = computed(() => sanitizeHtml(doc.value.html));
112
+ const safeHtml = computed(() => sanitizeHtml(doc.value?.html ?? ''));
112
113
 
113
114
 
114
115
  const hashBuffer = async () => {
115
116
  try {
116
117
  // Декодирование из base64
117
- const binaryString = atob(doc.value.binary);
118
+ const binaryString = atob(doc.value?.binary ?? '');
118
119
  const len = binaryString.length;
119
120
  const data = new Uint8Array(len);
120
121
 
@@ -138,24 +139,24 @@ const getSignerName = (signer: any) => {
138
139
 
139
140
  // Верификация всех подписей из агрегата
140
141
  const verifySignatures = () => {
141
- if (props.documentAggregate?.signatures?.length > 0) {
142
- signatures_verified.value = props.documentAggregate.signatures.map(signatureData => {
143
- try {
144
- if (signatureData.public_key && signatureData.signature) {
145
- const public_key = PublicKey.from(signatureData.public_key)
146
- const signature = Signature.from(signatureData.signature)
147
- const hash = doc.value.hash
148
- const is_valid = signature.verifyDigest(hash, public_key)
149
- return is_valid
150
- } else {
151
- return signatureData.is_valid
152
- }
153
- } catch (error) {
154
- console.error('Ошибка при верификации подписи:', error)
155
- return false
156
- }
157
- })
158
- }
142
+ // if (props.documentAggregate?.document?.signatures?.length > 0) {
143
+ // signatures_verified.value = props.documentAggregate.document.signatures.map(signatureData => {
144
+ // try {
145
+ // if (signatureData.public_key && signatureData.signature) {
146
+ // const public_key = PublicKey.from(signatureData.public_key)
147
+ // const signature = Signature.from(signatureData.signature)
148
+ // const hash = doc.value?.hash
149
+ // const is_valid = signature.verifyDigest(hash, public_key)
150
+ // return is_valid
151
+ // } else {
152
+ // return signatureData.is_valid
153
+ // }
154
+ // } catch (error) {
155
+ // console.error('Ошибка при верификации подписи:', error)
156
+ // return false
157
+ // }
158
+ // })
159
+ // }
159
160
  }
160
161
 
161
162
  onMounted(() => {
@@ -167,8 +168,8 @@ async function download() {
167
168
  try {
168
169
  // PDF теперь в формате base64, можно использовать data URL
169
170
  const link = document.createElement('a');
170
- link.href = `data:application/pdf;base64,${doc.value.binary}`;
171
- link.download = doc.value.full_title ? doc.value.full_title : `${doc.value.meta.title} - ${doc.value.meta.username} - ${doc.value.meta.created_at}.pdf`;
171
+ link.href = `data:application/pdf;base64,${doc.value?.binary}`;
172
+ link.download = doc.value?.full_title ? doc.value?.full_title : `${doc.value?.meta?.title} - ${doc.value?.meta?.username} - ${doc.value?.meta?.created_at}.pdf`;
172
173
 
173
174
  document.body.appendChild(link);
174
175
  link.click();
@@ -179,7 +180,7 @@ async function download() {
179
180
  }
180
181
 
181
182
  // Вычисляем, есть ли хотя бы одна невалидная подпись
182
- const hasInvalidSignature = computed(() => signatures_verified.value.some(v => v === false))
183
+ const hasInvalidSignature = computed(() => props.documentAggregate?.document?.signatures?.some(signature => !signature.is_valid))
183
184
 
184
185
  </script>
185
186
  <style>
@@ -7,6 +7,12 @@
7
7
  :documentAggregate="documentData.statement.documentAggregate"
8
8
  )
9
9
 
10
+ // Отображение документа решения с агрегатом
11
+ BaseDocument(
12
+ v-if="documentData.decision && documentData.decision.documentAggregate"
13
+ :documentAggregate="documentData.decision.documentAggregate"
14
+ )
15
+
10
16
  // Отображение связанных документов из агрегата
11
17
  div(v-if="documentData.links.length > 0 && documentData.statement")
12
18
  div(
@@ -17,11 +23,7 @@
17
23
  :documentAggregate="linkedDoc"
18
24
  )
19
25
 
20
- // Отображение документа решения с агрегатом
21
- BaseDocument(
22
- v-if="documentData.decision && documentData.decision.documentAggregate"
23
- :documentAggregate="documentData.decision.documentAggregate"
24
- )
26
+
25
27
  </template>
26
28
 
27
29
  <script setup lang="ts">
@@ -18,7 +18,7 @@ div
18
18
  </template>
19
19
  <script lang="ts" setup>
20
20
  import { defineProps, defineEmits, reactive, watch } from 'vue';
21
- import { QInput, QCheckbox, QSelect, QCard } from 'quasar';
21
+ import { QInput, QCheckbox, QSelect } from 'quasar';
22
22
  import type { IExtensionConfigSchema, ISchemaProperty } from 'src/entities/Extension/model';
23
23
 
24
24
  // Устанавливаем имя компонента для рекурсивного вызова