package excel import ( "archive/zip" "encoding/xml" "fmt" uuid "github.com/satori/go.uuid" "io" "io/fs" "io/ioutil" "net/url" "os" "path" "path/filepath" "regexp" "strconv" "strings" "time" ) var MonthMap = make(map[string]string) type DefineTimeFormat struct { //常规时间格式(日期带横杠) Normal_YMDhms string Normal_YMD string Normal_hms string //带斜杠的时间格式 Slash_YMDhms string Slash_YMD string //无间隔符 NoSpacer_YMDhms string NoSpacer_YMD string } var TimeFormat DefineTimeFormat var Loc *time.Location type Relationships struct { XMLName xml.Name `xml:"Relationships"` Text string `xml:",chardata"` Xmlns string `xml:"xmlns,attr"` Relationship []Relationship } type Relationship struct { Text string `xml:",chardata"` ID string `xml:"Id,attr"` Type string `xml:"Type,attr"` Target string `xml:"Target,attr"` } var xmlImageDocumentRel string = "/word/_rels/document.xml.rels" var xmlSuffix string = `` var xmlDocument string = "/word/document.xml" var imagePath string = "/word/media" var zipPath1 string = "/_rels" var zipPath2 string = "/customXml" var zipPath3 string = "/docProps" var zipPath4 string = "/word" var zipPath5 string = "/[Content_Types].xml" var deleteXmlDocument string = "/word/numbering.xml" // 将文字渲染进docx中{{image}} // // 将图片渲染进docx中{{image}} // // 渲染for循环 // var srcPath string = "./report/template2/report.docx" // var desPath string = "./report/report.docx" // mapImage := make(map[string][]string, 0) 宽高单位为px // mapImage["name"] = append(mapImage["name"], "./uploads/1.jpg?width=100&height=100") // mapImage["reasons"] = append(mapImage["reasons"], "./uploads/2.jpg?width=100&height=100") // mapImage["reasons"] = append(mapImage["reasons"], "./uploads/3.jpg?width=100&height=100") func JinJa2(srcPath string, desPath string, repl map[string]string, mapImage map[string][]string, mapListData map[string][]map[string]string) (err error) { // 渲染图片 CopyFile(srcPath, desPath) zipPath := strings.Replace(desPath, ".docx", ".zip", 1) dirPath := strings.Replace(desPath, ".docx", "", 1) // 重命名为zip CopyFile(desPath, zipPath) // 解压 Unzip(zipPath, dirPath) os.Remove(zipPath) //删除 DeleteXmlDocument(dirPath + deleteXmlDocument) // 修改xml文件 UpdateXml(dirPath, repl, mapImage, mapListData) // 压缩为zip _, err = os.Stat(dirPath + zipPath2) if err == nil { Zip(zipPath, dirPath+zipPath1, dirPath+zipPath2, dirPath+zipPath3, dirPath+zipPath4, dirPath+zipPath5) } else { Zip(zipPath, dirPath+zipPath1, dirPath+zipPath3, dirPath+zipPath4, dirPath+zipPath5) } // 重命名为docx CopyFile(zipPath, desPath) os.RemoveAll(dirPath) os.Remove(zipPath) return nil } func CopyFile(src string, dst string) (err error) { content, err := ioutil.ReadFile(src) if err != nil { fmt.Println(err) } ioutil.WriteFile(dst, content, os.ModePerm) return nil } func Unzip(zipPath, dstDir string) error { // open zip file reader, err := zip.OpenReader(zipPath) if err != nil { return err } defer reader.Close() for _, file := range reader.File { if err := unzipFile(file, dstDir); err != nil { return err } } return nil } func unzipFile(file *zip.File, dstDir string) error { filePath := path.Join(dstDir, file.Name) if file.FileInfo().IsDir() { if err := os.MkdirAll(filePath, os.ModePerm); err != nil { return err } return nil } if err := os.MkdirAll(filepath.Dir(filePath), os.ModePerm); err != nil { return err } rc, err := file.Open() if err != nil { return err } defer rc.Close() w, err := os.Create(filePath) if err != nil { return err } defer w.Close() _, err = io.Copy(w, rc) return err } func Zip(zipPath string, paths ...string) error { if err := os.MkdirAll(filepath.Dir(zipPath), os.ModePerm); err != nil { return err } archive, err := os.Create(zipPath) if err != nil { return err } defer archive.Close() zipWriter := zip.NewWriter(archive) defer zipWriter.Close() for _, srcPath := range paths { srcPath = strings.TrimSuffix(srcPath, string(os.PathSeparator)) err = filepath.Walk(srcPath, func(path string, info fs.FileInfo, err error) error { if err != nil { return err } header, err := zip.FileInfoHeader(info) if err != nil { return err } header.Method = zip.Deflate header.Name, err = filepath.Rel(filepath.Dir(srcPath), path) if err != nil { return err } if info.IsDir() { header.Name += string(os.PathSeparator) } headerWriter, err := zipWriter.CreateHeader(header) if err != nil { return err } if info.IsDir() { return nil } f, err := os.Open(path) if err != nil { return err } defer f.Close() _, err = io.Copy(headerWriter, f) return err }) if err != nil { return err } } return nil } func GetPicTag(ids []string, names []string) (picTags string) { for seq, v := range ids { cx := 629285 cy := 368300 vvalue := strings.Replace(v, "rId", "", 1) nameParams := strings.Split(names[seq], "?") var picTag string = ` ` uuid, _ := uuid.NewV4() vuuid := uuid.String() picTag = strings.Replace(picTag, ``, fmt.Sprintf(``, fmt.Sprintf("%v%v", vvalue, vuuid), nameParams[0], nameParams[0]), 1) picTag = strings.Replace(picTag, ``, fmt.Sprintf(``, fmt.Sprintf("%v%v", vvalue, vuuid), nameParams[0], nameParams[0]), 1) picTag = strings.Replace(picTag, ``, fmt.Sprintf(``, v), 1) if len(nameParams) > 1 { u, _ := url.Parse(nameParams[1]) m, _ := url.ParseQuery(u.Path) cx, _ = strconv.Atoi(m["width"][0]) cy, _ = strconv.Atoi(m["height"][0]) cx = cx * 9525 cy = cy * 9525 picTag = strings.Replace(picTag, ``, fmt.Sprintf(``, cx, cy), 1) picTag = strings.Replace(picTag, ``, fmt.Sprintf(``, cx, cy), 1) } picTags = picTags + picTag } return } func UpdateRelXml(path string, content string) { os.Remove(path) xmlfile1, _ := os.Create(path) defer xmlfile1.Close() xmlfile1.WriteString(content) } func UpdateDocumentXml(path string, content string) { os.Remove(path) xmlfile2, _ := os.Create(path) //打开文件 defer xmlfile2.Close() xmlfile2.WriteString(content) } func UpdateXml(dirPath string, repl map[string]string, mapImage map[string][]string, mapListData map[string][]map[string]string) { xmlDoc, err := ioutil.ReadFile(dirPath + xmlDocument) if err != nil { fmt.Println(err) } xmlDocContent := string(xmlDoc) if len(repl) > 0 { for k, v := range repl { v = strings.ReplaceAll(v, "\r\n", "") v = strings.ReplaceAll(v, "\n", "") v = strings.ReplaceAll(v, "\r", "") xmlDocContent = strings.ReplaceAll(xmlDocContent, fmt.Sprintf("{{%v}}", k), fmt.Sprintf("%v", v)) } } if len(mapImage) > 0 { // 修改rel文件 xmlRel, err := ioutil.ReadFile(dirPath + xmlImageDocumentRel) list := Relationships{} xml.Unmarshal([]byte(xmlRel), &list) for k1, v1 := range mapImage { list_rId := []string{} list_rName := []string{} for _, v2 := range v1 { // 将图片移动到docx中 lf := strings.Split(v2, "/") lfParms := strings.Split(lf[len(lf)-1], "?") v2s := strings.Split(v2, "?") CopyFile(v2s[0], dirPath+imagePath+"/"+lfParms[0]) rId := fmt.Sprintf("rId%v", len(list.Relationship)+1) list.Relationship = append(list.Relationship, Relationship{ ID: rId, Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", Target: fmt.Sprintf("media/%v", lfParms[0]), }) list_rId = append(list_rId, rId) list_rName = append(list_rName, lf[len(lf)-1]) } xmlDocContent = strings.ReplaceAll(xmlDocContent, fmt.Sprintf("{{%v}}", k1), GetPicTag(list_rId, list_rName)) } xmlContent, err := xml.Marshal(list) if err != nil { fmt.Println(err) } UpdateRelXml(dirPath+xmlImageDocumentRel, xmlSuffix+string(xmlContent)) } if len(mapListData) > 0 { xmlDocContent = RenderForTag(mapListData, xmlDocContent) } UpdateDocumentXml(dirPath+xmlDocument, xmlDocContent) } func RenderForTag(mapFor map[string][]map[string]string, xmlDocContent string) string { compileIndex2 := regexp.MustCompile(fmt.Sprintf(`{%%endfor%%}`)).FindAllStringIndex(xmlDocContent, -1) compileIndex3 := regexp.MustCompile(fmt.Sprintf("")).FindAllStringIndex(xmlDocContent, -1) compileIndex4 := regexp.MustCompile(fmt.Sprintf("")).FindAllStringIndex(xmlDocContent, -1) fmt.Println(compileIndex3, compileIndex4) contentList := []string{} contentReplaceList := []string{} for k, v := range mapFor { compileIndex := regexp.MustCompile(fmt.Sprintf(`{%%for v in %v%%}`, k)).FindAllStringIndex(xmlDocContent, -1) compileIndex2Copy := [][]int{} for _, vc2 := range compileIndex2 { if vc2[0] > compileIndex[0][1] { compileIndex2Copy = append(compileIndex2Copy, vc2) break } } if len(compileIndex3) > 0 && len(compileIndex4) > 0 { startIndex := compileIndex3[0][0] endIndex := compileIndex4[0][0] start2Index := compileIndex3[0][0] end2Index := compileIndex4[0][0] for _, v2 := range compileIndex { for s21, v21 := range compileIndex3 { if v21[0] > v2[0] && s21 > 0 { startIndex = compileIndex3[s21-1][0] start2Index = compileIndex3[s21][0] break } } for s22, v22 := range compileIndex4 { if v22[0] > compileIndex2Copy[0][0] && s22 > 0 { endIndex = compileIndex4[s22][1] end2Index = compileIndex4[s22-1][1] break } } tableContent := xmlDocContent[startIndex:endIndex] // fmt.Println(tableContent) // fmt.Println(table2Content) table2ReplaceContent := "" contentList = append(contentList, tableContent) for _, v22 := range v { table2Content := xmlDocContent[start2Index:end2Index] for k221, v221 := range v22 { table2Content = strings.ReplaceAll(table2Content, fmt.Sprintf("{{v.%v}}", k221), v221) } table2ReplaceContent = table2ReplaceContent + table2Content } fmt.Println(table2ReplaceContent) contentReplaceList = append(contentReplaceList, table2ReplaceContent) } } } for seq, _ := range contentList { xmlDocContent = strings.Replace(xmlDocContent, contentList[seq], contentReplaceList[seq], 1) } return xmlDocContent } func Decimal(value float64) float64 { value, _ = strconv.ParseFloat(fmt.Sprintf("%.2f", value), 64) return value } // Find 判断字符串是否存在数组或切片 func Find(slice []string, val string) (int, bool) { for i, item := range slice { if item == val { return i, true } } return -1, false } func StringTimeToFormat(str_time string) (str_time2 string) { lista := strings.Split(str_time, "T") listb := strings.Split(lista[1], ".") str_time2 = lista[0] + " " + listb[0] return } func DeleteXmlDocument(destDocument string) error { _, err := os.Stat(destDocument) if os.IsNotExist(err) { return nil } else { os.Remove(destDocument) } return nil }