feat(724-1): M02 단가산출 상세 · 일위대가 줄 모달 = 722 공용 상세(LogicLab_Ho) — 줄 모달 그 자리 고침 → M02 덮개 · 옛 고침 표 둘 · 이름 같은 모델 파일 걷음
- SK 셈 답 → 공용 상세 줄(logic/M02_Sangeun_Cover_Model.hoView · 정체 차례 · 바탕 줄 그대로 · 더한줄) · 고침 고리 HoEdit → setLineCover(덮개 · 더한줄 · 열린입력 = 배율) - HoEdit 덧칸 more(줄 빼기 · 별도계상) · M02 = 덧줄 율 고침 · 꼬리표 「변경 항목」 · 뺀 줄 띠 = Sangeun_Cover.removedStrip - 시험 계산 · 텍스트 수식 = 바탕 로직 + 덮개 품 · 단가 사본(applyCovers) · 뺀 바탕 줄 글 거름(dropText — 같은 이름 더한줄이 안 받음) - 717-3 openRowSangeun = 줄 모드 상세(mountRowSk) 얇은 모달(Labor_Detail 부름 그대로) · skCoverTable · coverTable · 뿌리 M02_Sangeun_Cover_Model.ts 지움(Labor_Api import 한 줄) - 낡은 시험: test_717_2b(setQty · setPrice → setLineCover · hoView · dropText) · test_717_3(모델 경로 · setCover · priceKey · sheetGroups 걷힘 → cleanPatch · 화면 이음 새 꼴) - 안내 글(M02_SangeunBaseViews) = 덮개 사본 반영 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -111,6 +111,7 @@ const TEXT = {
|
||||
Fold: ["누르면 펼침", "Click to expand"],
|
||||
Per: ["{n} — {v} 원/{u}", "{n} — {v} KRW/{u}"],
|
||||
Edited: ["시험 고침", "Trial edit"],
|
||||
EditedM02: ["변경 항목", "Override"],
|
||||
} as const satisfies Record<string, readonly [string, string]>;
|
||||
const th = (k: keyof typeof TEXT): string => TEXT[k][currentLanguageIndex as 0 | 1] ?? TEXT[k][0];
|
||||
const boxName = (b: string): string => (b in TEXT ? th(b as keyof typeof TEXT) : b);
|
||||
@@ -120,8 +121,14 @@ export interface HoEdit {
|
||||
covers: Record<number, LineCover>;
|
||||
set: (idx: number, cover: LineCover | null) => void;
|
||||
scope?: "m01" | "m02";
|
||||
/** (M02) 모달 고침 칸 아래 덧 동작(줄 빼기 · 별도계상 등) */
|
||||
more?: (idx: number, close: () => void) => HTMLElement[];
|
||||
}
|
||||
|
||||
/** 고친 줄 꼬리표 — M01 = 시험 고침 · M02 = 변경 항목 · 고침 없음 = "" */
|
||||
const editTag = (ctx: HoContext, idx: number): string =>
|
||||
ctx.edit?.covers[idx] ? th(ctx.edit.scope === "m02" ? "EditedM02" : "Edited") : "";
|
||||
|
||||
export interface HoContext {
|
||||
row: LogicRow;
|
||||
prices: Record<string, ElementBrief | null>;
|
||||
@@ -266,22 +273,28 @@ function modalOf(e: Entry, ctx: HoContext, extra: { cond?: PickCond; item?: HoLi
|
||||
...(item?.종류 === "재료" && ctx.calcHost
|
||||
? { onPick: (it) => pickMaterial(ctx.calcHost!, ctx.values, e.idx, it) }
|
||||
: {}),
|
||||
...(edit && item && !e.extra
|
||||
// 덧줄(%) = M02 덮개만 율 고침(M01 시험 값은 호표 줄만)
|
||||
...(edit && (e.extra ? edit.scope === "m02" : item)
|
||||
? {
|
||||
edit: (close: () => void) =>
|
||||
coverForm({
|
||||
qty: line ? line.수량 : null,
|
||||
prices: e.logic
|
||||
? {
|
||||
labor: perUnit("노무비"),
|
||||
material: perUnit("재료비"),
|
||||
expense: perUnit("경비"),
|
||||
}
|
||||
: { [e.part]: line ? line.단가 : null },
|
||||
edit: (close: () => void) => {
|
||||
const form = coverForm({
|
||||
qty: line ? pctView(line).qty : null,
|
||||
prices: e.extra
|
||||
? {}
|
||||
: e.logic
|
||||
? {
|
||||
labor: perUnit("노무비"),
|
||||
material: perUnit("재료비"),
|
||||
expense: perUnit("경비"),
|
||||
}
|
||||
: { [e.part]: line ? line.단가 : null },
|
||||
cover: edit.covers[e.idx],
|
||||
scope: edit.scope,
|
||||
onApply: (c) => (close(), edit.set(e.idx, c)),
|
||||
}),
|
||||
});
|
||||
const more = edit.more?.(e.idx, close) ?? [];
|
||||
return more.length ? el("div", { children: [form, ...more] }) : form;
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
@@ -429,23 +442,23 @@ function formulaCell(e: Entry, ctx: HoContext, text = ""): HTMLElement {
|
||||
return cell;
|
||||
}
|
||||
|
||||
function nameCell(e: Entry, label: string, covered: boolean): HTMLElement {
|
||||
function nameCell(e: Entry, label: string, tag: string): HTMLElement {
|
||||
return el("div", {
|
||||
children: [
|
||||
el("div", { text: label }),
|
||||
...(e.share && label === e.name ? [createBadge(`${e.share} ${tl("Share")}`, "accent")] : []),
|
||||
...(e.spec ? [el("div", { className: "ui-text ui-text--muted", text: e.spec })] : []),
|
||||
...(e.warn ? [createBadge(`${tx("Calc_UnitWarn")} · ${e.warn}`, "warning")] : []),
|
||||
...(covered ? [createBadge(th("Edited"), "accent")] : []),
|
||||
...(tag ? [createBadge(tag, "accent")] : []),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
/** 보통 줄 · 몫 줄 — 누르면 그 줄 모달 */
|
||||
function lineRow(e: Entry, ctx: HoContext, label = e.name): HTMLTableRowElement {
|
||||
const covered = !!ctx.edit?.covers[e.idx];
|
||||
const tag = editTag(ctx, e.idx);
|
||||
const tr = tableRow(COLS, [
|
||||
nameCell(e, label, covered && !e.share),
|
||||
nameCell(e, label, e.share ? "" : tag),
|
||||
e.qtyValue,
|
||||
e.unit,
|
||||
formulaCell(e, ctx),
|
||||
@@ -454,7 +467,7 @@ function lineRow(e: Entry, ctx: HoContext, label = e.name): HTMLTableRowElement
|
||||
]);
|
||||
tr.classList.add("m01lab__line");
|
||||
if (e.extra) tr.classList.add("m01lab__line--extra");
|
||||
if (covered) tr.classList.add("is-changed");
|
||||
if (tag) tr.classList.add("is-changed");
|
||||
tr.tabIndex = 0;
|
||||
tr.dataset.line = e.name;
|
||||
tr.addEventListener("click", () => e.open(e));
|
||||
@@ -486,9 +499,9 @@ function mergedRows(m: HoMerged<Entry>, ctx: HoContext): HTMLTableRowElement[] {
|
||||
.replace("{a}", share("노무비"))
|
||||
.replace("{b}", share("재료비"))
|
||||
.replace("{c}", share("경비"));
|
||||
const covered = !!ctx.edit?.covers[m.idx];
|
||||
const tag = editTag(ctx, m.idx);
|
||||
const head = tableRow(COLS, [
|
||||
nameCell(first, `▸ ${first.name}`, covered),
|
||||
nameCell(first, `▸ ${first.name}`, tag),
|
||||
first.qtyValue,
|
||||
first.unit,
|
||||
formulaCell(first, ctx, short),
|
||||
@@ -496,7 +509,7 @@ function mergedRows(m: HoMerged<Entry>, ctx: HoContext): HTMLTableRowElement[] {
|
||||
money(m.금액),
|
||||
]);
|
||||
head.classList.add("m01lab__line");
|
||||
if (covered) head.classList.add("is-changed");
|
||||
if (tag) head.classList.add("is-changed");
|
||||
head.dataset.equip = first.name;
|
||||
head.title = th("Fold");
|
||||
head.tabIndex = 0;
|
||||
|
||||
Reference in New Issue
Block a user