v1.3.1: isDemo только по кнопке демо (сброс при импорте/JSON-restore, авто-сброс если демо-строк нет), подписи: агент через сервер Vibe AI, import — «Импорт показателей и нормативов со сверкой по сводной книге», убрана ссылка Мониторинг из header (monitor.html на месте)
This commit is contained in:
parent
b85d743c5a
commit
70585ea058
20
index.html
20
index.html
@ -144,7 +144,7 @@ tr.overall-green td:first-child{box-shadow:inset 4px 0 0 var(--green)}
|
|||||||
<div class="brand">
|
<div class="brand">
|
||||||
<h1>КФУ-агент</h1>
|
<h1>КФУ-агент</h1>
|
||||||
<span>Расчёт К1–К3 по Политике финансовой устойчивости — Долг/EBITDA, EBITDA/Проценты, Долг/Капитал · версия 1.3</span>
|
<span>Расчёт К1–К3 по Политике финансовой устойчивости — Долг/EBITDA, EBITDA/Проценты, Долг/Капитал · версия 1.3</span>
|
||||||
<a href="monitor.html" style="font-size:12px;color:var(--acc)">Мониторинг →</a>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="spacer"></div>
|
<div class="spacer"></div>
|
||||||
<div class="field"><label>Единицы вывода</label>
|
<div class="field"><label>Единицы вывода</label>
|
||||||
@ -170,7 +170,7 @@ tr.overall-green td:first-child{box-shadow:inset 4px 0 0 var(--green)}
|
|||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
<main>
|
<main>
|
||||||
<div class="note warn small" style="margin-bottom:16px">Учебный пример: если реестр пуст, значения — синтетические (демо). Для рабочих расчётов загрузите выгрузку СУО или отчётность на шаге 1.</div>
|
<div class="note warn small hidden" id="demoBanner" style="margin-bottom:16px">Учебный пример: реестр содержит синтетические данные (кнопка «Учебный пример»). Для рабочих расчётов загрузите выгрузку СУО, сводную книгу или отчётность на шаге 1.</div>
|
||||||
|
|
||||||
<!-- ============ STEP 1: DATA ============ -->
|
<!-- ============ STEP 1: DATA ============ -->
|
||||||
<section class="step on" id="step-data">
|
<section class="step on" id="step-data">
|
||||||
@ -187,7 +187,7 @@ tr.overall-green td:first-child{box-shadow:inset 4px 0 0 var(--green)}
|
|||||||
<div class="row" style="align-items:center;flex-wrap:wrap;gap:12px">
|
<div class="row" style="align-items:center;flex-wrap:wrap;gap:12px">
|
||||||
<button class="small on" id="btnKfuBook">Сводная книга КФУ 2025</button>
|
<button class="small on" id="btnKfuBook">Сводная книга КФУ 2025</button>
|
||||||
<input type="file" id="kfuBookFile" accept=".xlsx,.xlsm,.xls" class="hidden">
|
<input type="file" id="kfuBookFile" accept=".xlsx,.xlsm,.xls" class="hidden">
|
||||||
<span class="note small" id="kfuBookStatus">Берёт данные только из загруженной книги: долг/прочие/EBITDA/проценты/капитал (млн → млрд), нормативы, источники адресов. Зоны — пересчёт ПГУ.</span>
|
<span class="note small" id="kfuBookStatus">Импорт показателей и нормативов со сверкой по сводной книге. Данные берутся только из загруженной книги: долг/прочие/EBITDA/проценты/капитал (млн → млрд), нормативы, источники адресов.</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="grid2">
|
<div class="grid2">
|
||||||
@ -385,7 +385,7 @@ tr.overall-green td:first-child{box-shadow:inset 4px 0 0 var(--green)}
|
|||||||
<li>методика из вкладки «Отчётность МСФО»</li>
|
<li>методика из вкладки «Отчётность МСФО»</li>
|
||||||
</ul>
|
</ul>
|
||||||
<div class="row"><button class="small" id="btnChatClear">Очистить диалог</button></div>
|
<div class="row"><button class="small" id="btnChatClear">Очистить диалог</button></div>
|
||||||
<div class="note small warn" style="margin-top:12px">Функции ИИ (извлечение из отчётности, подбор строк, агент) работают при открытии файла внутри Claude. Разбор выгрузки СУО, ручной ввод, расчёт и выгрузка в Excel работают и автономно в браузере.</div>
|
<div class="note small" style="margin-top:12px">ИИ анализирует данные текущего реестра через сервер Vibe AI. Исходный Excel остаётся в браузере; при запросе ИИ передаются показатели и выбранные фрагменты отчётности.</div>
|
||||||
<div class="field" style="margin-top:12px"><label>Дополнительные указания агенту</label><textarea id="agentExtra" placeholder="например: отвечай в формате таблицы; используй запятую как десятичный разделитель"></textarea></div>
|
<div class="field" style="margin-top:12px"><label>Дополнительные указания агенту</label><textarea id="agentExtra" placeholder="например: отвечай в формате таблицы; используй запятую как десятичный разделитель"></textarea></div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -638,7 +638,7 @@ function renderPivot(){
|
|||||||
if(!keys.length) h+='<tr><td class="muted">Нет данных.</td></tr>';
|
if(!keys.length) h+='<tr><td class="muted">Нет данных.</td></tr>';
|
||||||
t.innerHTML=h;
|
t.innerHTML=h;
|
||||||
}
|
}
|
||||||
function renderAll(){ S.registry.sort(sortKeys); renderRegistry(); renderParams(); renderCalc(); renderPivot(); }
|
function renderAll(){ S.registry.sort(sortKeys); if(S.isDemo && !S.registry.some(r=>(r.source||'').startsWith('Демо'))){ S.isDemo=false; } $('#demoBanner').hidden = !S.isDemo; renderRegistry(); renderParams(); renderCalc(); renderPivot(); }
|
||||||
|
|
||||||
/* ---------- export ---------- */
|
/* ---------- export ---------- */
|
||||||
function calcMatrix(){
|
function calcMatrix(){
|
||||||
@ -723,14 +723,14 @@ $('#btnCsv').onclick = () => {
|
|||||||
|
|
||||||
/* ---------- state save / load ---------- */
|
/* ---------- state save / load ---------- */
|
||||||
$('#btnSaveState').onclick = () => {
|
$('#btnSaveState').onclick = () => {
|
||||||
const data = {v:1, saved:new Date().toISOString(), params:S.params, registry:S.registry, method:$('#methodText').value, agentExtra:$('#agentExtra').value};
|
const data = {v:1, saved:new Date().toISOString(), isDemo:!!S.isDemo, params:S.params, registry:S.registry, method:$('#methodText').value, agentExtra:$('#agentExtra').value};
|
||||||
const blob = new Blob([JSON.stringify(data,null,1)],{type:'application/json'});
|
const blob = new Blob([JSON.stringify(data,null,1)],{type:'application/json'});
|
||||||
const a=document.createElement('a'); a.href=URL.createObjectURL(blob); a.download='КФУ_состояние.json'; a.click();
|
const a=document.createElement('a'); a.href=URL.createObjectURL(blob); a.download='КФУ_состояние.json'; a.click();
|
||||||
};
|
};
|
||||||
$('#btnLoadState').onclick = () => $('#stateFile').click();
|
$('#btnLoadState').onclick = () => $('#stateFile').click();
|
||||||
$('#stateFile').onchange = e => {
|
$('#stateFile').onchange = e => {
|
||||||
const f=e.target.files[0]; if(!f) return;
|
const f=e.target.files[0]; if(!f) return;
|
||||||
const rd=new FileReader(); rd.onload=()=>{ try{ const d=JSON.parse(rd.result); if(d.params) S.params={...S.params,...d.params}; if(d.registry) S.registry=d.registry; if(d.method) $('#methodText').value=d.method; if(d.agentExtra) $('#agentExtra').value=d.agentExtra; renderAll(); toast('Состояние загружено'); }catch(err){ toast('Не удалось прочитать JSON: '+err.message); } }; rd.readAsText(f); e.target.value='';
|
const rd=new FileReader(); rd.onload=()=>{ try{ const d=JSON.parse(rd.result); if(d.params) S.params={...S.params,...d.params}; if(d.registry) S.registry=d.registry; if(d.method) $('#methodText').value=d.method; if(d.agentExtra) $('#agentExtra').value=d.agentExtra; S.isDemo = !!(d.isDemo && S.registry.some(r=>(r.source||'').startsWith('Демо'))); renderAll(); toast('Состояние загружено'); }catch(err){ toast('Не удалось прочитать JSON: '+err.message); } }; rd.readAsText(f); e.target.value='';
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ---------- demo data (synthetic) ---------- */
|
/* ---------- demo data (synthetic) ---------- */
|
||||||
@ -749,13 +749,12 @@ const DEMO_ROWS = [
|
|||||||
{name:'АО "ФНБ "Самрук-Казына"', period:'2025', debt:0.0, guar:0.0, ebitda:0.0, interest:0.0, equity:510.0, note:'демо, без EBITDA'},
|
{name:'АО "ФНБ "Самрук-Казына"', period:'2025', debt:0.0, guar:0.0, ebitda:0.0, interest:0.0, equity:510.0, note:'демо, без EBITDA'},
|
||||||
{name:'Консолидированная группа 1', period:'2025', debt:132.0, guar:8.0, ebitda:25.0, interest:9.6, equity:180.0, note:'демо, консолидация'}
|
{name:'Консолидированная группа 1', period:'2025', debt:132.0, guar:8.0, ebitda:25.0, interest:9.6, equity:180.0, note:'демо, консолидация'}
|
||||||
];
|
];
|
||||||
S._demo = false;
|
|
||||||
function loadDemo(){
|
function loadDemo(){
|
||||||
DEMO_ROWS.forEach(r=>addRow({name:r.name, key:keyFor(r.name), period:r.period, source:'Демо (синтетика)', debt:r.debt, guar:r.guar, ebitda:r.ebitda, interest:r.interest, equity:r.equity, note:'Синтетические данные, '+r.note}));
|
DEMO_ROWS.forEach(r=>addRow({name:r.name, key:keyFor(r.name), period:r.period, source:'Демо (синтетика)', debt:r.debt, guar:r.guar, ebitda:r.ebitda, interest:r.interest, equity:r.equity, note:'Синтетические данные, '+r.note}));
|
||||||
S._demo = true; renderAll();
|
S.isDemo = true; renderAll();
|
||||||
toast('Демо: синтетические данные — '+DEMO_ROWS.length+' компаний');
|
toast('Демо: синтетические данные — '+DEMO_ROWS.length+' компаний');
|
||||||
}
|
}
|
||||||
function toggleDemo(){ if(S._demo){ S.registry=S.registry.filter(r=>!(r.source||'').startsWith('Демо')); S._demo=false; renderAll(); toast('Демо-данные убраны'); } else loadDemo(); }
|
function toggleDemo(){ if(S.isDemo && S.registry.length === S.registry.filter(r=>(r.source||'').startsWith('Демо')).length){ S.registry=S.registry.filter(r=>!(r.source||'').startsWith('Демо')); S.isDemo=false; renderAll(); toast('Демо-данные убраны'); } else loadDemo(); }
|
||||||
$('#btnDemo').onclick = toggleDemo;
|
$('#btnDemo').onclick = toggleDemo;
|
||||||
|
|
||||||
/* ---------- navigation ---------- */
|
/* ---------- navigation ---------- */
|
||||||
@ -793,6 +792,7 @@ async function importKfuBook(file){
|
|||||||
const missing = EXPECT.filter(k=>!names.some(n=>n.includes(k)));
|
const missing = EXPECT.filter(k=>!names.some(n=>n.includes(k)));
|
||||||
if(missing.length || !names.some(n=>n.includes('план'))) throw new Error('в файле нет ожидаемых листов (' + [missing.join(', '),'«План 2026»'].filter(Boolean).join(', ') + '): это не сводная книга КФУ');
|
if(missing.length || !names.some(n=>n.includes('план'))) throw new Error('в файле нет ожидаемых листов (' + [missing.join(', '),'«План 2026»'].filter(Boolean).join(', ') + '): это не сводная книга КФУ');
|
||||||
const r = window.KfuWorkbook.analyzeWorkbook(wb);
|
const r = window.KfuWorkbook.analyzeWorkbook(wb);
|
||||||
|
S.isDemo = false;
|
||||||
if(!r.entries || !r.entries.length) throw new Error('в книге нет распознанных записей (листы компаний пустые?)');
|
if(!r.entries || !r.entries.length) throw new Error('в книге нет распознанных записей (листы компаний пустые?)');
|
||||||
const bad = r.entries.filter(x => x.debt==null && x.ebitda==null && x.equity==null && x.intExp==null);
|
const bad = r.entries.filter(x => x.debt==null && x.ebitda==null && x.equity==null && x.intExp==null);
|
||||||
if(bad.length) throw new Error('по ' + bad.length + ' компаниям не найдено ни одного показателя (' + bad.map(x=>x.name).slice(0,4).join(', ') + '…) — проверьте файл');
|
if(bad.length) throw new Error('по ' + bad.length + ' компаниям не найдено ни одного показателя (' + bad.map(x=>x.name).slice(0,4).join(', ') + '…) — проверьте файл');
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user