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" ? "연결 품명 차이" : "연결 규격 차이", }); } }); } const costs = project.tables.CostMainDat || [], costGroups = EstNative.groups(costs); for (const message of project.calculation?.errors || []) { const text = String(message), match = text.match(/^(.+):(\d+) /), code = match?.[1], group = code && costGroups.get(code), offset = match ? Number(match[2]) - 1 : -1, unique = group && sources.get(104)?.get(code)?.length === 1, index = unique && offset >= 0 && offset < group.rows.length ? group.start + offset : -1; issues.push({ table: index >= 0 ? "CostMainDat" : "", index, code: index >= 0 ? code : "", message: text, }); } 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 = `
자료 오류 검색${issues.length}건 · ${page + 1}/${Math.max(1, Math.ceil(issues.length / 100))}쪽

연결 품명·규격 차이는 확인이 필요한 항목으로 표시합니다.

${rows.map((item) => ``).join("")}
자료행코드내용이동
${esc(titles[item.table] || item.table || "전체 계산")}${item.index >= 0 ? item.index + 1 : ""}${esc(item.code)}${esc(item.message)}${item.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 }; })();