|
@@ -19,9 +19,13 @@ import (
|
|
|
"hongze/hongze_mobile_admin/models/tables/contract_template"
|
|
|
"hongze/hongze_mobile_admin/utils"
|
|
|
"html/template"
|
|
|
+ "os"
|
|
|
+ "os/exec"
|
|
|
+ "path"
|
|
|
"reflect"
|
|
|
"strconv"
|
|
|
"strings"
|
|
|
+ "time"
|
|
|
)
|
|
|
|
|
|
type TableData struct {
|
|
@@ -569,21 +573,27 @@ func GetHtmlByContractDetail(contractDetail *contract.ContractDetail, htmlType s
|
|
|
|
|
|
//合同有效期
|
|
|
{
|
|
|
- //合同结束日期与合同开始日期的时间差(小时差)
|
|
|
- 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
|
|
|
+ ////合同结束日期与合同开始日期的时间差(小时差)
|
|
|
+ //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
|
|
|
+ //}
|
|
|
+ ////合同有效期
|
|
|
+ //data.NumYear = numYearDecimal.String()
|
|
|
+
|
|
|
+ tmpPrintContent, tmpErr := CalculationDate(contractDetail.StartDate, contractDetail.EndDate)
|
|
|
+ if tmpErr != nil {
|
|
|
+ err = tmpErr
|
|
|
+ return
|
|
|
}
|
|
|
-
|
|
|
- //合同有效期
|
|
|
- data.NumYear = numYearDecimal.String()
|
|
|
+ data.NumYear = tmpPrintContent
|
|
|
}
|
|
|
|
|
|
//合同金额
|
|
@@ -1056,6 +1066,726 @@ func getColList(item *contract_service_detail.ContractServiceDetail) (cellList [
|
|
|
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) {
|
|
|
+ contractTemplate, err := contract_template.GetContractTemplateByTemplateId(contractDetail.TemplateId)
|
|
|
+ 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("中文")
|
|
|
+
|
|
|
+ for _, data := range contractData {
|
|
|
+ fontSize := data.FontSize
|
|
|
+ if fontSize <= 0 {
|
|
|
+ fontSize = 15
|
|
|
+ }
|
|
|
+
|
|
|
+ printContent := ``
|
|
|
+ if data.ElementName == "services" {
|
|
|
+ tableTitleSlice := make([]string, 0)
|
|
|
+ title := ""
|
|
|
+ if contractDetail.ProductId == 1 {
|
|
|
+ title = "依照《【弘则研究】FICC客户客户服务列表2021》中"
|
|
|
+ } else {
|
|
|
+ title = "依照《【弘则研究】私募客户客户服务列表2021》中"
|
|
|
+ }
|
|
|
+ TableDataListSlice := make([]TableData, 0)
|
|
|
+ //for i := len(contractDetail.Service) - 1; i >= 0; i-- {
|
|
|
+ for i := 0; i < len(contractDetail.Service); i++ {
|
|
|
+ //表格数据
|
|
|
+ var tableDataList TableData
|
|
|
+
|
|
|
+ item := contractDetail.Service[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 := 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
|
|
|
+ } else {
|
|
|
+ //获取预设的表格数据
|
|
|
+ contractServiceTemplate, tmpErr := contract_service_template.GetContractServiceTemplateById(item.ServiceTemplateId)
|
|
|
+ if tmpErr != nil {
|
|
|
+ err = tmpErr
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ //赋值table表格数据
|
|
|
+ jsonStr := contractServiceTemplate.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, contractDetail)
|
|
|
+ if tmpErr != nil {
|
|
|
+ err = tmpErr
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if isPrint == false {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ printContent = tmpPrintContent
|
|
|
+ }
|
|
|
+ //分栏的宽度
|
|
|
+ printContentRune := []rune(printContent)
|
|
|
+ strLen := len(printContentRune)
|
|
|
+
|
|
|
+ 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 contractDetail.ProductId == 1 {
|
|
|
+ title = "依照《【弘则研究】FICC客户客户服务列表2021》中 "
|
|
|
+ } else {
|
|
|
+ title = "依照《【弘则研究】私募客户客户服务列表2021》中 "
|
|
|
+ }
|
|
|
+ TableDataListSlice := make([]TableData, 0)
|
|
|
+ for i := len(contractDetail.Service) - 1; i >= 0; i-- {
|
|
|
+ //表格数据
|
|
|
+ var tableDataList TableData
|
|
|
+
|
|
|
+ item := contractDetail.Service[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 := 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
|
|
|
+ } else {
|
|
|
+ //获取预设的表格数据
|
|
|
+ contractServiceTemplate, tmpErr := contract_service_template.GetContractServiceTemplateById(item.ServiceTemplateId)
|
|
|
+ if tmpErr != nil {
|
|
|
+ err = tmpErr
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ //赋值table表格数据
|
|
|
+ jsonStr := contractServiceTemplate.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, contractDetail)
|
|
|
+ if tmpErr != nil {
|
|
|
+ err = tmpErr
|
|
|
+ return
|
|
|
+ }
|
|
|
+ if isPrint == false {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if data.ElementType == "column" {
|
|
|
+ for j := 0; j < addTabNum; j++ {
|
|
|
+ //headerRun.AddTab()
|
|
|
+ printContent = " " + 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))
|
|
|
+
|
|
|
+ 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 := CalculationDate(contractDetail.StartDate, contractDetail.EndDate)
|
|
|
+ if tmpErr != nil {
|
|
|
+ err = tmpErr
|
|
|
+ return
|
|
|
+ }
|
|
|
+ printContent = tmpPrintContent
|
|
|
+ case "original_price":
|
|
|
+ //优惠前金额(小写)
|
|
|
+ newDecimal := decimal.NewFromFloat(contractDetail.OriginalPrice)
|
|
|
+ printContent = newDecimal.String()
|
|
|
+ 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 = newDecimal.String()
|
|
|
+ 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()
|
|
|
+ //表格数据
|
|
|
+
|
|
|
+ table := doc.InsertTableAfter(nowParagraph)
|
|
|
+ //设置表格宽度
|
|
|
+ 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
|
|
|
+ //每一列合并单元格状态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)
|
|
|
+ //因为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.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
|
|
|
+}
|
|
|
+
|
|
|
// getContractAddress 获取展示的详细地址
|
|
|
func getContractAddress(contractDetail *contract.ContractDetail) (address string) {
|
|
|
ignoreStrs := []string{"北京市", "上海市", "天津市", "重庆市"}
|
|
@@ -1066,3 +1796,143 @@ func getContractAddress(contractDetail *contract.ContractDetail) (address string
|
|
|
}
|
|
|
return
|
|
|
}
|
|
|
+
|
|
|
+/**
|
|
|
+*@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
|
|
|
+}
|
|
|
+
|
|
|
+// CalculationDate 计算两个日期之间相差n年m月y天
|
|
|
+func CalculationDate(startDate, endDate time.Time) (beetweenDay string, err error) {
|
|
|
+ //startDate := time.Date(2021, 3, 28, 0, 0, 0, 0, time.Now().Location())
|
|
|
+ //endDate := time.Date(2022, 3, 31, 0, 0, 0, 0, time.Now().Location())
|
|
|
+ numYear := endDate.Year() - startDate.Year()
|
|
|
+
|
|
|
+ numMonth := int(endDate.Month()) - int(startDate.Month())
|
|
|
+
|
|
|
+ numDay := 0
|
|
|
+ //获取截止月的总天数
|
|
|
+ endDateDays := getMonthDay(endDate.Year(), int(endDate.Month()))
|
|
|
+
|
|
|
+ //获取截止月的前一个月
|
|
|
+ endDatePrevMonthDate := endDate.AddDate(0, -1, 0)
|
|
|
+ //获取截止日期的上一个月的总天数
|
|
|
+ endDatePrevMonthDays := getMonthDay(endDatePrevMonthDate.Year(), int(endDatePrevMonthDate.Month()))
|
|
|
+ //获取开始日期的的月份总天数
|
|
|
+ startDateMonthDays := getMonthDay(startDate.Year(), int(startDate.Month()))
|
|
|
+
|
|
|
+ //判断,截止月是否完全被选中,如果相等,那么代表截止月份全部天数被选择
|
|
|
+ if endDate.Day() == endDateDays {
|
|
|
+ numDay = startDateMonthDays - startDate.Day() + 1
|
|
|
+
|
|
|
+ //如果剩余天数正好与开始日期的天数是一致的,那么月份加1
|
|
|
+ if numDay == startDateMonthDays {
|
|
|
+ numMonth++
|
|
|
+ numDay = 0
|
|
|
+ //超过月份了,那么年份加1
|
|
|
+ if numMonth == 12 {
|
|
|
+ numYear++
|
|
|
+ numMonth = 0
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ numDay = endDate.Day() - startDate.Day() + 1
|
|
|
+ }
|
|
|
+
|
|
|
+ //天数小于0,那么向月份借一位
|
|
|
+ if numDay < 0 {
|
|
|
+ //向上一个月借一个月的天数
|
|
|
+ numDay += endDatePrevMonthDays
|
|
|
+
|
|
|
+ //总月份减去一个月
|
|
|
+ numMonth = numMonth - 1
|
|
|
+ }
|
|
|
+
|
|
|
+ //月份小于0,那么向年份借一位
|
|
|
+ if numMonth < 0 {
|
|
|
+ //向上一个年借12个月
|
|
|
+ numMonth += 12
|
|
|
+
|
|
|
+ //总年份减去一年
|
|
|
+ numYear = numYear - 1
|
|
|
+ }
|
|
|
+ if numYear < 0 {
|
|
|
+ err = errors.New("日期异常")
|
|
|
+ return
|
|
|
+ }
|
|
|
+
|
|
|
+ if numYear > 0 {
|
|
|
+ beetweenDay += fmt.Sprint(numYear, "年")
|
|
|
+ }
|
|
|
+ if numMonth > 0 {
|
|
|
+ beetweenDay += fmt.Sprint(numMonth, "个月")
|
|
|
+ }
|
|
|
+ if numDay > 0 {
|
|
|
+ beetweenDay += fmt.Sprint(numDay, "天")
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|
|
|
+
|
|
|
+// getMonthDay 获取某年某月有多少天
|
|
|
+func getMonthDay(year, month int) (days int) {
|
|
|
+ if month != 2 {
|
|
|
+ if month == 4 || month == 6 || month == 9 || month == 11 {
|
|
|
+ days = 30
|
|
|
+
|
|
|
+ } else {
|
|
|
+ days = 31
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if ((year%4) == 0 && (year%100) != 0) || (year%400) == 0 {
|
|
|
+ days = 29
|
|
|
+ } else {
|
|
|
+ days = 28
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return
|
|
|
+}
|