chore: sync local updates

This commit is contained in:
2026-05-16 19:03:32 +08:00
parent 360a5f15b9
commit aff88ba97d
47 changed files with 3651 additions and 12175 deletions

View File

@@ -0,0 +1,136 @@
// 将 data/*.json站点与分组导入 MySQL。建议空库首次使用或加 -wipe 清空业务表后再导。
//
// go run ./cmd/importjson -data ./data -wipe
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"os"
"path/filepath"
"gorm.io/datatypes"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"mengyaping-backend/config"
"mengyaping-backend/models"
"mengyaping-backend/storage"
)
func main() {
dataDir := flag.String("data", "./data", "JSON 目录websites.json、groups.json")
wipe := flag.Bool("wipe", false, "导入前 TRUNCATE 所有 monitor_* 表(慎用)")
flag.Parse()
cfg := config.GetConfig()
// 大批量 INSERT 时单条超过 200ms 会触发 GORM 默认「SLOW SQL」提示易被误认为报错导入工具改为静默 SQL 日志
db, err := gorm.Open(mysql.Open(cfg.DatabaseDSN()), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
})
if err != nil {
log.Fatal(err)
}
if err := db.AutoMigrate(
&storage.MonitorGroup{},
&storage.MonitorWebsite{},
&storage.MonitorWebsiteURL{},
&storage.MonitorWebsiteGroup{},
&storage.MonitorProbeLatest{},
&storage.MonitorProbeHour{},
&storage.MonitorProbeDay{},
&storage.MonitorKV{},
); err != nil {
log.Fatal(err)
}
if *wipe {
_ = db.Exec("SET FOREIGN_KEY_CHECKS = 0").Error
for _, tbl := range []string{
"monitor_probe_latest",
"monitor_probe_hour",
"monitor_probe_day",
"monitor_kv",
"monitor_checks",
"monitor_website_urls",
"monitor_website_groups",
"monitor_websites",
"monitor_groups",
} {
_ = db.Exec("TRUNCATE TABLE " + tbl).Error
}
_ = db.Exec("SET FOREIGN_KEY_CHECKS = 1").Error
log.Println("已清空 monitor_* 表")
}
websitesPath := filepath.Join(*dataDir, "websites.json")
raw, err := os.ReadFile(websitesPath)
if err != nil {
log.Fatalf("读取 websites.json: %v", err)
}
var websites []models.Website
if err := json.Unmarshal(raw, &websites); err != nil {
log.Fatal(err)
}
groupsPath := filepath.Join(*dataDir, "groups.json")
var fileGroups []models.Group
if g, err := os.ReadFile(groupsPath); err == nil {
_ = json.Unmarshal(g, &fileGroups)
}
if len(fileGroups) == 0 {
fileGroups = models.DefaultGroups
}
for i, g := range fileGroups {
if err := db.Create(&storage.MonitorGroup{
ID: g.ID, Name: g.Name, SortOrder: i + 1,
}).Error; err != nil {
log.Printf("导入分组 %s: %v", g.ID, err)
}
}
for _, w := range websites {
if len(w.Groups) == 0 && w.Group != "" {
w.Groups = []string{w.Group}
}
row := &storage.MonitorWebsite{
ID: w.ID,
Name: w.Name,
LegacyGroup: "",
Favicon: w.Favicon,
Title: w.Title,
IPAddresses: datatypes.JSON(mustJSON(w.IPAddresses)),
CreatedAt: w.CreatedAt,
UpdatedAt: w.UpdatedAt,
}
if err := db.Create(row).Error; err != nil {
log.Printf("网站 %s: %v", w.ID, err)
continue
}
for i, u := range w.URLs {
_ = db.Create(&storage.MonitorWebsiteURL{
WebsiteID: w.ID, URLID: u.ID, URL: u.URL, Remark: u.Remark, SortOrder: i,
})
}
for _, gid := range w.Groups {
_ = db.Create(&storage.MonitorWebsiteGroup{WebsiteID: w.ID, GroupID: gid})
}
}
fmt.Printf("已导入 %d 个网站\n", len(websites))
log.Println("探测历史由运行时写入 monitor_probe_* 汇总表,不再从 records.json 导入")
}
func mustJSON(v []string) []byte {
if v == nil {
return []byte("[]")
}
b, err := json.Marshal(v)
if err != nil {
return []byte("[]")
}
return b
}