package services

import (
	"baliance.com/gooxml/color"
	"baliance.com/gooxml/document"
	"baliance.com/gooxml/measurement"
	"baliance.com/gooxml/schema/soo/ofc/sharedTypes"
	"baliance.com/gooxml/schema/soo/wml"
	"bytes"
	"encoding/json"
	"errors"
	"fmt"
	wkhtml "github.com/SebastiaanKlippert/go-wkhtmltopdf"
	"github.com/shopspring/decimal"
	"hongze/hz_crm_api/models/contract"
	"hongze/hz_crm_api/models/contract/request"
	"hongze/hz_crm_api/utils"
	"html/template"
	"os"
	"os/exec"
	"path"
	"reflect"
	"strconv"
	"strings"
	"time"
)

type TableData struct {
	List []TableRow `json:"table" description:"列数据"`
}

type TableRow struct {
	RowList []TableCel `json:"row" description:"列数据"`
}

type TableCel struct {
	Value         string  `json:"value" description:"展示的数据"`
	ColumnSpan    int     `json:"column_span" description:"需要合同的列数量"`
	RowSpan       int     `json:"row_span" description:"需要合同的行数量"`
	IsMerged      bool    `json:"is_merged" description:"是否需要上下行合并"`
	IsFirstMerged bool    `json:"is_first_merged" description:"是否是第一次合并上下行"`
	Background    string  `json:"background" description:"背景色"`
	IsBold        bool    `json:"is_bold" description:"是否加粗显示"`
	TextAlign     string  `json:"text_align" description:"对齐方式"`
	FontSize      float64 `json:"font_size" description:"字体大小"`
	WidthPercent  float64 `json:"width_percent" description:"单元格宽度占整个表格的百分比"`
}

// 获取颜色配置
func getColorConf(background string) (foreground color.Color) {
	switch background {
	case "slate_gray": //石板灰
		foreground = color.SlateGray
	case "light_slate_gray": //浅石板灰
		foreground = color.LightSlateGray
	case "light_gray": //浅灰
		foreground = color.LightGray
	case "gray": //灰色
		foreground = color.Gray
	case "gray_1": //灰色_1（中浅灰）
		foreground = color.RGB(uint8(215), uint8(215), uint8(215))
	case "gray_2": //灰色_2（浅灰）
		foreground = color.RGB(uint8(241), uint8(241), uint8(241))
	case "dim_gray": //暗灰色
		foreground = color.DimGray
	case "dark_slate_gray": //深灰色
		foreground = color.DarkSlateGray

	default:
		foreground = color.LightGray
	}
	return
}

func getTextAlignConf(textAlign string) (align wml.ST_Jc) {
	switch textAlign {
	case "left": //居左
		align = wml.ST_JcLeft
	case "center": //居中
		align = wml.ST_JcCenter
	case "right": //居右
		align = wml.ST_JcRight
	case "both": //
		align = wml.ST_JcBoth
	default:
		align = wml.ST_JcLeft
	}
	return
}

// GenerateWord 生成word
func GenerateWord(contractDetail *contract.ContractDetail) (err error) {
	wordTemplatePath := getWordPath(contractDetail.TemplateId)
	if wordTemplatePath == "" {
		err = errors.New("找不到对应的合同模板")
		return
	}

	doc, err := document.Open(wordTemplatePath)
	if err != nil {
		fmt.Println("error opening document: %s", err)
		return
	}
	paragraphs := []document.Paragraph{}
	for _, p := range doc.Paragraphs() {
		paragraphs = append(paragraphs, p)
	}

	// This sample document uses structured document tags, which are not common
	// except for in document templates.  Normally you can just iterate over the
	// document's paragraphs.
	for _, sdt := range doc.StructuredDocumentTags() {
		for _, p := range sdt.Paragraphs() {
			paragraphs = append(paragraphs, p)
		}
	}
	doc.AddParagraph()
	for _, p := range paragraphs {
		for _, r := range p.Runs() {
			switch r.Text() {
			case "{{address}}":
				// ClearContent clears both text and line breaks within a run,
				// so we need to add the line break back
				r.ClearContent()
				address := getContractAddress(contractDetail)
				r.AddText(address)
				//r.AddBreak()

				//para := doc.InsertParagraphBefore(p)
				//para.AddRun().AddText("Mr.")
				//para.SetStyle("Name") // Name is a default style in this template file
				//
				//para = doc.InsertParagraphAfter(p)
				//para.AddRun().AddText("III")
				//para.SetStyle("Name")

			case "{{postcode}}":
				r.ClearContent()
				r.AddText(contractDetail.Postcode)
			case "{{phone}}":
				r.ClearContent()
				r.AddText(contractDetail.Phone)
			case "{{fax}}":
				r.ClearContent()
				r.AddText(contractDetail.Fax)
			case "{{remark}}":
				r.ClearContent()
				remark := contractDetail.Remark
				if remark == "" {
					remark = "无"
				}
				r.AddText(remark)
			case "{{start_date}}":
				r.ClearContent()
				r.AddText(contractDetail.StartDate.Format("2006 年 01 月 02 日"))
			case "{{end_date}}":
				r.ClearContent()
				r.AddText(contractDetail.EndDate.Format("2006 年 01 月 02 日"))
			case "{{num_year}}":
				r.ClearContent()
				//合同结束日期与合同开始日期的时间差（小时差）
				newDecimal := decimal.NewFromFloat(contractDetail.EndDate.Sub(contractDetail.StartDate).Hours())
				//分母为365天 * 24 小时
				newDecimal2 := decimal.NewFromInt(24 * 365)
				//计算出来相差多少年，保留一位小数（四舍五入）
				numYearDecimal := newDecimal.Div(newDecimal2).Round(1)
				//定义最小年份差，不能小于0.1年
				minDecimal := decimal.NewFromFloat(0.1)
				//如果计算出来的年份差小于0.1年，那么该年份差就赋值 0.1年
				if numYearDecimal.LessThan(minDecimal) {
					numYearDecimal = minDecimal
				}
				//cnYear, cnErr := utils.ConvertNumToCn(numYearDecimal.String())
				//if cnErr != nil {
				//	err = cnErr
				//	return
				//}
				r.AddText(numYearDecimal.String())
			case "{{price}}":
				r.ClearContent()
				priceStr := ""
				//originalPrice := strconv.FormatFloat(contractDetail.OriginalPrice, 'E', -1, 64)

				//优惠前金额（小写）
				//newDecimal := decimal.NewFromFloat(contractDetail.OriginalPrice)
				originalPrice := utils.FormatPrice(contractDetail.OriginalPrice)
				priceStr += "小写：" + originalPrice + "，"

				//优惠前金额（大写）
				originalCnyPrice, cnyErr := utils.ConvertNumToCny(contractDetail.OriginalPrice)
				if cnyErr != nil {
					err = cnyErr
					return
				}
				priceStr += "大写：" + originalCnyPrice

				//如果实际支付金额与订单原金额不符
				if contractDetail.OriginalPrice != contractDetail.Price {
					//优惠后的金额（小写）
					//newDecimal := decimal.NewFromFloat(contractDetail.Price)
					price := utils.FormatPrice(contractDetail.Price)
					priceStr += "，经甲乙双方友好协商，优惠至：" + price + "元，"

					//优惠后的金额（大写）
					cnyPrice, cnyErr := utils.ConvertNumToCny(contractDetail.Price)
					if cnyErr != nil {
						err = cnyErr
						return
					}
					priceStr += "大写：" + cnyPrice
				}

				r.AddText(priceStr)

			case "{{pay_remark}}":
				r.ClearContent()
				r.AddText(contractDetail.PayRemark)
			case "{{company_name}}":
				r.ClearContent()
				r.AddText(contractDetail.CompanyName)
				//r.AddBreak()
			case "{{services}}":
				r.ClearContent()
				//赋值当前段落
				nowParagraph := p

				for i := len(contractDetail.Service) - 1; i >= 0; i-- {
					//表格数据
					var tableDataList TableData
					//表头备注信息
					tableTitle := ""

					item := contractDetail.Service[i]
					//表格数据
					if item.HasDetail == "是" && len(item.DetailList) > 0 {
						//表格每行数据切片
						tableRowList := make([]TableRow, 0)

						//遍历获取table行数据
						for j := 0; j < len(item.DetailList); j++ {
							//列数据样式初始化
							isBold := false
							backgrandColor := ""
							fontSize := 10.0

							//表头数据样式
							if j == 0 {
								isBold = true
								backgrandColor = "gray_2"
								fontSize = 12.0
							}

							//获取每一列的数据
							tmpCellList, colErr := getColList(item.DetailList[j])
							if colErr != nil {
								err = colErr
								return
							}

							//定义生成table列数据切片
							tableCelList := make([]TableCel, 0)
							lenCell := len(tmpCellList)
							for k := 0; k < len(tmpCellList); k++ {
								//计算出来每一列的宽度占比 start
								//总宽度
								newDecimal := decimal.NewFromFloat(100)
								//总列数
								newDecimal2 := decimal.NewFromInt(int64(lenCell))
								//计算出来每一列的宽度占比（四舍五入）
								widthPercent, _ := newDecimal.Div(newDecimal2).Round(3).Float64()
								//if !ok {
								//	err = errors.New("word普通数据表格宽度百分比计算失败")
								//	return
								//}
								//计算出来每一列的宽度占比 end

								tableCel := TableCel{
									Value:     tmpCellList[k],
									TextAlign: "center",
									//ColumnSpan   int     `json:"column_span";description:"需要合同的列数量"`
									//IsMerged     bool    `json:"is_merged";description:"是否需要上下行合并"`
									Background:   backgrandColor,
									IsBold:       isBold,
									FontSize:     fontSize,
									WidthPercent: widthPercent,
								}
								tableCelList = append(tableCelList, tableCel)
							}

							//将每行数据插入到table行数据切片之中
							tableRow := TableRow{
								RowList: tableCelList,
							}
							tableRowList = append(tableRowList, tableRow)
						}
						//赋值table表格数据
						tableDataList.List = tableRowList
						tableTitle = "依照《弘则研究FICC客户服务列表2022》中 小套餐 的服务内容，详细如下："
					} else {
						//获取预设的表格数据
						contractServiceTemplate, tmpErr := contract.GetContractServiceTemplateById(item.ServiceTemplateId)
						if tmpErr != nil {
							err = tmpErr
							return
						}

						//赋值table表格数据
						jsonStr := contractServiceTemplate.TableValue
						err = json.Unmarshal([]byte(jsonStr), &tableDataList)
						if err != nil {
							return
						}
						//表头备注信息
						tableTitle = contractServiceTemplate.Remark
					}

					//往word中添加表格数据
					tmpParagraph, tmpErr := addTable(tableTitle, tableDataList, doc, nowParagraph)
					if tmpErr != nil {
						err = tmpErr
						return
					}
					//fmt.Println("nowParagraph:", nowParagraph, "tmpParagraph:", tmpParagraph)
					//fmt.Println("doc:", doc.Paragraphs())
					//fmt.Println("==========:")
					nowParagraph = tmpParagraph
				}
			default:
				//fmt.Println("not modifying", r.Text())
			}
		}
	}
	doc.SaveToFile(fmt.Sprint("./static/word/系统生成合同", contractDetail.ContractId, ".docx"))
	return
}

