Files
Aislo/tools/est-test/native-block-actions.js
T

277 lines
9.0 KiB
JavaScript

// REA popMainBlockCut, popMainBlockCopy, popMainBlockPaste, popMainBlockDel 및 블럭 범위 지정 (ActionBlockOneSet, 블럭시작/끝)
// 및 popMainSetStr (산출근거 주석 지정/해제), TFRMWONGABASE popupTotal (공사비역산 자리수 맞추기)
const EstBlockActions = (() => {
let blockStart = null;
let blockTable = null;
function setBlockStart(state) {
const rows = state.project.tables[state.view];
if (!rows) throw Error("현재 화면에서는 블럭을 지정할 수 없습니다.");
const selected = [...state.selection];
if (!selected.length) throw Error("블럭 시작 위치로 지정할 행을 선택하세요.");
blockStart = selected[0];
blockTable = state.view;
state.notice = `${blockStart + 1}행이 블럭 시작점으로 설정되었습니다. (블럭 끝 행을 선택 후 '블럭 끝'을 누르세요)`;
}
function setBlockEnd(state) {
const rows = state.project.tables[state.view];
if (!rows) throw Error("현재 화면에서는 블럭을 지정할 수 없습니다.");
if (blockStart == null || blockTable !== state.view) {
throw Error("먼저 '블럭 시작'을 지정하세요.");
}
const selected = [...state.selection];
if (!selected.length) throw Error("블럭 끝 위치로 지정할 행을 선택하세요.");
const blockEnd = selected[0];
const start = Math.min(blockStart, blockEnd);
const end = Math.max(blockStart, blockEnd);
state.selection.clear();
for (let i = start; i <= end; i++) {
state.selection.add(i);
}
state.notice = `${start + 1}행부터 ${end + 1}행까지 총 ${end - start + 1}개 행이 블럭으로 선택되었습니다.`;
blockStart = null;
blockTable = null;
}
function clearBlockSelection(state) {
state.selection.clear();
blockStart = null;
blockTable = null;
state.notice = "선택이 해제되었습니다.";
}
function selectAllRows(state) {
const rows = state.project.tables[state.view];
if (!rows) throw Error("현재 화면에서는 전체 선택을 할 수 없습니다.");
state.selection.clear();
for (let i = 0; i < rows.length; i++) {
state.selection.add(i);
}
state.notice = `전체 ${rows.length}개 행이 선택되었습니다.`;
}
function deleteBlockRows(state) {
const rows = state.project.tables[state.view];
if (!rows) throw Error("현재 화면에서는 블럭 삭제를 할 수 없습니다.");
const indexes = new Set([...state.selection]);
if (!indexes.size) throw Error("삭제할 블럭 행을 먼저 선택하세요.");
// 호표/기계경비 그룹이 있는 경우 호표 제목 행 포함 시 전체 호표 행 포함
if (["HeadMainDat", "CostMainDat", "MachMainDat"].includes(state.view)) {
for (const group of EstNative.groups(rows).values()) {
if (indexes.has(group.start)) {
for (let i = group.start; i < group.start + group.rows.length; i++) {
indexes.add(i);
}
}
}
}
const codes = new Set(
[...indexes]
.map((i) => rows[i]?.Code)
.filter(Boolean)
.map((c) => String(c).trim()),
);
const kind = Number(
Object.entries(EstNative.sourceTables).find(([, table]) => table === state.view)?.[0] ||
{ HeadMainDat: 103, CostMainDat: 104, MachMainDat: 105 }[state.view],
);
if (
kind &&
Object.entries(state.project.tables).some(([table, list]) =>
list.some((row, i) => {
if (table === state.view && indexes.has(i)) return false;
const rLink = Number(row.LinkIndex);
const rCode = row.Code ? String(row.Code).trim() : "";
return rLink === kind && rCode && codes.has(rCode);
}),
)
) {
throw Error("다른 항목에서 사용 중입니다. 연결을 먼저 해제하세요.");
}
if (!confirm(`${indexes.size}개 행을 블럭 삭제하시겠습니까?`)) return;
EstApp.change(() => {
[...indexes].sort((a, b) => b - a).forEach((i) => rows.splice(i, 1));
state.selection.clear();
blockStart = null;
blockTable = null;
});
}
function toggleCostComment(state) {
// REA popMainSetStr: 단가산출 산출근거 행을 주석(Index = -1)으로 지정 또는 일반 산출식으로 복원
const rows = state.project.tables.CostMainDat;
const indices = [...state.selection].sort((a, b) => a - b);
if (state.view !== "CostMainDat" || !rows) {
throw Error("단가산출 화면에서만 산출근거 행을 주석으로 지정할 수 있습니다.");
}
if (!indices.length || indices.some((i) => !rows[i])) {
throw Error("주석으로 지정하거나 해제할 산출근거 행을 선택하세요.");
}
const plans = [];
for (const index of indices) {
const row = rows[index];
const curIndex = Number(row.Index) || 0;
if (curIndex > 0) {
throw Error(
`행 ${index + 1}: 호표 제목 행은 주석으로 지정할 수 없습니다. 상세 산출근거 행을 선택하세요.`,
);
}
if (curIndex === -20) {
throw Error(`행 ${index + 1}: 소계 구분선 행은 주석으로 지정할 수 없습니다.`);
}
const curSCheck = Number(row.SCheck) || 0;
const isComment = curIndex === -1 || curSCheck === -1;
if (isComment) {
// 이미 주석인 행 -> 복원
let restoreIndex = 0;
if (row._origIndex !== undefined) {
restoreIndex = Number(row._origIndex);
} else if (row.Index_ !== undefined) {
restoreIndex = Number(row.Index_);
}
let restoreSCheck = null;
if (row._origSCheck !== undefined) {
restoreSCheck = Number(row._origSCheck);
} else if (row.SCheck_ !== undefined) {
restoreSCheck = Number(row.SCheck_);
} else if ([-1, -2, -3, -5].includes(Number(row.OCheck))) {
restoreSCheck = Number(row.OCheck);
}
plans.push({
index,
row,
isComment: false,
restoreIndex,
restoreSCheck,
});
} else {
// 일반 상세 행 또는 비목 행(-2, -3, -5 등) -> 주석(-1)으로 전환
plans.push({
index,
row,
isComment: true,
origIndex: curIndex,
origSCheck: row.SCheck !== undefined ? Number(row.SCheck) : null,
});
}
}
EstApp.change(() => {
for (const p of plans) {
if (p.isComment) {
p.row._origIndex = p.origIndex;
if (p.origSCheck !== null) {
p.row._origSCheck = p.origSCheck;
}
p.row.Index = -1;
p.row.SCheck = -1;
} else {
delete p.row._origIndex;
delete p.row._origSCheck;
p.row.Index = p.restoreIndex;
if (p.restoreSCheck !== null) {
p.row.SCheck = p.restoreSCheck;
} else {
delete p.row.SCheck;
}
}
}
});
}
function alignWongaTotalAction(state) {
// REA TFRMWONGABASE popupTotal: 공사비역산 자리수 맞추기
const rows = state.project.tables.Wonga;
if (!rows || !rows.length) {
throw Error("원가계산서 자료가 없습니다.");
}
const targetRow = rows.find((r) => Number(r.LinkIndex) === 55);
const curTotal = targetRow ? Number(targetRow.Cost) || 0 : 0;
EstActions.form(
"공사비역산 자리수 맞추기",
[
{
name: "targetCost",
label: "목표 도급공사비 (원)",
type: "number",
value: curTotal,
},
{
name: "unitDigits",
label: "단단위 절하 기준",
value: "3",
choices: [
["0", "원 단위 (절하 없음)"],
["1", "십원 단위 (10원 절하)"],
["2", "백원 단위 (100원 절하)"],
["3", "천원 단위 (1,000원 절하)"],
["4", "만원 단위 (10,000원 절하)"],
],
},
],
({ targetCost, unitDigits }) => {
EstApp.change(() => {
EstWonga.alignTotal(rows, targetCost, unitDigits);
state.project.options.TotalFix = true;
});
},
);
}
function handle(name, state) {
if (name === "block-start") {
setBlockStart(state);
return true;
}
if (name === "block-end") {
setBlockEnd(state);
return true;
}
if (name === "block-clear") {
clearBlockSelection(state);
return true;
}
if (name === "select-all-rows") {
selectAllRows(state);
return true;
}
if (name === "block-del") {
deleteBlockRows(state);
return true;
}
if (name === "toggle-cost-comment") {
toggleCostComment(state);
return true;
}
if (name === "align-wonga-total") {
alignWongaTotalAction(state);
return true;
}
return false;
}
return {
setBlockStart,
setBlockEnd,
clearBlockSelection,
selectAllRows,
deleteBlockRows,
toggleCostComment,
alignWongaTotalAction,
handle,
};
})();