- 고른 내역 행을 차수 하나의 놓을 행부터 복사 - 수량·단가금액·명칭규격 고르기, 설계변경 상단/하단, 행 금액 다시 셈 - 내역서 도구줄과 연차 화면에 단추 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
114 lines
5.7 KiB
JavaScript
114 lines
5.7 KiB
JavaScript
// 원본 연차공사 「데이타 복사 옵션」(TfrmMultiDataCopyMethod btnApply 0xedaba4 → TDataCopyMulti eedc54 — spec_pb2 §1):
|
|
// 내역서 행을 골라 차수 하나의 놓을 행부터 차례로 옮긴다. 복사방법 = 덮어쓰기 · 열 삽입후 내용복사(놓을 자리에 빈 행을 넣어
|
|
// 모든 차수가 한 줄 밀림). 복사내용 = 명칭·규격(Name·Size·Unite) · 수량(GN) · 단가·금액(TU·TC·NU·NC·GU·GC·JU·JC·SU·SC).
|
|
// 설계변경 내역이면 상단(당초 = 「_」 짝 칸) / 하단(변경 = 지금 값). 고른 차수 줄이 없으면 지금 내역 줄을 바탕으로 하고,
|
|
// 행마다 금액을 수량×단가로 다시 셈(f1a078). 끝 행을 넘는 나머지는 버림. 코드·연결 등 다른 칸은 그대로.
|
|
const EstAnnualCopy = (() => {
|
|
const num = (v) => Number(v) || 0;
|
|
const NAME = ["Name", "Size", "Unite"],
|
|
COST = ["TU", "TC", "NU", "NC", "GU", "GC", "JU", "JC", "SU", "SC"];
|
|
const KEY = "est-annual-copy";
|
|
|
|
function apply(project, { sources, target, year, insert, name, gn, cost, top }) {
|
|
const main = project.tables.EstMainDat,
|
|
chosen = project.annual?.[year];
|
|
if (!chosen) throw Error("입력할 차수를 선택하세요.");
|
|
if (!(target >= 0 && target <= main.length)) throw Error("놓을 행이 없습니다.");
|
|
const picked = sources.map((i) => structuredClone(main[i])).filter(Boolean);
|
|
if (insert) {
|
|
main.splice(target, 0, {});
|
|
for (const y of project.annual) if (Array.isArray(y.rows)) y.rows.splice(target, 0, null);
|
|
}
|
|
chosen.rows ||= [];
|
|
let count = 0;
|
|
picked.forEach((src, k) => {
|
|
const t = target + k;
|
|
if (t >= main.length) return;
|
|
const read = (f) => (top && src[f + "_"] != null ? src[f + "_"] : src[f]);
|
|
const row = chosen.rows[t] ? { ...chosen.rows[t] } : structuredClone(main[t]);
|
|
if (name) for (const f of NAME) row[f] = read(f) ?? "";
|
|
if (gn) row.GN = num(read("GN"));
|
|
if (cost) for (const f of COST) row[f] = num(read(f));
|
|
// 행 금액 계산: 비목 금액 = 수량 × 비목 단가, 합계 = 비목 합
|
|
for (const p of ["N", "G", "J", "S"])
|
|
row[p + "C"] = Math.trunc(num(row.GN) * num(row[p + "U"]));
|
|
row.TC = ["NC", "GC", "JC", "SC"].reduce((s, f) => s + num(row[f]), 0);
|
|
row.TU = ["NU", "GU", "JU", "SU"].reduce((s, f) => s + num(row[f]), 0);
|
|
while (chosen.rows.length < t) chosen.rows.push(null);
|
|
chosen.rows[t] = row;
|
|
count++;
|
|
});
|
|
return count;
|
|
}
|
|
|
|
// 번호 목록 "1-3,5" → 0부터 차례
|
|
function parse(text) {
|
|
const out = [];
|
|
for (const part of String(text)
|
|
.split(/[,\s]+/)
|
|
.filter(Boolean)) {
|
|
const [a, b] = part.split("-").map(Number);
|
|
if (!Number.isInteger(a)) throw Error(`행 번호 오류: ${part}`);
|
|
for (let i = a; i <= (Number.isInteger(b) ? b : a); i++) out.push(i - 1);
|
|
}
|
|
return out;
|
|
}
|
|
|
|
function dialog(state) {
|
|
const project = state.project,
|
|
{ esc } = EstApp;
|
|
if (!project.annual?.length) throw Error("차수를 먼저 추가하세요.");
|
|
const saved = JSON.parse(localStorage.getItem(KEY) || "{}"),
|
|
o = { insert: false, gn: true, cost: true, name: true, ...saved };
|
|
const picked = state.view === "EstMainDat" ? [...state.selection].sort((a, b) => a - b) : [];
|
|
const range = picked.length ? picked.map((i) => i + 1).join(",") : "1";
|
|
const change = project.options.Mode === "설계변경";
|
|
const check = (k, label) =>
|
|
`<label><input type="checkbox" data-ac="${k}" ${o[k] ? "checked" : ""}> ${label}</label>`;
|
|
EstApp.showDialog(
|
|
"데이타 복사 옵션",
|
|
`<div class="form-fields"><label>복사할 내역 행(예 1-3,5) <input data-ac="rows" value="${esc(range)}"></label><label>놓을 행 번호 <input type="number" min="1" data-ac="target" value="${(picked[0] ?? 0) + 1}"></label>` +
|
|
`<label>복사방법 <select data-ac="insert"><option value="0">덮어쓰기</option><option value="1" ${o.insert ? "selected" : ""}>열 삽입후 내용복사</option></select></label>` +
|
|
`<fieldset><legend>복사내용</legend>${check("gn", "수량")}${check("cost", "단가, 금액")}${check("name", "명칭, 규격")}</fieldset>` +
|
|
(change
|
|
? `<label>설계변경 <select data-ac="top"><option value="1">상단데이타 복사</option><option value="0">하단데이타 복사</option></select></label>`
|
|
: "") +
|
|
`<fieldset><legend>복사위치</legend>${project.annual.map((y, i) => `<label><input type="radio" name="ac-year" value="${i}"> ${esc(y.name)}</label>`).join("")}</fieldset></div>` +
|
|
`<button data-action="annual-copy-apply">적 용</button>`,
|
|
);
|
|
}
|
|
function run(state) {
|
|
const box = document.getElementById("dialog-content"),
|
|
get = (k) => box.querySelector(`[data-ac="${k}"]`);
|
|
const year = box.querySelector('[name="ac-year"]:checked');
|
|
if (!year) throw Error("입력할 차수를 선택하세요.");
|
|
const opts = {
|
|
insert: get("insert").value === "1",
|
|
gn: get("gn").checked,
|
|
cost: get("cost").checked,
|
|
name: get("name").checked,
|
|
};
|
|
localStorage.setItem(KEY, JSON.stringify(opts));
|
|
let count = 0;
|
|
EstApp.change(
|
|
(project) =>
|
|
(count = apply(project, {
|
|
...opts,
|
|
sources: parse(get("rows").value),
|
|
target: Number(get("target").value) - 1,
|
|
year: Number(year.value),
|
|
top: get("top")?.value === "1",
|
|
})),
|
|
);
|
|
EstApp.byId("dialog").close();
|
|
state.notice = `${count}행을 복사했습니다.`;
|
|
}
|
|
function handle(name, state) {
|
|
if (name === "annual-copy") dialog(state);
|
|
else if (name === "annual-copy-apply") run(state);
|
|
else return false;
|
|
return true;
|
|
}
|
|
return { apply, parse, handle };
|
|
})();
|