// 添加表格数据
func addTable(title string, tableDataList TableData, doc *document.Document, paragraph document.Paragraph) (nowParagraph document.Paragraph, err error) {
	//fmt.Println("表头名称:", title)
	//插入一个新的段落
	nowParagraph = doc.InsertParagraphBefore(paragraph)
	nowRun := nowParagraph.AddRun()
	nowRun.AddBreak()
	//if title != "" {
	//	fmt.Println("表头名称:", title)
	//	nowRun.Properties().SetSize(11)
	//	nowRun.Properties().SetBold(true)
	//	nowRun.AddText(title)
	//	nowRun.AddBreak()
	//}

	//再次插入一个新段落
	//_ = doc.InsertParagraphAfter(nowParagraph)
	//表格数据

	{
		table := doc.InsertTableAfter(nowParagraph)
		//设置表格宽度
		table.Properties().SetWidth(6.5 * measurement.Inch)
		//表格宽度设置为自动
		//table.Properties().SetWidthAuto()

		//边框
		borders := table.Properties().Borders()
		// thin borders
		borders.SetAll(wml.ST_BorderSingle, color.Auto, measurement.Zero)

		//表格数据
		rowList := tableDataList.List
		//每一列合并单元格状态map
		rowIsMeged := make(map[int]bool)

		//table.Properties().W
		for i := 0; i < len(rowList); i++ {
			//创建新的一行
			row := table.AddRow()
			//设置行高，第二个参数是设置固定值还是自动
			row.Properties().SetHeight(30*measurement.Point, wml.ST_HeightRuleAtLeast)

			//遍历列数据
			rowDataList := rowList[i].RowList
			if rowDataList != nil {
				for j := 0; j < len(rowDataList); j++ {
					//当前列是否合并
					var isMeged bool
					isMeged, ok := rowIsMeged[j]
					if !ok {
						rowIsMeged[j] = false
						isMeged = false
					}

					cell := row.AddCell()
					cellPara := cell.AddParagraph()
					run := cellPara.AddRun()
					//列数据
					cellData := rowDataList[j]

					//如果合并列大于0，那么就合并列
					if cellData.ColumnSpan > 0 {
						// column span / merged cells
						cell.Properties().SetColumnSpan(cellData.ColumnSpan)
						//_ = row.AddCell()
					}

					//如果指定了上下单元格合并，那么去合并上下单元格
					if cellData.IsMerged {
						//将当前合并单元格状态调整为true
						rowIsMeged[j] = true
						//合并单元格类型
						var mergeVal wml.ST_Merge

						if isMeged { //如果上一层已经是合并了，那么这一层是继续合并
							mergeVal = wml.ST_MergeContinue
						} else { //如果上一层不是合并，那么这一层是开始合并
							mergeVal = wml.ST_MergeRestart
						}
						cell.Properties().SetVerticalMerge(mergeVal)
					} else {
						//将当前合并单元格状态调整为false，这样后续如果再次碰到合并单元格操作，就是重新开始合并了
						rowIsMeged[j] = false
					}

					//背景色
					if cellData.Background != "" {
						cell.Properties().SetShading(wml.ST_ShdSolid, getColorConf(cellData.Background), color.Auto)
					}

					//填充内容（文字）垂直对齐方式
					cell.Properties().SetVerticalAlignment(wml.ST_VerticalJcCenter)

					//将单元格设置为宽度百分比
					if cellData.WidthPercent > 0 {
						cell.Properties().SetWidthPercent(cellData.WidthPercent)
					}

					//文字排版（居中、左、右）
					if cellData.TextAlign != "" {
						cellPara.Properties().SetAlignment(getTextAlignConf(cellData.TextAlign))
						//cellPara.Properties().SetAlignment(wml.ST_JcLeft)
					}

					//cell.Properties().SetAli
					//设置是否加粗
					run.Properties().SetBold(cellData.IsBold)

					//设置字体大小
					fontSize := 10.0
					if cellData.FontSize > 0 {
						fontSize = cellData.FontSize
					}
					run.Properties().SetSize(measurement.Distance(fontSize * measurement.Point))

					//设置段落间的间距
					cellPara.Properties().Spacing().SetLineSpacing(measurement.Distance(1.4*fontSize*measurement.Point), wml.ST_LineSpacingRuleAuto)
					//设置段前间距
					cellPara.Properties().Spacing().SetBefore(measurement.Distance(0.9 * fontSize * measurement.Point))
					//设置段后间距
					cellPara.Properties().Spacing().SetAfter(measurement.Distance(0.5 * fontSize * measurement.Point))

					//设置字体
					run.Properties().SetFontFamily("宋体")

					//设置排序
					run.Properties().SetVerticalAlignment(sharedTypes.ST_VerticalAlignRunBaseline)

					//设置显示的文字
					if cellData.Value != "" {
						strSlice := strings.Split(cellData.Value, "<br/>")
						for s := 0; s < len(strSlice); s++ {
							if s > 0 {
								run.AddBreak()
							}
							run.AddText(strSlice[s])
						}
					} else {
						run.AddText("")
					}
				}

			}
		}

	}
	return
}

