123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857 |
- 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
- }
|