diff --git a/resources/views/business/pages/financial-operations/labor-expenses.blade.php b/resources/views/business/pages/financial-operations/labor-expenses.blade.php index f3762dc7..7f10951e 100644 --- a/resources/views/business/pages/financial-operations/labor-expenses.blade.php +++ b/resources/views/business/pages/financial-operations/labor-expenses.blade.php @@ -887,6 +887,11 @@ return moneyFormatter.format(value); }; + const amountInputText = (value) => { + const number = Number(value); + return Number.isFinite(number) ? number.toFixed(2) : String(value); + }; + const headerKeys = () => { const headerRow = table.tHead?.rows?.[table.tHead.rows.length - 1]; return [...(headerRow?.cells || [])] @@ -996,7 +1001,7 @@ input.setAttribute('aria-label', `${field.label},第 ${index + 1} 行`); if (field.kind === 'number') { input.type = 'number'; - input.step = 'any'; + input.step = '0.01'; input.inputMode = 'decimal'; input.classList.remove('labor-expense-input--text'); input.classList.add('labor-expense-input--number'); @@ -1004,8 +1009,10 @@ } const storedValue = rows[index]?.[field.key]; if (storedValue !== '' && storedValue !== null && storedValue !== undefined) { - input.value = String(storedValue); - cell.dataset.exportValue = String(storedValue); + input.value = field.kind === 'number' ? amountInputText(storedValue) : String(storedValue); + cell.dataset.exportValue = field.kind === 'number' && Number.isFinite(Number(storedValue)) + ? moneyFormatter.format(Number(storedValue)) + : String(storedValue); } cell.appendChild(input); return cell; @@ -1160,6 +1167,26 @@ markDirty(); }); + tbody.addEventListener('change', (event) => { + const input = event.target.closest('[data-labor-field]'); + if (!input) return; + const field = fieldMap[input.dataset.laborField]; + if (field?.kind !== 'number') return; + const parsed = Number(input.value); + if (input.value.trim() === '' || !Number.isFinite(parsed)) return; + + const rowElement = input.closest('tr[data-labor-row]'); + const index = Number(rowElement?.dataset.laborRow); + const formatted = parsed.toFixed(2); + input.value = formatted; + input.closest('td').dataset.exportValue = moneyFormatter.format(parsed); + if (Number.isInteger(index) && rows[index]) rows[index][field.key] = formatted; + if (Number.isInteger(index) && rowElement) { + updateOutputs(rowElement, index); + updateSummary(); + } + }); + tbody.addEventListener('click', (event) => { const remove = event.target.closest('[data-labor-remove]'); if (!remove) return; diff --git a/tests/Feature/Business/LaborExpensePageAccessTest.php b/tests/Feature/Business/LaborExpensePageAccessTest.php index d2cff6ec..9995f2c8 100644 --- a/tests/Feature/Business/LaborExpensePageAccessTest.php +++ b/tests/Feature/Business/LaborExpensePageAccessTest.php @@ -146,6 +146,18 @@ class LaborExpensePageAccessTest extends FeatureTestCase "const fixedStartColumns = ['A', 'B', 'C', 'D', 'E'];", $html ); + $this->assertStringContainsString( + 'const amountInputText = (value) => {', + $html + ); + $this->assertStringContainsString( + "input.value = field.kind === 'number' ? amountInputText(storedValue) : String(storedValue);", + $html + ); + $this->assertStringContainsString( + 'const formatted = parsed.toFixed(2);', + $html + ); foreach ([ 'base' => 'base', 'original' => 'original',