feat(est): add data issue search

This commit is contained in:
2026-11-07 11:02:20 +09:00
parent db02fa9994
commit b6a3392bc4
10 changed files with 372 additions and 0 deletions
+100
View File
@@ -0,0 +1,100 @@
const EstIssues = (() => {
let page = 0;
const grouped = new Set(["HeadMainDat", "CostMainDat", "MachMainDat"]);
const kinds = {
5: "StuffcDat",
6: "LaborcDat",
21: "SilJukDat",
101: "EstiMateDat",
103: "HeadMainDat",
104: "CostMainDat",
105: "MachMainDat",
};
function scan(project) {
const issues = [],
sources = new Map();
for (const [kind, table] of Object.entries(kinds)) {
const codes = new Map();
(project.tables[table] || []).forEach((row, index) => {
if (!row.Code || (grouped.has(table) && !(Number(row.Index) > 0))) return;
const list = codes.get(String(row.Code)) || [];
list.push({ row, index });
codes.set(String(row.Code), list);
});
sources.set(Number(kind), codes);
for (const [code, list] of codes)
if (list.length > 1)
for (const { index } of list) issues.push({ table, index, code, message: "코드 중복" });
}
for (const table of ["EstMainDat", "HeadMainDat", "MachMainDat"]) {
(project.tables[table] || []).forEach((row, index) => {
if (Number(row.Level) > 0 || Number(row.Index) > 0 || !row.Code) return;
const codes = sources.get(Number(row.LinkIndex));
if (!codes) return;
const matches = codes.get(String(row.Code)) || [];
if (!matches.length)
issues.push({ table, index, code: row.Code, message: "연결 자료 없음" });
else if (matches.length > 1)
issues.push({ table, index, code: row.Code, message: "연결 코드 중복" });
else
for (const field of ["Name", "Size"]) {
const a = row[field],
b = matches[0].row[field];
if (a && b && EstNative.normalize(a) !== EstNative.normalize(b))
issues.push({
table,
index,
code: row.Code,
message: field === "Name" ? "연결 품명 차이" : "연결 규격 차이",
});
}
});
}
for (const message of project.calculation?.errors || [])
issues.push({ table: "", index: -1, code: "", message: String(message) });
return issues;
}
function render() {
const { state, esc, byId, titles } = EstApp,
issues = scan(state.project);
page = Math.max(0, Math.min(page, Math.ceil(issues.length / 100) - 1));
const rows = issues.slice(page * 100, page * 100 + 100);
byId("work-content").innerHTML =
`<div class="business-tools"><b>자료 오류 검색</b><span>${issues.length}건 · ${page + 1}/${Math.max(1, Math.ceil(issues.length / 100))}쪽</span><button data-issue-page="-1" ${page === 0 ? "disabled" : ""}>이전</button><button data-issue-page="1" ${(page + 1) * 100 >= issues.length ? "disabled" : ""}>다음</button></div><p>연결 품명·규격 차이는 확인이 필요한 항목으로 표시합니다.</p><table class="sheet"><thead><tr><th>자료</th><th>행</th><th>코드</th><th>내용</th><th>이동</th></tr></thead><tbody>${rows.map((item) => `<tr><td>${esc(titles[item.table] || item.table || "전체 계산")}</td><td>${item.index >= 0 ? item.index + 1 : ""}</td><td>${esc(item.code)}</td><td>${esc(item.message)}</td><td>${item.table ? `<button data-issue-table="${esc(item.table)}" data-issue-row="${item.index}">행 열기</button>` : ""}</td></tr>`).join("")}</tbody></table>`;
}
function install() {
document.addEventListener("click", (event) => {
const step = event.target.closest("[data-issue-page]");
if (step) {
page += Number(step.dataset.issuePage);
render();
return;
}
const node = event.target.closest("[data-issue-table]");
if (!node) return;
const table = node.dataset.issueTable,
index = Number(node.dataset.issueRow),
rows = EstApp.state.project.tables[table] || [];
if (!rows[index]) return;
let group = "";
if (grouped.has(table))
for (const [code, item] of EstNative.groups(rows))
if (index >= item.start && index < item.start + item.rows.length) {
group = code;
break;
}
if (grouped.has(table) && !group) {
EstApp.state.notice = "묶음 코드가 중복되거나 해당 행의 묶음이 없어 이동할 수 없습니다.";
EstApp.render();
return;
}
EstApp.navigate(table, group);
const visible = EstApp.visibleRows(),
position = visible.findIndex((item) => item.index === index);
if (position >= 0) EstApp.state.page = Math.floor(position / 100);
EstApp.state.selection = new Set([index]);
EstApp.render();
});
}
return { scan, render, install };
})();