feat(M01): 요소 찾기에 기계 구분·상세구분 싣기 · 소요량/계수 로직키 눌러 로직 탭 연결
_brief 응답에 구분·상세구분 추가(테스트 컨테이너 기계 후보 거름용) 표 상세화면 용도의 로직키를 누르면 로직 탭으로 전환 + 키 클립보드 복사(찾기용) 로직 목록을 직접 열지는 못함(로직 부분은 sub1 담당) — _화면_계약.md 한 줄 추가
This commit is contained in:
@@ -343,7 +343,10 @@ def logic(key: str) -> dict:
|
||||
def _brief(ref: str, row: dict) -> dict:
|
||||
return {
|
||||
"ref": ref,
|
||||
**{k: row.get(k) for k in ("원문번호", "이름", "규격", "단위", "값", "값칸")},
|
||||
**{
|
||||
k: row.get(k)
|
||||
for k in ("원문번호", "구분", "상세구분", "이름", "규격", "단위", "값", "값칸")
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -23,7 +23,15 @@ import { fetchSessionUser } from "../A06_Login/A06_Login_Api_Fetch";
|
||||
import { saveFiles } from "./M01_MasterData_Api_Fetch";
|
||||
import { discard, isStale, onDraftChange, payload, totalCount } from "./M01_MasterData_Draft";
|
||||
import { renderRows } from "./M01_MasterData_UI_Rows";
|
||||
import { buildSide, fileLabel, loadView, saveView, type Pick } from "./M01_MasterData_UI_Side";
|
||||
import {
|
||||
buildSide,
|
||||
fileLabel,
|
||||
loadView,
|
||||
saveView,
|
||||
setPendingLogicKey,
|
||||
takePendingLogicKey,
|
||||
type Pick,
|
||||
} from "./M01_MasterData_UI_Side";
|
||||
import { renderTables } from "./M01_MasterData_UI_Tables";
|
||||
import "./M01_MasterData_UI_Style.css";
|
||||
|
||||
@@ -95,8 +103,9 @@ function buildPage(): HTMLElement {
|
||||
current = { ...pick, view: undefined };
|
||||
const groupTitle = pick.group === pick.label ? [pick.group] : [pick.group, pick.label];
|
||||
title.textContent = groupTitle.join(" · ");
|
||||
const view = TABLE_GROUPS.includes(pick.group) ? renderTables : renderRows;
|
||||
dispose = view(body, pick, query);
|
||||
dispose = TABLE_GROUPS.includes(pick.group)
|
||||
? renderTables(body, pick, query, openLogicTab)
|
||||
: renderRows(body, pick, query);
|
||||
showNotice(isStale(pick.file.file, pick.file.version) ? [L("M01_FileStale")] : []);
|
||||
};
|
||||
|
||||
@@ -165,18 +174,35 @@ function buildPage(): HTMLElement {
|
||||
return [L("M01_Stale").replace("{value}", stale.map(fileLabel).join(", ")), again];
|
||||
};
|
||||
|
||||
/** 로직 탭으로 전환 — `key` 가 있으면 들고 가서 로직 목록 찾기 칸에 넣으라고 안내
|
||||
* (로직 목록이 직접 그 키를 열지는 못함 — 로직 부분은 sub1 담당 파일). */
|
||||
const notifyLogicKey = (key: string): void => {
|
||||
navigator.clipboard?.writeText(key).catch(() => undefined);
|
||||
showToast(L("M01_LogicKeyCopy").replace("{value}", key), "success");
|
||||
};
|
||||
|
||||
const openLogicTab = (key?: string): void => {
|
||||
if (key) setPendingLogicKey(key);
|
||||
dispose();
|
||||
dispose = (): void => {};
|
||||
current = null;
|
||||
showMode("logic");
|
||||
if (logicMounted) {
|
||||
if (key) notifyLogicKey(key);
|
||||
return;
|
||||
}
|
||||
logicMounted = true;
|
||||
void import("./M01_MasterData_UI_Logic_Page").then((m) => {
|
||||
void m.mountM01Logic(logicHost, side);
|
||||
const pending = takePendingLogicKey();
|
||||
if (pending) notifyLogicKey(pending);
|
||||
});
|
||||
};
|
||||
|
||||
/* --- 좌측: 컨테이너 아홉 --- */
|
||||
const side = buildSide(
|
||||
openFile,
|
||||
() => {
|
||||
dispose();
|
||||
dispose = (): void => {};
|
||||
current = null;
|
||||
showMode("logic");
|
||||
if (logicMounted) return;
|
||||
logicMounted = true;
|
||||
void import("./M01_MasterData_UI_Logic_Page").then((m) => m.mountM01Logic(logicHost, side));
|
||||
},
|
||||
() => openLogicTab(),
|
||||
() => {
|
||||
dispose();
|
||||
dispose = (): void => {};
|
||||
|
||||
@@ -36,6 +36,27 @@ export function saveView(group: string, patch: Partial<View>): void {
|
||||
}
|
||||
}
|
||||
|
||||
const PENDING_LOGIC_KEY = "m01.logic.pending";
|
||||
|
||||
/** 소요량·계수 표의 「쓰는 로직」 키를 눌러 로직 탭으로 넘어갈 때 들고 갈 키 — 로직 목록 화면이 직접 열지는 못함(로직 부분은 sub1). */
|
||||
export function setPendingLogicKey(key: string): void {
|
||||
try {
|
||||
sessionStorage.setItem(PENDING_LOGIC_KEY, key);
|
||||
} catch {
|
||||
/* 기억 못 해도 로직 탭 전환은 됨 */
|
||||
}
|
||||
}
|
||||
|
||||
export function takePendingLogicKey(): string | null {
|
||||
try {
|
||||
const key = sessionStorage.getItem(PENDING_LOGIC_KEY);
|
||||
sessionStorage.removeItem(PENDING_LOGIC_KEY);
|
||||
return key;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/** 요소 화면에서 열 것 — 파일 · 하위 거름(구분·세부분류) · 상세구분 · 제목 */
|
||||
export interface Pick {
|
||||
group: string;
|
||||
|
||||
@@ -230,6 +230,16 @@
|
||||
color: var(--color-text-muted);
|
||||
}
|
||||
|
||||
.m01-master__logic-key {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
background: transparent;
|
||||
color: var(--color-accent);
|
||||
font: inherit;
|
||||
cursor: pointer;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
/* 조달 찾기 모달 */
|
||||
.m01-procure {
|
||||
position: fixed;
|
||||
|
||||
@@ -36,8 +36,13 @@ const LIST_COLS = ["키", "원문번호", "구분", "상세구분", "이름", "
|
||||
/** 용도 대상 거름 드롭다운 후보 — PLAN 1-1 셋째 줄 그대로. */
|
||||
const USAGE_TARGETS = ["인력", "기계", "재료", "할증", "환산", "작업량 조건"];
|
||||
|
||||
/** 돌려받은 함수 = 이 화면을 걷을 때 부를 해제. */
|
||||
export function renderTables(host: HTMLElement, pick: Pick, q: string): () => void {
|
||||
/** 돌려받은 함수 = 이 화면을 걷을 때 부를 해제. `openLogic` = 용도의 로직키 눌렀을 때 로직 탭으로. */
|
||||
export function renderTables(
|
||||
host: HTMLElement,
|
||||
pick: Pick,
|
||||
q: string,
|
||||
openLogic: (key: string) => void,
|
||||
): () => void {
|
||||
let stop = (): void => {};
|
||||
let usage = pick.view?.usage ?? "";
|
||||
const list = (page = pick.view?.page ?? 1): void => {
|
||||
@@ -50,7 +55,7 @@ export function renderTables(host: HTMLElement, pick: Pick, q: string): () => vo
|
||||
usage,
|
||||
page,
|
||||
(file, key) => {
|
||||
stop = openTable(host, file, key, () => list(page));
|
||||
stop = openTable(host, file, key, () => list(page), openLogic);
|
||||
},
|
||||
(next) => {
|
||||
usage = next;
|
||||
@@ -140,7 +145,13 @@ async function showList(
|
||||
}
|
||||
|
||||
/** 표 하나. 돌려받은 함수 = 해제. */
|
||||
function openTable(host: HTMLElement, file: string, key: string, back: () => void): () => void {
|
||||
function openTable(
|
||||
host: HTMLElement,
|
||||
file: string,
|
||||
key: string,
|
||||
back: () => void,
|
||||
openLogic: (key: string) => void,
|
||||
): () => void {
|
||||
let off = (): void => {};
|
||||
void (async () => {
|
||||
let version: string;
|
||||
@@ -209,6 +220,15 @@ function openTable(host: HTMLElement, file: string, key: string, back: () => voi
|
||||
el("p", { className: "m01-master__muted", text: n }),
|
||||
);
|
||||
const usage = table.용도 as TableUsage | undefined;
|
||||
const logicLinks = (usage?.로직키 ?? []).map((k, i) => {
|
||||
const btn = el("button", {
|
||||
className: "m01-master__logic-key",
|
||||
text: k,
|
||||
attrs: { type: "button", title: L("M01_OpenLogic") },
|
||||
});
|
||||
btn.addEventListener("click", () => openLogic(k));
|
||||
return i === 0 ? btn : el("span", { text: ", ", children: [btn] });
|
||||
});
|
||||
host.replaceChildren(
|
||||
el("div", {
|
||||
className: "m01-master__bar",
|
||||
@@ -223,10 +243,8 @@ function openTable(host: HTMLElement, file: string, key: string, back: () => voi
|
||||
? [
|
||||
el("span", {
|
||||
className: "m01-master__muted",
|
||||
attrs: { title: usage.로직키.join(", ") },
|
||||
text: `${L("M01_TableUsage")}: ${usage.공종} · ${usage.대상.join(", ")} · ${L(
|
||||
"M01_TableUsageLogicCount",
|
||||
).replace("{value}", String(usage.로직키.length))}`,
|
||||
text: `${L("M01_TableUsage")}: ${usage.공종} · ${usage.대상.join(", ")} · `,
|
||||
children: logicLinks,
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
|
||||
Reference in New Issue
Block a user