diff --git a/M02_MasterTemplete/M02_MasterTemplete_Api_Fetch.ts b/M02_MasterTemplete/M02_MasterTemplete_Api_Fetch.ts index e5361102..8ae41196 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Api_Fetch.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_Api_Fetch.ts @@ -118,6 +118,9 @@ export const createStructure = (column: string): Promise => export const fetchStructureNumbers = (): Promise> => call("/structures/numbers"); +/** `{열 id: 표번}` — 좌측 산출근거 줄(도번과 같은 규칙 · 「표-01」 꼴) */ +export const fetchBasisNumbers = (): Promise> => call("/basis/numbers"); + /* --- 프로젝트 층 단추 다섯 --- */ const project = (id: string, tail: string): string => `/projects/${enc(id)}/templates/${tail}`; const post = (path: string, body: object = {}): Promise => diff --git a/M02_MasterTemplete/M02_MasterTemplete_Router.py b/M02_MasterTemplete/M02_MasterTemplete_Router.py index 54a4c74f..ddb1b27d 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Router.py +++ b/M02_MasterTemplete/M02_MasterTemplete_Router.py @@ -43,6 +43,11 @@ def post_structure(column: str) -> dict: return _call(store.create_structure, column) +@router.get("/basis/numbers") +def get_basis_numbers() -> dict: + return _call(store.basis_numbers) + + @router.get("/templates/{kind}/{name}") def get_template(kind: str, name: str) -> dict: return _call(store.read, kind, name) diff --git a/M02_MasterTemplete/M02_MasterTemplete_Store.py b/M02_MasterTemplete/M02_MasterTemplete_Store.py index 670d664a..61f54cda 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_Store.py +++ b/M02_MasterTemplete/M02_MasterTemplete_Store.py @@ -31,6 +31,7 @@ _BASIS_HEAD_STYLE = { "테두리": {side: {"선": "thin"} for side in ("위", "아래", "왼", "오른")}, } _NUMBER = re.compile(r"^구-(\d+)$") +_TABLE_NUMBER = re.compile(r"^표-(\d+)$") _BAD_NAME = re.compile(r'[\\/:*?"<>|\x00-\x1f]|\.\.') # 도각 없는 빈 CAD 문서의 기본 도면층 — 없으면 B07 CAD 가 못 엶("Cannot read properties # of undefined (reading 'length')") · CAD 쪽도 없으면 새로 채우지만(2026-09-27 sub1 고침) @@ -221,16 +222,47 @@ def basis_doc(column: str, old: Any = None) -> dict[str, Any]: } +def _basis_docs() -> list[tuple[str, Any]]: + folder = FOLDER / "basis" + return [(p.stem, json.loads(p.read_bytes())) for p in sorted(folder.glob("[!.]*.json"))] + + +def _table_number(doc: Any) -> int: + found = _TABLE_NUMBER.match(str(doc.get("표번") or "")) if isinstance(doc, dict) else None + return int(found.group(1)) if found else 0 + + def ensure_basis(column: str, old: Any = None) -> bool: - """산출근거 파일이 없으면 만듦(식 없는 새 문서라 `계산값` 없음 · 첫 [저장] 때 서버가 적음).""" + """산출근거 파일이 없으면 만듦(식 없는 새 문서라 `계산값` 없음 · 첫 [저장] 때 서버가 적음). + 표번 = 도번과 같은 규칙(있는 것 중 가장 큰 번호 + 1) · 만든 뒤로는 안 바뀜.""" path = _path("basis", column) with _LOCK: if path.is_file(): return False - atomic_write_json(path, basis_doc(column, old)) + number = max((_table_number(doc) for _name, doc in _basis_docs()), default=0) + 1 + doc = {**basis_doc(column, old), "표번": f"표-{number:02d}"} + atomic_write_json(path, doc) return True +def basis_numbers() -> dict[str, str | None]: + """`{열 id: 표번}` — 좌측 산출근거 줄이 한 번에 받음. + 표번이 없는 옛 파일은 여기서 만나는 순서로 채움(도번 규칙과 같음).""" + docs = _basis_docs() + missing = [name for name, doc in docs if not (isinstance(doc, dict) and doc.get("표번"))] + if missing: + with _LOCK: + docs = _basis_docs() # 잠금 안에서 다시 읽음 — 그 사이 누가 채웠을 수 있음 + number = max((_table_number(doc) for _name, doc in docs), default=0) + for name, doc in docs: + if isinstance(doc, dict) and not doc.get("표번"): + number += 1 + doc["표번"] = f"표-{number:02d}" + atomic_write_json(_path("basis", name), doc) + docs = _basis_docs() + return {name: (doc.get("표번") if isinstance(doc, dict) else None) for name, doc in docs} + + def _server_values(doc: Any) -> dict[str, Any]: try: return spreadsheet.with_server_values(doc) diff --git a/M02_MasterTemplete/M02_MasterTemplete_UI_Side.ts b/M02_MasterTemplete/M02_MasterTemplete_UI_Side.ts index 97e462cc..b21dceac 100644 --- a/M02_MasterTemplete/M02_MasterTemplete_UI_Side.ts +++ b/M02_MasterTemplete/M02_MasterTemplete_UI_Side.ts @@ -1,7 +1,8 @@ /* ============================================================================= * M02_MasterTemplete_UI_Side.ts - * 마스터 템플릿 좌측 패널 — 시스템 양식 목록(표/도면/구조물 도면) · 새로 · 본떠 · 지우기. - * 서버 길은 계약 `6_계약.md`. 구조물 도면 줄은 집계표 열마다 하나(서버가 미리 만들어 둠 · 도번 항상 있음). + * 마스터 템플릿 좌측 패널 — 시스템 양식 목록(표/도면/구조물 도면/산출근거) · 새로 · 본떠 · 지우기. + * 서버 길은 계약 `6_계약.md`. 구조물 도면 · 산출근거 줄은 집계표 열마다 하나씩 — + * 서버가 미리 만들어 둠(도번·표번 항상 있음 · 같은 번호 매기기 규칙). * ========================================================================== */ import { @@ -17,6 +18,7 @@ import { t as L } from "@ui/ui_template_locale"; import { openModal } from "@ui/ui_template_modal"; import { deleteTemplate, + fetchBasisNumbers, fetchStructureNumbers, listTemplates, readTemplate, @@ -82,6 +84,7 @@ export function buildSide(opt: SideOptions): SideHandle { let items: TemplateInfo[] = []; let columns: StructureColumn[] = []; let numbers: Record = {}; + let basisNumbers: Record = {}; let seq = 0; let picked: { kind: Kind; name: string } | null = null; @@ -95,12 +98,14 @@ export function buildSide(opt: SideOptions): SideHandle { KINDS.map((k) => [k.kind, el("div", { className: "m02-side__items ui-sidebar-list" })]), ); const structureBody = el("div", { className: "m02-side__items ui-sidebar-list" }); + const basisBody = el("div", { className: "m02-side__items ui-sidebar-list" }); const listHost = el("div", { className: "m02-side__lists ui-sidebar-panel", children: [ section(L("M02_KindTable"), bodies.get("table")!), section(L("M02_KindDrawing"), bodies.get("drawing")!), section(L("M02_KindStructure"), structureBody), + section(L("M02_KindBasis"), basisBody), ], }); attachCollapsible(listHost); @@ -166,6 +171,24 @@ export function buildSide(opt: SideOptions): SideHandle { ); } + /** 산출근거 줄 — 구조물 도면과 같은 열 목록 · 표번은 도번과 같은 규칙(서버가 미리 만들어 둠) */ + function paintBasis(): void { + basisBody.replaceChildren( + ...(columns.length + ? columns.map((col) => { + const num = basisNumbers[col.id] ?? L("M02_StructureNone"); + const b = el("button", { + className: `m02-side__item ui-sidebar-row${isPicked("basis", col.id) ? " is-active" : ""}`, + text: `${columnHead(col)} · ${num}`, + attrs: { type: "button" }, + }); + b.addEventListener("click", () => void selectBasisColumn(col)); + return b; + }) + : [el("p", { className: "m02-side__empty", text: L("M02_NoTemplates") })]), + ); + } + function paintButtons(): void { const editable = canEdit(layer, opt.isAdmin); btnNew.disabled = !editable; @@ -192,23 +215,37 @@ export function buildSide(opt: SideOptions): SideHandle { label: columnHead(col), }); paintStructure(); + paintBasis(); + paintButtons(); + } + + async function selectBasisColumn(col: StructureColumn): Promise { + if (!isPicked("basis", col.id) && !(await opt.confirmLeave())) return; + picked = null; + opt.onOpen({ layer, projectId: null, kind: "basis", name: col.id, label: columnHead(col) }); + paintStructure(); + paintBasis(); paintButtons(); } async function refreshStructure(): Promise { try { - const [table, nums] = await Promise.all([ + const [table, nums, basisNums] = await Promise.all([ readTemplate(layer, "table", STRUCTURE_TABLE, null), fetchStructureNumbers(), + fetchBasisNumbers(), ]); columns = ((table.문서 as { 열?: StructureColumn[] }).열 ?? []) as StructureColumn[]; numbers = nums; + basisNumbers = basisNums; } catch (error) { columns = []; numbers = {}; + basisNumbers = {}; showToast(L("M02_LoadFailed").replace("{value}", why(error)), "error"); } paintStructure(); + paintBasis(); } async function refresh(): Promise { @@ -309,6 +346,7 @@ export function buildSide(opt: SideOptions): SideHandle { picked = { kind, name }; paintList(); paintStructure(); + paintBasis(); }, }; } diff --git a/resources/master_template/basis/be.json b/resources/master_template/basis/be.json index d144a756..dfea20aa 100644 --- a/resources/master_template/basis/be.json +++ b/resources/master_template/basis/be.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-01" } diff --git a/resources/master_template/basis/bg.json b/resources/master_template/basis/bg.json index 2cfbf5e9..6a72563b 100644 --- a/resources/master_template/basis/bg.json +++ b/resources/master_template/basis/bg.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-02" } diff --git a/resources/master_template/basis/bm_area.json b/resources/master_template/basis/bm_area.json index 6f2104cb..1b29ee01 100644 --- a/resources/master_template/basis/bm_area.json +++ b/resources/master_template/basis/bm_area.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-03" } diff --git a/resources/master_template/basis/bm_len.json b/resources/master_template/basis/bm_len.json index 6c485795..4a74736d 100644 --- a/resources/master_template/basis/bm_len.json +++ b/resources/master_template/basis/bm_len.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-04" } diff --git a/resources/master_template/basis/bx_len.json b/resources/master_template/basis/bx_len.json index 7f77b27a..9c0bd754 100644 --- a/resources/master_template/basis/bx_len.json +++ b/resources/master_template/basis/bx_len.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-05" } diff --git a/resources/master_template/basis/bx_wing.json b/resources/master_template/basis/bx_wing.json index abb5866d..1e0217a7 100644 --- a/resources/master_template/basis/bx_wing.json +++ b/resources/master_template/basis/bx_wing.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-06" } diff --git a/resources/master_template/basis/cs.json b/resources/master_template/basis/cs.json index c7e4c54e..e96e31c6 100644 --- a/resources/master_template/basis/cs.json +++ b/resources/master_template/basis/cs.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-07" } diff --git a/resources/master_template/basis/ec.json b/resources/master_template/basis/ec.json index 6fb922db..645360cb 100644 --- a/resources/master_template/basis/ec.json +++ b/resources/master_template/basis/ec.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-08" } diff --git a/resources/master_template/basis/etc.json b/resources/master_template/basis/etc.json index 39b122f6..11514e22 100644 --- a/resources/master_template/basis/etc.json +++ b/resources/master_template/basis/etc.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-09" } diff --git a/resources/master_template/basis/fb.json b/resources/master_template/basis/fb.json index fdf75c78..1a6d5193 100644 --- a/resources/master_template/basis/fb.json +++ b/resources/master_template/basis/fb.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-10" } diff --git a/resources/master_template/basis/fp_l.json b/resources/master_template/basis/fp_l.json index 94ea26a3..fa43c4a9 100644 --- a/resources/master_template/basis/fp_l.json +++ b/resources/master_template/basis/fp_l.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-11" } diff --git a/resources/master_template/basis/fp_w.json b/resources/master_template/basis/fp_w.json index 6bef5748..4611a5c2 100644 --- a/resources/master_template/basis/fp_w.json +++ b/resources/master_template/basis/fp_w.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-12" } diff --git a/resources/master_template/basis/gr_curb.json b/resources/master_template/basis/gr_curb.json index a7c3407c..2972a54f 100644 --- a/resources/master_template/basis/gr_curb.json +++ b/resources/master_template/basis/gr_curb.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-13" } diff --git a/resources/master_template/basis/gr_rail.json b/resources/master_template/basis/gr_rail.json index 6599a2fe..f5e3b906 100644 --- a/resources/master_template/basis/gr_rail.json +++ b/resources/master_template/basis/gr_rail.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-14" } diff --git a/resources/master_template/basis/gr_sign.json b/resources/master_template/basis/gr_sign.json index 3d05704a..5fa9c39c 100644 --- a/resources/master_template/basis/gr_sign.json +++ b/resources/master_template/basis/gr_sign.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-15" } diff --git a/resources/master_template/basis/h_break.json b/resources/master_template/basis/h_break.json index ae8cc151..7134d351 100644 --- a/resources/master_template/basis/h_break.json +++ b/resources/master_template/basis/h_break.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-16" } diff --git a/resources/master_template/basis/h_ford_basin.json b/resources/master_template/basis/h_ford_basin.json index 29d20574..5c621143 100644 --- a/resources/master_template/basis/h_ford_basin.json +++ b/resources/master_template/basis/h_ford_basin.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-17" } diff --git a/resources/master_template/basis/h_intake.json b/resources/master_template/basis/h_intake.json index d072f999..ac1ec71a 100644 --- a/resources/master_template/basis/h_intake.json +++ b/resources/master_template/basis/h_intake.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-18" } diff --git a/resources/master_template/basis/h_pg_rail.json b/resources/master_template/basis/h_pg_rail.json index ac1d69c2..31c6f620 100644 --- a/resources/master_template/basis/h_pg_rail.json +++ b/resources/master_template/basis/h_pg_rail.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-19" } diff --git a/resources/master_template/basis/h_pv_rail.json b/resources/master_template/basis/h_pv_rail.json index 665550f5..080c14eb 100644 --- a/resources/master_template/basis/h_pv_rail.json +++ b/resources/master_template/basis/h_pv_rail.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-20" } diff --git a/resources/master_template/basis/h_rip_c.json b/resources/master_template/basis/h_rip_c.json index ce2cb1b8..4a7be6fa 100644 --- a/resources/master_template/basis/h_rip_c.json +++ b/resources/master_template/basis/h_rip_c.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-21" } diff --git a/resources/master_template/basis/h_rip_m.json b/resources/master_template/basis/h_rip_m.json index 623be3b5..26bdf29e 100644 --- a/resources/master_template/basis/h_rip_m.json +++ b/resources/master_template/basis/h_rip_m.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-22" } diff --git a/resources/master_template/basis/h_rockfall.json b/resources/master_template/basis/h_rockfall.json index aaa0e2c1..9f604788 100644 --- a/resources/master_template/basis/h_rockfall.json +++ b/resources/master_template/basis/h_rockfall.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-23" } diff --git a/resources/master_template/basis/h_soil_ditch.json b/resources/master_template/basis/h_soil_ditch.json index c5b9a2c0..78775ef0 100644 --- a/resources/master_template/basis/h_soil_ditch.json +++ b/resources/master_template/basis/h_soil_ditch.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-24" } diff --git a/resources/master_template/basis/h_stone_bed.json b/resources/master_template/basis/h_stone_bed.json index dafb2577..67c7e5ba 100644 --- a/resources/master_template/basis/h_stone_bed.json +++ b/resources/master_template/basis/h_stone_bed.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-25" } diff --git a/resources/master_template/basis/h_stone_ch.json b/resources/master_template/basis/h_stone_ch.json index 1158d797..62958197 100644 --- a/resources/master_template/basis/h_stone_ch.json +++ b/resources/master_template/basis/h_stone_ch.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-26" } diff --git a/resources/master_template/basis/h_waste.json b/resources/master_template/basis/h_waste.json index a1aa8cd2..9a0c7ada 100644 --- a/resources/master_template/basis/h_waste.json +++ b/resources/master_template/basis/h_waste.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-27" } diff --git a/resources/master_template/basis/memo.json b/resources/master_template/basis/memo.json index 76fca18d..2a2cc430 100644 --- a/resources/master_template/basis/memo.json +++ b/resources/master_template/basis/memo.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-28" } diff --git a/resources/master_template/basis/mr.json b/resources/master_template/basis/mr.json index 7d90ba69..af631fc8 100644 --- a/resources/master_template/basis/mr.json +++ b/resources/master_template/basis/mr.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-29" } diff --git a/resources/master_template/basis/ms.json b/resources/master_template/basis/ms.json index 81cb2717..3fae50e8 100644 --- a/resources/master_template/basis/ms.json +++ b/resources/master_template/basis/ms.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-30" } diff --git a/resources/master_template/basis/no.json b/resources/master_template/basis/no.json index 771a4fc4..aa7985cc 100644 --- a/resources/master_template/basis/no.json +++ b/resources/master_template/basis/no.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-31" } diff --git a/resources/master_template/basis/od_cnt.json b/resources/master_template/basis/od_cnt.json index 00a55396..18cd83b9 100644 --- a/resources/master_template/basis/od_cnt.json +++ b/resources/master_template/basis/od_cnt.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-32" } diff --git a/resources/master_template/basis/od_len.json b/resources/master_template/basis/od_len.json index 71215e1b..3672007f 100644 --- a/resources/master_template/basis/od_len.json +++ b/resources/master_template/basis/od_len.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-33" } diff --git a/resources/master_template/basis/pg_in.json b/resources/master_template/basis/pg_in.json index 44eed2ae..e092e26a 100644 --- a/resources/master_template/basis/pg_in.json +++ b/resources/master_template/basis/pg_in.json @@ -52,5 +52,7 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-34", + "계산값": {} } diff --git a/resources/master_template/basis/pp_cp.json b/resources/master_template/basis/pp_cp.json index 623cae69..77ca0428 100644 --- a/resources/master_template/basis/pp_cp.json +++ b/resources/master_template/basis/pp_cp.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-35" } diff --git a/resources/master_template/basis/pp_len.json b/resources/master_template/basis/pp_len.json index 812d3076..6265d1e3 100644 --- a/resources/master_template/basis/pp_len.json +++ b/resources/master_template/basis/pp_len.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-36" } diff --git a/resources/master_template/basis/ps.json b/resources/master_template/basis/ps.json index 48ca7945..dcab53ab 100644 --- a/resources/master_template/basis/ps.json +++ b/resources/master_template/basis/ps.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-37" } diff --git a/resources/master_template/basis/pv_a.json b/resources/master_template/basis/pv_a.json index fe322750..62ec59d7 100644 --- a/resources/master_template/basis/pv_a.json +++ b/resources/master_template/basis/pv_a.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-38" } diff --git a/resources/master_template/basis/pv_b.json b/resources/master_template/basis/pv_b.json index 71ade0af..581bd756 100644 --- a/resources/master_template/basis/pv_b.json +++ b/resources/master_template/basis/pv_b.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-39" } diff --git a/resources/master_template/basis/pv_jt.json b/resources/master_template/basis/pv_jt.json index ed4e5ef6..d5d49f2d 100644 --- a/resources/master_template/basis/pv_jt.json +++ b/resources/master_template/basis/pv_jt.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-40" } diff --git a/resources/master_template/basis/pv_l.json b/resources/master_template/basis/pv_l.json index a5d588e3..7e8dc0c5 100644 --- a/resources/master_template/basis/pv_l.json +++ b/resources/master_template/basis/pv_l.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-41" } diff --git a/resources/master_template/basis/pv_w.json b/resources/master_template/basis/pv_w.json index 08406dc4..c45478c2 100644 --- a/resources/master_template/basis/pv_w.json +++ b/resources/master_template/basis/pv_w.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-42" } diff --git a/resources/master_template/basis/rf.json b/resources/master_template/basis/rf.json index e57337fd..9f1948a7 100644 --- a/resources/master_template/basis/rf.json +++ b/resources/master_template/basis/rf.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-43" } diff --git a/resources/master_template/basis/rv.json b/resources/master_template/basis/rv.json index fba5401b..e10dcaad 100644 --- a/resources/master_template/basis/rv.json +++ b/resources/master_template/basis/rv.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-44" } diff --git a/resources/master_template/basis/rw.json b/resources/master_template/basis/rw.json index 047f1e02..be1d59d6 100644 --- a/resources/master_template/basis/rw.json +++ b/resources/master_template/basis/rw.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-45" } diff --git a/resources/master_template/basis/sg.json b/resources/master_template/basis/sg.json index b974fcce..3acfffa3 100644 --- a/resources/master_template/basis/sg.json +++ b/resources/master_template/basis/sg.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-46" } diff --git a/resources/master_template/basis/sta.json b/resources/master_template/basis/sta.json index 16bf443b..f95ee33c 100644 --- a/resources/master_template/basis/sta.json +++ b/resources/master_template/basis/sta.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-47" } diff --git a/resources/master_template/basis/ta.json b/resources/master_template/basis/ta.json index 41ddd730..d75dda53 100644 --- a/resources/master_template/basis/ta.json +++ b/resources/master_template/basis/ta.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-48" } diff --git a/resources/master_template/basis/wy.json b/resources/master_template/basis/wy.json index e551e5e8..e7f1ae27 100644 --- a/resources/master_template/basis/wy.json +++ b/resources/master_template/basis/wy.json @@ -52,5 +52,6 @@ } } ], - "활성": "s1" + "활성": "s1", + "표번": "표-49" } diff --git a/resources/tester/spreadsheet/test_spreadsheet_store.py b/resources/tester/spreadsheet/test_spreadsheet_store.py index 2afec531..9f0dc02d 100644 --- a/resources/tester/spreadsheet/test_spreadsheet_store.py +++ b/resources/tester/spreadsheet/test_spreadsheet_store.py @@ -88,6 +88,29 @@ def test_새_구조물_도면은_산출근거_따로(client): assert heads == ["공종", "규격", "산출 내역", "단위", "수량(m당)"] +def test_표번은_도번과_같은_규칙(client): + made1 = client.post("/api/m02/structures/rv").json()["문서"] + made2 = client.post("/api/m02/structures/pv_b").json()["문서"] + assert made1["도번"] == "구-01" and made2["도번"] == "구-02" + basis1 = client.get("/api/m02/templates/basis/rv").json()["문서"] + basis2 = client.get("/api/m02/templates/basis/pv_b").json()["문서"] + assert basis1["표번"] == "표-01" and basis2["표번"] == "표-02" + numbers = client.get("/api/m02/basis/numbers").json() + assert numbers["rv"] == "표-01" and numbers["pv_b"] == "표-02" + + +def test_표번_없는_옛_파일은_만나면_채움(client, tmp_path): + store.ensure_basis("rv") + doc = store.read("basis", "rv")["문서"] + del doc["표번"] + (tmp_path / "basis" / "rv.json").write_text( + json.dumps(doc, ensure_ascii=False), encoding="utf-8" + ) + numbers = client.get("/api/m02/basis/numbers").json() + assert numbers["rv"] == "표-01" + assert store.read("basis", "rv")["문서"]["표번"] == "표-01" # 한 번 채우면 파일에 남음 + + def test_저장은_서버_계산값만_적음(client): store.ensure_basis("rv") got = client.get("/api/m02/templates/basis/rv").json() diff --git a/resources/tester/test_m02_structure_panel.py b/resources/tester/test_m02_structure_panel.py index 73be180e..15e8a1e9 100644 --- a/resources/tester/test_m02_structure_panel.py +++ b/resources/tester/test_m02_structure_panel.py @@ -22,6 +22,7 @@ ROOT = Path(__file__).resolve().parents[2] M02 = ROOT / "M02_MasterTemplete" PANEL = M02 / "M02_MasterTemplete_Structure.ts" MAIN = M02 / "M02_MasterTemplete_UI_Main.ts" +SIDE = M02 / "M02_MasterTemplete_UI_Side.ts" def _text(path: Path) -> str: @@ -39,23 +40,28 @@ def test_소스가_700줄을_넘지_않음(): @pytest.mark.parametrize( - ("source", "names"), + ("source", "names", "target"), [ ( "M02_MasterTemplete_Api_Fetch.ts", - ["createStructure", "fetchStructureNumbers", "readTemplate", "saveTemplate"], + ["createStructure", "fetchStructureNumbers", "readTemplate"], + PANEL, ), - ("M02_MasterTemplete_Drawing.ts", ["mountDrawingTemplate"]), - ("../A00_Common/spreadsheet/spreadsheet.ts", ["createSpreadsheet"]), + # 산출근거 저장은 컨테이너가 안 함 — [산출근거 수정] 이 여는 메인 칸 전체 편집이 함 + ("M02_MasterTemplete_Api_Fetch.ts", ["saveTemplate"], MAIN), + # 좌측 산출근거 줄 번호는 좌측 패널이 받음(구조물 도면 줄과 같은 자리) + ("M02_MasterTemplete_Api_Fetch.ts", ["fetchBasisNumbers"], SIDE), + ("M02_MasterTemplete_Drawing.ts", ["mountDrawingTemplate"], PANEL), + ("../A00_Common/spreadsheet/spreadsheet.ts", ["createSpreadsheet"], PANEL), ], ) -def test_컨테이너가_쓰는_이름이_내보내진_것(source: str, names: list[str]): +def test_컨테이너가_쓰는_이름이_내보내진_것(source: str, names: list[str], target: Path): """도면 부품 · 스프레드시트(D) 가 이름을 바꾸면 여기서 먼저 걸림.""" body = _text(M02 / source) - panel = _text(PANEL) + used = _text(target) for name in names: assert re.search(rf"export (const|function|interface) {name}\b", body), f"{source}:{name}" - assert name in panel, name + assert name in used, name def test_집계표만_컨테이너를_붙임(): diff --git a/ui_template/ui_template_locale_m2.ts b/ui_template/ui_template_locale_m2.ts index 238cd5f1..d0cf0197 100644 --- a/ui_template/ui_template_locale_m2.ts +++ b/ui_template/ui_template_locale_m2.ts @@ -9,6 +9,7 @@ export const ui_locales_m2 = { M02_KindTable: ["표 양식", "Table templates"], M02_KindDrawing: ["도면 양식", "Drawing templates"], M02_KindStructure: ["구조물 도면", "Structure drawings"], + M02_KindBasis: ["산출근거", "Cost basis"], M02_NoTemplates: ["양식 없음", "None"], M02_New: ["새로", "New"], M02_Copy: ["본떠 만들기", "Copy as new"], @@ -37,6 +38,7 @@ export const ui_locales_m2 = { ], M02_NoSheet: ["표 편집 부품이 아직 없음", "Table editor not available yet"], M02_NoDrawing: ["도면 편집 부품이 아직 없음", "Drawing editor not available yet"], + M02_NoSpreadsheet: ["산출근거 편집 부품이 아직 없음", "Cost basis editor not available yet"], M02_NameExists: ["이미 있는 이름", "That name already exists"], M02_BadName: [ '쓸 수 없는 글자 — / \\ : * ? " < > | 와 .. · 앞의 점은 안 됨',