saveBatchDownloadData.go 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873
  1. package jobs
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "fwh-toolbox-server/domain"
  7. "fwh-toolbox-server/dto"
  8. function "fwh-toolbox-server/function/SnapFile"
  9. "fwh-toolbox-server/repositories"
  10. "fwh-toolbox-server/utils/echart"
  11. "fwh-toolbox-server/utils/mimetype"
  12. "fwh-toolbox-server/utils/minio"
  13. "os"
  14. "path/filepath"
  15. "regexp"
  16. "sort"
  17. "strconv"
  18. "strings"
  19. "time"
  20. "github.com/go-echarts/go-echarts/v2/opts"
  21. "github.com/xuri/excelize/v2"
  22. "go.uber.org/zap"
  23. )
  24. /* 文件服务器存储结构
  25. * BatchDownloadData/
  26. * └── `SN`/
  27. * ├── PowerFlow/ 功率流图文件
  28. * ├── MQTT/ MQTT通讯数据文件
  29. * ├── EventAlarm/ 事件日志与告警日志文件
  30. * ├── AlarmSnapshot 告警快照
  31. * ├── EmsLogs/ EMS日志文件
  32. * ├── FaultRecord/ 故障录波文件
  33. * ├── UpdateLog/ 升级日志数据文件
  34. * └── Settings/ 设置数据文件
  35. *
  36. * BatchDownloadPackage/ 任务打包数据
  37. */
  38. var (
  39. mainPathName string = "BatchDownloadData"
  40. subPowerFlowPathName string = "PowerFlow"
  41. subMqttPathName string = "MQTT"
  42. subEventAlarmPathName string = "EventAlarm"
  43. subAlarmSnapshotPathName string = "AlarmSnapshot"
  44. subEmsLogsPathName string = "EmsLogs"
  45. subFaultRecordPathName string = "FaultRecord"
  46. subUpdateLogPathName string = "UpdateLog"
  47. subSettingsPathName string = "Settings"
  48. )
  49. func stringPtr(s string) *string {
  50. return &s
  51. }
  52. // 创建临时保存路径
  53. func createTempPath(pathType string) (string, error) {
  54. // 创建临时目录存储下载和解压数据
  55. tempDirName := fmt.Sprintf("fwhtb-batchDownload-%s-*", pathType)
  56. tempDir, err := os.MkdirTemp("", tempDirName)
  57. if err != nil {
  58. zap.L().Error("创建临时目录失败", zap.String("pathName", tempDirName), zap.String("err", err.Error()))
  59. return "", err
  60. }
  61. return tempDir, nil
  62. }
  63. // Excel 指定行-列写入数据, 行列从1开始
  64. func excelSetCellValue(f *excelize.File, sheetName string, col int, row int, val interface{}) error {
  65. colName, err := excelize.ColumnNumberToName(col)
  66. if err != nil {
  67. zap.L().Error("Excel 列标转换失败", zap.String("col", strconv.Itoa(col)), zap.String("err", err.Error()))
  68. return err
  69. }
  70. return f.SetCellValue(sheetName, fmt.Sprintf("%s%d", colName, row), val)
  71. }
  72. // 判断功率流图文件是否存在
  73. func ExistsBatchDownloadPowerFlow(sn string, dateStr string) (bool, error) {
  74. fileName := fmt.Sprintf("PowerFlow_%s.html", strings.ReplaceAll(dateStr, "-", ""))
  75. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subPowerFlowPathName, fileName)
  76. exists, err := minio.ExistsObject(objectName)
  77. if err != nil {
  78. zap.L().Error("检查PowerFlow文件失败", zap.String("fileName", fileName), zap.String("objectName", objectName), zap.String("err", err.Error()))
  79. return false, err
  80. }
  81. return exists, nil
  82. }
  83. // 获取功率流图文件状态信息
  84. func StatBatchDownloadPowerFlow(sn string, dateStr string) (*minio.ObjectInfo, error) {
  85. fileName := fmt.Sprintf("PowerFlow_%s.html", strings.ReplaceAll(dateStr, "-", ""))
  86. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subPowerFlowPathName, fileName)
  87. status, err := minio.StatObject(objectName)
  88. if err != nil {
  89. zap.L().Error("获取PowerFlow文件状态失败", zap.String("fileName", fileName), zap.String("objectName", objectName), zap.String("err", err.Error()))
  90. return nil, err
  91. }
  92. return &status, nil
  93. }
  94. // 保存功率流图到文件服务器
  95. // return objName
  96. func SaveBatchDownloadPowerFlow(sn string, dateStr string, powerFlowData dto.SitePowerFlow) (string, error) {
  97. // 创建临时保存文件路径
  98. tempPath, err := createTempPath("powerFlow")
  99. if err != nil {
  100. return "", err
  101. }
  102. defer os.RemoveAll(tempPath) // 程序结束时清理临时目录
  103. fileName := fmt.Sprintf("PowerFlow_%s.html", strings.ReplaceAll(dateStr, "-", ""))
  104. filePath := filepath.Join(tempPath, fileName)
  105. // 数据结构转换
  106. pvData := []opts.LineData{}
  107. genData := []opts.LineData{}
  108. gridData := []opts.LineData{}
  109. aPowerData := []opts.LineData{}
  110. loadData := []opts.LineData{}
  111. socData := []opts.LineData{}
  112. for i, t := range powerFlowData.DeviceTimeArray {
  113. var pvValue []interface{}
  114. if i < len(powerFlowData.PowerSunArray) {
  115. pvValue = []interface{}{
  116. t,
  117. powerFlowData.PowerSunArray[i],
  118. }
  119. } else {
  120. pvValue = []interface{}{
  121. t,
  122. nil,
  123. }
  124. }
  125. pvData = append(pvData, opts.LineData{
  126. Value: pvValue,
  127. })
  128. var genValue []interface{}
  129. if i < len(powerFlowData.PowerGenArray) {
  130. genValue = []interface{}{
  131. t,
  132. powerFlowData.PowerGenArray[i],
  133. }
  134. } else {
  135. genValue = []interface{}{
  136. t,
  137. nil,
  138. }
  139. }
  140. genData = append(genData, opts.LineData{
  141. Value: genValue,
  142. })
  143. var gridValue []interface{}
  144. if i < len(powerFlowData.PowerUtiArray) {
  145. gridValue = []interface{}{
  146. t,
  147. powerFlowData.PowerUtiArray[i],
  148. }
  149. } else {
  150. gridValue = []interface{}{
  151. t,
  152. nil,
  153. }
  154. }
  155. gridData = append(gridData, opts.LineData{
  156. Value: gridValue,
  157. })
  158. var aPowerValue []interface{}
  159. if i < len(powerFlowData.PowerFhpArray) {
  160. aPowerValue = []interface{}{
  161. t,
  162. powerFlowData.PowerFhpArray[i],
  163. }
  164. } else {
  165. aPowerValue = []interface{}{
  166. t,
  167. nil,
  168. }
  169. }
  170. aPowerData = append(aPowerData, opts.LineData{
  171. Value: aPowerValue,
  172. })
  173. var loadValue []interface{}
  174. if i < len(powerFlowData.PowerLoadArray) {
  175. loadValue = []interface{}{
  176. t,
  177. powerFlowData.PowerLoadArray[i],
  178. }
  179. } else {
  180. loadValue = []interface{}{
  181. t,
  182. nil,
  183. }
  184. }
  185. loadData = append(loadData, opts.LineData{
  186. Value: loadValue,
  187. })
  188. // SOC
  189. var socValue []interface{}
  190. if i < len(powerFlowData.SocArray) {
  191. socValue = []interface{}{
  192. t,
  193. powerFlowData.SocArray[i],
  194. }
  195. } else {
  196. socValue = []interface{}{
  197. t,
  198. nil,
  199. }
  200. }
  201. socData = append(socData, opts.LineData{
  202. Value: socValue,
  203. })
  204. }
  205. // 生成功率流图
  206. var pfChartData []echart.PowerFlowChartData = []echart.PowerFlowChartData{}
  207. pfChartData = append(pfChartData, echart.PowerFlowChartData{
  208. Legend: "光伏",
  209. Color: stringPtr("#F1A502"),
  210. Data: pvData,
  211. })
  212. pfChartData = append(pfChartData, echart.PowerFlowChartData{
  213. Legend: "发电机",
  214. Color: stringPtr("#5398FF"),
  215. Data: genData,
  216. })
  217. pfChartData = append(pfChartData, echart.PowerFlowChartData{
  218. Legend: "市电",
  219. Color: stringPtr("#BB56FD"),
  220. Data: gridData,
  221. })
  222. pfChartData = append(pfChartData, echart.PowerFlowChartData{
  223. Legend: "aPower",
  224. Color: stringPtr("#41D187"),
  225. Data: aPowerData,
  226. })
  227. pfChartData = append(pfChartData, echart.PowerFlowChartData{
  228. Legend: "家庭负载",
  229. Color: stringPtr("#0BF5FF"),
  230. Data: loadData,
  231. })
  232. var socChartData echart.SocChartData = echart.SocChartData{
  233. Color: stringPtr("#3E7B4D"),
  234. Data: socData,
  235. }
  236. lineOpt := echart.LineChartOpt{
  237. Global: echart.ChartOpt{
  238. Title: "功率流图",
  239. },
  240. Smooth: true,
  241. }
  242. line := echart.CreatePowerFlowChart(lineOpt, pfChartData, socChartData)
  243. f, _ := os.Create(filePath)
  244. defer f.Close()
  245. line.Render(f)
  246. // 上传到文件服务器
  247. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subPowerFlowPathName, fileName)
  248. if err = minio.UploadFile(filePath, objectName); err != nil {
  249. zap.L().Error("上传PowerFlow文件失败", zap.String("path", filePath), zap.String("objectName", objectName), zap.String("err", err.Error()))
  250. return "", err
  251. }
  252. return objectName, nil
  253. }
  254. // 判断MqttLog excel文件是否存在
  255. func ExistsBatchDownloadMqttLog(sn string, cmdType string, dateStr string) (bool, error) {
  256. fileName := fmt.Sprintf("MqttLog_%s_%s.xlsx", cmdType, strings.ReplaceAll(dateStr, "-", ""))
  257. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subMqttPathName, fileName)
  258. exists, err := minio.ExistsObject(objectName)
  259. if err != nil {
  260. zap.L().Error("检查MqttLog excel文件失败", zap.String("fileName", fileName), zap.String("objectName", objectName), zap.String("err", err.Error()))
  261. return false, err
  262. }
  263. return exists, nil
  264. }
  265. // 获取MqttLog excel文件状态信息
  266. func StatBatchDownloadMqttLog(sn string, cmdType string, dateStr string) (*minio.ObjectInfo, error) {
  267. fileName := fmt.Sprintf("MqttLog_%s_%s.xlsx", cmdType, strings.ReplaceAll(dateStr, "-", ""))
  268. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subMqttPathName, fileName)
  269. status, err := minio.StatObject(objectName)
  270. if err != nil {
  271. zap.L().Error("获取MqttLog excel文件状态失败", zap.String("fileName", fileName), zap.String("objectName", objectName), zap.String("err", err.Error()))
  272. return nil, err
  273. }
  274. return &status, nil
  275. }
  276. // 保存MqttLog excel到文件服务器
  277. // return objName
  278. func SaveBatchDownloadMqttLog(sn string, cmdType string, dateStr string, data []domain.MqttLogItem) (objectName string, err error) {
  279. err = nil
  280. f := excelize.NewFile()
  281. defer func() {
  282. closeErr := f.Close()
  283. if closeErr != nil {
  284. zap.L().Error("Excel 文件close失败", zap.String("err", err.Error()))
  285. if err == nil {
  286. err = closeErr
  287. }
  288. }
  289. }()
  290. // 写标题行
  291. f.SetCellValue("Sheet1", "A1", "Type")
  292. f.SetCellValue("Sheet1", "B1", "Time")
  293. f.SetCellValue("Sheet1", "C1", "Data")
  294. // 写入数据
  295. for i, d := range data {
  296. f.SetCellValue("Sheet1", "A"+strconv.Itoa(i+2), d.CmdType)
  297. f.SetCellValue("Sheet1", "B"+strconv.Itoa(i+2), d.LogTime)
  298. f.SetCellValue("Sheet1", "C"+strconv.Itoa(i+2), d.LogData)
  299. }
  300. // 创建临时保存文件路径
  301. tempPath, err := createTempPath("mqtt_" + cmdType)
  302. if err != nil {
  303. return
  304. }
  305. defer os.RemoveAll(tempPath) // 程序结束时清理临时目录
  306. fileName := fmt.Sprintf("MqttLog_%s_%s.xlsx", cmdType, strings.ReplaceAll(dateStr, "-", ""))
  307. filePath := filepath.Join(tempPath, fileName)
  308. // 保存到文件
  309. err = f.SaveAs(filePath)
  310. if err != nil {
  311. zap.L().Error("Excel文件save失败", zap.String("path", filePath), zap.String("err", err.Error()))
  312. return
  313. }
  314. // 上传到文件服务器
  315. objectName = fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subMqttPathName, fileName)
  316. if err = minio.UploadFile(filePath, objectName); err != nil {
  317. zap.L().Error("上传Excel文件失败", zap.String("path", filePath), zap.String("objectName", objectName), zap.String("err", err.Error()))
  318. return
  319. }
  320. return
  321. }
  322. // 判断EventAlarm excel文件是否存在
  323. func ExistsBatchDownloadEventAlarm(sn string, dateStr string) (bool, error) {
  324. fileName := fmt.Sprintf("EventAlarm_%s.xlsx", strings.ReplaceAll(dateStr, "-", ""))
  325. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subEventAlarmPathName, fileName)
  326. exists, err := minio.ExistsObject(objectName)
  327. if err != nil {
  328. zap.L().Error("检查EventAlarm excel文件失败", zap.String("fileName", fileName), zap.String("objectName", objectName), zap.String("err", err.Error()))
  329. return false, err
  330. }
  331. return exists, nil
  332. }
  333. // 获取EventAlarm excel文件状态信息
  334. func StatBatchDownloadEventAlarm(sn string, dateStr string) (*minio.ObjectInfo, error) {
  335. fileName := fmt.Sprintf("EventAlarm_%s.xlsx", strings.ReplaceAll(dateStr, "-", ""))
  336. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subEventAlarmPathName, fileName)
  337. status, err := minio.StatObject(objectName)
  338. if err != nil {
  339. zap.L().Error("获取EventAlarm excel文件状态失败", zap.String("fileName", fileName), zap.String("objectName", objectName), zap.String("err", err.Error()))
  340. return nil, err
  341. }
  342. return &status, nil
  343. }
  344. // 保存EventAlarm excel到文件服务器
  345. // return objName
  346. func SaveBatchDownloadEventAlarm(sn string, dateStr string, eventAlarmData []domain.EventAlarmItem) (objectName string, err error) {
  347. err = nil
  348. f := excelize.NewFile()
  349. defer func() {
  350. closeErr := f.Close()
  351. if closeErr != nil {
  352. zap.L().Error("Excel 文件close失败", zap.String("err", err.Error()))
  353. if err == nil {
  354. err = closeErr
  355. }
  356. }
  357. }()
  358. // 写标题行
  359. f.SetCellValue("Sheet1", "A1", "ID")
  360. f.SetCellValue("Sheet1", "B1", "Time")
  361. f.SetCellValue("Sheet1", "C1", "Type")
  362. f.SetCellValue("Sheet1", "D1", "AlarmCode")
  363. f.SetCellValue("Sheet1", "E1", "Name")
  364. f.SetCellValue("Sheet1", "F1", "StartTime")
  365. f.SetCellValue("Sheet1", "G1", "EndTime")
  366. f.SetCellValue("Sheet1", "H1", "Data")
  367. for i, data := range eventAlarmData {
  368. var id string
  369. if data.ID == nil || *data.ID == "" {
  370. id = strconv.Itoa(i + 1)
  371. } else {
  372. id = *data.ID
  373. }
  374. f.SetCellValue("Sheet1", "A"+strconv.Itoa(i+2), id)
  375. f.SetCellValue("Sheet1", "B"+strconv.Itoa(i+2), data.LogTime)
  376. f.SetCellValue("Sheet1", "C"+strconv.Itoa(i+2), data.LogType)
  377. f.SetCellValue("Sheet1", "D"+strconv.Itoa(i+2), data.AlarmCode)
  378. f.SetCellValue("Sheet1", "E"+strconv.Itoa(i+2), data.LogName)
  379. f.SetCellValue("Sheet1", "F"+strconv.Itoa(i+2), data.StartTime)
  380. f.SetCellValue("Sheet1", "G"+strconv.Itoa(i+2), data.EndTime)
  381. f.SetCellValue("Sheet1", "H"+strconv.Itoa(i+2), data.LogData)
  382. }
  383. // 创建临时保存文件路径
  384. tempPath, err := createTempPath("eventAlarm")
  385. if err != nil {
  386. return
  387. }
  388. defer os.RemoveAll(tempPath) // 程序结束时清理临时目录
  389. fileName := fmt.Sprintf("EventAlarm_%s.xlsx", strings.ReplaceAll(dateStr, "-", ""))
  390. filePath := filepath.Join(tempPath, fileName)
  391. // 保存到文件
  392. err = f.SaveAs(filePath)
  393. if err != nil {
  394. zap.L().Error("Excel文件save失败", zap.String("path", filePath), zap.String("err", err.Error()))
  395. return
  396. }
  397. // 上传到文件服务器
  398. objectName = fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subEventAlarmPathName, fileName)
  399. if err = minio.UploadFile(filePath, objectName); err != nil {
  400. zap.L().Error("上传Excel文件失败", zap.String("path", filePath), zap.String("objectName", objectName), zap.String("err", err.Error()))
  401. return
  402. }
  403. return
  404. }
  405. // 判断AlarmSnapshot文件是否存在
  406. func ExistsBatchDownloadAlarmSnapshot(sn string, dateStr string) (bool, error) {
  407. fileName := fmt.Sprintf("EventAlarm_%s.xlsx", strings.ReplaceAll(dateStr, "-", ""))
  408. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subAlarmSnapshotPathName, fileName)
  409. exists, err := minio.ExistsObject(objectName)
  410. if err != nil {
  411. zap.L().Error("检查AlarmSnapshot文件失败", zap.String("fileName", fileName), zap.String("objectName", objectName), zap.String("err", err.Error()))
  412. return false, err
  413. }
  414. return exists, nil
  415. }
  416. // 获取AlarmSnapshot文件状态信息
  417. func StatBatchDownloadAlarmSnapshot(sn string, dateStr string) (*minio.ObjectInfo, error) {
  418. fileName := fmt.Sprintf("EventAlarm_%s.xlsx", strings.ReplaceAll(dateStr, "-", ""))
  419. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subAlarmSnapshotPathName, fileName)
  420. status, err := minio.StatObject(objectName)
  421. if err != nil {
  422. zap.L().Error("获取AlarmSnapshot文件状态失败", zap.String("fileName", fileName), zap.String("objectName", objectName), zap.String("err", err.Error()))
  423. return nil, err
  424. }
  425. return &status, nil
  426. }
  427. // 保存AlarmSnapshot文件到文件服务器
  428. // return objName
  429. func SaveBatchDownloadAlarmSnapshot(sn string, dateStr string, alarmSnapshotData []*domain.SiteAlarmSnapshotData) (objectName string, err error) {
  430. err = nil
  431. f := excelize.NewFile()
  432. defer func() {
  433. closeErr := f.Close()
  434. if closeErr != nil {
  435. zap.L().Error("Excel 文件close失败", zap.String("err", err.Error()))
  436. if err == nil {
  437. err = closeErr
  438. }
  439. }
  440. }()
  441. // 写标题行
  442. f.SetCellValue("Sheet1", "A1", "ID")
  443. f.SetCellValue("Sheet1", "B1", "Time")
  444. f.SetCellValue("Sheet1", "C1", "Data")
  445. // 数据按时间排序
  446. sort.Slice(alarmSnapshotData[:], func(i, j int) bool { return alarmSnapshotData[i].LogTime.Before(alarmSnapshotData[j].LogTime) })
  447. for i, data := range alarmSnapshotData {
  448. var logTime string
  449. loc, e := time.LoadLocation(data.ZoneInfo)
  450. if e != nil {
  451. zap.L().Warn("本地时间加载失败", zap.String("ZoneInfo", data.ZoneInfo), zap.String("err", err.Error()))
  452. logTime = data.LogTime.Format(time.DateTime)
  453. } else {
  454. logTime = data.LogTime.In(loc).Format(time.DateTime)
  455. }
  456. // 尝试解析成function.
  457. var snapJson function.SnapUnmarshalJson
  458. if err := json.Unmarshal([]byte(data.JSONData), &snapJson); err == nil {
  459. // 能解析成功,则为new json,需要转换
  460. for _, xid := range snapJson.SnapInfo.XidList {
  461. if xid.Type == "VID" {
  462. macro, desc, err := repositories.GetEmsparaVidInfo(uint(xid.ID))
  463. if err != nil {
  464. zap.L().Warn("GetEmsparaVidInfo error", zap.String("err", err.Error()))
  465. continue
  466. }
  467. xid.Macro = &macro
  468. xid.Brief = &desc
  469. } else if xid.Type == "PID" {
  470. macro, desc, err := repositories.GetEmsparaPidInfo(uint(xid.ID))
  471. if err != nil {
  472. zap.L().Warn("GetEmsparaPidInfo error", zap.String("err", err.Error()))
  473. continue
  474. }
  475. xid.Macro = &macro
  476. xid.Brief = &desc
  477. }
  478. }
  479. if jsonBytes, err := json.Marshal(snapJson); err != nil {
  480. zap.L().Error("Marshal snapJson failed", zap.String("err", err.Error()))
  481. } else {
  482. data.JSONData = string(jsonBytes)
  483. }
  484. }
  485. f.SetCellValue("Sheet1", "A"+strconv.Itoa(i+2), data.ID)
  486. f.SetCellValue("Sheet1", "B"+strconv.Itoa(i+2), logTime)
  487. f.SetCellValue("Sheet1", "C"+strconv.Itoa(i+2), data.JSONData)
  488. }
  489. // 创建临时保存文件路径
  490. tempPath, err := createTempPath("alarmSnapshot")
  491. if err != nil {
  492. return
  493. }
  494. defer os.RemoveAll(tempPath) // 程序结束时清理临时目录
  495. fileName := fmt.Sprintf("EventAlarm_%s.xlsx", strings.ReplaceAll(dateStr, "-", ""))
  496. filePath := filepath.Join(tempPath, fileName)
  497. // 保存到文件
  498. err = f.SaveAs(filePath)
  499. if err != nil {
  500. zap.L().Error("Excel文件save失败", zap.String("path", filePath), zap.String("err", err.Error()))
  501. return
  502. }
  503. // 上传到文件服务器
  504. objectName = fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subAlarmSnapshotPathName, fileName)
  505. if err = minio.UploadFile(filePath, objectName); err != nil {
  506. zap.L().Error("上传Excel文件失败", zap.String("path", filePath), zap.String("objectName", objectName), zap.String("err", err.Error()))
  507. return
  508. }
  509. return
  510. }
  511. // 判断EmsLog文件是否存在
  512. func ExistsBatchDownloadEmsLog(sn string, originalFileName string, fileSupType string, dateStr string, callTime time.Time) (bool, error) {
  513. // 使用正则匹配多级后缀,例如 .tar.bz2, .tar.gz, .min.js 等
  514. re := regexp.MustCompile(`(\.[a-zA-Z0-9]+)+$`)
  515. matchSuffix := re.FindString(originalFileName)
  516. fileName := fmt.Sprintf("EmsLog_%s_%s_%s_%s%s", sn, fileSupType, strings.ReplaceAll(dateStr, "-", "_"), strconv.FormatInt(callTime.Unix(), 10), matchSuffix)
  517. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subEmsLogsPathName, fileName)
  518. exists, err := minio.ExistsObject(objectName)
  519. if err != nil {
  520. zap.L().Error("检查EmsLog文件失败", zap.String("fileName", fileName), zap.String("objectName", objectName), zap.String("err", err.Error()))
  521. return false, err
  522. }
  523. return exists, nil
  524. }
  525. // 获取EmsLog文件状态信息
  526. func StatBatchDownloadEmsLog(sn string, originalFileName string, fileSupType string, dateStr string, callTime time.Time) (*minio.ObjectInfo, error) {
  527. // 使用正则匹配多级后缀,例如 .tar.bz2, .tar.gz, .min.js 等
  528. re := regexp.MustCompile(`(\.[a-zA-Z0-9]+)+$`)
  529. matchSuffix := re.FindString(originalFileName)
  530. fileName := fmt.Sprintf("EmsLog_%s_%s_%s_%s%s", sn, fileSupType, strings.ReplaceAll(dateStr, "-", "_"), strconv.FormatInt(callTime.Unix(), 10), matchSuffix)
  531. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subEmsLogsPathName, fileName)
  532. status, err := minio.StatObject(objectName)
  533. if err != nil {
  534. zap.L().Error("获取EmsLog文件状态失败", zap.String("fileName", fileName), zap.String("objectName", objectName), zap.String("err", err.Error()))
  535. return nil, err
  536. }
  537. return &status, nil
  538. }
  539. // 保存EmsLog文件到文件服务器
  540. // return objName
  541. func SaveBatchDownloadEmsLog(sn string, dataBytes []byte, originalFileName string, fileSupType string, dateStr string, callTime time.Time) (string, error) {
  542. // 将 []byte 封装成 io.Reader
  543. dataReader := bytes.NewReader(dataBytes)
  544. // 使用正则匹配多级后缀,例如 .tar.bz2, .tar.gz, .min.js 等
  545. re := regexp.MustCompile(`(\.[a-zA-Z0-9]+)+$`)
  546. matchSuffix := re.FindString(originalFileName)
  547. // 计算Content Type
  548. contentType := mimetype.GetContentType(originalFileName)
  549. // 保存到minio
  550. fileName := fmt.Sprintf("EmsLog_%s_%s_%s_%s%s", sn, fileSupType, strings.ReplaceAll(dateStr, "-", "_"), strconv.FormatInt(callTime.Unix(), 10), matchSuffix)
  551. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subEmsLogsPathName, fileName)
  552. return objectName, minio.UploadFromReader(dataReader, int64(len(dataBytes)), objectName, contentType)
  553. }
  554. // 判断FaultRecord文件是否存在
  555. func ExistsBatchDownloadFaultRecord(sn string, faultRecordFileName string) (bool, error) {
  556. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subFaultRecordPathName, faultRecordFileName)
  557. exists, err := minio.ExistsObject(objectName)
  558. if err != nil {
  559. zap.L().Error("检查FaultRecord文件失败", zap.String("fileName", faultRecordFileName), zap.String("objectName", objectName), zap.String("err", err.Error()))
  560. return false, err
  561. }
  562. return exists, nil
  563. }
  564. // 获取FaultRecord文件状态信息
  565. func StatBatchDownloadFaultRecord(sn string, faultRecordFileName string) (*minio.ObjectInfo, error) {
  566. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subFaultRecordPathName, faultRecordFileName)
  567. status, err := minio.StatObject(objectName)
  568. if err != nil {
  569. zap.L().Error("获取FaultRecord文件状态失败", zap.String("fileName", faultRecordFileName), zap.String("objectName", objectName), zap.String("err", err.Error()))
  570. return nil, err
  571. }
  572. return &status, nil
  573. }
  574. // 保存FaultRecord文件到文件服务器
  575. // return objName
  576. func SaveBatchDownloadFaultRecord(sn string, dataBytes []byte, faultRecordFileName string) (string, error) {
  577. // 将 []byte 封装成 io.Reader
  578. dataReader := bytes.NewReader(dataBytes)
  579. // 计算Content Type
  580. contentType := mimetype.GetContentType(faultRecordFileName)
  581. // 保存到minio
  582. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subFaultRecordPathName, faultRecordFileName)
  583. return objectName, minio.UploadFromReader(dataReader, int64(len(dataBytes)), objectName, contentType)
  584. }
  585. // 判断UpdateLog excel文件是否存在
  586. func ExistsBatchDownloadUpdateLog(sn string, date time.Time) (bool, error) {
  587. fileName := fmt.Sprintf("UpdateLog_%s_%s.xlsx", sn, strings.ReplaceAll(date.Format(time.DateTime), " ", "_"))
  588. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subUpdateLogPathName, fileName)
  589. exists, err := minio.ExistsObject(objectName)
  590. if err != nil {
  591. zap.L().Error("检查UpdateLog excel文件失败", zap.String("fileName", fileName), zap.String("objectName", objectName), zap.String("err", err.Error()))
  592. return false, err
  593. }
  594. return exists, nil
  595. }
  596. // 获取UpdateLog excel文件状态信息
  597. func StatBatchDownloadUpdateLog(sn string, date time.Time) (*minio.ObjectInfo, error) {
  598. fileName := fmt.Sprintf("UpdateLog_%s_%s.xlsx", sn, strings.ReplaceAll(date.Format(time.DateTime), " ", "_"))
  599. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subUpdateLogPathName, fileName)
  600. status, err := minio.StatObject(objectName)
  601. if err != nil {
  602. zap.L().Error("获取UpdateLog excel文件状态失败", zap.String("fileName", fileName), zap.String("objectName", objectName), zap.String("err", err.Error()))
  603. return nil, err
  604. }
  605. return &status, nil
  606. }
  607. // 保存UpdateLog excel到文件服务器
  608. // return objName
  609. func SaveBatchDownloadUpdateLog(sn string, systemUpdateLogData []domain.BatchDownloadSystemUpdateLogInfo, aHubUpdateLogData []domain.BatchDownloadAHubUpdateLogInfo) (objectName string, err error) {
  610. err = nil
  611. f := excelize.NewFile()
  612. defer func() {
  613. closeErr := f.Close()
  614. if closeErr != nil {
  615. zap.L().Error("Excel 文件close失败", zap.String("err", err.Error()))
  616. if err == nil {
  617. err = closeErr
  618. }
  619. }
  620. }()
  621. systemUpdateSheetName := "SystemUpdate"
  622. aHubUpdateSheetName := "aHubUpdate"
  623. err = f.SetSheetName("Sheet1", systemUpdateSheetName)
  624. if err != nil {
  625. zap.L().Error("Excel Sheet1更名失败", zap.String("sheetName", systemUpdateSheetName), zap.String("err", err.Error()))
  626. return
  627. }
  628. _, err = f.NewSheet(aHubUpdateSheetName)
  629. if err != nil {
  630. zap.L().Error("Excel 新增Sheet失败", zap.String("sheetName", aHubUpdateSheetName), zap.String("err", err.Error()))
  631. return
  632. }
  633. // 样式集
  634. // 加粗
  635. // 创建加粗样式
  636. styleBold, err := f.NewStyle(&excelize.Style{
  637. Font: &excelize.Font{
  638. Bold: true,
  639. },
  640. })
  641. if err != nil {
  642. zap.L().Error("Excel 新增Sheet失败", zap.String("err", err.Error()))
  643. return
  644. }
  645. var rowIndex int = 1
  646. // 写入系统升级日志
  647. for _, updateItem := range systemUpdateLogData {
  648. // 写标题行
  649. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), "OrderNo")
  650. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("B%d", rowIndex), "GateSn")
  651. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("C%d", rowIndex), "TriggerType")
  652. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("D%d", rowIndex), "FileName")
  653. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("E%d", rowIndex), "UpdateTime")
  654. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("F%d", rowIndex), "Result")
  655. f.SetCellStyle(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), fmt.Sprintf("F%d", rowIndex), styleBold)
  656. rowIndex++
  657. // 写入项目信息内容
  658. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), updateItem.OrderNo)
  659. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("B%d", rowIndex), updateItem.GateSn)
  660. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("C%d", rowIndex), updateItem.TriggerType)
  661. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("D%d", rowIndex), updateItem.FileName)
  662. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("E%d", rowIndex), updateItem.UpdateTime)
  663. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("F%d", rowIndex), updateItem.Result)
  664. rowIndex = rowIndex + 2
  665. // Gate版本信息
  666. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), "GateVer")
  667. f.SetCellStyle(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), fmt.Sprintf("A%d", rowIndex), styleBold)
  668. rowIndex++
  669. for idx, modeVer := range updateItem.GateVerList {
  670. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+1, rowIndex, "Name")
  671. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+1, rowIndex+1, "OldVer")
  672. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+1, rowIndex+2, "NewVer")
  673. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+2, rowIndex, modeVer.Name)
  674. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+2, rowIndex+1, modeVer.OldVer)
  675. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+2, rowIndex+2, modeVer.NewVer)
  676. }
  677. rowIndex = rowIndex + 2
  678. // SubDev版本信息
  679. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), "SubVer")
  680. f.SetCellStyle(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), fmt.Sprintf("A%d", rowIndex), styleBold)
  681. rowIndex++
  682. for _, subVer := range updateItem.SubDevList {
  683. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), "SubSn")
  684. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("B%d", rowIndex), subVer.DevSn)
  685. rowIndex++
  686. for idx, modeVer := range subVer.DevVerList {
  687. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+1, rowIndex, "Name")
  688. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+1, rowIndex+1, "OldVer")
  689. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+1, rowIndex+2, "NewVer")
  690. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+2, rowIndex, modeVer.Name)
  691. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+2, rowIndex+1, modeVer.OldVer)
  692. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+2, rowIndex+2, modeVer.NewVer)
  693. }
  694. rowIndex = rowIndex + 3
  695. }
  696. rowIndex++
  697. }
  698. rowIndex = 1
  699. // 写入aHub升级日志
  700. for _, aHubUpdateItem := range aHubUpdateLogData {
  701. // 写标题行
  702. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("A%d", rowIndex), "OrderNo")
  703. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("B%d", rowIndex), "GateSn")
  704. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("C%d", rowIndex), "TriggerType")
  705. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("D%d", rowIndex), "AHubSn")
  706. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("E%d", rowIndex), "EndTime")
  707. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("F%d", rowIndex), "Result")
  708. f.SetCellStyle(aHubUpdateSheetName, fmt.Sprintf("A%d", rowIndex), fmt.Sprintf("F%d", rowIndex), styleBold)
  709. rowIndex++
  710. // 写入项目信息内容
  711. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("A%d", rowIndex), aHubUpdateItem.OrderNo)
  712. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("B%d", rowIndex), aHubUpdateItem.GateSn)
  713. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("C%d", rowIndex), aHubUpdateItem.TriggerType)
  714. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("D%d", rowIndex), aHubUpdateItem.AHubSn)
  715. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("E%d", rowIndex), aHubUpdateItem.EndTime)
  716. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("F%d", rowIndex), aHubUpdateItem.Result)
  717. rowIndex = rowIndex + 2
  718. // aHub版本信息
  719. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("A%d", rowIndex), "aHubVer")
  720. f.SetCellStyle(aHubUpdateSheetName, fmt.Sprintf("A%d", rowIndex), fmt.Sprintf("A%d", rowIndex), styleBold)
  721. rowIndex++
  722. for idx, modeVer := range aHubUpdateItem.DetailList {
  723. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+1, rowIndex, "FileName")
  724. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+1, rowIndex+1, "FileOrder")
  725. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+1, rowIndex+2, "ResultDesc")
  726. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+1, rowIndex+3, "OldVer")
  727. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+1, rowIndex+4, "NewVer")
  728. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+2, rowIndex, modeVer.FileName)
  729. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+2, rowIndex+1, modeVer.FileOrder)
  730. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+2, rowIndex+2, modeVer.ResultDesc)
  731. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+2, rowIndex+3, modeVer.OldVer)
  732. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+2, rowIndex+4, modeVer.NewVer)
  733. }
  734. rowIndex = rowIndex + 6
  735. }
  736. // 创建临时保存文件路径
  737. tempPath, err := createTempPath("updateLog")
  738. if err != nil {
  739. return
  740. }
  741. defer os.RemoveAll(tempPath) // 程序结束时清理临时目录
  742. fileName := fmt.Sprintf("UpdateLog_%s_%s.xlsx", sn, strings.ReplaceAll(time.Now().Format(time.DateTime), " ", "_"))
  743. filePath := filepath.Join(tempPath, fileName)
  744. // 保存到文件
  745. err = f.SaveAs(filePath)
  746. if err != nil {
  747. zap.L().Error("Excel文件save失败", zap.String("path", filePath), zap.String("err", err.Error()))
  748. return
  749. }
  750. // 上传到文件服务器
  751. objectName = fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subUpdateLogPathName, fileName)
  752. if err = minio.UploadFile(filePath, objectName); err != nil {
  753. zap.L().Error("上传Excel文件失败", zap.String("path", filePath), zap.String("objectName", objectName), zap.String("err", err.Error()))
  754. return
  755. }
  756. return
  757. }
  758. // 保存Settings excel到文件服务器
  759. // return objName
  760. // func SaveBatchDownloadSettings(sn string, dateStr string, settingsData []domain.SiteSettings) (string, error) {
  761. // }