diff --git a/Z01_MasterData/Z01_MasterData_Api_Fetch.ts b/Z01_MasterData/Z01_MasterData_Api_Fetch.ts index 7d881ee6..7a76b9e7 100644 --- a/Z01_MasterData/Z01_MasterData_Api_Fetch.ts +++ b/Z01_MasterData/Z01_MasterData_Api_Fetch.ts @@ -47,9 +47,26 @@ export interface RowsQuery { sort?: SortOrder | null; } -/** 기초단가 다섯 — 고친 값은 원본이 아니라 덮개 파일에 쌓임(품셈이 갱신돼도 안 날아감). */ +/** + * ① 기초단가 다섯 — 얼마인가. 시장이 정하고 주간~반기로 바뀜. + * 고친 값은 원본이 아니라 덮개 파일에 쌓임(품셈이 갱신돼도 안 날아감). + */ export const BASE_PRICE_KINDS = ["labor", "machine", "material", "oil", "rate"] as const; -export type BasePriceKind = (typeof BASE_PRICE_KINDS)[number]; + +/** ② 품셈 기준 아홉 — 얼마나 드나. 품셈이 정하고 해마다 한 번 개정(2026-09-16 사용자 ①②). */ +export const SPEC_KINDS = [ + "coef", + "material_surcharge", + "formwork_reuse", + "rebar_complexity", + "timber_structure_class", + "masonry_slope", + "masonry_back_length", + "stone_kind", + "masonry_class", +] as const; + +export type BasePriceKind = (typeof BASE_PRICE_KINDS)[number] | (typeof SPEC_KINDS)[number]; async function request(path: string, init: RequestInit = {}): Promise { const response = await fetch(`${API_BASE_URL}${path}`, { diff --git a/Z01_MasterData/Z01_MasterData_UI_Side.ts b/Z01_MasterData/Z01_MasterData_UI_Side.ts index c50d6fed..a0fb7fee 100644 --- a/Z01_MasterData/Z01_MasterData_UI_Side.ts +++ b/Z01_MasterData/Z01_MasterData_UI_Side.ts @@ -15,9 +15,11 @@ import { fetchMasterRows, fetchOverrides, type MasterGroup, + type BasePriceKind, type MasterRows, type RowsQuery, saveBasePrice, + SPEC_KINDS, VALUES_TABLE_ID, } from "./Z01_MasterData_Api_Fetch"; import { valueWithUnit, type OverrideState } from "./Z01_MasterData_UI_Cells"; @@ -31,25 +33,32 @@ export function buildSidePanel(groups: MasterGroup[], view: RowsView): HTMLEleme }; const baseTitle = L("Z01_MasterData_BasePrices"); - const baseGrid = el("div", { className: "z01-master__base-grid" }); - for (const kind of BASE_PRICE_KINDS) { - const label = L(`Z01_MasterData_Base_${kind}` as const); - const button = el("button", { - className: "z01-master__base", - attrs: { type: "button" }, - text: label, - }); - button.addEventListener("click", () => { - activate(button); - view.show({ - title: `${baseTitle} › ${label}`, - key: `base-prices/${kind}`, - load: (query) => fetchBasePrices(kind, query), - save: (rowId, values) => saveBasePrice(kind, rowId, values), + const specTitle = L("Z01_MasterData_SpecValues"); + /** 한 상자 몫 단추들 — ①얼마인가 ②얼마나 드나 로 갈라 세움(성격도 갱신 주기도 다름). */ + const kindGrid = (boxTitle: string, kinds: readonly BasePriceKind[]): HTMLElement => { + const grid = el("div", { className: "z01-master__base-grid" }); + for (const kind of kinds) { + const label = L(`Z01_MasterData_Base_${kind}` as const); + const button = el("button", { + className: "z01-master__base", + attrs: { type: "button" }, + text: label, }); - }); - baseGrid.append(button); - } + button.addEventListener("click", () => { + activate(button); + view.show({ + title: `${boxTitle} › ${label}`, + key: `base-prices/${kind}`, + load: (query) => fetchBasePrices(kind, query), + save: (rowId, values) => saveBasePrice(kind, rowId, values), + }); + }); + grid.append(button); + } + return grid; + }; + const baseGrid = kindGrid(baseTitle, BASE_PRICE_KINDS); + const specGrid = kindGrid(specTitle, SPEC_KINDS); const overridesButton = el("button", { className: "z01-master__base z01-master__base--wide", attrs: { type: "button" }, @@ -113,7 +122,11 @@ export function buildSidePanel(groups: MasterGroup[], view: RowsView): HTMLEleme tree.append(groupBox); } - panel.append(section(baseTitle, baseGrid), section(L("Z01_MasterData_Tree"), tree)); + panel.append( + section(baseTitle, baseGrid), + section(specTitle, specGrid), + section(L("Z01_MasterData_Tree"), tree), + ); attachCollapsible(panel); return panel; } diff --git a/ui_template/ui_template_locale_b3.ts b/ui_template/ui_template_locale_b3.ts index 662fc14c..866bf245 100644 --- a/ui_template/ui_template_locale_b3.ts +++ b/ui_template/ui_template_locale_b3.ts @@ -147,6 +147,17 @@ export const ui_locales_b3 = { Z01_MasterData_Base_material: ["자재단가", "Material"], Z01_MasterData_Base_oil: ["유가", "Fuel"], Z01_MasterData_Base_rate: ["요율", "Rates"], + /* ② 품셈 기준 아홉 — 얼마나 드나(품셈이 정하고 해마다 한 번 개정) */ + Z01_MasterData_SpecValues: ["품셈 기준", "Standard rates"], + Z01_MasterData_Base_coef: ["토량환산", "Soil conversion"], + Z01_MasterData_Base_material_surcharge: ["자재할증", "Material surcharge"], + Z01_MasterData_Base_formwork_reuse: ["거푸집", "Formwork reuse"], + Z01_MasterData_Base_rebar_complexity: ["철근", "Rebar"], + Z01_MasterData_Base_timber_structure_class: ["목구조", "Timber structure"], + Z01_MasterData_Base_masonry_slope: ["돌쌓기 경사", "Masonry slope"], + Z01_MasterData_Base_masonry_back_length: ["뒷길이", "Back length"], + Z01_MasterData_Base_stone_kind: ["돌종류", "Stone kind"], + Z01_MasterData_Base_masonry_class: ["갈래", "Masonry class"], Z01_MasterData_Overrides: ["고친 것 모아 보기", "Edited values"], Z01_MasterData_Edit_Can: [ "고칠 수 있는 칸 — 눌러 고치고 Enter 로 저장 (Esc 취소)",