buhanka-finance-app 1.63.0 → 1.65.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.html +24 -12
  2. package/package.json +1 -1
package/index.html CHANGED
@@ -111,8 +111,11 @@ table.stick tr.subtotal .nm{background:var(--subbg)}
111
111
  table.wide{border-collapse:separate;border-spacing:0;table-layout:fixed}
112
112
  table.wide th,table.wide td{padding:5px 8px;white-space:nowrap;font-size:12.5px;border-bottom:1px solid var(--line)}
113
113
  table.wide th.nm,table.wide td.nm{position:sticky;left:0;z-index:3;background:var(--panel);width:230px;min-width:230px;max-width:230px;overflow:hidden;text-overflow:ellipsis;border-right:1px solid var(--line2)}
114
- table.wide thead th{position:sticky;top:0;z-index:4;background:var(--panel2)}
115
- table.wide thead th.nm{z-index:5;background:var(--panel2)}
114
+ table.wide thead th{position:sticky;top:0;z-index:6;background:var(--panel2)}
115
+ table.wide thead th.nm{z-index:7;background:var(--panel2)}
116
+ /* ячейки тела получают свой слой ниже шапки — иначе поля ввода в Chrome всплывают поверх неё */
117
+ table.wide tbody td{position:relative;z-index:0}
118
+ table.wide tbody td.nm{position:sticky;z-index:3}
116
119
  table.wide td.num,table.wide th.num{text-align:right;font-variant-numeric:tabular-nums}
117
120
  table.wide tr.sec>td{font-weight:800;background:var(--subbg)}
118
121
  table.wide tr.sec>td.nm{color:var(--accent);box-shadow:inset 3px 0 0 var(--accent)}
@@ -124,7 +127,10 @@ table.wide tr.acc>td{color:var(--muted);font-weight:400}
124
127
  table.wide tr.bal>td{background:transparent;color:var(--text);font-weight:400}
125
128
  table.wide tr.bal>td.nm{font-weight:700;color:var(--text)}
126
129
  table.wide tr.bal.brd>td{border-top:1px solid var(--line2)}
127
- table.wide col.plan,table.wide th.plan{background:rgba(232,163,61,.06)}
130
+ table.wide col.plan{background:rgba(232,163,61,.06)}
131
+ /* у шапки подсветка кладётся поверх непрозрачного фона, иначе строки просвечивают сквозь неё */
132
+ table.wide thead th.plan{background-color:var(--panel2);
133
+ background-image:linear-gradient(rgba(232,163,61,.06),rgba(232,163,61,.06))}
128
134
  table.wide tr.sec>td.nm,table.wide tr.sub>td.nm{background:var(--subbg)}
129
135
  table.wide tr.tot>td.nm{background-color:var(--panel);background-image:linear-gradient(var(--grandbg),var(--grandbg))}
130
136
  table.wide tr.bal>td.nm,table.wide tr.val>td.nm,table.wide tr.acc>td.nm{background:var(--panel)}
