Files
Aislo/A00_Common/m_settings_nav.ts
T
eomsangdonandClaude Opus 5.5 f96907fb8a fix(772-1): ☰ 서랍 진행 단계 · 바로가기 칸 빠짐 — 진행 판 공용 자리에서 맡김 · 안 맡긴 쪽 기본 목록
- 까닭: B03 파일입력 = 진행 판을 직접 조립(createWorkflowOverlays)해 서랍 맡김(setDrawerSteps)이 빠짐 ·
  B02 · B10 · B11 · D01 · E01 = 일반 판이라 맡기는 쪽이 없음 · B01 = 10-26 새 틀(e505f4014)에서 옛 ☰ 구역 바로가기를 걷음
- 진행 판(createWorkflowOverlays)이 progressContent 를 받으면 서랍에 맡김 — 워크플로 판 · B03 한 자리
- ☰ 를 열 때 맡긴 목록이 없으면 기본 목록 = 🏠 대시보드 + 권한별 M01 · M02(mountSettingsDrawer 와 같은 한 벌) · 늦게 온 쪽 목록이 이김
- 터치 켬 서랍 진행 단계 줄 40 → 44(옆 규칙이 더 세어 덮던 것)
- 시험: helper_280_2 의 app_shell 대역은 workflow_layout 이 더는 안 불러 지움 · helper_359_2 에 overlay 용 대역 더함 · test_772_1 새로

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 20:05:47 +09:00

151 lines
6.2 KiB
TypeScript

