package ExcelUtil import ( "dsBaseRpc/Const" "dsBaseRpc/Utils/CommonUtil" "dsBaseRpc/Utils/DbUtil" "dsBaseRpc/Utils/FileUtil" "encoding/json" "fmt" "github.com/xuri/excelize/v2" "strconv" "strings" ) //中文文档: xuri.me/excelize/zh-hans type ColStruct struct { ColName string `json:"col_name"` ColField string `json:"col_field"` Width float64 `json:"width"` Require bool `json:"require"` Level1Sql bool `json:"level_1_sql"` Level2Sql bool `json:"level_2_sql"` SqlNum int64 `json:"sql_num"` SqlParameter []interface{} `json:"sql_parameter"` } type TemplateStruct struct { Title string `json:"title"` Level1Sql []string `json:"level_1_sql"` Level2Sql [][]string `json:"level_2_sql"` Cols []ColStruct `json:"cols"` } var db = DbUtil.Engine //样式文件的前缀路径 var stylePathPrefix = "./Config/ExcelStyle/" /** 功能:设置指定EXCEL SHEET的某个单元格的背景色为红色 作者:黄海 时间:2020-06-08 */ func GetBackgroundColorStyle(hexColor string) string { tableStyleWarningPath := stylePathPrefix + "tableStyleTemplate.json" if !FileUtil.PathExists(tableStyleWarningPath) { tableStyleWarningPath = "." + tableStyleWarningPath } content := FileUtil.ReadFileContent(tableStyleWarningPath) content = strings.Replace(content, "\r\n", "", -1) styleTemplate := strings.Replace(content, "#color#", hexColor, -1) return styleTemplate } //导出标识 const ExportFlag = 1 //导入标识 const ImportFlag = 2 /** 功能:判断是不是合法的导入模板 作者:黄海 时间:2020-06-17 */ func IsValidTemplate(excelPath string, s1 TemplateStruct) bool { f, _ := excelize.OpenFile(excelPath) //如果 sheet名称不正确 if f.GetSheetName(0) != s1.Title { return false } var isValidTemplate = true for i := range s1.Cols { colName, _ := excelize.ColumnNumberToName(i + 1) v, _ := f.GetCellValue(s1.Title, colName+CommonUtil.ConvertIntToString(HiddenRows+1)) if s1.Cols[i].Require { if v != s1.Cols[i].ColName+"[*]" { isValidTemplate = false break } } else { if v != s1.Cols[i].ColName { isValidTemplate = false break } } } return isValidTemplate } /** 功能:读取配置JSON 作者:黄海 时间:2020-06-17 */ func ReadJson(jsonTemplate string, ExportOrImport int) TemplateStruct { if ExportOrImport == 1 { jsonTemplate = "./Config/ExportExcelTemplate/" + jsonTemplate } else { jsonTemplate = "./Config/ImportExcelTemplate/" + jsonTemplate } if !FileUtil.PathExists(jsonTemplate) { jsonTemplate = "." + jsonTemplate } var jsonContent = FileUtil.ReadFileContent(jsonTemplate) jsonContent = strings.Replace(jsonContent, "\r\n", "", -1) var s1 TemplateStruct json.Unmarshal([]byte(jsonContent), &s1) return s1 } /** 功能:通过JSON模板定义导出EXCEL 作者:黄海 时间:2020-06-05 */ func ExportExcel(jsonTemplate string, listData []map[string]interface{}, targetPath string) { var s1 = ReadJson(jsonTemplate, ExportFlag) rows := len(listData) //行数 cols := len(s1.Cols) //列数 //初始化excel f := excelize.NewFile() titleStylePath := stylePathPrefix + "titleStyle.json" tableStylePath := stylePathPrefix + "tableStyleNormal.json" if !FileUtil.PathExists(titleStylePath) { titleStylePath = "." + titleStylePath } if !FileUtil.PathExists(tableStylePath) { tableStylePath = "." + tableStylePath } titleStyle, _ := f.NewStyle(FileUtil.ReadFileContent(titleStylePath)) tableStyle, _ := f.NewStyle(FileUtil.ReadFileContent(tableStylePath)) var oldName = "Sheet1" var SheetName = s1.Title var RowHeight = 28.0 f.SetSheetName(oldName, SheetName) //设置标题行行高 f.SetRowHeight(SheetName, 1, RowHeight) //合并单元格(标题行) lastCol, _ := excelize.ColumnNumberToName(cols) f.MergeCell(SheetName, "A1", lastCol+"1") // 设置单元格的值(标题) f.SetCellValue(SheetName, "A1", s1.Title) //测试设置单元格背景颜色 //设置字体(标题) f.SetCellStyle(SheetName, "A1", "A1", titleStyle) //设置列宽 for i := 0; i < cols; i++ { m, _ := excelize.ColumnNumberToName(i + 1) f.SetColWidth(SheetName, m, m, s1.Cols[i].Width) } //设置边框 for i := 2; i <= rows+2; i++ { for j := 0; j < cols; j++ { cName, _ := excelize.ColumnNumberToName(j + 1) cName = cName + strconv.Itoa(i) f.SetCellStyle(SheetName, cName, cName, tableStyle) f.SetRowHeight(SheetName, i, RowHeight) } } //写入标题头 for i := 0; i < cols; i++ { cName, _ := excelize.ColumnNumberToName(i + 1) cName = cName + strconv.Itoa(2) f.SetCellValue(SheetName, cName, s1.Cols[i].ColName) } //写入内容 for i := 0; i < rows; i++ { for j := 0; j < cols; j++ { cName, _ := excelize.ColumnNumberToName(j + 1) cName = cName + strconv.Itoa(i+1+2) fieldName := s1.Cols[j].ColField if fieldName == "number" { f.SetCellValue(SheetName, cName, CommonUtil.ConvertIntToString(i+1)) } else { f.SetCellValue(SheetName, cName, listData[i][fieldName]) } } } // 根据指定路径保存文件 if err := f.SaveAs(targetPath); err != nil { println(err.Error()) } } //5000个 const RowsCount = 5000 //隐藏用来装字典的行数 const HiddenRows = 200 /** 功能:通用的导入模板函数 作者:黄海 时间:2020-06-06 */ func GenerateTemplate(jsonTemplate string, excelPath string) { var f *excelize.File var s1 TemplateStruct var SheetName string jsonTemplate = "./Config/ImportExcelTemplate/" + jsonTemplate if !FileUtil.PathExists(jsonTemplate) { jsonTemplate = "." + jsonTemplate } var jsonContent = FileUtil.ReadFileContent(jsonTemplate) //2、还原成结构体 json.Unmarshal([]byte(jsonContent), &s1) //3、准备根据结构体进行创建导入模板 var oldName = "Sheet1" SheetName = s1.Title f = excelize.NewFile() f.SetSheetName(oldName, SheetName) cols := len(s1.Cols) //列数 //隐藏前hiddenRows行 for i := 0; i < HiddenRows; i++ { f.SetRowVisible(SheetName, i+1, false) } //4、声明样式描述文件 titleStylePath := stylePathPrefix + "titleStyle.json" tableStylePath := stylePathPrefix + "tableStyleNormal.json" if !FileUtil.PathExists(titleStylePath) { titleStylePath = "." + titleStylePath } if !FileUtil.PathExists(tableStylePath) { tableStylePath = "." + tableStylePath } tableStyle, _ := f.NewStyle(FileUtil.ReadFileContent(tableStylePath)) //5、表头 for i := 0; i < cols; i++ { //设置列宽 cName, _ := excelize.ColumnNumberToName(i + 1) f.SetColWidth(SheetName, cName, cName, s1.Cols[i].Width) //写入文字 cName = cName + strconv.Itoa(HiddenRows+1) //第hiddenRows+1行 f.SetCellStyle(SheetName, cName, cName, tableStyle) //加上红星提醒 if s1.Cols[i].Require { f.SetCellValue(SheetName, cName, s1.Cols[i].ColName) f.SetCellRichText(SheetName, cName, []excelize.RichTextRun{ { Text: s1.Cols[i].ColName, Font: &excelize.Font{ Family: "宋体", Size: 14, }, }, { Text: "[*]", Font: &excelize.Font{ Bold: true, Color: "e83723", Family: "宋体", Size: 14, }, }, }) } else { f.SetCellValue(SheetName, cName, s1.Cols[i].ColName) } } //6、设置足够多的行是28这个高度,RowsCount行应该够用了 var RowHeight = 28.0 //表头设置行高 f.SetRowHeight(SheetName, 1, RowHeight) //设置边框 for i := HiddenRows + 1; i <= HiddenRows+RowsCount; i++ { for j := 0; j < cols; j++ { cName, _ := excelize.ColumnNumberToName(j + 1) cName = cName + strconv.Itoa(i) f.SetCellStyle(SheetName, cName, cName, tableStyle) } f.SetRowHeight(SheetName, i, RowHeight) } //白色 WhiteJson := GetBackgroundColorStyle(Const.WhiteStyle) WhiteStyle, _ := f.NewStyle(WhiteJson) f.SetCellStyle(SheetName, Const.WhiteCell, Const.WhiteCell, WhiteStyle) //红色 RedJson := GetBackgroundColorStyle(Const.RedStyle) RedStyle, _ := f.NewStyle(RedJson) f.SetCellStyle(SheetName, Const.RedCell, Const.RedCell, RedStyle) //蓝色 BlueJson := GetBackgroundColorStyle(Const.BlueStyle) BlueStyle, _ := f.NewStyle(BlueJson) f.SetCellStyle(SheetName, Const.BlueCell, Const.BlueCell, BlueStyle) //黄色 YellowJson := GetBackgroundColorStyle(Const.YellowStyle) YellowStyle, _ := f.NewStyle(YellowJson) f.SetCellStyle(SheetName, Const.YellowCell, Const.YellowCell, YellowStyle) //保存 // 根据指定路径保存文件(不管是不是通过,都保存一次) if err := f.SaveAs(excelPath); err != nil { println(err.Error()) } return } /** 功能:按SQL定义添加字典 作者:黄海 时间:2020-06-18 */ func TemplateAddDict(excelPath string, jsonTemplate string) (*excelize.File, TemplateStruct, int, string) { excelPath = "./Config/ImportExcelTemplate/" + excelPath if !FileUtil.PathExists(excelPath) { excelPath = "." + excelPath } f, _ := excelize.OpenFile(excelPath) var s1 TemplateStruct jsonTemplate = "./Config/ImportExcelTemplate/" + jsonTemplate if !FileUtil.PathExists(jsonTemplate) { jsonTemplate = "." + jsonTemplate } var jsonContent = FileUtil.ReadFileContent(jsonTemplate) //2、还原成结构体 json.Unmarshal([]byte(jsonContent), &s1) cols := len(s1.Cols) //列数 var SheetName = s1.Title //字典的列开始值 dictCols := cols + 1 //设置下拉框 for i := 0; i < cols; i++ { //如果需要设置一级下接框 if s1.Cols[i].Level1Sql { //查询值域 args := s1.Cols[i].SqlParameter list, err := db.SQL(s1.Level1Sql[s1.Cols[i].SqlNum-1], args...).Query().List() if err != nil { fmt.Println(err.Error()) } //字典列从cols+1开始 dictCName, _ := excelize.ColumnNumberToName(dictCols) dictCols++ for j := range list { f.SetCellValue(SheetName, dictCName+CommonUtil.ConvertIntToString(j+1), list[j]["dict_value"]) } //隐藏字典列 f.SetColVisible(SheetName, dictCName, false) //要设置下拉框的列 cName, _ := excelize.ColumnNumberToName(i + 1) dvRange := excelize.NewDataValidation(true) dvRange.Sqref = cName + CommonUtil.ConvertIntToString(2) + ":" + cName + CommonUtil.ConvertIntToString(RowsCount) c := "$" + dictCName + "$1:$" + dictCName + "$" + CommonUtil.ConvertIntToString(len(list)) dvRange.SetSqrefDropList(c) f.AddDataValidation(SheetName, dvRange) } } return f, s1, dictCols, SheetName }