createAutoUpdateConfigFile.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  1. package jobs
  2. import (
  3. "fmt"
  4. "fwh-toolbox-server/domain"
  5. "fwh-toolbox-server/repositories"
  6. "fwh-toolbox-server/utils/minio"
  7. "sort"
  8. "strings"
  9. "github.com/xuri/excelize/v2"
  10. "go.uber.org/zap"
  11. )
  12. type AutoUpdateConfigUpdateOrder struct {
  13. Order []string // 升级顺序
  14. Remark string // 用于特殊流程的备注,标准流程留空即可
  15. }
  16. // key = aPowerVersion组合, value = 升级流程
  17. type AutoUpdateConfigAPowerCombMap = map[string]AutoUpdateConfigUpdateOrder
  18. type AutoUpdateConfigEmsVersion struct {
  19. Config AutoUpdateConfigAPowerCombMap
  20. Remark string
  21. }
  22. // key = EmsVersion, value = aPowerVersionListData
  23. type AutoUpdateConfigEmsVersionMap = map[string]AutoUpdateConfigEmsVersion
  24. // key = aGateName, value = EmsVersionListData
  25. type AutoUpdateConfigAGateMap = map[string]AutoUpdateConfigEmsVersionMap
  26. // 组合函数
  27. func combinations(arr []string, k int) [][]string {
  28. var result [][]string
  29. path := make([]string, 0, k)
  30. var dfs func(start int)
  31. dfs = func(start int) {
  32. if len(path) == k {
  33. tmp := make([]string, k)
  34. copy(tmp, path)
  35. result = append(result, tmp)
  36. return
  37. }
  38. for i := start; i < len(arr); i++ {
  39. path = append(path, arr[i])
  40. dfs(i + 1)
  41. path = path[:len(path)-1]
  42. }
  43. }
  44. dfs(0)
  45. return result
  46. }
  47. // 所有组合函数
  48. func allCombinations(arr []string) [][]string {
  49. var result [][]string
  50. for k := 1; k <= len(arr); k++ {
  51. result = append(result, combinations(arr, k)...)
  52. }
  53. return result
  54. }
  55. // 生成自动升级配置文件,并保存到Minio
  56. func CreateAutoUpdateConfigFile(filePath, bucket, key string) (err error) {
  57. err = nil
  58. // 提取配置相关数据
  59. configOption, err := repositories.GetAutoUpdateConfigOption()
  60. if err != nil {
  61. zap.L().Error("GetAutoUpdateConfigOption failed.")
  62. return
  63. }
  64. packages := make(map[string]domain.AutoUpdatePackages)
  65. // system
  66. for _, fileName := range configOption.Packages.System {
  67. p, subErr := repositories.GetAutoUpdatePackages(fileName)
  68. if subErr != nil {
  69. err = subErr
  70. zap.L().Error("GetAutoUpdatePackages failed.", zap.String("err", subErr.Error()), zap.String("fileName", fileName))
  71. return
  72. }
  73. packages[fileName] = *p
  74. }
  75. // aGate
  76. for _, fileName := range configOption.Packages.AGate {
  77. p, subErr := repositories.GetAutoUpdatePackages(fileName)
  78. if subErr != nil {
  79. err = subErr
  80. zap.L().Error("GetAutoUpdatePackages failed.", zap.String("err", subErr.Error()), zap.String("fileName", fileName))
  81. return
  82. }
  83. packages[fileName] = *p
  84. }
  85. // subDevice
  86. for _, fileName := range configOption.Packages.SubDevice {
  87. p, subErr := repositories.GetAutoUpdatePackages(fileName)
  88. if subErr != nil {
  89. err = subErr
  90. zap.L().Error("GetAutoUpdatePackages failed.", zap.String("err", subErr.Error()), zap.String("fileName", fileName))
  91. return
  92. }
  93. packages[fileName] = *p
  94. }
  95. // others
  96. for _, fileName := range configOption.Packages.Others {
  97. p, subErr := repositories.GetAutoUpdatePackages(fileName)
  98. if subErr != nil {
  99. err = subErr
  100. zap.L().Error("GetAutoUpdatePackages failed.", zap.String("err", subErr.Error()), zap.String("fileName", fileName))
  101. return
  102. }
  103. packages[fileName] = *p
  104. }
  105. configs := make(map[string]domain.AutoUpdateConfig, len(configOption.AGateVersions))
  106. for _, aGateName := range configOption.AGateVersions {
  107. c, subErr := repositories.GetAutoUpdateConfig(aGateName)
  108. if subErr != nil {
  109. err = subErr
  110. zap.L().Error("GetAutoUpdateConfig failed.", zap.String("err", subErr.Error()), zap.String("aGateName", aGateName))
  111. return
  112. }
  113. configs[aGateName] = *c
  114. }
  115. // 将配置数据转换成升级流程map
  116. mapConfig := make(AutoUpdateConfigAGateMap, len(configs))
  117. for aGateName, cfg := range configs {
  118. emsVersionList := make(AutoUpdateConfigEmsVersionMap)
  119. for _, emsVer := range cfg.Config.DefaultType.EmsVersions {
  120. aPowerVersionList := make(AutoUpdateConfigAPowerCombMap)
  121. aPowerCombinations := allCombinations(cfg.Config.DefaultType.APowerVersions)
  122. if len(aPowerCombinations) == 0 {
  123. aPowerVersionList["null"] = AutoUpdateConfigUpdateOrder{
  124. Order: cfg.Config.DefaultType.UpdateOrder,
  125. Remark: "", // 标准流程留空
  126. }
  127. break
  128. }
  129. for _, comb := range aPowerCombinations {
  130. aPowerVersionList[strings.Join(comb, ",")] = AutoUpdateConfigUpdateOrder{
  131. Order: cfg.Config.DefaultType.UpdateOrder,
  132. Remark: "", // 标准流程留空
  133. }
  134. }
  135. emsVersionList[emsVer.Version] = AutoUpdateConfigEmsVersion{
  136. Config: aPowerVersionList,
  137. Remark: emsVer.Remark,
  138. }
  139. }
  140. for _, specialConfig := range cfg.Config.SpecialType {
  141. for _, emsVer := range specialConfig.EmsVersions {
  142. aPowerVersionList := make(AutoUpdateConfigAPowerCombMap)
  143. aPowerCombinations := allCombinations(specialConfig.APowerVersions)
  144. for _, comb := range aPowerCombinations {
  145. if specialConfig.UseDefaultUpdate {
  146. aPowerVersionList[strings.Join(comb, ",")] = AutoUpdateConfigUpdateOrder{
  147. Order: append(cfg.Config.DefaultType.UpdateOrder, specialConfig.SpecialUpdateOrder...),
  148. Remark: emsVer.Remark,
  149. }
  150. } else {
  151. aPowerVersionList[strings.Join(comb, ",")] = AutoUpdateConfigUpdateOrder{
  152. Order: specialConfig.SpecialUpdateOrder,
  153. Remark: emsVer.Remark,
  154. }
  155. }
  156. }
  157. if _, ok := emsVersionList[emsVer.Version]; ok {
  158. // EMS 版本已存在
  159. for comb, updateOrder := range aPowerVersionList {
  160. emsVersionList[emsVer.Version].Config[comb] = updateOrder
  161. }
  162. } else {
  163. // EMS 版本不存在
  164. emsVersionList[emsVer.Version] = AutoUpdateConfigEmsVersion{
  165. Config: aPowerVersionList,
  166. Remark: emsVer.Remark,
  167. }
  168. }
  169. }
  170. }
  171. mapConfig[aGateName] = emsVersionList
  172. }
  173. // 生成xlsx文件
  174. f := excelize.NewFile()
  175. defer func() {
  176. closeErr := f.Close()
  177. if closeErr != nil {
  178. zap.L().Error("Excel 文件close失败", zap.String("err", err.Error()))
  179. if err == nil {
  180. err = closeErr
  181. }
  182. }
  183. }()
  184. // 提取 key list 排序
  185. configAGateNameList := make([]string, 0, len(mapConfig))
  186. for key := range mapConfig {
  187. configAGateNameList = append(configAGateNameList, key)
  188. }
  189. sort.Strings(configAGateNameList)
  190. // f.DeleteSheet("Sheet1")
  191. f.SetSheetName("Sheet1", "说明")
  192. for _, aGateName := range configAGateNameList {
  193. sheetName := aGateName
  194. // 写标题行
  195. f.NewSheet(sheetName)
  196. f.SetCellValue(sheetName, "A1", "#")
  197. f.SetCellValue(sheetName, "B1", "升级类型")
  198. f.SetCellValue(sheetName, "C1", "aGate硬件")
  199. f.SetCellValue(sheetName, "D1", "EMS版本")
  200. f.SetCellValue(sheetName, "E1", "aPower硬件")
  201. f.SetCellValue(sheetName, "F1", "INV版本")
  202. f.SetCellValue(sheetName, "G1", "配置Type")
  203. f.SetCellValue(sheetName, "H1", "完整升级的步骤")
  204. f.SetCellValue(sheetName, "I1", "备注")
  205. var titleStyle int
  206. titleStyle, err = styleBoldBlueCenter(f)
  207. if err != nil {
  208. return
  209. }
  210. f.SetCellStyle(sheetName, "A1", "I1", titleStyle)
  211. // 调整列宽
  212. f.SetColWidth(sheetName, "A", "A", 3.93)
  213. f.SetColWidth(sheetName, "B", "B", 17.89)
  214. f.SetColWidth(sheetName, "C", "C", 13.99)
  215. f.SetColWidth(sheetName, "D", "D", 18.94)
  216. f.SetColWidth(sheetName, "E", "E", 15.19)
  217. f.SetColWidth(sheetName, "F", "F", 24.36)
  218. f.SetColWidth(sheetName, "G", "G", 15.47)
  219. f.SetColWidth(sheetName, "H", "H", 68.43)
  220. f.SetColWidth(sheetName, "I", "I", 47.86)
  221. // 数据从第二行开始
  222. row := 2
  223. configIndex := 1
  224. // 写入数据
  225. aGateConfig := mapConfig[aGateName]
  226. // 提取EMS版本表,并排序
  227. configEmsVersionList := make([]string, 0, len(aGateConfig))
  228. for key := range aGateConfig {
  229. configEmsVersionList = append(configEmsVersionList, key)
  230. }
  231. sort.Strings(configEmsVersionList)
  232. for emsVerIndex, emsVer := range configEmsVersionList {
  233. var rowStyleCenter int
  234. var rowStyleLeftWrap int
  235. if emsVerIndex%2 == 1 {
  236. rowStyleCenter, err = styleLightPinkCenter(f)
  237. if err != nil {
  238. return
  239. }
  240. rowStyleLeftWrap, err = styleLightPinkLeft(f)
  241. if err != nil {
  242. return
  243. }
  244. } else {
  245. rowStyleCenter, err = styleLightGreenCenter(f)
  246. if err != nil {
  247. return
  248. }
  249. rowStyleLeftWrap, err = styleLightGreenLeft(f)
  250. if err != nil {
  251. return
  252. }
  253. }
  254. emsVersionConfig := aGateConfig[emsVer]
  255. // 提取aPower版本表,并排序
  256. configAPowerCombList := make([]string, 0, len(emsVersionConfig.Config))
  257. for key := range emsVersionConfig.Config {
  258. configAPowerCombList = append(configAPowerCombList, key)
  259. }
  260. sort.Strings(configAPowerCombList)
  261. for _, aPowerComb := range configAPowerCombList {
  262. updateOrder := emsVersionConfig.Config[aPowerComb]
  263. // 生成升级步骤
  264. updateOrderList := make([]string, 0, len(updateOrder.Order))
  265. invVersion := ""
  266. for i, order := range updateOrder.Order {
  267. updateOrderList = append(updateOrderList, fmt.Sprintf("%d、%s: %s", i+1, packages[order].Title, order))
  268. invVersion = strings.Join(packages[order].InvVersion, "\n")
  269. }
  270. updateOrderStr := strings.Join(updateOrderList, "\n")
  271. // 获取INV版本
  272. // 获取备注
  273. remark := emsVersionConfig.Remark
  274. if updateOrder.Remark != "" {
  275. remark = updateOrder.Remark
  276. }
  277. f.SetCellValue(sheetName, fmt.Sprintf("A%d", row), fmt.Sprintf("%d", configIndex))
  278. f.SetCellValue(sheetName, fmt.Sprintf("B%d", row), "commissions升级")
  279. f.SetCellValue(sheetName, fmt.Sprintf("C%d", row), aGateName)
  280. f.SetCellValue(sheetName, fmt.Sprintf("D%d", row), emsVer)
  281. f.SetCellValue(sheetName, fmt.Sprintf("E%d", row), aPowerComb)
  282. f.SetCellValue(sheetName, fmt.Sprintf("F%d", row), invVersion)
  283. f.SetCellValue(sheetName, fmt.Sprintf("G%d", row), "not_eq_type")
  284. f.SetCellValue(sheetName, fmt.Sprintf("H%d", row), updateOrderStr)
  285. f.SetCellValue(sheetName, fmt.Sprintf("I%d", row), remark)
  286. f.SetCellStyle(sheetName, fmt.Sprintf("A%d", row), fmt.Sprintf("G%d", row), rowStyleCenter)
  287. f.SetCellStyle(sheetName, fmt.Sprintf("H%d", row), fmt.Sprintf("I%d", row), rowStyleLeftWrap)
  288. row++
  289. if emsVerIndex == len(configEmsVersionList)-1 {
  290. // 最后一个版本
  291. f.SetCellValue(sheetName, fmt.Sprintf("A%d", row), fmt.Sprintf("%d", configIndex))
  292. f.SetCellValue(sheetName, fmt.Sprintf("B%d", row), "commissions升级")
  293. f.SetCellValue(sheetName, fmt.Sprintf("C%d", row), aGateName)
  294. f.SetCellValue(sheetName, fmt.Sprintf("D%d", row), emsVer)
  295. f.SetCellValue(sheetName, fmt.Sprintf("E%d", row), aPowerComb)
  296. f.SetCellValue(sheetName, fmt.Sprintf("F%d", row), invVersion)
  297. f.SetCellValue(sheetName, fmt.Sprintf("G%d", row), "eq_type")
  298. f.SetCellValue(sheetName, fmt.Sprintf("H%d", row), "/")
  299. f.SetCellValue(sheetName, fmt.Sprintf("I%d", row), remark)
  300. } else {
  301. f.SetCellValue(sheetName, fmt.Sprintf("A%d", row), fmt.Sprintf("%d", configIndex))
  302. f.SetCellValue(sheetName, fmt.Sprintf("B%d", row), "commissions升级")
  303. f.SetCellValue(sheetName, fmt.Sprintf("C%d", row), aGateName)
  304. f.SetCellValue(sheetName, fmt.Sprintf("D%d", row), emsVer)
  305. f.SetCellValue(sheetName, fmt.Sprintf("E%d", row), aPowerComb)
  306. f.SetCellValue(sheetName, fmt.Sprintf("F%d", row), invVersion)
  307. f.SetCellValue(sheetName, fmt.Sprintf("G%d", row), "eq_type")
  308. f.SetCellValue(sheetName, fmt.Sprintf("H%d", row), updateOrderStr)
  309. f.SetCellValue(sheetName, fmt.Sprintf("I%d", row), remark)
  310. }
  311. f.SetCellStyle(sheetName, fmt.Sprintf("A%d", row), fmt.Sprintf("G%d", row), rowStyleCenter)
  312. f.SetCellStyle(sheetName, fmt.Sprintf("H%d", row), fmt.Sprintf("I%d", row), rowStyleLeftWrap)
  313. row++
  314. }
  315. }
  316. }
  317. // 保存到文件
  318. err = f.SaveAs(filePath)
  319. if err != nil {
  320. zap.L().Error("Excel文件save失败", zap.String("path", filePath), zap.String("err", err.Error()))
  321. return
  322. }
  323. // 上传到文件服务器
  324. if err = minio.UploadFileToBucket(bucket, filePath, key); err != nil {
  325. zap.L().Error("上传Excel文件失败", zap.String("path", filePath), zap.String("bucket", bucket), zap.String("key", key), zap.String("err", err.Error()))
  326. return
  327. }
  328. return
  329. }
  330. // 字体加粗,背景蓝色,文字居中
  331. func styleBoldBlueCenter(f *excelize.File) (int, error) {
  332. style, err := f.NewStyle(&excelize.Style{
  333. Font: &excelize.Font{
  334. Bold: true,
  335. },
  336. Fill: excelize.Fill{
  337. Type: "pattern",
  338. Color: []string{"#3399FF"}, // 蓝色
  339. Pattern: 1,
  340. },
  341. Alignment: &excelize.Alignment{
  342. Horizontal: "center",
  343. Vertical: "center",
  344. },
  345. // 黑色实线边框
  346. Border: []excelize.Border{
  347. {Type: "left", Color: "000000", Style: 1},
  348. {Type: "top", Color: "000000", Style: 1},
  349. {Type: "right", Color: "000000", Style: 1},
  350. {Type: "bottom", Color: "000000", Style: 1},
  351. },
  352. })
  353. if err != nil {
  354. zap.L().Error("StyleBoldBlueCenter error", zap.String("err", err.Error()))
  355. return 0, err
  356. }
  357. return style, nil
  358. }
  359. // 背景浅粉色、文字居中、自动换行
  360. func styleLightPinkCenter(f *excelize.File) (int, error) {
  361. style, err := f.NewStyle(&excelize.Style{
  362. Fill: excelize.Fill{
  363. Type: "pattern",
  364. Color: []string{"#FFDDEE"}, // 浅粉色
  365. Pattern: 1,
  366. },
  367. Alignment: &excelize.Alignment{
  368. Horizontal: "center",
  369. Vertical: "center",
  370. WrapText: true,
  371. },
  372. // 黑色实线边框
  373. Border: []excelize.Border{
  374. {Type: "left", Color: "000000", Style: 1},
  375. {Type: "top", Color: "000000", Style: 1},
  376. {Type: "right", Color: "000000", Style: 1},
  377. {Type: "bottom", Color: "000000", Style: 1},
  378. },
  379. })
  380. if err != nil {
  381. zap.L().Error("StyleLightPinkCenter error", zap.String("err", err.Error()))
  382. return 0, err
  383. }
  384. return style, nil
  385. }
  386. // 背景浅粉色、文字左对齐、自动换行
  387. func styleLightPinkLeft(f *excelize.File) (int, error) {
  388. style, err := f.NewStyle(&excelize.Style{
  389. Fill: excelize.Fill{
  390. Type: "pattern",
  391. Color: []string{"#FFDDEE"},
  392. Pattern: 1,
  393. },
  394. Alignment: &excelize.Alignment{
  395. Horizontal: "left",
  396. Vertical: "center",
  397. WrapText: true,
  398. },
  399. // 黑色实线边框
  400. Border: []excelize.Border{
  401. {Type: "left", Color: "000000", Style: 1},
  402. {Type: "top", Color: "000000", Style: 1},
  403. {Type: "right", Color: "000000", Style: 1},
  404. {Type: "bottom", Color: "000000", Style: 1},
  405. },
  406. })
  407. if err != nil {
  408. zap.L().Error("StyleLightPinkLeftWrap error", zap.String("err", err.Error()))
  409. return 0, err
  410. }
  411. return style, nil
  412. }
  413. // 背景浅绿色、文字居中、自动换行
  414. func styleLightGreenCenter(f *excelize.File) (int, error) {
  415. style, err := f.NewStyle(&excelize.Style{
  416. Fill: excelize.Fill{
  417. Type: "pattern",
  418. Color: []string{"#CCFFCC"}, // 浅绿色
  419. Pattern: 1,
  420. },
  421. Alignment: &excelize.Alignment{
  422. Horizontal: "center",
  423. Vertical: "center",
  424. WrapText: true,
  425. },
  426. // 黑色实线边框
  427. Border: []excelize.Border{
  428. {Type: "left", Color: "000000", Style: 1},
  429. {Type: "top", Color: "000000", Style: 1},
  430. {Type: "right", Color: "000000", Style: 1},
  431. {Type: "bottom", Color: "000000", Style: 1},
  432. },
  433. })
  434. if err != nil {
  435. zap.L().Error("StyleLightGreenCenter error", zap.String("err", err.Error()))
  436. return 0, err
  437. }
  438. return style, nil
  439. }
  440. // 背景浅绿色、文字左对齐、自动换行
  441. func styleLightGreenLeft(f *excelize.File) (int, error) {
  442. style, err := f.NewStyle(&excelize.Style{
  443. Fill: excelize.Fill{
  444. Type: "pattern",
  445. Color: []string{"#CCFFCC"},
  446. Pattern: 1,
  447. },
  448. Alignment: &excelize.Alignment{
  449. Horizontal: "left",
  450. Vertical: "center",
  451. WrapText: true,
  452. },
  453. // 黑色实线边框
  454. Border: []excelize.Border{
  455. {Type: "left", Color: "000000", Style: 1},
  456. {Type: "top", Color: "000000", Style: 1},
  457. {Type: "right", Color: "000000", Style: 1},
  458. {Type: "bottom", Color: "000000", Style: 1},
  459. },
  460. })
  461. if err != nil {
  462. zap.L().Error("StyleLightGreenLeftWrap error", zap.String("err", err.Error()))
  463. return 0, err
  464. }
  465. return style, nil
  466. }