You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

355 lines
10 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
}