mirror of
https://github.com/snailyp/gemini-balance.git
synced 2026-09-06 16:16:37 +08:00
feat: 为无效密钥列表添加筛选和搜索功能
- 添加无效密钥的失败次数筛选控件 - 添加无效密钥的搜索框和每页显示数量选择器 - 实现无效密钥列表的筛选、搜索和分页功能 - 优化相关CSS样式以保持界面一致性
This commit is contained in:
@@ -862,6 +862,12 @@ function initializeKeyFilterControls() {
|
|||||||
if (thresholdInput) {
|
if (thresholdInput) {
|
||||||
thresholdInput.addEventListener("input", filterValidKeys);
|
thresholdInput.addEventListener("input", filterValidKeys);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 为无效密钥添加筛选控件监听器
|
||||||
|
const invalidThresholdInput = document.getElementById("invalidFailCountThreshold");
|
||||||
|
if (invalidThresholdInput) {
|
||||||
|
invalidThresholdInput.addEventListener("input", () => fetchAndDisplayKeys('invalid', 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function initializeGlobalBatchVerificationHandlers() {
|
function initializeGlobalBatchVerificationHandlers() {
|
||||||
@@ -1174,13 +1180,14 @@ async function fetchAndDisplayKeys(type, page = 1) {
|
|||||||
// Show loading indicator
|
// Show loading indicator
|
||||||
listElement.innerHTML = `<li><div class="text-center py-4 col-span-full"><i class="fas fa-spinner fa-spin"></i> Loading...</div></li>`;
|
listElement.innerHTML = `<li><div class="text-center py-4 col-span-full"><i class="fas fa-spinner fa-spin"></i> Loading...</div></li>`;
|
||||||
|
|
||||||
const itemsPerPageSelect = document.getElementById("itemsPerPageSelect");
|
// 根据类型选择对应的控件
|
||||||
|
const itemsPerPageSelect = document.getElementById(type === 'valid' ? "itemsPerPageSelect" : "invalidItemsPerPageSelect");
|
||||||
const limit = itemsPerPageSelect ? parseInt(itemsPerPageSelect.value, 10) : 10;
|
const limit = itemsPerPageSelect ? parseInt(itemsPerPageSelect.value, 10) : 10;
|
||||||
|
|
||||||
const searchInput = document.getElementById("keySearchInput");
|
const searchInput = document.getElementById(type === 'valid' ? "keySearchInput" : "invalidKeySearchInput");
|
||||||
const searchTerm = searchInput ? searchInput.value : '';
|
const searchTerm = searchInput ? searchInput.value : '';
|
||||||
|
|
||||||
const thresholdInput = document.getElementById("failCountThreshold");
|
const thresholdInput = document.getElementById(type === 'valid' ? "failCountThreshold" : "invalidFailCountThreshold");
|
||||||
const failCountThreshold = thresholdInput ? (thresholdInput.value === '' ? null : parseInt(thresholdInput.value, 10)) : null;
|
const failCountThreshold = thresholdInput ? (thresholdInput.value === '' ? null : parseInt(thresholdInput.value, 10)) : null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -1319,6 +1326,7 @@ function initializeKeyPaginationAndSearch() {
|
|||||||
const debouncedFetchValidKeys = debounce(() => fetchAndDisplayKeys('valid', 1), 300);
|
const debouncedFetchValidKeys = debounce(() => fetchAndDisplayKeys('valid', 1), 300);
|
||||||
const debouncedFetchInvalidKeys = debounce(() => fetchAndDisplayKeys('invalid', 1), 300);
|
const debouncedFetchInvalidKeys = debounce(() => fetchAndDisplayKeys('invalid', 1), 300);
|
||||||
|
|
||||||
|
// 有效密钥的搜索和筛选控件
|
||||||
const searchInput = document.getElementById("keySearchInput");
|
const searchInput = document.getElementById("keySearchInput");
|
||||||
if (searchInput) {
|
if (searchInput) {
|
||||||
searchInput.addEventListener("input", debouncedFetchValidKeys);
|
searchInput.addEventListener("input", debouncedFetchValidKeys);
|
||||||
@@ -1333,6 +1341,23 @@ function initializeKeyPaginationAndSearch() {
|
|||||||
if (itemsPerPageSelect) {
|
if (itemsPerPageSelect) {
|
||||||
itemsPerPageSelect.addEventListener("change", () => {
|
itemsPerPageSelect.addEventListener("change", () => {
|
||||||
fetchAndDisplayKeys('valid', 1);
|
fetchAndDisplayKeys('valid', 1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 无效密钥的搜索和筛选控件
|
||||||
|
const invalidSearchInput = document.getElementById("invalidKeySearchInput");
|
||||||
|
if (invalidSearchInput) {
|
||||||
|
invalidSearchInput.addEventListener("input", debouncedFetchInvalidKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
const invalidThresholdInput = document.getElementById("invalidFailCountThreshold");
|
||||||
|
if (invalidThresholdInput) {
|
||||||
|
invalidThresholdInput.addEventListener("input", debouncedFetchInvalidKeys);
|
||||||
|
}
|
||||||
|
|
||||||
|
const invalidItemsPerPageSelect = document.getElementById("invalidItemsPerPageSelect");
|
||||||
|
if (invalidItemsPerPageSelect) {
|
||||||
|
invalidItemsPerPageSelect.addEventListener("change", () => {
|
||||||
fetchAndDisplayKeys('invalid', 1);
|
fetchAndDisplayKeys('invalid', 1);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -875,7 +875,8 @@ endblock %} {% block head_extra_styles %}
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Fix specific pagination elements by ID and class */
|
/* Fix specific pagination elements by ID and class */
|
||||||
#validKeysPageSize, #invalidKeysPageSize {
|
#validKeysPageSize, #invalidKeysPageSize,
|
||||||
|
#itemsPerPageSelect, #invalidItemsPerPageSelect {
|
||||||
background-color: rgba(255, 255, 255, 0.95) !important;
|
background-color: rgba(255, 255, 255, 0.95) !important;
|
||||||
color: #374151 !important; /* gray-700 */
|
color: #374151 !important; /* gray-700 */
|
||||||
border: 1px solid rgba(0, 0, 0, 0.12) !important;
|
border: 1px solid rgba(0, 0, 0, 0.12) !important;
|
||||||
@@ -884,7 +885,8 @@ endblock %} {% block head_extra_styles %}
|
|||||||
font-size: 0.875rem !important; /* text-sm */
|
font-size: 0.875rem !important; /* text-sm */
|
||||||
}
|
}
|
||||||
|
|
||||||
#validKeysPageSize:focus, #invalidKeysPageSize:focus {
|
#validKeysPageSize:focus, #invalidKeysPageSize:focus,
|
||||||
|
#itemsPerPageSelect:focus, #invalidItemsPerPageSelect:focus {
|
||||||
border-color: #3b82f6 !important; /* blue-500 */
|
border-color: #3b82f6 !important; /* blue-500 */
|
||||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1) !important;
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1) !important;
|
||||||
outline: none !important;
|
outline: none !important;
|
||||||
@@ -947,7 +949,10 @@ endblock %} {% block head_extra_styles %}
|
|||||||
label[for="selectAllInvalid"],
|
label[for="selectAllInvalid"],
|
||||||
label[for="failCountThreshold"],
|
label[for="failCountThreshold"],
|
||||||
label[for="keySearchInput"],
|
label[for="keySearchInput"],
|
||||||
label[for="itemsPerPageSelect"] {
|
label[for="itemsPerPageSelect"],
|
||||||
|
label[for="invalidFailCountThreshold"],
|
||||||
|
label[for="invalidKeySearchInput"],
|
||||||
|
label[for="invalidItemsPerPageSelect"] {
|
||||||
color: #1f2937 !important; /* gray-800 for maximum contrast */
|
color: #1f2937 !important; /* gray-800 for maximum contrast */
|
||||||
font-weight: 600 !important; /* font-semibold for better visibility */
|
font-weight: 600 !important; /* font-semibold for better visibility */
|
||||||
text-shadow: none !important;
|
text-shadow: none !important;
|
||||||
@@ -1434,12 +1439,72 @@ endblock %} {% block head_extra_styles %}
|
|||||||
无效密钥列表 ({{ invalid_key_count }})
|
无效密钥列表 ({{ invalid_key_count }})
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Middle: Filters and Search (Allow wrapping) -->
|
||||||
|
<div
|
||||||
|
class="flex items-center gap-x-4 gap-y-2 flex-grow flex-wrap justify-start md:justify-center"
|
||||||
|
>
|
||||||
|
<!-- Allow wrapping, center on medium+ -->
|
||||||
|
<!-- 失败次数筛选 -->
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<label
|
||||||
|
for="invalidFailCountThreshold"
|
||||||
|
class="text-sm select-none whitespace-nowrap font-semibold"
|
||||||
|
style="color: #1f2937 !important;"
|
||||||
|
>失败次数≥</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
id="invalidFailCountThreshold"
|
||||||
|
value="0"
|
||||||
|
min="0"
|
||||||
|
class="form-input h-7 w-16 px-2 py-1 text-sm border rounded focus:ring-primary-500 focus:border-primary-500"
|
||||||
|
onclick="event.stopPropagation();"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!-- 密钥搜索 -->
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<label
|
||||||
|
for="invalidKeySearchInput"
|
||||||
|
class="text-sm select-none whitespace-nowrap font-semibold"
|
||||||
|
style="color: #1f2937 !important;"
|
||||||
|
><i class="fas fa-search mr-1"></i>搜索</label
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="search"
|
||||||
|
id="invalidKeySearchInput"
|
||||||
|
placeholder="输入密钥..."
|
||||||
|
class="form-input h-7 w-32 px-2 py-1 text-sm border rounded focus:ring-primary-500 focus:border-primary-500"
|
||||||
|
onclick="event.stopPropagation();"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<!-- 每页显示数量 -->
|
||||||
|
<div class="flex items-center gap-1">
|
||||||
|
<label
|
||||||
|
for="invalidItemsPerPageSelect"
|
||||||
|
class="text-sm select-none whitespace-nowrap font-semibold"
|
||||||
|
style="color: #1f2937 !important;"
|
||||||
|
>每页</label
|
||||||
|
>
|
||||||
|
<select
|
||||||
|
id="invalidItemsPerPageSelect"
|
||||||
|
class="form-select h-7 px-2 py-1 text-sm border rounded focus:ring-primary-500 focus:border-primary-500"
|
||||||
|
onclick="event.stopPropagation();"
|
||||||
|
>
|
||||||
|
<option value="10">10</option>
|
||||||
|
<option value="20">20</option>
|
||||||
|
<option value="50">50</option>
|
||||||
|
<option value="100">100</option>
|
||||||
|
<option value="500">500</option>
|
||||||
|
</select>
|
||||||
|
<span class="text-sm select-none font-semibold" style="color: #1f2937 !important;">项</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<!-- Right side: Select All -->
|
<!-- Right side: Select All -->
|
||||||
<div
|
<div
|
||||||
class="flex items-center gap-1 ml-auto flex-shrink-0"
|
class="flex items-center gap-1 flex-shrink-0"
|
||||||
onclick="event.stopPropagation();"
|
onclick="event.stopPropagation();"
|
||||||
>
|
>
|
||||||
<!-- Use ml-auto, Prevent shrinking -->
|
<!-- Prevent shrinking -->
|
||||||
<input
|
<input
|
||||||
type="checkbox"
|
type="checkbox"
|
||||||
id="selectAllInvalid"
|
id="selectAllInvalid"
|
||||||
|
|||||||
Reference in New Issue
Block a user