// Демо-данные договоров аренды ОЦО ЮС const DEMO_CONTRACTS = [ { id: 1, number: 'ДА-2026-001', counterparty: 'ТОО "Алма-Ата Ритейл"', bin: '203456789012', branch: 'Алматы', initiator: 'Иванова Мария Петровна', object: 'Помещение офиса', area: 120, cadastral: '01:49:000123:456', rate: 650000, term: 24, total: 15600000, signer: 'Ахметов Ержан Болатович, Директор', status: 'ai-review', risks: ['high'], riskDetails: [ { level: 'high', text: 'Тариф не соответствует SAP (заявка: 650000, SAP: 720000)' }, { level: 'medium', text: 'Отсутствие кадастрового паспорта в приложении' } ], sapTariffDate: '14.09.2026', sapTariffRate: 720000, aiChecks: [ { name: 'ГК РК Статья 403', passed: true, comment: 'Существенные условия указаны' }, { name: 'Полномочия подписанта', passed: true, comment: 'Доверенность №123 от 01.01.2026 действительна' }, { name: 'Тариф SAP', passed: false, comment: 'Ставка в заявке ниже актуального тарифа на 9.7%' }, { name: 'Кадастровые данные', passed: false, comment: 'Номер указан, паспорт не приложен' } ], date: '12.09.2026', comment: '' }, { id: 2, number: 'ДА-2026-002', counterparty: 'ИП "Самат"', bin: '198765432109', branch: 'Астана', initiator: 'Кузнецов Андрей Владимирович', object: 'Торговая площадь', area: 85, cadastral: '02:11:000456:789', rate: 480000, term: 12, total: 5760000, signer: 'Саматов Самат Нурланович, ИП', status: 'new', risks: [], riskDetails: [], sapTariffDate: '14.09.2026', sapTariffRate: 480000, aiChecks: [ { name: 'ГК РК Статья 403', passed: true, comment: 'Существенные условия указаны' }, { name: 'Полномочия подписанта', passed: true, comment: 'ИП действует без доверенности' }, { name: 'Тариф SAP', passed: true, comment: 'Ставка соответствует тарифу' }, { name: 'Кадастровые данные', passed: true, comment: 'Паспорт приложен' } ], date: '13.09.2026', comment: '' }, { id: 3, number: 'ДА-2026-003', counterparty: 'АО "Каспий Банк"', bin: '211234567890', branch: 'Алматы', initiator: 'Султанова Гульнара Ахметовна', object: 'Помещение отделения', area: 250, cadastral: '01:49:000789:012', rate: 1200000, term: 36, total: 43200000, signer: 'Ибраев Нурлан Жуматович, Управляющий', status: 'lawyer-check', risks: ['medium'], riskDetails: [ { level: 'medium', text: 'Контрагентская версия содержит отклонения в пункте 5.2' } ], sapTariffDate: '14.09.2026', sapTariffRate: 1150000, aiChecks: [ { name: 'ГК РК Статья 403', passed: true, comment: 'Существенные условия указаны' }, { name: 'Полномочия подписанта', passed: true, comment: 'Приказ №456 от 15.03.2025' }, { name: 'Тариф SAP', passed: false, comment: 'Ставка выше тарифа на 4.3% (требуется обоснование)' }, { name: 'Кадастровые данные', passed: true, comment: 'Все документы в порядке' } ], diff: [ { op: 'del', text: '5.2. Арендатор обязуется оплатить аренду до 10 числа текущего месяца' }, { op: 'add', text: '5.2. Арендатор обязуется оплатить аренду до 15 числа текущего месяца' }, { op: 'del', text: '7.1. Договор действует до 31.12.2028' }, { op: 'add', text: '7.1. Договор действует до 30.06.2029 с автоматической пролонгацией' } ], date: '10.09.2026', comment: '' }, { id: 4, number: 'ДА-2026-004', counterparty: 'ТОО "СтройМаш"', bin: '205678901234', branch: 'Караганда', initiator: 'Петров Сергей Михайлович', object: 'Складское помещение', area: 500, cadastral: '', rate: 350000, term: 6, total: 2100000, signer: 'Куанышев Болатбек Асылбекович, Директор', status: 'revision', risks: ['high'], riskDetails: [ { level: 'high', text: 'Отсутствуют кадастровые данные объекта' } ], sapTariffDate: '14.09.2026', sapTariffRate: 380000, aiChecks: [ { name: 'ГК РК Статья 403', passed: true, comment: 'Существенные условия указаны' }, { name: 'Полномочия подписанта', passed: true, comment: 'Доверенность №789 от 20.02.2026' }, { name: 'Тариф SAP', passed: false, comment: 'Ставка ниже тарифа на 7.9%' }, { name: 'Кадастровые данные', passed: false, comment: 'Данные отсутствуют' } ], date: '08.09.2026', comment: 'Запрошены кадастровые документы у инициатора' }, { id: 5, number: 'ДА-2026-005', counterparty: 'ТОО "Нур-СултанTrade"', bin: '219876543210', branch: 'Астана', initiator: 'Омарова Айгуль Ержановна', object: 'Офисное помещение', area: 180, cadastral: '02:11:001234:567', rate: 900000, term: 18, total: 16200000, signer: 'Жуманов Ермек Бауыржанович, Генеральный директор', status: 'approved', risks: [], riskDetails: [], sapTariffDate: '14.09.2026', sapTariffRate: 900000, aiChecks: [ { name: 'ГК РК Статья 403', passed: true, comment: 'Существенные условия указаны' }, { name: 'Полномочия подписанта', passed: true, comment: 'Устав подтверждает полномочия' }, { name: 'Тариф SAP', passed: true, comment: 'Ставка соответствует тарифу' }, { name: 'Кадастровые данные', passed: true, comment: 'Все документы приложены' } ], date: '05.09.2026', comment: 'Согласовано, отправлено на подпись' }, { id: 6, number: 'ДА-2026-006', counterparty: 'ИП "Алия"', bin: '187654321098', branch: 'Шымкент', initiator: 'Турсумбаев Максат Алиевич', object: 'Торговая точка', area: 45, cadastral: '03:22:002345:678', rate: 220000, term: 12, total: 2640000, signer: 'Каримова Алия Сериковна, ИП', status: 'ai-review', risks: ['low'], riskDetails: [ { level: 'low', text: 'Небольшие отклонения в формулировках' } ], sapTariffDate: '14.09.2026', sapTariffRate: 230000, aiChecks: [ { name: 'ГК РК Статья 403', passed: true, comment: 'Существенные условия указаны' }, { name: 'Полномочия подписанта', passed: true, comment: 'ИП действует без доверенности' }, { name: 'Тариф SAP', passed: false, comment: 'Ставка ниже тарифа на 4.3%' }, { name: 'Кадастровые данные', passed: true, comment: 'Документы приложены' } ], date: '14.09.2026', comment: '' }, { id: 7, number: 'ДА-2026-007', counterparty: 'ТОО "Актобе-Инвест"', bin: '213456789012', branch: 'Актобе', initiator: 'Жанбеков Руслан Кенжевич', object: 'Производственное помещение', area: 320, cadastral: '04:33:003456:789', rate: 580000, term: 24, total: 13920000, signer: 'Алиев Серикжан Болатович, Директор', status: 'approved', risks: [], riskDetails: [], sapTariffDate: '14.09.2026', sapTariffRate: 580000, aiChecks: [ { name: 'ГК РК Статья 403', passed: true, comment: 'Существенные условия указаны' }, { name: 'Полномочия подписанта', passed: true, comment: 'Доверенность №321 от 10.01.2026' }, { name: 'Тариф SAP', passed: true, comment: 'Ставка соответствует тарифу' }, { name: 'Кадастровые данные', passed: true, comment: 'Все документы в порядке' } ], date: '03.09.2026', comment: 'Согласовано' }, { id: 8, number: 'ДА-2026-008', counterparty: 'ТОО "Байтерек-Строй"', bin: '224567890123', branch: 'Астана', initiator: 'Ким Дмитрий Андреевич', object: 'Офис', area: 95, cadastral: '', rate: 520000, term: 12, total: 6240000, signer: 'Ли Владимир Петрович, Генеральный директор', status: 'revision', risks: ['high'], riskDetails: [ { level: 'high', text: 'Нет кадастровых данных' }, { level: 'medium', text: 'Срок аренды не соответствует стандарту' } ], sapTariffDate: '14.09.2026', sapTariffRate: 550000, aiChecks: [ { name: 'ГК РК Статья 403', passed: true, comment: 'Существенные условия указаны' }, { name: 'Полномочия подписанта', passed: true, comment: 'Протокол №5 от 15.12.2025' }, { name: 'Тариф SAP', passed: false, comment: 'Ставка ниже тарифа на 5.5%' }, { name: 'Кадастровые данные', passed: false, comment: 'Отсутствуют' } ], date: '11.09.2026', comment: 'Ожидание кадастровых документов' } ]; // Состояние приложения let contracts = []; let currentFilter = 'all'; let currentScreen = 'queue'; let selectedContract = null; // Инициализация function init() { loadContracts(); renderQueue(); renderMetrics(); renderProblems(); renderRegistry(); setupNavigation(); setupFilters(); setupSearch(); setupForm(); setupThemeToggle(); } // Загрузка данных из localStorage или демо function loadContracts() { const stored = localStorage.getItem('contracts'); if (stored) { contracts = JSON.parse(stored); } else { contracts = JSON.parse(JSON.stringify(DEMO_CONTRACTS)); saveContracts(); } } // Сохранение в localStorage function saveContracts() { localStorage.setItem('contracts', JSON.stringify(contracts)); } // Навигация function setupNavigation() { document.querySelectorAll('.kt-ai-nav-item').forEach(item => { item.addEventListener('click', () => { const screen = item.dataset.screen; navigateTo(screen); }); }); } function navigateTo(screen) { currentScreen = screen; // Обновляем активный пункт меню document.querySelectorAll('.kt-ai-nav-item').forEach(item => { item.classList.toggle('active', item.dataset.screen === screen); }); // Показываем экран document.querySelectorAll('.screen').forEach(s => s.classList.remove('active')); document.getElementById(`screen-${screen}`).classList.add('active'); // Обновляем заголовок const titles = { queue: { title: 'Очередь договоров', subtitle: 'Проверка и согласование договоров аренды' }, problems: { title: 'Проблемные заявки', subtitle: 'Требуют дозапроса данных у инициатора' }, registry: { title: 'Реестр договоров', subtitle: 'История всех договоров' }, new: { title: 'Новая заявка', subtitle: 'Создание заявки на договор аренды' }, contract: { title: 'Карточка договора', subtitle: 'Детальная информация' } }; document.getElementById('page-title').textContent = titles[screen]?.title || 'Договоры аренды'; document.getElementById('page-subtitle').textContent = titles[screen]?.subtitle || ''; if (screen === 'queue') renderQueue(); if (screen === 'problems') renderProblems(); if (screen === 'registry') renderRegistry(); } // Фильтры function setupFilters() { document.querySelectorAll('.kt-ai-filter-chip').forEach(chip => { chip.addEventListener('click', () => { document.querySelectorAll('.kt-ai-filter-chip').forEach(c => c.classList.remove('active')); chip.classList.add('active'); currentFilter = chip.dataset.filter; renderQueue(); }); }); } function filterByStatus(status) { document.querySelectorAll('.kt-ai-filter-chip').forEach(c => { c.classList.toggle('active', c.dataset.filter === status); }); currentFilter = status; renderQueue(); navigateTo('queue'); } // Поиск function setupSearch() { document.getElementById('search-input').addEventListener('input', (e) => { renderQueue(e.target.value); }); } // Рендер очереди function renderQueue(searchTerm = '') { const tbody = document.getElementById('queue-table-body'); let filtered = contracts; // Фильтр по статусу if (currentFilter !== 'all') { filtered = filtered.filter(c => c.status === currentFilter); } // Поиск if (searchTerm) { const term = searchTerm.toLowerCase(); filtered = filtered.filter(c => c.number.toLowerCase().includes(term) || c.counterparty.toLowerCase().includes(term) || c.branch.toLowerCase().includes(term) ); } tbody.innerHTML = filtered.map(c => ` ${c.number} ${c.counterparty} ${c.branch} ${formatMoney(c.total)} ${getStatusName(c.status)} ${c.risks.length > 0 ? `⚠ ${c.risks.length}` : '—'} ${c.date} `).join(''); } // Рендер метрик function renderMetrics() { const total = contracts.length; const pending = contracts.filter(c => ['new', 'ai-review', 'lawyer-check'].includes(c.status)).length; const risks = contracts.filter(c => c.risks.some(r => r === 'high' || r === 'medium')).length; document.getElementById('metric-total').textContent = total; document.getElementById('metric-pending').textContent = pending; document.getElementById('metric-risks').textContent = risks; const highRisks = contracts.filter(c => c.risks.some(r => r === 'high')).length; const banner = document.getElementById('banner-risk'); if (highRisks > 0) { document.getElementById('risk-count').textContent = highRisks; banner.classList.remove('hidden'); } else { banner.classList.add('hidden'); } } // Рендер проблемных function renderProblems() { const tbody = document.getElementById('problems-table-body'); const problems = contracts.filter(c => c.status === 'revision' || (c.risks.length > 0 && c.risks.includes('high'))); tbody.innerHTML = problems.map(c => ` ${c.number} ${c.riskDetails[0]?.text || 'Неполные данные'} ${c.branch} ${c.date} `).join(''); } // Рендер реестра function renderRegistry() { const tbody = document.getElementById('registry-table-body'); tbody.innerHTML = contracts.map(c => ` ${c.number} ${c.counterparty} ${c.object} ${formatMoney(c.total)} ${getStatusName(c.status)} ${c.comment || 'Без изменений'} `).join(''); } // Открытие карточки договора function openContract(id) { const c = contracts.find(x => x.id === id); if (!c) return; selectedContract = c; document.getElementById('contract-title').textContent = c.number; document.getElementById('contract-status').setAttribute('data-status', c.status); document.getElementById('contract-status').textContent = getStatusName(c.status); document.getElementById('contract-counterparty').textContent = c.counterparty; document.getElementById('contract-bin').textContent = c.bin; document.getElementById('contract-branch').textContent = c.branch; document.getElementById('contract-initiator').textContent = c.initiator; document.getElementById('contract-object').textContent = c.object; document.getElementById('contract-area').textContent = c.area + ' м²'; document.getElementById('contract-cadastral').textContent = c.cadastral || 'Не указан'; document.getElementById('contract-rate').textContent = formatMoney(c.rate); document.getElementById('contract-term').textContent = c.term + ' мес'; document.getElementById('contract-total').textContent = formatMoney(c.total); // SAP тариф document.getElementById('sap-tariff-date').textContent = c.sapTariffDate; document.getElementById('sap-tariff-rate').textContent = formatMoney(c.sapTariffRate); const diff = c.rate - c.sapTariffRate; const diffPercent = ((diff / c.sapTariffRate) * 100).toFixed(1); document.getElementById('sap-diff').textContent = `${diff > 0 ? '+' : ''}${diffPercent}% (${diff > 0 ? 'выше' : 'ниже'})`; // Проверки ИИ const checksHtml = c.aiChecks.map(check => `
${check.passed ? '✅' : '⚠️'}
${check.name}
${check.comment}
`).join(''); document.getElementById('ai-checks').innerHTML = checksHtml; // Отклонения const diffCard = document.getElementById('diff-card'); if (c.diff && c.diff.length > 0) { diffCard.style.display = 'block'; document.getElementById('diff-content').innerHTML = c.diff.map(d => `
${d.op === 'add' ? '+' : '-'} ${d.text}
` ).join(''); } else { diffCard.style.display = 'none'; } navigateTo('contract'); } // Форма новой заявки function setupForm() { document.getElementById('new-contract-form').addEventListener('submit', (e) => { e.preventDefault(); const form = e.target; const formData = new FormData(form); const newContract = { id: contracts.length + 1, number: `ДА-2026-${String(contracts.length + 1).padStart(3, '0')}`, counterparty: formData.get('counterparty'), bin: formData.get('bin'), branch: formData.get('branch'), initiator: formData.get('initiator'), object: formData.get('object'), area: Number(formData.get('area')), cadastral: formData.get('cadastral'), rate: Number(formData.get('rate')), term: Number(formData.get('term')), total: Number(formData.get('rate')) * Number(formData.get('term')), signer: formData.get('signer'), status: 'new', risks: [], riskDetails: [], sapTariffDate: new Date().toLocaleDateString('ru-RU'), sapTariffRate: Number(formData.get('rate')), aiChecks: [], date: new Date().toLocaleDateString('ru-RU'), comment: formData.get('comment') }; contracts.unshift(newContract); saveContracts(); renderMetrics(); renderQueue(); renderRegistry(); form.reset(); alert('Заявка отправлена! ИИ-агент начнёт обработку в ближайшее время.'); navigateTo('queue'); }); } // Переключение темы function setupThemeToggle() { const btn = document.getElementById('theme-toggle'); btn.addEventListener('click', () => { const html = document.documentElement; const isDark = html.getAttribute('data-theme') === 'dark'; html.setAttribute('data-theme', isDark ? 'light' : 'dark'); btn.textContent = isDark ? '🌙' : '☀️'; }); } // Вспомогательные функции function getStatusName(status) { const names = { 'new': 'Новый', 'ai-review': 'ИИ проверка', 'lawyer-check': 'Проверка юриста', 'approved': 'Согласовано', 'revision': 'На доработке' }; return names[status] || status; } function formatMoney(amount) { return new Intl.NumberFormat('ru-RU', { style: 'currency', currency: 'KZT', maximumFractionDigits: 0 }).format(amount); } function sendReminder(id) { alert('Напоминание отправлено инициатору через Лотус'); } // Кнопки действий document.getElementById('btn-approve')?.addEventListener('click', () => { if (selectedContract) { selectedContract.status = 'approved'; selectedContract.comment = 'Согласовано ' + new Date().toLocaleDateString('ru-RU'); saveContracts(); alert('Договор согласован и отправлен на подпись'); navigateTo('queue'); } }); document.getElementById('btn-revision')?.addEventListener('click', () => { if (selectedContract) { selectedContract.status = 'revision'; selectedContract.comment = 'На доработке ' + new Date().toLocaleDateString('ru-RU'); saveContracts(); alert('Договор возвращён на доработку'); navigateTo('queue'); } }); document.getElementById('btn-download')?.addEventListener('click', () => { alert('Файл договора будет скачан. В рабочей версии — генерация Word через ИИ.'); }); // Запуск init();