Merge remote-tracking branch 'origin/sub_laptop_1' into main_laptop_1
# Conflicts: # B09_Estimation/B09_Estimation_UI_Tabs_Bill.ts
This commit is contained in:
@@ -56,7 +56,7 @@ PARTS = ("labor", "material", "expense")
|
||||
COST_PART = {"노무비": "labor", "재료비": "material", "경비": "expense"}
|
||||
DEPTH = 4 # 하위 산근 깊이 상한
|
||||
_Q = re.compile(r"Q\d*") # 작업량 중간값 이름(산림품셈 09장 토공 · 07장 집재 …)
|
||||
NO_SOURCE = "조합 밖 토공 · 운반 · 사토 산근 · 준비공 = 원천 없음(연결 없음 · 만들지 않음)"
|
||||
NO_SOURCE = "조합 밖 토공 · 운반 · 사토 · 준비공은 산근 없음"
|
||||
EMPTY = "연결된 구조물 조합 사본에 단가산출 줄 없음 — 연결 없음"
|
||||
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ import {
|
||||
} from "./B09_Estimation_UI_Tabs_Summary";
|
||||
import { buildCost, buildTotal } from "./B09_Estimation_UI_Tabs_Total";
|
||||
import { buildSg, buildSgList } from "./B09_Estimation_UI_Tabs_Sangeun";
|
||||
import { isGroupTab, renderGroupPanel } from "./B09_Estimation_UI_Tabs_Groups";
|
||||
import { isGroupTab, lineHint, renderGroupPanel } from "./B09_Estimation_UI_Tabs_Groups";
|
||||
|
||||
function L(key: keyof typeof ui_locales): string {
|
||||
return ui_locales[key][currentLanguageIndex];
|
||||
@@ -244,7 +244,7 @@ export function renderB09Estimation(root: HTMLElement): void {
|
||||
);
|
||||
return made;
|
||||
};
|
||||
const hint = spec.hint ? note(spec.hint) : null;
|
||||
const hint = spec.hint ? lineHint(note(spec.hint)) : null; // 236-1 안내 글 = 한 줄
|
||||
// 171-3 묶음 탭(일위대가표 · 중기사용료 · 단가산출근거) = 묶음 카드 기본 · 머리 단추로 표
|
||||
if (isGroupTab(tab)) {
|
||||
const redraw = (): void => show(tab);
|
||||
|
||||
@@ -52,14 +52,14 @@ export const buildLabor: TabBuild = ({ sheets, payload }) =>
|
||||
priceList(
|
||||
sheets.labor || [],
|
||||
"단가(원/인)",
|
||||
`노임 = 굳힌 단가(${madeText(payload)}) · M01 인력 · 바꾸려면 [업데이트]`,
|
||||
`굳힌 단가(${madeText(payload)}) 기준 · 바꾸려면 [업데이트]`,
|
||||
);
|
||||
|
||||
export const buildExpense: TabBuild = ({ sheets, payload }) =>
|
||||
priceList(
|
||||
sheets.expense || [],
|
||||
"기준가(천원)",
|
||||
`기계 손료 기준가 = 굳힌 단가(${madeText(payload)}) · M01 기계 가격 · 바꾸려면 [업데이트]`,
|
||||
`굳힌 단가(${madeText(payload)}) 기준 · 바꾸려면 [업데이트]`,
|
||||
);
|
||||
|
||||
function madeText(payload: Row): string {
|
||||
@@ -104,7 +104,7 @@ export const buildBasis: TabBuild = ({ sheets }): TabTable => {
|
||||
rows,
|
||||
frozen: 2,
|
||||
mergeSame: ["part"],
|
||||
hint: "운전사 시간 노임 = ROUNDDOWN(일당 × 1/8 × 16/12 × 25/20, 0)(M01 CC000336 · 건협기술-2230) · 환율 = M01 한국은행 · 인건비 줄 누름 = 노무비목록표",
|
||||
hint: "인건비 줄을 누르면 노무비목록표로 이동",
|
||||
link: (i) => {
|
||||
const row = rows[i];
|
||||
return row?.labor_key ? { tab: "labor", key: String(row.labor_key) } : null;
|
||||
@@ -196,7 +196,7 @@ export const buildCompare: TabBuild = ({ sheets, user, setUser }): TabTable => {
|
||||
],
|
||||
rows: out,
|
||||
frozen: 2,
|
||||
hint: "적용 단가 = 출처 중 최저(0 · 빈칸 뺌 · 견적 포함) 자동 · 「적용 단가」 칸 누름 = 고르기(값 있는 출처 · 견적 · 최저(자동) · 견적이 높아도 고름) · 고른 출처 단가 칸 강조 · 견적 단가 = 수기 입력(출처 없는 B08 줄은 견적으로 단가) · 「관급 · 별도」 칸 누름 = 없음 → 관급 → 별도 · 「견적서」 칸(견적 단가를 넣은 줄만) 누름 = 파일 올리기 · 보기 · 출처 단가 칸에 마우스 = 출처 뜻(책 · 호 · 쪽 · 기준일)",
|
||||
hint: "「적용 단가」 칸을 누르면 출처 고르기 · 「관급 · 별도」 칸을 누르면 구분 바꿈 · 견적 단가는 수기 입력",
|
||||
tip: (i, key) =>
|
||||
key.startsWith("p:") && rows[i]
|
||||
? sourceInfo(
|
||||
@@ -297,7 +297,7 @@ export const buildMaterial: TabBuild = ({ sheets }): TabTable => {
|
||||
? { name: "계", amount: rows.reduce((sum, r) => sum + (Number(r.amount) || 0), 0) }
|
||||
: null,
|
||||
frozen: 2,
|
||||
hint: `줄 = 연결된 일위대가 · 산근 · 중기가 쓰는 자재 + B08 총괄 줄 · 관급 · 별도 줄 · 수량 = 설계내역서 × 호표 역전개 총수량(재료비수량금액집계표와 같음 · B08 할증 값과 다를 수 있음) · 단가 = 자재단가대비표 적용 단가 · 총액 = ROUND(수량 × 단가, 0) · 계 = 빈칸 뺀 합 · 비고 = 쓰는 곳 · ${LINK_HINT}`,
|
||||
hint: LINK_HINT,
|
||||
link: (i) => (rows[i] ? { tab: "compare", key: String(rows[i].key) } : null),
|
||||
};
|
||||
};
|
||||
@@ -317,7 +317,7 @@ export const buildMachine: TabBuild = ({ sheets }): TabTable => {
|
||||
],
|
||||
rows,
|
||||
frozen: 2,
|
||||
hint: `시간당 = 중기사용료 블록 합계 · ${LINK_HINT}`,
|
||||
hint: LINK_HINT,
|
||||
link: (i) => (rows[i] ? { tab: "machine_blocks", key: String(rows[i].key) } : null),
|
||||
};
|
||||
};
|
||||
@@ -388,7 +388,7 @@ export const buildMachineBlocks: TabBuild = ({ sheets }): TabTable => {
|
||||
],
|
||||
rows,
|
||||
frozen: 1,
|
||||
hint: "손료 = 기준가(천원) × 손료계수 ÷ 10,000 · 운전사 = 인 × 시간 노임 · 연료 = ℓ/hr × 적용 단가 · 잡품 = 연료 금액 × % · 줄 ROUNDDOWN 1 · 비목 합 ROUNDDOWN 0 · 줄 누름 = 단가를 낸 탭",
|
||||
hint: LINK_HINT,
|
||||
link: (i) => links[i] ?? null,
|
||||
level: blockLevel("name", (i) => !String(rows[i]?.key).includes("|")),
|
||||
};
|
||||
|
||||
@@ -64,11 +64,10 @@ export const buildBill: TabBuild = (ctx): BillTable => {
|
||||
total: { name: "순공사비 계(관급 제외)", ...direct },
|
||||
frozen: 1,
|
||||
hint:
|
||||
"기본 로직이 짠 내역 = 초기값 · 모든 줄 고침 · 더함 · 지움 · 옮김 자유(우클릭 · 고친 칸 = 색 칸 · 풍선 = 자동 값) · " +
|
||||
"칸 누름 = 줄 고름 · 입력 = 더블클릭 · Enter · F2 · 폴더 줄 = 이름만(금액 = 아래 합) · 파일 줄 = 값 입력 · 연결 · " +
|
||||
"금액 = ROUNDDOWN(단가 × 수량, 0) 비목마다 · 묶음 금액 = 아래 항목 합 · 4 자재대 = 대비표 「별도」 · 관급자재대 = 「관급」 표시 자재(관급자재대 밖으로 못 옮김) · " +
|
||||
"조달수수료 율(%)은 수량 칸 · 「연결 ▾」 = 일위대가 · 단가산출 연결(새 산근 단가 = [저장] 뒤) · 처음으로 = 왼쪽 [내역 초기화] · " +
|
||||
`빈 줄 ${direct.blank ?? 0} — 계는 아는 금액만 · 원가계산서는 빈 줄이 없을 때만 받음`,
|
||||
"줄을 우클릭하면 추가 · 지움 · 옮김 · 「연결 ▾」로 일위대가 · 단가산출 연결" +
|
||||
(direct.blank
|
||||
? ` · 빈 줄 ${direct.blank} — 계는 아는 금액만 · 원가계산서는 빈 줄이 없을 때만 받음`
|
||||
: ""),
|
||||
editOnDouble: true,
|
||||
editable: (i, key) => {
|
||||
const r = rows[i];
|
||||
|
||||
@@ -133,7 +133,7 @@ export function levelBar(
|
||||
return button;
|
||||
});
|
||||
const guide = document.createElement("p");
|
||||
guide.className = "ui-general-block__empty";
|
||||
guide.className = "ui-general-block__empty b09-estimation__line-hint";
|
||||
guide.textContent = GUIDE;
|
||||
attachHoverInfo(guide, GUIDE_MORE);
|
||||
const sync = (): void => {
|
||||
|
||||
@@ -178,8 +178,8 @@ function numberFormat(spec: TabTable, key: string): (v: number | null | undefine
|
||||
/* ── 그리기 ───────────────────────────────────────────────────────────── */
|
||||
|
||||
/** 안내 글 = 한 줄(줄임표) · 잘렸을 때만 마우스 올리면 전문(공용 호버 185-3) */
|
||||
function lineHint(hint: HTMLElement | null): HTMLElement | null {
|
||||
if (!hint) return null;
|
||||
export function lineHint(hint: HTMLElement | null): HTMLElement | null {
|
||||
if (!hint || hint.classList.contains("b09-estimation__line-hint")) return hint;
|
||||
hint.classList.add("b09-estimation__line-hint");
|
||||
attachHoverInfo(hint, (el) => (el.scrollWidth > el.clientWidth ? el.textContent : null));
|
||||
return hint;
|
||||
|
||||
@@ -27,8 +27,7 @@ const EMPTY =
|
||||
"연결 없음 — 연결된 구조물 조합 사본(일위대가)이 없음 · B05 · B06 에서 조합을 고르고 [저장]";
|
||||
/** 하위 줄 앞 — 들여쓰기 + 「ㄴ」(공용 표가 앞 빈칸을 접지 않음) */
|
||||
const CHILD = "ㄴ "; // 들여쓰기 = 공용 표 level(201-1)
|
||||
const ROUNDS = "줄 금액 ROUNDDOWN(단가 × 수량, 1) · % 줄 = 밑수 × % / 100 · 합계 ROUNDDOWN 0";
|
||||
const BLANK = "빈 줄 n = 금액 모르는 줄 · 합계 = 아는 줄 합 · 내역 단가엔 안 넘김";
|
||||
const BLANK = "빈 줄은 금액을 모르는 줄(합계는 아는 줄만)";
|
||||
/** 「빈 줄 n」 작은 글 · 풍선 = 빈 줄 이름 */
|
||||
const blankNote = (b: Row): string => (b.blank ? `빈 줄 ${b.blank}` : "");
|
||||
const blankTip = (b: Row | undefined): string | null =>
|
||||
@@ -65,7 +64,7 @@ export const buildDaegaList: TabBuild = ({ sheets }): TabTable | string => {
|
||||
],
|
||||
rows,
|
||||
frozen: 3,
|
||||
hint: `호표 = 일위대가표 블록 합계 · ${BLANK} · 줄을 누르면 그 블록으로`,
|
||||
hint: `줄을 누르면 그 블록으로 이동 · ${BLANK}`,
|
||||
link: (i: number): Link | null => (rows[i] ? { tab: "dg", key: String(rows[i].key) } : null),
|
||||
tip: (i, key) =>
|
||||
key === "spec"
|
||||
@@ -152,7 +151,7 @@ export const buildDaegaBlocks: TabBuild = ({ sheets }): TabTable | string => {
|
||||
],
|
||||
rows,
|
||||
frozen: 1,
|
||||
hint: `단가 = B09 프로젝트 한 벌 굳힌 단가 · ${ROUNDS} · ${BLANK} · 줄 누름 = 단가를 낸 탭(대가 줄 = 그 블록)`,
|
||||
hint: `줄을 누르면 단가를 낸 탭으로 이동 · ${BLANK}`,
|
||||
link: (i: number) => links[i] ?? null,
|
||||
rowClass: (i: number) => (titles.has(i) ? "is-title" : null),
|
||||
level: blockLevel("name", (i) => titles.has(i)),
|
||||
|
||||
@@ -56,9 +56,7 @@ export const buildSgList: TabBuild = ({ sheets }): TabTable => {
|
||||
],
|
||||
rows,
|
||||
frozen: 2,
|
||||
hint:
|
||||
"산근 = 연결된 구조물 조합 사본의 단가산출 로직 줄 · 사전조합 안 줄 · 일위대가화 줄의 하위 로직(노무 · 자재 · 중기 줄은 각 목록표) · 같은 로직 + 같은 입력값 = 한 호표 · 합계 = 블록 총계 · 줄 누름 = 그 블록" +
|
||||
notes(sheets),
|
||||
hint: "줄을 누르면 그 블록으로 이동" + notes(sheets),
|
||||
link: (i) => (rows[i] ? { tab: "sg", key: String(rows[i].key) } : null),
|
||||
tip: (i, key) => (key === "spec" ? raw(rows[i]?.spec, rows[i]?.spec_raw) : null),
|
||||
};
|
||||
@@ -159,8 +157,7 @@ export const buildSg: TabBuild = ({ sheets }): TabTable | string => {
|
||||
rows,
|
||||
frozen: 1,
|
||||
hint:
|
||||
"산출내역 = 값이 든 식(B09 굳힌 단가 * 수량 = 금액 · 작업량 Q = ROUND 2) · 줄 ROUNDDOWN 1 · 총계 비목마다 ROUNDDOWN 0 · 자재 적용 단가를 고치면 [저장] 뒤 반영 · 줄 누름 = 단가를 낸 탭" +
|
||||
notes(sheets),
|
||||
"줄을 누르면 단가를 낸 탭으로 이동 · 자재 적용 단가를 고치면 [저장] 뒤 반영" + notes(sheets),
|
||||
link: (i: number) => links[i] ?? null,
|
||||
rowClass: (i: number) => (titles.has(i) ? "is-title" : null),
|
||||
level: blockLevel("text", (i) => titles.has(i)),
|
||||
|
||||
@@ -18,8 +18,7 @@ import {
|
||||
type TabTable,
|
||||
} from "./B09_Estimation_UI_Tabs";
|
||||
|
||||
const HINT =
|
||||
"총수량 = 설계내역서 수량 × 호표(산근 · 대가) 구성 역전개(서버 · [저장] 뒤 다시 셈) · ROUND 2 · 금액 = ROUND(수량 × 단가, 0) · 줄 누름 = 목록표";
|
||||
const HINT = "줄을 누르면 목록표로 이동";
|
||||
|
||||
/** 안내 + 「연결 없음 n」(전개 안 한 내역 항목 — 조합 밖 토공 · 운반 산근 등) */
|
||||
const hint = (payload: Row, extra = ""): string => {
|
||||
@@ -28,7 +27,7 @@ const hint = (payload: Row, extra = ""): string => {
|
||||
};
|
||||
|
||||
/** 줄이 없을 때 표 위 맨 앞 안내 */
|
||||
const EXPENSE_NONE = "경비 갈래 자원 없음 — 중기 · 자재로 셈 · 경비 로직이 들어오면 채워짐";
|
||||
const EXPENSE_NONE = "경비 자원 없음";
|
||||
|
||||
function resourceTab(id: string, list: TabId, unitPrice: string, none = ""): TabBuild {
|
||||
return ({ payload }): TabTable => {
|
||||
@@ -86,7 +85,7 @@ export const buildSumMachine: TabBuild = ({ payload }): TabTable => {
|
||||
}
|
||||
: null,
|
||||
frozen: 2,
|
||||
hint: hint(payload, " · 비목마다 ROUND(시간 × 시간당, 0)"),
|
||||
hint: hint(payload),
|
||||
link: (i) => (rows[i] ? { tab: "machine", key: String(rows[i].key) } : null),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -211,11 +211,7 @@ export const buildTotal: TabBuild = (ctx): TabTable => {
|
||||
rowClass: (i) => levelClass(rows[i]),
|
||||
level: nameLevel(rows),
|
||||
mergeSame: ["part"],
|
||||
hint:
|
||||
"요율 = M01 조달청 제비율에서 자동(맨 위 고르는 값 · 공종 토목) — 칸에 적으면 사용자 값이 앞섬 · 지우거나 출처 칸 누르면 자동 · " +
|
||||
"2024 엑셀 요율과 연도 차로 다를 수 있음 · 자동도 없으면 그 줄 · 그 줄을 쓰는 소계 빈칸 · 끝수 = 엑셀 그대로(줄마다 원 버림 · 관급 천원 올림) · " +
|
||||
"수기 입력 = 안전관리비 기초액(빈칸 = 자동 구간 기초액) · 이윤 보정 · 부가세 조정 · 조달수수료율(빈칸 = 0) · " +
|
||||
"공종 제목 줄은 설계내역서(145-3)가 들어오면 붙음",
|
||||
hint: "요율 칸에 적으면 사용자 값 · 지우거나 출처 칸을 누르면 자동 값",
|
||||
editable: (i, key) =>
|
||||
(key === "rate" && RATE_KEYS.has(String(rows[i]?.key))) ||
|
||||
(key === "hand" && String(rows[i]?.key) in HAND),
|
||||
@@ -292,7 +288,7 @@ export const buildCost: TabBuild = (ctx): TabTable => {
|
||||
rowClass: (i) => levelClass(rows[i]),
|
||||
level: nameLevel(rows),
|
||||
mergeSame: ["group", "part"],
|
||||
hint: "총괄설계내역서 값 거울 · 구성비 = 총공사비 대비 · 고칠 칸 = 간접재료비 · 작업설(직접재료비가 그만큼 바뀌고 재료비 소계는 그대로 — 엑셀 꼴) · 줄 누름 = 총괄 그 줄",
|
||||
hint: "고칠 칸은 간접재료비 · 줄을 누르면 총괄 그 줄로 이동",
|
||||
editable: (i, key) => key === "amount" && String(rows[i]?.key) in HAND,
|
||||
onEdit: (i, key, value) => editEstimate(ctx, String(rows[i]?.key), key, value),
|
||||
link: (i) => {
|
||||
|
||||
Reference in New Issue
Block a user