/* =============================================================================
* m_settings_nav.ts
* 시스템 설정 바로가기(334 · 요구 225-2 · 716-2) — 대시보드 설계 기본값 줄(`settingLinks` · 칸마다 한 줄 ·
* `?open=`) / M01 · M02 ☰ 메뉴(`pageLinks` · 페이지 둘 · `mountSettingsDrawer`) /
* 진행 판 없는 쪽 ☰ 기본 목록(`defaultSettingsBar` · 772-1).
* ========================================================================== */
import { ROUTES, type RoutePath } from "@config/config_frontend";
import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale";
import { createStepBar } from "@ui/ui_template_workflow_layout";
import { setDrawerSteps } from "./app_shell";
import { currentRoute, navigateTo, takeLeaveGuard } from "./router";
interface SettingUser {
role?: string;
is_master?: boolean;
company_id?: number | null;
}
/** key = 페이지 열쇠(☰ · 「m01」 「m02」) 또는 칸 열쇠(대시보드 줄 · 계산 자리 「calcSites」 = 창 504-2) ·
* group = 대시보드 설계 기본값 묶음 제목 */
export interface SettingLink {
key: string;
title: string;
desc: string;
route: RoutePath;
query?: Record<string, string>;
group?: string;
}
function L(key: keyof typeof ui_locales): string {
return ui_locales[key][currentLanguageIndex];
}
const ICONS: Record<string, string> = { m01: "🗄️", m02: "🧱" };
/** 설계 기본값 줄(대시보드) — 칸마다 한 줄 · 역할로 숨김 · M01 줄 `?open=`(칸 고름) · M02 줄 `?open=&root=`(27-1d).
* 칸을 더할 때는 아래 표에 한 줄(m01 / m02 호출)만 더함. */
export function settingLinks(user: SettingUser, companyId: number | string | null): SettingLink[] {
// 시스템 관리자는 고른 회사를 해시에 실음(29-1)
const company: Record<string, string> =
user.role === "SYSTEM_ADMIN" && companyId ? { company: String(companyId) } : {};
const m01 = (key: string, title: string, desc: string, open?: string): SettingLink => ({
key,
title,
desc,
route: ROUTES.M01_MASTER_DATA,
query: open ? { open } : undefined,
group: "마스터 데이터",
});
const m02 = (title: string, open: string, root: string, desc: string): SettingLink => ({
key: open,
title,
desc,
route: ROUTES.M02_MASTER_TEMPLATE,
query: { open, root, ...company },
group: "마스터 템플릿",
});
// 구조물 조합 기본 층 = 개인(123-1 · 누구든) · 개인 층 없음(회사 없음) = 아래 역할 규칙
const comboRoot = (fallback: string): string => (user.company_id ? "personal" : fallback);
if (user.role === "SYSTEM_ADMIN") {
const desc = L("B01_Dashboard_PermMasterWrite");
const read = L("B01_Dashboard_PermSourceRead");
return [
m01("m01", L("M01_Title"), read),
m01("로직", L("B01_Dashboard_CardLogic"), read, "로직"),
m01("옵션", L("B01_Dashboard_CardStructOptionDef"), desc, "옵션"),
m01("별칭", L("B01_Dashboard_CardAliasLedger"), desc, "별칭"),
m02(L("B01_Dashboard_CardSangeun"), "단가산출", comboRoot("master"), desc),
m02(L("B01_Dashboard_CardPrecombo"), "일위대가조합", comboRoot("master"), desc),
m02(L("B01_Dashboard_CardStructCombo"), "구조물조합", comboRoot("master"), desc),
m02(L("B01_Dashboard_CardDrawing"), "도면", "master", desc),
{
key: "calcSites",
title: L("B01_CalcSites_Title"),
desc: L("B01_CalcSites_Desc"),
route: ROUTES.B01_ACCOUNT,
group: "계산",
},
];
}
// 회사 수정 = 회사 관리자 · 회사 마스터(M02 accessFor 와 같은 규칙)
const companyAdmin = user.role === "ADMIN" || user.is_master;
const root = companyAdmin ? "company" : "personal";
const desc = [
L("B01_Dashboard_PermMasterRead"),
L(companyAdmin ? "B01_Dashboard_PermCompanyWrite" : "B01_Dashboard_PermCompanyRead"),
L("B01_Dashboard_PermPersonalWrite"),
].join(" · ");
return [m02(L("B01_Dashboard_CardStructCombo"), "구조물조합", comboRoot(root), desc)];
}
/** ☰ 메뉴 — 페이지 둘만(M01 = 시스템 관리자 · M02 = 누구나) · 열쇠 「m01」 「m02」 */
export function pageLinks(user: SettingUser, companyId: number | string | null): SettingLink[] {
const combo = settingLinks(user, companyId).find((link) => link.key === "구조물조합");
const links: SettingLink[] = [];
if (user.role === "SYSTEM_ADMIN")
links.push({
key: "m01",
title: L("B01_Dashboard_MasterElements"),
desc: "",
route: ROUTES.M01_MASTER_DATA,
});
if (combo)
links.push({ ...combo, key: "m02", title: L("M02_Title"), desc: "", group: undefined });
return links;
}
/** ☰ 진행 단계 자리 — 🏠 대시보드 + 페이지 둘 · 지금 페이지 강조(`activeKey` = 「m01」 「m02」) ·
* 같은 길(M02 → M02)은 머리 가드가 안 물어 여기서 먼저 */
export function mountSettingsDrawer(
user: SettingUser,
activeKey: string,
companyId: number | string | null,
): void {
setDrawerSteps(settingsBar(user, activeKey, companyId));
}
/** ☰ 기본 목록(772-1) — 진행 판 · 바로가기를 안 세운 로그인 뒤 쪽(B02 · D01 · E01 등) = 🏠 대시보드 + 권한별 페이지 둘 ·
* 로그인 전 = 없음 */
export async function defaultSettingsBar(): Promise<HTMLElement | null> {
const { fetchSessionUser } = await import("../A06_Login/A06_Login_Api_Fetch");
const user = await fetchSessionUser().catch(() => null);
return user ? settingsBar(user, "", null) : null;
}
function settingsBar(
user: SettingUser,
activeKey: string,
companyId: number | string | null,
): HTMLElement {
const links = pageLinks(user, companyId);
return createStepBar(
links.map((link) => link.title),
links.findIndex((link) => link.key === activeKey),
{
orientation: "vertical",
icons: links.map((link) => ICONS[link.key] ?? ""),
routes: links.map((link) => link.route),
homeButton: true,
onStepClick: (index) => void go(links[index]),
},
);
}
async function go(link: SettingLink): Promise<void> {
const guard = link.route === currentRoute() ? takeLeaveGuard() : null;
if (guard && !(await guard())) return;
navigateTo(link.route, link.query);
}