// 获取生成word的docx模板文件
func getWordPath(templateId int) string {
	var path string
	switch templateId {
	case 1:
		path = "./static/word/template_1.docx"
	case 2:
		path = "./static/word/template_2.docx"
	}
	return path
}

// html转pdf数据样式
type html2pdfData struct {
	CompanyName     string `description:"甲方名称"`
	ContractCode    string `description:"合同编号"`
	Address         string `description:"甲方地址"`
	PostcodeDisplay string `description:"甲方邮编；是否展示"`
	Postcode        string `description:"甲方邮编"`
	PhoneDisplay    string `description:"甲方电话；是否展示"`
	Phone           string `description:"甲方电话"`
	FaxDisplay      string `description:"传真；是否展示"`
	Fax             string `description:"传真"`
	RemarkDisplay   string `description:"备注；是否展示"`
	Remark          string `description:"备注"`
	PayRemark       string `description:"支付备注"`
	StartDate       string `description:"合同开始日期"`
	EndDate         string `description:"合同结束日期"`
	NumYear         string `description:"合同有效期"`
	Price           string `description:"支付金额"`
	TableHtml       string `description:"表格数据"`
}

// GetHtmlByContractDetail 获取合同样式预览的html
func GetHtmlByContractDetail(contractDetail *contract.ContractDetail, htmlType string) (contractHtml string, err error) {
	tmpContractDetail := *contractDetail

	contractTemplate, err := contract.GetContractTemplateByTemplateId(tmpContractDetail.TemplateId)
	if err != nil {
		return
	}
	// 初始化合同中一些特定区域的文字展示配置
	contentConfigMap := make(map[string]string)
	err = json.Unmarshal([]byte(contractTemplate.ContentConfig), &contentConfigMap)
	if err != nil {
		return
	}
	htmlTpl := contractTemplate.Html
	if htmlType == "pdf" {
		htmlTpl = contractTemplate.PdfHtml
	}
	myTpl := template.Must(template.New("contract").Parse(htmlTpl))
	//合同有效期
	contractServiceAndDetailList := make([]*contract.ContractServiceAndDetail, 0) //服务内容

	if tmpContractDetail.ContractBusinessType == "代付合同" {
		if tmpContractDetail.RelationContractDetailList != nil && len(tmpContractDetail.RelationContractDetailList) > 0 {
			tmpContractDetail.StartDate = tmpContractDetail.RelationContractDetailList[0].StartDate
			tmpContractDetail.EndDate = tmpContractDetail.RelationContractDetailList[0].EndDate
			contractServiceAndDetailList = tmpContractDetail.RelationContractDetailList[0].Service
		}
	} else {
		contractServiceAndDetailList = tmpContractDetail.Service
	}
	//地址
	address := getContractAddress(&tmpContractDetail)
	data := html2pdfData{
		CompanyName:     tmpContractDetail.CompanyName,
		ContractCode:    tmpContractDetail.ContractCode,
		Address:         address,
		PostcodeDisplay: "block",
		Postcode:        tmpContractDetail.Postcode,
		PhoneDisplay:    "block",
		Phone:           tmpContractDetail.Phone,
		FaxDisplay:      "block",
		Fax:             tmpContractDetail.Fax,
		RemarkDisplay:   "block",
		Remark:          tmpContractDetail.Remark,
		PayRemark:       tmpContractDetail.PayRemark,
		StartDate:       tmpContractDetail.StartDate.Format("2006年01月02日"),
		EndDate:         tmpContractDetail.EndDate.Format("2006年01月02日"),
	}

	if data.Postcode == "" {
		data.Postcode = "无"
		data.PostcodeDisplay = "none"
	}
	if data.Fax == "" {
		data.Fax = "无"
		data.FaxDisplay = "none"
	}
	if data.Phone == "" {
		data.Phone = "无"
		data.PhoneDisplay = "none"
	}
	if data.PayRemark == "" {
		data.PayRemark = "无"
	}
	if data.Remark == "" {
		data.Remark = "无"
		data.RemarkDisplay = "none"
	}

	//合同有效期
	{
		////合同结束日期与合同开始日期的时间差（小时差）
		//newDecimal := decimal.NewFromFloat(tmpContractDetail.EndDate.Sub(tmpContractDetail.StartDate).Hours())
		////分母为365天 * 24 小时
		//newDecimal2 := decimal.NewFromInt(24 * 365)
		////计算出来相差多少年，保留一位小数（四舍五入）
		//numYearDecimal := newDecimal.Div(newDecimal2).Round(1)
		////定义最小年份差，不能小于0.1年
		//minDecimal := decimal.NewFromFloat(0.1)
		////如果计算出来的年份差小于0.1年，那么该年份差就赋值 0.1年
		//if numYearDecimal.LessThan(minDecimal) {
		//	numYearDecimal = minDecimal
		//}
		//
		////合同有效期
		//data.NumYear = numYearDecimal.String()

		tmpPrintContent, tmpErr := utils.CalculationDate(tmpContractDetail.StartDate, tmpContractDetail.EndDate)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		data.NumYear = tmpPrintContent
	}

	//合同金额
	{
		priceStr := ""
		//originalPrice := strconv.FormatFloat(tmpContractDetail.OriginalPrice, 'E', -1, 64)

		//优惠前金额（小写）
		//newDecimal := decimal.NewFromFloat(tmpContractDetail.OriginalPrice)
		originalPrice := utils.FormatPrice(tmpContractDetail.OriginalPrice)
		priceStr += "小写：" + originalPrice + "元，"

		//优惠前金额（大写）
		originalCnyPrice, cnyErr := utils.ConvertNumToCny(tmpContractDetail.OriginalPrice)
		if cnyErr != nil {
			err = cnyErr
			return
		}
		priceStr += "大写：" + originalCnyPrice

		//如果实际支付金额与订单原金额不符
		if tmpContractDetail.OriginalPrice != tmpContractDetail.Price {
			//优惠后的金额（小写）
			//newDecimal := decimal.NewFromFloat(tmpContractDetail.Price)
			price := utils.FormatPrice(tmpContractDetail.Price)
			priceStr += "，经甲乙双方友好协商，优惠至：" + price + "元，"

			//优惠后的金额（大写）
			cnyPrice, cnyErr := utils.ConvertNumToCny(tmpContractDetail.Price)
			if cnyErr != nil {
				err = cnyErr
				return
			}
			priceStr += "大写：" + cnyPrice
		}
		data.Price = priceStr
	}

	buf := new(bytes.Buffer) //实现了读写方法的可变大小的字节缓冲
	tplErr := myTpl.Execute(buf, data)
	if tplErr != nil {
		err = tplErr
		return
	}
	contractHtml = buf.String()

	//服务内容
	{
		tableStr := ""
		tableDataSlice := make([]TableData, 0)
		tableTitleSlice := make([]string, 0)
		title := ``
		if tmpTitle, ok := contentConfigMap["title1"]; ok {
			title = tmpTitle
		}
		for i := 0; i < len(contractServiceAndDetailList); i++ {
			//表格数据
			var tableDataList TableData

			item := contractServiceAndDetailList[i]
			//表头备注信息
			tableTitleSlice = append(tableTitleSlice, item.Title)

			//表格数据
			if item.HasDetail == "是" && len(item.DetailList) > 0 {
				//表格每行数据切片
				tableRowList := make([]TableRow, 0)

				//遍历获取table行数据
				for j := 0; j < len(item.DetailList); j++ {
					//列数据样式初始化
					isBold := false
					backgrandColor := ""
					fontSize := 13.0

					//表头数据样式
					if j == 0 {
						isBold = true
						backgrandColor = "gray_2"
						fontSize = 13.0
					}

					//获取每一列的数据
					tmpCellList, colErr := getColList(item.DetailList[j])
					if colErr != nil {
						err = colErr
						return
					}

					//定义生成table列数据切片
					tableCelList := make([]TableCel, 0)
					lenCell := len(tmpCellList)
					for k := 0; k < len(tmpCellList); k++ {
						//默认30%的宽度，如果不是第一列，那么需要额外计算
						widthPercent := 30.0
						if k > 0 {
							//计算出来每一列的宽度占比 start
							//总宽度
							newDecimal := decimal.NewFromFloat(70)
							//总列数
							newDecimal2 := decimal.NewFromInt(int64(lenCell) - 1)
							//计算出来每一列的宽度占比（四舍五入）
							tmpWidthPercent, _ := newDecimal.Div(newDecimal2).Round(3).Float64()
							//if !ok {
							//	err = errors.New("word普通数据表格宽度百分比计算失败")
							//	return
							//}
							widthPercent = tmpWidthPercent
							//计算出来每一列的宽度占比 end
						}

						tableCel := TableCel{
							Value:     tmpCellList[k],
							TextAlign: "center",
							//ColumnSpan   int     `json:"column_span";description:"需要合同的列数量"`
							//IsMerged     bool    `json:"is_merged";description:"是否需要上下行合并"`
							Background:   backgrandColor,
							IsBold:       isBold,
							FontSize:     fontSize,
							WidthPercent: widthPercent,
						}
						tableCelList = append(tableCelList, tableCel)
					}

					//将每行数据插入到table行数据切片之中
					tableRow := TableRow{
						RowList: tableCelList,
					}
					tableRowList = append(tableRowList, tableRow)
				}
				//赋值table表格数据
				tableDataList.List = tableRowList
			} else {
				//赋值table表格数据
				jsonStr := item.TableValue
				tmpEerr := json.Unmarshal([]byte(jsonStr), &tableDataList)
				if tmpEerr != nil {
					err = tmpEerr
					return
				}
			}

			tableDataSlice = append(tableDataSlice, tableDataList)

		}
		titleStr := strings.Join(tableTitleSlice, "、")
		title += titleStr + "的服务内容，详细如下："

		if htmlType == "pdf" {
			tableStr += `<p style="">` + title + `</p>`
		} else {
			tableStr = `<p style="font-size: 13pt;  line-height: 40px">` + title + `</p>`
		}

		for _, tableDataList := range tableDataSlice {
			//往word中添加表格数据
			if htmlType == "pdf" {
				tableStr += getTableStrByPdf(tableDataList)
			} else {
				tableStr += getTableStr(tableDataList)
			}
		}
		data.TableHtml = tableStr
	}
	//fmt.Println("TableHtml:", data.TableHtml)
	contractHtml = strings.Replace(contractHtml, `\{\{\{TableHtml\}\}\}`, data.TableHtml, -1)
	return
	//生成pdf
	//pdfPath := fmt.Sprint("./static/word/系统生成合同", contractDetail.ContractCode, ".pdf")
	//err = Html2Pdf(contractHtml, pdfPath)
	//if err != nil {
	//	return
	//}
	////defer func() {
	////	//删除对应的Pdf
	////	os.Remove(pdfPath)
	////}()
	//
	//return
}

