Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EAKRDNzXtRrwmWz9z6PZu3
82 lines
2.4 KiB
TypeScript
82 lines
2.4 KiB
TypeScript
import { Input, Table, Tooltip } from 'antd';
|
|
import type { ColumnsType } from 'antd/es/table';
|
|
import type { ColumnOut, ValueOut } from '../../types/api';
|
|
import { formatAmount, parseAmountInput } from '../../utils/money';
|
|
import { type GridRow, cellFlags, cellKey } from './statementGrid';
|
|
|
|
type Props = {
|
|
columns: ColumnOut[];
|
|
rows: GridRow[];
|
|
editable: boolean;
|
|
draft: Record<string, string>;
|
|
onDraftChange: (key: string, text: string, originalAmount: string | null) => void;
|
|
};
|
|
|
|
const ATTENTION_BG = '#fff7e6';
|
|
const MODIFIED_BG = '#e6f4ff';
|
|
|
|
function cellBackground(value: ValueOut | undefined): string | undefined {
|
|
const flags = cellFlags(value);
|
|
if (flags.modified) {
|
|
return MODIFIED_BG;
|
|
}
|
|
return flags.attention ? ATTENTION_BG : undefined;
|
|
}
|
|
|
|
function cellTip(value: ValueOut): string | undefined {
|
|
if (value.is_modified) {
|
|
return `Исходное: ${formatAmount(value.original_amount)}`;
|
|
}
|
|
return value.confidence ? `Уверенность: ${value.confidence}%` : undefined;
|
|
}
|
|
|
|
export function StatementTable({ columns, rows, editable, draft, onDraftChange }: Props) {
|
|
const tableColumns: ColumnsType<GridRow> = [
|
|
{ key: 'name', title: 'Показатель', dataIndex: 'name', width: 320 },
|
|
{ key: 'code', title: 'Код', dataIndex: 'code', width: 70 },
|
|
...columns.map((col) => ({
|
|
key: col.id,
|
|
title: col.label ?? `Колонка ${col.column_index + 1}`,
|
|
width: 160,
|
|
align: 'right' as const,
|
|
onCell: (row: GridRow) => {
|
|
return { style: { background: cellBackground(row.cells[col.id]) } };
|
|
},
|
|
render: (_: unknown, row: GridRow) => {
|
|
const value = row.cells[col.id];
|
|
if (!value) {
|
|
return null;
|
|
}
|
|
const key = cellKey(row.lineId, col.id);
|
|
const tip = cellTip(value);
|
|
if (!editable) {
|
|
return <Tooltip title={tip}>{formatAmount(value.amount)}</Tooltip>;
|
|
}
|
|
const text = draft[key] ?? value.amount ?? '';
|
|
const invalid = key in draft && !parseAmountInput(text).ok;
|
|
return (
|
|
<Tooltip title={invalid ? 'Неверный формат суммы' : tip}>
|
|
<Input
|
|
size='small'
|
|
status={invalid ? 'error' : undefined}
|
|
value={text}
|
|
onChange={(e) => onDraftChange(key, e.target.value, value.amount)}
|
|
style={{ textAlign: 'right' }}
|
|
/>
|
|
</Tooltip>
|
|
);
|
|
},
|
|
})),
|
|
];
|
|
return (
|
|
<Table<GridRow>
|
|
size='small'
|
|
rowKey='key'
|
|
columns={tableColumns}
|
|
dataSource={rows}
|
|
pagination={false}
|
|
scroll={{ y: 'calc(100vh - 360px)' }}
|
|
/>
|
|
);
|
|
}
|