Update remicon_cost_app.html with advanced specification selection features
This commit is contained in:
@@ -364,7 +364,11 @@
|
||||
<div class="modal-body">
|
||||
<div class="field full">
|
||||
<label for="mSpec">규격명</label>
|
||||
<input id="mSpec" placeholder="예: 25-24-150" />
|
||||
<select id="mSpec"></select>
|
||||
<div class="row" style="margin-top:6px;">
|
||||
<input id="mNewSpec" placeholder="신규 규격 입력 (예: 20-55-600)" />
|
||||
<button type="button" class="sub" id="addSpecBtn">규격 추가</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="field full">
|
||||
<label for="mPriceSetId">적용 단가</label>
|
||||
@@ -527,6 +531,16 @@
|
||||
const SELECTED_PRICE_SET_KEY = "remicon_selected_price_set_v1";
|
||||
const MIX_DRAFT_KEY = "remicon_mix_draft_v1";
|
||||
const PRICE_DRAFT_KEY = "remicon_price_draft_v1";
|
||||
const CUSTOM_SPECS_KEY = "remicon_custom_specs_v1";
|
||||
const PRESET_SPECS = [
|
||||
"25-27-600",
|
||||
"25-30-600",
|
||||
"25-35-600",
|
||||
"20-40-600",
|
||||
"20-45-600",
|
||||
"20-50-600",
|
||||
"20-60-600"
|
||||
];
|
||||
|
||||
const DEFAULT_PRICE_SETS = [
|
||||
{
|
||||
@@ -690,6 +704,16 @@
|
||||
}
|
||||
}
|
||||
|
||||
function getCustomSpecs() {
|
||||
return loadJsonArray(CUSTOM_SPECS_KEY)
|
||||
.map((x) => String(x || "").trim())
|
||||
.filter((x) => x.length > 0);
|
||||
}
|
||||
|
||||
function saveCustomSpecs(specs) {
|
||||
localStorage.setItem(CUSTOM_SPECS_KEY, JSON.stringify(specs));
|
||||
}
|
||||
|
||||
function formatDateTime(iso) {
|
||||
if (!iso) return "-";
|
||||
const d = new Date(iso);
|
||||
@@ -1032,6 +1056,58 @@
|
||||
.sort((a, b) => a.spec.localeCompare(b.spec, "ko-KR", { numeric: true, sensitivity: "base" }));
|
||||
}
|
||||
|
||||
function renderSpecDataList(selectedValue = "") {
|
||||
const specSelect = document.getElementById("mSpec");
|
||||
if (!specSelect) return;
|
||||
specSelect.innerHTML = "";
|
||||
const dynamicSpecs = uniqueLatestSpecs().map(({ spec }) => spec);
|
||||
const customSpecs = getCustomSpecs();
|
||||
const mergedSpecs = [...new Set([...PRESET_SPECS, ...customSpecs, ...dynamicSpecs])]
|
||||
.sort((a, b) => a.localeCompare(b, "ko-KR", { numeric: true, sensitivity: "base" }));
|
||||
const placeholder = document.createElement("option");
|
||||
placeholder.value = "";
|
||||
placeholder.textContent = "규격 선택";
|
||||
specSelect.appendChild(placeholder);
|
||||
mergedSpecs.forEach((spec) => {
|
||||
const opt = document.createElement("option");
|
||||
opt.value = spec;
|
||||
opt.textContent = spec;
|
||||
specSelect.appendChild(opt);
|
||||
});
|
||||
const target = selectedValue || "";
|
||||
if (target && !mergedSpecs.includes(target)) {
|
||||
const custom = document.createElement("option");
|
||||
custom.value = target;
|
||||
custom.textContent = target;
|
||||
specSelect.appendChild(custom);
|
||||
}
|
||||
specSelect.value = target;
|
||||
}
|
||||
|
||||
function addCustomSpec() {
|
||||
const input = document.getElementById("mNewSpec");
|
||||
if (!input) return;
|
||||
const next = String(input.value || "").trim();
|
||||
if (!next) {
|
||||
alert("추가할 규격을 입력하세요.");
|
||||
return;
|
||||
}
|
||||
const all = [...new Set([...PRESET_SPECS, ...getCustomSpecs(), ...uniqueLatestSpecs().map((x) => x.spec)])];
|
||||
if (all.includes(next)) {
|
||||
renderSpecDataList(next);
|
||||
input.value = "";
|
||||
return;
|
||||
}
|
||||
const updated = [...getCustomSpecs(), next]
|
||||
.filter((x) => x)
|
||||
.sort((a, b) => a.localeCompare(b, "ko-KR", { numeric: true, sensitivity: "base" }));
|
||||
saveCustomSpecs(updated);
|
||||
renderSpecDataList(next);
|
||||
document.getElementById("mSpec").value = next;
|
||||
saveDraft(MIX_DRAFT_KEY, getMixDraftPayload());
|
||||
input.value = "";
|
||||
}
|
||||
|
||||
function renderSpecList() {
|
||||
const area = document.getElementById("specListArea");
|
||||
const items = uniqueLatestSpecs();
|
||||
@@ -1379,6 +1455,7 @@
|
||||
mixModalTitle.textContent = "배합표 수정";
|
||||
saveMixBtn.textContent = "수정 저장";
|
||||
|
||||
renderSpecDataList(entry.spec || "");
|
||||
document.getElementById("mSpec").value = entry.spec || "";
|
||||
document.getElementById("mWaterCementRatio").value = toNum(entry.mixMeta?.waterCementRatio);
|
||||
document.getElementById("mFineAggRatio").value = toNum(entry.mixMeta?.fineAggRatio);
|
||||
@@ -1409,6 +1486,7 @@
|
||||
mixModalTitle.textContent = "배합표 등록";
|
||||
saveMixBtn.textContent = "저장";
|
||||
clearModalFields();
|
||||
renderSpecDataList(selectedSpec || "");
|
||||
document.getElementById("mSpec").value = selectedSpec || "";
|
||||
renderMixPriceSetSelect(localStorage.getItem(SELECTED_PRICE_SET_KEY) || "");
|
||||
applyMixDraft();
|
||||
@@ -1498,6 +1576,16 @@
|
||||
function applyMixDraft() {
|
||||
const draft = loadDraft(MIX_DRAFT_KEY);
|
||||
if (!draft) return;
|
||||
const draftSpec = String(draft.mSpec || "").trim();
|
||||
if (draftSpec) {
|
||||
const specSelect = document.getElementById("mSpec");
|
||||
if (specSelect && ![...specSelect.options].some((o) => o.value === draftSpec)) {
|
||||
const opt = document.createElement("option");
|
||||
opt.value = draftSpec;
|
||||
opt.textContent = draftSpec;
|
||||
specSelect.appendChild(opt);
|
||||
}
|
||||
}
|
||||
Object.entries(draft).forEach(([id, val]) => {
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.value = val ?? "";
|
||||
@@ -2234,6 +2322,13 @@
|
||||
document.getElementById("goPriceBtn").addEventListener("click", () => switchPage("price"));
|
||||
document.getElementById("refreshBtn").addEventListener("click", renderMain);
|
||||
document.getElementById("newMixBtn").addEventListener("click", openModal);
|
||||
document.getElementById("addSpecBtn").addEventListener("click", addCustomSpec);
|
||||
document.getElementById("mNewSpec").addEventListener("keydown", (e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
addCustomSpec();
|
||||
}
|
||||
});
|
||||
document.getElementById("closeModalBtn").addEventListener("click", closeModal);
|
||||
document.getElementById("cancelBtn").addEventListener("click", closeModal);
|
||||
document.getElementById("saveMixBtn").addEventListener("click", saveMixEntry);
|
||||
@@ -2256,12 +2351,13 @@
|
||||
});
|
||||
|
||||
[
|
||||
"mSpec", "mPriceSetId", "mWaterCementRatio", "mFineAggRatio", "mWater",
|
||||
"mPriceSetId", "mWaterCementRatio", "mFineAggRatio", "mWater",
|
||||
"mCement", "mSlag", "mWashedSand", "mCrushedSand", "mMm20", "mMm25", "mAdmixture", "mNote"
|
||||
].forEach((id) => {
|
||||
const el = document.getElementById(id);
|
||||
if (el) el.addEventListener("input", () => saveDraft(MIX_DRAFT_KEY, getMixDraftPayload()));
|
||||
});
|
||||
document.getElementById("mSpec").addEventListener("change", () => saveDraft(MIX_DRAFT_KEY, getMixDraftPayload()));
|
||||
|
||||
[
|
||||
"pYear", "pMonth", "pCementPrice", "pSlagPrice", "pWashedSandPrice", "pCrushedSandPrice",
|
||||
@@ -2295,4 +2391,4 @@
|
||||
init();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
Reference in New Issue
Block a user