// 生成合同服务的预览表格html代码
func getTableStr(tableDataList TableData) (tableStr string) {
	//如果表格需要分页，那么在table的style里面添加该配置：page-break-inside: avoid !important
	tableStr += `<table style="width: 100%;border-collapse: collapse;font-size: 13pt;margin-bottom:30px;page-break-inside: avoid !important;"><tbody>`
	rowList := tableDataList.List
	for i := 0; i < len(rowList); i++ {
		//创建新的一行
		tableStr += `<tr style="`
		tableStr += `page-break-before: always;page-break-after: always;page-break-inside: avoid !important;`

		//background-color: #F0F2F5;
		tableStr += `">`

		//<td style="border-right:1px solid #808181;border-bottom:1px solid #808181;padding: 15px 10px;font-weight: bold;" colspan="5">2.市场跟踪类报告</td>

		//row := table.AddRow()
		////设置行高，第二个参数是设置固定值还是自动
		//row.Properties().SetHeight(30*measurement.Point, wml.ST_HeightRuleAtLeast)
		//
		//遍历列数据
		rowDataList := rowList[i].RowList

		cellStr := ""
		if rowDataList != nil {
			for j := 0; j < len(rowDataList); j++ {
				//当前列是否合并
				//                <td style="font-weight: bold;" colspan="5">2.市场跟踪类报告</td>
				//                <td style="" align="center" rowspan="3">市场跟踪</td>
				//                <td style="" align="center">市场估值</td>

				tdStr := `<td `
				//单元格样式
				styleStr := `style="`
				styleStr += `border:1px solid #808181;padding: 15px 10px;line-height: 1.5;`

				//其他参数
				cellOtherStr := ` valign="middle" `

				//列数据
				cellData := rowDataList[j]

				//如果合并列大于0，那么就合并列
				if cellData.ColumnSpan > 0 {
					// column span / merged cells
					cellOtherStr += ` colspan="` + strconv.Itoa(cellData.ColumnSpan) + `" `
				}

				//如果指定了上下单元格合并，那么去合并上下单元格
				if cellData.IsMerged {
					if cellData.IsFirstMerged {
						cellOtherStr += ` rowspan="` + strconv.Itoa(cellData.RowSpan) + `" `
					} else {
						//如果是合并行，且不是第一行，那么就退出当前单元格循环，进入下一个循环
						continue
					}
				}

				//背景色
				if cellData.Background != "" {
					styleStr += `background-color: #F0F2F5;`
				}

				//将单元格设置为宽度百分比
				if cellData.WidthPercent > 0 {
					widthDecimal := decimal.NewFromFloat(cellData.WidthPercent)
					cellOtherStr += ` width="` + widthDecimal.String() + `%" `
				}

				//文字排版（居中、左、右）
				if cellData.TextAlign != "" {
					cellOtherStr += ` align="` + cellData.TextAlign + `" `
				}

				//cell.Properties().SetAli
				//设置是否加粗
				if cellData.IsBold {
					styleStr += `font-weight:bold;`
				}

				//设置字体大小
				fontSize := 10.0
				if cellData.FontSize > 0 {
					fontSize = cellData.FontSize
				}
				fontDecimal := decimal.NewFromFloat(fontSize)
				styleStr += `font-size: ` + fontDecimal.String() + `pt;`

				bodyStr := cellData.Value

				styleStr += `" `

				cellStr += tdStr + styleStr + cellOtherStr + `>` + bodyStr + `</td>`
			}
		}
		tableStr += cellStr + `</tr>`
	}
	tableStr += `</tbody></table>`

	return
}

