fix(desktop): не показывать ложное несовпадение контрольной суммы документа
Typecheck / controller (pull_request) Has been cancelled
Typecheck / desktop (pull_request) Has been cancelled

Пересчёт хэша при появлении binary и состояние загрузки вместо предупреждения, пока PDF ещё не готов.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Alex Ant
2026-06-24 00:09:11 +05:00
parent 07fb4599e6
commit ff1965376d
3 changed files with 49 additions and 15 deletions
@@ -19,6 +19,7 @@ q-card.dynamic-padding(
DocumentSignatures(
:doc-hash='documentAggregate?.document?.doc_hash ?? ""',
:regenerated-hash='regeneratedHash',
:hash-loading='hashComputing',
:signatures='canonSignatures',
:verifying='onRegenerate',
:hide-verify='true',
@@ -27,7 +28,7 @@ q-card.dynamic-padding(
)
</template>
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue';
import { ref, computed, watch } from 'vue';
import { useGlobalStore } from 'src/shared/store';
import DOMPurify from 'dompurify';
import { DigitalDocument, prepareDocumentArchive } from 'src/shared/lib/document';
@@ -54,10 +55,13 @@ const hasDocHash = computed(() => !!props.documentAggregate?.document?.doc_hash)
const loading = ref(false);
const { isMobile } = useWindowSize();
const regeneratedHash = ref();
const regeneratedHash = ref<string | undefined>();
const hashComputing = ref(false);
const onRegenerate = ref(false);
const regenerated = ref();
let hashRequestId = 0;
const regenerate = async () => {
try {
onRegenerate.value = true;
@@ -171,9 +175,18 @@ const shadowStyles = computed(
);
const hashBuffer = async () => {
const binary = doc.value?.binary;
if (!binary) {
regeneratedHash.value = undefined;
hashComputing.value = hasDocHash.value;
return;
}
const requestId = ++hashRequestId;
hashComputing.value = true;
try {
// Декодирование из base64
const binaryString = atob(doc.value?.binary ?? '');
const binaryString = atob(binary);
const len = binaryString.length;
const data = new Uint8Array(len);
@@ -181,16 +194,31 @@ const hashBuffer = async () => {
data[i] = binaryString.charCodeAt(i);
}
// Вычисление хэша из декодированных бинарных данных
regeneratedHash.value = (
await useGlobalStore().hashMessage(data)
).toUpperCase();
console.log('Хэш успешно вычислен:', regeneratedHash.value);
const hash = (await useGlobalStore().hashMessage(data)).toUpperCase();
if (requestId !== hashRequestId) return;
regeneratedHash.value = hash;
} catch (error) {
if (requestId !== hashRequestId) return;
regeneratedHash.value = undefined;
console.error('Ошибка при вычислении хэша:', error);
} finally {
if (requestId === hashRequestId) {
hashComputing.value = false;
}
}
};
watch(
() => (hasDocHash.value ? doc.value?.binary : undefined),
(binary, prevBinary) => {
if (binary === prevBinary) return;
regeneratedHash.value = undefined;
if (hasDocHash.value) void hashBuffer();
},
{ immediate: true },
);
// Получение ФИО/названия подписанта по сертификату
const getSignerName = (signer_certificate: any) => {
if (!signer_certificate) return 'Неизвестный подписант';
@@ -219,10 +247,7 @@ const verifySignatures = () => {
// }
};
onMounted(() => {
if (hasDocHash.value) hashBuffer();
verifySignatures();
});
verifySignatures();
async function download() {
try {
@@ -14,6 +14,8 @@ export interface DocumentSignaturesProps {
docHash: string;
/** Контрольная сумма, пересчитанная на клиенте. Если задана и == docHash — отметка «верно». */
regeneratedHash?: string;
/** Идёт локальный пересчёт контрольной суммы — показываем загрузку, не «не совпадает». */
hashLoading?: boolean;
/** Список приложенных подписей */
signatures?: DocumentSignatureEntry[];
/** Идёт ли сейчас «сверка» — для loading-состояния кнопки */
@@ -6,7 +6,10 @@
q-icon(:name='hashIcon' size='14px')
span Контрольная сумма
.doc-sig__hash {{ docHash }}
.doc-sig__hash-hint(v-if='regeneratedHash !== undefined && !hashMatches')
.doc-sig__hash-hint(v-if='hashLoading')
q-spinner(color='primary' size='14px')
span Проверяем контрольную сумму
.doc-sig__hash-hint(v-else-if='regeneratedHash !== undefined && !hashMatches')
q-icon(name='warning_amber' size='14px')
span Локально пересчитанный хеш не совпадает
@@ -82,6 +85,7 @@ import type { DocumentSignaturesProps } from './DocumentSignatures.types';
const props = withDefaults(defineProps<DocumentSignaturesProps>(), {
signatures: () => [],
verifying: false,
hashLoading: false,
hideDownload: false,
hideVerify: false,
});
@@ -96,7 +100,7 @@ const hashMatches = computed((): boolean =>
);
const hashState = computed((): 'pos' | 'neutral' | 'neg' => {
if (props.regeneratedHash === undefined) return 'neutral';
if (props.hashLoading || props.regeneratedHash === undefined) return 'neutral';
return hashMatches.value ? 'pos' : 'neg';
});
@@ -169,6 +173,9 @@ function toggle(idx: number): void {
color: var(--p-neg);
font-size: var(--p-fs-meta, 12px);
}
.doc-sig__hash-hint:has(.q-spinner) {
color: var(--p-ink-2);
}
/* ============ Список подписей ============ */
.doc-sig__list {