@@ -301,7 +307,7 @@ tr.subtotal>td:first-child{color:var(--accent);box-shadow:inset 3px 0 0 var(--ac
301
307
 
302
308
  <script>
303
309
  /* ============================================================ БУХАНКА · Финансы v2 ============================================================ */
304
- const APP_VERSION='9.6';
310
+ const APP_VERSION='9.8';
305
311
  const SCHEMA=8; /* версия структуры данных; растёт при доработках */
306
312
  const STORE_KEY='buhanka_finance_v9';/* НЕ МЕНЯТЬ НИКОГДА — иначе данные «слетят» при обновлении файла */
307
313
  const LEGACY_KEYS=['buhanka_finance_v8','buhanka_finance_v7','buhanka_finance_v6','buhanka_finance_v5'];
@@ -1675,16 +1681,22 @@ function renderPoints(C){
1675
1681
  const P=ST.ui.period; const useFact=periodLocked(P);
1676
1682
  document.getElementById('pageSub').textContent=`${P} · ${useFact?'период закрыт — факт':'период открыт — бюджет'}`;
1677
1683
  const struct=ST.structures.point; const comps={}; ST.points.forEach(p=>comps[p]=computePnL(p,P));
1678
- const colw=130; const minw=240+(ST.points.length+1)*colw;
1684
+ const colw=130, pctw=64; const minw=240+(ST.points.length+1)*(colw+pctw);
1685
+ const revOf={}; ST.points.forEach(p=>{ const r=comps[p].find(x=>x.row.role==='value'&&x.row.sign===1);
1686
+ revOf[p]=r?(useFact?r.fact:r.budget):0; });
1687
+ const revTot=ST.points.reduce((s,p)=>s+revOf[p],0);
1688
+ const pctCell=(v,base)=>`<td class="num pctcell">${base?(v/base*100).toFixed(1).replace('.',',')+'%':'—'}</td>`;
1679
1689
  let html=`<div class="panel"><div class="hd"><h3>Сравнение точек · ${P}</h3><div class="spacer"></div><span class="tag ${useFact?'lock':''}">${useFact?'значения: факт':'значения: бюджет'}</span></div><div class="bd" style="padding:0"><div class="tbl-wrap"><table class="pnl" style="table-layout:fixed;min-width:${minw}px">
1680
- <colgroup><col style="width:240px">${ST.points.map(()=>`<col style="width:${colw}px">`).join('')}<col style="width:${colw+10}px"></colgroup>
1681
- <thead><tr><th>Статья</th>${ST.points.map(p=>`<th class="num" style="white-space:normal">${p.replace('Скандинавский','Сканд.')}</th>`).join('')}<th class="num">Итого</th></tr></thead><tbody>`;
1690
+ <colgroup><col style="width:240px">${ST.points.map(()=>`<col style="width:${colw}px"><col style="width:${pctw}px">`).join('')}<col style="width:${colw+10}px"><col style="width:${pctw}px"></colgroup>
1691
+ <thead><tr><th>Статья</th>${ST.points.map(p=>`<th class="num" colspan="2" style="white-space:normal">${p.replace('Скандинавский','Сканд.')}</th>`).join('')}<th class="num" colspan="2">Итого</th></tr></thead><tbody>`;
1682
1692
  struct.forEach((row,i)=>{
1683
- if(row.role==='spacer'){html+=`<tr class="spacer"><td colspan="${ST.points.length+2}"></td></tr>`;return;}
1684
- if(row.role==='header'){html+=`<tr class="header"><td colspan="${ST.points.length+2}" class="nmcell">${esc(row.name)}</td></tr>`;return;}
1693
+ const span=(ST.points.length+1)*2+1;
1694
+ if(row.role==='spacer'){html+=`<tr class="spacer"><td colspan="${span}"></td></tr>`;return;}
1695
+ if(row.role==='header'){html+=`<tr class="header"><td colspan="${span}" class="nmcell">${esc(row.name)}</td></tr>`;return;}
1685
1696
  const cls=row.grand?'grand':row.role==='subtotal'?'subtotal':'value'; let tot=0,cells='';
1686
- ST.points.forEach(p=>{const x=comps[p][i]; const v=x?(useFact?x.fact:x.budget):0; tot+=v; cells+=`<td class="num">${v?fmt(v):'—'}</td>`;});
1687
- html+=`<tr class="${cls}"><td class="nmcell">${esc(row.name)}</td>${cells}<td class="num">${tot?fmt(tot):'—'}</td></tr>`;
1697
+ ST.points.forEach(p=>{const x=comps[p][i]; const v=x?(useFact?x.fact:x.budget):0; tot+=v;
1698
+ cells+=`<td class="num">${v?fmt(v):'—'}</td>`+pctCell(v,revOf[p]);});
1699
+ html+=`<tr class="${cls}"><td class="nmcell">${esc(row.name)}</td>${cells}<td class="num">${tot?fmt(tot):'—'}</td>${pctCell(tot,revTot)}</tr>`;
1688
1700
  });
1689
1701
  html+=`</tbody></table></div></div></div>`;
1690
1702
  // чеки и средний чек
@@ -1805,7 +1817,7 @@ function renderCF(C){
1805
1817
  const num=v=>v?fmt(v):'—';
1806
1818
  const neg=v=>v?'('+fmt(Math.abs(v))+')':'—';
1807
1819
  const cell=(v,cls)=>`<td class="num ${cls||''}">${v}</td>`;
1808
- /* out=true — строка расхода: в прогнозе показываем со знаком минус, как и факт */
1820
+ /* out=true — строка расхода: в прогнозе показываем в скобках, как и факт */
1809
1821
  const planCell=(day,key,shown,out)=>{
1810
1822
  if(day.actual) return `<td class="num">${shown}</td>`;
1811
1823
  const cur=planVal(M.mo,day.d,key);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "buhanka-finance-app",
3
- "version": "1.63.0",
3
+ "version": "1.65.0",
4
4
  "description": "Buhanka bakery finance dashboard — single-file web app",
5
5
  "license": "MIT",
6
6
  "files": [