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 @@
@@ -64,7 +64,7 @@ const holdTypeModel = computed({
結束日期
全部
+
+
+
+
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 {