Add project takeoff verification and bearing dimensions

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
CopilotandCopilot committed 2026-11-06 16:25:53 +09:00
1 parent d22c5008f0
commit 7182b6cbb4
15 files changed
+337 -28

No files matched your search

+8 -5
View File
@@ -5,11 +5,13 @@ import {cellKey} from './formula';
import {node,fmt,type TakeoffResult,type Selection} from './dashboard-types';
import {rowStatus} from './results-panel';
import type {QuantityInputs} from './model';
export function createReviewPanel(o:{result:TakeoffResult;stored:QuantityInputs;pier:string;project:{name:string;bridge:string};plan:{selected:PierModel;models:readonly PierModel[]};stale:boolean;miniState:{sheet:string;zoom:number};onCell:(cell:string)=>void}){
export function createReviewPanel(o:{result:TakeoffResult;stored:QuantityInputs;pier:string;project:{name:string;bridge:string};projectRows:{name:string;result:TakeoffResult}[];plan:{selected:PierModel;models:readonly PierModel[]};stale:boolean;miniState:{sheet:string;zoom:number};onCell:(cell:string)=>void}){
const panel=node('aside',undefined,'tq-right-panel'),preview=node('section',undefined,'tq-panel tq-mini-panel');const heading=node('div',undefined,'tq-panel-heading');heading.append(node('h3','산출서 미리보기'));const expand=node('button','⛶');expand.type='button';expand.setAttribute('aria-label','산출서 미리보기 전체화면');heading.append(expand);preview.append(heading);
const mini=createExcelPreview({result:o.result,stored:o.stored,pier:o.pier,project:o.project,plan:o.plan,state:o.miniState,compact:true,onCell:o.onCell});preview.append(mini);panel.append(preview);
const mini=createExcelPreview({result:o.result,stored:o.stored,pier:o.pier,project:o.project,plan:o.plan,projectRows:o.projectRows,state:o.miniState,compact:true,onCell:o.onCell});preview.append(mini);panel.append(preview);
const trace=node('section',undefined,'tq-panel tq-formula-panel takeoff-trace');trace.setAttribute('aria-live','polite');panel.append(trace);
expand.onclick=()=>{const dialog=node('dialog',undefined,'tq-preview-dialog');dialog.dataset.quantityPreviewDialog='true';dialog.setAttribute('aria-label','수량산출서 전체화면');const close=node('button','닫기 ×');close.type='button';close.className='tq-dialog-close';close.onclick=()=>dialog.close();dialog.append(close,createExcelPreview({result:o.result,stored:o.stored,pier:o.pier,project:o.project,plan:o.plan,state:{sheet:'__all__',zoom:1},onCell:o.onCell}));dialog.addEventListener('close',()=>{dialog.remove();expand.focus({preventScroll:true});},{once:true});document.body.append(dialog);dialog.showModal();};
let dialogTrace:HTMLElement|undefined,hasSelection=false;
const open=()=>{const dialog=node('dialog',undefined,'tq-preview-dialog tq-report-dialog');dialog.dataset.quantityPreviewDialog='true';dialog.setAttribute('aria-label','수량산출서 확대 및 산식 상세');const close=node('button','닫기 ×');close.type='button';close.className='tq-dialog-close';close.onclick=()=>dialog.close();const grid=node('div',undefined,'tq-report-grid'),documentView=createExcelPreview({result:o.result,stored:o.stored,pier:o.pier,project:o.project,plan:o.plan,projectRows:o.projectRows,state:{sheet:'표지및목차',zoom:0},onCell:o.onCell});dialogTrace=trace.cloneNode(true) as HTMLElement;dialogTrace.classList.add('tq-dialog-trace');grid.append(documentView,dialogTrace);dialog.append(close,grid);dialog.addEventListener('close',()=>{dialogTrace=undefined;dialog.remove();expand.focus({preventScroll:true});},{once:true});document.body.append(dialog);dialog.showModal();};
expand.onclick=open;
const select=(s:Selection)=>{
trace.replaceChildren(node('h3','산식 상세'),node('p',s.title,'tq-selected-title'));
const block=(label:string,content:HTMLElement)=>{const row=node('div',undefined,'tq-formula-block');row.append(node('b',label),content);trace.append(row);};
@@ -23,7 +25,8 @@ export function createReviewPanel(o:{result:TakeoffResult;stored:QuantityInputs;
const source=node('details',undefined,'tq-formula-source');source.append(node('summary','원본식 · 중간 계산값 · 참조 셀'));source.append(node('pre',s.formula));
for(const r of s.rows)if(r.formula!==r.sourceFormula)source.append(node('p',r.cell+' · 직선 모델: 원본 곡률항의 R→∞ 극한 적용'),node('pre','원본: '+r.sourceFormula));
for(const key of deps){const ix=key.lastIndexOf('!'),sheet=key.slice(0,ix),cell=key.slice(ix+1);if(s.rows.some(r=>sheet===DETAIL&&r.cell===cell))continue;let value:string;try{value=String(o.result.book.cell(sheet,cell));}catch{value='미입력';}source.append(node('p',key+' = '+value));}trace.append(source);
mini.dispatchEvent(new CustomEvent('takeoff:focus-cells',{detail:s.rows.map(r=>r.cell)}));
if(dialogTrace)dialogTrace.replaceChildren(...Array.from(trace.childNodes,n=>n.cloneNode(true)));
if(hasSelection)mini.dispatchEvent(new CustomEvent('takeoff:focus-cells',{detail:s.rows.map(r=>r.cell)}));hasSelection=true;
};
return {panel,select,focusPreview:()=>{preview.tabIndex=-1;preview.focus();}};
return {panel,select,open,focusPreview:()=>{preview.tabIndex=-1;preview.focus();}};
}