export.go 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. package excels
  2. import (
  3. "github.com/druidcaesa/gotool"
  4. "github.com/xuri/excelize/v2"
  5. "reflect"
  6. "strconv"
  7. )
  8. // 获取title头list
  9. func getTitle(list []map[string]string) []string {
  10. titleList := make([]string, 0)
  11. for _, item := range list {
  12. for _, s := range item {
  13. titleList = append(titleList, s)
  14. }
  15. }
  16. return titleList
  17. }
  18. // ExportExcel 导出excel
  19. func ExportExcel(list []interface{}, title string) (error, *excelize.File) {
  20. //获取标题
  21. headerList, expList := ExcelCreate(list[0])
  22. headers := getTitle(headerList)
  23. // 默认存在第一个工作簿是 Sheet1 首字母要大写,否则会报错。
  24. // 如果想额外的创建工作簿,可以使用,sheet2 := file.NewSheet("Sheet2"),工作簿的名称不区分大小写。
  25. // 如果有多个工作簿,可以使用 file.SetActiveSheet(index) 来指定打开文件时focus到哪个工作簿
  26. sheet1 := "Sheet1"
  27. files := excelize.NewFile()
  28. character := string(65 + len(headers) - 1)
  29. /* -------------------- 第一行大标题 -------------------- */
  30. // 设置行高
  31. err := files.SetRowHeight(sheet1, 1, 25)
  32. if err != nil {
  33. return err, nil
  34. }
  35. // 合并单元格
  36. err = files.MergeCell(sheet1, "A1", character+"1")
  37. if err != nil {
  38. return err, nil
  39. }
  40. // 设置单元格样式:对齐;字体,大小;单元格边框
  41. styleTitle, _ := files.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},"font":{"bold":true,"italic":false,"family":"Calibri","size":16,"color":"#000000"},"border":[{"type":"left","color":"#3FAD08","style":0},{"type":"top","color":"#3FAD08","style":0},{"type":"bottom","color":"#3FAD08","style":2},{"type":"right","color":"#3FAD08","style":0}]}`)
  42. err = files.SetCellStyle(sheet1, "A1", character+"1", styleTitle)
  43. if err != nil {
  44. return err, nil
  45. }
  46. err = files.SetCellValue(sheet1, "A1", title)
  47. if err != nil {
  48. return err, nil
  49. }
  50. /* -------------------- 字段标题 -------------------- */
  51. styleHeader, _ := files.NewStyle(`{"alignment":{"horizontal":"center","vertical":"center"},"font":{"bold":false,"italic":false,"family":"Calibri","size":10,"color":"#000000"}}`)
  52. err = files.SetCellStyle(sheet1, "A2", character+"2", styleHeader)
  53. if err != nil {
  54. return err, nil
  55. }
  56. for k, v := range headers {
  57. if k < 26 {
  58. err = files.SetCellValue(sheet1, string(65+k)+"2", v)
  59. } else {
  60. err = files.SetCellValue(sheet1, "A"+string(65+k-26)+"2", v)
  61. }
  62. if err != nil {
  63. return err, nil
  64. }
  65. }
  66. // 设置最后一列宽度
  67. err = files.SetColWidth(sheet1, "C", character, 20)
  68. if err != nil {
  69. return err, nil
  70. }
  71. // 冻结窗口:冻结第一行和第二行
  72. err = files.SetPanes(sheet1, `{"freeze":true,"split":false,"x_split":0,"y_split":2}`)
  73. if err != nil {
  74. return err, nil
  75. }
  76. ///* -------------------- 填充行数据 -------------------- */
  77. line := 3
  78. for _, v := range list {
  79. var num = 0
  80. lineChr := strconv.Itoa(line)
  81. // 设置样式
  82. err = files.SetCellStyle(sheet1, "A"+lineChr, character+lineChr, styleHeader)
  83. if err != nil {
  84. return err, nil
  85. }
  86. // 反射获取数据和类型
  87. getValue := reflect.ValueOf(v)
  88. getType := reflect.TypeOf(v)
  89. n := getValue.NumField()
  90. for i := 0; i < n; i++ {
  91. val := getValue.Field(i)
  92. name := getType.Field(i).Name
  93. if !getIsTitle(name, headerList) {
  94. continue
  95. }
  96. if num < 26 {
  97. err = files.SetCellValue(sheet1, string(65+num)+lineChr, getExp(name, expList, val.Interface()))
  98. } else {
  99. err = files.SetCellValue(sheet1, "A"+string(65-26+num)+lineChr, getExp(name, expList, val.Interface()))
  100. }
  101. /* err = files.SetCellValue(sheet1, string(65+num)+lineChr, getExp(name, expList, val.Interface()))*/
  102. if err != nil {
  103. return err, nil
  104. }
  105. num++
  106. }
  107. line++
  108. }
  109. return nil, files
  110. }
  111. func getIsTitle(name string, headerList []map[string]string) bool {
  112. flag := false
  113. for _, m := range headerList {
  114. if gotool.StrUtils.HasNotEmpty(m[name]) {
  115. flag = true
  116. }
  117. }
  118. return flag
  119. }
  120. func getExp(name string, expList []map[string][]map[string]string, value interface{}) interface{} {
  121. for _, m := range expList {
  122. if len(m[name]) > 0 {
  123. maps := m[name]
  124. for _, m2 := range maps {
  125. if gotool.StrUtils.HasNotEmpty(m2[interfaceToString(value)]) {
  126. value = m2[interfaceToString(value)]
  127. }
  128. }
  129. }
  130. }
  131. return value
  132. }
  133. func interfaceToString(inter interface{}) string {
  134. switch inter.(type) {
  135. case string:
  136. return inter.(string)
  137. case int:
  138. return strconv.Itoa(inter.(int))
  139. case int64:
  140. return strconv.FormatInt(inter.(int64), 10)
  141. default:
  142. return inter.(string)
  143. }
  144. }