Merge remote-tracking branch 'origin/sub_laptop_1' into sub_desktop_1

This commit is contained in:
2026-09-16 10:46:05 +09:00
6 changed files with 81 additions and 37 deletions
+19 -6
View File
@@ -58,28 +58,41 @@ export function valueWithUnit(value: unknown, unit?: string | null): string {
/** 자료 출처표 한 줄 — 어디서 받고 최신이 무엇인지(데스크탑 서브 출처표 · 메인이 표 수준에 실음). */
export interface TableSource {
source_id?: string;
/** 원본 이름 — 한 표가 원본 여럿을 모아 어느 것이 뒤처졌는지 가려야 함 */
name?: string;
publisher: string;
where: string;
cycle?: string;
latest_published?: string;
our_edition?: string;
checked_at?: string;
/** 뒤처짐 판정 — 서버만 함 */
outdated?: boolean;
/** 뒤처짐 판정 — 서버만 함 · null 은 「모름」이라 띠를 안 세움 */
outdated?: boolean | null;
}
/**
* 뒤처진 자료 띠 글자 — 서버가 outdated 라 할 때만. 화면은 날짜를 견주지 않음(판정 두 벌 금지).
* 받는 자리를 꼭 적음 — 최신이 무엇인지·어디서 받는지가 없어 건설 노임이 반 년 뒤처졌음.
*/
export function outdatedBanner(source?: TableSource): string | null {
if (source?.outdated !== true) return null;
return `이 자료는 ${source.our_edition ?? "판 모름"} 판 · 최신은 ${source.latest_published ?? "?"} 공표 · ${source.publisher} ${source.where}`;
export function outdatedBanner(sources?: TableSource[]): string[] {
return (sources ?? [])
.filter((source) => source.outdated === true)
.map((source) => {
const head = source.name ? `${source.name}` : "";
const where = source.where ? ` ${source.where}` : "";
return `${head}이 자료는 ${source.our_edition ?? "판 모름"} 판 · 최신은 ${source.latest_published ?? "?"} 공표 · ${source.publisher}${where}`;
});
}
/** 기초단가 표 머리 — 열 하나에 한 문장이라 표에 한 번만 옴(2026-09-15 브레인 ④). */
export interface TableMeta {
source?: TableSource;
/** 한 표가 모은 원본마다 한 줄 */
source?: TableSource[];
/** 서버가 주는 알림 한 줄(요율 — 법이 정한 값) — 화면이 사전을 가지면 두 벌이 됨 */
notice?: string;
/** 고친 값이 어디에 닿는지 — 새로 만드는 프로젝트부터 쓰임(서버가 줌) */
scope_notice?: string;
editable?: string[];
/** 열key → 왜 못 고치나 */
locked?: Record<string, string>;
+14 -8
View File
@@ -33,8 +33,6 @@ type Row = Record<string, unknown>;
export interface RowsSource {
title: string;
key: string;
/** 표 위 알림 한 줄(요율 — 법이 정한 값) */
notice?: string;
/** false 면 검색 칸을 숨김 — 서버에 검색이 없는 표(고친 것 모아 보기) */
searchable?: boolean;
load: (query: RowsQuery) => Promise<MasterRows>;
@@ -100,7 +98,8 @@ export function buildRowsView(): RowsView {
children: [hiddenToggle, L("Z01_MasterData_ShowHidden")],
});
const notice = el("p", { className: "z01-master__notice" });
const banner = el("p", { className: "z01-master__outdated" });
const scope = el("p", { className: "z01-master__scope" });
const banner = el("div", { className: "z01-master__outdated" });
const detail = el("div", { className: "z01-master__detail" });
const grid = el("div", { className: "z01-master__grid-wrap" });
const pageInput = el("input", {
@@ -128,6 +127,7 @@ export function buildRowsView(): RowsView {
className: "z01-master__panel",
children: [
el("div", { children: [title, titleKey] }),
scope,
banner,
notice,
toolbar,
@@ -141,6 +141,7 @@ export function buildRowsView(): RowsView {
detail.hidden = true;
notice.hidden = true;
banner.hidden = true;
scope.hidden = true;
function goTo(page: number): void {
const pages = pageCount(last?.total ?? 0, PAGE_SIZE);
@@ -190,10 +191,15 @@ export function buildRowsView(): RowsView {
function draw(): void {
if (!last) return;
const meta = last;
// 뒤처진 자료 띠 — 서버 outdated 만 봄(날짜 비교 안 함).
// 표 머리 세 줄 — 모두 서버가 주는 글자 그대로(화면이 사전을 가지면 두 벌이 됨).
// ① 고친 값이 닿는 자리 ② 뒤처진 원본(서버 outdated 만 · 날짜 비교 안 함) ③ 그 밖 알림
scope.textContent = meta.scope_notice ?? "";
scope.hidden = !meta.scope_notice;
const outdated = outdatedBanner(meta.source);
banner.textContent = outdated ? `${outdated}` : "";
banner.hidden = !outdated;
banner.replaceChildren(...outdated.map((text) => el("p", { text: `${text}` })));
banner.hidden = outdated.length === 0;
notice.textContent = meta.notice ?? "";
notice.hidden = !meta.notice;
const columns = shownColumns(meta.columns, showHidden);
const headRow = el("tr", { children: columns.map((column) => headCell(meta, column)) });
const body = el("tbody");
@@ -358,9 +364,9 @@ export function buildRowsView(): RowsView {
state.page = 1;
title.textContent = picked.title;
titleKey.textContent = picked.key;
notice.textContent = picked.notice ?? "";
notice.hidden = !picked.notice;
notice.hidden = true;
banner.hidden = true;
scope.hidden = true;
search.root.hidden = picked.searchable === false;
toolbar.hidden = false;
pager.hidden = false;
-2
View File
@@ -44,8 +44,6 @@ export function buildSidePanel(groups: MasterGroup[], view: RowsView): HTMLEleme
view.show({
title: `${baseTitle} ${label}`,
key: `base-prices/${kind}`,
// 요율은 구간 줄에 코드가 없어 구간 이름으로 이음 — 법이 바뀌면 고친 값이 주인을 잃기 쉬움.
notice: kind === "rate" ? L("Z01_MasterData_Rate_Notice") : undefined,
load: (query) => fetchBasePrices(kind, query),
save: (rowId, values) => saveBasePrice(kind, rowId, values),
});
+16 -1
View File
@@ -125,7 +125,22 @@
font-size: var(--text-body);
}
/* 뒤처진 자료 띠 — 받는 자리까지 적힘 · 또렷이 */
/* 고친 값이 닿는 자리 — 흐리면 「저장이 안 됐다」로 읽힘(2026-09-16 브레인) */
.z01-master__scope {
margin: 0;
padding: var(--spacing-8) var(--spacing-12);
border-left: 4px solid var(--color-accent);
background: var(--color-mist-violet);
color: var(--color-accent);
font-size: var(--text-body-sm);
font-weight: var(--font-weight-bold);
}
/* 뒤처진 자료 띠 — 받는 자리까지 적힘 · 또렷이 · 원본마다 한 줄 */
.z01-master__outdated p {
margin: 0;
}
.z01-master__outdated {
margin: 0;
padding: var(--spacing-8) var(--spacing-12);