saveBatchDownloadData.go 29 KB

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