Files
dbx-main/app/static/malaysia.js
T
king d56365b338 feat(malaysia): 입출고 일자별 낱개 수량 엑셀 다운로드
- '일괄 적용' 버튼명 '입력'으로 변경
- 입력 버튼 우측 '다운로드' 버튼 추가
- GET /malaysia/movements/export: 해당 일자/종류(IN/OUT) 낱개 합계를
  엑셀(A=사방넷코드, B=수량, C=이름)로 스트리밍
- db.daily_movement_totals(): 일자/종류별 낱개 합계 집계
- itemcode.sabangnet_code_map(): item_code → 사방넷 코드 매핑
- i18n 사전 '입력'/'다운로드' 추가, malaysia.js 캐시 버전 bump

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-12 10:36:10 +09:00

163 lines
6.0 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* 말레이시아 재고관리 — 화면 한글/영문 실시간 토글.
*
* - UI 고정 문구: 아래 KO_EN 사전으로 치환(요소 텍스트 = 한글 키).
* 대상 셀렉터는 UI 크롬(제목/헤더/버튼/라벨/배지/옵션/안내문)으로 한정 →
* 데이터 셀(상품코드/수량)은 건드리지 않음.
* - 상품명: 서버가 data-ko / data-en 을 함께 렌더 → 언어에 맞게 textContent 교체.
* - 선택값은 localStorage('mys_lang') 에 저장, 모든 화면 공통 적용.
*/
(function () {
"use strict";
var KO_EN = {
// 사이드바 메뉴 / 페이지 제목
"말레이시아 재고관리": "Malaysia Stock",
"입고/출고/조정 일괄 등록": "IN/OUT/ADJUST bulk",
// 탭 / 공통
"재고 현황": "Stock Status",
"입출고": "In / Out",
"일일 재고조사": "Daily Stocktake",
"창고": "Warehouse",
"날짜": "Date",
"메모": "Memo",
"상태": "Status",
// 재고현황
"전산 재고 현황 — 낱개 기준": "System Stock — by Single",
"현재고 = 입고 − 출고 + 조정 + 재고조사반영 (콤보는 낱개로 분해 반영됨)":
"Current = IN OUT + ADJUST + Stocktake (combos exploded to singles)",
"전산재고": "System Qty",
"조사수량": "Stocktake Qty",
"차이": "Diff",
"콤보 재고 (세트 단위)": "Combo Stock (by set)",
"재고조사 입력 없음": "No stocktake input",
"표시할 재고가 없습니다.": "No stock to display.",
"콤보 재고 입력이 없습니다.": "No combo stock input.",
// 입출고
"등록 옵션": "Options",
"이동 종류 (낱개)": "Type (single)",
"IN (입고)": "IN (In)",
"OUT (출고)": "OUT (Out)",
"ADJUST (조정 ±)": "ADJUST (±)",
"입력": "Input",
"다운로드": "Download",
"낱개 상품": "Single Products",
"콤보 상품": "Combo Products",
"이동 이력": "Movement History",
"전체": "All",
"날짜해제": "Clear date",
"이동 이력이 없습니다.": "No movements.",
// 재고조사 목록
"재고조사 생성": "New Stocktake",
"조사 날짜": "Date",
"생성": "Create",
"생성 후 상세에서 낱개/세트 수량을 입력하고 확정하세요.":
"After creating, enter single/set qty in detail and finalize.",
"조사 목록": "Stocktake List",
"열기": "Open",
"삭제": "Delete",
"재고조사가 없습니다.": "No stocktakes.",
"확정": "Final",
"취소": "Cancel",
"작성중": "Draft",
// 재고조사 상세
"재고조사": "Stocktake",
"◀◀ 조사 목록": "◀◀ List",
"확정시각": "Finalized at",
"입력 저장": "Save",
"확정 (전산 반영)": "Finalize (apply)",
"삭제 (슈퍼관리자)": "Delete (super)",
"최종 계산 (낱개 기준)": "Final Calc (by single)",
"total_qty = direct_qty(낱개 직접) + from_set_qty(콤보 분해)":
"total_qty = direct_qty (single) + from_set_qty (combo)",
"입력된 수량이 없습니다.": "No quantities entered.",
// 표 헤더(한글만)
"이동일": "Date",
};
var EN_KO = {};
Object.keys(KO_EN).forEach(function (k) { EN_KO[KO_EN[k]] = k; });
// 부분치환용 키 — 긴 키부터(부분 매칭 충돌 방지)
var RICH_KEYS = Object.keys(KO_EN).sort(function (a, b) { return b.length - a.length; });
// 헤더/사이드바처럼 .mys 밖이면서 KO 문구가 다른 텍스트와 섞인 요소.
// 사이드바는 현재 활성(말레이시아) 항목만 번역 → 다른 메뉴는 그대로 유지.
var RICH_SEL = [
".erp-topbar-title h1",
".erp-topbar-title p",
".erp-sidebar-item.is-active .erp-sidebar-label",
].join(",");
function applyRich(lang) {
document.querySelectorAll(RICH_SEL).forEach(function (el) {
if (el.getAttribute("data-o") === null) {
el.setAttribute("data-o", (el.textContent || "").trim());
}
var ko = el.getAttribute("data-o");
if (lang !== "en") { el.textContent = ko; return; }
var s = ko;
RICH_KEYS.forEach(function (k) {
if (s.indexOf(k) !== -1) s = s.split(k).join(KO_EN[k]);
});
el.textContent = s;
});
}
var SEL = [
".mys h1", ".mys h2", ".mys h3",
".mys th",
".mys label > span",
".mys button",
".mys a.erp-btn",
".mys .erp-muted",
".mys option",
".mys .erp-badge",
".mys .i18n",
].join(",");
function applyLang(lang) {
// 1) 상품명(한/영 동시 보유)
document.querySelectorAll(".mys [data-ko][data-en]").forEach(function (el) {
el.textContent = (lang === "en") ? el.getAttribute("data-en")
: el.getAttribute("data-ko");
});
// 2) UI 고정 문구
document.querySelectorAll(SEL).forEach(function (el) {
// 자식 요소가 있는 컨테이너는 건너뜀(.i18n 로 명시한 경우만 허용)
if (el.children.length && !el.classList.contains("i18n")) return;
if (el.hasAttribute("data-ko") && el.hasAttribute("data-en")) return; // 이미 처리됨
if (el.getAttribute("data-o") === null) {
el.setAttribute("data-o", (el.textContent || "").trim());
}
var ko = el.getAttribute("data-o");
if (lang === "en") {
if (KO_EN[ko] !== undefined) el.textContent = KO_EN[ko];
} else {
el.textContent = ko;
}
});
// 3) 헤더/사이드바(부분 치환)
applyRich(lang);
// 4) 토글 버튼 라벨
var btn = document.getElementById("mys-lang-toggle");
if (btn) btn.textContent = (lang === "en") ? "한글" : "ENG";
document.documentElement.setAttribute("data-mys-lang", lang);
}
function current() {
return localStorage.getItem("mys_lang") === "en" ? "en" : "ko";
}
function toggle() {
var next = current() === "en" ? "ko" : "en";
localStorage.setItem("mys_lang", next);
applyLang(next);
}
document.addEventListener("DOMContentLoaded", function () {
var btn = document.getElementById("mys-lang-toggle");
if (btn) btn.addEventListener("click", toggle);
applyLang(current());
});
})();