package main
import (
"fmt"
"github.com/xuri/excelize/v2"
"strconv"
)
func main() {
// 保存
meta := map[string]interface{}{
"title": []map[string]string{
{"field": "sn", "value": "订单编号", "width": "15"},
{"field": "name", "value": "收件人", "width": "9"},
{"field": "tel", "value": "联系电话", "width": "15"},
{"field": "goods_name", "value": "商品名称", "width": "15"},
{"field": "goods_number", "value": "数量", "width": "9"},
},
"col_merge": []map[string]interface{}{
{"field": "sn", "children": []string{"name", "tel"}},
},
}
data := []map[string]interface{}{
{"sn": "10000", "name": "小张", "tel": "13880808080", "goods_name": "商品A", "goods_number": "1份"},
{"sn": "10000", "name": "小张", "tel": "13880808080", "goods_name": "商品B", "goods_number": "1份"},
{"sn": "10000", "name": "小张", "tel": "13880808080", "goods_name": "商品C", "goods_number": "1份"},
{"sn": "10000", "name": "小张", "tel": "13880808080", "goods_name": "商品D", "goods_number": "1份"},
{"sn": "10001", "name": "小李", "tel": "13880808081", "goods_name": "商品A", "goods_number": "1份"},
{"sn": "10002", "name": "小王", "tel": "13880808082", "goods_name": "商品A", "goods_number": "1份"},
{"sn": "10002", "name": "小王", "tel": "1388080808X", "goods_name": "商品B", "goods_number": "1份"},
{"sn": "10003", "name": "小赵", "tel": "13880808083", "goods_name": "商品A", "goods_number": "1份"},
{"sn": "10003", "name": "小赵", "tel": "13880808083", "goods_name": "商品B", "goods_number": "1份"},
{"sn": "10004", "name": "小周", "tel": "13880808084", "goods_name": "商品A", "goods_number": "1份"},
}
_ = SaveExcel(meta, data, "订单.xlsx")
// 读取
dataExcel, _ := ReadExcel("./订单.xlsx", []string{"sn", "name", "tel", "goods_name", "goods_number"})
fmt.Println(dataExcel)
}
// 数字转Excel列编号
func stringFromColumnIndex(pColumnIndex int) string {
var index string
if pColumnIndex < 26 {
index = fmt.Sprintf("%c", 65+pColumnIndex)
} else if pColumnIndex < 702 {
index = fmt.Sprintf("%c%c", 64+(pColumnIndex/26), 65+pColumnIndex%26)
} else {
index = fmt.Sprintf("%c%c%c", 64+((pColumnIndex-26)/676), 65+(((pColumnIndex-26)%676)/26), 65+pColumnIndex%26)
}
return index
}
// 保存Excel
func SaveExcel(meta map[string]interface{}, data []map[string]interface{}, name string) error {
// 准备数据
// 表头、列合并、字段关联列序号、数据长度
title, _ := meta["title"].([]map[string]string)
colMerge, _ := meta["col_merge"].([]map[string]interface{})
fieldColumnIndex := map[string]string{}
dataLen := len(data)
// 创建工作簿
newFile := excelize.NewFile()
// 创建工作表
index := newFile.NewSheet("Sheet1")
// 处理数据
for key, value := range title {
// 索引转列序号
columnIndex := stringFromColumnIndex(key)
// 字段关联列序号
fieldColumnIndex[value["field"]] = columnIndex
// 设置列宽度
i, _ := strconv.ParseFloat(value["width"], 64)
_ = newFile.SetColWidth("Sheet1", columnIndex, columnIndex, i)
// 设置表头
_ = newFile.SetCellValue("Sheet1", fmt.Sprintf("%s1", columnIndex), value["value"])
// 填充数据
for keyRow, valueRow := range data {
_ = newFile.SetCellValue("Sheet1", fmt.Sprintf("%s%d", columnIndex, 2+keyRow), valueRow[value["field"]])
}
}
// 处理列合并
for _, value := range colMerge {
// 拿到列序号
column, ok := fieldColumnIndex[value["field"].(string)]
if !ok {
continue
}
// 根据主列需要处理的子列
children, ok := value["children"].([]string)
// 处理主列
// 块数据标记起始、结束行、上一行内容
startLine := 2
endLine := 2
upLineValue := ""
// 表头占一行,所以起始行为2
for i := 2; i < dataLen+2; i++ {
// 单元格内容
cellValue, _ := newFile.GetCellValue("Sheet1", fmt.Sprintf("%s%d", column, i))
// 起始行仅存储单元格内容
if i == 2 {
upLineValue = cellValue
} else {
// 当前行和上一行内容一致时,把块数据结束行移动到当前行
if upLineValue == cellValue {
endLine = i
}
// 当前行和上一行内容不一致 或者 是最后一行 时,需要对内容判断合并
if upLineValue != cellValue || i == dataLen+1 {
// 如果起始行和结束行标记是一样的,说明之前的内容不是一样的,重新定义标记块数据从当前行开始
// 否则开始行和结束行不一样,说明数据块是一样的,需要做合并处理
if startLine == endLine {
startLine = i
endLine = i
upLineValue = cellValue
} else {
// 合并主字列
_ = newFile.MergeCell("Sheet1",
fmt.Sprintf("%s%d", column, startLine),
fmt.Sprintf("%s%d", column, endLine),
)
// 处理子列
// 处理子列逻辑和处理主列一样,就不在赘述
for _, valueSlave := range children {
columnSlave, ok := fieldColumnIndex[valueSlave]
if !ok {
continue
}
startLineSlave := startLine
endLineSlave := startLine
upLineValueSlave := ""
for j := startLine; j <= endLine; j++ {
cellValueSlave, _ := newFile.GetCellValue("Sheet1", fmt.Sprintf("%s%d", columnSlave, i))
if j == startLine {
upLineValueSlave = cellValueSlave
} else {
if upLineValueSlave == cellValueSlave {
endLineSlave = j
}
if upLineValueSlave != cellValueSlave || j == endLine {
if startLineSlave == endLineSlave {
startLineSlave = j
endLineSlave = j
upLineValueSlave = cellValueSlave
} else {
_ = newFile.MergeCell("Sheet1",
fmt.Sprintf("%s%d", columnSlave, startLineSlave),
fmt.Sprintf("%s%d", columnSlave, endLineSlave),
)
}
}
}
}
}
startLine = i
endLine = i
upLineValue = cellValue
}
}
}
}
}
// 设置工作簿的默认工作表
newFile.SetActiveSheet(index)
// 保存方式
return newFile.SaveAs(name)
}
// 读取Excel
func ReadExcel(filename string, title []string) ([]map[string]interface{}, error) {
// 打开文件
newFile, err := excelize.OpenFile(filename)
if err != nil {
return nil, err
}
defer newFile.Close()
// 获取Sheet1工作表所有行
rows, err := newFile.GetRows("Sheet1")
if err != nil {
return nil, err
}
// 读取所有数据
data := []map[string]interface{}{}
titleLen := len(title)
for key, row := range rows {
// 剔除表头
if key == 0 {
continue
}
rowData := map[string]interface{}{}
for colKey, colCell := range row {
if !(colKey < titleLen) {
break
}
rowData[title[colKey]] = colCell
}
data = append(data, rowData)
}
return data, nil
}