// getTableStrByPdf 生成合同服务的pdf表格html代码
func getTableStrByPdf(tableDataList TableData) (tableStr string) {
	//如果表格需要分页，那么在table的style里面添加该配置：page-break-inside: avoid !important
	tableStr += `<table style="width: 100%;border-collapse: collapse;margin-top:10pt;page-break-inside: avoid !important;"><tbody>`
	rowList := tableDataList.List
	for i := 0; i < len(rowList); i++ {
		//创建新的一行
		tableStr += `<tr style="`
		tableStr += `page-break-before: always;page-break-after: always;page-break-inside: avoid !important;`

		//background-color: #F0F2F5;
		tableStr += `">`

		//<td style="border-right:1px solid #808181;border-bottom:1px solid #808181;padding: 15px 10px;font-weight: bold;" colspan="5">2.市场跟踪类报告</td>

		//row := table.AddRow()
		////设置行高，第二个参数是设置固定值还是自动
		//row.Properties().SetHeight(30*measurement.Point, wml.ST_HeightRuleAtLeast)
		//
		//遍历列数据
		rowDataList := rowList[i].RowList

		cellStr := ""
		if rowDataList != nil {
			for j := 0; j < len(rowDataList); j++ {
				//当前列是否合并
				//                <td style="font-weight: bold;" colspan="5">2.市场跟踪类报告</td>
				//                <td style="" align="center" rowspan="3">市场跟踪</td>
				//                <td style="" align="center">市场估值</td>

				tdStr := `<td `
				//单元格样式
				styleStr := `style="`
				styleStr += `border:1px solid #808181;padding:4pt 10pt;`

				//其他参数
				cellOtherStr := ` valign="middle" `

				//列数据
				cellData := rowDataList[j]

				//如果合并列大于0，那么就合并列
				if cellData.ColumnSpan > 0 {
					// column span / merged cells
					cellOtherStr += ` colspan="` + strconv.Itoa(cellData.ColumnSpan) + `" `
				}

				//如果指定了上下单元格合并，那么去合并上下单元格
				if cellData.IsMerged {
					if cellData.IsFirstMerged {
						cellOtherStr += ` rowspan="` + strconv.Itoa(cellData.RowSpan) + `" `
					} else {
						//如果是合并行，且不是第一行，那么就退出当前单元格循环，进入下一个循环
						continue
					}
				}

				//背景色
				if cellData.Background != "" {
					styleStr += `background-color: #F0F2F5;`
				}

				//将单元格设置为宽度百分比
				if cellData.WidthPercent > 0 {
					widthDecimal := decimal.NewFromFloat(cellData.WidthPercent)
					cellOtherStr += ` width="` + widthDecimal.String() + `%" `
				}

				//文字排版（居中、左、右）
				if cellData.TextAlign != "" {
					cellOtherStr += ` align="` + cellData.TextAlign + `" `
				}

				//cell.Properties().SetAli
				//设置是否加粗
				if cellData.IsBold {
					styleStr += `font-weight:bold;`
				}

				//设置字体大小
				fontSize := 10.0
				if cellData.FontSize > 0 {
					fontSize = cellData.FontSize
				}
				fontDecimal := decimal.NewFromFloat(fontSize)
				styleStr += `font-size: ` + fontDecimal.String() + `pt;`

				bodyStr := cellData.Value

				styleStr += `" `

				cellStr += tdStr + styleStr + cellOtherStr + `>` + bodyStr + `</td>`
			}
		}
		tableStr += cellStr + `</tr>`
	}
	tableStr += `</tbody></table>`

	return
}

// Html2Pdf 根据html生成pdf
func Html2Pdf(htmlStr, pdfPath string) (err error) {
	pdfg, err := wkhtml.NewPDFGenerator()
	if err != nil {
		fmt.Println("err:", err)
		return
	}

	//通过html生成page
	page := wkhtml.NewPageReader(strings.NewReader(htmlStr))

	//页眉设置
	//page.HeaderLeft.Set("弘则弥道（上海）投资咨询有限公司")
	//page.HeaderFontName.Set("宋体")
	//page.HeaderFontSize.Set(8)
	//page.HeaderSpacing.Set(4)
	//page.HeaderLine.Set(true)

	//page.HeaderSpacing.Set(10)

	//页脚设置
	page.FooterFontSize.Set(8)
	page.FooterRight.Set("[page]")
	page.FooterSpacing.Set(4)
	//page.FooterLine.Set(true)
	//page.EnableForms.Set(false)

	//转换HTML表单为PDF表单
	//page.EnableForms.Set(true)
	//使用打印媒体类型而不是屏幕
	//page.PrintMediaType.Set(true)

	//允许从标题链接到目录
	page.EnableTocBackLinks.Set(true)
	//将该page插入到pdf中
	pdfg.AddPage(page)

	//pdfg.PageSize.Set(wkhtml.PageSizeA4)
	//pdfg.MarginTop.Set(20)
	//pdfg.MarginBottom.Set(5)
	//pdfg.MarginLeft.Set(0)
	//pdfg.

	err = pdfg.Create()
	if err != nil {
		return
	}

	err = pdfg.WriteFile(pdfPath)
	return
}

// getColList 获取表格列数据
func getColList(item *contract.ContractServiceDetail) (cellList []string, err error) {
	cellList = make([]string, 0)
	var serviceDetailReq request.AddContractServiceDetailReq

	tmpItem := *item
	t := reflect.TypeOf(tmpItem)
	v := reflect.ValueOf(tmpItem)
	for k := 0; k < t.NumField(); k++ {
		//获取结构体的参数名
		tmpName := t.Field(k).Name
		if strings.Contains(tmpName, "Col") {
			//获取结构体该参数名的值
			tmpValue := v.Field(k).String()
			//如果值不为空的话，那么做下json转换
			if tmpValue != "" {
				err = json.Unmarshal([]byte(tmpValue), &serviceDetailReq)
				if err != nil {
					return
				} else {
					cellList = append(cellList, serviceDetailReq.Value)
				}
			}
		}
	}
	return
}

type WordElement struct {
	ElementType  string        `json:"element_type" description:"元素类型"`
	ElementName  string        `json:"element_name" description:"元素名称"`
	RelationName string        `json:"relation_name" description:"关联元素名称"`
	Content      string        `json:"content" description:"元素内容"`
	Background   string        `json:"background" description:"背景色"`
	IsBold       bool          `json:"is_bold" description:"是否加粗显示"`
	TextAlign    string        `json:"text_align" description:"对齐方式"`
	FontSize     float64       `json:"font_size" description:"字体大小"`
	ElementList  []WordElement `json:"list" description:"子元素"`
}

