Web优化
This commit is contained in:
@@ -166,6 +166,65 @@
|
||||
text-shadow: 0 0 5px rgba(250, 204, 21, 0.3);
|
||||
}
|
||||
}
|
||||
|
||||
/* 状态过渡效果 */
|
||||
.status-transition {
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
|
||||
/* 状态淡入动画 */
|
||||
@keyframes status-fade-in {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* 状态淡出动画 */
|
||||
@keyframes status-fade-out {
|
||||
0% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
100% {
|
||||
opacity: 0;
|
||||
transform: translateY(-5px);
|
||||
}
|
||||
}
|
||||
|
||||
/* 淡入类 */
|
||||
.status-fade-in {
|
||||
animation: status-fade-in 0.3s ease-in-out forwards;
|
||||
}
|
||||
|
||||
/* 淡出类 */
|
||||
.status-fade-out {
|
||||
animation: status-fade-out 0.3s ease-in-out forwards;
|
||||
}
|
||||
|
||||
/* 加载状态样式 */
|
||||
.status-loading {
|
||||
animation: status-pulse 1.5s ease-in-out infinite;
|
||||
}
|
||||
|
||||
/* 状态脉冲动画 */
|
||||
@keyframes status-pulse {
|
||||
0%, 100% {
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
opacity: 0.7;
|
||||
}
|
||||
}
|
||||
|
||||
/* 保存按钮状态样式 */
|
||||
#save-blacklist-status {
|
||||
transition: all 0.3s ease-in-out;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body class="bg-gray-50 text-dark font-sans">
|
||||
@@ -739,6 +798,7 @@
|
||||
<button id="save-rule-btn" class="px-4 py-2 bg-success text-white rounded-md hover:bg-success/90 transition-colors">
|
||||
保存
|
||||
</button>
|
||||
<div id="save-rule-status" class="flex items-center text-sm"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -748,12 +808,13 @@
|
||||
<thead>
|
||||
<tr class="border-b border-gray-200">
|
||||
<th class="text-left py-3 px-4 text-sm font-medium text-gray-500">规则</th>
|
||||
<th class="text-center py-3 px-4 text-sm font-medium text-gray-500">状态</th>
|
||||
<th class="text-right py-3 px-4 text-sm font-medium text-gray-500">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="rules-table-body">
|
||||
<tr>
|
||||
<td colspan="2" class="py-4 text-center text-gray-500">暂无规则</td>
|
||||
<td colspan="3" class="py-4 text-center text-gray-500">暂无规则</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
@@ -775,11 +836,13 @@
|
||||
<label for="blacklist-url" class="block text-sm font-medium text-gray-700 mb-1">URL</label>
|
||||
<input type="text" id="blacklist-url" placeholder="输入黑名单URL" class="w-full px-4 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-primary focus:border-transparent">
|
||||
</div>
|
||||
<div class="flex items-end space-x-2">
|
||||
<button id="save-blacklist-btn" class="px-4 py-2 bg-success text-white rounded-md hover:bg-success/90 transition-colors">
|
||||
保存
|
||||
</button>
|
||||
<div id="save-blacklist-status" class="flex items-center text-sm"></div>
|
||||
<div class="flex items-end">
|
||||
<div class="flex items-center space-x-2">
|
||||
<button id="save-blacklist-btn" class="px-4 py-2 bg-success text-white rounded-md hover:bg-success/90 transition-colors">
|
||||
保存
|
||||
</button>
|
||||
<div id="save-blacklist-status" class="flex items-center text-sm"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -17,6 +17,9 @@ function updateStatus(url, status, message) {
|
||||
const statusElement = document.getElementById(`update-status-${encodeURIComponent(url)}`);
|
||||
if (!statusElement) return;
|
||||
|
||||
// 清除之前的所有类
|
||||
statusElement.classList.remove('status-transition', 'status-loading', 'status-success', 'status-error', 'status-fade-in', 'status-fade-out');
|
||||
|
||||
let statusHTML = '';
|
||||
|
||||
switch (status) {
|
||||
@@ -33,12 +36,90 @@ function updateStatus(url, status, message) {
|
||||
statusHTML = '<span class="text-gray-400">-</span>';
|
||||
}
|
||||
|
||||
// 强制重排,确保过渡效果生效
|
||||
void statusElement.offsetWidth;
|
||||
|
||||
// 设置新的HTML内容
|
||||
statusElement.innerHTML = statusHTML;
|
||||
|
||||
// 如果是成功或失败状态,3秒后恢复默认状态
|
||||
// 添加过渡类和对应状态类
|
||||
statusElement.classList.add('status-transition');
|
||||
|
||||
// 如果不是默认状态,添加淡入动画和对应状态类
|
||||
if (status !== 'default') {
|
||||
statusElement.classList.add('status-fade-in');
|
||||
statusElement.classList.add(`status-${status}`);
|
||||
}
|
||||
|
||||
// 如果是成功或失败状态,3秒后渐变消失
|
||||
if (status === 'success' || status === 'error') {
|
||||
setTimeout(() => {
|
||||
updateStatus(url, 'default');
|
||||
// 添加淡出类
|
||||
statusElement.classList.add('status-fade-out');
|
||||
|
||||
// 等待淡出动画完成后切换到默认状态
|
||||
setTimeout(() => {
|
||||
// 清除所有类
|
||||
statusElement.classList.remove('status-transition', 'status-loading', 'status-success', 'status-error', 'status-fade-in', 'status-fade-out');
|
||||
// 设置默认状态
|
||||
statusElement.innerHTML = '<span class="text-gray-400">-</span>';
|
||||
}, 300); // 与CSS动画持续时间一致
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
// 更新规则状态显示函数
|
||||
function updateRuleStatus(rule, status, message) {
|
||||
const statusElement = document.getElementById(`rule-status-${encodeURIComponent(rule)}`);
|
||||
if (!statusElement) return;
|
||||
|
||||
// 清除之前的所有类
|
||||
statusElement.classList.remove('status-transition', 'status-loading', 'status-success', 'status-error', 'status-fade-in', 'status-fade-out');
|
||||
|
||||
let statusHTML = '';
|
||||
|
||||
switch (status) {
|
||||
case 'loading':
|
||||
statusHTML = '<span class="text-blue-500"><i class="fa fa-spinner fa-spin"></i> 处理中...</span>';
|
||||
break;
|
||||
case 'success':
|
||||
statusHTML = `<span class="text-green-500"><i class="fa fa-check"></i> ${message || '成功'}</span>`;
|
||||
break;
|
||||
case 'error':
|
||||
statusHTML = `<span class="text-red-500"><i class="fa fa-times"></i> ${message || '失败'}</span>`;
|
||||
break;
|
||||
default:
|
||||
statusHTML = '<span class="text-gray-400">-</span>';
|
||||
}
|
||||
|
||||
// 强制重排,确保过渡效果生效
|
||||
void statusElement.offsetWidth;
|
||||
|
||||
// 设置新的HTML内容
|
||||
statusElement.innerHTML = statusHTML;
|
||||
|
||||
// 添加过渡类和对应状态类
|
||||
statusElement.classList.add('status-transition');
|
||||
|
||||
// 如果不是默认状态,添加淡入动画和对应状态类
|
||||
if (status !== 'default') {
|
||||
statusElement.classList.add('status-fade-in');
|
||||
statusElement.classList.add(`status-${status}`);
|
||||
}
|
||||
|
||||
// 如果是成功或失败状态,3秒后渐变消失
|
||||
if (status === 'success' || status === 'error') {
|
||||
setTimeout(() => {
|
||||
// 添加淡出类
|
||||
statusElement.classList.add('status-fade-out');
|
||||
|
||||
// 等待淡出动画完成后切换到默认状态
|
||||
setTimeout(() => {
|
||||
// 清除所有类
|
||||
statusElement.classList.remove('status-transition', 'status-loading', 'status-success', 'status-error', 'status-fade-in', 'status-fade-out');
|
||||
// 设置默认状态
|
||||
statusElement.innerHTML = '<span class="text-gray-400">-</span>';
|
||||
}, 300); // 与CSS动画持续时间一致
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
@@ -248,7 +329,7 @@ function updateRulesTable(rules) {
|
||||
|
||||
if (rules.length === 0) {
|
||||
const emptyRow = document.createElement('tr');
|
||||
emptyRow.innerHTML = '<td colspan="2" class="py-4 text-center text-gray-500">暂无规则</td>';
|
||||
emptyRow.innerHTML = '<td colspan="3" class="py-4 text-center text-gray-500">暂无规则</td>';
|
||||
tbody.appendChild(emptyRow);
|
||||
return;
|
||||
}
|
||||
@@ -268,6 +349,11 @@ function updateRulesTable(rules) {
|
||||
tdRule.className = 'py-3 px-4';
|
||||
tdRule.textContent = rule;
|
||||
|
||||
const tdStatus = document.createElement('td');
|
||||
tdStatus.className = 'py-3 px-4 text-center';
|
||||
tdStatus.id = `rule-status-${encodeURIComponent(rule)}`;
|
||||
tdStatus.innerHTML = '<span class="text-gray-400">-</span>';
|
||||
|
||||
const tdAction = document.createElement('td');
|
||||
tdAction.className = 'py-3 px-4 text-right';
|
||||
|
||||
@@ -289,7 +375,9 @@ function updateRulesTable(rules) {
|
||||
};
|
||||
|
||||
tdAction.appendChild(deleteBtn);
|
||||
|
||||
tr.appendChild(tdRule);
|
||||
tr.appendChild(tdStatus);
|
||||
tr.appendChild(tdAction);
|
||||
fragment.appendChild(tr);
|
||||
});
|
||||
@@ -300,7 +388,7 @@ function updateRulesTable(rules) {
|
||||
// 如果有更多规则,添加提示
|
||||
if (rules.length > maxRulesToShow) {
|
||||
const infoRow = document.createElement('tr');
|
||||
infoRow.innerHTML = `<td colspan="2" class="py-4 text-center text-gray-500">显示前 ${maxRulesToShow} 条规则,共 ${rules.length} 条</td>`;
|
||||
infoRow.innerHTML = `<td colspan="3" class="py-4 text-center text-gray-500">显示前 ${maxRulesToShow} 条规则,共 ${rules.length} 条</td>`;
|
||||
tbody.appendChild(infoRow);
|
||||
}
|
||||
}
|
||||
@@ -336,6 +424,9 @@ async function handleDeleteRule(e) {
|
||||
}
|
||||
|
||||
try {
|
||||
// 显示加载状态
|
||||
updateRuleStatus(rule, 'loading');
|
||||
|
||||
console.log('Sending DELETE request to /api/shield');
|
||||
const response = await fetch('/api/shield', {
|
||||
method: 'DELETE',
|
||||
@@ -348,28 +439,47 @@ async function handleDeleteRule(e) {
|
||||
console.log('Response status:', response.status);
|
||||
console.log('Response ok:', response.ok);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`Failed to delete rule: ${response.status} ${errorText}`);
|
||||
// 解析服务器响应
|
||||
let responseData;
|
||||
try {
|
||||
responseData = await response.json();
|
||||
} catch (jsonError) {
|
||||
responseData = {};
|
||||
}
|
||||
|
||||
const responseData = await response.json();
|
||||
console.log('Response data:', responseData);
|
||||
|
||||
showNotification('规则删除成功', 'success');
|
||||
console.log('Current rules type:', currentRulesType);
|
||||
// 根据当前显示的规则类型重新加载对应的规则列表
|
||||
if (currentRulesType === 'local') {
|
||||
console.log('Reloading local rules');
|
||||
loadLocalRules();
|
||||
// 根据服务器响应判断是否成功
|
||||
if (response.ok && responseData.status === 'success') {
|
||||
// 显示成功状态
|
||||
updateRuleStatus(rule, 'success', '已删除');
|
||||
|
||||
showNotification('规则删除成功', 'success');
|
||||
console.log('Current rules type:', currentRulesType);
|
||||
|
||||
// 延迟重新加载规则列表和统计信息,让用户能看到成功状态
|
||||
setTimeout(() => {
|
||||
// 根据当前显示的规则类型重新加载对应的规则列表
|
||||
if (currentRulesType === 'local') {
|
||||
console.log('Reloading local rules');
|
||||
loadLocalRules();
|
||||
} else {
|
||||
console.log('Reloading remote rules');
|
||||
loadRemoteRules();
|
||||
}
|
||||
// 重新加载统计信息
|
||||
loadShieldStats();
|
||||
}, 3000);
|
||||
} else {
|
||||
console.log('Reloading remote rules');
|
||||
loadRemoteRules();
|
||||
const errorMessage = responseData.error || responseData.message || `删除规则失败: ${response.status}`;
|
||||
// 显示错误状态
|
||||
updateRuleStatus(rule, 'error', errorMessage);
|
||||
throw new Error(errorMessage);
|
||||
}
|
||||
// 重新加载统计信息
|
||||
loadShieldStats();
|
||||
} catch (error) {
|
||||
console.error('Error deleting rule:', error);
|
||||
// 显示错误状态
|
||||
updateRuleStatus(rule, 'error', error.message);
|
||||
showNotification('删除规则失败: ' + error.message, 'error');
|
||||
}
|
||||
}
|
||||
@@ -377,12 +487,26 @@ async function handleDeleteRule(e) {
|
||||
// 添加新规则
|
||||
async function handleAddRule() {
|
||||
const rule = document.getElementById('new-rule').value.trim();
|
||||
const statusElement = document.getElementById('save-rule-status');
|
||||
|
||||
if (!rule) {
|
||||
showNotification('规则不能为空', 'error');
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 清除之前的所有类
|
||||
statusElement.classList.remove('status-transition', 'status-loading', 'status-success', 'status-error', 'status-fade-in', 'status-fade-out');
|
||||
|
||||
// 显示加载状态
|
||||
statusElement.innerHTML = '<i class="fa fa-spinner fa-spin text-blue-500"></i> 正在添加...';
|
||||
|
||||
// 强制重排,确保过渡效果生效
|
||||
void statusElement.offsetWidth;
|
||||
|
||||
// 添加过渡类和加载状态类
|
||||
statusElement.classList.add('status-transition', 'status-fade-in', 'status-loading');
|
||||
|
||||
const response = await fetch('/api/shield', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
@@ -391,20 +515,86 @@ async function handleAddRule() {
|
||||
body: JSON.stringify({ rule })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to add rule');
|
||||
// 解析服务器响应
|
||||
let responseData;
|
||||
try {
|
||||
responseData = await response.json();
|
||||
} catch (jsonError) {
|
||||
responseData = {};
|
||||
}
|
||||
|
||||
showNotification('规则添加成功', 'success');
|
||||
// 清空输入框
|
||||
document.getElementById('new-rule').value = '';
|
||||
// 重新加载规则
|
||||
loadLocalRules();
|
||||
// 重新加载统计信息
|
||||
loadShieldStats();
|
||||
// 根据服务器响应判断是否成功
|
||||
if (response.ok && responseData.status === 'success') {
|
||||
// 清除之前的所有类
|
||||
statusElement.classList.remove('status-transition', 'status-loading', 'status-success', 'status-error', 'status-fade-in', 'status-fade-out');
|
||||
|
||||
// 显示成功状态
|
||||
statusElement.innerHTML = '<span class="text-green-500"><i class="fa fa-check"></i> 成功</span>';
|
||||
|
||||
// 强制重排,确保过渡效果生效
|
||||
void statusElement.offsetWidth;
|
||||
|
||||
// 添加过渡类和成功状态类
|
||||
statusElement.classList.add('status-transition', 'status-fade-in', 'status-success');
|
||||
|
||||
showNotification('规则添加成功', 'success');
|
||||
// 清空输入框
|
||||
document.getElementById('new-rule').value = '';
|
||||
|
||||
// 延迟重新加载规则和统计信息,让用户能看到成功状态
|
||||
setTimeout(() => {
|
||||
// 重新加载规则
|
||||
loadLocalRules();
|
||||
// 重新加载统计信息
|
||||
loadShieldStats();
|
||||
}, 3000);
|
||||
} else {
|
||||
// 清除之前的所有类
|
||||
statusElement.classList.remove('status-transition', 'status-loading', 'status-success', 'status-error', 'status-fade-in', 'status-fade-out');
|
||||
|
||||
// 显示失败状态
|
||||
const errorMessage = responseData.error || responseData.message || '添加规则失败';
|
||||
statusElement.innerHTML = `<span class="text-red-500"><i class="fa fa-times"></i> ${errorMessage}</span>`;
|
||||
|
||||
// 强制重排,确保过渡效果生效
|
||||
void statusElement.offsetWidth;
|
||||
|
||||
// 添加过渡类和错误状态类
|
||||
statusElement.classList.add('status-transition', 'status-fade-in', 'status-error');
|
||||
|
||||
showNotification(errorMessage, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error adding rule:', error);
|
||||
showNotification('添加规则失败', 'error');
|
||||
|
||||
// 清除之前的所有类
|
||||
statusElement.classList.remove('status-transition', 'status-loading', 'status-success', 'status-error', 'status-fade-in', 'status-fade-out');
|
||||
|
||||
// 显示错误状态
|
||||
const errorMessage = error.message || '添加规则失败';
|
||||
statusElement.innerHTML = `<span class="text-red-500"><i class="fa fa-times"></i> ${errorMessage}</span>`;
|
||||
|
||||
// 强制重排,确保过渡效果生效
|
||||
void statusElement.offsetWidth;
|
||||
|
||||
// 添加过渡类和错误状态类
|
||||
statusElement.classList.add('status-transition', 'status-fade-in', 'status-error');
|
||||
|
||||
showNotification(errorMessage, 'error');
|
||||
} finally {
|
||||
// 3秒后渐变消失
|
||||
setTimeout(() => {
|
||||
// 添加淡出类
|
||||
statusElement.classList.add('status-fade-out');
|
||||
|
||||
// 等待淡出动画完成后清除状态
|
||||
setTimeout(() => {
|
||||
// 清除所有类
|
||||
statusElement.classList.remove('status-transition', 'status-loading', 'status-success', 'status-error', 'status-fade-in', 'status-fade-out');
|
||||
// 清空状态显示
|
||||
statusElement.innerHTML = '';
|
||||
}, 300); // 与CSS动画持续时间一致
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -618,19 +808,42 @@ async function handleUpdateBlacklist(e) {
|
||||
body: JSON.stringify(updatedBlacklists)
|
||||
});
|
||||
|
||||
if (!updateResponse.ok) {
|
||||
const errorText = await updateResponse.text();
|
||||
throw new Error(`更新失败: ${updateResponse.status} ${errorText}`);
|
||||
// 解析服务器响应
|
||||
let responseData;
|
||||
try {
|
||||
responseData = await updateResponse.json();
|
||||
} catch (jsonError) {
|
||||
responseData = {};
|
||||
}
|
||||
|
||||
// 显示成功状态
|
||||
updateStatus(url, 'success');
|
||||
|
||||
// 重新加载黑名单
|
||||
loadRemoteBlacklists();
|
||||
// 重新加载统计信息
|
||||
loadShieldStats();
|
||||
showNotification('黑名单更新成功', 'success');
|
||||
// 根据服务器响应判断是否成功
|
||||
if (updateResponse.ok && (responseData.status === 'success' || !responseData.status)) {
|
||||
// 显示成功状态
|
||||
updateStatus(url, 'success');
|
||||
|
||||
// 显示通知
|
||||
showNotification('黑名单更新成功', 'success');
|
||||
|
||||
// 延迟重新加载黑名单和统计信息,让用户能看到成功状态
|
||||
setTimeout(() => {
|
||||
// 重新加载黑名单
|
||||
loadRemoteBlacklists();
|
||||
// 重新加载统计信息
|
||||
loadShieldStats();
|
||||
}, 3000);
|
||||
} else {
|
||||
// 显示失败状态
|
||||
updateStatus(url, 'error', responseData.error || responseData.message || `更新失败: ${updateResponse.status}`);
|
||||
showNotification(`黑名单更新失败: ${responseData.error || responseData.message || updateResponse.status}`, 'error');
|
||||
|
||||
// 延迟重新加载黑名单和统计信息
|
||||
setTimeout(() => {
|
||||
// 重新加载黑名单
|
||||
loadRemoteBlacklists();
|
||||
// 重新加载统计信息
|
||||
loadShieldStats();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('更新黑名单失败:', error);
|
||||
// 显示错误状态
|
||||
@@ -661,6 +874,13 @@ async function handleDeleteBlacklist(e) {
|
||||
}
|
||||
|
||||
try {
|
||||
// 获取当前行元素
|
||||
const tr = btn.closest('tr');
|
||||
if (!tr) {
|
||||
console.error('未找到行元素');
|
||||
return;
|
||||
}
|
||||
|
||||
// 显示加载状态
|
||||
updateStatus(url, 'loading');
|
||||
|
||||
@@ -684,19 +904,58 @@ async function handleDeleteBlacklist(e) {
|
||||
body: JSON.stringify(updatedBlacklists)
|
||||
});
|
||||
|
||||
if (!updateResponse.ok) {
|
||||
const errorText = await updateResponse.text();
|
||||
throw new Error(`删除失败: ${updateResponse.status} ${errorText}`);
|
||||
// 解析服务器响应
|
||||
let responseData;
|
||||
try {
|
||||
responseData = await updateResponse.json();
|
||||
} catch (jsonError) {
|
||||
responseData = {};
|
||||
}
|
||||
|
||||
// 显示成功状态
|
||||
updateStatus(url, 'success', '已删除');
|
||||
|
||||
// 重新加载黑名单
|
||||
loadRemoteBlacklists();
|
||||
// 重新加载统计信息
|
||||
loadShieldStats();
|
||||
showNotification('黑名单删除成功', 'success');
|
||||
// 根据服务器响应判断是否成功
|
||||
if (updateResponse.ok && responseData.status === 'success') {
|
||||
// 显示成功状态
|
||||
updateStatus(url, 'success', '已删除');
|
||||
|
||||
// 显示通知
|
||||
showNotification('黑名单删除成功', 'success');
|
||||
|
||||
// 延迟后渐变移除该行
|
||||
setTimeout(() => {
|
||||
// 添加渐变移除类
|
||||
tr.style.transition = 'all 0.3s ease-in-out';
|
||||
tr.style.opacity = '0';
|
||||
tr.style.transform = 'translateX(-10px)';
|
||||
tr.style.height = tr.offsetHeight + 'px';
|
||||
tr.style.overflow = 'hidden';
|
||||
|
||||
// 等待过渡效果完成后,隐藏该行
|
||||
setTimeout(() => {
|
||||
tr.style.display = 'none';
|
||||
|
||||
// 延迟重新加载黑名单和统计信息,确保视觉效果完成
|
||||
setTimeout(() => {
|
||||
// 重新加载黑名单
|
||||
loadRemoteBlacklists();
|
||||
// 重新加载统计信息
|
||||
loadShieldStats();
|
||||
}, 100);
|
||||
}, 300);
|
||||
}, 3000);
|
||||
} else {
|
||||
// 显示失败状态
|
||||
const errorMessage = responseData.error || responseData.message || `删除失败: ${updateResponse.status}`;
|
||||
updateStatus(url, 'error', errorMessage);
|
||||
showNotification(errorMessage, 'error');
|
||||
|
||||
// 延迟重新加载黑名单和统计信息
|
||||
setTimeout(() => {
|
||||
// 重新加载黑名单
|
||||
loadRemoteBlacklists();
|
||||
// 重新加载统计信息
|
||||
loadShieldStats();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('删除黑名单失败:', error);
|
||||
// 显示错误状态
|
||||
@@ -761,19 +1020,43 @@ async function handleToggleBlacklist(e) {
|
||||
body: JSON.stringify(updatedBlacklists)
|
||||
});
|
||||
|
||||
if (!updateResponse.ok) {
|
||||
const errorText = await updateResponse.text();
|
||||
throw new Error(`更新状态失败: ${updateResponse.status} ${errorText}`);
|
||||
// 解析服务器响应
|
||||
let responseData;
|
||||
try {
|
||||
responseData = await updateResponse.json();
|
||||
} catch (jsonError) {
|
||||
responseData = {};
|
||||
}
|
||||
|
||||
// 显示成功状态
|
||||
updateStatus(url, 'success', currentEnabled ? '已禁用' : '已启用');
|
||||
|
||||
// 重新加载黑名单
|
||||
loadRemoteBlacklists();
|
||||
// 重新加载统计信息
|
||||
loadShieldStats();
|
||||
showNotification(`黑名单已${currentEnabled ? '禁用' : '启用'}`, 'success');
|
||||
// 根据服务器响应判断是否成功
|
||||
if (updateResponse.ok && responseData.status === 'success') {
|
||||
// 显示成功状态
|
||||
updateStatus(url, 'success', currentEnabled ? '已禁用' : '已启用');
|
||||
|
||||
// 显示通知
|
||||
showNotification(`黑名单已${currentEnabled ? '禁用' : '启用'}`, 'success');
|
||||
|
||||
// 延迟重新加载黑名单和统计信息,让用户能看到成功状态
|
||||
setTimeout(() => {
|
||||
// 重新加载黑名单
|
||||
loadRemoteBlacklists();
|
||||
// 重新加载统计信息
|
||||
loadShieldStats();
|
||||
}, 3000);
|
||||
} else {
|
||||
// 显示失败状态
|
||||
const errorMessage = responseData.error || responseData.message || `更新状态失败: ${updateResponse.status}`;
|
||||
updateStatus(url, 'error', errorMessage);
|
||||
showNotification(errorMessage, 'error');
|
||||
|
||||
// 延迟重新加载黑名单和统计信息
|
||||
setTimeout(() => {
|
||||
// 重新加载黑名单
|
||||
loadRemoteBlacklists();
|
||||
// 重新加载统计信息
|
||||
loadShieldStats();
|
||||
}, 3000);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('启用/禁用黑名单失败:', error);
|
||||
// 显示错误状态
|
||||
@@ -811,9 +1094,18 @@ async function handleAddBlacklist(event) {
|
||||
}
|
||||
|
||||
try {
|
||||
// 清除之前的所有类
|
||||
statusElement.classList.remove('status-transition', 'status-loading', 'status-success', 'status-error', 'status-fade-in', 'status-fade-out');
|
||||
|
||||
// 显示加载状态
|
||||
statusElement.innerHTML = '<i class="fa fa-spinner fa-spin text-blue-500"></i> 正在添加...';
|
||||
|
||||
// 强制重排,确保过渡效果生效
|
||||
void statusElement.offsetWidth;
|
||||
|
||||
// 添加过渡类和加载状态类
|
||||
statusElement.classList.add('status-transition', 'status-fade-in', 'status-loading');
|
||||
|
||||
// 发送添加请求
|
||||
const response = await fetch('/api/shield/blacklists', {
|
||||
method: 'POST',
|
||||
@@ -823,40 +1115,82 @@ async function handleAddBlacklist(event) {
|
||||
body: JSON.stringify({ name, url })
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
// 尝试从响应中获取更详细的错误信息
|
||||
let errorMessage = '添加黑名单失败';
|
||||
try {
|
||||
const errorData = await response.json();
|
||||
if (errorData.error) {
|
||||
errorMessage = errorData.error;
|
||||
}
|
||||
} catch (jsonError) {
|
||||
// 忽略JSON解析错误
|
||||
}
|
||||
throw new Error(errorMessage);
|
||||
// 解析服务器响应
|
||||
let responseData;
|
||||
try {
|
||||
responseData = await response.json();
|
||||
} catch (jsonError) {
|
||||
responseData = {};
|
||||
}
|
||||
|
||||
// 显示成功状态
|
||||
statusElement.innerHTML = '<span class="text-green-500"><i class="fa fa-check"></i> 成功</span>';
|
||||
|
||||
showNotification('黑名单添加成功', 'success');
|
||||
// 清空输入框
|
||||
if (nameInput) nameInput.value = '';
|
||||
if (urlInput) urlInput.value = '';
|
||||
// 重新加载黑名单
|
||||
loadRemoteBlacklists();
|
||||
// 重新加载统计信息
|
||||
loadShieldStats();
|
||||
// 根据服务器响应判断是否成功
|
||||
if (response.ok && (responseData.status === 'success' || !responseData.status)) {
|
||||
// 清除之前的所有类
|
||||
statusElement.classList.remove('status-transition', 'status-loading', 'status-success', 'status-error', 'status-fade-in', 'status-fade-out');
|
||||
|
||||
// 显示成功状态
|
||||
statusElement.innerHTML = '<span class="text-green-500"><i class="fa fa-check"></i> 成功</span>';
|
||||
|
||||
// 强制重排,确保过渡效果生效
|
||||
void statusElement.offsetWidth;
|
||||
|
||||
// 添加过渡类和成功状态类
|
||||
statusElement.classList.add('status-transition', 'status-fade-in', 'status-success');
|
||||
|
||||
showNotification('黑名单添加成功', 'success');
|
||||
// 清空输入框
|
||||
if (nameInput) nameInput.value = '';
|
||||
if (urlInput) urlInput.value = '';
|
||||
// 重新加载黑名单
|
||||
loadRemoteBlacklists();
|
||||
// 重新加载统计信息
|
||||
loadShieldStats();
|
||||
} else {
|
||||
// 清除之前的所有类
|
||||
statusElement.classList.remove('status-transition', 'status-loading', 'status-success', 'status-error', 'status-fade-in', 'status-fade-out');
|
||||
|
||||
// 显示失败状态
|
||||
const errorMessage = responseData.error || responseData.message || `添加失败: ${response.status}`;
|
||||
statusElement.innerHTML = `<span class="text-red-500"><i class="fa fa-times"></i> ${errorMessage}</span>`;
|
||||
|
||||
// 强制重排,确保过渡效果生效
|
||||
void statusElement.offsetWidth;
|
||||
|
||||
// 添加过渡类和错误状态类
|
||||
statusElement.classList.add('status-transition', 'status-fade-in', 'status-error');
|
||||
|
||||
showNotification(errorMessage, 'error');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error adding blacklist:', error);
|
||||
|
||||
// 清除之前的所有类
|
||||
statusElement.classList.remove('status-transition', 'status-loading', 'status-success', 'status-error', 'status-fade-in', 'status-fade-out');
|
||||
|
||||
// 显示错误状态
|
||||
statusElement.innerHTML = `<span class="text-red-500"><i class="fa fa-times"></i> 失败</span>`;
|
||||
showNotification(error.message || '添加黑名单失败', 'error');
|
||||
const errorMessage = error.message || '添加黑名单失败';
|
||||
statusElement.innerHTML = `<span class="text-red-500"><i class="fa fa-times"></i> ${errorMessage}</span>`;
|
||||
|
||||
// 强制重排,确保过渡效果生效
|
||||
void statusElement.offsetWidth;
|
||||
|
||||
// 添加过渡类和错误状态类
|
||||
statusElement.classList.add('status-transition', 'status-fade-in', 'status-error');
|
||||
|
||||
showNotification(errorMessage, 'error');
|
||||
} finally {
|
||||
// 3秒后清除状态显示
|
||||
// 3秒后渐变消失
|
||||
setTimeout(() => {
|
||||
statusElement.innerHTML = '';
|
||||
// 添加淡出类
|
||||
statusElement.classList.add('status-fade-out');
|
||||
|
||||
// 等待淡出动画完成后清除状态
|
||||
setTimeout(() => {
|
||||
// 清除所有类
|
||||
statusElement.classList.remove('status-transition', 'status-loading', 'status-success', 'status-error', 'status-fade-in', 'status-fade-out');
|
||||
// 清空状态显示
|
||||
statusElement.innerHTML = '';
|
||||
}, 300); // 与CSS动画持续时间一致
|
||||
}, 3000);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user