package m9zApi import ( "encoding/json" "fmt" "github.com/gogf/gf/v2/errors/gerror" "github.com/towgo/towgo/lib/system" "os" "path/filepath" "sort" "sync" "tgk-touch/internal/global" "tgk-touch/internal/library/m9z" "time" ) var l sync.Mutex var filePath = system.GetPathOfProgram() + "data/data.json" // JSON 文件路径 const ( maxItems = 50 // 最大存储条数 ) func ScanM9z() { tryLock := l.TryLock() if !tryLock { return } defer l.Unlock() /** 挨个查询是否有报警*/ cuid := deviceInfo["deviceId"].(string) for i := 0; i < 10; i++ { read, err := m9z.SubLoopParametersRead(cuid, uint(i)) if err != nil { g.Log().Error("sub loop parameters read error:", err) continue } if read == nil { continue } if read.AlarmStatus != 0 { var mph M9zFaultHistory mph.CommUid = cuid mph.LoopIdx = uint(i) + 1 mph.FaultCode = read.AlarmCode mph.Voltage = read.DCVoltage mph.FaultTime = time.Now() switch read.AlarmStatus { case 1: mph.FaultMsg = "欠压/短路故障" break case 2: mph.FaultMsg = "过压/开路故障" break case 8: mph.FaultMsg = "电源故障" break case 9: mph.FaultMsg = "欠压/电源故障" break default: mph.FaultMsg = "未知异常" } err = addData(mph) if err != nil { g.Log().Error(gerror.Wrap(err, "create error")) } } } } // 读取现有数据(如果文件不存在则返回空切片) func readData() ([]M9zFaultHistory, error) { if _, err := os.Stat(filePath); os.IsNotExist(err) { _, err := createFileWithPath(filePath) if err != nil { return nil, gerror.Wrap(err, "create file error") } return []M9zFaultHistory{}, nil // 文件不存在,返回空切片 } data, err := os.ReadFile(filePath) if err != nil { return nil, fmt.Errorf("读取文件失败: %v", err) } var items []M9zFaultHistory if len(data) > 0 { if err := json.Unmarshal(data, &items); err != nil { return nil, fmt.Errorf("解析 JSON 失败: %v", err) } } // 确保ID匹配索引+1(处理旧数据或缺失ID) for i := range items { items[i].ID = int64(i + 1) } return items, nil } // 写入数据到 JSON 文件 func writeData(items []M9zFaultHistory) error { data, err := json.MarshalIndent(items, "", " ") if err != nil { return fmt.Errorf("序列化 JSON 失败: %v", err) } return os.WriteFile(filePath, data, 0644) } // 新增数据(自动处理容量限制) func addData(newItem M9zFaultHistory) error { // 1. 读取现有数据 items, err := readData() if err != nil { return gerror.Wrap(err, "readData") } // 2. 追加新数据 items = append(items, newItem) // 3. 检查容量,如果超过 maxItems 则删除最早的数据(按时间排序) if len(items) > maxItems { // 按 Timestamp 排序(最早的在前) sort.Slice(items, func(i, j int) bool { return items[i].FaultTime.Before(items[j].FaultTime) }) // 删除最早的数据(保留最新的 maxItems 条) items = items[1:] for i, _ := range items { items[i].ID = int64(i + 1) } } // 4. 写回文件 err = writeData(items) if err != nil { return gerror.Wrap(err, "writeData") } return nil } // 按ID删除数据 func deleteById(id int) error { items, err := readData() if err != nil { return gerror.Wrap(err, "readData") } if id < 1 || id > len(items) { return fmt.Errorf("ID %d 超出范围", id) } // 删除指定索引的数据(id-1) items = append(items[:id-1], items[id:]...) // 重新分配ID(确保后续数据ID连续) for i := id - 1; i < len(items); i++ { items[i].ID = int64(i + 1) } return writeData(items) } func createFileWithPath(filePath string) (*os.File, error) { // 创建所有必需的父目录(使用 0755 权限) if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil { return nil, err } // 创建并打开文件(如果已存在则截断) return os.Create(filePath) }