diff --git a/src/modules/practical_training/controller/pt_ne_config_data.go b/src/modules/practical_training/controller/pt_ne_config_data.go index 96d6b72e..11f0ecb1 100644 --- a/src/modules/practical_training/controller/pt_ne_config_data.go +++ b/src/modules/practical_training/controller/pt_ne_config_data.go @@ -2,7 +2,9 @@ package controller import ( "encoding/json" + "fmt" "strings" + "time" "be.ems/src/framework/i18n" "be.ems/src/framework/utils/ctx" @@ -147,6 +149,42 @@ func (s *PtNeConfigDataController) Contrast(c *gin.Context) { c.JSON(200, result.Err(nil)) } +// 配置数据导出Excel +// +// GET /export +func (s *PtNeConfigDataController) Export(c *gin.Context) { + language := ctx.AcceptLanguage(c) + var querys struct { + Student string `form:"student"` // 教师携带学生账号查询 + } + if err := c.ShouldBindQuery(&querys); err != nil { + c.JSON(400, result.CodeMsg(400, i18n.TKey(language, "app.common.err400"))) + return + } + + loginUser, _ := ctx.LoginUser(c) + currentUserName := loginUser.User.UserName + for _, v := range loginUser.User.Roles { + // if v.RoleKey == "admin" {} + if v.RoleKey == "teacher" { + // 查看学生数据 + if querys.Student != "" { + currentUserName = querys.Student + } + } + // if v.RoleKey == "student" {} + } + + fileName := fmt.Sprintf("%s_config_data_%d.xlsx", currentUserName, time.Now().Unix()) + filePath, err := s.ptNeConfigDataService.ExportToExcel(currentUserName, fileName) + + if err != nil { + c.JSON(200, result.ErrMsg(fmt.Sprintf("exprot err: %s", err.Error()))) + return + } + c.FileAttachment(filePath, fileName) +} + // 网元参数配置信息 // // GET / diff --git a/src/modules/practical_training/practical_training.go b/src/modules/practical_training/practical_training.go index 2ec08d8d..8ed40b05 100644 --- a/src/modules/practical_training/practical_training.go +++ b/src/modules/practical_training/practical_training.go @@ -32,6 +32,11 @@ func Setup(router *gin.Engine) { middleware.PreAuthorize(nil), controller.NewPtNeConfigData.Contrast, ) + neConfigDataGroup.GET("/export", + middleware.PreAuthorize(nil), + collectlogs.OperateLog(collectlogs.OptionNew("log.operate.title.neConfigData", collectlogs.BUSINESS_TYPE_EXPORT)), + controller.NewPtNeConfigData.Export, + ) neConfigDataGroup.GET("", middleware.PreAuthorize(nil), controller.NewPtNeConfigData.Info, diff --git a/src/modules/practical_training/service/pt_ne_config_data.go b/src/modules/practical_training/service/pt_ne_config_data.go index f3505245..b8aad0a9 100644 --- a/src/modules/practical_training/service/pt_ne_config_data.go +++ b/src/modules/practical_training/service/pt_ne_config_data.go @@ -36,4 +36,7 @@ type IPtNeConfigDataService interface { // ApplyToNe 参数应用到网元 ApplyToNe(paramUser, neType string) error + + // ExportToExcel 导出网元的全部配置项数据 + ExportToExcel(operaUserName, fileName string) (string, error) } diff --git a/src/modules/practical_training/service/pt_ne_config_data.impl.go b/src/modules/practical_training/service/pt_ne_config_data.impl.go index 049aac2a..a6b9bc66 100644 --- a/src/modules/practical_training/service/pt_ne_config_data.impl.go +++ b/src/modules/practical_training/service/pt_ne_config_data.impl.go @@ -3,14 +3,19 @@ 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 实例化服务层 @@ -302,3 +307,155 @@ func (r *PtNeConfigDataService) ApplyToNe(paramUser, neType string) error { 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 +}