Merge remote-tracking branch 'origin/sub_laptop_3' into sub_laptop_1
This commit is contained in:
@@ -24,7 +24,7 @@ import type { PipeFacility } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
|
||||
import { type FacilityAttributes } from "./B05_Profile_UI_Drainage_Facility";
|
||||
import { field } from "./B05_Profile_UI_Structures_Fields";
|
||||
import { renderOptionFields as renderOptionFieldsInto } from "./B05_Profile_UI_Structures_Panel_Options";
|
||||
import { openItemPicker } from "./B05_Profile_UI_Structures_Summary_Picker";
|
||||
import { openItemPicker } from "@ui/ui_template_item_picker";
|
||||
import { buildStructuresForm } from "./B05_Profile_UI_Structures_Form";
|
||||
import {
|
||||
bindStructuresEvents,
|
||||
@@ -474,9 +474,10 @@ export function createStructuresSection(
|
||||
// (새 항목은 종전대로 [추가]가 확정). 안 고른 채 닫으면 그대로.
|
||||
summary.bind({
|
||||
pick: () => {
|
||||
void openItemPicker({ current: summary.get() }).then((result) => {
|
||||
if (!result) return;
|
||||
summary.set("item" in result ? result.item : null);
|
||||
// canCopy — 개인 층에 쓸 수 없는 사용자의 복사는 서버가 막은 까닭을 모달이 그대로 보임
|
||||
void openItemPicker({ current: summary.get(), canCopy: true }).then((result) => {
|
||||
if (result.action === "cancel") return;
|
||||
summary.set(result.action === "apply" ? result.item : null);
|
||||
liveCommit();
|
||||
});
|
||||
},
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
/* =============================================================================
|
||||
* B05_Profile_UI_Structures_Summary_Picker.ts
|
||||
* ⚠ **임시(가짜) 항목 고르기 모달** — 21-5(sub1) `ui_template/ui_template_item_picker.ts` 의
|
||||
* `openItemPicker()` 가 오면 이 파일을 지우고 `Summary_Row` 를 쓰는 패널의 import 한 줄만 바꾼다.
|
||||
*
|
||||
* 이름 · 돌려주는 값은 21-5 와 맞춘 자리다:
|
||||
* openItemPicker({ current }) → Promise<{ item } | { clear: true } | null>
|
||||
* (item = 21-1 `summary_item` · clear = [해제] · null = 닫음)
|
||||
* 목록은 `GET /api/m02/items?all=1`(21-2) 을 읽고, 아직 없으면(404 등) 같은 21-1 모양의 가짜 세 줄.
|
||||
* ========================================================================== */
|
||||
|
||||
import { API_BASE_URL } from "@config/config_frontend";
|
||||
import { createButton, el } from "@ui/ui_template_elements";
|
||||
import { openModal } from "@ui/ui_template_modal";
|
||||
import {
|
||||
sameSummaryItem,
|
||||
summaryLabel,
|
||||
type SummaryItem,
|
||||
type SummaryLayer,
|
||||
} from "../common_util/common_util_summary_item";
|
||||
|
||||
export type ItemPickResult = { item: SummaryItem } | { clear: true } | null;
|
||||
|
||||
interface ItemRow {
|
||||
key: string;
|
||||
이름?: string;
|
||||
종류?: string;
|
||||
분류1?: string;
|
||||
layer?: SummaryLayer;
|
||||
owner?: string | null;
|
||||
}
|
||||
|
||||
/** 21-2 서버가 없을 때의 가짜 응답 — 21-1 모양. */
|
||||
const FAKE_ITEMS: SummaryItem[] = [
|
||||
{ layer: "system", owner: null, key: "SS000001", name: "돌기슭막이 메쌓기(가짜)" },
|
||||
{ layer: "company", owner: "가짜회사", key: "SS000002", name: "옹벽 콘크리트(가짜)" },
|
||||
{ layer: "personal", owner: "가짜회사/가짜사용자", key: "SS000003", name: "돌쌓기 찰쌓기(가짜)" },
|
||||
];
|
||||
|
||||
async function loadItems(): Promise<SummaryItem[]> {
|
||||
try {
|
||||
const response = await fetch(`${API_BASE_URL}/m02/items?all=1`, { credentials: "include" });
|
||||
if (!response.ok) return FAKE_ITEMS;
|
||||
const rows = (await response.json()) as ItemRow[];
|
||||
if (!Array.isArray(rows) || !rows.length) return FAKE_ITEMS;
|
||||
return rows.map((row) => ({
|
||||
layer: row.layer ?? "system",
|
||||
owner: row.owner ?? null,
|
||||
key: row.key,
|
||||
name: row.분류1 ? `${row.종류 ?? ""} · ${row.분류1} · ${row.key}` : (row.종류 ?? row.key),
|
||||
}));
|
||||
} catch {
|
||||
return FAKE_ITEMS;
|
||||
}
|
||||
}
|
||||
|
||||
export function openItemPicker(options: { current: SummaryItem | null }): Promise<ItemPickResult> {
|
||||
return new Promise((resolve) => {
|
||||
let settled = false;
|
||||
const finish = (result: ItemPickResult, close?: () => void): void => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
close?.();
|
||||
resolve(result);
|
||||
};
|
||||
const modal = openModal({
|
||||
title: "집계 항목 고르기(임시)",
|
||||
closeLabel: "닫기",
|
||||
mount: (body, close) => {
|
||||
const list = el("div", { className: "b05-structure__pick-list" });
|
||||
const apply = createButton({ label: "적용", variant: "filled" });
|
||||
apply.disabled = true;
|
||||
let chosen: SummaryItem | null = null;
|
||||
void loadItems().then((items) => {
|
||||
items.forEach((item) => {
|
||||
const row = createButton({ label: summaryLabel(item), variant: "ghost" });
|
||||
row.dataset.b05PickItem = item.key;
|
||||
// 지금 지정된 항목은 미리 표시(눌러서 바로 [적용] 가능)
|
||||
if (sameSummaryItem(item, options.current)) {
|
||||
chosen = item;
|
||||
apply.disabled = false;
|
||||
row.classList.add("is-picked");
|
||||
}
|
||||
row.addEventListener("click", () => {
|
||||
chosen = item;
|
||||
apply.disabled = false;
|
||||
list
|
||||
.querySelectorAll(".is-picked")
|
||||
.forEach((node) => node.classList.remove("is-picked"));
|
||||
row.classList.add("is-picked");
|
||||
});
|
||||
list.append(row);
|
||||
});
|
||||
});
|
||||
apply.addEventListener("click", () => chosen && finish({ item: chosen }, close));
|
||||
const clear = createButton({ label: "해제", variant: "ghost" });
|
||||
clear.addEventListener("click", () => finish({ clear: true }, close));
|
||||
body.append(list, el("div", { children: [apply, clear] }));
|
||||
},
|
||||
beforeClose: () => {
|
||||
finish(null);
|
||||
return true;
|
||||
},
|
||||
});
|
||||
void modal;
|
||||
});
|
||||
}
|
||||
@@ -484,15 +484,3 @@
|
||||
.b05-route__irregular-item.is-assigned span {
|
||||
color: color-mix(in srgb, var(--color-success) 65%, var(--color-text));
|
||||
}
|
||||
|
||||
/* 임시 항목 고르기 모달(21-5 가 오면 사라짐) */
|
||||
.b05-structure__pick-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-4);
|
||||
margin-bottom: var(--spacing-8);
|
||||
}
|
||||
|
||||
.b05-structure__pick-list .is-picked {
|
||||
outline: 2px solid var(--color-success);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user