Files
Aislo/tools/est-test/native-views.js
T
eomsangdonandClaude Opus 5.5 ceab1ab8c5 feat(est-test): 하단으로 집계·공종 다듬기·들여쓰기·레벨 확인
- 원본 처리 근거대로 소계 줄 넣기·지우기, 내역 엔진에 소계 행 합 추가
- 공종 들여쓰기, 단가산출 들여쓰기, 단가산출 레벨 나무 보기

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-11 21:03:37 +09:00

146 lines
6.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const EstViews = (() => {
const enums = {
LinkIndex: [
[0, "직접입력"],
[5, "자재"],
[6, "노임"],
[21, "표준"],
[101, "견적"],
[103, "일위"],
[104, "단가산출"],
[105, "기계"],
[51, "소계"],
[52, "낙찰"],
[54, "순공사비"],
[55, "도급액"],
[57, "조달수수료"],
[58, "비율"],
[59, "경계"],
[61, "산근 소계"],
[62, "구간비율"],
[67, "내역비율"],
[68, "묶음끝"],
[99, "연차 배분"],
],
CalcIndex: [
[0, "계산·합산"],
[1, "고정·합산"],
[2, "계산·제외"],
[3, "고정·제외"],
],
ValueIndex: [
[0, "최저"],
[1, "평균"],
[2, "최고"],
[3, "출처선택"],
[4, "직접입력"],
],
DigetIndex: [
[0, "AUTO"],
[1, "사사오입"],
[2, "절사"],
[3, "올림식"],
],
SCheck: [
[0, "비목별"],
[1, "재료"],
[2, "노무"],
[3, "경비"],
[-1, "노무 소계"],
[-2, "재료 소계"],
[-3, "경비 소계"],
[-4, "실적 소계"],
[-5, "합계"],
],
BaseField: [
["", "직접 입력"],
["NC", "직접 노무"],
["GC", "직접 재료"],
["JC", "직접 경비"],
["SC", "직접 실적"],
["TC", "순공사비"],
],
};
function cell(table, index, key, value) {
const { esc } = EstApp,
label = EstModel.labels[key] || key;
const attrs = `data-table="${table}" data-row="${index}" data-field="${key}" aria-label="${esc(label)}"`;
if (enums[key])
return `<select ${attrs}>${enums[key].map(([v, name]) => `<option value="${v}" ${String(v) === String(value ?? (key === "BaseField" ? "" : 0)) ? "selected" : ""}>${esc(name)}</option>`).join("")}</select>`;
if (key === "LineData")
return `<textarea ${attrs} rows="1" spellcheck="false">${esc(EstText.display(value))}</textarea><button class="tiny" data-action="raw-line" data-row="${index}" title="산출근거 편집">…</button>`;
if (value && typeof value === "object") return `<span class="muted">바이너리 자료</span>`;
if (EstModel.numeric.has(key))
return `<input ${attrs} inputmode="decimal" type="number" step="any" value="${value ?? ""}">`;
return `<input ${attrs} type="text" value="${esc(value)}" maxlength="10000">`;
}
function grid(table, list, columns) {
const { esc, number, state } = EstApp;
return `<table class="sheet" data-grid="${table}"><thead><tr><th class="row-number">선택</th>${columns.map((key) => `<th class="col-${key}">${esc((table === "Wonga" && typeof EstJungSang !== "undefined" && EstJungSang.label(state.project, key)) || EstModel.labels[key] || key)}</th>`).join("")}</tr></thead><tbody>${list.map(({ row, index }) => `<tr data-index="${index}" class="${state.selection.has(index) ? "selected " : ""}${Number(row.Index) > 0 ? "heading " : ""}${Number(row.Level) > 0 ? "level " : ""}${row.Error ? "error-row" : ""}"><th class="row-number"><label><input type="checkbox" data-select="${index}" ${state.selection.has(index) ? "checked" : ""}>${index + 1}</label></th>${columns.map((key) => `<td class="col-${key}"${key === "Name" && Number(row.LeftSpace) > 0 ? ` style="padding-left:${Number(row.LeftSpace) * 6}px"` : ""}>${cell(table, index, key, row[key])}</td>`).join("")}</tr>`).join("")}</tbody></table>`;
}
function render(state) {
const { project, view } = state,
{ byId, esc, number } = EstApp;
if (project.tables[view]) EstApp.visibleRows();
const grouped = ["HeadMainDat", "CostMainDat", "MachMainDat"].includes(view);
byId("group-pane").hidden = !grouped;
if (grouped) {
const records = EstNative.groups(project.tables[view] || []);
byId("group-list").innerHTML =
[...records]
.map(
([code, group]) =>
`<button data-group="${esc(code)}" class="${state.group === code ? "active" : ""}"><b>${esc(group.rows[0].Name || EstText.clean(group.rows[0].LineData))}</b><small>${esc(code)}</small><span>${number(group.rows[0].TC)}</span></button>`,
)
.join("") || '<p class="muted">자료가 없습니다. 묶음 추가를 누르세요.</p>';
}
byId("search").value = state.query;
byId("business-search").value = state.query;
byId("business-search").hidden = !["progress", "escalation", "change"].includes(view);
byId("standard-tools").hidden = !project.tables[view];
byId("add-group").hidden = !grouped;
const haljungBtn = byId("haljung-calc-btn");
if (haljungBtn) haljungBtn.hidden = view !== "HeadMainDat";
const vatBtn = byId("vat-calc-btn");
if (vatBtn) vatBtn.hidden = view !== "StuffcDat";
const unitCalcBtn = byId("unit-calc-btn");
if (unitCalcBtn) unitCalcBtn.hidden = view !== "HeadMainDat";
byId("move-estimate-up").hidden = ![
"EstMainDat",
"HeadMainDat",
"CostMainDat",
"MachMainDat",
].includes(view);
byId("move-estimate-down").hidden = ![
"EstMainDat",
"HeadMainDat",
"CostMainDat",
"MachMainDat",
].includes(view);
if (project.tables[view]) {
const all = EstApp.visibleRows(),
start = state.page * 100,
list = all.slice(start, start + 100),
columns =
view === "Wonga" && typeof EstJungSang !== "undefined"
? EstJungSang.columns(project, EstModel.columns(view))
: EstModel.columns(view);
byId("work-content").innerHTML = grid(view, list, columns);
byId("paging").hidden = false;
byId("page-info").textContent =
`${all.length ? start + 1 : 0}–${Math.min(start + 100, all.length)} / ${all.length}행`;
byId("previous-page").disabled = state.page === 0;
byId("next-page").disabled = start + 100 >= all.length;
} else {
byId("paging").hidden = true;
EstExtra.render(state);
}
const chosen = [...state.selection][0],
row = project.tables[view]?.[chosen];
byId("selected-info").textContent = row
? `${chosen + 1}행 · ${row.Code || ""} ${row.Name || EstText.clean(row.LineData)}`
: "행 왼쪽을 선택한 뒤 복사·삭제·레벨 지정 등을 사용할 수 있습니다.";
}
return { render, grid, cell, enums };
})();