// GenerateWordV2 生成word
func GenerateWordV2(contractDetail *contract.ContractDetail, wordPath string) (err error) {
	//临时合同信息
	tmpContractDetail := *contractDetail
	//合同服务
	contractServiceAndDetailList := make([]*contract.ContractServiceAndDetail, 0) //服务内容
	if tmpContractDetail.ContractBusinessType == "代付合同" {
		if contractDetail.RelationContractDetailList != nil && len(contractDetail.RelationContractDetailList) > 0 {
			tmpContractDetail.StartDate = tmpContractDetail.RelationContractDetailList[0].StartDate
			tmpContractDetail.EndDate = tmpContractDetail.RelationContractDetailList[0].EndDate
			contractServiceAndDetailList = tmpContractDetail.RelationContractDetailList[0].Service
		}
	} else {
		contractServiceAndDetailList = tmpContractDetail.Service
	}

	contractTemplate, err := contract.GetContractTemplateByTemplateId(tmpContractDetail.TemplateId)
	if err != nil {
		return
	}
	// 初始化合同中一些特定区域的文字展示配置
	contentConfigMap := make(map[string]string)
	err = json.Unmarshal([]byte(contractTemplate.ContentConfig), &contentConfigMap)
	if err != nil {
		return
	}

	//合同信息参数
	jsonStr := contractTemplate.WordConfig
	var contractData []WordElement
	err = json.Unmarshal([]byte(jsonStr), &contractData)
	if err != nil {
		fmt.Println("json字符串解析失败,ERR:", err)
		return
	}

	doc := document.New()

	//word的属性设置，类型，作者之类的
	cp := doc.CoreProperties
	// And change them as well
	cp.SetTitle("弘则弥道（上海）投资咨询有限公司 & 研究服务合同")
	cp.SetAuthor("弘则弥道（上海）投资咨询有限公司")
	cp.SetCategory("合同")
	//cp.SetContentStatus("Draft")
	cp.SetLastModifiedBy("弘则弥道（上海）投资咨询有限公司")
	cp.SetCreated(time.Now())
	cp.SetModified(time.Now())
	cp.SetDescription("弘则弥道（上海）投资咨询有限公司 研究服务合同")
	cp.SetLanguage("中文")

	tableFontSize := 10.5 //默认表格内文字10.5
	for _, data := range contractData {
		fontSize := data.FontSize
		if fontSize <= 0 {
			fontSize = 15
		}

		printContent := ``
		if data.ElementName == "services" {
			tableTitleSlice := make([]string, 0)
			title := ``
			if tmpTitle, ok := contentConfigMap["title1"]; ok {
				title = tmpTitle
			}
			TableDataListSlice := make([]TableData, 0)
			//for i := len(contractServiceAndDetailList) - 1; i >= 0; i-- {
			for i := 0; i < len(contractServiceAndDetailList); i++ {
				//表格数据
				var tableDataList TableData

				item := contractServiceAndDetailList[i]
				//表头备注信息
				tableTitleSlice = append(tableTitleSlice, item.Title)
				//表格数据
				if item.HasDetail == "是" && len(item.DetailList) > 0 {
					//表格每行数据切片
					tableRowList := make([]TableRow, 0)

					//遍历获取table行数据
					for j := 0; j < len(item.DetailList); j++ {
						//列数据样式初始化
						isBold := false
						backgrandColor := ""
						fontSize := tableFontSize

						//表头数据样式
						if j == 0 {
							isBold = true
							backgrandColor = "gray_2"
						}

						//获取每一列的数据
						tmpCellList, colErr := getColList(item.DetailList[j])
						if colErr != nil {
							err = colErr
							return
						}

						//定义生成table列数据切片
						tableCelList := make([]TableCel, 0)
						lenCell := len(tmpCellList)
						for k := 0; k < len(tmpCellList); k++ {
							//计算出来每一列的宽度占比 start
							//总宽度
							newDecimal := decimal.NewFromFloat(100)
							//总列数
							newDecimal2 := decimal.NewFromInt(int64(lenCell))
							//计算出来每一列的宽度占比（四舍五入）
							widthPercent, _ := newDecimal.Div(newDecimal2).Round(3).Float64()
							//if !ok {
							//	err = errors.New("word普通数据表格宽度百分比计算失败")
							//	return
							//}
							//计算出来每一列的宽度占比 end

							tableCel := TableCel{
								Value:     tmpCellList[k],
								TextAlign: "center",
								//ColumnSpan   int     `json:"column_span";description:"需要合同的列数量"`
								//IsMerged     bool    `json:"is_merged";description:"是否需要上下行合并"`
								Background:   backgrandColor,
								IsBold:       isBold,
								FontSize:     fontSize,
								WidthPercent: widthPercent,
							}
							tableCelList = append(tableCelList, tableCel)
						}

						//将每行数据插入到table行数据切片之中
						tableRow := TableRow{
							RowList: tableCelList,
						}
						tableRowList = append(tableRowList, tableRow)
					}
					//赋值table表格数据
					tableDataList.List = tableRowList
				} else {
					//赋值table表格数据
					jsonStr := item.TableValue
					err = json.Unmarshal([]byte(jsonStr), &tableDataList)
					if err != nil {
						return
					}
				}

				//往word中添加表格数据
				TableDataListSlice = append(TableDataListSlice, tableDataList)
			}

			//表格标题
			titleStr := strings.Join(tableTitleSlice, "、")
			title += titleStr + "的服务内容，详细如下："

			//开始一个新的段落
			headerPar := doc.AddParagraph()
			headerParPro := headerPar.Properties()
			//headerParPro.AddTabStop()
			textAlign := getTextAlignConf(data.TextAlign)
			headerParPro.SetAlignment(textAlign)
			//if data.ElementType == "column" {
			//	headerParPro.SetAlignment(wml.ST_JcBoth)
			//}

			headerRun := headerPar.AddRun()
			headerRunPro := headerRun.Properties()
			headerRunPro.SetBold(data.IsBold)
			headerRunPro.SetSize(measurement.Distance(fontSize * measurement.Point))
			headerRunPro.SetFontFamily("宋体")
			//headerRunPro.SetKerning(measurement.Distance(2 * fontSize * measurement.Point))
			headerRun.AddText(title)

			//生成表格
			for _, tableDataList := range TableDataListSlice {
				tmpErr := addTableV2(tableDataList, doc)
				if tmpErr != nil {
					err = tmpErr
					return
				}
			}
			continue
		} else {
			isPrint, tmpPrintContent, tmpErr := getPrintData(data, &tmpContractDetail)
			if tmpErr != nil {
				err = tmpErr
				return
			}
			if isPrint == false {
				continue
			}
			printContent = tmpPrintContent
		}
		//分栏的宽度
		//columnWidth := 240.00
		printContentRune := []rune(printContent)
		strLen := len(printContentRune)

		//width := fontSize * float64(strLen)
		//tabNum := 0.0
		addTabNum := 0
		printContentList := make([]map[int]string, 0)
		firstLen := 17
		secondLen := 14
		if data.ElementType == "column" {
			if strLen > firstLen {
				maxLine := ((strLen - firstLen) / secondLen) + 1
				for i := 0; i < maxLine; i++ {
					printContentMap := make(map[int]string)
					startIndex := secondLen*i + firstLen
					endIndex := secondLen*(i+1) + firstLen
					if endIndex > strLen {
						endIndex = strLen
					}
					tmpPrintContent := string(printContentRune[startIndex:endIndex])
					printContentMap[0] = tmpPrintContent
					printContentList = append(printContentList, printContentMap)
				}
				printContent = string(printContentRune[:firstLen])
				strLen = firstLen

				//重新计算宽度
				//width = fontSize * float64(strLen)
				//addTabNum = 3
			} else {
				addTabNum = firstLen - strLen
			}
			addTabNum += 3
		}

		//开始一个新的段落
		headerPar := doc.AddParagraph()
		headerParPro := headerPar.Properties()

		headerParPro.Spacing().SetLineSpacing(measurement.Distance(1.5*fontSize*measurement.Point), wml.ST_LineSpacingRuleAuto)
		//headerParPro.AddTabStop()
		textAlign := getTextAlignConf(data.TextAlign)
		headerParPro.SetAlignment(textAlign)
		//if data.ElementType == "column" {
		//	headerParPro.SetAlignment(wml.ST_JcBoth)
		//}

		headerRun := headerPar.AddRun()
		headerRunPro := headerRun.Properties()
		headerRunPro.SetBold(data.IsBold)
		headerRunPro.SetSize(measurement.Distance(fontSize * measurement.Point))
		headerRunPro.SetFontFamily("宋体")
		//headerRunPro.SetKerning(measurement.Distance(2 * fontSize * measurement.Point))
		headerRun.AddText(printContent)

		for _, text := range data.ElementList {
			if text.ElementName == "services" {
				tableTitleSlice := make([]string, 0)
				title := ``
				if tmpTitle, ok := contentConfigMap["title1"]; ok {
					title = tmpTitle
				}
				TableDataListSlice := make([]TableData, 0)
				for i := len(contractServiceAndDetailList) - 1; i >= 0; i-- {
					//表格数据
					var tableDataList TableData

					item := contractServiceAndDetailList[i]
					//表头备注信息
					tableTitleSlice = append(tableTitleSlice, item.Title)
					//表格数据
					if item.HasDetail == "是" && len(item.DetailList) > 0 {
						//表格每行数据切片
						tableRowList := make([]TableRow, 0)

						//遍历获取table行数据
						for j := 0; j < len(item.DetailList); j++ {
							//列数据样式初始化
							isBold := false
							backgrandColor := ""
							fontSize := tableFontSize

							//表头数据样式
							if j == 0 {
								isBold = true
								backgrandColor = "gray_2"
							}

							//获取每一列的数据
							tmpCellList, colErr := getColList(item.DetailList[j])
							if colErr != nil {
								err = colErr
								return
							}

							//定义生成table列数据切片
							tableCelList := make([]TableCel, 0)
							lenCell := len(tmpCellList)
							for k := 0; k < len(tmpCellList); k++ {
								//计算出来每一列的宽度占比 start
								//总宽度
								newDecimal := decimal.NewFromFloat(100)
								//总列数
								newDecimal2 := decimal.NewFromInt(int64(lenCell))
								//计算出来每一列的宽度占比（四舍五入）
								widthPercent, _ := newDecimal.Div(newDecimal2).Round(3).Float64()
								//if !ok {
								//	err = errors.New("word普通数据表格宽度百分比计算失败")
								//	return
								//}
								//计算出来每一列的宽度占比 end

								tableCel := TableCel{
									Value:     tmpCellList[k],
									TextAlign: "center",
									//ColumnSpan   int     `json:"column_span";description:"需要合同的列数量"`
									//IsMerged     bool    `json:"is_merged";description:"是否需要上下行合并"`
									Background:   backgrandColor,
									IsBold:       isBold,
									FontSize:     fontSize,
									WidthPercent: widthPercent,
								}
								tableCelList = append(tableCelList, tableCel)
							}

							//将每行数据插入到table行数据切片之中
							tableRow := TableRow{
								RowList: tableCelList,
							}
							tableRowList = append(tableRowList, tableRow)
						}
						//赋值table表格数据
						tableDataList.List = tableRowList
					} else {
						//赋值table表格数据
						jsonStr := item.TableValue
						err = json.Unmarshal([]byte(jsonStr), &tableDataList)
						if err != nil {
							return
						}
					}

					//往word中添加表格数据
					TableDataListSlice = append(TableDataListSlice, tableDataList)
				}

				//表格标题
				titleStr := strings.Join(tableTitleSlice, "、")
				title += titleStr + "的服务内容，详细如下："

				headerRun := headerPar.AddRun()
				headerRun.AddBreak()
				headerRunPro := headerRun.Properties()
				headerRunPro.SetBold(text.IsBold)
				headerRunPro.SetSize(measurement.Distance(fontSize * measurement.Point))
				headerRunPro.SetFontFamily("宋体")
				//headerRunPro.SetKerning(measurement.Distance(2 * fontSize * measurement.Point))
				headerRun.AddText(title)

				//生成表格
				for _, tableDataList := range TableDataListSlice {
					tmpErr := addTableV2(tableDataList, doc)
					if tmpErr != nil {
						err = tmpErr
						return
					}
				}
			} else {
				isPrint, printContent, tmpErr := getPrintData(text, &tmpContractDetail)
				if tmpErr != nil {
					err = tmpErr
					return
				}
				if isPrint == false {
					continue
				}
				if data.ElementType == "column" {
					for j := 0; j < addTabNum; j++ {
						tabStr := "  "
						printContent = tabStr + printContent
					}
				}
				fontSize := text.FontSize
				if fontSize <= 0 {
					fontSize = 15
				}
				headerRun2 := headerPar.AddRun()
				headerRunPro2 := headerRun2.Properties()
				headerRunPro2.SetBold(text.IsBold)
				headerRunPro2.SetSize(measurement.Distance(fontSize * measurement.Point))
				headerRunPro2.SetFontFamily("宋体")
				//headerRunPro2.SetKerning(measurement.Distance(2 * fontSize * measurement.Point))
				headerRun2.AddText(printContent)
			}
		}

		for _, printMap := range printContentList {
			//开始一个新的段落
			headerPar := doc.AddParagraph()
			headerParPro := headerPar.Properties()
			headerParPro.Spacing().SetLineSpacing(measurement.Distance(1.5*fontSize*measurement.Point), wml.ST_LineSpacingRuleAuto)

			//headerParPro.AddTabStop()
			textAlign := getTextAlignConf(data.TextAlign)
			headerParPro.SetAlignment(textAlign)
			//空出三个字符出来，避免签名顶在最前方展示
			headerParPro.SetStartIndent(measurement.Distance(3 * fontSize * measurement.Point))
			//if data.ElementType == "column" {
			//	for j := 0; j < 3; j++ {
			//		printContent = "  " + printContent
			//	}
			//}
			//printContent = "       " + printContent
			headerRun := headerPar.AddRun()
			headerRunPro := headerRun.Properties()
			headerRunPro.SetBold(data.IsBold)
			headerRunPro.SetSize(measurement.Distance(fontSize * measurement.Point))
			headerRunPro.SetFontFamily("宋体")
			//headerRunPro.SetKerning(measurement.Distance(2 * fontSize * measurement.Point))

			headerRun.AddText(printMap[0])
		}
	}

	//for _, data := range list {
	//	headerPar := doc.AddParagraph()
	//	headerParPro := headerPar.Properties()
	//	headerParPro.SetAlignment(wml.ST_JcCenter)
	//	headerRun := headerPar.AddRun()
	//	headerRunPro := headerRun.Properties()
	//	headerRunPro.SetBold(true)
	//	headerRunPro.SetSize(16)
	//	headerRun.AddText(data)
	//}

	err = doc.SaveToFile(wordPath)
	return
}

