package jobs import ( "fmt" "fwh-toolbox-server/domain" "fwh-toolbox-server/repositories" "fwh-toolbox-server/utils/minio" "sort" "strings" "github.com/xuri/excelize/v2" "go.uber.org/zap" ) type AutoUpdateConfigUpdateOrder struct { Order []string // 升级顺序 Remark string // 用于特殊流程的备注,标准流程留空即可 } // key = aPowerVersion组合, value = 升级流程 type AutoUpdateConfigAPowerCombMap = map[string]AutoUpdateConfigUpdateOrder type AutoUpdateConfigEmsVersion struct { Config AutoUpdateConfigAPowerCombMap Remark string } // key = EmsVersion, value = aPowerVersionListData type AutoUpdateConfigEmsVersionMap = map[string]AutoUpdateConfigEmsVersion // key = aGateName, value = EmsVersionListData type AutoUpdateConfigAGateMap = map[string]AutoUpdateConfigEmsVersionMap // 组合函数 func combinations(arr []string, k int) [][]string { var result [][]string path := make([]string, 0, k) var dfs func(start int) dfs = func(start int) { if len(path) == k { tmp := make([]string, k) copy(tmp, path) result = append(result, tmp) return } for i := start; i < len(arr); i++ { path = append(path, arr[i]) dfs(i + 1) path = path[:len(path)-1] } } dfs(0) return result } // 所有组合函数 func allCombinations(arr []string) [][]string { var result [][]string for k := 1; k <= len(arr); k++ { result = append(result, combinations(arr, k)...) } return result } // 生成自动升级配置文件,并保存到Minio func CreateAutoUpdateConfigFile(filePath, bucket, key string) (err error) { err = nil // 提取配置相关数据 configOption, err := repositories.GetAutoUpdateConfigOption() if err != nil { zap.L().Error("GetAutoUpdateConfigOption failed.") return } packages := make(map[string]domain.AutoUpdatePackages) // system for _, fileName := range configOption.Packages.System { p, subErr := repositories.GetAutoUpdatePackages(fileName) if subErr != nil { err = subErr zap.L().Error("GetAutoUpdatePackages failed.", zap.String("err", subErr.Error()), zap.String("fileName", fileName)) return } packages[fileName] = *p } // aGate for _, fileName := range configOption.Packages.AGate { p, subErr := repositories.GetAutoUpdatePackages(fileName) if subErr != nil { err = subErr zap.L().Error("GetAutoUpdatePackages failed.", zap.String("err", subErr.Error()), zap.String("fileName", fileName)) return } packages[fileName] = *p } // subDevice for _, fileName := range configOption.Packages.SubDevice { p, subErr := repositories.GetAutoUpdatePackages(fileName) if subErr != nil { err = subErr zap.L().Error("GetAutoUpdatePackages failed.", zap.String("err", subErr.Error()), zap.String("fileName", fileName)) return } packages[fileName] = *p } // others for _, fileName := range configOption.Packages.Others { p, subErr := repositories.GetAutoUpdatePackages(fileName) if subErr != nil { err = subErr zap.L().Error("GetAutoUpdatePackages failed.", zap.String("err", subErr.Error()), zap.String("fileName", fileName)) return } packages[fileName] = *p } configs := make(map[string]domain.AutoUpdateConfig, len(configOption.AGateVersions)) for _, aGateName := range configOption.AGateVersions { c, subErr := repositories.GetAutoUpdateConfig(aGateName) if subErr != nil { err = subErr zap.L().Error("GetAutoUpdateConfig failed.", zap.String("err", subErr.Error()), zap.String("aGateName", aGateName)) return } configs[aGateName] = *c } // 将配置数据转换成升级流程map mapConfig := make(AutoUpdateConfigAGateMap, len(configs)) for aGateName, cfg := range configs { emsVersionList := make(AutoUpdateConfigEmsVersionMap) for _, emsVer := range cfg.Config.DefaultType.EmsVersions { aPowerVersionList := make(AutoUpdateConfigAPowerCombMap) aPowerCombinations := allCombinations(cfg.Config.DefaultType.APowerVersions) if len(aPowerCombinations) == 0 { aPowerVersionList["null"] = AutoUpdateConfigUpdateOrder{ Order: cfg.Config.DefaultType.UpdateOrder, Remark: "", // 标准流程留空 } break } for _, comb := range aPowerCombinations { aPowerVersionList[strings.Join(comb, ",")] = AutoUpdateConfigUpdateOrder{ Order: cfg.Config.DefaultType.UpdateOrder, Remark: "", // 标准流程留空 } } emsVersionList[emsVer.Version] = AutoUpdateConfigEmsVersion{ Config: aPowerVersionList, Remark: emsVer.Remark, } } for _, specialConfig := range cfg.Config.SpecialType { for _, emsVer := range specialConfig.EmsVersions { aPowerVersionList := make(AutoUpdateConfigAPowerCombMap) aPowerCombinations := allCombinations(specialConfig.APowerVersions) for _, comb := range aPowerCombinations { if specialConfig.UseDefaultUpdate { aPowerVersionList[strings.Join(comb, ",")] = AutoUpdateConfigUpdateOrder{ Order: append(cfg.Config.DefaultType.UpdateOrder, specialConfig.SpecialUpdateOrder...), Remark: emsVer.Remark, } } else { aPowerVersionList[strings.Join(comb, ",")] = AutoUpdateConfigUpdateOrder{ Order: specialConfig.SpecialUpdateOrder, Remark: emsVer.Remark, } } } if _, ok := emsVersionList[emsVer.Version]; ok { // EMS 版本已存在 for comb, updateOrder := range aPowerVersionList { emsVersionList[emsVer.Version].Config[comb] = updateOrder } } else { // EMS 版本不存在 emsVersionList[emsVer.Version] = AutoUpdateConfigEmsVersion{ Config: aPowerVersionList, Remark: emsVer.Remark, } } } } mapConfig[aGateName] = emsVersionList } // 生成xlsx文件 f := excelize.NewFile() defer func() { closeErr := f.Close() if closeErr != nil { zap.L().Error("Excel 文件close失败", zap.String("err", err.Error())) if err == nil { err = closeErr } } }() // 提取 key list 排序 configAGateNameList := make([]string, 0, len(mapConfig)) for key := range mapConfig { configAGateNameList = append(configAGateNameList, key) } sort.Strings(configAGateNameList) // f.DeleteSheet("Sheet1") f.SetSheetName("Sheet1", "说明") for _, aGateName := range configAGateNameList { sheetName := aGateName // 写标题行 f.NewSheet(sheetName) f.SetCellValue(sheetName, "A1", "#") f.SetCellValue(sheetName, "B1", "升级类型") f.SetCellValue(sheetName, "C1", "aGate硬件") f.SetCellValue(sheetName, "D1", "EMS版本") f.SetCellValue(sheetName, "E1", "aPower硬件") f.SetCellValue(sheetName, "F1", "INV版本") f.SetCellValue(sheetName, "G1", "配置Type") f.SetCellValue(sheetName, "H1", "完整升级的步骤") f.SetCellValue(sheetName, "I1", "备注") var titleStyle int titleStyle, err = styleBoldBlueCenter(f) if err != nil { return } f.SetCellStyle(sheetName, "A1", "I1", titleStyle) // 调整列宽 f.SetColWidth(sheetName, "A", "A", 3.93) f.SetColWidth(sheetName, "B", "B", 17.89) f.SetColWidth(sheetName, "C", "C", 13.99) f.SetColWidth(sheetName, "D", "D", 18.94) f.SetColWidth(sheetName, "E", "E", 15.19) f.SetColWidth(sheetName, "F", "F", 24.36) f.SetColWidth(sheetName, "G", "G", 15.47) f.SetColWidth(sheetName, "H", "H", 68.43) f.SetColWidth(sheetName, "I", "I", 47.86) // 数据从第二行开始 row := 2 configIndex := 1 // 写入数据 aGateConfig := mapConfig[aGateName] // 提取EMS版本表,并排序 configEmsVersionList := make([]string, 0, len(aGateConfig)) for key := range aGateConfig { configEmsVersionList = append(configEmsVersionList, key) } sort.Strings(configEmsVersionList) for emsVerIndex, emsVer := range configEmsVersionList { var rowStyleCenter int var rowStyleLeftWrap int if emsVerIndex%2 == 1 { rowStyleCenter, err = styleLightPinkCenter(f) if err != nil { return } rowStyleLeftWrap, err = styleLightPinkLeft(f) if err != nil { return } } else { rowStyleCenter, err = styleLightGreenCenter(f) if err != nil { return } rowStyleLeftWrap, err = styleLightGreenLeft(f) if err != nil { return } } emsVersionConfig := aGateConfig[emsVer] // 提取aPower版本表,并排序 configAPowerCombList := make([]string, 0, len(emsVersionConfig.Config)) for key := range emsVersionConfig.Config { configAPowerCombList = append(configAPowerCombList, key) } sort.Strings(configAPowerCombList) for _, aPowerComb := range configAPowerCombList { updateOrder := emsVersionConfig.Config[aPowerComb] // 生成升级步骤 updateOrderList := make([]string, 0, len(updateOrder.Order)) invVersion := "" for i, order := range updateOrder.Order { updateOrderList = append(updateOrderList, fmt.Sprintf("%d、%s: %s", i+1, packages[order].Title, order)) invVersion = strings.Join(packages[order].InvVersion, "\n") } updateOrderStr := strings.Join(updateOrderList, "\n") // 获取INV版本 // 获取备注 remark := emsVersionConfig.Remark if updateOrder.Remark != "" { remark = updateOrder.Remark } f.SetCellValue(sheetName, fmt.Sprintf("A%d", row), fmt.Sprintf("%d", configIndex)) f.SetCellValue(sheetName, fmt.Sprintf("B%d", row), "commissions升级") f.SetCellValue(sheetName, fmt.Sprintf("C%d", row), aGateName) f.SetCellValue(sheetName, fmt.Sprintf("D%d", row), emsVer) f.SetCellValue(sheetName, fmt.Sprintf("E%d", row), aPowerComb) f.SetCellValue(sheetName, fmt.Sprintf("F%d", row), invVersion) f.SetCellValue(sheetName, fmt.Sprintf("G%d", row), "not_eq_type") f.SetCellValue(sheetName, fmt.Sprintf("H%d", row), updateOrderStr) f.SetCellValue(sheetName, fmt.Sprintf("I%d", row), remark) f.SetCellStyle(sheetName, fmt.Sprintf("A%d", row), fmt.Sprintf("G%d", row), rowStyleCenter) f.SetCellStyle(sheetName, fmt.Sprintf("H%d", row), fmt.Sprintf("I%d", row), rowStyleLeftWrap) row++ if emsVerIndex == len(configEmsVersionList)-1 { // 最后一个版本 f.SetCellValue(sheetName, fmt.Sprintf("A%d", row), fmt.Sprintf("%d", configIndex)) f.SetCellValue(sheetName, fmt.Sprintf("B%d", row), "commissions升级") f.SetCellValue(sheetName, fmt.Sprintf("C%d", row), aGateName) f.SetCellValue(sheetName, fmt.Sprintf("D%d", row), emsVer) f.SetCellValue(sheetName, fmt.Sprintf("E%d", row), aPowerComb) f.SetCellValue(sheetName, fmt.Sprintf("F%d", row), invVersion) f.SetCellValue(sheetName, fmt.Sprintf("G%d", row), "eq_type") f.SetCellValue(sheetName, fmt.Sprintf("H%d", row), "/") f.SetCellValue(sheetName, fmt.Sprintf("I%d", row), remark) } else { f.SetCellValue(sheetName, fmt.Sprintf("A%d", row), fmt.Sprintf("%d", configIndex)) f.SetCellValue(sheetName, fmt.Sprintf("B%d", row), "commissions升级") f.SetCellValue(sheetName, fmt.Sprintf("C%d", row), aGateName) f.SetCellValue(sheetName, fmt.Sprintf("D%d", row), emsVer) f.SetCellValue(sheetName, fmt.Sprintf("E%d", row), aPowerComb) f.SetCellValue(sheetName, fmt.Sprintf("F%d", row), invVersion) f.SetCellValue(sheetName, fmt.Sprintf("G%d", row), "eq_type") f.SetCellValue(sheetName, fmt.Sprintf("H%d", row), updateOrderStr) f.SetCellValue(sheetName, fmt.Sprintf("I%d", row), remark) } f.SetCellStyle(sheetName, fmt.Sprintf("A%d", row), fmt.Sprintf("G%d", row), rowStyleCenter) f.SetCellStyle(sheetName, fmt.Sprintf("H%d", row), fmt.Sprintf("I%d", row), rowStyleLeftWrap) row++ } } } // 保存到文件 err = f.SaveAs(filePath) if err != nil { zap.L().Error("Excel文件save失败", zap.String("path", filePath), zap.String("err", err.Error())) return } // 上传到文件服务器 if err = minio.UploadFileToBucket(bucket, filePath, key); err != nil { zap.L().Error("上传Excel文件失败", zap.String("path", filePath), zap.String("bucket", bucket), zap.String("key", key), zap.String("err", err.Error())) return } return } // 字体加粗,背景蓝色,文字居中 func styleBoldBlueCenter(f *excelize.File) (int, error) { style, err := f.NewStyle(&excelize.Style{ Font: &excelize.Font{ Bold: true, }, Fill: excelize.Fill{ Type: "pattern", Color: []string{"#3399FF"}, // 蓝色 Pattern: 1, }, Alignment: &excelize.Alignment{ Horizontal: "center", Vertical: "center", }, // 黑色实线边框 Border: []excelize.Border{ {Type: "left", Color: "000000", Style: 1}, {Type: "top", Color: "000000", Style: 1}, {Type: "right", Color: "000000", Style: 1}, {Type: "bottom", Color: "000000", Style: 1}, }, }) if err != nil { zap.L().Error("StyleBoldBlueCenter error", zap.String("err", err.Error())) return 0, err } return style, nil } // 背景浅粉色、文字居中、自动换行 func styleLightPinkCenter(f *excelize.File) (int, error) { style, err := f.NewStyle(&excelize.Style{ Fill: excelize.Fill{ Type: "pattern", Color: []string{"#FFDDEE"}, // 浅粉色 Pattern: 1, }, Alignment: &excelize.Alignment{ Horizontal: "center", Vertical: "center", WrapText: true, }, // 黑色实线边框 Border: []excelize.Border{ {Type: "left", Color: "000000", Style: 1}, {Type: "top", Color: "000000", Style: 1}, {Type: "right", Color: "000000", Style: 1}, {Type: "bottom", Color: "000000", Style: 1}, }, }) if err != nil { zap.L().Error("StyleLightPinkCenter error", zap.String("err", err.Error())) return 0, err } return style, nil } // 背景浅粉色、文字左对齐、自动换行 func styleLightPinkLeft(f *excelize.File) (int, error) { style, err := f.NewStyle(&excelize.Style{ Fill: excelize.Fill{ Type: "pattern", Color: []string{"#FFDDEE"}, Pattern: 1, }, Alignment: &excelize.Alignment{ Horizontal: "left", Vertical: "center", WrapText: true, }, // 黑色实线边框 Border: []excelize.Border{ {Type: "left", Color: "000000", Style: 1}, {Type: "top", Color: "000000", Style: 1}, {Type: "right", Color: "000000", Style: 1}, {Type: "bottom", Color: "000000", Style: 1}, }, }) if err != nil { zap.L().Error("StyleLightPinkLeftWrap error", zap.String("err", err.Error())) return 0, err } return style, nil } // 背景浅绿色、文字居中、自动换行 func styleLightGreenCenter(f *excelize.File) (int, error) { style, err := f.NewStyle(&excelize.Style{ Fill: excelize.Fill{ Type: "pattern", Color: []string{"#CCFFCC"}, // 浅绿色 Pattern: 1, }, Alignment: &excelize.Alignment{ Horizontal: "center", Vertical: "center", WrapText: true, }, // 黑色实线边框 Border: []excelize.Border{ {Type: "left", Color: "000000", Style: 1}, {Type: "top", Color: "000000", Style: 1}, {Type: "right", Color: "000000", Style: 1}, {Type: "bottom", Color: "000000", Style: 1}, }, }) if err != nil { zap.L().Error("StyleLightGreenCenter error", zap.String("err", err.Error())) return 0, err } return style, nil } // 背景浅绿色、文字左对齐、自动换行 func styleLightGreenLeft(f *excelize.File) (int, error) { style, err := f.NewStyle(&excelize.Style{ Fill: excelize.Fill{ Type: "pattern", Color: []string{"#CCFFCC"}, Pattern: 1, }, Alignment: &excelize.Alignment{ Horizontal: "left", Vertical: "center", WrapText: true, }, // 黑色实线边框 Border: []excelize.Border{ {Type: "left", Color: "000000", Style: 1}, {Type: "top", Color: "000000", Style: 1}, {Type: "right", Color: "000000", Style: 1}, {Type: "bottom", Color: "000000", Style: 1}, }, }) if err != nil { zap.L().Error("StyleLightGreenLeftWrap error", zap.String("err", err.Error())) return 0, err } return style, nil }