saveBatchDownloadData.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632
  1. package jobs
  2. import (
  3. "bytes"
  4. "fmt"
  5. "fwh-toolbox-server/domain"
  6. "fwh-toolbox-server/dto"
  7. "fwh-toolbox-server/utils/echart"
  8. "fwh-toolbox-server/utils/minio"
  9. "os"
  10. "path/filepath"
  11. "strconv"
  12. "strings"
  13. "time"
  14. "github.com/go-echarts/go-echarts/v2/opts"
  15. "github.com/xuri/excelize/v2"
  16. "go.uber.org/zap"
  17. )
  18. /* 文件服务器存储结构
  19. * BatchDownloadData/
  20. * └── `SN`/
  21. * ├── PowerFlow/ 功率流图文件
  22. * ├── MQTT/ MQTT通讯数据文件
  23. * ├── EventAlarm/ 事件日志与告警日志文件
  24. * ├── AlarmSnapshot 告警快照
  25. * ├── EmsLogs/ EMS日志文件
  26. * ├── FaultRecord/ 故障录波文件
  27. * ├── UpdateLog/ 升级日志数据文件
  28. * └── Settings/ 设置数据文件
  29. *
  30. * BatchDownloadPackage/ 任务打包数据
  31. */
  32. var (
  33. mainPathName string = "BatchDownloadData"
  34. subPowerFlowPathName string = "PowerFlow"
  35. subMqttPathName string = "MQTT"
  36. subEventAlarmPathName string = "EventAlarm"
  37. subAlarmSnapshotPathName string = "AlarmSnapshot"
  38. subEmsLogsPathName string = "EmsLogs"
  39. subFaultRecordPathName string = "FaultRecord"
  40. subUpdateLogPathName string = "UpdateLog"
  41. subSettingsPathName string = "Settings"
  42. )
  43. func stringPtr(s string) *string {
  44. return &s
  45. }
  46. // 创建临时保存路径
  47. func createTempPath(pathType string) (string, error) {
  48. // 创建临时目录存储下载和解压数据
  49. tempDirName := fmt.Sprintf("fwhtb-batchDownload-%s-*", pathType)
  50. tempDir, err := os.MkdirTemp("", tempDirName)
  51. if err != nil {
  52. zap.L().Error("创建临时目录失败", zap.String("pathName", tempDirName), zap.String("err", err.Error()))
  53. return "", err
  54. }
  55. return tempDir, nil
  56. }
  57. // Excel 指定行-列写入数据, 行列从1开始
  58. func excelSetCellValue(f *excelize.File, sheetName string, col int, row int, val interface{}) error {
  59. colName, err := excelize.ColumnNumberToName(col)
  60. if err != nil {
  61. zap.L().Error("Excel 列标转换失败", zap.String("col", strconv.Itoa(col)), zap.String("err", err.Error()))
  62. return err
  63. }
  64. return f.SetCellValue(sheetName, fmt.Sprintf("%s%d", colName, row), val)
  65. }
  66. // 保存功率流图到文件服务器
  67. // return objName
  68. func SaveBatchDownloadPowerFlow(sn string, dateStr string, powerFlowData dto.SitePowerFlow) (string, error) {
  69. // 创建临时保存文件路径
  70. tempPath, err := createTempPath("powerFlow")
  71. if err != nil {
  72. return "", err
  73. }
  74. defer os.RemoveAll(tempPath) // 程序结束时清理临时目录
  75. fileName := fmt.Sprintf("PowerFlow_%s.html", strings.ReplaceAll(dateStr, "-", ""))
  76. filePath := filepath.Join(tempPath, fileName)
  77. // 数据结构转换
  78. pvData := []opts.LineData{}
  79. genData := []opts.LineData{}
  80. gridData := []opts.LineData{}
  81. aPowerData := []opts.LineData{}
  82. loadData := []opts.LineData{}
  83. socData := []opts.LineData{}
  84. for i, t := range powerFlowData.DeviceTimeArray {
  85. var pvValue []interface{}
  86. if i < len(powerFlowData.PowerSunArray) {
  87. pvValue = []interface{}{
  88. t,
  89. powerFlowData.PowerSunArray[i],
  90. }
  91. } else {
  92. pvValue = []interface{}{
  93. t,
  94. nil,
  95. }
  96. }
  97. pvData = append(pvData, opts.LineData{
  98. Value: pvValue,
  99. })
  100. var genValue []interface{}
  101. if i < len(powerFlowData.PowerGenArray) {
  102. genValue = []interface{}{
  103. t,
  104. powerFlowData.PowerGenArray[i],
  105. }
  106. } else {
  107. genValue = []interface{}{
  108. t,
  109. nil,
  110. }
  111. }
  112. genData = append(genData, opts.LineData{
  113. Value: genValue,
  114. })
  115. var gridValue []interface{}
  116. if i < len(powerFlowData.PowerUtiArray) {
  117. gridValue = []interface{}{
  118. t,
  119. powerFlowData.PowerUtiArray[i],
  120. }
  121. } else {
  122. gridValue = []interface{}{
  123. t,
  124. nil,
  125. }
  126. }
  127. gridData = append(gridData, opts.LineData{
  128. Value: gridValue,
  129. })
  130. var aPowerValue []interface{}
  131. if i < len(powerFlowData.PowerFhpArray) {
  132. aPowerValue = []interface{}{
  133. t,
  134. powerFlowData.PowerFhpArray[i],
  135. }
  136. } else {
  137. aPowerValue = []interface{}{
  138. t,
  139. nil,
  140. }
  141. }
  142. aPowerData = append(aPowerData, opts.LineData{
  143. Value: aPowerValue,
  144. })
  145. var loadValue []interface{}
  146. if i < len(powerFlowData.PowerLoadArray) {
  147. loadValue = []interface{}{
  148. t,
  149. powerFlowData.PowerLoadArray[i],
  150. }
  151. } else {
  152. loadValue = []interface{}{
  153. t,
  154. nil,
  155. }
  156. }
  157. loadData = append(loadData, opts.LineData{
  158. Value: loadValue,
  159. })
  160. // SOC
  161. var socValue []interface{}
  162. if i < len(powerFlowData.SocArray) {
  163. socValue = []interface{}{
  164. t,
  165. powerFlowData.SocArray[i],
  166. }
  167. } else {
  168. socValue = []interface{}{
  169. t,
  170. nil,
  171. }
  172. }
  173. socData = append(socData, opts.LineData{
  174. Value: socValue,
  175. })
  176. }
  177. // 生成功率流图
  178. var pfChartData []echart.PowerFlowChartData = []echart.PowerFlowChartData{}
  179. pfChartData = append(pfChartData, echart.PowerFlowChartData{
  180. Legend: "光伏",
  181. Color: stringPtr("#F1A502"),
  182. Data: pvData,
  183. })
  184. pfChartData = append(pfChartData, echart.PowerFlowChartData{
  185. Legend: "发电机",
  186. Color: stringPtr("#5398FF"),
  187. Data: genData,
  188. })
  189. pfChartData = append(pfChartData, echart.PowerFlowChartData{
  190. Legend: "市电",
  191. Color: stringPtr("#BB56FD"),
  192. Data: gridData,
  193. })
  194. pfChartData = append(pfChartData, echart.PowerFlowChartData{
  195. Legend: "aPower",
  196. Color: stringPtr("#41D187"),
  197. Data: aPowerData,
  198. })
  199. pfChartData = append(pfChartData, echart.PowerFlowChartData{
  200. Legend: "家庭负载",
  201. Color: stringPtr("#0BF5FF"),
  202. Data: loadData,
  203. })
  204. var socChartData echart.SocChartData = echart.SocChartData{
  205. Color: stringPtr("#3E7B4D"),
  206. Data: socData,
  207. }
  208. lineOpt := echart.LineChartOpt{
  209. Global: echart.ChartOpt{
  210. Title: "功率流图",
  211. },
  212. Smooth: true,
  213. }
  214. line := echart.CreatePowerFlowChart(lineOpt, pfChartData, socChartData)
  215. f, _ := os.Create(filePath)
  216. defer f.Close()
  217. line.Render(f)
  218. // 上传到文件服务器
  219. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subPowerFlowPathName, fileName)
  220. if err = minio.UploadFile(filePath, objectName); err != nil {
  221. zap.L().Error("上传PowerFlow文件失败", zap.String("path", filePath), zap.String("objectName", objectName), zap.String("err", err.Error()))
  222. return "", err
  223. }
  224. return objectName, nil
  225. }
  226. // 保存MqttLog excel到文件服务器
  227. // return objName
  228. func SaveBatchDownloadMqttLog(sn string, cmdType string, dateStr string, data []domain.MqttLogItem) (objectName string, err error) {
  229. err = nil
  230. f := excelize.NewFile()
  231. defer func() {
  232. closeErr := f.Close()
  233. if closeErr != nil {
  234. zap.L().Error("Excel 文件close失败", zap.String("err", err.Error()))
  235. if err == nil {
  236. err = closeErr
  237. }
  238. }
  239. }()
  240. // 写标题行
  241. f.SetCellValue("Sheet1", "A1", "Type")
  242. f.SetCellValue("Sheet1", "B1", "Time")
  243. f.SetCellValue("Sheet1", "C1", "Data")
  244. // 写入数据
  245. for i, d := range data {
  246. f.SetCellValue("Sheet1", "A"+strconv.Itoa(i+2), d.CmdType)
  247. f.SetCellValue("Sheet1", "B"+strconv.Itoa(i+2), d.LogTime)
  248. f.SetCellValue("Sheet1", "C"+strconv.Itoa(i+2), d.LogData)
  249. }
  250. // 创建临时保存文件路径
  251. tempPath, err := createTempPath("mqtt_" + cmdType)
  252. if err != nil {
  253. return
  254. }
  255. defer os.RemoveAll(tempPath) // 程序结束时清理临时目录
  256. fileName := fmt.Sprintf("MqttLog_%s_%s.xlsx", cmdType, strings.ReplaceAll(dateStr, "-", ""))
  257. filePath := filepath.Join(tempPath, fileName)
  258. // 保存到文件
  259. err = f.SaveAs(filePath)
  260. if err != nil {
  261. zap.L().Error("Excel文件save失败", zap.String("path", filePath), zap.String("err", err.Error()))
  262. return
  263. }
  264. // 上传到文件服务器
  265. objectName = fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subMqttPathName, fileName)
  266. if err = minio.UploadFile(filePath, objectName); err != nil {
  267. zap.L().Error("上传Excel文件失败", zap.String("path", filePath), zap.String("objectName", objectName), zap.String("err", err.Error()))
  268. return
  269. }
  270. return
  271. }
  272. // 保存EventAlarm excel到文件服务器
  273. // return objName
  274. func SaveBatchDownloadEventAlarm(sn string, dateStr string, eventAlarmData []domain.EventAlarmItem) (objectName string, err error) {
  275. err = nil
  276. f := excelize.NewFile()
  277. defer func() {
  278. closeErr := f.Close()
  279. if closeErr != nil {
  280. zap.L().Error("Excel 文件close失败", zap.String("err", err.Error()))
  281. if err == nil {
  282. err = closeErr
  283. }
  284. }
  285. }()
  286. // 写标题行
  287. f.SetCellValue("Sheet1", "A1", "ID")
  288. f.SetCellValue("Sheet1", "B1", "Time")
  289. f.SetCellValue("Sheet1", "C1", "Type")
  290. f.SetCellValue("Sheet1", "D1", "AlarmCode")
  291. f.SetCellValue("Sheet1", "E1", "Name")
  292. f.SetCellValue("Sheet1", "F1", "StartTime")
  293. f.SetCellValue("Sheet1", "G1", "EndTime")
  294. f.SetCellValue("Sheet1", "H1", "Data")
  295. for i, data := range eventAlarmData {
  296. var id string
  297. if data.ID == nil || *data.ID == "" {
  298. id = strconv.Itoa(i + 1)
  299. } else {
  300. id = *data.ID
  301. }
  302. f.SetCellValue("Sheet1", "A"+strconv.Itoa(i+2), id)
  303. f.SetCellValue("Sheet1", "B"+strconv.Itoa(i+2), data.LogTime)
  304. f.SetCellValue("Sheet1", "C"+strconv.Itoa(i+2), data.LogType)
  305. f.SetCellValue("Sheet1", "D"+strconv.Itoa(i+2), data.AlarmCode)
  306. f.SetCellValue("Sheet1", "E"+strconv.Itoa(i+2), data.LogName)
  307. f.SetCellValue("Sheet1", "F"+strconv.Itoa(i+2), data.StartTime)
  308. f.SetCellValue("Sheet1", "G"+strconv.Itoa(i+2), data.EndTime)
  309. f.SetCellValue("Sheet1", "H"+strconv.Itoa(i+2), data.LogData)
  310. }
  311. // 创建临时保存文件路径
  312. tempPath, err := createTempPath("eventAlarm")
  313. if err != nil {
  314. return
  315. }
  316. defer os.RemoveAll(tempPath) // 程序结束时清理临时目录
  317. fileName := fmt.Sprintf("EventAlarm_%s.xlsx", strings.ReplaceAll(dateStr, "-", ""))
  318. filePath := filepath.Join(tempPath, fileName)
  319. // 保存到文件
  320. err = f.SaveAs(filePath)
  321. if err != nil {
  322. zap.L().Error("Excel文件save失败", zap.String("path", filePath), zap.String("err", err.Error()))
  323. return
  324. }
  325. // 上传到文件服务器
  326. objectName = fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subEventAlarmPathName, fileName)
  327. if err = minio.UploadFile(filePath, objectName); err != nil {
  328. zap.L().Error("上传Excel文件失败", zap.String("path", filePath), zap.String("objectName", objectName), zap.String("err", err.Error()))
  329. return
  330. }
  331. return
  332. }
  333. // 保存AlarmSnapshot文件到文件服务器
  334. // return objName
  335. func SaveBatchDownloadAlarmSnapshot(sn string, dateStr string, alarmSnapshotData []*domain.SiteAlarmSnapshotData) (objectName string, err error) {
  336. err = nil
  337. f := excelize.NewFile()
  338. defer func() {
  339. closeErr := f.Close()
  340. if closeErr != nil {
  341. zap.L().Error("Excel 文件close失败", zap.String("err", err.Error()))
  342. if err == nil {
  343. err = closeErr
  344. }
  345. }
  346. }()
  347. // 写标题行
  348. f.SetCellValue("Sheet1", "A1", "ID")
  349. f.SetCellValue("Sheet1", "B1", "Time")
  350. f.SetCellValue("Sheet1", "C1", "Data")
  351. for i, data := range alarmSnapshotData {
  352. var logTime string
  353. loc, e := time.LoadLocation(data.ZoneInfo)
  354. if e != nil {
  355. zap.L().Warn("本地时间加载失败", zap.String("ZoneInfo", data.ZoneInfo), zap.String("err", err.Error()))
  356. logTime = data.LogTime.Format(time.DateTime)
  357. } else {
  358. logTime = data.LogTime.In(loc).Format(time.DateTime)
  359. }
  360. f.SetCellValue("Sheet1", "A"+strconv.Itoa(i+2), data.ID)
  361. f.SetCellValue("Sheet1", "B"+strconv.Itoa(i+2), logTime)
  362. f.SetCellValue("Sheet1", "C"+strconv.Itoa(i+2), data.JSONData)
  363. }
  364. // 创建临时保存文件路径
  365. tempPath, err := createTempPath("alarmSnapshot")
  366. if err != nil {
  367. return
  368. }
  369. defer os.RemoveAll(tempPath) // 程序结束时清理临时目录
  370. fileName := fmt.Sprintf("EventAlarm_%s.xlsx", strings.ReplaceAll(dateStr, "-", ""))
  371. filePath := filepath.Join(tempPath, fileName)
  372. // 保存到文件
  373. err = f.SaveAs(filePath)
  374. if err != nil {
  375. zap.L().Error("Excel文件save失败", zap.String("path", filePath), zap.String("err", err.Error()))
  376. return
  377. }
  378. // 上传到文件服务器
  379. objectName = fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subAlarmSnapshotPathName, fileName)
  380. if err = minio.UploadFile(filePath, objectName); err != nil {
  381. zap.L().Error("上传Excel文件失败", zap.String("path", filePath), zap.String("objectName", objectName), zap.String("err", err.Error()))
  382. return
  383. }
  384. return
  385. }
  386. // 保存EmsLog文件到文件服务器
  387. // return objName
  388. func SaveBatchDownloadEmsLog(sn string, dataBytes []byte, emsLogFileName string, contentType string) (string, error) {
  389. // 将 []byte 封装成 io.Reader
  390. dataReader := bytes.NewReader(dataBytes)
  391. // 保存到minio
  392. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subEmsLogsPathName, emsLogFileName)
  393. return objectName, minio.UploadFromReader(dataReader, int64(len(dataBytes)), objectName, contentType)
  394. }
  395. // 保存FaultRecord文件到文件服务器
  396. // return objName
  397. func SaveBatchDownloadFaultRecord(sn string, dataBytes []byte, faultRecordFileName string, contentType string) (string, error) {
  398. // 将 []byte 封装成 io.Reader
  399. dataReader := bytes.NewReader(dataBytes)
  400. // 保存到minio
  401. objectName := fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subFaultRecordPathName, faultRecordFileName)
  402. return objectName, minio.UploadFromReader(dataReader, int64(len(dataBytes)), objectName, contentType)
  403. }
  404. // 保存UpdateLog excel到文件服务器
  405. // return objName
  406. func SaveBatchDownloadUpdateLog(sn string, systemUpdateLogData []domain.BatchDownloadSystemUpdateLogInfo, aHubUpdateLogData []domain.BatchDownloadAHubUpdateLogInfo) (objectName string, err error) {
  407. err = nil
  408. f := excelize.NewFile()
  409. defer func() {
  410. closeErr := f.Close()
  411. if closeErr != nil {
  412. zap.L().Error("Excel 文件close失败", zap.String("err", err.Error()))
  413. if err == nil {
  414. err = closeErr
  415. }
  416. }
  417. }()
  418. systemUpdateSheetName := "SystemUpdate"
  419. aHubUpdateSheetName := "aHubUpdate"
  420. err = f.SetSheetName("Sheet1", systemUpdateSheetName)
  421. if err != nil {
  422. zap.L().Error("Excel Sheet1更名失败", zap.String("sheetName", systemUpdateSheetName), zap.String("err", err.Error()))
  423. return
  424. }
  425. _, err = f.NewSheet(aHubUpdateSheetName)
  426. if err != nil {
  427. zap.L().Error("Excel 新增Sheet失败", zap.String("sheetName", aHubUpdateSheetName), zap.String("err", err.Error()))
  428. return
  429. }
  430. // 样式集
  431. // 加粗
  432. // 创建加粗样式
  433. styleBold, err := f.NewStyle(&excelize.Style{
  434. Font: &excelize.Font{
  435. Bold: true,
  436. },
  437. })
  438. if err != nil {
  439. zap.L().Error("Excel 新增Sheet失败", zap.String("err", err.Error()))
  440. return
  441. }
  442. var rowIndex int = 1
  443. // 写入系统升级日志
  444. for _, updateItem := range systemUpdateLogData {
  445. // 写标题行
  446. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), "OrderNo")
  447. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("B%d", rowIndex), "GateSn")
  448. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("C%d", rowIndex), "TriggerType")
  449. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("D%d", rowIndex), "FileName")
  450. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("E%d", rowIndex), "UpdateTime")
  451. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("F%d", rowIndex), "Result")
  452. f.SetCellStyle(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), fmt.Sprintf("F%d", rowIndex), styleBold)
  453. rowIndex++
  454. // 写入项目信息内容
  455. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), updateItem.OrderNo)
  456. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("B%d", rowIndex), updateItem.GateSn)
  457. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("C%d", rowIndex), updateItem.TriggerType)
  458. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("D%d", rowIndex), updateItem.FileName)
  459. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("E%d", rowIndex), updateItem.UpdateTime)
  460. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("F%d", rowIndex), updateItem.Result)
  461. rowIndex = rowIndex + 2
  462. // Gate版本信息
  463. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), "GateVer")
  464. f.SetCellStyle(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), fmt.Sprintf("A%d", rowIndex), styleBold)
  465. rowIndex++
  466. for idx, modeVer := range updateItem.GateVerList {
  467. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+1, rowIndex, "Name")
  468. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+1, rowIndex+1, "OldVer")
  469. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+1, rowIndex+2, "NewVer")
  470. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+2, rowIndex, modeVer.Name)
  471. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+2, rowIndex+1, modeVer.OldVer)
  472. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+2, rowIndex+2, modeVer.NewVer)
  473. }
  474. rowIndex = rowIndex + 2
  475. // SubDev版本信息
  476. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), "SubVer")
  477. f.SetCellStyle(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), fmt.Sprintf("A%d", rowIndex), styleBold)
  478. rowIndex++
  479. for _, subVer := range updateItem.SubDevList {
  480. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("A%d", rowIndex), "SubSn")
  481. f.SetCellValue(systemUpdateSheetName, fmt.Sprintf("B%d", rowIndex), subVer.DevSn)
  482. rowIndex++
  483. for idx, modeVer := range subVer.DevVerList {
  484. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+1, rowIndex, "Name")
  485. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+1, rowIndex+1, "OldVer")
  486. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+1, rowIndex+2, "NewVer")
  487. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+2, rowIndex, modeVer.Name)
  488. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+2, rowIndex+1, modeVer.OldVer)
  489. excelSetCellValue(f, systemUpdateSheetName, (3*idx)+2, rowIndex+2, modeVer.NewVer)
  490. }
  491. rowIndex = rowIndex + 3
  492. }
  493. rowIndex++
  494. }
  495. rowIndex = 1
  496. // 写入aHub升级日志
  497. for _, aHubUpdateItem := range aHubUpdateLogData {
  498. // 写标题行
  499. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("A%d", rowIndex), "OrderNo")
  500. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("B%d", rowIndex), "GateSn")
  501. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("C%d", rowIndex), "TriggerType")
  502. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("D%d", rowIndex), "AHubSn")
  503. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("E%d", rowIndex), "EndTime")
  504. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("F%d", rowIndex), "Result")
  505. f.SetCellStyle(aHubUpdateSheetName, fmt.Sprintf("A%d", rowIndex), fmt.Sprintf("F%d", rowIndex), styleBold)
  506. rowIndex++
  507. // 写入项目信息内容
  508. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("A%d", rowIndex), aHubUpdateItem.OrderNo)
  509. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("B%d", rowIndex), aHubUpdateItem.GateSn)
  510. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("C%d", rowIndex), aHubUpdateItem.TriggerType)
  511. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("D%d", rowIndex), aHubUpdateItem.AHubSn)
  512. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("E%d", rowIndex), aHubUpdateItem.EndTime)
  513. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("F%d", rowIndex), aHubUpdateItem.Result)
  514. rowIndex = rowIndex + 2
  515. // aHub版本信息
  516. f.SetCellValue(aHubUpdateSheetName, fmt.Sprintf("A%d", rowIndex), "aHubVer")
  517. f.SetCellStyle(aHubUpdateSheetName, fmt.Sprintf("A%d", rowIndex), fmt.Sprintf("A%d", rowIndex), styleBold)
  518. rowIndex++
  519. for idx, modeVer := range aHubUpdateItem.DetailList {
  520. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+1, rowIndex, "FileName")
  521. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+1, rowIndex+1, "FileOrder")
  522. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+1, rowIndex+2, "ResultDesc")
  523. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+1, rowIndex+3, "OldVer")
  524. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+1, rowIndex+4, "NewVer")
  525. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+2, rowIndex, modeVer.FileName)
  526. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+2, rowIndex+1, modeVer.FileOrder)
  527. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+2, rowIndex+2, modeVer.ResultDesc)
  528. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+2, rowIndex+3, modeVer.OldVer)
  529. excelSetCellValue(f, aHubUpdateSheetName, (3*idx)+2, rowIndex+4, modeVer.NewVer)
  530. }
  531. rowIndex = rowIndex + 6
  532. }
  533. // 创建临时保存文件路径
  534. tempPath, err := createTempPath("updateLog")
  535. if err != nil {
  536. return
  537. }
  538. defer os.RemoveAll(tempPath) // 程序结束时清理临时目录
  539. fileName := fmt.Sprintf("UpdateLog_%s_%s.xlsx", sn, strings.ReplaceAll(time.Now().Format(time.DateTime), " ", "_"))
  540. filePath := filepath.Join(tempPath, fileName)
  541. // 保存到文件
  542. err = f.SaveAs(filePath)
  543. if err != nil {
  544. zap.L().Error("Excel文件save失败", zap.String("path", filePath), zap.String("err", err.Error()))
  545. return
  546. }
  547. // 上传到文件服务器
  548. objectName = fmt.Sprintf("%s/%s/%s/%s", mainPathName, sn, subUpdateLogPathName, fileName)
  549. if err = minio.UploadFile(filePath, objectName); err != nil {
  550. zap.L().Error("上传Excel文件失败", zap.String("path", filePath), zap.String("objectName", objectName), zap.String("err", err.Error()))
  551. return
  552. }
  553. return
  554. }
  555. // 保存Settings excel到文件服务器
  556. // return objName
  557. // func SaveBatchDownloadSettings(sn string, dateStr string, settingsData []domain.SiteSettings) (string, error) {
  558. // }