feat: 选择上游分组弹窗支持倍率范围(大于等于/小于等于)筛选

This commit is contained in:
liumangmang
2026-07-01 17:06:18 +08:00
parent f9b5a03330
commit 04d719b417
+119 -5
View File
@@ -309,13 +309,23 @@
<!-- 选择上游分组弹窗 --> <!-- 选择上游分组弹窗 -->
<el-dialog v-model="groupSelectVisible" title="选择上游分组" width="min(85vw, 1200px)" destroy-on-close class="group-select-dialog custom-theme-dialog"> <el-dialog v-model="groupSelectVisible" title="选择上游分组" width="min(85vw, 1200px)" destroy-on-close class="group-select-dialog custom-theme-dialog">
<!-- 搜索 --> <!-- 搜索和倍率筛选条 -->
<div class="dialog-search-bar" style="margin-bottom: 16px;"> <div class="dialog-filter-bar" style="margin-bottom: 16px;">
<el-input v-model="groupSearchQuery" placeholder="输入分组名称、分组 ID、倍率进行过滤..." clearable class="custom-theme-search"> <el-input v-model="groupSearchQuery" placeholder="输入分组名称、分组 ID..." clearable class="custom-theme-search keyword-search-input">
<template #prefix> <template #prefix>
<el-icon><Search /></el-icon> <el-icon><Search /></el-icon>
</template> </template>
</el-input> </el-input>
<div class="rate-range-inputs">
<div class="rate-input-box">
<span class="rate-input-label">倍率 &gt;=</span>
<input type="number" step="0.01" v-model.number="groupRateMin" placeholder="不限" class="rate-number-input" />
</div>
<div class="rate-input-box">
<span class="rate-input-label">倍率 &lt;=</span>
<input type="number" step="0.01" v-model.number="groupRateMax" placeholder="不限" class="rate-number-input" />
</div>
</div>
</div> </div>
<div class="group-selector-layout"> <div class="group-selector-layout">
@@ -1249,6 +1259,8 @@ async function saveBinding() {
// 选择上游分组弹窗相关状态与方法 // 选择上游分组弹窗相关状态与方法
const groupSelectVisible = ref(false) const groupSelectVisible = ref(false)
const groupSearchQuery = ref('') const groupSearchQuery = ref('')
const groupRateMin = ref<number | null>(null)
const groupRateMax = ref<number | null>(null)
const selectedUpstreamId = ref<number | ''>('') const selectedUpstreamId = ref<number | ''>('')
const tempSelectedKeys = ref<string[]>([]) const tempSelectedKeys = ref<string[]>([])
@@ -1256,6 +1268,8 @@ function openGroupSelectModal() {
tempSelectedKeys.value = [...sourceGroupKeys.value] tempSelectedKeys.value = [...sourceGroupKeys.value]
groupSearchQuery.value = '' groupSearchQuery.value = ''
selectedUpstreamId.value = '' selectedUpstreamId.value = ''
groupRateMin.value = null
groupRateMax.value = null
groupSelectVisible.value = true groupSelectVisible.value = true
} }
@@ -1285,15 +1299,36 @@ const upstreamCounts = computed(() => {
const filteredGroupsForModal = computed(() => { const filteredGroupsForModal = computed(() => {
const query = groupSearchQuery.value.trim().toLowerCase() const query = groupSearchQuery.value.trim().toLowerCase()
return upstreamGroupOptions.value.filter(item => { return upstreamGroupOptions.value.filter(item => {
// 1. 上游站点过滤
if (selectedUpstreamId.value !== '' && item.source.upstream_id !== selectedUpstreamId.value) { if (selectedUpstreamId.value !== '' && item.source.upstream_id !== selectedUpstreamId.value) {
return false return false
} }
// 2. 关键词过滤:只匹配 group_name、group_id
if (query) { if (query) {
const matchGroupName = item.source.group_name.toLowerCase().includes(query) const matchGroupName = item.source.group_name.toLowerCase().includes(query)
const matchGroupId = String(item.source.group_id).toLowerCase().includes(query) const matchGroupId = String(item.source.group_id).toLowerCase().includes(query)
const matchRate = String(item.rate).toLowerCase().includes(query) if (!matchGroupName && !matchGroupId) {
return matchGroupName || matchGroupId || matchRate return false
} }
}
// 3. 倍率范围过滤
const min = groupRateMin.value
const max = groupRateMax.value
if (min !== null || max !== null) {
const rateVal = parseFloat(String(item.rate))
if (isNaN(rateVal)) {
return false
}
if (min !== null && rateVal < min) {
return false
}
if (max !== null && rateVal > max) {
return false
}
}
return true return true
}) })
}) })
@@ -2337,8 +2372,87 @@ onMounted(loadAll)
margin-bottom: 8px; margin-bottom: 8px;
} }
/* Combination Search and Filter Bar */
.dialog-filter-bar {
display: flex;
align-items: center;
gap: 16px;
width: 100%;
}
.keyword-search-input {
flex: 1;
}
.rate-range-inputs {
display: flex;
align-items: center;
gap: 12px;
flex-shrink: 0;
}
.rate-input-box {
display: flex;
align-items: center;
background: #160c0a;
border: 1px solid #3e2821;
border-radius: 4px;
height: 36px;
padding: 0 10px;
gap: 8px;
}
.rate-input-label {
font-size: 11px;
color: #a68d85;
white-space: nowrap;
font-weight: 600;
text-transform: uppercase;
}
.rate-number-input {
width: 80px;
border: none;
background: transparent;
color: #f5ecea;
outline: none;
font-size: 12px;
height: 100%;
text-align: center;
}
.rate-number-input::placeholder {
color: rgba(166, 141, 133, 0.3);
}
.rate-number-input::-webkit-inner-spin-button,
.rate-number-input::-webkit-outer-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Responsive dialog styling */ /* Responsive dialog styling */
@media (max-width: 768px) { @media (max-width: 768px) {
.dialog-filter-bar {
flex-direction: column;
align-items: stretch;
gap: 8px;
}
.rate-range-inputs {
justify-content: space-between;
width: 100%;
}
.rate-input-box {
flex: 1;
justify-content: center;
}
.rate-number-input {
width: 100%;
}
.group-selector-layout { .group-selector-layout {
display: flex; display: flex;
flex-direction: column; flex-direction: column;