// getPrintData 获取打印数据
func getPrintData(data WordElement, contractDetail *contract.ContractDetail) (isPrint bool, printContent string, err error) {
	printContent = data.Content
	if data.RelationName != "" {
		switch data.RelationName {
		case "address":
			if contractDetail.Address == "" && contractDetail.Province == "" && contractDetail.City == "" {
				return
			}
		case "postcode":
			if contractDetail.Postcode == "" {
				return
			}
		case "phone":
			if contractDetail.Phone == "" {
				return
			}
		case "fax":
			if contractDetail.Fax == "" {
				return
			}
		case "remark":
			if contractDetail.Remark == "" {
				return
			}
		case "price":
			//实际金额（小写）
			if contractDetail.OriginalPrice == contractDetail.Price {
				return
			}
		case "price_cn":
			//实际金额（大写）
			if contractDetail.OriginalPrice == contractDetail.Price {
				return
			}
		case "pay_remark":
			if contractDetail.PayRemark == "" {
				return
			}
		case "company_name":
			if contractDetail.CompanyName == "" {
				return
			}
		}
	}
	switch data.ElementName {
	case "address":
		if contractDetail.Address == "" && contractDetail.Province == "" && contractDetail.City == "" {
			return
		}
		printContent = getContractAddress(contractDetail)
	case "postcode":
		if contractDetail.Postcode == "" {
			return
		}
		printContent = contractDetail.Postcode
	case "phone":
		if contractDetail.Phone == "" {
			return
		}
		printContent = contractDetail.Phone
	case "fax":
		if contractDetail.Fax == "" {
			return
		}
		printContent = contractDetail.Fax
	case "remark":
		if contractDetail.Remark == "" {
			return
		}
		printContent = contractDetail.Remark
	case "start_date":
		printContent = contractDetail.StartDate.Format("2006年01月02日")
	case "end_date":
		printContent = contractDetail.EndDate.Format("2006年01月02日")
	case "num_year":
		////合同结束日期与合同开始日期的时间差（小时差）
		//newDecimal := decimal.NewFromFloat(contractDetail.EndDate.Sub(contractDetail.StartDate).Hours())
		////分母为365天 * 24 小时
		//newDecimal2 := decimal.NewFromInt(24 * 365)
		////计算出来相差多少年，保留一位小数（四舍五入）
		//numYearDecimal := newDecimal.Div(newDecimal2).Round(1)
		////定义最小年份差，不能小于0.1年
		//minDecimal := decimal.NewFromFloat(0.1)
		////如果计算出来的年份差小于0.1年，那么该年份差就赋值 0.1年
		//if numYearDecimal.LessThan(minDecimal) {
		//	numYearDecimal = minDecimal
		//}
		//printContent = numYearDecimal.String()
		tmpPrintContent, tmpErr := utils.CalculationDate(contractDetail.StartDate, contractDetail.EndDate)
		if tmpErr != nil {
			err = tmpErr
			return
		}
		printContent = tmpPrintContent
	case "original_price":
		//优惠前金额（小写）
		//newDecimal := decimal.NewFromFloat(contractDetail.OriginalPrice)
		printContent = utils.FormatPrice(contractDetail.OriginalPrice)
	case "original_price_cn":
		//优惠前金额（大写）
		originalCnyPrice, cnyErr := utils.ConvertNumToCny(contractDetail.OriginalPrice)
		if cnyErr != nil {
			err = cnyErr
			return
		}
		printContent = originalCnyPrice
	case "price":
		//实际金额（小写）
		if contractDetail.OriginalPrice == contractDetail.Price {
			return
		}
		//newDecimal := decimal.NewFromFloat(contractDetail.Price)
		printContent = utils.FormatPrice(contractDetail.Price)
	case "price_cn":
		//实际金额（大写）
		if contractDetail.OriginalPrice == contractDetail.Price {
			return
		}
		cnyPrice, cnyErr := utils.ConvertNumToCny(contractDetail.Price)
		if cnyErr != nil {
			err = cnyErr
			return
		}
		printContent = cnyPrice

	case "pay_remark":
		if contractDetail.PayRemark == "" {
			return
		}
		printContent = contractDetail.PayRemark
	case "company_name":
		if contractDetail.CompanyName == "" {
			return
		}
		printContent = contractDetail.CompanyName
	case "company_name_sign":
		if contractDetail.CompanyName == "" {
			return
		}
		printContent = "甲方：" + contractDetail.CompanyName
	}
	isPrint = true
	return
}

