后端更新: - 在 machines 表新增 offline_count、total_offline_seconds、last_offline_at、last_offline_reason 字段,用于记录机器离线统计信息。 - 新增 offline_logs 表,记录每次离线的开始时间、结束时间、持续时长及离线原因。 - 重写 ping 服务为状态机模式: – 单台机器依次使用 system ping / ICMP / TCP(SSH端口) 三种方式检测连通性; – 任意一次成功即视为在线; – 若一次失败,则会连续重试 3 次(间隔 2 秒),3 次均失败才判定为离线,避免网络抖动导致误判。 – 仅在状态发生 online→offline 或 offline→online 变化时更新 offline_logs 与累计时长。 – 机器按顺序逐个检测,每台间隔 30 秒。 - 新增 API:GET /admin/machines/:id/offline-logs,用于查询最近 50 条离线记录。 - CleanupLogs 增加对 offline_logs 的过期清理。 前端更新: - 机器详情页(MachineDetail.vue)新增离线统计卡片,展示离线次数、累计离线时长、上次离线原因及最近 5 条离线记录。 - 全局支持暗黑模式: – App.vue 引入 light/dark CSS 变量,并加载 Element Plus 深色主题(dark/css-vars.css)。 – MainLayout.vue 侧边栏新增主题切换按钮,支持深浅色切换并持久化到 localStorage。 – Topology.vue 监听主题变化,动态重绘 G6 节点/边的颜色、背景与阴影。 – MachineList.vue / MachineDetail.vue 全面适配深色变量(卡片、表格、标签、进度条等)。 - 机器列表卡片 UI 调整:改为顶部 OS 色点 + 在线/离线状态胶囊标签,离线卡片降低透明度并去色。 构建与部署: - 重新构建前端并打包静态资源。 - 交叉编译 Linux amd64 二进制并更新 deploy/lan-manager-debian12.tar.gz 部署包。
122 lines
3.7 KiB
Go
122 lines
3.7 KiB
Go
package db
|
|
|
|
import (
|
|
"database/sql"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"lan-manager/server/config"
|
|
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
var DB *sql.DB
|
|
|
|
func Init(cfg *config.Config) error {
|
|
if err := os.MkdirAll(filepath.Dir(cfg.DBPath), 0750); err != nil {
|
|
return err
|
|
}
|
|
var err error
|
|
DB, err = sql.Open("sqlite", cfg.DBPath+"?_pragma=foreign_keys(1)")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := DB.Ping(); err != nil {
|
|
return err
|
|
}
|
|
DB.SetMaxOpenConns(1)
|
|
return migrate()
|
|
}
|
|
|
|
func migrate() error {
|
|
stmts := []string{
|
|
`CREATE TABLE IF NOT EXISTS machines (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
hostname TEXT NOT NULL,
|
|
ip TEXT NOT NULL UNIQUE,
|
|
mac TEXT,
|
|
os_type TEXT NOT NULL,
|
|
os_version TEXT,
|
|
notes TEXT,
|
|
ssh_port INTEGER DEFAULT 22,
|
|
is_online INTEGER DEFAULT 0,
|
|
last_ping_at DATETIME,
|
|
cpu_info TEXT,
|
|
memory_info TEXT,
|
|
disk_info TEXT,
|
|
uptime TEXT,
|
|
listen_ports TEXT,
|
|
ssh_synced_at DATETIME,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)`,
|
|
`ALTER TABLE machines ADD COLUMN ssh_port INTEGER DEFAULT 22`,
|
|
`ALTER TABLE machines ADD COLUMN ssh_username TEXT`,
|
|
`ALTER TABLE machines ADD COLUMN ssh_password TEXT`,
|
|
`CREATE TABLE IF NOT EXISTS services (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
machine_id INTEGER NOT NULL REFERENCES machines(id) ON DELETE CASCADE,
|
|
name TEXT NOT NULL,
|
|
port INTEGER NOT NULL,
|
|
protocol TEXT DEFAULT 'TCP',
|
|
notes TEXT,
|
|
target_machine_id INTEGER REFERENCES machines(id) ON DELETE SET NULL,
|
|
target_notes TEXT
|
|
)`,
|
|
`ALTER TABLE services ADD COLUMN target_machine_id INTEGER REFERENCES machines(id) ON DELETE SET NULL`,
|
|
`ALTER TABLE services ADD COLUMN target_notes TEXT`,
|
|
`CREATE TABLE IF NOT EXISTS relationships (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
source_machine_id INTEGER NOT NULL REFERENCES machines(id) ON DELETE CASCADE,
|
|
target_machine_id INTEGER NOT NULL REFERENCES machines(id) ON DELETE CASCADE,
|
|
relation_type TEXT NOT NULL,
|
|
source_port INTEGER,
|
|
target_port INTEGER,
|
|
notes TEXT
|
|
)`,
|
|
`CREATE TABLE IF NOT EXISTS operation_logs (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
action TEXT NOT NULL,
|
|
entity_type TEXT NOT NULL,
|
|
entity_id INTEGER,
|
|
entity_name TEXT,
|
|
old_value TEXT,
|
|
new_value TEXT,
|
|
source_ip TEXT,
|
|
username TEXT,
|
|
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
|
|
)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_machines_ip ON machines(ip)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_services_machine ON services(machine_id)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_rel_src ON relationships(source_machine_id)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_rel_tgt ON relationships(target_machine_id)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_logs_created ON operation_logs(created_at)`,
|
|
`ALTER TABLE machines ADD COLUMN offline_count INTEGER DEFAULT 0`,
|
|
`ALTER TABLE machines ADD COLUMN total_offline_seconds INTEGER DEFAULT 0`,
|
|
`ALTER TABLE machines ADD COLUMN last_offline_at DATETIME`,
|
|
`ALTER TABLE machines ADD COLUMN last_offline_reason TEXT`,
|
|
`CREATE TABLE IF NOT EXISTS offline_logs (
|
|
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
machine_id INTEGER NOT NULL REFERENCES machines(id) ON DELETE CASCADE,
|
|
reason TEXT,
|
|
started_at DATETIME DEFAULT CURRENT_TIMESTAMP,
|
|
ended_at DATETIME,
|
|
duration_seconds INTEGER
|
|
)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_offline_logs_machine ON offline_logs(machine_id)`,
|
|
`CREATE INDEX IF NOT EXISTS idx_offline_logs_started ON offline_logs(started_at)`,
|
|
}
|
|
for _, s := range stmts {
|
|
if _, err := DB.Exec(s); err != nil {
|
|
// ignore "duplicate column" errors for ALTER TABLE compatibility
|
|
if strings.Contains(err.Error(), "duplicate column name") {
|
|
continue
|
|
}
|
|
return fmt.Errorf("migration failed: %w", err)
|
|
}
|
|
}
|
|
return nil
|
|
}
|