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

187 lines
6.9 KiB
JavaScript

const EstBusinessActions = (() => {
let purpose = "",
documentKey;
const currentRound = () =>
EstApp.state.project.progress.find((round) => round.id === EstApp.state.roundId);
function numeric(value) {
const n = Number(value);
if (!Number.isFinite(n) || Math.abs(n) > Number.MAX_SAFE_INTEGER)
throw Error("유효한 수치를 입력하세요.");
return n;
}
function change(node) {
const { state } = EstApp;
if (node.dataset.option === "EscDesignTotal") {
const value = numeric(node.value);
if (value < 0) throw Error("조사 도급액은 0 이상입니다.");
EstApp.change(() => (state.project.options.EscDesignTotal = value), false);
return true;
}
if (node.dataset.escAuto !== undefined) {
EstApp.change(
() =>
(state.project.tables.EstMainDat[Number(node.dataset.escAuto)].EscAuto = node.checked),
false,
);
return true;
}
if (node.id === "progress-components" || node.id === "progress-digits") {
const round = currentRound();
if (round.locked) throw Error("확정 회차입니다.");
const value = node.id === "progress-components" ? node.checked : numeric(node.value);
if (node.id === "progress-digits" && (!Number.isInteger(value) || value < 0 || value > 4))
throw Error("금액 소수자리는 0~4입니다.");
EstApp.change(
() =>
(round[node.id === "progress-components" ? "separateComponents" : "amountDigits"] =
value),
false,
);
return true;
}
return false;
}
async function handle(name) {
const { state } = EstApp,
project = state.project,
round = currentRound();
if (name === "unlock-round") {
if (confirm("이 회차와 이후 회차의 확정을 해제하시겠습니까? 입력값은 유지됩니다."))
EstApp.change(() => (state.project = EstProgress.unlock(project, round.id)), false);
} else if (name === "delete-round") {
if (round.locked) throw Error("확정을 먼저 해제하세요.");
if (project.progress.at(-1) !== round) throw Error("마지막 회차부터 삭제하세요.");
if (confirm("선택한 기성 회차를 삭제하시겠습니까?"))
EstApp.change(() => {
project.progress.pop();
state.roundId = project.progress.at(-1)?.id;
}, false);
} else if (name === "rename-round") {
if (round.locked) throw Error("확정을 먼저 해제하세요.");
EstActions.form(
"기성 회차 이름",
[{ name: "name", label: "회차 이름", value: round.name }],
(values) => {
if (
!values.name.trim() ||
project.progress.some((item) => item !== round && item.name === values.name)
)
throw Error("회차 이름은 비어 있거나 중복될 수 없습니다.");
EstApp.change(() => (round.name = values.name.trim()), false);
},
);
} else if (name === "fill-progress") {
if (round.locked) throw Error("확정 회차입니다.");
EstActions.form(
"기성 일괄 입력",
[
{
name: "prefix",
label: "대상",
value: "Gum",
choices: [
["Gum", "금회기성"],
["Sa", "금회사정"],
],
},
{
name: "mode",
label: "방법",
value: "ratio",
choices: [
["ratio", "비율 입력"],
["full", "전량"],
],
},
{ name: "ratio", label: "비율 %", type: "number", value: 100 },
],
(values) =>
EstApp.change(() => {
const value = numeric(values.ratio);
project.tables.EstMainDat.forEach((row, index) => {
if (
Number(row.Level) > 0 ||
Number(row.CalcIndex) >= 2 ||
[54, 55, 58, 59, 62, 67].includes(Number(row.LinkIndex))
)
return;
if (values.mode === "full" && Number(row.LinkIndex) === 57) return;
const key = EstBusiness.rowKey(row, index);
round.inputs[key] ||= {};
round.inputs[key][values.prefix + "Mode"] =
values.mode === "full" ? "quantity" : "ratio";
round.inputs[key][values.prefix] =
values.mode === "full" ? Number(row.GN) || 0 : value;
});
}, false),
);
} else if (name === "load-progress-exclusion") {
const locked = project.progress.filter((round) => round.locked && round.result);
if (!locked.length) throw Error("확정한 기성 회차가 없습니다.");
EstActions.form(
"기성 누계수량 불러오기",
[
{
name: "id",
label: "기성 회차",
value: locked.at(-1).id,
choices: locked.map((round) => [round.id, round.name]),
},
],
(values) =>
EstApp.change(() => {
const result = locked.find((round) => round.id === values.id).result;
const rows = new Map(
result.rows.map((row, index) => [EstBusiness.rowKey(row, index), row]),
);
project.tables.EstMainDat.forEach(
(row, index) =>
(row.EscProgress = Number(rows.get(EstBusiness.rowKey(row, index))?.TotalGN) || 0),
);
}, false),
);
} else if (name === "load-contract" || name === "load-bid") {
purpose = name;
documentKey = state.documentKey;
document.getElementById("business-file").click();
}
}
function install() {
const input = document.createElement("input");
input.type = "file";
input.id = "business-file";
input.accept = ".json,.estx";
input.hidden = true;
document.body.append(input);
input.addEventListener("change", async () => {
try {
const file = input.files[0];
if (!file) return;
const raw = /\.estx$/i.test(file.name)
? await EstApp.api("/api/import?name=" + encodeURIComponent(file.name), {
method: "POST",
body: await file.arrayBuffer(),
})
: JSON.parse(await file.text());
const incoming = EstModel.legacy(raw);
if (documentKey !== EstApp.state.documentKey)
throw Error("문서가 변경되어 불러오기를 취소했습니다.");
EstApp.change(
() =>
(EstApp.state.project =
purpose === "load-contract"
? EstBusiness.importContract(EstApp.state.project, incoming)
: EstBusiness.importBid(EstApp.state.project, incoming)),
false,
);
} catch (error) {
EstApp.state.notice = error.message;
EstApp.render();
} finally {
input.value = "";
}
});
}
return { handle, change, install };
})();