Files
Aislo/B01_Dashboard/B01_Dashboard_Api_Home.ts
T
eomsangdonandClaude Opus 5.5 729f4c75b8 feat(B01): 대시보드 홈 — 진행 중 수에 따라 꼴이 저절로(1 큰 카드 · 2~3 중간 · 4~8 한 줄 · 9 넘음 요약) (PLAN 547-2)
- 등록부 home 줄 = mountHome · 썸네일 선 · 단계 점 · 「다음: 지금 단계」 · [이어서 하기] = 그 단계 화면 · [자세히] = 상세
- 4~8 = 팀원별 · 단계 분포 · 14 일 넘게 그대로 표시 · 9 넘음 = 요약 숫자 · 회사별 막대 · 종류 원(인라인 SVG)
- 오른쪽 = 처리할 일 · 임시 보관함 · 회사(회사 관리자) · 예정노선(산림청) · 처음 = 세 걸음 · 꼴 고정(자동 · 작게 · 크게) 기억
- 홈 역할 차례 = 셸 roleOf 와 같게(회사 관리자가 산림청 앞)
- test_546 등록부 시험 — import 한 mount 이름을 빈 함수로 저절로(페이지 줄 갈아 끼워도 그대로)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 18:20:21 +09:00

75 lines
2.7 KiB
TypeScript

/* =============================================================================
* B01_Dashboard_Api_Home.ts
* 대시보드 홈 API(PLAN 547) — GET /dashboard/home · /dashboard/projects/summary
* ========================================================================== */
import { API_BASE_URL } from "@config/config_frontend";
/** 프로젝트 카드 요약(547-1 · `B01_Dashboard_Summary.py`) — 값이 없으면 칸이 빠짐 */
export interface ProjectSummary {
id: string;
name: string;
kind: string;
region?: string | null;
company_id?: number | null;
stage_index: number;
stage_total: number;
stage_name: string;
done: boolean;
updated_at?: string | null;
stale_days?: number | null;
owner_user_id?: number | null;
owner_names: string[];
/** 노선 중심선 0~1(y 아래로) · 없으면 null */
thumb: [number, number][] | null;
metrics: { length_m?: number; stations?: number; structures?: number };
}
export interface PlanTodo {
project_id: string;
project_name: string;
year: number;
linked_project_id: string | null;
}
export interface HomeData {
role: "SYSTEM_ADMIN" | "FOREST" | "ADMIN" | "USER";
/** 진행 중(완료 아님) · 최근 수정 순 · 썸네일은 앞 8 개만 */
projects: ProjectSummary[];
/** 홈 범위 프로젝트 전체(완료 포함) — 0 = 처음 */
project_total: number;
todos: {
new_plans: PlanTodo[];
updated_plans: PlanTodo[];
join_requests?: number;
expiring_temp: { batch_id: string; name: string; expires_at: string; days_left: number }[];
temp_count: number;
};
company?: { id: number; name: string | null; member_count: number | null };
forest?: {
plan_status: { draft: number; analyzed: number; confirmed: number };
assign_waiting: number;
};
system?: {
companies: number;
users: number;
company_names: Record<string, string>;
server: { cpu: number | null; memory: number | null; disk: number | null };
};
}
async function getJson<T>(path: string): Promise<T> {
const response = await fetch(`${API_BASE_URL}${path}`, { credentials: "include" });
if (!response.ok) throw new Error(`홈 자료를 불러오지 못했습니다 (${response.status})`);
return (await response.json()) as T;
}
export const fetchHome = (): Promise<HomeData> => getJson<HomeData>("/dashboard/home");
/** 카드 요약 — ids 없으면 보이는 프로젝트 전부(최근 수정 순) */
export async function fetchProjectSummaries(ids?: string[]): Promise<ProjectSummary[]> {
const query = ids?.length ? `?ids=${encodeURIComponent(ids.join(","))}` : "";
return (await getJson<{ projects: ProjectSummary[] }>(`/dashboard/projects/summary${query}`))
.projects;
}