Merge remote-tracking branch 'origin/main_laptop_1' into sub_laptop_2
This commit is contained in:
@@ -0,0 +1 @@
|
||||
_data/
|
||||
@@ -0,0 +1,108 @@
|
||||
/* =============================================================================
|
||||
* M01_SL_Api.ts
|
||||
* 시트 로직 Api — 목록 · 열기 · 저장(서버가 바깥 값을 다시 넣고 같은 엔진으로 다시 셈) · 지우기 ·
|
||||
* 바깥 값 한 번에 받기(품셈 표 · 노임 · 자재 · 장비 · 기존 로직 결과)
|
||||
* 서버 = `M01_SL_Router.py`(`/api/m01/sl/*`) · 정함 `docs/raw/M01_쉬운단가/시트로직_정함.md` 4 · 5 · 6
|
||||
* ========================================================================== */
|
||||
|
||||
import type { Workbook } from "../../A00_Common/spreadsheet/spreadsheet_types";
|
||||
|
||||
/** 바깥 값 하나 — 값은 열 때 · 저장 때 마스터에서 새로(표는 사본으로 들고 있지 않음)
|
||||
* · 표 = 품셈 표 통째(머리 줄 + 줄 · 범위 조건 · 값은 「이름·아래」 「이름·위」 두 칸)
|
||||
* · 노임 · 자재 = 그 줄의 단가(`/calc` 와 같은 셈 · 준용 · 낮은 값)
|
||||
* · 장비 = 기계경비 로직 부름 글(EasyCalc `machineElement` 의 element) + 넘길 입력값 → 한 시간 값
|
||||
* · 로직 = 기존 로직 결과(`/calc` · 돈 로직은 `field` 비목 · 기본 계) */
|
||||
export type SlOutside =
|
||||
| { id: string; kind: "표"; table: string }
|
||||
| { id: string; kind: "노임"; key: string }
|
||||
| { id: string; kind: "자재"; key: string }
|
||||
| {
|
||||
id: string;
|
||||
kind: "장비";
|
||||
element: string;
|
||||
inputs: Record<string, unknown>;
|
||||
field?: SlField;
|
||||
}
|
||||
| {
|
||||
id: string;
|
||||
kind: "로직";
|
||||
key: string;
|
||||
inputs: Record<string, unknown>;
|
||||
field?: SlField;
|
||||
};
|
||||
export type SlField = "노무비" | "재료비" | "경비" | "계";
|
||||
|
||||
/** 바깥 값이 들어갈 자리 — 시트 id · 칸(표는 이 칸을 왼쪽 위로 펼침) */
|
||||
export interface SlOutsideAt {
|
||||
item: SlOutside;
|
||||
sheet: string;
|
||||
cell: string;
|
||||
}
|
||||
|
||||
/** 바깥 값 답 — 표는 `rows`(머리 줄 포함) · 그 밖은 `value` · 못 구하면 ok false + 쉬운 말 */
|
||||
export interface SlOutsideValue {
|
||||
id: string;
|
||||
ok: boolean;
|
||||
value?: number | null;
|
||||
rows?: (string | number | null)[][];
|
||||
name?: string;
|
||||
unit?: string;
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
/** 시트 로직 한 벌 = 통합문서 하나(상자 = 시트) + 바깥 값 자리 */
|
||||
export interface SlLogic {
|
||||
/** 새 로직 null · 저장하면 서버가 `SL-0001` 꼴로 줌 */
|
||||
key: string | null;
|
||||
이름: string;
|
||||
결과단위: string;
|
||||
book: Workbook;
|
||||
outside: SlOutsideAt[];
|
||||
/** 다른 창이 더하는 칸(상자 · 알약 · 선 …)은 그대로 저장 · 돌려줌 */
|
||||
[extra: string]: unknown;
|
||||
}
|
||||
|
||||
/** 목록 한 줄 */
|
||||
export interface SlListItem {
|
||||
key: string;
|
||||
이름: string;
|
||||
결과단위: string;
|
||||
/** 마지막 저장 때(ISO) */
|
||||
saved: string;
|
||||
}
|
||||
|
||||
/** 저장 답 — `logic.book.계산값` 은 서버가 다시 셈한 값 · `values` 는 넣은 바깥 값 */
|
||||
export interface SlSaved {
|
||||
key: string;
|
||||
logic: SlLogic;
|
||||
values: SlOutsideValue[];
|
||||
}
|
||||
|
||||
const notReady = (): never => {
|
||||
throw new Error("준비 중");
|
||||
};
|
||||
|
||||
export async function slList(): Promise<SlListItem[]> {
|
||||
return notReady();
|
||||
}
|
||||
|
||||
export async function slGet(_key: string): Promise<SlLogic> {
|
||||
return notReady();
|
||||
}
|
||||
|
||||
export async function slSave(_logic: SlLogic): Promise<SlSaved> {
|
||||
return notReady();
|
||||
}
|
||||
|
||||
export async function slDelete(_key: string): Promise<void> {
|
||||
return notReady();
|
||||
}
|
||||
|
||||
export async function slOutside(_items: SlOutside[]): Promise<SlOutsideValue[]> {
|
||||
return notReady();
|
||||
}
|
||||
|
||||
/** 실패 → 쉬운 말(EasyCalc `plainError` 그대로) */
|
||||
export function slPlain(_e: unknown): string {
|
||||
return notReady();
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/* =============================================================================
|
||||
* M01_SL_Eval.ts
|
||||
* 시트 로직 화면 계산 — 바깥 값 넣기 → 우리 스프레드시트 엔진(브라우저) → 출력 알약 · 결과 읽기 · 검사
|
||||
* 저장 때는 서버가 같은 엔진을 Node 로(정함 5) · DOM 없음
|
||||
* ========================================================================== */
|
||||
|
||||
import type { SheetLogic, SlOutside } from "./M01_SL_Model";
|
||||
|
||||
/** 알약 값 — 수 · 글 · 참거짓 · 빈 칸 */
|
||||
export type SlValue = number | string | boolean | null;
|
||||
|
||||
/** 바깥 값 하나 — 표는 칸 덩어리(cell 이 왼위) */
|
||||
export interface SlOutsideValue {
|
||||
node: string;
|
||||
cell: string;
|
||||
value: SlValue | SlValue[][];
|
||||
}
|
||||
|
||||
export interface SlEvalResult {
|
||||
/** 상자 id → 출력 알약 이름 → 값 */
|
||||
pills: Record<string, Record<string, SlValue>>;
|
||||
result: { 노무비: number | null; 재료비: number | null; 경비: number | null; 계: number | null };
|
||||
/** 쉬운 말 */
|
||||
errors: string[];
|
||||
}
|
||||
|
||||
const notReady = (): never => {
|
||||
throw new Error("준비 중");
|
||||
};
|
||||
|
||||
/** 바깥 값 칸 목록 — 화면 · 서버가 이 칸에 값을 넣음 */
|
||||
export function outsideCells(_sl: SheetLogic): SlOutside[] {
|
||||
return notReady();
|
||||
}
|
||||
|
||||
/** 바깥 값 넣기 — 새 시트 로직(받은 것은 안 바꿈) */
|
||||
export function applyOutside(_sl: SheetLogic, _values: SlOutsideValue[]): SheetLogic {
|
||||
return notReady();
|
||||
}
|
||||
|
||||
/** 화면 계산 */
|
||||
export function evalLogic(_sl: SheetLogic): SlEvalResult {
|
||||
return notReady();
|
||||
}
|
||||
|
||||
/** 검사 — 빈 입력 알약 · 순환 · 오류 칸(쉬운 말 목록) */
|
||||
export function checkLogic(_sl: SheetLogic): string[] {
|
||||
return notReady();
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
/* =============================================================================
|
||||
* M01_SL_Model.ts
|
||||
* 시트 로직 Model — 로직 한 벌 = 통합문서 하나 · 상자 하나 = 시트 하나 · 알약 = 이름 붙은 칸
|
||||
* 선 = 받는 입력 알약 칸에 「'시트 이름'!칸」 참조 수식 · DOM 없음
|
||||
* 모양은 `docs/raw/M01_쉬운단가/시트로직_정함.md` 정함 1~5 그대로
|
||||
* ========================================================================== */
|
||||
|
||||
import type { Workbook } from "../../A00_Common/spreadsheet/spreadsheet_types";
|
||||
|
||||
/** 상자 종류 — 입력값 · 고정값 · 표 · 계산 · 항목 · 다른 로직 · 결과 */
|
||||
export type SlKind = "input" | "const" | "table" | "calc" | "item" | "logic" | "result";
|
||||
|
||||
/** 알약 = 이름 붙은 칸 */
|
||||
export interface SlPill {
|
||||
name: string;
|
||||
/** 「B3」 */
|
||||
cell: string;
|
||||
unit?: string;
|
||||
/** 바깥 값 칸 — 열 때 · 저장 때 마스터에서 넣음 */
|
||||
outside?: boolean;
|
||||
}
|
||||
|
||||
/** 상자 = 시트 하나 */
|
||||
export interface SlNode {
|
||||
id: string;
|
||||
kind: SlKind;
|
||||
name: string;
|
||||
sheetId: string;
|
||||
pillsIn: SlPill[];
|
||||
pillsOut: SlPill[];
|
||||
/** 표 키 · 요소 · 기존 로직 키 · 내 표 id */
|
||||
ref?: string;
|
||||
/** 띠 단계 — 0 입력값 · 1 표 · 2 계산 · 3 항목 · 4 결과 */
|
||||
stage: number;
|
||||
}
|
||||
|
||||
/** 선 — 출력 알약 → 입력 알약 */
|
||||
export interface SlEdge {
|
||||
id: string;
|
||||
from: { node: string; pill: string };
|
||||
to: { node: string; pill: string };
|
||||
}
|
||||
|
||||
/** 바깥 값 칸 */
|
||||
export interface SlOutside {
|
||||
node: string;
|
||||
cell: string;
|
||||
kind: "table" | "price" | "logic";
|
||||
ref: string;
|
||||
}
|
||||
|
||||
/** 내 표 — 품셈에 없는 표(사용자가 만듦) */
|
||||
export interface SlUserTable {
|
||||
id: string;
|
||||
name: string;
|
||||
cols: string[];
|
||||
rows: (number | string | null)[][];
|
||||
}
|
||||
|
||||
export interface SheetLogic {
|
||||
key: string | null;
|
||||
name: string;
|
||||
resultUnit: string;
|
||||
workbook: Workbook;
|
||||
nodes: SlNode[];
|
||||
edges: SlEdge[];
|
||||
userTables?: SlUserTable[];
|
||||
}
|
||||
|
||||
/** 알약 한쪽 끝 */
|
||||
export interface SlEnd {
|
||||
node: string;
|
||||
pill: string;
|
||||
}
|
||||
|
||||
const notReady = (): never => {
|
||||
throw new Error("준비 중");
|
||||
};
|
||||
|
||||
/** 빈 시트 로직 */
|
||||
export function newLogic(_name?: string, _resultUnit?: string): SheetLogic {
|
||||
return notReady();
|
||||
}
|
||||
|
||||
/** 상자 더하기 — 그 종류 틀(칸 A 이름 · B 값 · C 설명)로 시트를 만듦 */
|
||||
export function addNode(
|
||||
_sl: SheetLogic,
|
||||
_kind: SlKind,
|
||||
_name: string,
|
||||
): { sl: SheetLogic; node: SlNode } {
|
||||
return notReady();
|
||||
}
|
||||
|
||||
/** 상자 지우기 — 시트 · 이어진 선 · 받던 참조 수식을 함께 지움 */
|
||||
export function removeNode(_sl: SheetLogic, _node: string): SheetLogic {
|
||||
return notReady();
|
||||
}
|
||||
|
||||
/** 선 잇기 — 받는 알약 칸에 참조 수식 · 순환 · 없는 알약이면 막고 까닭(쉬운 말) */
|
||||
export function connect(
|
||||
_sl: SheetLogic,
|
||||
_from: SlEnd,
|
||||
_to: SlEnd,
|
||||
): { sl: SheetLogic; why: string | null } {
|
||||
return notReady();
|
||||
}
|
||||
|
||||
/** 선 끊기 — 그 참조를 받는 칸 수식에서 뺌 */
|
||||
export function disconnect(_sl: SheetLogic, _edge: string): SheetLogic {
|
||||
return notReady();
|
||||
}
|
||||
|
||||
/** 알약 정하기 — 같은 칸이나 같은 이름이 있으면 바꿈 */
|
||||
export function setPill(
|
||||
_sl: SheetLogic,
|
||||
_node: string,
|
||||
_cell: string,
|
||||
_dir: "in" | "out",
|
||||
_name: string,
|
||||
_extra?: Pick<SlPill, "unit" | "outside">,
|
||||
): SheetLogic {
|
||||
return notReady();
|
||||
}
|
||||
|
||||
/** 알약 빼기 — 이어진 선도 끊음 */
|
||||
export function removePill(
|
||||
_sl: SheetLogic,
|
||||
_node: string,
|
||||
_dir: "in" | "out",
|
||||
_name: string,
|
||||
): SheetLogic {
|
||||
return notReady();
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"다음": {"LB": 409, "EQ": 655, "RT": 20, "MN": 7000, "MT": 30719, "MO": 74, "MP": 364, "FX": 6, "CF": 159, "QF": 477, "GF": 331, "CC": 341, "GC": 1140, "QC": 2060, "GX": 2, "UA": 38},
|
||||
"다음": {"LB": 409, "EQ": 655, "RT": 20, "MN": 7000, "MT": 30719, "MO": 74, "MP": 364, "FX": 6, "CF": 159, "QF": 477, "GF": 331, "CC": 341, "GC": 1140, "QC": 2060, "GX": 4, "UA": 38},
|
||||
"폐기": {"MT000001": "자재품목 휘발유 — 값이 비고 글뿐 · 유가 테이블로 감", "MT000002": "자재품목 경유 — 값이 비고 글뿐 · 유가 테이블로 감", "MT000003": "자재품목 선박용경유 — 값이 비고 글뿐 · 유가 테이블로 감", "MT000004": "자재품목 중유 — 값이 비고 글뿐 · 유가 테이블로 감", "MT000005": "자재품목 등유 — 값이 비고 글뿐 · 유가 테이블로 감", "LB000399": "이름 「〃」 — 직종이 아니라 되풀이 기호 · 소요량 13-6-9 에서 윗줄 직종으로 바로잡음", "MN": "재료_나라장터자재 — old 로 옮김 · 로직은 자재품목·품셈재료로 갈아 끼움", "LB000372": "미확보 고급기능사 — 측량노임 항공사진고급기능사 옛이름으로 옮김", "LB000393": "미확보 리베팅공 — 건설노임 철골공 옛이름으로 옮김(2010 통합표 연번10)", "LB000405": "미확보 Belt Conveyor 설치공 — 품셈 13-10-1 주② 배분으로 다섯 직종에 나눔", "MT000006": "자재품목 전력 — 재료_유가전력 전력 줄로 감", "MT000007": "자재품목 전력 — 재료_유가전력 전력 줄로 감", "LB000368": "미확보 기술사 — 기술사(건설) 옛이름으로 옮김", "LB000369": "미확보 특급기술자 — 특급기술자(건설) 옛이름으로 옮김", "LB000370": "미확보 고급기술자 — 고급기술자(건설) 옛이름으로 옮김", "LB000361": "미확보 중급기술자 — 중급기술자(건설) 옛이름으로 옮김", "LB000364": "미확보 초급기술자 — 초급기술자(건설) 옛이름으로 옮김", "LB000365": "미확보 고급숙련기술자 — 고급숙련기술자(건설) 옛이름으로 옮김", "LB000366": "미확보 중급숙련기술자 — 중급숙련기술자(건설) 옛이름으로 옮김", "LB000367": "미확보 초급숙련기술자 — 초급숙련기술자(건설) 옛이름으로 옮김", "LB000389": "미확보 기계기사 — 초급기술자(기계·설비) 옛이름으로 옮김", "LB000388": "미확보 기계산업기사 — 초급숙련기술자(기계·설비) 옛이름으로 옮김", "MO000055": {"원문번호": "주택용저압:기본_200이하", "파일": "재료_유가전력.json"}, "MO000056": {"원문번호": "주택용저압:기본_201~400", "파일": "재료_유가전력.json"}, "MO000057": {"원문번호": "주택용저압:기본_400초과", "파일": "재료_유가전력.json"}, "MO000059": {"원문번호": "주택용저압:전력량_다음200", "파일": "재료_유가전력.json"}, "MO000060": {"원문번호": "주택용저압:전력량_400초과", "파일": "재료_유가전력.json"}, "MO000061": {"원문번호": "주택용저압:월간최저요금", "파일": "재료_유가전력.json"}, "MO000062": {"원문번호": "일반용갑I저압:기본", "파일": "재료_유가전력.json"}, "MO000063": {"원문번호": "일반용갑I저압:전력량_여름철", "파일": "재료_유가전력.json"}, "MO000064": {"원문번호": "일반용갑I저압:전력량_봄가을철", "파일": "재료_유가전력.json"}, "MO000065": {"원문번호": "일반용갑I저압:전력량_겨울철", "파일": "재료_유가전력.json"}, "MO000066": {"원문번호": "산업용갑I저압:기본", "파일": "재료_유가전력.json"}, "MO000067": {"원문번호": "산업용갑I저압:전력량_여름철", "파일": "재료_유가전력.json"}, "MO000068": {"원문번호": "산업용갑I저압:전력량_봄가을철", "파일": "재료_유가전력.json"}, "MO000069": {"원문번호": "산업용갑I저압:전력량_겨울철", "파일": "재료_유가전력.json"}, "MO000070": {"원문번호": "임시전력갑:기본요금적용", "파일": "재료_유가전력.json"}, "MO000071": {"원문번호": "임시전력갑:전력량요금적용", "파일": "재료_유가전력.json"}, "MO000072": {"원문번호": "임시전력갑:월간최저요금", "파일": "재료_유가전력.json"}},
|
||||
"키": {
|
||||
"CC000001": {"원문번호": "공통 1-3-1 콘크리트 및 포장용 재료", "파일": "계수_건설품셈_01장_적용기준.json"},
|
||||
@@ -2629,6 +2629,8 @@
|
||||
"GF000329": {"원문번호": "13-11-2 타원형 돌망태", "파일": "로직_산림품셈_13장_구조물.json"},
|
||||
"GF000330": {"원문번호": "13-15-1 목재 껍질벗기기", "파일": "로직_산림품셈_13장_구조물.json"},
|
||||
"GX000001": {"원문번호": "13-4-1 돌쌓기 메쌓기(인력)", "파일": "로직_자체.json"},
|
||||
"GX000002": {"원문번호": "12-34-4 암거이음받침 채움재(T=20㎜)", "파일": "로직_자체.json"},
|
||||
"GX000003": {"원문번호": "13-4-1 돌쌓기 메쌓기(인력) (2)", "파일": "로직_자체.json"},
|
||||
"LB000001": {"원문번호": "1001", "파일": "인력.json"},
|
||||
"LB000002": {"원문번호": "1002", "파일": "인력.json"},
|
||||
"LB000003": {"원문번호": "1003", "파일": "인력.json"},
|
||||
|
||||
@@ -28,6 +28,48 @@
|
||||
"덧줄": [],
|
||||
"끝수": null,
|
||||
"시험입력": { "높이": 4.0, "돌": "깬잡석" }
|
||||
},
|
||||
{
|
||||
"키": "GX000002",
|
||||
"원문번호": "12-34-4",
|
||||
"구분": "자체",
|
||||
"상세구분": "12장 철근콘크리트",
|
||||
"이름": "암거이음받침 채움재(T=20㎜)",
|
||||
"결과단위": "원/㎡",
|
||||
"출처": "산림품셈 12-34-4",
|
||||
"소유": "현장",
|
||||
"비고": "해석: 원문 재료비 「JOINT FILLER」 뿐 — ㎡당 1㎡ · 설치 품 원문 없음 · GF000208 를 본뜸",
|
||||
"입력": [],
|
||||
"중간": [],
|
||||
"호표": [{ "종류": "재료", "요소": { "구분": "도료·방수·접착", "상세구분": "방수·실링", "검색어": "JOINT FILLER" }, "이름": "JOINT FILLER(T=20㎜)", "단위": "㎡", "수량": "1", "비목": "재료비" }],
|
||||
"덧줄": [],
|
||||
"끝수": null
|
||||
},
|
||||
{
|
||||
"키": "GX000003",
|
||||
"원문번호": "13-4-1",
|
||||
"구분": "자체",
|
||||
"상세구분": "13장 구조물",
|
||||
"이름": "돌쌓기 메쌓기(인력)",
|
||||
"결과단위": "원/㎡",
|
||||
"출처": "산림품셈 13-4-1",
|
||||
"소유": "현장",
|
||||
"비고": "고르기 첫 값 = 원문에 있는 조합(뒷길이 25 · 깬잡석 · 골쌓기) · 「원문에 없는 조합: 뒷길이=25 · 돌=견치돌 · 쌓기=골쌓기 / 뒷길이=25 · 돌=견치돌 · 쌓기=켜쌓기 / 뒷길이=25 · 돌=깬돌 · 쌓기=골쌓기 / 뒷길이=25 · 돌=깬돌 · 쌓기=켜쌓기 / 뒷길이=30 · 돌=견치돌 · 쌓기=골쌓기 외 5」 · GF000219 를 본뜸",
|
||||
"입력": [
|
||||
{ "이름": "뒷길이", "설명": "쌓을 돌의 뒤쪽 길이", "단위": "㎝", "고르기": [25, 30, 35, 45, 55, 60, 75] },
|
||||
{ "이름": "돌", "설명": "쌓을 돌 종류", "고르기": ["깬잡석", "견치돌", "깬돌", "호박돌 및 야면석"] },
|
||||
{ "이름": "쌓기", "설명": "돌을 어긋나게 쌓는지 줄 맞춰 쌓는지", "고르기": ["골쌓기", "켜쌓기"] },
|
||||
{ "이름": "높이", "설명": "쌓는 벽 높이", "단위": "m" },
|
||||
{ "이름": "초과증가율", "설명": "기준 높이를 넘어 더 드는 품 비율", "단위": "%", "범위": [80, 100] }
|
||||
],
|
||||
"중간": [{ "이름": "증가율", "식": "만약(높이 <= 3, 0, 만약(높이 <= 7.5, 찾기(QF000422, 높이=높이).증가율, 초과증가율))", "출처": "산림품셈 13-4-1 주③" }],
|
||||
"호표": [
|
||||
{ "종류": "인력", "요소": "LB000033", "이름": "석공", "단위": "인", "수량": "찾기(QF000421, 뒷길이=뒷길이, 돌=돌, 쌓기=쌓기).석공 * (1 + 증가율 / 100)", "비목": "노무비" },
|
||||
{ "종류": "인력", "요소": "LB000002", "이름": "보통인부", "단위": "인", "수량": "찾기(QF000421, 뒷길이=뒷길이, 돌=돌, 쌓기=쌓기).보통인부 * (1 + 증가율 / 100)", "비목": "노무비" }
|
||||
],
|
||||
"덧줄": [],
|
||||
"끝수": null,
|
||||
"시험입력": { "높이": 4.0, "돌": "깬잡석" }
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user