- 해시 ?tab= 탭 줄(B08 단추 꼴) · 고른 탭 자료만 받음 · 설정 카드는 탭 줄 위 · 회사 고르기 알약은 탭 줄 오른쪽 하나 - 회사 없음 진입 두 곳(router · M02 Layer)은 ?tab=company · 회사 관리자 프로젝트 목록 한 번만 받음 - 개요 숫자 카드(단계별 · 실패 · 재확인 · 가입 대기 · 보관함 · 리소스) · 프로젝트 표 칸 보강 · 찾기 · 거르기 · 쪽 넘김 · 진행 현황 - 회사 정보 칸(사업자번호 · 대표 · 상태) · 팀원 읽기 · 자산 표 · 내 계정 마지막 로그인 · 시스템 리소스 7·30·90일 · 활성 추이 · 전체 회사 · 사용자 · 로그 쪽 · 고객 문의 - 시험 test_b01_dashboard_tabs 신규 · test_b01_settings_cards 고침 Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MgChuAcyBqUkhHMTXomQC7
136 lines
4.5 KiB
TypeScript
136 lines
4.5 KiB
TypeScript
import { createButton } from "@ui/ui_template_elements";
|
|
import type { AuditLog, DashboardUser } from "./B01_Dashboard_Api_Fetch";
|
|
import { canChangeRole, canDeleteUser } from "./B01_Dashboard_UI_Helper";
|
|
import {
|
|
openChangeRoleModal,
|
|
openDeleteUserModal,
|
|
openEditUserModal,
|
|
} from "./B01_Dashboard_UI_Modals";
|
|
import { table, text } from "@ui/ui_template_general_blocks";
|
|
import { formatDate, formatTime, L, stackedCell } from "./B01_Dashboard_UI_Common";
|
|
import { createPagedTable } from "./B01_Dashboard_UI_Paging";
|
|
|
|
export function userTable(users: DashboardUser[], currentUser: DashboardUser): HTMLElement {
|
|
return createPagedTable(
|
|
[
|
|
L("B01_Dashboard_Table_Email"),
|
|
L("B01_Dashboard_Table_Name"),
|
|
L("B01_Dashboard_Table_Position"),
|
|
L("B01_Dashboard_Table_Department"),
|
|
L("B01_Account_Field_Phone"),
|
|
L("B01_Dashboard_Table_Role"),
|
|
L("B01_Dashboard_Table_Status"),
|
|
L("B01_Dashboard_Table_Action"),
|
|
],
|
|
(user: DashboardUser) => {
|
|
const actionsEl = document.createElement("div");
|
|
actionsEl.className = "b01-dashboard__actions";
|
|
|
|
actionsEl.append(
|
|
createButton({
|
|
label: L("Common_Btn_Edit"),
|
|
variant: "ghost",
|
|
onClick: () => openEditUserModal(currentUser, user),
|
|
}),
|
|
);
|
|
|
|
if (canChangeRole(currentUser, user)) {
|
|
actionsEl.append(
|
|
createButton({
|
|
label: L("B01_Dashboard_ChangeRole"),
|
|
variant: "ghost",
|
|
onClick: () => openChangeRoleModal(user),
|
|
}),
|
|
);
|
|
}
|
|
|
|
// 회사에서 빼기·계정 삭제 (2026-09-06 사용자 지시) — 범위는 백엔드가 다시 본다.
|
|
if (canDeleteUser(currentUser, user) && user.id !== currentUser.id) {
|
|
actionsEl.append(
|
|
createButton({
|
|
label: L("B01_Dashboard_DeleteUser"),
|
|
variant: "ghost",
|
|
onClick: () => openDeleteUserModal(user),
|
|
}),
|
|
);
|
|
}
|
|
|
|
return [
|
|
text(user.email),
|
|
text(user.name),
|
|
text(user.position),
|
|
text(user.department),
|
|
text(user.phone),
|
|
text(user.role),
|
|
text(user.status),
|
|
actionsEl,
|
|
];
|
|
},
|
|
users,
|
|
).root;
|
|
}
|
|
|
|
/** 전체 사용자(시스템 탭) — 소속 · 마지막 로그인까지 읽기만 · 관리는 회사 탭 */
|
|
export function allUserTable(users: DashboardUser[]): HTMLElement {
|
|
return createPagedTable(
|
|
[
|
|
L("B01_Dashboard_Table_Email"),
|
|
L("B01_Dashboard_Table_Name"),
|
|
L("B01_Sy_Affiliation"),
|
|
L("B01_Dashboard_Table_Role"),
|
|
L("B01_Dashboard_Table_Status"),
|
|
L("B01_Sy_LastLogin"),
|
|
],
|
|
(user: DashboardUser) => [
|
|
text(user.email),
|
|
text(user.name),
|
|
text(user.company_name),
|
|
text(user.role),
|
|
text(user.status),
|
|
stackedCell(formatDate(user.last_login), formatTime(user.last_login)),
|
|
],
|
|
users,
|
|
).root;
|
|
}
|
|
|
|
/** 무엇에 한 일인지 — 표에 저장된 대상 종류·번호를 사람이 읽는 말로. */
|
|
function auditTarget(log: AuditLog): string {
|
|
// 저장값은 소문자(`project`)로 들어온다 — 대문자로 맞춰 찾는다.
|
|
const key = (log.resource_type ?? "").toUpperCase();
|
|
const kind = TARGET_LABELS[key] ?? log.resource_type ?? "";
|
|
const reference = log.resource_ref ?? (log.resource_id ? String(log.resource_id) : "");
|
|
if (!kind) return reference || "-";
|
|
// 프로젝트 UUID 는 길어 앞 8자만 — 어느 프로젝트인지 가리기에는 충분하다.
|
|
const shortened = reference.length > 12 ? `${reference.slice(0, 8)}…` : reference;
|
|
return shortened ? `${kind} ${shortened}` : kind;
|
|
}
|
|
|
|
const TARGET_LABELS: Record<string, string> = {
|
|
PROJECT: "프로젝트",
|
|
COMPANY: "회사",
|
|
USER: "사용자",
|
|
ASSET: "자산",
|
|
};
|
|
|
|
export function auditLogTable(logs: AuditLog[]): HTMLElement {
|
|
return table(
|
|
[
|
|
L("B01_Dashboard_Table_Email"),
|
|
// 관리 버튼 열과 같은 말(「관리」)을 돌려 쓰던 것을 갈랐다 (2026-09-06 사용자 지적).
|
|
L("B01_Dashboard_Table_Event"),
|
|
L("B01_Dashboard_Table_Target"),
|
|
L("B01_Dashboard_Table_Origin"),
|
|
L("B01_Dashboard_Table_When"),
|
|
],
|
|
logs.map((log) => [
|
|
text(log.email),
|
|
text(log.action),
|
|
text(auditTarget(log)),
|
|
// 접속 주소 — 기록이 없는 옛 줄은 빈칸으로 남는다 (2026-09-06부터 기록).
|
|
text(log.ip_address ?? "-"),
|
|
// 날짜와 시각을 두 줄로 — 아랫줄이 작은 글씨라 행 높이는 그대로다.
|
|
stackedCell(formatDate(log.timestamp), formatTime(log.timestamp)),
|
|
]),
|
|
);
|
|
}
|