- 개요 = 숫자 카드 넷 + CPU · 메모리 · 디스크 게이지(70 % 주황 · 90 % 빨강) + 7 일 SVG 그래프 - 회사 = 목록(찾기 · ⋯) → 상세(정보 · 사람 · 프로젝트 탭) · 사용자 = 회사 · 역할 · 찾기 거르기 · ⋯ - 설계 기본값 = 설정 카드를 묶음 제목 + 줄로 · 시스템 로그 = 동작 · 기간 · 찾기 거르기 + 이전 기록 더 보기 - 내 정보 = Linear 꼴 설정 줄(기본정보 · 비밀번호 · 테마 · 내 설계 기본값) - 옛 구역(리소스 패널 · 옛 내 정보 폼) 지움 · 지킴 시험 test_549 추가 · test_546 stub 맞춤 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
254 lines
8.8 KiB
TypeScript
254 lines
8.8 KiB
TypeScript
/* =============================================================================
|
|
* B01_Dashboard_UI_Legacy.ts
|
|
* 옛 한 페이지 대시보드의 구역 부품을 세부 페이지에 그대로 얹음(546-1) — 기능 빠짐 0.
|
|
* 새 모양 페이지가 등록부(`B01_Dashboard_UI_Views.ts`) 줄을 갈아 끼우면 여기 그 구역은 지움.
|
|
* 자료 = 열 때마다 역할별로 다시 읽음(옛 화면이 주소 바뀔 때마다 다시 읽던 것과 같음).
|
|
* ========================================================================== */
|
|
|
|
import { navigateTo } from "../A00_Common/router";
|
|
import { settingLinks } from "../A00_Common/m_settings_nav";
|
|
import { createButton, hideLoadingOverlay, showLoadingOverlay } from "@ui/ui_template_elements";
|
|
import { section } from "@ui/ui_template_general_blocks";
|
|
import {
|
|
fetchAllCompanies,
|
|
fetchAllUsers,
|
|
fetchAuditLogs,
|
|
fetchCompanyJoinRequests,
|
|
fetchCompanyMembers,
|
|
fetchCompanyProjects,
|
|
fetchSystemResources,
|
|
fetchUserCompany,
|
|
fetchUserProjects,
|
|
type AuditLog,
|
|
type CompanyInfo,
|
|
type DashboardUser,
|
|
type JoinRequest,
|
|
type Member,
|
|
type ProjectItem,
|
|
type ResourceData,
|
|
} from "./B01_Dashboard_Api_Fetch";
|
|
import { userTable } from "./B01_Dashboard_UI_Admin";
|
|
import {
|
|
assignedPlanTable,
|
|
fetchAssignedPlans,
|
|
type AssignedPlan,
|
|
} from "./B01_Dashboard_UI_AssignedPlans";
|
|
import { openCalcSitesDialog } from "./B01_Dashboard_UI_CalcSites";
|
|
import { L } from "./B01_Dashboard_UI_Common";
|
|
import {
|
|
buildCompanyPanel,
|
|
companyTable,
|
|
joinRequestTable,
|
|
memberTable,
|
|
} from "./B01_Dashboard_UI_Company";
|
|
import { openAddMemberModal } from "./B01_Dashboard_UI_Modals";
|
|
import { openNewProjectPicker } from "./B01_Dashboard_UI_NewProject";
|
|
import { projectTable } from "./B01_Dashboard_UI_Projects";
|
|
import { buildTempUploadSection } from "./B01_Dashboard_UI_TempUpload";
|
|
|
|
export interface DashboardState {
|
|
user: DashboardUser;
|
|
userProjects: ProjectItem[];
|
|
companyProjects: ProjectItem[];
|
|
allProjects: ProjectItem[];
|
|
company: CompanyInfo | null;
|
|
members: Member[];
|
|
joinRequests: JoinRequest[];
|
|
allCompanies: CompanyInfo[];
|
|
allUsers: DashboardUser[];
|
|
allJoinRequests: JoinRequest[];
|
|
auditLogs: AuditLog[];
|
|
resources: ResourceData | null;
|
|
/** 우리 회사에 지정된 예정노선(528-2) — 회사관리자 · 사용자만 */
|
|
assignedPlans: AssignedPlan[];
|
|
/** 시스템 관리자가 고른 회사(29-1) — 프로젝트 · 사용자 · 가입 요청 · 회사 관리가 이 회사 것 */
|
|
adminCompanyId: number | null;
|
|
}
|
|
|
|
/** 고른 회사 id 자리 — M02 도 같은 키를 읽음(이름 바꾸지 않음) */
|
|
export const ADMIN_COMPANY_KEY = "aislo.adminCompany";
|
|
|
|
/** 고른 회사 — 저장값이 없거나 없는 회사면 자기 회사 */
|
|
export function pickAdminCompany(user: DashboardUser, companies: CompanyInfo[]): number | null {
|
|
const saved = Number(sessionStorage.getItem(ADMIN_COMPANY_KEY));
|
|
if (companies.some((c) => c.id === saved)) return saved;
|
|
return user.company_id ?? companies[0]?.id ?? null;
|
|
}
|
|
|
|
async function loadRoleData(state: DashboardState): Promise<void> {
|
|
if (state.user.role === "SYSTEM_ADMIN") {
|
|
// 회사 목록을 먼저 — 고른 회사를 가린 뒤 그 회사 것만 읽음(29-1)
|
|
state.allCompanies = await fetchAllCompanies().catch(() => []);
|
|
const companyId = pickAdminCompany(state.user, state.allCompanies);
|
|
state.adminCompanyId = companyId;
|
|
const results = await Promise.allSettled([
|
|
fetchAllUsers(companyId),
|
|
fetchCompanyJoinRequests(companyId),
|
|
fetchAuditLogs(),
|
|
fetchSystemResources(7),
|
|
fetchCompanyProjects(companyId),
|
|
]);
|
|
state.allUsers = results[0].status === "fulfilled" ? results[0].value : [];
|
|
state.allJoinRequests = results[1].status === "fulfilled" ? results[1].value : [];
|
|
state.auditLogs = results[2].status === "fulfilled" ? results[2].value : [];
|
|
state.resources = results[3].status === "fulfilled" ? results[3].value : null;
|
|
state.allProjects = results[4].status === "fulfilled" ? results[4].value : [];
|
|
|
|
results.forEach((res, idx) => {
|
|
if (res.status === "rejected") {
|
|
console.error(`System Admin API failed at index ${idx}:`, res.reason);
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
const [projects, company, assigned] = await Promise.all([
|
|
fetchUserProjects().catch(() => []),
|
|
fetchUserCompany().catch(() => null),
|
|
fetchAssignedPlans().catch(() => []),
|
|
]);
|
|
state.userProjects = projects;
|
|
state.company = company;
|
|
state.assignedPlans = assigned;
|
|
if (state.user.role === "ADMIN") {
|
|
const [members, requests, companyProjects] = await Promise.all([
|
|
fetchCompanyMembers().catch(() => []),
|
|
fetchCompanyJoinRequests().catch(() => []),
|
|
fetchCompanyProjects().catch(() => []),
|
|
]);
|
|
state.members = members;
|
|
state.joinRequests = requests;
|
|
state.companyProjects = companyProjects;
|
|
}
|
|
}
|
|
|
|
/** 설정 카드 공용 양식 — 제목 + 한 줄 설명 · 누르면 이동 */
|
|
function settingCard(title: string, desc: string, go: () => void): HTMLElement {
|
|
const card = document.createElement("button");
|
|
card.type = "button";
|
|
card.className = "b01-dashboard__setting-card";
|
|
const head = document.createElement("strong");
|
|
head.className = "b01-dashboard__setting-title";
|
|
head.textContent = title;
|
|
const sub = document.createElement("span");
|
|
sub.className = "b01-dashboard__setting-desc";
|
|
sub.textContent = desc;
|
|
card.append(head, sub);
|
|
card.addEventListener("click", go);
|
|
return card;
|
|
}
|
|
|
|
/** 설계 기본값 카드 — 카드 규칙은 `settingLinks` 한 벌(334) · 계산 자리 = 창(504-2) */
|
|
function buildSystemSettingsPanel(user: DashboardUser, companyId: number | null): HTMLElement {
|
|
const wrap = document.createElement("div");
|
|
wrap.className = "b01-dashboard__setting-grid";
|
|
wrap.append(
|
|
...settingLinks(user, companyId).map((link) =>
|
|
settingCard(link.title, link.desc, () =>
|
|
link.key === "calcSites" ? void openCalcSitesDialog() : navigateTo(link.route, link.query),
|
|
),
|
|
),
|
|
);
|
|
return wrap;
|
|
}
|
|
|
|
const addButton = (onClick: () => void): HTMLElement[] => [createButton({ label: "+", onClick })];
|
|
|
|
/** 열쇠별 옛 구역 — 역할 갈래는 옛 `buildPage` 그대로 */
|
|
const SECTIONS: Record<string, (s: DashboardState) => HTMLElement[]> = {
|
|
projects: (s) => {
|
|
const list =
|
|
s.user.role === "SYSTEM_ADMIN"
|
|
? s.allProjects
|
|
: s.user.role === "ADMIN"
|
|
? s.companyProjects
|
|
: s.userProjects;
|
|
return [
|
|
section(
|
|
L("B01_Dashboard_Projects"),
|
|
projectTable(list, s.user),
|
|
true,
|
|
addButton(() => void openNewProjectPicker()),
|
|
),
|
|
];
|
|
},
|
|
assigned: (s) => [section(L("DE_Assigned_Title"), assignedPlanTable(s.assignedPlans), true)],
|
|
temp: () => [buildTempUploadSection()],
|
|
people: (s) =>
|
|
s.user.role === "SYSTEM_ADMIN"
|
|
? [
|
|
section(
|
|
L("B01_Dashboard_Users"),
|
|
userTable(s.allUsers, s.user),
|
|
true,
|
|
addButton(() => openAddMemberModal(undefined, s.adminCompanyId)),
|
|
),
|
|
section(L("B01_Dashboard_JoinRequests"), joinRequestTable(s.allJoinRequests, true), true),
|
|
]
|
|
: [
|
|
section(
|
|
L("B01_Dashboard_Members"),
|
|
memberTable(s.members, s.user),
|
|
true,
|
|
addButton(() => openAddMemberModal()),
|
|
),
|
|
section(L("B01_Dashboard_JoinRequests"), joinRequestTable(s.joinRequests, false), true),
|
|
],
|
|
company: (s) =>
|
|
s.user.role === "SYSTEM_ADMIN"
|
|
? [
|
|
section(
|
|
L("B01_Dashboard_Companies"),
|
|
companyTable(
|
|
s.allCompanies.filter((c) => c.id === s.adminCompanyId),
|
|
s.user,
|
|
),
|
|
true,
|
|
),
|
|
]
|
|
: [section(L("B01_Dashboard_Company"), buildCompanyPanel(s), true)],
|
|
companyDefaults: (s) => [
|
|
section(
|
|
L("B01_Dashboard_SystemSettings"),
|
|
buildSystemSettingsPanel(s.user, s.adminCompanyId),
|
|
true,
|
|
),
|
|
],
|
|
};
|
|
|
|
export type LegacyKey = keyof typeof SECTIONS;
|
|
|
|
/** 옛 구역을 host 에 얹음 — 자료를 다 읽은 뒤 그림 · 그 사이 떠났으면(host 떨어짐) 안 그림 */
|
|
export async function mountLegacy(
|
|
key: LegacyKey,
|
|
host: HTMLElement,
|
|
me: DashboardUser,
|
|
): Promise<void> {
|
|
const state: DashboardState = {
|
|
user: me,
|
|
userProjects: [],
|
|
companyProjects: [],
|
|
allProjects: [],
|
|
company: null,
|
|
members: [],
|
|
joinRequests: [],
|
|
allCompanies: [],
|
|
allUsers: [],
|
|
allJoinRequests: [],
|
|
auditLogs: [],
|
|
resources: null,
|
|
assignedPlans: [],
|
|
adminCompanyId: null,
|
|
};
|
|
showLoadingOverlay();
|
|
try {
|
|
await loadRoleData(state);
|
|
} finally {
|
|
hideLoadingOverlay();
|
|
}
|
|
if (!host.isConnected) return;
|
|
const grid = document.createElement("div");
|
|
grid.className = "b01-dashboard__grid";
|
|
grid.append(...SECTIONS[key](state));
|
|
host.append(grid);
|
|
}
|