From 4ee90060e166782fcf011c548ee0b6f19c5d1ab0 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sat, 10 Oct 2026 14:03:32 +0900 Subject: [PATCH] =?UTF-8?q?=EF=BB=BFfeat(B08):=20=EA=B5=AC=EC=A1=B0?= =?UTF-8?q?=EB=AC=BC=20=EC=A7=91=EA=B3=84=ED=91=9C=20=EB=AF=B8=EC=97=B0?= =?UTF-8?q?=EA=B2=B0=20=3D=20=EC=B8=A1=EC=A0=90=20=EC=B9=B8=20=EC=99=BC?= =?UTF-8?q?=EC=AA=BD=20=EB=85=B8=EB=9E=91=20=EB=9E=A8=ED=94=84=20=C2=B7=20?= =?UTF-8?q?=EB=AF=B8=EC=A7=80=EC=A0=95=20=EC=97=B4=20=EC=A7=80=EC=9B=80=20?= =?UTF-8?q?(198-1)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 「미지정」 열 · 조합 칸 「미지정」 표기 · 측점 「· 미연결」 글 지움 - 미연결 줄 측점 칸 = 경고 노랑 램프 · 호버 = 구조물 조합 미연결 — 빈 조합 칸 - 서버 안내 글 「노랑 램프 줄을 눌러 조합 연결」 - 새 시험 test_198_1 · test_61_1 · 143_1 · 160_2 단정 고침 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01STqEqztUthVFBmEP18wBSz --- B08_Quantity/B08_Quantity_Router_Summary.py | 2 +- B08_Quantity/B08_Quantity_Summary_Data.ts | 17 +-- B08_Quantity/B08_Quantity_UI_Page.css | 12 ++ B08_Quantity/B08_Quantity_UI_Summary.ts | 50 ++++---- .../tester/test_143_1_b08_linked_snapshots.py | 4 +- resources/tester/test_160_2_b08_unassigned.py | 20 +-- .../tester/test_198_1_b08_summary_lamp.py | 114 ++++++++++++++++++ .../tester/test_61_1_b08_summary_table.py | 2 +- ui_template/ui_template_locale_b4.ts | 2 +- 9 files changed, 163 insertions(+), 60 deletions(-) create mode 100644 resources/tester/test_198_1_b08_summary_lamp.py diff --git a/B08_Quantity/B08_Quantity_Router_Summary.py b/B08_Quantity/B08_Quantity_Router_Summary.py index 85f66877f..3ac853296 100644 --- a/B08_Quantity/B08_Quantity_Router_Summary.py +++ b/B08_Quantity/B08_Quantity_Router_Summary.py @@ -595,7 +595,7 @@ def pipe_summary( notes = [] missing = sheet.unlinked | {key for key, found in others.items() if not found} if missing: - notes.append(f"조합 사본 없는 시설 {len(missing)}곳 — 「미연결」 줄을 눌러 조합 연결") + notes.append(f"조합 사본 없는 시설 {len(missing)}곳 — 노랑 램프 줄을 눌러 조합 연결") if no_length: notes.append(f"관 연장 없음 {no_length}곳 — B06 횡단 [저장] 뒤 채워짐") if no_basin: diff --git a/B08_Quantity/B08_Quantity_Summary_Data.ts b/B08_Quantity/B08_Quantity_Summary_Data.ts index 3784dd949..116aecc9b 100644 --- a/B08_Quantity/B08_Quantity_Summary_Data.ts +++ b/B08_Quantity/B08_Quantity_Summary_Data.ts @@ -5,8 +5,8 @@ * 줄 = 구조물 · 배관이 놓인 측점(같은 측점은 한 줄 · 오름차순) * 열 = 저장된 구조물 조합(본체 `summary_item` + 그룹 `group_items`) — 같은 층 · 주인 · 키는 한 열 * 조합 = 프로젝트 안 사본이 있는 것만(`linkedOnly` · 서버 `linked_snapshots` · PLAN 143-1) - * 미연결 시설 = 서버 `unlinked`(셈한 칸 기준) — 그 측점도 줄(값 빈칸 · 「미연결」 · PLAN 154-1) - * 「미지정」 열 글 · 같은 조합 열 칸 = 빈 조합 칸(`unassignedText` · `unassignedCombos` · 160-2) + * 미연결 시설 = 서버 `unlinked`(셈한 칸 기준) — 그 측점도 줄(값 빈칸 · 노랑 램프 · PLAN 154-1 · 198-1) + * 램프 호버 글 = 빈 조합 칸(`unassignedText` · 160-2) * * 읽기만 — B05/B06 저장 자료(structures.json · pipe_points.json)를 고치지 않는다. * 런타임 import 는 `common_util_summary_item` 하나 — 시험이 두 파일을 이어 붙여 돌림. @@ -114,7 +114,7 @@ export interface ComboColumn { export const comboId = (item: SummaryItem): string => `${item.layer}|${item.owner ?? ""}|${item.key}`; -/** 측점 「미지정」 칸 글 — 시설마다 「이름: 빈 칸 · 빈 칸」(칸 이름 = 그룹 · 본체 = `body` · 160-2). */ +/** 측점 램프 호버 글 —시설마다 「이름: 빈 칸 · 빈 칸」(칸 이름 = 그룹 · 본체 = `body` · 160-2). */ export const unassignedText = (facilities: readonly UnlinkedFacility[], body: string): string => facilities .map((f) => { @@ -123,17 +123,6 @@ export const unassignedText = (facilities: readonly UnlinkedFacility[], body: st }) .join(" / "); -/** 빈 칸에 고른 조합 id — 같은 조합 열이 있으면 그 칸에 「미지정」(160-2). */ -export function unassignedCombos(facilities: readonly UnlinkedFacility[]): Set { - const ids = new Set(); - for (const f of facilities) - for (const slot of f.slots) { - const item = slot.linked ? null : readSummaryItem(slot.item); - if (item) ids.add(comboId(item)); - } - return ids; -} - function stationOf(thing: PlacedItem): number | null { const value = thing.chainage_m ?? thing.start_m; return typeof value === "number" && Number.isFinite(value) ? value : null; diff --git a/B08_Quantity/B08_Quantity_UI_Page.css b/B08_Quantity/B08_Quantity_UI_Page.css index b419ee0de..f1c338629 100644 --- a/B08_Quantity/B08_Quantity_UI_Page.css +++ b/B08_Quantity/B08_Quantity_UI_Page.css @@ -44,6 +44,18 @@ overflow-wrap: anywhere; } +/* 구조물 집계표 미연결 램프(198-1) — 측점 칸 왼쪽 경고 노랑 점 하나(177-1 미연결 노랑 토큰) · 연결 줄은 없음 */ +[data-b08-summary="table"] td.b08-summary__lamp::before { + content: ""; + display: inline-block; + width: 8px; + height: 8px; + margin-right: 6px; + border-radius: 50%; + background: var(--color-warning); + vertical-align: middle; +} + /* 좌측 패널 옵션(122) — 연암 · 경암 두 칸 나란히 · 설명 한 줄 */ .b08-options__row { display: grid; diff --git a/B08_Quantity/B08_Quantity_UI_Summary.ts b/B08_Quantity/B08_Quantity_UI_Summary.ts index 5a25baa8f..21cc8febf 100644 --- a/B08_Quantity/B08_Quantity_UI_Summary.ts +++ b/B08_Quantity/B08_Quantity_UI_Summary.ts @@ -6,8 +6,8 @@ * 구조물 = GET …/route/structures · 배관 = GET …/drainage/pipe-points (읽기만) * 머리 두 줄 = 조합 구분(경로 첫 칸) · 조합 이름(나머지 경로) — 사본 manifest 경로(집계 응답 `linked`) * 조합 · 측점 = 프로젝트 안 사본이 있는 것만(`linkedOnly` · PLAN 143-1) — 미연결 시설은 그 측점 - * 줄만 「· 미연결」(값 빈칸 · 서버 `unlinked` · PLAN 154-1) · 측점 옆 「미지정」 열 = 그 측점 빈 조합 칸 - * · 같은 조합 열이 있으면 그 칸에도 「미지정」(160-2 · 화면만) + * 줄만 측점 칸 왼쪽 노랑 램프(값 빈칸 · 서버 `unlinked` · PLAN 154-1 · 198-1) + * · 램프 호버(공용 `ui_template_hover_info`) = 그 측점 빈 조합 칸(160-2 · 화면만) * 횡단배수 열 · 칸 = GET …/quantity/summary(서버 단독 · PLAN 98 · 120) — 머리 구조물 · 형식 · 규격 * 3단 + 단위 줄 · 「관 공」 맨 윗 머리 = 관에 이은 조합 경로(있으면) · 서버가 펼친 종류(`types`)는 * 조합 열에서 뺌 · 다른 구조물 열은 조합 그대로 @@ -24,6 +24,7 @@ import { fetchStructures } from "../B05_Profile/B05_Profile_Api_Structures"; import { fetchLatestRoute, readRouteLatestCache } from "../B05_Profile/B05_Profile_Api_Fetch"; import { fetchDetailPipePoints } from "../B04_PreProcess/B04_PreProcess_Api_Fetch"; import { createDataTable, type DataColumn, type DataRow } from "@ui/ui_template_data_table"; +import { attachHoverInfo } from "@ui/ui_template_hover_info"; import { pipeStructureId } from "@ui/ui_template_item_picker_project"; import { stationLabel } from "../common_util/common_util_station"; import { summaryTooltip, type SummaryItem } from "../common_util/common_util_summary_item"; @@ -39,7 +40,6 @@ import { type LinkedSnapshot, type PlacedItem, type UnlinkedFacility, - unassignedCombos, unassignedText, unlinkedAt, widthOf, @@ -98,6 +98,9 @@ async function fetchPipeSummary(projectId: string): Promise { } const PIPE_TOP = "관 공"; +/** 미연결 램프 칸 class(`B08_Quantity_UI_Page.css` · 198-1) · 램프 자리 폭(12px 글 기준) */ +const LAMP_CLASS = "b08-summary__lamp"; +const LAMP_W = 14; const stationKey = (station: number): number => Math.round(station * 100); /** 열 소수 자리 — 칸 · 계 값이 쓰는 만큼(최대 2). */ const placesOf = (values: number[]): number => @@ -150,29 +153,14 @@ function buildTable( ? { station: L("B08_Quantity_Summary_Total"), ...pipe.total } : null; const labels = stations.map((station) => stationLabel(station, interval)); - // 미연결 시설 측점 = 「· 미연결」(값 빈칸 · 누르면 바로 연결 · 154) - const shown = stations.map((station, i) => - unlinkedAt(unlinked, station).length - ? `${labels[i]} · ${L("B08_Quantity_Summary_Unlinked")}` - : labels[i], - ); const stationHead = L("B08_Quantity_Summary_Station"); - // 160-2 — 빈 조합 칸 이름 · 같은 조합 열 칸에도 「미지정」(미연결 시설이 있을 때만 열) - const missingHead = L("B08_Quantity_Summary_Unassigned"); - const here = stations.map((station) => unlinkedAt(unlinked, station)); - const missing = here.map((at) => unassignedText(at, L("B08_Quantity_Link_Body"))); - const hasMissing = missing.some(Boolean); - const comboIds = new Set(columns.map((column) => column.id)); - const markOf = (at: readonly UnlinkedFacility[]): Record => - Object.fromEntries( - [...unassignedCombos(at)].filter((id) => comboIds.has(id)).map((id) => [id, missingHead]), - ); + // 198-1 — 미연결 시설 측점 = 측점 칸 왼쪽 노랑 램프(값 빈칸 · 누르면 바로 연결 · 154) · 호버 = 빈 조합 칸(160-2) + const missing = stations.map((station) => + unassignedText(unlinkedAt(unlinked, station), L("B08_Quantity_Link_Body")), + ); const table = createDataTable({ columns: [ - { key: "station", label: stationHead, width: widthOf(stationHead, ...shown) }, - ...(hasMissing - ? [{ key: "unassigned", label: missingHead, width: widthOf(missingHead, ...missing) }] - : []), + { key: "station", label: stationHead, width: widthOf(stationHead, ...labels) + LAMP_W }, ...columns.map((column) => ({ key: column.id, label: column.name, @@ -185,18 +173,26 @@ function buildTable( ], // 조합 열 칸은 아직 비움 — 사용자가 채울 자리라 「-」 대신 빈칸 · 배관 칸 = 서버 값 rows: stations.map((station, i) => ({ - station: shown[i], - ...(hasMissing ? { unassigned: missing[i] } : {}), - ...markOf(here[i]), + station: labels[i], ...values.get(stationKey(station)), })), total, onRowClick: (i) => onRowClick(stations[i], labels[i]), - frozen: hasMissing ? 2 : 1, + cellClass: (i, key) => (key === "station" && missing[i] ? LAMP_CLASS : null), + frozen: 1, empty: "", caption: L("B08_Quantity_Tab_StructureSummary"), }); table.root.dataset.b08Summary = "table"; + // 줄을 다시 그려도(보이는 줄만) 떠 있는 root 하나에 걸어 둠 — 줄 번호 = 줄 `data-i` + attachHoverInfo( + table.root, + (cell) => { + const why = missing[Number(cell.closest("tr")?.dataset.i)]; + return why && `${L("B08_Quantity_Summary_LampTip")} — ${why}`; + }, + `td.${LAMP_CLASS}`, + ); return table.root; } diff --git a/resources/tester/test_143_1_b08_linked_snapshots.py b/resources/tester/test_143_1_b08_linked_snapshots.py index 2f48bbcbf..6eb698a8f 100644 --- a/resources/tester/test_143_1_b08_linked_snapshots.py +++ b/resources/tester/test_143_1_b08_linked_snapshots.py @@ -154,7 +154,7 @@ def test_사본_없는_시설_알림_응답에_사본(root): out = _run(root) # 100(유출 흙막이) · 200 · 300 · 400 · 500(기본 날개벽 잇기) · 600 · 개거 700 = 7곳 assert not any("wing" in c["id"] for c in out["columns"]) - assert "조합 사본 없는 시설 7곳 — 「미연결」 줄을 눌러 조합 연결" in out["notes"] + assert "조합 사본 없는 시설 7곳 — 노랑 램프 줄을 눌러 조합 연결" in out["notes"] assert not any("관 연장 없음" in n for n in out["notes"]) assert set(out["linked"]) == {"pipe@100.0", "pipe@500.0__gford"} @@ -187,7 +187,7 @@ def test_화면_조합_이름_구조물도는_사본에서(): ui = (ROOT / "B08_Quantity/B08_Quantity_UI_Summary.ts").read_text(encoding="utf-8") assert "loadPickerRows" not in ui # 층 목록 GET 안 씀 assert "linkedOnly(" in ui - assert "unlinkedAt(" in ui and "B08_Quantity_Summary_Unlinked" in ui # 154-1 미연결 줄 + assert "unlinkedAt(" in ui and "B08_Quantity_Summary_LampTip" in ui # 154-1 · 198-1 미연결 램프 drawing = (ROOT / "B08_Quantity/B08_Quantity_UI_Drawing.ts").read_text(encoding="utf-8") assert "readTemplate" not in drawing # 층 폴백 없음 assert "B08_Quantity_Sheets_NoCopy" in drawing diff --git a/resources/tester/test_160_2_b08_unassigned.py b/resources/tester/test_160_2_b08_unassigned.py index 7b9a37433..e2e351912 100644 --- a/resources/tester/test_160_2_b08_unassigned.py +++ b/resources/tester/test_160_2_b08_unassigned.py @@ -1,4 +1,4 @@ -"""160-2 B08 구조물 집계표 「미지정」 — 측점 옆 열 글 · 같은 조합 열 칸 표기(화면만). +"""160-2 B08 구조물 집계표 빈 조합 칸 글(198-1 부터 미연결 램프 호버 글 · 「미지정」 열 · 칸 표기는 지움). `B08_Quantity_Summary_Data.ts` 를 `common_util_summary_item.ts` 와 이어 붙여 node 로 돌림(61-1 시험과 같은 꼴). """ @@ -47,31 +47,23 @@ FACILITIES = [ ] -def test_미지정_글과_조합_칸(): +def test_빈_조합_칸_글(): out = _run( f"\nconst f = {json.dumps(FACILITIES, ensure_ascii=False)};" "\nconst at = (s) => unlinkedAt(f, s);" "\nconsole.log(JSON.stringify({" " t100: unassignedText(at(100), '본체'), t160: unassignedText(at(160), '본체')," - " t0: unassignedText(at(0), '본체')," - " c100: [...unassignedCombos(at(100))], c160: [...unassignedCombos(at(160))] }));" + " t0: unassignedText(at(0), '본체') }));" ) assert out["t100"] == "배관: 본체 · 관 / 세월교: 유출 구조" assert out["t160"] == "BOX" and out["t0"] == "" - assert out["c100"] == ["system||SS2"] # 연결된 칸 · 고른 조합 없는 칸은 뺌 - assert out["c160"] == [] def test_화면_연결(): summary = (ROOT / "B08_Quantity/B08_Quantity_UI_Summary.ts").read_text(encoding="utf-8") assert ( - 'unassignedText(at, L("B08_Quantity_Link_Body"))' in summary + 'unassignedText(unlinkedAt(unlinked, station), L("B08_Quantity_Link_Body"))' in summary ) # 칸 이름 = 모달과 같은 규칙 - assert ( - 'key: "unassigned", label: missingHead' in summary - and "frozen: hasMissing ? 2 : 1" in summary - ) - assert "...markOf(here[i])," in summary and "filter((id) => comboIds.has(id))" in summary - assert '${L("B08_Quantity_Summary_Unlinked")}' in summary # 「· 미연결」 측점 표기 그대로 + assert 'key: "unassigned"' not in summary and "unassignedCombos" not in summary # 198-1 locale = (ROOT / "ui_template/ui_template_locale_b4.ts").read_text(encoding="utf-8") - assert 'B08_Quantity_Summary_Unassigned: ["미지정", "Unassigned"]' in locale + assert "B08_Quantity_Summary_Unassigned" not in locale diff --git a/resources/tester/test_198_1_b08_summary_lamp.py b/resources/tester/test_198_1_b08_summary_lamp.py new file mode 100644 index 000000000..184e9396d --- /dev/null +++ b/resources/tester/test_198_1_b08_summary_lamp.py @@ -0,0 +1,114 @@ +"""198-1 B08 구조물 집계표 — 미연결 = 측점 칸 왼쪽 램프 하나 · 「미지정」 열 지움. + +- 칸 class: 화면 소스의 `cellClass` 를 떼어 공용 표 `renderDataTableHtml` 로 그림(Node) — 미연결 줄 측점 칸만 램프 +- 호버 글: 화면 소스의 호버 함수를 떼어 가짜 칸으로 부름 — 「구조물 조합 미연결 — 빈 칸 이름」 · 연결 줄은 없음 +- CSS: 램프 = 경고 노랑 토큰(177-1) · 밝음 · 어두움 둘 다 +- 줄 값 = 측점 + 서버 값뿐(「미지정」 · 「· 미연결」 글 없음 → 수량 · 합계 그대로) +""" + +import json +import re +import subprocess +from pathlib import Path + +ROOT = Path(__file__).resolve().parents[2] +TS = ROOT / "config" / "node_modules" / "typescript" +UI = (ROOT / "B08_Quantity" / "B08_Quantity_UI_Summary.ts").read_text(encoding="utf-8") + +PRELUDE = f""" +const fs = require("fs"); +const ts = require({json.dumps(str(TS))}); +const js = (code) => ts.transpileModule(code, {{ + compilerOptions: {{ module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 }}, +}}).outputText; +""" + + +def _node(script: str): + out = subprocess.run( + ["node", "-e", script], capture_output=True, text=True, encoding="utf-8", timeout=60 + ) + assert out.returncode == 0, out.stderr + return json.loads(out.stdout) + + +def _lamp_class() -> str: + m = re.search(r'const LAMP_CLASS = "([^"]+)";', UI) + assert m + return m.group(1) + + +def test_미연결_줄_측점_칸만_램프(): + cell = re.search(r"cellClass: (\(i, key\) => .*?),\n", UI) + assert cell + table = json.dumps(str(ROOT / "ui_template" / "ui_template_data_table.ts")) + got = _node( + PRELUDE + + f""" +const box = {{ exports: {{}} }}; +new Function("exports", "module", "require", js(fs.readFileSync({table}, "utf8")))( + box.exports, box, (p) => (p.endsWith(".css") ? {{}} : require(p))); +const LAMP_CLASS = {json.dumps(_lamp_class())}; +const missing = ["", "BOX", ""]; +const cellClass = {cell.group(1)}; +const html = box.exports.renderDataTableHtml({{ + columns: [{{ key: "station", label: "측점" }}, {{ key: "c1", label: "조합" }}], + rows: [{{ station: "0+000" }}, {{ station: "0+020" }}, {{ station: "0+040", c1: 1 }}], + frozen: 1, empty: "", cellClass }}); +const rows = html.split("")[1].split(""); +console.log(JSON.stringify({{ + count: html.split(LAMP_CLASS).length - 1, + row1: rows[1], + row0: rows[0], +}})); +""" + ) + assert got["count"] == 1 + assert f' \{.*?\n\s*\}),\n", UI, re.S + ) + assert hover + got = _node( + PRELUDE + + f""" +const L = (k) => ({{ B08_Quantity_Summary_LampTip: "구조물 조합 미연결" }})[k]; +const missing = ["", "배관: 본체 · 관 / 세월교: 유출 구조"]; +const text = eval(js("(" + {json.dumps(hover.group(1))} + ")")); +const cell = (i) => ({{ closest: () => ({{ dataset: {{ i: String(i) }} }}) }}); +console.log(JSON.stringify([text(cell(1)), text(cell(0)) || null])); +""" + ) + assert got == ["구조물 조합 미연결 — 배관: 본체 · 관 / 세월교: 유출 구조", None] + assert 'import { attachHoverInfo } from "@ui/ui_template_hover_info";' in UI + assert "`td.${LAMP_CLASS}`," in UI # 램프 칸에만 + locale = (ROOT / "ui_template" / "ui_template_locale_b4.ts").read_text(encoding="utf-8") + assert 'B08_Quantity_Summary_LampTip: ["구조물 조합 미연결",' in locale + + +def test_미지정_열_없음_줄_값_그대로(): + assert 'key: "unassigned"' not in UI and "B08_Quantity_Summary_Unassigned" not in UI + assert 'L("B08_Quantity_Summary_Unlinked")' not in UI # 측점 「· 미연결」 글 지움 + assert "frozen: 1," in UI + rows = re.search(r"rows: stations\.map\(\(station, i\) => \(\{(.*?)\}\)\),", UI, re.S) + assert rows and [s.strip() for s in rows.group(1).strip().split("\n")] == [ + "station: labels[i],", + "...values.get(stationKey(station)),", + ] + + +def test_램프_경고_노랑_토큰(): + css = (ROOT / "B08_Quantity" / "B08_Quantity_UI_Page.css").read_text(encoding="utf-8") + m = re.search( + r'\[data-b08-summary="table"\] td\.' + re.escape(_lamp_class()) + r"::before\s*\{([^}]*)\}", + css, + ) + assert m + assert re.search(r"background:\s*var\(--color-warning\)", m.group(1)) + assert "border-radius: 50%" in m.group(1) + theme = (ROOT / "ui_template" / "ui_template_theme.css").read_text(encoding="utf-8") + assert len(re.findall(r"--color-warning:\s*#", theme)) >= 2 # 밝음 · 어두움 diff --git a/resources/tester/test_61_1_b08_summary_table.py b/resources/tester/test_61_1_b08_summary_table.py index 8922b2a81..c7454065a 100644 --- a/resources/tester/test_61_1_b08_summary_table.py +++ b/resources/tester/test_61_1_b08_summary_table.py @@ -96,5 +96,5 @@ def test_집계표는_공용_표(): # PLAN 70-2 — 공용 많은 자료 표 · 측점 열 고정 · 칸은 빈칸(「—」 아님) ui = (ROOT / "B08_Quantity" / "B08_Quantity_UI_Summary.ts").read_text(encoding="utf-8") assert "createDataTable(" in ui and "@ui/ui_template_data_table" in ui - assert "frozen: hasMissing ? 2 : 1" in ui and 'empty: ""' in ui and "onRowClick" in ui + assert "frozen: 1," in ui and 'empty: ""' in ui and "onRowClick" in ui assert 'document.createElement("table")' not in ui diff --git a/ui_template/ui_template_locale_b4.ts b/ui_template/ui_template_locale_b4.ts index bc300a4ee..4dd32bf14 100644 --- a/ui_template/ui_template_locale_b4.ts +++ b/ui_template/ui_template_locale_b4.ts @@ -63,7 +63,7 @@ export const ui_locales_b4 = { ], B08_Quantity_Summary_Total: ["계", "Total"], B08_Quantity_Summary_Unlinked: ["미연결", "Unlinked"], - B08_Quantity_Summary_Unassigned: ["미지정", "Unassigned"], + B08_Quantity_Summary_LampTip: ["구조물 조합 미연결", "Structure combination unlinked"], B08_Quantity_Link_Title: ["조합 연결", "Link combinations"], B08_Quantity_Link_Body: ["본체", "Body"], B08_Quantity_Link_Linked: ["연결됨", "Linked"],