공용 파일(main.ts·index.html·style.css)에서 서로 얽혀 있어 한 커밋으로 묶음. - 지반: ① 형상 프로젝트 지반모델 관리창(생성·JSON 불러오기·교각별 비교·선택 적용), 프로젝트 JSON 내장 groundModel 추출, 교대 8행 통합 적용·공통지형 중복격자 제외 - 재료표·수량: 상단 ⑤ 메뉴·배근 바로가기, 결과 교각/탭 기억, 수량 워크북·정합 보정 - 랜딩: 옥성교 6교각 히어로 이미지·투영 강조점·좌→우 광선·지형 라운드/도로 연결 - 검증 스크립트(verify-project-ground/ground-abutments/okseong-user-files/quantity-*/landing-hero 등) 정본: DOC/04_실행/실행_*_2026-11-09_v0.1.00.md Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
45 lines
4.0 KiB
TypeScript
45 lines
4.0 KiB
TypeScript
import {straightCopingFormulas} from './coping-formulas.ts';
|
||
import {FormulaBook,cellKey,type Overrides} from './formula.ts';
|
||
import {template,templateHash} from './template-data.ts';
|
||
import {DETAIL,INPUTS,extraNumbers,specifications} from './schema.ts';
|
||
export type ExportRequest={project:{name:string;bridge:string};pier:string;overrides:Overrides;specs:Record<string,unknown>;reviewed:boolean;copingMode?:'straight';templateHash:string;planPng?:string;solplateMode?:'model'};
|
||
export function exportEdits(request:ExportRequest){
|
||
if(request.templateHash!==templateHash||!request.reviewed)throw new Error('원본 산식 적용 확인 후 다시 계산하세요.');
|
||
const edits:Record<string,Record<string,{value?:string|number|null;cached?:number|string;formula?:string}>>={},evaluation:Overrides={...request.overrides};
|
||
if(request.solplateMode!=='model'){delete evaluation[cellKey(DETAIL,'W64')];delete evaluation[cellKey(DETAIL,'K64')];}
|
||
const value=(sheet:string,cell:string,v:string|number|null)=>{(edits[sheet]??={})[cell]={value:v};evaluation[cellKey(sheet,cell)]=v??0;};
|
||
for(let r=18;r<=46;r++){
|
||
const raw=request.overrides[cellKey(INPUTS,'N'+r)];if(raw!==null&&(typeof raw!=='number'||!Number.isFinite(raw)))throw new Error('입력값 누락 N'+r);
|
||
value(INPUTS,'N'+r,request.copingMode==='straight'&&r===30?null:raw as number|null);
|
||
}
|
||
for(const v of extraNumbers){const n=request.overrides[cellKey(DETAIL,v.cell)];if(typeof n!=='number'||!Number.isFinite(n)||n<0)throw new Error(v.name+' 입력을 확인하세요.');value(DETAIL,v.cell,n);}
|
||
for(const v of specifications){const s=request.specs[v.key];if(typeof s!=='string'||!s.trim())throw new Error(v.name+'을 확인하세요.');value(DETAIL,v.cell,s);}
|
||
if(request.solplateMode==='model'){
|
||
const ton=request.overrides[cellKey(DETAIL,'W64')];
|
||
if(typeof ton!=='number'||!Number.isFinite(ton)||ton<0)throw new Error('모델 솔플레이트 중량을 확인하세요.');
|
||
value(DETAIL,'W64',ton);
|
||
value(DETAIL,'K64','3D 모델 판별 체적 합계 × 7.85 (앱 재생성 값)');
|
||
}
|
||
for(let i=2;i<=6;i++){
|
||
const sheet='3.3 수량산출_P'+i;
|
||
for(const [cell,c]of Object.entries(template[sheet]))if(typeof c.value==='number'||typeof c.value==='string'&&c.value.startsWith('='))value(sheet,cell,null);
|
||
value(sheet,'F2','(미사용)');value(sheet,'BG5','미사용');
|
||
const col=['P','R','T','V','X'][i-2];for(let r=18;r<=46;r++)value(INPUTS,col+r,null);value(INPUTS,col+'17','미사용');
|
||
value('1. 수량집계',['Q','T','W','Z','AC'][i-2]+'4','미사용');
|
||
}
|
||
// The example sheet must stay a source example, not follow the active pier's straight R.
|
||
for(let r=6;r<=34;r++){const c=template['3.3 수량산출_ex)']['BG'+r];if(c&&typeof c.cached==='number')value('3.3 수량산출_ex)','BG'+r,c.cached);}
|
||
value(INPUTS,'N17',request.pier);value(DETAIL,'F2','('+request.pier+')');value(DETAIL,'BG5',request.pier);value('1. 수량집계','N4',request.pier);
|
||
value('표지및목차','A6',request.project.name);value('표지및목차','A14',request.project.bridge+' · '+request.pier);value('표지및목차','A24',new Date().toISOString().slice(0,10));
|
||
const formulas=request.copingMode==='straight'?straightCopingFormulas:{};
|
||
for(const [key,formula]of Object.entries(formulas)){const pos=key.lastIndexOf('!');(edits[key.slice(0,pos)]??={})[key.slice(pos+1)]={formula};}
|
||
const book=new FormulaBook(evaluation,template,formulas);
|
||
for(const [sheet,cells]of Object.entries(template))for(const [cell,c]of Object.entries(cells)){
|
||
if(typeof c.value!=='string'||(!c.value.startsWith('=')||c.value.length===1)||edits[sheet]?.[cell]&&Object.hasOwn(edits[sheet][cell],'value'))continue;
|
||
const n=book.cell(sheet,cell);if(typeof n!=='number'||!Number.isFinite(n))throw new Error('출력 수식 검증 실패 '+sheet+'!'+cell);
|
||
(edits[sheet]??={})[cell]={...edits[sheet]?.[cell],cached:n};
|
||
}
|
||
if(request.planPng&&(!/^[A-Za-z0-9+/=]+$/.test(request.planPng)||request.planPng.length>1500000))throw new Error('평면도 이미지 형식을 확인하세요.');
|
||
return {templateHash,edits,planPng:request.planPng};
|
||
}
|