package service import ( "encoding/json" "fmt" "os" "path/filepath" "reflect" "be.ems/src/framework/constants/uploadsubpath" "be.ems/src/framework/utils/file" "be.ems/src/framework/utils/parse" neFetchlink "be.ems/src/modules/network_element/fetch_link" neModel "be.ems/src/modules/network_element/model" neService "be.ems/src/modules/network_element/service" "be.ems/src/modules/practical_training/model" "be.ems/src/modules/practical_training/repository" "github.com/xuri/excelize/v2" ) // NewPtNeConfigDataService 实例化服务层 var NewPtNeConfigDataService = &PtNeConfigDataService{ ptNeConfigDataLogRepository: repository.NewPtNeConfigDataLogRepository, ptNeConfigDataRepository: repository.NewPtNeConfigDataRepository, neConfigService: neService.NewNeConfigImpl, neInfoService: neService.NewNeInfoImpl, } // PtNeConfigDataService 服务层处理 type PtNeConfigDataService struct { // 实训教学_网元参数配置数据变更日志 ptNeConfigDataLogRepository repository.IPtNeConfigDataLogRepository // 实训教学_网元参数配置表 ptNeConfigDataRepository repository.IPtNeConfigDataRepository // 网元参数配置可用属性值服务 neConfigService neService.INeConfig // 网元信息服务 neInfoService neService.INeInfo } // SelectNeHostPage 分页查询列表数据 func (r *PtNeConfigDataService) SelectPage(query map[string]any) map[string]any { return r.ptNeConfigDataRepository.SelectPage(query) } // SelectConfigList 查询列表 func (r *PtNeConfigDataService) SelectList(param model.PtNeConfigData) []model.PtNeConfigData { return r.ptNeConfigDataRepository.SelectList(param) } // SelectByIds 通过ID查询 func (r *PtNeConfigDataService) SelectById(paramId string) model.PtNeConfigData { if paramId == "" { return model.PtNeConfigData{} } neHosts := r.ptNeConfigDataRepository.SelectByIds([]string{paramId}) if len(neHosts) > 0 { return neHosts[0] } return model.PtNeConfigData{} } // Insert 新增信息 func (r *PtNeConfigDataService) Insert(param model.PtNeConfigData) string { return r.ptNeConfigDataRepository.Insert(param) } // Update 修改信息 func (r *PtNeConfigDataService) Update(param model.PtNeConfigData) int64 { return r.ptNeConfigDataRepository.Update(param) } // DeleteByIds 批量删除信息 func (r *PtNeConfigDataService) DeleteByIds(paramIds []string) (int64, error) { // 检查是否存在 ids := r.ptNeConfigDataRepository.SelectByIds(paramIds) if len(ids) <= 0 { return 0, fmt.Errorf("ptNeConfigData.noData") } if len(ids) == len(paramIds) { rows := r.ptNeConfigDataRepository.DeleteByIds(paramIds) return rows, nil } // 删除信息失败! return 0, fmt.Errorf("delete fail") } // SaveAsDefault 系统网元配置保存为系统示例 func (r *PtNeConfigDataService) SaveAsDefault(neType, neId string) { // 查询网元获取IP获取网元状态 neInfo := r.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, neId) if neInfo.NeId != neId || neInfo.IP == "" { return } stubType := "0" operaUserName := "admin" deptId := "100" confs := r.neConfigService.SelectList(neModel.NeConfig{NeType: neInfo.NeType}) for _, v := range confs { // 查询是否存在记录 hasItems := r.SelectList(model.PtNeConfigData{ NeType: v.NeType, StubType: stubType, ParamName: v.ParamName, ParamType: v.ParamType, }) // 网元直连 获取网元配置信息 resData, err := neFetchlink.NeConfigInfo(neInfo, v.ParamName) if err != nil { continue } // 将json数据转字符串存储 data:[{},{}] data, ok := resData["data"] if !ok { continue } paramDataByte, err := json.Marshal(data) if err != nil { continue } // 插入 if len(hasItems) == 0 { r.Insert(model.PtNeConfigData{ CreateBy: operaUserName, StubType: stubType, NeType: v.NeType, ParamName: v.ParamName, ParamDisplay: v.ParamDisplay, ParamType: v.ParamType, ParamJson: string(paramDataByte), DeptId: deptId, }) } // 更新 if len(hasItems) == 1 { item := hasItems[0] item.UpdateBy = operaUserName item.ParamDisplay = v.ParamDisplay item.ParamJson = string(paramDataByte) item.DeptId = deptId r.Update(item) } } } // ResetAsDefault 重置配置示例 // stubType:2个人为班级示例 1班级为系统示例 func (r *PtNeConfigDataService) ResetAsDefault(operaUserName, stubType, neType, deptId string) { rootStubType := "1" if stubType == "1" { rootStubType = "0" } if stubType == "2" { rootStubType = "1" } ptConfs := r.SelectList(model.PtNeConfigData{StubType: rootStubType, NeType: neType}) for _, v := range ptConfs { // 查询是否存在记录 hasItems := r.SelectList(model.PtNeConfigData{ CreateBy: operaUserName, NeType: v.NeType, StubType: stubType, ParamName: v.ParamName, ParamType: v.ParamType, }) // 插入 if len(hasItems) == 0 { r.Insert(model.PtNeConfigData{ CreateBy: operaUserName, StubType: stubType, NeType: v.NeType, ParamName: v.ParamName, ParamDisplay: v.ParamDisplay, ParamType: v.ParamType, ParamJson: v.ParamJson, DeptId: deptId, }) // 保留变更日志 changeLog := model.PtNeConfigDataLog{ CreateBy: operaUserName, StubType: stubType, NeType: v.NeType, ParamName: v.ParamName, ParamDisplay: v.ParamDisplay, ParamType: v.ParamType, OperaType: 0, ParamJsonOld: "[]", ParamJsonNew: v.ParamJson, } r.ptNeConfigDataLogRepository.Insert(changeLog) } // 更新 if len(hasItems) == 1 { item := hasItems[0] item.UpdateBy = operaUserName item.ParamDisplay = v.ParamDisplay item.ParamJson = v.ParamJson item.DeptId = deptId r.Update(item) // 保留变更日志 changeLog := model.PtNeConfigDataLog{ CreateBy: operaUserName, StubType: hasItems[0].StubType, NeType: v.NeType, ParamName: v.ParamName, ParamDisplay: v.ParamDisplay, ParamType: v.ParamType, OperaType: 0, ParamJsonOld: hasItems[0].ParamJson, ParamJsonNew: v.ParamJson, } r.ptNeConfigDataLogRepository.Insert(changeLog) } } } // SelectByStubType 通过存根类型查询 func (r *PtNeConfigDataService) SelectByStubType(param model.PtNeConfigData) model.PtNeConfigData { list := r.SelectList(param) if len(list) == 0 && param.StubType != "1" { param.CreateBy = "" param.StubType = "1" list = r.SelectList(param) } if len(list) == 0 && param.StubType != "0" { param.CreateBy = "" param.StubType = "0" param.DeptId = "100" list = r.SelectList(param) } var paraData model.PtNeConfigData if len(list) > 0 { paraData = list[0] if err := json.Unmarshal([]byte(paraData.ParamJson), ¶Data.ParamData); err != nil { paraData.ParamData = []map[string]any{} } } return paraData } // ApplyToNe 参数应用到网元 func (r *PtNeConfigDataService) ApplyToNe(paramUser, neType string) error { ptConfs := r.SelectList(model.PtNeConfigData{CreateBy: paramUser, NeType: neType}) if len(ptConfs) == 0 { return fmt.Errorf("NeConfigData Not Found") } // 找网元,只有一套就固定neId:001 neInfo := r.neInfoService.SelectNeInfoByNeTypeAndNeID(neType, "001") if neInfo.NeType != neType || neInfo.ID == "" { return fmt.Errorf("NeInfo Not Found") } // 遍历去设置参数 for _, ptConf := range ptConfs { if err := json.Unmarshal([]byte(ptConf.ParamJson), &ptConf.ParamData); err != nil { ptConf.ParamData = []map[string]any{} } // 将json数据转字符串存储 [{},{}] if len(ptConf.ParamData) == 0 { continue } // 单层逐个更新 if ptConf.ParamType == "list" { for k, v := range ptConf.ParamData[0] { neFetchlink.NeConfigUpdate(neInfo, ptConf.ParamName, "", map[string]any{k: v}) } } // 多层逐个更新 if ptConf.ParamType == "array" { // 删除原先配置 resData, err := neFetchlink.NeConfigInfo(neInfo, ptConf.ParamName) if err != nil { continue } if data, ok := resData["data"]; ok { for i := 0; i < len(data.([]any)); i++ { // 倒序遍历 originIndex := i newIndex := len(data.([]any)) - originIndex - 1 element := data.([]any)[newIndex] loc := parse.Number(element.(map[string]any)["index"]) neFetchlink.NeConfigDelete(neInfo, ptConf.ParamName, fmt.Sprint(loc)) } } // 遍历新增 for _, v := range ptConf.ParamData { loc := parse.Number(v["index"]) neFetchlink.NeConfigInstall(neInfo, ptConf.ParamName, fmt.Sprint(loc), v) // 检查是否有array子层 for vk, vv := range v { if reflect.TypeOf(vv).Kind() == reflect.Slice { for i, item := range vv.([]any) { data := item.(map[string]any) data["index"] = i neFetchlink.NeConfigInstall(neInfo, ptConf.ParamName, fmt.Sprintf("%v/%s/%v", loc, vk, i), data) } } } } } } return nil } // ExportToExcel 导出网元的全部配置项数据 func (r *PtNeConfigDataService) ExportToExcel(operaUserName, fileName string) (string, error) { confs := r.neConfigService.SelectNeConfigByNeType("*") datas := r.ptNeConfigDataRepository.SelectList(model.PtNeConfigData{CreateBy: operaUserName}) return r.writeSheet(confs, datas, fileName) } // writeSheet 写入表格 func (r *PtNeConfigDataService) writeSheet(sheetData []neModel.NeConfig, cellData []model.PtNeConfigData, fileName string) (string, error) { f := excelize.NewFile() defer f.Close() // 设置颜色填充 styleType, _ := f.NewStyle(&excelize.Style{Fill: excelize.Fill{ Type: "pattern", Pattern: 1, Color: []string{"F0F806"}, // RRGGBB 格式的 }}) styleRow, _ := f.NewStyle(&excelize.Style{Fill: excelize.Fill{ Type: "pattern", Pattern: 1, Color: []string{"D0CECE"}, // RRGGBB 格式的 }}) styleMore, _ := f.NewStyle(&excelize.Style{Font: &excelize.Font{ Color: "4472C4", VertAlign: "center", }}) // 网元工作簿行计数 sheetNameRows := make(map[string]int) for _, sd := range sheetData { _ = json.Unmarshal([]byte(sd.ParamJson), &sd.ParamData) // 取到对应数据 var data model.PtNeConfigData for _, cell := range cellData { if cell.NeType == sd.NeType && cell.ParamName == sd.ParamName { data = cell break } } if err := json.Unmarshal([]byte(data.ParamJson), &data.ParamData); err != nil || len(data.ParamData) == 0 { continue } sheetName := sd.NeType // 创建一个工作表 f.NewSheet(sheetName) // 设置工作表上宽度为 20 // f.SetColWidth(sheetName, "B", "C", 20) sheetRows := 1 if v, ok := sheetNameRows[sheetName]; ok && v != 0 { sheetRows = v } // 合并标题单元格 f.MergeCell(sheetName, fmt.Sprintf("A%d", sheetRows), fmt.Sprintf("C%d", sheetRows)) f.SetCellStyle(sheetName, fmt.Sprintf("A%d", sheetRows), fmt.Sprintf("C%d", sheetRows), styleType) // 标题 f.SetCellValue(sheetName, fmt.Sprintf("A%d", sheetRows), sd.ParamDisplay) sheetRows += 1 // fmt.Println(sheetName, " ========= ", sd.ParamDisplay, " ==== ", sd.ParamType, len(data.ParamData)) itemData := []*[]any{} if sd.ParamType == "list" { itemData = append(itemData, &[]any{"Key", "Value"}) for _, v := range sd.ParamData { name := v["name"].(string) value := v["value"] // 取到对应数据 for _, dv := range data.ParamData { value = dv[name] } itemData = append(itemData, &[]any{v["display"], value}) } } if sd.ParamType == "array" { rowTitle := []any{} // 行头 rowData := make([][]any, len(data.ParamData)) // 行数据 for _, v := range sd.ParamData { rowTitle = append(rowTitle, v["display"]) name := v["name"].(string) // 取到对应数据 for i, dv := range data.ParamData { rowData[i] = append(rowData[i], dv[name]) } } itemData = append(itemData, &rowTitle) for _, v := range rowData { item := v itemData = append(itemData, &item) } } for i, row := range itemData { // 行头样式 if i == 0 { f.SetCellStyle(sheetName, fmt.Sprintf("A%d", sheetRows), fmt.Sprintf("A%d", sheetRows), styleRow) } f.SetSheetRow(sheetName, fmt.Sprintf("A%d", sheetRows), row) // 存在array子层时转字符串 for i, s := range *row { if reflect.ValueOf(s).Kind() == reflect.Slice { if cell, err := excelize.CoordinatesToCellName(i+1, sheetRows); err == nil { b, _ := json.Marshal(s) f.SetCellDefault(sheetName, cell, "#") f.SetCellStyle(sheetName, cell, cell, styleMore) f.AddComment(sheetName, excelize.Comment{ Cell: cell, Author: "OMC", Text: string(b), }) } } } sheetRows += 1 } // 记下次写入的行数 sheetRows += 2 sheetNameRows[sheetName] = sheetRows } // 默认工作表 f.SetCellValue("Sheet1", "A1", cellData[0].CreateBy) f.MergeCell("Sheet1", "A1", "B1") f.SetCellStyle("Sheet1", "A1", "B1", styleType) f.SetCellValue("Sheet1", "A2", "5GC") f.SetCellStyle("Sheet1", "A2", "A2", styleRow) sheetNameData := []any{} for k := range sheetNameRows { sheetNameData = append(sheetNameData, k) } f.SetSheetRow("Sheet1", "A3", &sheetNameData) // 上传资源路径 filePath := file.ParseUploadFileDir(uploadsubpath.EXPORT) saveFilePath := filepath.ToSlash(filepath.Join(filePath, fileName)) // 创建文件目录 if err := os.MkdirAll(filepath.Dir(saveFilePath), 0775); err != nil { return "", fmt.Errorf("failed to create save file %v", err) } // 根据指定路径保存文件 if err := f.SaveAs(saveFilePath); err != nil { return "", fmt.Errorf("failed to save worksheet %v", err) } return saveFilePath, nil }