/* ============================================================================= * 「시스템」 탭(92장 · 시스템 관리자만) — 리소스(7 · 30 · 90일) · 활성 추이 · 전체 회사 · * 전체 사용자 · 시스템 로그(쪽 넘김) · 고객 문의. 모두 이미 있는 API. * ========================================================================== */ import { createButton, createTag, showToast, type TagVariant } from "@ui/ui_template_elements"; import { section, text } from "@ui/ui_template_general_blocks"; import { fetchAuditLogPage, fetchSystemResources, type AuditLog, type ResourceData, type SupportRequest, } from "./B01_Dashboard_Api_Fetch"; import { allUserTable, auditLogTable } from "./B01_Dashboard_UI_Admin"; import { companyTable } from "./B01_Dashboard_UI_Company"; import { formatDate, formatTime, L, stackedCell } from "./B01_Dashboard_UI_Common"; import type { DashboardState } from "./B01_Dashboard_UI_Page"; import { buildPager, createPagedTable } from "./B01_Dashboard_UI_Paging"; import { buildActivityChart, buildResourcePanel } from "./B01_Dashboard_UI_Resources"; /** 리소스 기간(일) — 백엔드 최대 90 */ export const RESOURCE_DAYS = [7, 30, 90] as const; /** 시스템 로그 한 쪽 줄 수 */ export const AUDIT_PAGE_SIZE = 20; const INQUIRY_TAG: Record = { NEW: "warning", REVIEWED: "accent", RESOLVED: "success", DELETED: "neutral", }; /** 기간 고르기 + 리소스 현황 + 활성 추이 — 기간을 바꾸면 이 두 컨테이너만 새로 받음 */ function buildResourceSections(initial: ResourceData | null): HTMLElement[] { const bar = document.createElement("div"); bar.className = "b01-dashboard__period"; const panelHost = document.createElement("div"); const trendHost = document.createElement("div"); let days: number = RESOURCE_DAYS[0]; let latest = 0; const draw = (data: ResourceData | null): void => { panelHost.replaceChildren(buildResourcePanel(data, days)); trendHost.replaceChildren(buildActivityChart(data, days)); }; const drawBar = (): void => { bar.replaceChildren( ...RESOURCE_DAYS.map((value) => { const button = createButton({ label: L("B01_Sy_Days").replace("{days}", String(value)), variant: value === days ? "filled" : "ghost", onClick: () => void pick(value), }); button.setAttribute("aria-pressed", String(value === days)); button.dataset.b01Days = String(value); return button; }), ); }; const pick = async (value: number): Promise => { if (value === days) return; days = value; drawBar(); const mine = ++latest; try { const data = await fetchSystemResources(value); if (mine === latest) draw(data); } catch (error) { if (mine === latest) showToast(error instanceof Error ? error.message : "", "error"); } }; drawBar(); draw(initial); const resource = section(L("B01_Dashboard_Resources"), panelHost, true); resource.querySelector(".ui-card__body")?.prepend(bar); return [resource, section(L("B01_Sy_ActiveTrend"), trendHost, true)]; } /** 시스템 로그 — 서버가 쪽으로 나눠 줌(전체 건수 포함) */ function buildAuditSection(first: { total: number; items: AuditLog[] }): HTMLElement { const host = document.createElement("div"); const draw = (page: number, data: { total: number; items: AuditLog[] }): void => { const pages = Math.max(1, Math.ceil(data.total / AUDIT_PAGE_SIZE)); host.replaceChildren( auditLogTable(data.items), buildPager(page, pages, data.total, (next) => { fetchAuditLogPage(next, AUDIT_PAGE_SIZE) .then((result) => draw(next, result)) .catch((error) => showToast(error instanceof Error ? error.message : "", "error")); }), ); }; draw(1, first); return section(L("B01_Dashboard_AuditLogs"), host, true); } function inquiryTable(requests: SupportRequest[]): HTMLElement { return createPagedTable( [ L("B01_Sy_Received"), L("B01_Sy_Sender"), L("B01_Dashboard_Table_Company"), L("B01_Sy_Subject"), L("B01_Pj_Message"), L("B01_Dashboard_Table_Status"), ], (request: SupportRequest) => { const message = document.createElement("span"); message.className = "b01-dashboard__ellipsis"; message.textContent = request.message; message.title = request.message; return [ stackedCell(formatDate(request.created_at), formatTime(request.created_at)), text([request.user_name, request.user_email].filter(Boolean).join(" · ")), text(request.company_name), text(request.subject), message, createTag(L(`B01_Sy_Inquiry_${request.status}`), INQUIRY_TAG[request.status]), ]; }, requests, ).root; } export function buildSystemTab(state: DashboardState): HTMLElement[] { return [ ...buildResourceSections(state.resources), section(L("B01_Sy_AllCompanies"), companyTable(state.allCompanies, state.user), true), section(L("B01_Sy_AllUsers"), allUserTable(state.systemUsers), true), buildAuditSection({ total: state.auditTotal, items: state.auditLogs }), section(L("B01_Sy_Inquiries"), inquiryTable(state.supportRequests), true), ]; }