feat:품목관리 수식 산출 입력폼에 제품모델/설치타입/마감타입 추가

- 제품모델(KSS01~KDSS01), 설치타입(벽면형/측면형/혼합형), 마감타입(SUS/EGI) select 추가
- FG 코드 파싱으로 입력폼 자동 세팅 (FG-KQTS01-벽면형-SUS → 각 필드 매핑)
- calculateFormula() API 호출 시 새 파라미터 전송
- ItemManagementApiController에서 product_model/installation_type/finishing_type 수신 처리

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-20 15:41:14 +09:00
parent 15f83d0367
commit df3feeade9
2 changed files with 78 additions and 3 deletions

View File

@@ -75,7 +75,18 @@ public function calculateFormula(Request $request, int $id): JsonResponse
'MP' => in_array($mp, ['single', 'three']) ? $mp : 'single',
];
$formulaService = new FormulaApiService();
// 제품모델/설치타입/마감타입 (입력값이 있으면 전달)
if ($request->filled('product_model')) {
$variables['product_model'] = $request->input('product_model');
}
if ($request->filled('installation_type')) {
$variables['installation_type'] = $request->input('installation_type');
}
if ($request->filled('finishing_type')) {
$variables['finishing_type'] = $request->input('finishing_type');
}
$formulaService = new FormulaApiService;
$result = $formulaService->calculateBom(
$item->code,
$variables,

View File

@@ -61,7 +61,7 @@ class="bom-tab px-3 py-1.5 text-xs font-medium rounded-md bg-gray-100 text-gray-
<!-- 수식 산출 입력 (가변사이즈 품목 선택 시에만 표시) -->
<div id="formula-input-panel" style="display:none;" class="p-4 bg-gray-50 border-b border-gray-200">
<div class="flex items-end gap-3">
<div class="flex items-end gap-3 flex-wrap">
<div>
<label class="block text-xs text-gray-500 mb-1"> W (mm)</label>
<input type="number" id="input-width" value="1000" min="100" max="10000" step="1"
@@ -85,6 +85,36 @@ class="px-2 py-1.5 text-sm border border-gray-300 rounded focus:ring-2 focus:rin
<option value="three">삼상(380V)</option>
</select>
</div>
<div>
<label class="block text-xs text-gray-500 mb-1">제품모델</label>
<select id="input-product-model"
class="px-2 py-1.5 text-sm border border-gray-300 rounded focus:ring-2 focus:ring-blue-500 focus:outline-none">
<option value="KSS01">KSS01</option>
<option value="KSS02">KSS02</option>
<option value="KSE01">KSE01</option>
<option value="KWE01">KWE01</option>
<option value="KTE01">KTE01</option>
<option value="KQTS01">KQTS01</option>
<option value="KDSS01">KDSS01</option>
</select>
</div>
<div>
<label class="block text-xs text-gray-500 mb-1">설치타입</label>
<select id="input-installation-type"
class="px-2 py-1.5 text-sm border border-gray-300 rounded focus:ring-2 focus:ring-blue-500 focus:outline-none">
<option value="벽면형">벽면형</option>
<option value="측면형">측면형</option>
<option value="혼합형">혼합형</option>
</select>
</div>
<div>
<label class="block text-xs text-gray-500 mb-1">마감</label>
<select id="input-finishing-type"
class="px-2 py-1.5 text-sm border border-gray-300 rounded focus:ring-2 focus:ring-blue-500 focus:outline-none">
<option value="SUS">SUS</option>
<option value="EGI">EGI</option>
</select>
</div>
<button type="button" id="btn-calculate" onclick="calculateFormula()"
class="px-4 py-1.5 text-sm font-medium text-white bg-blue-600 rounded hover:bg-blue-700 transition-colors">
산출
@@ -334,6 +364,30 @@ function hideFormulaTab() {
switchBomTab('static');
}
// ── FG 코드 파싱 → 입력폼 자동 세팅 ──
// FG-KQTS01-벽면형-SUS → { model: 'KQTS01', installation: '벽면형', finishing: 'SUS' }
// 파싱 실패 시 기본값 유지 (추후 FG 코드 형식 변경 대비)
function parseFgCode(code) {
if (!code) return null;
const parts = code.split('-');
// FG-{MODEL}-{INSTALLATION}-{FINISHING} 형식인 경우만 파싱
if (parts.length >= 4 && parts[0] === 'FG') {
return { model: parts[1], installation: parts[2], finishing: parts[3] };
}
return null;
}
function setSelectValue(selectId, value) {
const el = document.getElementById(selectId);
if (!el) return;
for (let i = 0; i < el.options.length; i++) {
if (el.options[i].value === value) {
el.selectedIndex = i;
return;
}
}
}
// ── 상세 로드 완료 후 FG 품목 감지 → 수식 산출 탭 표시 ──
document.body.addEventListener('htmx:afterSwap', function(event) {
if (event.detail.target.id === 'item-detail') {
@@ -347,6 +401,13 @@ function hideFormulaTab() {
currentItemId = meta.dataset.itemId;
currentItemCode = meta.dataset.itemCode;
if (meta.dataset.itemType === 'FG') {
// FG 코드에서 모델/설치타입/마감타입 파싱하여 입력폼 자동 세팅
const parsed = parseFgCode(currentItemCode);
if (parsed) {
setSelectValue('input-product-model', parsed.model);
setSelectValue('input-installation-type', parsed.installation);
setSelectValue('input-finishing-type', parsed.finishing);
}
showFormulaTab();
calculateFormula();
} else {
@@ -364,6 +425,9 @@ function hideFormulaTab() {
const height = parseInt(document.getElementById('input-height').value) || 1000;
const qty = parseInt(document.getElementById('input-qty').value) || 1;
const mp = document.getElementById('input-mp').value || 'single';
const productModel = document.getElementById('input-product-model').value || 'KSS01';
const installationType = document.getElementById('input-installation-type').value || '벽면형';
const finishingType = document.getElementById('input-finishing-type').value || 'SUS';
if (width < 100 || width > 10000 || height < 100 || height > 10000) {
alert('폭과 높이는 100~10000 범위로 입력하세요.');
@@ -380,7 +444,7 @@ function hideFormulaTab() {
'Accept': 'application/json',
'X-CSRF-TOKEN': csrfToken,
},
body: JSON.stringify({ width, height, qty, mp }),
body: JSON.stringify({ width, height, qty, mp, product_model: productModel, installation_type: installationType, finishing_type: finishingType }),
})
.then(res => {
if (!res.ok) {