/* Kotlovans — модуль для отображения котлованов проекта Показывает: код, глубина, кольца, объём, стоимость, даты, статус, прогресс */ window.RD = window.RD || { core: {}, modules: {} }; window.RD.modules.Kotlovans = function Kotlovans() { var store = RD.core.useStore(); var h = React.createElement; var fmt = RD.core; var useState = React.useState; // FIX: kotlovans are in root of store.raw, not in store.raw.data var kotlovans = store.raw.kotlovans || []; var filterState = useState('all'); var filter = filterState[0]; var setFilter = filterState[1]; var filtered = filter === 'all' ? kotlovans : kotlovans.filter(function (k) { return k.status === filter; }); var totalCost = kotlovans.reduce(function (s, k) { return s + (k.cost || 0); }, 0); var totalVolume = kotlovans.reduce(function (s, k) { return s + (k.volume_m3 || 0); }, 0); var avgDepth = kotlovans.length > 0 ? (kotlovans.reduce(function (s, k) { return s + (k.depth_m || 0); }, 0) / kotlovans.length).toFixed(1) : 0; function statusBadge(status) { var colors = { pending: { bg: 'var(--rd-surface-2)', text: 'var(--rd-text-muted)' }, in_progress: { bg: 'var(--rd-info)', text: '#fff' }, completed: { bg: 'var(--rd-good)', text: '#fff' }, delayed: { bg: 'var(--rd-warn)', text: '#000' } }; var labels = { pending: 'Ожидание', in_progress: 'В работе', completed: 'Завершён', delayed: 'Задержка' }; var c = colors[status] || colors.pending; return h('span', { style: { fontSize: 10, fontWeight: 700, background: c.bg, color: c.text, padding: '4px 8px', borderRadius: 6, textTransform: 'uppercase' } }, labels[status] || status); } function progressBar(pct) { pct = Math.min(Math.max(pct || 0, 0), 100); return h('div', { style: { width: 100, height: 16, background: 'var(--rd-surface-3)', borderRadius: 6, overflow: 'hidden', position: 'relative' } }, h('div', { style: { width: pct + '%', height: '100%', background: pct === 100 ? 'var(--rd-good)' : 'var(--rd-accent)', transition: 'width 0.3s' } }), h('div', { style: { position: 'absolute', inset: 0, display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 9, fontWeight: 700, color: pct > 50 ? '#fff' : 'var(--rd-text)' } }, pct + '%') ); } return h('div', { style: { flex: 1, overflow: 'auto', padding: 20, display: 'flex', flexDirection: 'column', gap: 16 } }, // Header h('div', null, h('h2', { style: { fontSize: 20, fontWeight: 700, color: 'var(--rd-text)', marginBottom: 6 } }, 'Котлованы'), h('p', { style: { fontSize: 13, color: 'var(--rd-text-muted)' } }, kotlovans.length + ' котлованов · ' + fmt.money(totalCost) + ' · ' + totalVolume.toFixed(1) + ' м³' ) ), // KPI cards h('div', { style: { display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(180px, 1fr))', gap: 12 } }, h('div', { style: { background: 'var(--rd-surface)', border: '1px solid var(--rd-border)', borderRadius: 10, padding: 14 } }, h('div', { style: { fontSize: 11, color: 'var(--rd-text-muted)', fontWeight: 600, marginBottom: 4 } }, 'ВСЕГО КОТЛОВАНОВ'), h('div', { style: { fontSize: 24, fontWeight: 700, color: 'var(--rd-text)' } }, kotlovans.length) ), h('div', { style: { background: 'var(--rd-surface)', border: '1px solid var(--rd-border)', borderRadius: 10, padding: 14 } }, h('div', { style: { fontSize: 11, color: 'var(--rd-text-muted)', fontWeight: 600, marginBottom: 4 } }, 'ОБЩАЯ СТОИМОСТЬ'), h('div', { style: { fontSize: 18, fontWeight: 700, color: 'var(--rd-accent)' } }, fmt.money(totalCost)) ), h('div', { style: { background: 'var(--rd-surface)', border: '1px solid var(--rd-border)', borderRadius: 10, padding: 14 } }, h('div', { style: { fontSize: 11, color: 'var(--rd-text-muted)', fontWeight: 600, marginBottom: 4 } }, 'ОБЩИЙ ОБЪЁМ'), h('div', { style: { fontSize: 18, fontWeight: 700, color: 'var(--rd-info)' } }, totalVolume.toFixed(1) + ' м³') ), h('div', { style: { background: 'var(--rd-surface)', border: '1px solid var(--rd-border)', borderRadius: 10, padding: 14 } }, h('div', { style: { fontSize: 11, color: 'var(--rd-text-muted)', fontWeight: 600, marginBottom: 4 } }, 'СРЕДНЯЯ ГЛУБИНА'), h('div', { style: { fontSize: 18, fontWeight: 700, color: 'var(--rd-text)' } }, avgDepth + ' м') ) ), // Filters h('div', { style: { display: 'flex', gap: 8, flexWrap: 'wrap' } }, ['all', 'pending', 'in_progress', 'completed', 'delayed'].map(function (f) { var labels = { all: 'Все', pending: 'Ожидание', in_progress: 'В работе', completed: 'Завершён', delayed: 'Задержка' }; var isActive = filter === f; return h('button', { key: f, onClick: function () { setFilter(f); }, style: { fontSize: 12, fontWeight: 600, padding: '8px 14px', border: '1px solid var(--rd-border)', borderRadius: 8, background: isActive ? 'var(--rd-accent)' : 'var(--rd-surface)', color: isActive ? '#fff' : 'var(--rd-text)', cursor: 'pointer', transition: 'all 0.2s' } }, labels[f]); }) ), // Table h('div', { style: { background: 'var(--rd-surface)', border: '1px solid var(--rd-border)', borderRadius: 12, overflow: 'hidden' } }, h('table', { style: { width: '100%', borderCollapse: 'collapse' } }, h('thead', null, h('tr', { style: { background: 'var(--rd-surface-2)', borderBottom: '1px solid var(--rd-border)' } }, ['Код', 'Название', 'Глубина', 'Кольца', 'Объём', 'Стоимость', 'Даты', 'Статус', 'Прогресс'].map(function (col) { return h('th', { key: col, style: { padding: '12px 14px', textAlign: 'left', fontSize: 11, fontWeight: 700, color: 'var(--rd-text-muted)', textTransform: 'uppercase' } }, col); }) ) ), h('tbody', null, filtered.length === 0 ? h('tr', null, h('td', { colSpan: 9, style: { padding: 40, textAlign: 'center', color: 'var(--rd-text-muted)', fontSize: 13 } }, 'Нет котлованов')) : filtered.map(function (k, i) { return h('tr', { key: k.id, style: { borderBottom: i < filtered.length - 1 ? '1px solid var(--rd-border)' : 'none', transition: 'background 0.2s' }, onMouseEnter: function (e) { e.currentTarget.style.background = 'var(--rd-surface-2)'; }, onMouseLeave: function (e) { e.currentTarget.style.background = 'transparent'; } }, h('td', { style: { padding: '12px 14px', fontSize: 13, fontWeight: 700, color: 'var(--rd-accent)' } }, k.code), h('td', { style: { padding: '12px 14px', fontSize: 12, color: 'var(--rd-text)' } }, k.name || k.code || ('Котлован #' + (i + 1))), h('td', { style: { padding: '12px 14px', fontSize: 12, color: 'var(--rd-text)' } }, k.depth_m + ' м'), h('td', { style: { padding: '12px 14px', fontSize: 12, color: 'var(--rd-text)' } }, k.rings_count + ' шт'), h('td', { style: { padding: '12px 14px', fontSize: 12, color: 'var(--rd-text)' } }, k.volume_m3.toFixed(1) + ' м³'), h('td', { style: { padding: '12px 14px', fontSize: 12, color: 'var(--rd-text)' } }, fmt.money(k.cost)), h('td', { style: { padding: '12px 14px', fontSize: 11, color: 'var(--rd-text-muted)' } }, k.planned_start && k.planned_end ? fmt.dayLabel(k.planned_start) + ' — ' + fmt.dayLabel(k.planned_end) : '—' ), h('td', { style: { padding: '12px 14px' } }, statusBadge(k.status)), h('td', { style: { padding: '12px 14px' } }, progressBar(k.progress_pct)) ); }) ) ) ) ); };