From ff2232787f113027be897b24e4bd06c9f31d8cd4 Mon Sep 17 00:00:00 2001 From: Andrey Epifancev Date: Tue, 27 Oct 2026 00:22:28 +0400 Subject: [PATCH] =?UTF-8?q?AURORA-1683=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=82=D0=B0=D1=80=D0=B8=D0=B8:=20=D1=82=D0=B8=D0=BF,=20?= =?UTF-8?q?=D0=B7=D0=B0=D0=BF=D1=80=D0=BE=D1=81,=20=D0=B2=D1=80=D0=B5?= =?UTF-8?q?=D0=BC=D1=8F=20=D0=BF=D0=BE=20=D0=9C=D0=BE=D1=81=D0=BA=D0=B2?= =?UTF-8?q?=D0=B5,=20=D1=81=D1=87=D1=91=D1=82=D1=87=D0=B8=D0=BA=20=D1=81?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D0=BA=D0=B8=20=D0=BF=D0=B0=D0=BD=D0=B5=D0=BB?= =?UTF-8?q?=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- web/src/services/api/documents.ts | 7 +++++-- web/src/types/api.ts | 7 +++++++ web/src/utils/dates.test.ts | 13 ++++++++++++- web/src/utils/dates.ts | 17 +++++++++++++++++ .../widgets/FilesDrawer/documentRows.test.ts | 12 ++++++++++++ web/src/widgets/FilesDrawer/documentRows.ts | 4 ++++ 6 files changed, 57 insertions(+), 3 deletions(-) diff --git a/web/src/services/api/documents.ts b/web/src/services/api/documents.ts index 64bd52d..e5aeece 100644 --- a/web/src/services/api/documents.ts +++ b/web/src/services/api/documents.ts @@ -1,5 +1,5 @@ import { api } from '../../api/client'; -import type { DocumentOut, EntryOut, Page, StatementOut, StatementPatch } from '../../types/api'; +import type { CommentOut, DocumentOut, EntryOut, Page, StatementOut, StatementPatch } from '../../types/api'; const ENTRIES_PAGE = 2000; @@ -23,4 +23,7 @@ export async function getAllEntries(id: string): Promise { } /** Комментарий к документу: текст 1–4000 символов после обрезки пробелов (иначе 422). */ -export const postComment = (documentId: string, text: string) => api.post(`/documents/${documentId}/comments`, { text }); +export const postComment = (documentId: string, text: string) => api.post(`/documents/${documentId}/comments`, { text }); + +/** Комментарии к документу по возрастанию времени, с ФИО автора. */ +export const getComments = (documentId: string) => api.get(`/documents/${documentId}/comments`); diff --git a/web/src/types/api.ts b/web/src/types/api.ts index 0956c4f..dbc0339 100644 --- a/web/src/types/api.ts +++ b/web/src/types/api.ts @@ -75,6 +75,13 @@ export interface DocumentBrief { comments_count: number; issue_counts: IssueCountsOut; } +/** Комментарий к документу (`GET /documents/{id}/comments`); правки и удаления нет. */ +export interface CommentOut { + id: string; + text: string; + author: { id: string; full_name: string }; + created_at: string; +} export type FileType = 'XLS' | 'XLSX' | 'XLSB' | 'PDF' | 'PNG' | 'JPG'; export interface FileOut { id: string; diff --git a/web/src/utils/dates.test.ts b/web/src/utils/dates.test.ts index ab6ad08..e37144f 100644 --- a/web/src/utils/dates.test.ts +++ b/web/src/utils/dates.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from 'vitest'; -import { formatMoscowDate, isIsoDate } from './dates'; +import { formatMoscowDate, formatMoscowDateTime, isIsoDate } from './dates'; describe('formatMoscowDate', () => { it('момент времени из API (UTC) — дата по Москве', () => { @@ -12,6 +12,17 @@ describe('formatMoscowDate', () => { }); }); +describe('formatMoscowDateTime', () => { + it('момент из API (UTC) — дата и время по Москве', () => { + expect(formatMoscowDateTime('2026-10-07T23:11:42.981145Z')).toBe('08.10.2026 02:11'); + expect(formatMoscowDateTime('2024-03-12T10:05:00Z')).toBe('12.03.2024 13:05'); + }); + it('пусто и мусор', () => { + expect(formatMoscowDateTime(null)).toBeNull(); + expect(formatMoscowDateTime('не дата')).toBeNull(); + }); +}); + describe('isIsoDate', () => { it('строго ГГГГ-ММ-ДД и существующая дата', () => { expect(isIsoDate('2024-12-31')).toBe(true); diff --git a/web/src/utils/dates.ts b/web/src/utils/dates.ts index 21c345d..8473c6a 100644 --- a/web/src/utils/dates.ts +++ b/web/src/utils/dates.ts @@ -7,6 +7,23 @@ export function formatMoscowDate(iso: string | null | undefined): string | null return Number.isNaN(date.getTime()) ? null : MOSCOW.format(date); } +const MOSCOW_DATE_TIME = new Intl.DateTimeFormat('ru-RU', { + timeZone: 'Europe/Moscow', + day: '2-digit', + month: '2-digit', + year: 'numeric', + hour: '2-digit', + minute: '2-digit', + hourCycle: 'h23', +}); + +/** Момент времени из API (ISO, UTC) → «dd.mm.yyyy hh:mm» по Москве; пусто/мусор → null. */ +export function formatMoscowDateTime(iso: string | null | undefined): string | null { + if (!iso) return null; + const date = new Date(iso); + return Number.isNaN(date.getTime()) ? null : MOSCOW_DATE_TIME.format(date).replace(', ', ' '); +} + /** Строго «ГГГГ-ММ-ДД» и существующая календарная дата (30 февраля — нет). */ export function isIsoDate(text: string): boolean { const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(text); diff --git a/web/src/widgets/FilesDrawer/documentRows.test.ts b/web/src/widgets/FilesDrawer/documentRows.test.ts index d99e3fc..74b157c 100644 --- a/web/src/widgets/FilesDrawer/documentRows.test.ts +++ b/web/src/widgets/FilesDrawer/documentRows.test.ts @@ -169,6 +169,18 @@ describe('buildDocumentRows: предупреждения', () => { const rows = buildDocumentRows([file({ documents: [doc({ issue_counts: { error: 1, info: 3 } })] })]); expect(rows[0].issueCounts).toEqual({ error: 1, info: 3 }); }); + + it('comments_count документа переносится в commentsCount', () => { + const rows = buildDocumentRows([file({ documents: [doc({ comments_count: 2 })] })]); + expect(rows[0].commentsCount).toBe(2); + }); + + it('ядро без comments_count и строка файла без документов — 0', () => { + const old = doc() as Partial; + old.comments_count = undefined; + expect(buildDocumentRows([file({ documents: [old as DocumentBrief] })])[0].commentsCount).toBe(0); + expect(buildDocumentRows([file({ status: 'PROCESSING' })])[0].commentsCount).toBe(0); + }); }); describe('rowBadge', () => { diff --git a/web/src/widgets/FilesDrawer/documentRows.ts b/web/src/widgets/FilesDrawer/documentRows.ts index 2a62265..6f9a6d5 100644 --- a/web/src/widgets/FilesDrawer/documentRows.ts +++ b/web/src/widgets/FilesDrawer/documentRows.ts @@ -27,6 +27,8 @@ export interface DocumentRow { mappingWarnings: string[]; /** счётчики issues документа; у строки файла без документов — нули */ issueCounts: IssueCountsOut; + /** число комментариев документа; у строки файла без документов — 0 */ + commentsCount: number; } /** Значок у статуса (P6-12): число предупреждений и цвет уровня; ничего нет — null. */ @@ -78,6 +80,7 @@ export function buildDocumentRows(files: FileOut[], labelFor?: (f: FileOut) => s fileWarnings, mappingWarnings, issueCounts: { error: 0, info: 0 }, + commentsCount: 0, }, ]; } @@ -105,6 +108,7 @@ export function buildDocumentRows(files: FileOut[], labelFor?: (f: FileOut) => s mappingWarnings, // ядро без v5.19 не присылает issue_counts — считаем, что замечаний нет issueCounts: d.issue_counts ?? { error: 0, info: 0 }, + commentsCount: d.comments_count ?? 0, }; }); });