From f1506787fb7ceb72ed72f632581a93e5a9f797c0 Mon Sep 17 00:00:00 2001 From: egg Date: Tue, 3 Mar 2026 08:05:56 +0800 Subject: [PATCH] fix(hold-history): replace auto-search with explicit query button for date filtering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Date changes no longer auto-trigger Oracle queries. Users can freely adjust dates and click "查詢" to execute. Hold Type still auto-refreshes from cache. Record Type checkboxes now use pill-toggle style (hidden native checkbox). Co-Authored-By: Claude Opus 4.6 --- frontend/src/hold-history/App.vue | 37 ++++++----- .../src/hold-history/components/FilterBar.vue | 66 +++++++++++-------- frontend/src/hold-history/style.css | 51 ++++++++++++-- 3 files changed, 105 insertions(+), 49 deletions(-) diff --git a/frontend/src/hold-history/App.vue b/frontend/src/hold-history/App.vue index 9fa76b1..954e119 100644 --- a/frontend/src/hold-history/App.vue +++ b/frontend/src/hold-history/App.vue @@ -352,34 +352,34 @@ const holdTypeLabel = computed(() => { // ---- Event handlers ---- -function handleFilterChange(next) { +function handleApply(next) { const nextStartDate = next?.startDate || ''; const nextEndDate = next?.endDate || ''; - const nextHoldType = next?.holdType || 'quality'; - - const dateChanged = filterBar.startDate !== nextStartDate || filterBar.endDate !== nextEndDate; - const holdTypeChanged = filterBar.holdType !== nextHoldType; - - if (!dateChanged && !holdTypeChanged) { - return; - } filterBar.startDate = nextStartDate; filterBar.endDate = nextEndDate; - filterBar.holdType = nextHoldType; reasonFilter.value = ''; durationFilter.value = ''; recordType.value = ['new']; page.value = 1; updateUrlState(); - if (dateChanged) { - // Date changed -> new primary query (Oracle) - void executePrimaryQuery(); - } else { - // Only hold_type changed -> view refresh (cache only) - void refreshView(); - } + void executePrimaryQuery(); +} + +function handleHoldTypeChange(nextHoldType) { + const holdType = nextHoldType || 'quality'; + if (filterBar.holdType === holdType) return; + + filterBar.holdType = holdType; + reasonFilter.value = ''; + durationFilter.value = ''; + recordType.value = ['new']; + page.value = 1; + updateUrlState(); + + // Hold type only → view refresh (cache read, no Oracle query) + void refreshView(); } function handleRecordTypeChange() { @@ -502,7 +502,8 @@ onMounted(() => { :end-date="filterBar.endDate" :hold-type="filterBar.holdType" :disabled="loading.global" - @change="handleFilterChange" + @apply="handleApply" + @hold-type-change="handleHoldTypeChange" /> diff --git a/frontend/src/hold-history/components/FilterBar.vue b/frontend/src/hold-history/components/FilterBar.vue index d0c9cb9..a3103bf 100644 --- a/frontend/src/hold-history/components/FilterBar.vue +++ b/frontend/src/hold-history/components/FilterBar.vue @@ -1,5 +1,5 @@ diff --git a/frontend/src/hold-history/style.css b/frontend/src/hold-history/style.css index fa623b5..96fee02 100644 --- a/frontend/src/hold-history/style.css +++ b/frontend/src/hold-history/style.css @@ -100,6 +100,38 @@ box-shadow: 0 0 0 2px rgba(14, 165, 233, 0.18); } +.filter-action-group { + display: flex; + align-items: flex-end; +} + +.btn-query { + white-space: nowrap; +} + +.btn-query:disabled { + opacity: 0.7; + cursor: not-allowed; +} + +.btn-spinner { + display: inline-block; + width: 12px; + height: 12px; + border: 2px solid rgba(255, 255, 255, 0.4); + border-top-color: #fff; + border-radius: 50%; + animation: spin 0.6s linear infinite; + margin-right: 6px; + vertical-align: middle; +} + +@keyframes spin { + to { + transform: rotate(360deg); + } +} + .checkbox-group { display: inline-flex; flex-wrap: wrap; @@ -109,13 +141,24 @@ .checkbox-option { display: inline-flex; align-items: center; - gap: 6px; - padding: 6px 10px; - border-radius: 8px; + gap: 0; + padding: 6px 12px; + border-radius: 999px; border: 1px solid var(--border); - background: #ffffff; + background: #f8fafc; cursor: pointer; font-size: 13px; + color: #475569; + transition: all 0.15s ease; + user-select: none; +} + +.checkbox-option input[type='checkbox'] { + position: absolute; + width: 0; + height: 0; + opacity: 0; + pointer-events: none; } .checkbox-option.active {