feat: 添加Cookie搜索和分组功能 #1
+175
-12
@@ -377,6 +377,80 @@
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.search-box {
|
||||
margin-bottom: 20px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
width: 100%;
|
||||
padding: 12px 40px 12px 16px;
|
||||
border: 2px solid #e0e0e0;
|
||||
border-radius: 8px;
|
||||
font-size: 16px;
|
||||
transition: border-color 0.3s;
|
||||
}
|
||||
|
||||
.search-input:focus {
|
||||
outline: none;
|
||||
border-color: #667eea;
|
||||
}
|
||||
|
||||
.search-icon {
|
||||
position: absolute;
|
||||
right: 12px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
color: #999;
|
||||
font-size: 20px;
|
||||
}
|
||||
|
||||
.group-header {
|
||||
background: #f8f9fa;
|
||||
padding: 15px 20px;
|
||||
margin: 15px 0 10px 0;
|
||||
border-radius: 8px;
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
transition: background 0.3s;
|
||||
}
|
||||
|
||||
.group-header:hover {
|
||||
background: #e9ecef;
|
||||
}
|
||||
|
||||
.group-title {
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.group-count {
|
||||
color: #999;
|
||||
font-size: 14px;
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.group-toggle {
|
||||
font-size: 20px;
|
||||
color: #667eea;
|
||||
transition: transform 0.3s;
|
||||
}
|
||||
|
||||
.group-toggle.collapsed {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
.group-content {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.group-content.collapsed {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.api-docs {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
@@ -443,7 +517,12 @@
|
||||
<div class="data-list">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
|
||||
<h2 style="margin: 0;">📋 数据列表</h2>
|
||||
<button class="btn btn-primary" onclick="loadDataList()">🔄 刷新</button>
|
||||
<button class="btn btn-primary" onclick="loadData()">🔄 刷新</button>
|
||||
</div>
|
||||
<!-- Search Box -->
|
||||
<div class="search-box">
|
||||
<input type="text" class="search-input" id="search-input" placeholder="🔍 搜索 Tag..." oninput="filterData()">
|
||||
<span class="search-icon">🔍</span>
|
||||
</div>
|
||||
<div id="data-container">
|
||||
<div class="loading">正在加载...</div>
|
||||
@@ -516,6 +595,8 @@
|
||||
<script>
|
||||
let currentViewData = null;
|
||||
let deleteCallback = null;
|
||||
let allDataItems = []; // 存储所有数据项
|
||||
let collapsedGroups = new Set(); // 存储折叠的分组
|
||||
|
||||
// Toast 通知
|
||||
function showToast(message, type = 'success') {
|
||||
@@ -615,15 +696,65 @@
|
||||
document.getElementById('warning-count').textContent = warningCount;
|
||||
document.getElementById('expired-count').textContent = expiredCount;
|
||||
|
||||
// 保存所有数据项
|
||||
allDataItems = tagArray;
|
||||
|
||||
// 渲染列表
|
||||
const container = document.getElementById('data-container');
|
||||
renderDataList(tagArray);
|
||||
|
||||
if (tagArray.length === 0) {
|
||||
container.innerHTML = '<div class="empty">📭 暂无数据</div>';
|
||||
return;
|
||||
} catch (error) {
|
||||
console.error('加载失败:', error);
|
||||
document.getElementById('data-container').innerHTML =
|
||||
'<div class="empty">❌ 加载失败,请刷新重试</div>';
|
||||
}
|
||||
}
|
||||
|
||||
// 渲染数据列表(支持分组)
|
||||
function renderDataList(items) {
|
||||
const container = document.getElementById('data-container');
|
||||
|
||||
if (items.length === 0) {
|
||||
container.innerHTML = '<div class="empty">📭 暂无数据</div>';
|
||||
return;
|
||||
}
|
||||
|
||||
// 按分组组织数据
|
||||
const groups = {};
|
||||
items.forEach(item => {
|
||||
const colonIndex = item.tag.indexOf(':');
|
||||
const groupName = colonIndex > 0 ? item.tag.substring(0, colonIndex) : '未分组';
|
||||
|
||||
if (!groups[groupName]) {
|
||||
groups[groupName] = [];
|
||||
}
|
||||
groups[groupName].push(item);
|
||||
});
|
||||
|
||||
container.innerHTML = tagArray.map((item) => {
|
||||
// 按分组名称排序
|
||||
const sortedGroupNames = Object.keys(groups).sort((a, b) => {
|
||||
if (a === '未分组') return 1;
|
||||
if (b === '未分组') return -1;
|
||||
return a.localeCompare(b);
|
||||
});
|
||||
|
||||
// 渲染分组
|
||||
let html = '';
|
||||
sortedGroupNames.forEach(groupName => {
|
||||
const groupItems = groups[groupName];
|
||||
const isCollapsed = collapsedGroups.has(groupName);
|
||||
|
||||
html += `
|
||||
<div class="group-header" onclick="toggleGroup('${groupName.replace(/'/g, "\\'")}')">
|
||||
<div>
|
||||
<span class="group-title">${groupName}</span>
|
||||
<span class="group-count">(${groupItems.length})</span>
|
||||
</div>
|
||||
<span class="group-toggle ${isCollapsed ? 'collapsed' : ''}">▼</span>
|
||||
</div>
|
||||
<div class="group-content ${isCollapsed ? 'collapsed' : ''}" id="group-${groupName}">
|
||||
`;
|
||||
|
||||
groupItems.forEach(item => {
|
||||
const statusClass = `status-${item.status}`;
|
||||
const statusText = {
|
||||
'valid': '正常',
|
||||
@@ -633,7 +764,7 @@
|
||||
|
||||
const escapedTag = item.tag.replace(/'/g, "\\'").replace(/"/g, '\\"');
|
||||
|
||||
return `
|
||||
html += `
|
||||
<div class="data-item">
|
||||
<div class="data-info">
|
||||
<div class="data-tag">
|
||||
@@ -654,13 +785,45 @@
|
||||
</div>
|
||||
</div>
|
||||
`;
|
||||
}).join('');
|
||||
});
|
||||
|
||||
} catch (error) {
|
||||
console.error('加载失败:', error);
|
||||
document.getElementById('data-container').innerHTML =
|
||||
'<div class="empty">❌ 加载失败,请刷新重试</div>';
|
||||
html += '</div>';
|
||||
});
|
||||
|
||||
container.innerHTML = html;
|
||||
}
|
||||
|
||||
// 切换分组折叠/展开
|
||||
function toggleGroup(groupName) {
|
||||
if (collapsedGroups.has(groupName)) {
|
||||
collapsedGroups.delete(groupName);
|
||||
} else {
|
||||
collapsedGroups.add(groupName);
|
||||
}
|
||||
|
||||
// 重新渲染当前显示的数据
|
||||
const searchTerm = document.getElementById('search-input').value.trim().toLowerCase();
|
||||
if (searchTerm) {
|
||||
filterData();
|
||||
} else {
|
||||
renderDataList(allDataItems);
|
||||
}
|
||||
}
|
||||
|
||||
// 搜索过滤
|
||||
function filterData() {
|
||||
const searchTerm = document.getElementById('search-input').value.trim().toLowerCase();
|
||||
|
||||
if (!searchTerm) {
|
||||
renderDataList(allDataItems);
|
||||
return;
|
||||
}
|
||||
|
||||
const filteredItems = allDataItems.filter(item =>
|
||||
item.tag.toLowerCase().includes(searchTerm)
|
||||
);
|
||||
|
||||
renderDataList(filteredItems);
|
||||
}
|
||||
|
||||
// 查看数据
|
||||
|
||||
Reference in new issue
Block a user