diff --git a/resources/views/business/pages/financial-ledger/ledger.blade.php b/resources/views/business/pages/financial-ledger/ledger.blade.php index 3b6fea59..544ebcd2 100644 --- a/resources/views/business/pages/financial-ledger/ledger.blade.php +++ b/resources/views/business/pages/financial-ledger/ledger.blade.php @@ -271,6 +271,13 @@ .ledger-manual-input { width:100%; min-width:0; height:1.85rem; padding:0 .42rem; border:1px solid var(--vip-border, #D8D2C7); border-radius:.35rem; background:#fff; color:var(--vip-content-ink, #171717); font:inherit; font-size:.7rem; } .ledger-manual-input:focus { border-color:var(--vip-content-accent-dark, #856632); outline:none; box-shadow:0 0 0 3px rgba(133,102,50,.14); } .ledger-manual-input:disabled { background:#f5f2eb; color:var(--vip-content-muted, #595959); } + .ledger-manual-date { display:flex; align-items:stretch; min-width:0; } + .ledger-manual-date .ledger-manual-input { flex:1 1 auto; width:auto; min-width:0; border-radius:.35rem 0 0 .35rem; cursor:pointer; } + .ledger-manual-date .ledger-manual-input:focus { position:relative; z-index:1; } + .ledger-manual-date__button { display:inline-grid; flex:none; place-items:center; width:1.85rem; height:1.85rem; padding:0; border:1px solid var(--vip-content-accent-dark, #856632); border-left:0; border-radius:0 .35rem .35rem 0; background:var(--vip-content-accent-soft, #F7F0DE); color:var(--vip-content-accent-dark, #856632); cursor:pointer; } + .ledger-manual-date__button:hover { background:#efe4c8; } + .ledger-manual-date__button:focus-visible { position:relative; z-index:2; outline:none; box-shadow:0 0 0 3px rgba(133,102,50,.18); } + .ledger-manual-date__button .material-icons-outlined { font-size:1rem; } .ledger-manual-actions { display:flex; align-items:center; gap:.25rem; } .ledger-manual-action { display:inline-grid; place-items:center; width:1.75rem; height:1.75rem; padding:0; border:1px solid var(--vip-border, #D8D2C7); border-radius:.35rem; background:#fff; color:var(--vip-content-muted, #595959); cursor:pointer; } .ledger-manual-action.is-save { border-color:var(--vip-content-accent-dark, #856632); background:var(--vip-content-accent-dark, #856632); color:#fff; } @@ -613,15 +620,20 @@ @csrf - +
+ + +
- + @foreach ($manualTransactionAccountOptions as $option) - + @endforeach - + 手工录入 @@ -822,6 +834,20 @@ const tokenInput = manualTransactionForm.querySelector('[data-ledger-manual-token]'); const saveButton = page.querySelector('[data-ledger-manual-save]'); const cancelButton = page.querySelector('[data-ledger-manual-cancel]'); + const dateInput = page.querySelector('[data-ledger-manual-date]'); + const datePickerButton = page.querySelector('[data-ledger-manual-date-picker]'); + const accountInput = page.querySelector('[data-ledger-manual-account]'); + const accountOptions = page.querySelector('#ledger-manual-account-options'); + const accountShortValues = new Set( + Array.from(accountOptions?.options || []).map((option) => option.value) + ); + const validateManualAccount = () => { + if (!accountInput) return false; + const accountShort = accountInput.value.trim(); + const invalid = accountShort !== '' && !accountShortValues.has(accountShort); + accountInput.setCustomValidity(invalid ? '请选择账户总表中的账户简称' : ''); + return !invalid; + }; const incomeInput = page.querySelector('[data-ledger-manual-income]'); const expenseInput = page.querySelector('[data-ledger-manual-expense]'); const summaryCount = page.querySelector('[data-ledger-transaction-summary-count]'); @@ -858,6 +884,7 @@ const resetManualDraft = (nextToken = null) => { manualTransactionForm.reset(); + accountInput?.setCustomValidity(''); if (nextToken) tokenInput.dataset.currentToken = nextToken; if (tokenInput?.dataset.currentToken) tokenInput.value = tokenInput.dataset.currentToken; syncManualDirection(); @@ -895,11 +922,39 @@ manualTransactionTrigger.addEventListener('click', () => showManualDraft(true)); cancelButton?.addEventListener('click', () => resetManualDraft()); + accountInput?.addEventListener('input', () => accountInput.setCustomValidity('')); + accountInput?.addEventListener('change', validateManualAccount); + accountInput?.addEventListener('blur', validateManualAccount); + dateInput?.addEventListener('click', () => { + if (typeof dateInput.showPicker !== 'function') return; + try { dateInput.showPicker(); } catch (error) { /* 已经打开时忽略 */ } + }); + datePickerButton?.addEventListener('click', () => { + if (!dateInput) return; + dateInput.focus({ preventScroll: true }); + if (typeof dateInput.showPicker === 'function') { + try { + dateInput.showPicker(); + return; + } catch (error) { /* 回退到输入框原生点击 */ } + } + dateInput.click(); + }); incomeInput?.addEventListener('input', () => syncManualDirection(incomeInput)); expenseInput?.addEventListener('input', () => syncManualDirection(expenseInput)); manualTransactionForm.addEventListener('submit', async (event) => { event.preventDefault(); + const accountShort = accountInput?.value.trim() || ''; + if (!accountShortValues.has(accountShort)) { + accountInput?.setCustomValidity('请选择账户总表中的账户简称'); + accountInput?.reportValidity(); + return; + } + if (accountInput) { + accountInput.value = accountShort; + accountInput.setCustomValidity(''); + } if (!manualTransactionForm.reportValidity()) return; const income = Number(incomeInput?.value || 0); const expense = Number(expenseInput?.value || 0); diff --git a/tests/Feature/Business/FinanceLedgerManualTransactionTest.php b/tests/Feature/Business/FinanceLedgerManualTransactionTest.php index 9574e815..e3865312 100644 --- a/tests/Feature/Business/FinanceLedgerManualTransactionTest.php +++ b/tests/Feature/Business/FinanceLedgerManualTransactionTest.php @@ -75,7 +75,12 @@ class FinanceLedgerManualTransactionTest extends FeatureTestCase ->assertSee('新增手工明细') ->assertSee('data-ledger-manual-trigger', false) ->assertSee('data-ledger-manual-draft', false) + ->assertSee('data-ledger-manual-date-picker', false) + ->assertSee('calendar_today', false) ->assertSee('name="account_short"', false) + ->assertSee('list="ledger-manual-account-options"', false) + ->assertSee('data-ledger-manual-account', false) + ->assertSee('输入账户简称', false) ->assertSee('手工账户甲 · 手工测试公司甲', false) ->assertSee('name="income"', false) ->assertSee('name="expense"', false)