BUG修复:添加分离式刷新按钮
This commit is contained in:
parent
ec5c2db848
commit
00617621f9
@ -195,13 +195,18 @@ function getAliyunRegions($configId) {
|
|||||||
*/
|
*/
|
||||||
function getAliyunSwasRegions($configId) {
|
function getAliyunSwasRegions($configId) {
|
||||||
return [
|
return [
|
||||||
'cn-hangzhou', // 华东1(杭州)
|
|
||||||
'cn-shanghai', // 华东2(上海)
|
|
||||||
'cn-qingdao', // 华北1(青岛)
|
'cn-qingdao', // 华北1(青岛)
|
||||||
'cn-beijing', // 华北2(北京)
|
'cn-beijing', // 华北2(北京)
|
||||||
'cn-zhangjiakou', // 华北3(张家口)
|
'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-shenzhen', // 华南1(深圳)
|
||||||
'cn-heyuan', // 华南2(河源)
|
'cn-heyuan', // 华南2(河源)
|
||||||
|
'cn-guangzhou', // 华南3(广州)
|
||||||
'cn-chengdu', // 西南1(成都)
|
'cn-chengdu', // 西南1(成都)
|
||||||
'cn-hongkong', // 中国香港
|
'cn-hongkong', // 中国香港
|
||||||
'ap-southeast-1', // 新加坡
|
'ap-southeast-1', // 新加坡
|
||||||
|
|||||||
@ -141,10 +141,61 @@ function initVpsTables($db) {
|
|||||||
api_key TEXT NOT NULL,
|
api_key TEXT NOT NULL,
|
||||||
auto_monitor BOOLEAN DEFAULT 1,
|
auto_monitor BOOLEAN DEFAULT 1,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
UNIQUE(site_url, account)
|
|
||||||
)
|
)
|
||||||
");
|
");
|
||||||
|
|
||||||
|
// 迁移:如果存在旧的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());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -9,33 +9,34 @@ from datetime import datetime
|
|||||||
|
|
||||||
class DatabaseManager:
|
class DatabaseManager:
|
||||||
"""数据库管理器"""
|
"""数据库管理器"""
|
||||||
|
|
||||||
def __init__(self, db_dir=None):
|
def __init__(self, db_dir=None):
|
||||||
if db_dir is 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
|
self.db_dir = db_dir
|
||||||
os.makedirs(db_dir, exist_ok=True)
|
os.makedirs(db_dir, exist_ok=True)
|
||||||
|
|
||||||
self.vps_db = os.path.join(db_dir, 'vps.db')
|
self.vps_db = os.path.join(db_dir, 'vps.db')
|
||||||
self.vpslist_db = os.path.join(db_dir, 'vpslist.db')
|
self.vpslist_db = os.path.join(db_dir, 'vpslist.db')
|
||||||
self.status_db = os.path.join(db_dir, 'status.db')
|
self.status_db = os.path.join(db_dir, 'status.db')
|
||||||
|
|
||||||
self.init_vps_db()
|
self.init_vps_db()
|
||||||
self.init_vpslist_db()
|
self.init_vpslist_db()
|
||||||
self.init_status_db()
|
self.init_status_db()
|
||||||
|
|
||||||
def get_connection(self, db_path):
|
def get_connection(self, db_path):
|
||||||
"""获取数据库连接"""
|
"""获取数据库连接"""
|
||||||
conn = sqlite3.connect(db_path)
|
conn = sqlite3.connect(db_path)
|
||||||
conn.row_factory = sqlite3.Row
|
conn.row_factory = sqlite3.Row
|
||||||
return conn
|
return conn
|
||||||
|
|
||||||
def init_vps_db(self):
|
def init_vps_db(self):
|
||||||
"""初始化vps.db - VPS配置表"""
|
"""初始化vps.db - VPS配置表"""
|
||||||
conn = self.get_connection(self.vps_db)
|
conn = self.get_connection(self.vps_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
CREATE TABLE IF NOT EXISTS configs (
|
CREATE TABLE IF NOT EXISTS configs (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@ -46,19 +47,18 @@ class DatabaseManager:
|
|||||||
api_key TEXT NOT NULL,
|
api_key TEXT NOT NULL,
|
||||||
auto_monitor BOOLEAN DEFAULT 1,
|
auto_monitor BOOLEAN DEFAULT 1,
|
||||||
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
||||||
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
|
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
UNIQUE(site_url, account)
|
|
||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
def init_vpslist_db(self):
|
def init_vpslist_db(self):
|
||||||
"""初始化vpslist.db - VPS列表缓存表"""
|
"""初始化vpslist.db - VPS列表缓存表"""
|
||||||
conn = self.get_connection(self.vpslist_db)
|
conn = self.get_connection(self.vpslist_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
CREATE TABLE IF NOT EXISTS vps_list (
|
CREATE TABLE IF NOT EXISTS vps_list (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@ -80,19 +80,22 @@ class DatabaseManager:
|
|||||||
FOREIGN KEY (config_id) REFERENCES configs(id)
|
FOREIGN KEY (config_id) REFERENCES configs(id)
|
||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
|
|
||||||
cursor.execute('CREATE INDEX IF NOT EXISTS idx_vps_config ON vps_list(config_id)')
|
cursor.execute(
|
||||||
cursor.execute('CREATE INDEX IF NOT EXISTS idx_vps_vps_id ON vps_list(vps_id)')
|
'CREATE INDEX IF NOT EXISTS idx_vps_config ON vps_list(config_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_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.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
def init_status_db(self):
|
def init_status_db(self):
|
||||||
"""初始化status.db - Ping状态记录和摘要统计表"""
|
"""初始化status.db - Ping状态记录和摘要统计表"""
|
||||||
conn = self.get_connection(self.status_db)
|
conn = self.get_connection(self.status_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
CREATE TABLE IF NOT EXISTS ping_status (
|
CREATE TABLE IF NOT EXISTS ping_status (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@ -103,7 +106,7 @@ class DatabaseManager:
|
|||||||
check_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
check_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
|
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
CREATE TABLE IF NOT EXISTS vps_summary (
|
CREATE TABLE IF NOT EXISTS vps_summary (
|
||||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
@ -120,36 +123,40 @@ class DatabaseManager:
|
|||||||
UNIQUE(vps_id, date)
|
UNIQUE(vps_id, date)
|
||||||
)
|
)
|
||||||
''')
|
''')
|
||||||
|
|
||||||
cursor.execute('CREATE INDEX IF NOT EXISTS idx_ping_vps ON ping_status(vps_id)')
|
cursor.execute(
|
||||||
cursor.execute('CREATE INDEX IF NOT EXISTS idx_ping_time ON ping_status(check_time)')
|
'CREATE INDEX IF NOT EXISTS idx_ping_vps ON ping_status(vps_id)')
|
||||||
cursor.execute('CREATE INDEX IF NOT EXISTS idx_summary_vps ON vps_summary(vps_id)')
|
cursor.execute(
|
||||||
cursor.execute('CREATE INDEX IF NOT EXISTS idx_summary_date ON vps_summary(date)')
|
'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.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
# ==================== vps.db 操作 ====================
|
# ==================== vps.db 操作 ====================
|
||||||
|
|
||||||
def add_config(self, api_label, site_type, account, api_key, site_url=None, auto_monitor=True):
|
def add_config(self, api_label, site_type, account, api_key, site_url=None, auto_monitor=True):
|
||||||
"""添加VPS配置,基于site_url和account去重"""
|
"""添加VPS配置,基于site_url和account去重"""
|
||||||
conn = self.get_connection(self.vps_db)
|
conn = self.get_connection(self.vps_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
existing = cursor.execute(
|
existing = cursor.execute(
|
||||||
'SELECT id FROM configs WHERE site_url = ? AND account = ?',
|
'SELECT id FROM configs WHERE site_url = ? AND account = ?',
|
||||||
(site_url, account)
|
(site_url, account)
|
||||||
).fetchone()
|
).fetchone()
|
||||||
|
|
||||||
if existing:
|
if existing:
|
||||||
return existing['id']
|
return existing['id']
|
||||||
|
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
INSERT INTO configs (api_label, site_type, site_url, account, api_key, auto_monitor)
|
INSERT INTO configs (api_label, site_type, site_url, account, api_key, auto_monitor)
|
||||||
VALUES (?, ?, ?, ?, ?, ?)
|
VALUES (?, ?, ?, ?, ?, ?)
|
||||||
''', (api_label, site_type, site_url, account, api_key, auto_monitor))
|
''', (api_label, site_type, site_url, account, api_key, auto_monitor))
|
||||||
|
|
||||||
config_id = cursor.lastrowid
|
config_id = cursor.lastrowid
|
||||||
conn.commit()
|
conn.commit()
|
||||||
return config_id
|
return config_id
|
||||||
@ -158,82 +165,83 @@ class DatabaseManager:
|
|||||||
raise e
|
raise e
|
||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
def get_all_configs(self):
|
def get_all_configs(self):
|
||||||
"""获取所有配置"""
|
"""获取所有配置"""
|
||||||
conn = self.get_connection(self.vps_db)
|
conn = self.get_connection(self.vps_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
cursor.execute('SELECT * FROM configs ORDER BY id')
|
cursor.execute('SELECT * FROM configs ORDER BY id')
|
||||||
configs = [dict(row) for row in cursor.fetchall()]
|
configs = [dict(row) for row in cursor.fetchall()]
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
return configs
|
return configs
|
||||||
|
|
||||||
def get_config_by_id(self, config_id):
|
def get_config_by_id(self, config_id):
|
||||||
"""根据ID获取配置"""
|
"""根据ID获取配置"""
|
||||||
conn = self.get_connection(self.vps_db)
|
conn = self.get_connection(self.vps_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
cursor.execute('SELECT * FROM configs WHERE id = ?', (config_id,))
|
cursor.execute('SELECT * FROM configs WHERE id = ?', (config_id,))
|
||||||
row = cursor.fetchone()
|
row = cursor.fetchone()
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
return dict(row) if row else None
|
return dict(row) if row else None
|
||||||
|
|
||||||
def update_config(self, config_id, **kwargs):
|
def update_config(self, config_id, **kwargs):
|
||||||
"""更新配置"""
|
"""更新配置"""
|
||||||
if not kwargs:
|
if not kwargs:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
conn = self.get_connection(self.vps_db)
|
conn = self.get_connection(self.vps_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
fields = ', '.join([f"{key} = ?" for key in kwargs.keys()])
|
fields = ', '.join([f"{key} = ?" for key in kwargs.keys()])
|
||||||
values = list(kwargs.values())
|
values = list(kwargs.values())
|
||||||
values.append(config_id)
|
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
|
affected = cursor.rowcount
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return affected > 0
|
return affected > 0
|
||||||
|
|
||||||
def delete_config(self, config_id):
|
def delete_config(self, config_id):
|
||||||
"""删除配置"""
|
"""删除配置"""
|
||||||
conn = self.get_connection(self.vps_db)
|
conn = self.get_connection(self.vps_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
cursor.execute('DELETE FROM configs WHERE id = ?', (config_id,))
|
cursor.execute('DELETE FROM configs WHERE id = ?', (config_id,))
|
||||||
|
|
||||||
affected = cursor.rowcount
|
affected = cursor.rowcount
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return affected > 0
|
return affected > 0
|
||||||
|
|
||||||
def reset_config_ids(self):
|
def reset_config_ids(self):
|
||||||
"""重置configs表的ID序列,从1开始连续编号"""
|
"""重置configs表的ID序列,从1开始连续编号"""
|
||||||
conn = self.get_connection(self.vps_db)
|
conn = self.get_connection(self.vps_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cursor.execute('SELECT * FROM configs ORDER BY id')
|
cursor.execute('SELECT * FROM configs ORDER BY id')
|
||||||
configs = [dict(row) for row in cursor.fetchall()]
|
configs = [dict(row) for row in cursor.fetchall()]
|
||||||
|
|
||||||
if not configs:
|
if not configs:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
cursor.execute('DROP TABLE IF EXISTS configs_backup')
|
cursor.execute('DROP TABLE IF EXISTS configs_backup')
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
CREATE TABLE configs_backup AS SELECT * FROM configs
|
CREATE TABLE configs_backup AS SELECT * FROM configs
|
||||||
''')
|
''')
|
||||||
|
|
||||||
cursor.execute('DELETE FROM configs')
|
cursor.execute('DELETE FROM configs')
|
||||||
cursor.execute("DELETE FROM sqlite_sequence WHERE name='configs'")
|
cursor.execute("DELETE FROM sqlite_sequence WHERE name='configs'")
|
||||||
|
|
||||||
for config in configs:
|
for config in configs:
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
INSERT INTO configs (api_label, site_type, site_url, account, api_key, auto_monitor, created_at, updated_at)
|
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['created_at'],
|
||||||
config['updated_at']
|
config['updated_at']
|
||||||
))
|
))
|
||||||
|
|
||||||
cursor.execute('DROP TABLE IF EXISTS configs_backup')
|
cursor.execute('DROP TABLE IF EXISTS configs_backup')
|
||||||
conn.commit()
|
conn.commit()
|
||||||
return True
|
return True
|
||||||
@ -257,35 +265,35 @@ class DatabaseManager:
|
|||||||
raise e
|
raise e
|
||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
# ==================== vpslist.db 操作 ====================
|
# ==================== vpslist.db 操作 ====================
|
||||||
|
|
||||||
def get_next_available_id(self):
|
def get_next_available_id(self):
|
||||||
"""获取下一个可用的ID(填补空缺)"""
|
"""获取下一个可用的ID(填补空缺)"""
|
||||||
conn = self.get_connection(self.vpslist_db)
|
conn = self.get_connection(self.vpslist_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
cursor.execute('SELECT id FROM vps_list ORDER BY id')
|
cursor.execute('SELECT id FROM vps_list ORDER BY id')
|
||||||
ids = [row['id'] for row in cursor.fetchall()]
|
ids = [row['id'] for row in cursor.fetchall()]
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
if not ids:
|
if not ids:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
for i in range(1, max(ids) + 1):
|
for i in range(1, max(ids) + 1):
|
||||||
if i not in ids:
|
if i not in ids:
|
||||||
return i
|
return i
|
||||||
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def add_vps(self, config_id, vps_id, domain=None, ip_address=None, product_name=None, section=False, custom_id=None):
|
def add_vps(self, config_id, vps_id, domain=None, ip_address=None, product_name=None, section=False, custom_id=None):
|
||||||
"""添加VPS到列表,支持指定ID以填补空缺"""
|
"""添加VPS到列表,支持指定ID以填补空缺"""
|
||||||
conn = self.get_connection(self.vpslist_db)
|
conn = self.get_connection(self.vpslist_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
if custom_id is None:
|
if custom_id is None:
|
||||||
custom_id = self.get_next_available_id()
|
custom_id = self.get_next_available_id()
|
||||||
|
|
||||||
if custom_id:
|
if custom_id:
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
INSERT INTO vps_list (id, config_id, vps_id, domain, ip_address, product_name, section, last_check)
|
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)
|
INSERT INTO vps_list (config_id, vps_id, domain, ip_address, product_name, section, last_check)
|
||||||
VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
|
VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
|
||||||
''', (config_id, vps_id, domain, ip_address, product_name, section))
|
''', (config_id, vps_id, domain, ip_address, product_name, section))
|
||||||
|
|
||||||
record_id = cursor.lastrowid
|
record_id = cursor.lastrowid
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return record_id
|
return record_id
|
||||||
|
|
||||||
def batch_add_vps(self, vps_list):
|
def batch_add_vps(self, vps_list):
|
||||||
"""批量添加VPS,基于vps_id和ip_address去重"""
|
"""批量添加VPS,基于vps_id和ip_address去重"""
|
||||||
conn = self.get_connection(self.vpslist_db)
|
conn = self.get_connection(self.vpslist_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
for vps in vps_list:
|
for vps in vps_list:
|
||||||
existing = cursor.execute(
|
existing = cursor.execute(
|
||||||
'SELECT id FROM vps_list WHERE vps_id = ? AND ip_address = ?',
|
'SELECT id FROM vps_list WHERE vps_id = ? AND ip_address = ?',
|
||||||
(vps['vps_id'], vps.get('ip_address'))
|
(vps['vps_id'], vps.get('ip_address'))
|
||||||
).fetchone()
|
).fetchone()
|
||||||
|
|
||||||
if existing:
|
if existing:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
custom_id = self.get_next_available_id()
|
custom_id = self.get_next_available_id()
|
||||||
|
|
||||||
if custom_id:
|
if custom_id:
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
INSERT INTO vps_list
|
INSERT INTO vps_list
|
||||||
@ -360,87 +368,90 @@ class DatabaseManager:
|
|||||||
vps.get('nextduedate'),
|
vps.get('nextduedate'),
|
||||||
vps.get('section', False)
|
vps.get('section', False)
|
||||||
))
|
))
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
def get_all_vps(self):
|
def get_all_vps(self):
|
||||||
"""获取所有VPS"""
|
"""获取所有VPS"""
|
||||||
conn = self.get_connection(self.vpslist_db)
|
conn = self.get_connection(self.vpslist_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
cursor.execute('SELECT * FROM vps_list ORDER BY config_id, vps_id')
|
cursor.execute('SELECT * FROM vps_list ORDER BY config_id, vps_id')
|
||||||
vps_list = [dict(row) for row in cursor.fetchall()]
|
vps_list = [dict(row) for row in cursor.fetchall()]
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
return vps_list
|
return vps_list
|
||||||
|
|
||||||
def get_vps_by_config(self, config_id):
|
def get_vps_by_config(self, config_id):
|
||||||
"""根据配置ID获取VPS列表"""
|
"""根据配置ID获取VPS列表"""
|
||||||
conn = self.get_connection(self.vpslist_db)
|
conn = self.get_connection(self.vpslist_db)
|
||||||
cursor = conn.cursor()
|
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()]
|
vps_list = [dict(row) for row in cursor.fetchall()]
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
return vps_list
|
return vps_list
|
||||||
|
|
||||||
def update_vps_details(self, vps_id, **kwargs):
|
def update_vps_details(self, vps_id, **kwargs):
|
||||||
"""更新VPS详细信息"""
|
"""更新VPS详细信息"""
|
||||||
if not kwargs:
|
if not kwargs:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
conn = self.get_connection(self.vpslist_db)
|
conn = self.get_connection(self.vpslist_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
fields = ', '.join([f"{key} = ?" for key in kwargs.keys()])
|
fields = ', '.join([f"{key} = ?" for key in kwargs.keys()])
|
||||||
values = list(kwargs.values())
|
values = list(kwargs.values())
|
||||||
values.append(vps_id)
|
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
|
affected = cursor.rowcount
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return affected > 0
|
return affected > 0
|
||||||
|
|
||||||
def update_vps_status(self, vps_id, status):
|
def update_vps_status(self, vps_id, status):
|
||||||
"""更新VPS状态"""
|
"""更新VPS状态"""
|
||||||
return self.update_vps_details(vps_id, status=status)
|
return self.update_vps_details(vps_id, status=status)
|
||||||
|
|
||||||
def get_monitored_vps(self):
|
def get_monitored_vps(self):
|
||||||
"""获取所有标记为需要监控的VPS"""
|
"""获取所有标记为需要监控的VPS"""
|
||||||
conn = self.get_connection(self.vpslist_db)
|
conn = self.get_connection(self.vpslist_db)
|
||||||
cursor = conn.cursor()
|
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()]
|
vps_list = [dict(row) for row in cursor.fetchall()]
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
return vps_list
|
return vps_list
|
||||||
|
|
||||||
def reset_vps_list_ids(self):
|
def reset_vps_list_ids(self):
|
||||||
"""重置vps_list表的ID序列,从1开始连续编号"""
|
"""重置vps_list表的ID序列,从1开始连续编号"""
|
||||||
conn = self.get_connection(self.vpslist_db)
|
conn = self.get_connection(self.vpslist_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
cursor.execute('SELECT * FROM vps_list ORDER BY id')
|
cursor.execute('SELECT * FROM vps_list ORDER BY id')
|
||||||
vps_items = [dict(row) for row in cursor.fetchall()]
|
vps_items = [dict(row) for row in cursor.fetchall()]
|
||||||
|
|
||||||
if not vps_items:
|
if not vps_items:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
cursor.execute('DROP TABLE IF EXISTS vps_list_backup')
|
cursor.execute('DROP TABLE IF EXISTS vps_list_backup')
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
CREATE TABLE vps_list_backup AS SELECT * FROM vps_list
|
CREATE TABLE vps_list_backup AS SELECT * FROM vps_list
|
||||||
''')
|
''')
|
||||||
|
|
||||||
cursor.execute('DELETE FROM vps_list')
|
cursor.execute('DELETE FROM vps_list')
|
||||||
cursor.execute("DELETE FROM sqlite_sequence WHERE name='vps_list'")
|
cursor.execute("DELETE FROM sqlite_sequence WHERE name='vps_list'")
|
||||||
|
|
||||||
for vps in vps_items:
|
for vps in vps_items:
|
||||||
cursor.execute('''
|
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)
|
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('section', 0),
|
||||||
vps.get('last_check')
|
vps.get('last_check')
|
||||||
))
|
))
|
||||||
|
|
||||||
cursor.execute('DROP TABLE IF EXISTS vps_list_backup')
|
cursor.execute('DROP TABLE IF EXISTS vps_list_backup')
|
||||||
conn.commit()
|
conn.commit()
|
||||||
return True
|
return True
|
||||||
@ -471,27 +482,27 @@ class DatabaseManager:
|
|||||||
raise e
|
raise e
|
||||||
finally:
|
finally:
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
# ==================== status.db 操作 ====================
|
# ==================== status.db 操作 ====================
|
||||||
|
|
||||||
def save_ping_status(self, vps_id, target, status, latency_ms=None):
|
def save_ping_status(self, vps_id, target, status, latency_ms=None):
|
||||||
"""保存Ping状态记录"""
|
"""保存Ping状态记录"""
|
||||||
conn = self.get_connection(self.status_db)
|
conn = self.get_connection(self.status_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
INSERT INTO ping_status (vps_id, target, status, latency_ms)
|
INSERT INTO ping_status (vps_id, target, status, latency_ms)
|
||||||
VALUES (?, ?, ?, ?)
|
VALUES (?, ?, ?, ?)
|
||||||
''', (vps_id, target, status, latency_ms))
|
''', (vps_id, target, status, latency_ms))
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
def get_ping_records(self, vps_id, date=None):
|
def get_ping_records(self, vps_id, date=None):
|
||||||
"""获取Ping记录"""
|
"""获取Ping记录"""
|
||||||
conn = self.get_connection(self.status_db)
|
conn = self.get_connection(self.status_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
if date:
|
if date:
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
SELECT * FROM ping_status
|
SELECT * FROM ping_status
|
||||||
@ -504,35 +515,37 @@ class DatabaseManager:
|
|||||||
WHERE vps_id = ?
|
WHERE vps_id = ?
|
||||||
ORDER BY check_time DESC
|
ORDER BY check_time DESC
|
||||||
''', (vps_id,))
|
''', (vps_id,))
|
||||||
|
|
||||||
records = [dict(row) for row in cursor.fetchall()]
|
records = [dict(row) for row in cursor.fetchall()]
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return records
|
return records
|
||||||
|
|
||||||
def cleanup_old_ping_records(self, days=30):
|
def cleanup_old_ping_records(self, days=30):
|
||||||
"""清理旧的Ping记录"""
|
"""清理旧的Ping记录"""
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
conn = self.get_connection(self.status_db)
|
conn = self.get_connection(self.status_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
cutoff_date = (datetime.now() - timedelta(days=days)).strftime('%Y-%m-%d %H:%M:%S')
|
cutoff_date = (datetime.now() - timedelta(days=days)
|
||||||
cursor.execute('DELETE FROM ping_status WHERE check_time < ?', (cutoff_date,))
|
).strftime('%Y-%m-%d %H:%M:%S')
|
||||||
|
cursor.execute(
|
||||||
|
'DELETE FROM ping_status WHERE check_time < ?', (cutoff_date,))
|
||||||
|
|
||||||
deleted = cursor.rowcount
|
deleted = cursor.rowcount
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return deleted
|
return deleted
|
||||||
|
|
||||||
def save_vps_summary(self, vps_id, date, avg_latency, max_latency, min_latency,
|
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_under_100, count_100_to_300, count_300_to_500,
|
||||||
count_abnormal, availability):
|
count_abnormal, availability):
|
||||||
"""保存VPS摘要统计"""
|
"""保存VPS摘要统计"""
|
||||||
conn = self.get_connection(self.status_db)
|
conn = self.get_connection(self.status_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
INSERT OR REPLACE INTO vps_summary
|
INSERT OR REPLACE INTO vps_summary
|
||||||
(vps_id, date, avg_latency_ms, max_latency_ms, min_latency_ms,
|
(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,
|
''', (vps_id, date, avg_latency, max_latency, min_latency,
|
||||||
count_under_100, count_100_to_300, count_300_to_500,
|
count_under_100, count_100_to_300, count_300_to_500,
|
||||||
count_abnormal, availability))
|
count_abnormal, availability))
|
||||||
|
|
||||||
conn.commit()
|
conn.commit()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
def get_vps_summary(self, vps_id, date=None):
|
def get_vps_summary(self, vps_id, date=None):
|
||||||
"""获取VPS摘要统计"""
|
"""获取VPS摘要统计"""
|
||||||
conn = self.get_connection(self.status_db)
|
conn = self.get_connection(self.status_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
if date:
|
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:
|
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()
|
row = cursor.fetchone()
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return dict(row) if row else None
|
return dict(row) if row else None
|
||||||
|
|
||||||
def get_all_summaries(self, date=None):
|
def get_all_summaries(self, date=None):
|
||||||
"""获取所有VPS的摘要统计"""
|
"""获取所有VPS的摘要统计"""
|
||||||
conn = self.get_connection(self.status_db)
|
conn = self.get_connection(self.status_db)
|
||||||
cursor = conn.cursor()
|
cursor = conn.cursor()
|
||||||
|
|
||||||
if date:
|
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:
|
else:
|
||||||
cursor.execute('''
|
cursor.execute('''
|
||||||
SELECT vs.* FROM vps_summary vs
|
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
|
) latest ON vs.vps_id = latest.vps_id AND vs.date = latest.max_date
|
||||||
ORDER BY vs.vps_id
|
ORDER BY vs.vps_id
|
||||||
''')
|
''')
|
||||||
|
|
||||||
summaries = [dict(row) for row in cursor.fetchall()]
|
summaries = [dict(row) for row in cursor.fetchall()]
|
||||||
conn.close()
|
conn.close()
|
||||||
|
|
||||||
return summaries
|
return summaries
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
86
index.php
86
index.php
@ -87,8 +87,52 @@ if ($_SERVER['REQUEST_METHOD'] === 'POST') {
|
|||||||
$errorMsg = $result['error'] ?? $result['msg'] ?? '未知错误';
|
$errorMsg = $result['error'] ?? $result['msg'] ?? '未知错误';
|
||||||
$message = '<div class="error-message"><h3>❌ 操作失败</h3><p>' . htmlspecialchars($errorMsg) . '</p></div>';
|
$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') {
|
} elseif ($action === 'refresh_vps_list') {
|
||||||
// 手动刷新VPS列表
|
// 手动刷新VPS列表(全部)
|
||||||
$count = 0;
|
$count = 0;
|
||||||
|
|
||||||
// 刷新魔方平台的VPS列表
|
// 刷新魔方平台的VPS列表
|
||||||
@ -201,6 +245,12 @@ foreach ($vpsList as $vps) {
|
|||||||
$vpsByApiLabel[$apiLabel][] = $vps;
|
$vpsByApiLabel[$apiLabel][] = $vps;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 构建api_label到config_id的映射(用于单独刷新)
|
||||||
|
$apiLabelToConfigId = [];
|
||||||
|
foreach ($configs as $config) {
|
||||||
|
$apiLabelToConfigId[$config['api_label']] = $config['id'];
|
||||||
|
}
|
||||||
|
|
||||||
// 统计信息
|
// 统计信息
|
||||||
$totalCount = count($vpsList);
|
$totalCount = count($vpsList);
|
||||||
$runningCount = 0;
|
$runningCount = 0;
|
||||||
@ -245,6 +295,11 @@ foreach ($vpsList as $vps) {
|
|||||||
.btn-refresh:hover {
|
.btn-refresh:hover {
|
||||||
background-color: #0056b3;
|
background-color: #0056b3;
|
||||||
}
|
}
|
||||||
|
.config-title {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
/* 消息自动消失动画 */
|
/* 消息自动消失动画 */
|
||||||
.success-message, .error-message {
|
.success-message, .error-message {
|
||||||
transition: opacity 0.5s ease-out;
|
transition: opacity 0.5s ease-out;
|
||||||
@ -417,9 +472,9 @@ foreach ($vpsList as $vps) {
|
|||||||
|
|
||||||
<!-- 工具栏 -->
|
<!-- 工具栏 -->
|
||||||
<div class="toolbar">
|
<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">
|
<button type="submit" name="action" value="refresh_vps_list" class="btn-refresh">
|
||||||
🔄 手动刷新VPS列表
|
🔄 刷新全部列表
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
@ -454,13 +509,21 @@ foreach ($vpsList as $vps) {
|
|||||||
<?php foreach ($vpsByApiLabel as $apiLabel => $labelVps): ?>
|
<?php foreach ($vpsByApiLabel as $apiLabel => $labelVps): ?>
|
||||||
<div class="config-section">
|
<div class="config-section">
|
||||||
<div class="config-title">
|
<div class="config-title">
|
||||||
<?php echo htmlspecialchars($apiLabel); ?>
|
<span>
|
||||||
- <?php echo count($labelVps); ?> 台VPS
|
<?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>
|
</div>
|
||||||
|
|
||||||
<?php if (empty($labelVps)): ?>
|
<?php if (empty($labelVps)): ?>
|
||||||
<div class="empty-state" style="background: white; padding: 40px;">
|
<div class="empty-state" style="background: white; padding: 40px;">
|
||||||
<p>此配置下暂无VPS,请点击“手动刷新VPS列表”获取</p>
|
<p>此配置下暂无VPS,请点击右上角“🔄 刷新此配置”按钮获取</p>
|
||||||
</div>
|
</div>
|
||||||
<?php else: ?>
|
<?php else: ?>
|
||||||
<div class="vps-grid">
|
<div class="vps-grid">
|
||||||
@ -627,6 +690,17 @@ foreach ($vpsList as $vps) {
|
|||||||
}, 5000); // 5秒后开始淡出
|
}, 5000); // 5秒后开始淡出
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 刷新全部列表确认
|
||||||
|
function confirmRefreshAll() {
|
||||||
|
return confirm('⚠️ 警告:资源消耗占用较高\n\n' +
|
||||||
|
'刷新全部列表会同时请求所有配置的API,可能会导致:\n' +
|
||||||
|
'• 页面卡顿或响应缓慢\n' +
|
||||||
|
'• API超时导致报错中断\n' +
|
||||||
|
'• 部分配置刷新失败\n\n' +
|
||||||
|
'建议优先使用分离式刷新功能(点击每个配置右上角的🔄按钮)\n\n' +
|
||||||
|
'确定要继续刷新全部列表吗?');
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user