// 원본 데이타 자동연결(ActionAutoLink Ctrl+Alt+L 0x10d54f4 → TfrmDataAutoLink 적용 0x10d3008, 행 처리 10d2a48, 맞춤 10e0e58). // 내역서·일위대가·기계경비 화면에서 현재 공사의 노임·자재·견적·표준·기계경비·단가산출·일위대가 표로 품명(·규격·단위)을 맞춰 연결. // 정규화: 빈칸·|·(·) 제거, 단위는 「당」·[·] 를 한 번씩 더 지움. 노임은 품명만(못 찾으면 규격으로 찾고 품명·규격을 맞바꿈), // 규격·단위 비면 품명+규격, 단위 있으면 품명+규격+단위. 노임·기계는 단위 무시. 처음 맞는 행. Over Write 끄면 이미 연결된 행은 건너뜀. // 쓰는 값: Code, TU(=원본 TC), 내역·일위대가는 NU·GU·JU·SU(=원본 NC·GC·JC·SC), LinkIndex, 원본 SCheck 3 이면 SCheck 3. // 「전체연결 끊기」는 원본처럼 모든 행 LinkIndex 를 0 으로 한다(조건 없음). const EstAutoLink = (() => { const num = (value) => Number(value) || 0; const sources = { 6: "LaborcDat", 5: "StuffcDat", 101: "EstiMateDat", 21: "SilJukDat", 105: "MachTitleDat", 104: "CostTitleDat", 103: "HeadTitleDat", }; const order = [6, 5, 101, 21, 105, 104, 103]; const tags = { EstMainDat: 1, HeadMainDat: 2, MachMainDat: 4 }; const norm = (s) => String(s ?? "").replace(/[\s|()]/g, ""); const unit = (s) => norm(s).replace("당", "").replace("[", "").replace("]", ""); function key(row, tag) { let name = row.Name ?? "", size = row.Size ?? ""; const unite = row.Unite ?? ""; if (tag === 4) { name = String(name).replace(/[\s|]/g, ""); size = String(size).replace(/[\s|]/g, ""); if ([5, 212].includes(num(row.LinkIndex)) && name.includes("주연료")) { name = size; size = ""; } } return { name: String(name).trim(), size: String(size).trim(), unite: String(unite).trim() }; } function find(project, kind, k) { const rows = project.tables[sources[kind]] || [], useUnit = ![6, 105].includes(kind) && k.unite; const mode = !k.size && !useUnit ? (kind === 6 ? "name" : "size") : useUnit ? "unit" : "size"; return rows.find((src) => { if (!src.Code) return false; if (kind !== 101 && src.LinkIndex != null && num(src.LinkIndex) !== kind) return false; if (src.DataKind != null && num(src.DataKind) !== 1) return false; if (norm(src.Name) !== norm(k.name)) return false; if (mode === "name" || kind === 6) return true; if (norm(src.Size) !== norm(k.size)) return false; if (mode === "size" || kind === 105) return true; return unit(src.Unite) === unit(k.unite); }); } function linkKind(project, view, kind, overwrite) { const tag = tags[view], rows = project.tables[view] || []; let linked = 0; for (const row of rows) { if ((tag === 2 || tag === 4) && num(row.Index) > 0) continue; if (tag === 1 && (num(row.Level) > 0 || [54, 55, 58].includes(num(row.LinkIndex)))) continue; const k = key(row, tag); if (!k.name && !k.size && !k.unite) continue; if (!overwrite && num(row.LinkIndex)) continue; let src = find(project, kind, kind === 6 ? { name: k.name, size: "", unite: "" } : k); if (!src && kind === 6 && k.size) { src = find(project, kind, { name: k.size, size: "", unite: "" }); if (src) [row.Name, row.Size] = [row.Size, row.Name]; } if (!src) continue; row.Code = src.Code; row.TU = num(src.TC); if (tag === 1 || tag === 2) { row.NU = num(src.NC); row.GU = num(src.GC); row.JU = num(src.JC); row.SU = num(src.SC); } row.LinkIndex = kind; if (num(src.SCheck) === 3) row.SCheck = 3; linked++; } return linked; } function run(project, view, choice, overwrite) { if (!tags[view]) throw Error("내역서·일위대가·기계경비 화면에서 자동연결하세요."); if (choice === "unlink") { for (const row of project.tables[view] || []) row.LinkIndex = 0; return (project.tables[view] || []).length; } const kinds = choice === "all" ? order.filter((k) => k !== 105 || [1, 2].includes(tags[view])) : [Number(choice)]; return kinds.reduce((n, kind) => n + linkKind(project, view, kind, overwrite), 0); } const choices = [ ["unlink", "전체연결 끊기"], ["all", "전체자동 연결"], ["6", "노임단가 연결"], ["5", "자재단가 연결"], ["101", "견적단가 연결"], ["21", "표준단가 연결"], ["105", "기계경비 연결"], ["104", "단가산출 연결"], ["103", "일위대가 연결"], ]; function open(state) { if (!tags[state.view]) throw Error("내역서·일위대가·기계경비 화면에서 자동연결하세요."); EstApp.showDialog( "데이타 자동연결", `
`, ); } function apply(state) { const choice = document.querySelector('#dialog-content [name="al-choice"]').value, overwrite = document.querySelector('#dialog-content [name="al-over"]').checked; const ask = choice === "unlink" ? "데이타를 연결을 끊을까요?" : choice === "all" ? "전체 데이타를 연결 시킬까요?" : null; if (ask && !confirm(ask)) return; let count; EstApp.change((project) => (count = run(project, state.view, choice, overwrite))); EstApp.byId("autolink-result").textContent = choice === "unlink" ? `${count}행의 연결을 끊었습니다.` : `${count}행을 연결했습니다.`; } function handle(name, state) { if (name === "autolink") open(state); else if (name === "autolink-apply") apply(state); else return false; return true; } return { run, find, key, handle }; })();