BUG修复:添加分离式刷新按钮

This commit is contained in:
MasonLiu 2026-06-30 23:56:57 +08:00
parent ec5c2db848
commit 00617621f9
4 changed files with 287 additions and 141 deletions

View File

@ -195,13 +195,18 @@ function getAliyunRegions($configId) {
*/
function getAliyunSwasRegions($configId) {
return [
'cn-hangzhou', // 华东1杭州
'cn-shanghai', // 华东2上海
'cn-qingdao', // 华北1青岛
'cn-beijing', // 华北2北京
'cn-zhangjiakou', // 华北3张家口
'cn-huhehaote', // 华北5呼和浩特
'cn-wulanchabu', // 华北6乌兰察布
'cn-hangzhou', // 华东1杭州
'cn-shanghai', // 华东2上海
'cn-nanjing', // 华东5南京
'cn-fuzhou', // 华东6福州
'cn-shenzhen', // 华南1深圳
'cn-heyuan', // 华南2河源
'cn-guangzhou', // 华南3广州
'cn-chengdu', // 西南1成都
'cn-hongkong', // 中国香港
'ap-southeast-1', // 新加坡

View File

@ -141,10 +141,61 @@ function initVpsTables($db) {
api_key TEXT NOT NULL,
auto_monitor BOOLEAN DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(site_url, account)
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
");
// 迁移如果存在旧的UNIQUE约束需要重建表
migrateConfigsTable($db);
}
/**
* 迁移configs表删除UNIQUE(site_url, account)约束
* 允许同一个源添加多个不同的AccessKey
*/
function migrateConfigsTable($db) {
try {
// 检查是否存在旧的唯一约束
$result = $db->query("PRAGMA index_list(configs)");
$hasOldConstraint = false;
foreach ($result as $index) {
if (isset($index['name']) && strpos($index['name'], 'site_url') !== false) {
$hasOldConstraint = true;
break;
}
}
if ($hasOldConstraint) {
// 需要迁移:创建新表 -> 复制数据 -> 删除旧表 -> 重命名
$db->execute("ALTER TABLE configs RENAME TO configs_old");
$db->execute("
CREATE TABLE configs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
api_label TEXT NOT NULL UNIQUE,
site_type TEXT NOT NULL,
site_url TEXT,
account TEXT NOT NULL,
api_key TEXT NOT NULL,
auto_monitor BOOLEAN DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
");
$db->execute("
INSERT INTO configs (id, api_label, site_type, site_url, account, api_key, auto_monitor, created_at, updated_at)
SELECT id, api_label, site_type, site_url, account, api_key, auto_monitor, created_at, updated_at
FROM configs_old
");
$db->execute("DROP TABLE configs_old");
}
} catch (Exception $e) {
// 迁移失败不影响正常使用,记录日志即可
error_log("[迁移警告] configs表迁移失败: " . $e->getMessage());
}
}
/**

View File

@ -9,33 +9,34 @@ from datetime import datetime
class DatabaseManager:
"""数据库管理器"""
def __init__(self, db_dir=None):
if db_dir is None:
db_dir = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'db')
db_dir = os.path.join(os.path.dirname(
os.path.abspath(__file__)), 'db')
self.db_dir = db_dir
os.makedirs(db_dir, exist_ok=True)
self.vps_db = os.path.join(db_dir, 'vps.db')
self.vpslist_db = os.path.join(db_dir, 'vpslist.db')
self.status_db = os.path.join(db_dir, 'status.db')
self.init_vps_db()
self.init_vpslist_db()
self.init_status_db()
def get_connection(self, db_path):
"""获取数据库连接"""
conn = sqlite3.connect(db_path)
conn.row_factory = sqlite3.Row
return conn
def init_vps_db(self):
"""初始化vps.db - VPS配置表"""
conn = self.get_connection(self.vps_db)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS configs (
id INTEGER PRIMARY KEY AUTOINCREMENT,
@ -46,19 +47,18 @@ class DatabaseManager:
api_key TEXT NOT NULL,
auto_monitor BOOLEAN DEFAULT 1,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE(site_url, account)
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
conn.commit()
conn.close()
def init_vpslist_db(self):
"""初始化vpslist.db - VPS列表缓存表"""
conn = self.get_connection(self.vpslist_db)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS vps_list (
id INTEGER PRIMARY KEY AUTOINCREMENT,
@ -80,19 +80,22 @@ class DatabaseManager:
FOREIGN KEY (config_id) REFERENCES configs(id)
)
''')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_vps_config ON vps_list(config_id)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_vps_vps_id ON vps_list(vps_id)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_vps_unique ON vps_list(vps_id, ip_address)')
cursor.execute(
'CREATE INDEX IF NOT EXISTS idx_vps_config ON vps_list(config_id)')
cursor.execute(
'CREATE INDEX IF NOT EXISTS idx_vps_vps_id ON vps_list(vps_id)')
cursor.execute(
'CREATE INDEX IF NOT EXISTS idx_vps_unique ON vps_list(vps_id, ip_address)')
conn.commit()
conn.close()
def init_status_db(self):
"""初始化status.db - Ping状态记录和摘要统计表"""
conn = self.get_connection(self.status_db)
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS ping_status (
id INTEGER PRIMARY KEY AUTOINCREMENT,
@ -103,7 +106,7 @@ class DatabaseManager:
check_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
''')
cursor.execute('''
CREATE TABLE IF NOT EXISTS vps_summary (
id INTEGER PRIMARY KEY AUTOINCREMENT,
@ -120,36 +123,40 @@ class DatabaseManager:
UNIQUE(vps_id, date)
)
''')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_ping_vps ON ping_status(vps_id)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_ping_time ON ping_status(check_time)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_summary_vps ON vps_summary(vps_id)')
cursor.execute('CREATE INDEX IF NOT EXISTS idx_summary_date ON vps_summary(date)')
cursor.execute(
'CREATE INDEX IF NOT EXISTS idx_ping_vps ON ping_status(vps_id)')
cursor.execute(
'CREATE INDEX IF NOT EXISTS idx_ping_time ON ping_status(check_time)')
cursor.execute(
'CREATE INDEX IF NOT EXISTS idx_summary_vps ON vps_summary(vps_id)')
cursor.execute(
'CREATE INDEX IF NOT EXISTS idx_summary_date ON vps_summary(date)')
conn.commit()
conn.close()
# ==================== vps.db 操作 ====================
def add_config(self, api_label, site_type, account, api_key, site_url=None, auto_monitor=True):
"""添加VPS配置基于site_url和account去重"""
conn = self.get_connection(self.vps_db)
cursor = conn.cursor()
try:
existing = cursor.execute(
'SELECT id FROM configs WHERE site_url = ? AND account = ?',
(site_url, account)
).fetchone()
if existing:
return existing['id']
cursor.execute('''
INSERT INTO configs (api_label, site_type, site_url, account, api_key, auto_monitor)
VALUES (?, ?, ?, ?, ?, ?)
''', (api_label, site_type, site_url, account, api_key, auto_monitor))
config_id = cursor.lastrowid
conn.commit()
return config_id
@ -158,82 +165,83 @@ class DatabaseManager:
raise e
finally:
conn.close()
def get_all_configs(self):
"""获取所有配置"""
conn = self.get_connection(self.vps_db)
cursor = conn.cursor()
cursor.execute('SELECT * FROM configs ORDER BY id')
configs = [dict(row) for row in cursor.fetchall()]
conn.close()
return configs
def get_config_by_id(self, config_id):
"""根据ID获取配置"""
conn = self.get_connection(self.vps_db)
cursor = conn.cursor()
cursor.execute('SELECT * FROM configs WHERE id = ?', (config_id,))
row = cursor.fetchone()
conn.close()
return dict(row) if row else None
def update_config(self, config_id, **kwargs):
"""更新配置"""
if not kwargs:
return False
conn = self.get_connection(self.vps_db)
cursor = conn.cursor()
fields = ', '.join([f"{key} = ?" for key in kwargs.keys()])
values = list(kwargs.values())
values.append(config_id)
cursor.execute(f'UPDATE configs SET {fields}, updated_at = CURRENT_TIMESTAMP WHERE id = ?', values)
cursor.execute(
f'UPDATE configs SET {fields}, updated_at = CURRENT_TIMESTAMP WHERE id = ?', values)
affected = cursor.rowcount
conn.commit()
conn.close()
return affected > 0
def delete_config(self, config_id):
"""删除配置"""
conn = self.get_connection(self.vps_db)
cursor = conn.cursor()
cursor.execute('DELETE FROM configs WHERE id = ?', (config_id,))
affected = cursor.rowcount
conn.commit()
conn.close()
return affected > 0
def reset_config_ids(self):
"""重置configs表的ID序列从1开始连续编号"""
conn = self.get_connection(self.vps_db)
cursor = conn.cursor()
try:
cursor.execute('SELECT * FROM configs ORDER BY id')
configs = [dict(row) for row in cursor.fetchall()]
if not configs:
return True
cursor.execute('DROP TABLE IF EXISTS configs_backup')
cursor.execute('''
CREATE TABLE configs_backup AS SELECT * FROM configs
''')
cursor.execute('DELETE FROM configs')
cursor.execute("DELETE FROM sqlite_sequence WHERE name='configs'")
for config in configs:
cursor.execute('''
INSERT INTO configs (api_label, site_type, site_url, account, api_key, auto_monitor, created_at, updated_at)
@ -248,7 +256,7 @@ class DatabaseManager:
config['created_at'],
config['updated_at']
))
cursor.execute('DROP TABLE IF EXISTS configs_backup')
conn.commit()
return True
@ -257,35 +265,35 @@ class DatabaseManager:
raise e
finally:
conn.close()
# ==================== vpslist.db 操作 ====================
def get_next_available_id(self):
"""获取下一个可用的ID填补空缺"""
conn = self.get_connection(self.vpslist_db)
cursor = conn.cursor()
cursor.execute('SELECT id FROM vps_list ORDER BY id')
ids = [row['id'] for row in cursor.fetchall()]
conn.close()
if not ids:
return 1
for i in range(1, max(ids) + 1):
if i not in ids:
return i
return None
def add_vps(self, config_id, vps_id, domain=None, ip_address=None, product_name=None, section=False, custom_id=None):
"""添加VPS到列表支持指定ID以填补空缺"""
conn = self.get_connection(self.vpslist_db)
cursor = conn.cursor()
if custom_id is None:
custom_id = self.get_next_available_id()
if custom_id:
cursor.execute('''
INSERT INTO vps_list (id, config_id, vps_id, domain, ip_address, product_name, section, last_check)
@ -296,29 +304,29 @@ class DatabaseManager:
INSERT INTO vps_list (config_id, vps_id, domain, ip_address, product_name, section, last_check)
VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
''', (config_id, vps_id, domain, ip_address, product_name, section))
record_id = cursor.lastrowid
conn.commit()
conn.close()
return record_id
def batch_add_vps(self, vps_list):
"""批量添加VPS基于vps_id和ip_address去重"""
conn = self.get_connection(self.vpslist_db)
cursor = conn.cursor()
for vps in vps_list:
existing = cursor.execute(
'SELECT id FROM vps_list WHERE vps_id = ? AND ip_address = ?',
(vps['vps_id'], vps.get('ip_address'))
).fetchone()
if existing:
continue
custom_id = self.get_next_available_id()
if custom_id:
cursor.execute('''
INSERT INTO vps_list
@ -360,87 +368,90 @@ class DatabaseManager:
vps.get('nextduedate'),
vps.get('section', False)
))
conn.commit()
conn.close()
def get_all_vps(self):
"""获取所有VPS"""
conn = self.get_connection(self.vpslist_db)
cursor = conn.cursor()
cursor.execute('SELECT * FROM vps_list ORDER BY config_id, vps_id')
vps_list = [dict(row) for row in cursor.fetchall()]
conn.close()
return vps_list
def get_vps_by_config(self, config_id):
"""根据配置ID获取VPS列表"""
conn = self.get_connection(self.vpslist_db)
cursor = conn.cursor()
cursor.execute('SELECT * FROM vps_list WHERE config_id = ? ORDER BY vps_id', (config_id,))
cursor.execute(
'SELECT * FROM vps_list WHERE config_id = ? ORDER BY vps_id', (config_id,))
vps_list = [dict(row) for row in cursor.fetchall()]
conn.close()
return vps_list
def update_vps_details(self, vps_id, **kwargs):
"""更新VPS详细信息"""
if not kwargs:
return False
conn = self.get_connection(self.vpslist_db)
cursor = conn.cursor()
fields = ', '.join([f"{key} = ?" for key in kwargs.keys()])
values = list(kwargs.values())
values.append(vps_id)
cursor.execute(f'UPDATE vps_list SET {fields}, last_check = CURRENT_TIMESTAMP WHERE vps_id = ?', values)
cursor.execute(
f'UPDATE vps_list SET {fields}, last_check = CURRENT_TIMESTAMP WHERE vps_id = ?', values)
affected = cursor.rowcount
conn.commit()
conn.close()
return affected > 0
def update_vps_status(self, vps_id, status):
"""更新VPS状态"""
return self.update_vps_details(vps_id, status=status)
def get_monitored_vps(self):
"""获取所有标记为需要监控的VPS"""
conn = self.get_connection(self.vpslist_db)
cursor = conn.cursor()
cursor.execute('SELECT * FROM vps_list WHERE section = 1 ORDER BY config_id, vps_id')
cursor.execute(
'SELECT * FROM vps_list WHERE section = 1 ORDER BY config_id, vps_id')
vps_list = [dict(row) for row in cursor.fetchall()]
conn.close()
return vps_list
def reset_vps_list_ids(self):
"""重置vps_list表的ID序列从1开始连续编号"""
conn = self.get_connection(self.vpslist_db)
cursor = conn.cursor()
try:
cursor.execute('SELECT * FROM vps_list ORDER BY id')
vps_items = [dict(row) for row in cursor.fetchall()]
if not vps_items:
return True
cursor.execute('DROP TABLE IF EXISTS vps_list_backup')
cursor.execute('''
CREATE TABLE vps_list_backup AS SELECT * FROM vps_list
''')
cursor.execute('DELETE FROM vps_list')
cursor.execute("DELETE FROM sqlite_sequence WHERE name='vps_list'")
for vps in vps_items:
cursor.execute('''
INSERT INTO vps_list (config_id, vps_id, domain, ip_address, product_name, cpu_cores, memory_size, disk_size, bandwidth, os_type, amount, nextduedate, status, section, last_check)
@ -462,7 +473,7 @@ class DatabaseManager:
vps.get('section', 0),
vps.get('last_check')
))
cursor.execute('DROP TABLE IF EXISTS vps_list_backup')
conn.commit()
return True
@ -471,27 +482,27 @@ class DatabaseManager:
raise e
finally:
conn.close()
# ==================== status.db 操作 ====================
def save_ping_status(self, vps_id, target, status, latency_ms=None):
"""保存Ping状态记录"""
conn = self.get_connection(self.status_db)
cursor = conn.cursor()
cursor.execute('''
INSERT INTO ping_status (vps_id, target, status, latency_ms)
VALUES (?, ?, ?, ?)
''', (vps_id, target, status, latency_ms))
conn.commit()
conn.close()
def get_ping_records(self, vps_id, date=None):
"""获取Ping记录"""
conn = self.get_connection(self.status_db)
cursor = conn.cursor()
if date:
cursor.execute('''
SELECT * FROM ping_status
@ -504,35 +515,37 @@ class DatabaseManager:
WHERE vps_id = ?
ORDER BY check_time DESC
''', (vps_id,))
records = [dict(row) for row in cursor.fetchall()]
conn.close()
return records
def cleanup_old_ping_records(self, days=30):
"""清理旧的Ping记录"""
from datetime import timedelta
conn = self.get_connection(self.status_db)
cursor = conn.cursor()
cutoff_date = (datetime.now() - timedelta(days=days)).strftime('%Y-%m-%d %H:%M:%S')
cursor.execute('DELETE FROM ping_status WHERE check_time < ?', (cutoff_date,))
cutoff_date = (datetime.now() - timedelta(days=days)
).strftime('%Y-%m-%d %H:%M:%S')
cursor.execute(
'DELETE FROM ping_status WHERE check_time < ?', (cutoff_date,))
deleted = cursor.rowcount
conn.commit()
conn.close()
return deleted
def save_vps_summary(self, vps_id, date, avg_latency, max_latency, min_latency,
count_under_100, count_100_to_300, count_300_to_500,
count_abnormal, availability):
count_under_100, count_100_to_300, count_300_to_500,
count_abnormal, availability):
"""保存VPS摘要统计"""
conn = self.get_connection(self.status_db)
cursor = conn.cursor()
cursor.execute('''
INSERT OR REPLACE INTO vps_summary
(vps_id, date, avg_latency_ms, max_latency_ms, min_latency_ms,
@ -541,32 +554,35 @@ class DatabaseManager:
''', (vps_id, date, avg_latency, max_latency, min_latency,
count_under_100, count_100_to_300, count_300_to_500,
count_abnormal, availability))
conn.commit()
conn.close()
def get_vps_summary(self, vps_id, date=None):
"""获取VPS摘要统计"""
conn = self.get_connection(self.status_db)
cursor = conn.cursor()
if date:
cursor.execute('SELECT * FROM vps_summary WHERE vps_id = ? AND date = ?', (vps_id, date))
cursor.execute(
'SELECT * FROM vps_summary WHERE vps_id = ? AND date = ?', (vps_id, date))
else:
cursor.execute('SELECT * FROM vps_summary WHERE vps_id = ? ORDER BY date DESC LIMIT 1', (vps_id,))
cursor.execute(
'SELECT * FROM vps_summary WHERE vps_id = ? ORDER BY date DESC LIMIT 1', (vps_id,))
row = cursor.fetchone()
conn.close()
return dict(row) if row else None
def get_all_summaries(self, date=None):
"""获取所有VPS的摘要统计"""
conn = self.get_connection(self.status_db)
cursor = conn.cursor()
if date:
cursor.execute('SELECT * FROM vps_summary WHERE date = ? ORDER BY vps_id', (date,))
cursor.execute(
'SELECT * FROM vps_summary WHERE date = ? ORDER BY vps_id', (date,))
else:
cursor.execute('''
SELECT vs.* FROM vps_summary vs
@ -577,10 +593,10 @@ class DatabaseManager:
) latest ON vs.vps_id = latest.vps_id AND vs.date = latest.max_date
ORDER BY vs.vps_id
''')
summaries = [dict(row) for row in cursor.fetchall()]
conn.close()
return summaries

View File

@ -87,8 +87,52 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$errorMsg = $result['error'] ?? $result['msg'] ?? '未知错误';
$message = '<div class="error-message"><h3>❌ 操作失败</h3><p>' . htmlspecialchars($errorMsg) . '</p></div>';
}
} elseif ($action === 'refresh_single_config') {
// 单独刷新某个配置
$configId = intval($_POST['config_id'] ?? 0);
if ($configId > 0) {
$configDb = getVpsDB();
$config = $configDb->queryOne('SELECT * FROM configs WHERE id = ?', [$configId]);
if ($config) {
$success = false;
$typeName = '';
if ($config['site_type'] === 'mofang') {
require_once __DIR__ . '/mofangidc.php';
$success = refreshVpsListForConfig($configId);
$typeName = '魔方平台';
} elseif ($config['site_type'] === 'tencent') {
require_once __DIR__ . '/tencentcloud.php';
// 同时刷新CVM和轻量
$cvmSuccess = refreshTencentCvmListForConfig($configId);
$lhSuccess = refreshTencentLighthouseListForConfig($configId);
$success = $cvmSuccess || $lhSuccess;
$typeName = '腾讯云';
} elseif ($config['site_type'] === 'aliyun') {
require_once __DIR__ . '/aliyun.php';
$success = refreshAliyunEcsListForConfig($configId);
$typeName = '阿里云ECS';
} elseif ($config['site_type'] === 'aliyun_swas') {
require_once __DIR__ . '/aliyun.php';
$success = refreshAliyunSwasListForConfig($configId);
$typeName = '阿里云轻量';
}
if ($success) {
$message = '<div class="success-message"><h3>✅ 刷新成功</h3><p>已刷新配置「' . htmlspecialchars($config['api_label']) . '」(' . $typeName . ')的VPS列表</p></div>';
} else {
$message = '<div class="error-message"><h3>❌ 刷新失败</h3><p>配置「' . htmlspecialchars($config['api_label']) . '」刷新失败请检查API凭证和网络连接</p></div>';
}
} else {
$message = '<div class="error-message">❌ 配置不存在</div>';
}
} else {
$message = '<div class="error-message">❌ 无效的配置ID</div>';
}
} elseif ($action === 'refresh_vps_list') {
// 手动刷新VPS列表
// 手动刷新VPS列表(全部)
$count = 0;
// 刷新魔方平台的VPS列表
@ -201,6 +245,12 @@ foreach ($vpsList as $vps) {
$vpsByApiLabel[$apiLabel][] = $vps;
}
// 构建api_label到config_id的映射用于单独刷新
$apiLabelToConfigId = [];
foreach ($configs as $config) {
$apiLabelToConfigId[$config['api_label']] = $config['id'];
}
// 统计信息
$totalCount = count($vpsList);
$runningCount = 0;
@ -245,6 +295,11 @@ foreach ($vpsList as $vps) {
.btn-refresh:hover {
background-color: #0056b3;
}
.config-title {
display: flex;
justify-content: space-between;
align-items: center;
}
/* 消息自动消失动画 */
.success-message, .error-message {
transition: opacity 0.5s ease-out;
@ -417,9 +472,9 @@ foreach ($vpsList as $vps) {
<!-- 工具栏 -->
<div class="toolbar">
<form method="POST" style="display: inline;">
<form method="POST" style="display: inline;" onsubmit="return confirmRefreshAll()">
<button type="submit" name="action" value="refresh_vps_list" class="btn-refresh">
🔄 手动刷新VPS列表
🔄 刷新全部列表
</button>
</form>
@ -454,13 +509,21 @@ foreach ($vpsList as $vps) {
<?php foreach ($vpsByApiLabel as $apiLabel => $labelVps): ?>
<div class="config-section">
<div class="config-title">
<?php echo htmlspecialchars($apiLabel); ?>
- <?php echo count($labelVps); ?> 台VPS
<span>
<?php echo htmlspecialchars($apiLabel); ?>
- <?php echo count($labelVps); ?> 台VPS
</span>
<form method="POST" style="display: inline; margin-left: 15px;" onsubmit="return confirm('确认刷新此配置的VPS列表')">
<input type="hidden" name="config_id" value="<?php echo $apiLabelToConfigId[$apiLabel] ?? 0; ?>">
<button type="submit" name="action" value="refresh_single_config" class="btn-refresh" style="padding: 5px 12px; font-size: 13px;">
🔄 刷新此配置
</button>
</form>
</div>
<?php if (empty($labelVps)): ?>
<div class="empty-state" style="background: white; padding: 40px;">
<p>此配置下暂无VPS请点击“手动刷新VPS列表”获取</p>
<p>此配置下暂无VPS请点击右上角“🔄 刷新此配置”按钮获取</p>
</div>
<?php else: ?>
<div class="vps-grid">
@ -627,6 +690,17 @@ foreach ($vpsList as $vps) {
}, 5000); // 5秒后开始淡出
});
});
// 刷新全部列表确认
function confirmRefreshAll() {
return confirm('⚠️ 警告:资源消耗占用较高\n\n' +
'刷新全部列表会同时请求所有配置的API可能会导致\n' +
'• 页面卡顿或响应缓慢\n' +
'• API超时导致报错中断\n' +
'• 部分配置刷新失败\n\n' +
'建议优先使用分离式刷新功能(点击每个配置右上角的🔄按钮)\n\n' +
'确定要继续刷新全部列表吗?');
}
</script>
</body>
</html>