// addTableV2 添加表格数据
func addTableV2(tableDataList TableData, doc *document.Document) (err error) {
	//fmt.Println("表头名称:", title)
	//插入一个新的段落
	//nowParagraph := doc.AddParagraph()
	//doc.AddParagraph()
	//表格数据
	doc.AddParagraph().Properties().AddSection(wml.ST_SectionMarkNextPage)
	table := doc.AddTable()
	//设置表格宽度
	tableWidth := 6.5
	table.Properties().SetWidth(measurement.Distance(tableWidth * measurement.Inch))
	//表格宽度设置为自动
	//table.Properties().SetWidthAuto()

	//边框
	borders := table.Properties().Borders()
	// thin borders
	borders.SetAll(wml.ST_BorderSingle, color.Auto, measurement.Zero)

	//表格数据
	rowList := tableDataList.List

	//table.Properties().W
	for i := 0; i < len(rowList); i++ {
		//创建新的一行
		row := table.AddRow()
		//设置行高，第二个参数是设置固定值还是自动
		row.Properties().SetHeight(20*measurement.Point, wml.ST_HeightRuleAtLeast)

		//遍历列数据
		rowDataList := rowList[i].RowList
		if rowDataList != nil {
			for j := 0; j < len(rowDataList); j++ {
				cell := row.AddCell()
				cellPara := cell.AddParagraph()
				run := cellPara.AddRun()
				//列数据
				cellData := rowDataList[j]

				//如果合并列大于0，那么就合并列
				if cellData.ColumnSpan > 0 {
					// column span / merged cells
					cell.Properties().SetColumnSpan(cellData.ColumnSpan)
					//_ = row.AddCell()
				}

				//如果指定了上下单元格合并，那么去合并上下单元格
				if cellData.IsMerged {
					//合并单元格类型
					var mergeVal wml.ST_Merge

					if cellData.IsFirstMerged { //如果是第一个合并行，那么开始重新合并
						mergeVal = wml.ST_MergeRestart
					} else { //如果不是第一个合并行，那么是继续合并
						mergeVal = wml.ST_MergeContinue
					}
					cell.Properties().SetVerticalMerge(mergeVal)
				}

				//背景色
				if cellData.Background != "" {
					cell.Properties().SetShading(wml.ST_ShdSolid, getColorConf(cellData.Background), color.Auto)
				}

				//填充内容（文字）垂直对齐方式
				cell.Properties().SetVerticalAlignment(wml.ST_VerticalJcCenter)

				//将单元格设置为宽度百分比
				if cellData.WidthPercent > 0 {
					//cell.Properties().SetWidthPercent(cellData.WidthPercent)
					//因为libreOffice不支持百分比的设置表格宽度
					cellWidth := tableWidth * cellData.WidthPercent * measurement.Inch / 100
					cell.Properties().SetWidth(measurement.Distance(cellWidth))
				}

				//文字排版（居中、左、右）
				if cellData.TextAlign != "" {
					cellPara.Properties().SetAlignment(getTextAlignConf(cellData.TextAlign))
					//cellPara.Properties().SetAlignment(wml.ST_JcLeft)
				}

				//cell.Properties().SetAli
				//设置是否加粗
				run.Properties().SetBold(cellData.IsBold)

				//设置字体大小
				fontSize := 10.5
				if cellData.FontSize > 0 {
					fontSize = cellData.FontSize
				}
				run.Properties().SetSize(measurement.Distance(fontSize * measurement.Point))

				//设置段落间的间距
				cellPara.Properties().Spacing().SetLineSpacing(measurement.Distance(1.4*fontSize*measurement.Point), wml.ST_LineSpacingRuleAuto)
				//设置段前间距
				cellPara.Properties().Spacing().SetBefore(measurement.Distance(0.9 * fontSize * measurement.Point))
				//设置段后间距
				cellPara.Properties().Spacing().SetAfter(measurement.Distance(0.5 * fontSize * measurement.Point))

				//设置字体
				run.Properties().SetFontFamily("宋体")

				//设置排序
				run.Properties().SetVerticalAlignment(sharedTypes.ST_VerticalAlignRunBaseline)

				//设置显示的文字
				if cellData.Value != "" {
					strSlice := strings.Split(cellData.Value, "<br/>")
					for s := 0; s < len(strSlice); s++ {
						if s > 0 {
							run.AddBreak()
						}
						run.AddText(strSlice[s])
					}
				} else {
					run.AddText("")
				}
			}

		}
	}
	//twoParagraph := doc.AddParagraph()
	//twoParagraph.AddRun()
	doc.AddParagraph()

	return
}

// getContractAddress 获取展示的详细地址
func getContractAddress(contractDetail *contract.ContractDetail) (address string) {
	ignoreStrs := []string{"北京市", "上海市", "天津市", "重庆市"}
	if strings.Contains(strings.Join(ignoreStrs, ","), contractDetail.Province) {
		address = contractDetail.City + contractDetail.Address
	} else {
		address = contractDetail.Province + contractDetail.City + contractDetail.Address
	}
	return
}

//FuncDocs2Pdf
/**
*@tips libreoffice 转换指令：
* libreoffice6.2 invisible --convert-to pdf csDoc.doc --outdir /home/[转出目录]
*
* @function 实现文档类型转换为pdf或html
* @param command:libreofficed的命令(具体以版本为准)；win：soffice； linux：libreoffice6.2
*     fileSrcPath:转换文件的路径
*         fileOutDir:转换后文件存储目录
*       converterType：转换的类型pdf/html
* @return fileOutPath 转换成功生成的文件的路径 error 转换错误
 */
func FuncDocs2Pdf(command string, fileSrcPath string, fileOutDir string, converterType string) (fileOutPath string, error error) {
	//校验fileSrcPath
	srcFile, erByOpenSrcFile := os.Open(fileSrcPath)
	if erByOpenSrcFile != nil && os.IsNotExist(erByOpenSrcFile) {
		return "", erByOpenSrcFile
	}
	//如文件输出目录fileOutDir不存在则自动创建
	outFileDir, erByOpenFileOutDir := os.Open(fileOutDir)
	if erByOpenFileOutDir != nil && os.IsNotExist(erByOpenFileOutDir) {
		erByCreateFileOutDir := os.MkdirAll(fileOutDir, os.ModePerm)
		if erByCreateFileOutDir != nil {
			fmt.Println("File ouput dir create error.....", erByCreateFileOutDir.Error())
			return "", erByCreateFileOutDir
		}
	}
	//关闭流
	defer func() {
		_ = srcFile.Close()
		_ = outFileDir.Close()
	}()
	//convert
	cmd := exec.Command(command, "--invisible", "--convert-to", converterType,
		fileSrcPath, "--outdir", fileOutDir)
	_, errByCmdStart := cmd.Output()
	//命令调用转换失败
	if errByCmdStart != nil {
		return "", errByCmdStart
	}
	//success
	fileOutPath = fileOutDir + "/" + strings.Split(path.Base(fileSrcPath), ".")[0]
	if converterType == "html" {
		fileOutPath += ".html"
	} else {
		fileOutPath += ".pdf"
	}
	//fmt.Println("文件转换成功...", string(byteByStat))
	return fileOutPath, nil
}
