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
-
+
+
+
+
-
+
|
|
手工录入 |
@@ -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)