feat(z01): 좌측을 둘로 가름 — ①기초단가 다섯(얼마인가 · 시장이 정함) ②품셈 기준 아홉(얼마나 드나 · 품셈이 해마다 한 번 · 토량환산·자재할증·거푸집·철근·목구조·돌쌓기 경사·뒷길이·돌종류·갈래) · 축 칸 잠금·구간 이름은 서버가 준 대로 그대로(사용자 ①② 지시)
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016VBGFXB9AbJBwXP19z75Qq
This commit is contained in:
@@ -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<T>(path: string, init: RequestInit = {}): Promise<T> {
|
||||
const response = await fetch(`${API_BASE_URL}${path}`, {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 취소)",
|
||||
|
||||
Reference in New Issue
Block a user