- 공용 `common_util_time.ts`(날짜 · 시각 · 오늘/어제/n 일 전 · Z 없는 옛 글 = UTC) · `common_util_time.py`(UTC Z 글 · 한국 시각) - 화면 바꿈: 대시보드(프로젝트 · 휴지통 · 시스템 로그 · 보관함 · 홈 카드) · B09 굳힘 · E03 · E05 · E07 · M02 호표 이력 · 목록 고친 날 · 지난 판 - 서버: 응답 datetime = UTC + Z(main.py) · 로컬 시각 저장 → UTC · 대시보드 경과일 = UTC 기준 · 엑셀 날짜 · 파일 이름 = 한국 시각 - 시험: test_593_time(서울 · 뉴욕 · Z 없는 옛 글 · 서버 글) Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
94 lines
3.8 KiB
TypeScript
94 lines
3.8 KiB
TypeScript
/* =============================================================================
|
|
* B09_Estimation_UI_Check.ts
|
|
* B09 좌측 「데이터 점검」 묶음(PLAN 203-1) — [업데이트] · 연결 점검(옛 「연결 점검」 탭 내용).
|
|
*
|
|
* [업데이트] = 단가를 지금 M01 값으로 새로 굳힘 · 서버가 낡았다고 보면(`payload.stale` 까닭 한 줄)
|
|
* 단추에 점 배지(`is-pending`) · 굳힌 시각 · 까닭 = 공용 호버
|
|
* 연결 점검 = 「연결 없음」 줄 목록(누르면 그 탭 그 줄로 · 까닭 = 공용 호버) + 서버 알림 · M01 에 없는 키
|
|
* ========================================================================== */
|
|
|
|
import { attachHoverInfo } from "@ui/ui_template_hover_info";
|
|
import { createBadge } from "@ui/ui_template_badge";
|
|
import { createText } from "@ui/ui_template_text";
|
|
import type { Row } from "./B09_Estimation_Calc_Base";
|
|
import { dateTimeText } from "../common_util/common_util_time";
|
|
import { tabName, type Link, type TabId } from "./B09_Estimation_UI_Tabs";
|
|
|
|
export interface CheckItem {
|
|
link: Link;
|
|
tab: string;
|
|
name: string;
|
|
why: string;
|
|
}
|
|
|
|
/** 빠진 연결 줄 · 알림 글(서버 알림 + M01 에 없는 키) */
|
|
export function checkItems(sheets: Row, payload: Row): { items: CheckItem[]; notes: string[] } {
|
|
const gaps: Row[] = sheets.gaps || [];
|
|
const items = gaps.map((g) => ({
|
|
link: { tab: g.tab as TabId, key: g.key },
|
|
tab: tabName(g.tab),
|
|
name: String(g.name ?? ""),
|
|
why: String(g.why ?? ""),
|
|
}));
|
|
const notes: string[] = [...(payload.notes || [])];
|
|
const missing: string[] = payload.inputs?.missing || [];
|
|
if (missing.length) notes.push(`M01 에 없는 키 ${missing.length} — ${missing.join(" · ")}`);
|
|
return { items, notes };
|
|
}
|
|
|
|
/** [업데이트] 호버 글 — 굳힌 시각 + 낡은 까닭 */
|
|
export function refreshTip(payload: Row | null): string {
|
|
const made = payload?.book?.made;
|
|
const when = made ? `단가 굳힘 ${dateTimeText(String(made))}` : "단가 아직 안 굳힘";
|
|
const stale = payload?.stale;
|
|
return `${when} · 누르면 지금 M01 값으로 새로 굳힘${stale ? ` · 업데이트 필요 — ${stale}` : ""}`;
|
|
}
|
|
|
|
export interface CheckPanel {
|
|
/** 묶음 안 연결 점검 자리 */
|
|
list: HTMLElement;
|
|
draw: (payload: Row, sheets: Row) => void;
|
|
}
|
|
|
|
export function createCheckPanel(refresh: HTMLElement, goto: (link: Link) => void): CheckPanel {
|
|
let payload: Row | null = null;
|
|
let items: CheckItem[] = [];
|
|
attachHoverInfo(refresh, () => refreshTip(payload));
|
|
const list = document.createElement("div");
|
|
list.className = "b09-check";
|
|
attachHoverInfo(list, (row) => items[Number(row.dataset.i)]?.why, "[data-i]");
|
|
|
|
const draw = (next: Row, sheets: Row): void => {
|
|
payload = next;
|
|
refresh.classList.toggle("is-pending", Boolean(next.stale));
|
|
const made = checkItems(sheets, next);
|
|
items = made.items;
|
|
const head = createText(`연결 없음 ${items.length}곳`, "muted");
|
|
head.classList.add("b09-check__head");
|
|
const rows = document.createElement("div");
|
|
rows.className = "ui-sidebar-list";
|
|
rows.append(
|
|
...items.map((item, i) => {
|
|
const row = document.createElement("button");
|
|
row.type = "button";
|
|
row.className = "ui-sidebar-row";
|
|
row.dataset.i = String(i);
|
|
const name = document.createElement("span");
|
|
name.textContent = item.name;
|
|
const tab = createBadge(item.tab, "neutral", { size: 18 });
|
|
tab.classList.add("b09-check__tab");
|
|
row.append(name, tab);
|
|
row.addEventListener("click", () => goto(item.link));
|
|
return row;
|
|
}),
|
|
);
|
|
const notes = made.notes.map((text) => {
|
|
const p = createText(text, "muted");
|
|
p.classList.add("b09-check__note");
|
|
return p;
|
|
});
|
|
list.replaceChildren(head, ...(items.length ? [rows] : []), ...notes);
|
|
};
|
|
return { list, draw };
|
|
}
|