word.go 57 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857
  1. package services
  2. import (
  3. "baliance.com/gooxml/color"
  4. "baliance.com/gooxml/document"
  5. "baliance.com/gooxml/measurement"
  6. "baliance.com/gooxml/schema/soo/ofc/sharedTypes"
  7. "baliance.com/gooxml/schema/soo/wml"
  8. "bytes"
  9. "encoding/json"
  10. "errors"
  11. "fmt"
  12. wkhtml "github.com/SebastiaanKlippert/go-wkhtmltopdf"
  13. "github.com/shopspring/decimal"
  14. "hongze/hz_crm_api/models/contract"
  15. "hongze/hz_crm_api/models/contract/request"
  16. "hongze/hz_crm_api/utils"
  17. "html/template"
  18. "os"
  19. "os/exec"
  20. "path"
  21. "reflect"
  22. "strconv"
  23. "strings"
  24. "time"
  25. )
  26. type TableData struct {
  27. List []TableRow `json:"table" description:"列数据"`
  28. }
  29. type TableRow struct {
  30. RowList []TableCel `json:"row" description:"列数据"`
  31. }
  32. type TableCel struct {
  33. Value string `json:"value" description:"展示的数据"`
  34. ColumnSpan int `json:"column_span" description:"需要合同的列数量"`
  35. RowSpan int `json:"row_span" description:"需要合同的行数量"`
  36. IsMerged bool `json:"is_merged" description:"是否需要上下行合并"`
  37. IsFirstMerged bool `json:"is_first_merged" description:"是否是第一次合并上下行"`
  38. Background string `json:"background" description:"背景色"`
  39. IsBold bool `json:"is_bold" description:"是否加粗显示"`
  40. TextAlign string `json:"text_align" description:"对齐方式"`
  41. FontSize float64 `json:"font_size" description:"字体大小"`
  42. WidthPercent float64 `json:"width_percent" description:"单元格宽度占整个表格的百分比"`
  43. }
  44. // 获取颜色配置
  45. func getColorConf(background string) (foreground color.Color) {
  46. switch background {
  47. case "slate_gray": //石板灰
  48. foreground = color.SlateGray
  49. case "light_slate_gray": //浅石板灰
  50. foreground = color.LightSlateGray
  51. case "light_gray": //浅灰
  52. foreground = color.LightGray
  53. case "gray": //灰色
  54. foreground = color.Gray
  55. case "gray_1": //灰色_1(中浅灰)
  56. foreground = color.RGB(uint8(215), uint8(215), uint8(215))
  57. case "gray_2": //灰色_2(浅灰)
  58. foreground = color.RGB(uint8(241), uint8(241), uint8(241))
  59. case "dim_gray": //暗灰色
  60. foreground = color.DimGray
  61. case "dark_slate_gray": //深灰色
  62. foreground = color.DarkSlateGray
  63. default:
  64. foreground = color.LightGray
  65. }
  66. return
  67. }
  68. func getTextAlignConf(textAlign string) (align wml.ST_Jc) {
  69. switch textAlign {
  70. case "left": //居左
  71. align = wml.ST_JcLeft
  72. case "center": //居中
  73. align = wml.ST_JcCenter
  74. case "right": //居右
  75. align = wml.ST_JcRight
  76. case "both": //
  77. align = wml.ST_JcBoth
  78. default:
  79. align = wml.ST_JcLeft
  80. }
  81. return
  82. }
  83. // GenerateWord 生成word
  84. func GenerateWord(contractDetail *contract.ContractDetail) (err error) {
  85. wordTemplatePath := getWordPath(contractDetail.TemplateId)
  86. if wordTemplatePath == "" {
  87. err = errors.New("找不到对应的合同模板")
  88. return
  89. }
  90. doc, err := document.Open(wordTemplatePath)
  91. if err != nil {
  92. fmt.Println("error opening document: %s", err)
  93. return
  94. }
  95. paragraphs := []document.Paragraph{}
  96. for _, p := range doc.Paragraphs() {
  97. paragraphs = append(paragraphs, p)
  98. }
  99. // This sample document uses structured document tags, which are not common
  100. // except for in document templates. Normally you can just iterate over the
  101. // document's paragraphs.
  102. for _, sdt := range doc.StructuredDocumentTags() {
  103. for _, p := range sdt.Paragraphs() {
  104. paragraphs = append(paragraphs, p)
  105. }
  106. }
  107. doc.AddParagraph()
  108. for _, p := range paragraphs {
  109. for _, r := range p.Runs() {
  110. switch r.Text() {
  111. case "{{address}}":
  112. // ClearContent clears both text and line breaks within a run,
  113. // so we need to add the line break back
  114. r.ClearContent()
  115. address := getContractAddress(contractDetail)
  116. r.AddText(address)
  117. //r.AddBreak()
  118. //para := doc.InsertParagraphBefore(p)
  119. //para.AddRun().AddText("Mr.")
  120. //para.SetStyle("Name") // Name is a default style in this template file
  121. //
  122. //para = doc.InsertParagraphAfter(p)
  123. //para.AddRun().AddText("III")
  124. //para.SetStyle("Name")
  125. case "{{postcode}}":
  126. r.ClearContent()
  127. r.AddText(contractDetail.Postcode)
  128. case "{{phone}}":
  129. r.ClearContent()
  130. r.AddText(contractDetail.Phone)
  131. case "{{fax}}":
  132. r.ClearContent()
  133. r.AddText(contractDetail.Fax)
  134. case "{{remark}}":
  135. r.ClearContent()
  136. remark := contractDetail.Remark
  137. if remark == "" {
  138. remark = "无"
  139. }
  140. r.AddText(remark)
  141. case "{{start_date}}":
  142. r.ClearContent()
  143. r.AddText(contractDetail.StartDate.Format("2006 年 01 月 02 日"))
  144. case "{{end_date}}":
  145. r.ClearContent()
  146. r.AddText(contractDetail.EndDate.Format("2006 年 01 月 02 日"))
  147. case "{{num_year}}":
  148. r.ClearContent()
  149. //合同结束日期与合同开始日期的时间差(小时差)
  150. newDecimal := decimal.NewFromFloat(contractDetail.EndDate.Sub(contractDetail.StartDate).Hours())
  151. //分母为365天 * 24 小时
  152. newDecimal2 := decimal.NewFromInt(24 * 365)
  153. //计算出来相差多少年,保留一位小数(四舍五入)
  154. numYearDecimal := newDecimal.Div(newDecimal2).Round(1)
  155. //定义最小年份差,不能小于0.1年
  156. minDecimal := decimal.NewFromFloat(0.1)
  157. //如果计算出来的年份差小于0.1年,那么该年份差就赋值 0.1年
  158. if numYearDecimal.LessThan(minDecimal) {
  159. numYearDecimal = minDecimal
  160. }
  161. //cnYear, cnErr := utils.ConvertNumToCn(numYearDecimal.String())
  162. //if cnErr != nil {
  163. // err = cnErr
  164. // return
  165. //}
  166. r.AddText(numYearDecimal.String())
  167. case "{{price}}":
  168. r.ClearContent()
  169. priceStr := ""
  170. //originalPrice := strconv.FormatFloat(contractDetail.OriginalPrice, 'E', -1, 64)
  171. //优惠前金额(小写)
  172. //newDecimal := decimal.NewFromFloat(contractDetail.OriginalPrice)
  173. originalPrice := utils.FormatPrice(contractDetail.OriginalPrice)
  174. priceStr += "小写:" + originalPrice + ","
  175. //优惠前金额(大写)
  176. originalCnyPrice, cnyErr := utils.ConvertNumToCny(contractDetail.OriginalPrice)
  177. if cnyErr != nil {
  178. err = cnyErr
  179. return
  180. }
  181. priceStr += "大写:" + originalCnyPrice
  182. //如果实际支付金额与订单原金额不符
  183. if contractDetail.OriginalPrice != contractDetail.Price {
  184. //优惠后的金额(小写)
  185. //newDecimal := decimal.NewFromFloat(contractDetail.Price)
  186. price := utils.FormatPrice(contractDetail.Price)
  187. priceStr += ",经甲乙双方友好协商,优惠至:" + price + "元,"
  188. //优惠后的金额(大写)
  189. cnyPrice, cnyErr := utils.ConvertNumToCny(contractDetail.Price)
  190. if cnyErr != nil {
  191. err = cnyErr
  192. return
  193. }
  194. priceStr += "大写:" + cnyPrice
  195. }
  196. r.AddText(priceStr)
  197. case "{{pay_remark}}":
  198. r.ClearContent()
  199. r.AddText(contractDetail.PayRemark)
  200. case "{{company_name}}":
  201. r.ClearContent()
  202. r.AddText(contractDetail.CompanyName)
  203. //r.AddBreak()
  204. case "{{services}}":
  205. r.ClearContent()
  206. //赋值当前段落
  207. nowParagraph := p
  208. for i := len(contractDetail.Service) - 1; i >= 0; i-- {
  209. //表格数据
  210. var tableDataList TableData
  211. //表头备注信息
  212. tableTitle := ""
  213. item := contractDetail.Service[i]
  214. //表格数据
  215. if item.HasDetail == "是" && len(item.DetailList) > 0 {
  216. //表格每行数据切片
  217. tableRowList := make([]TableRow, 0)
  218. //遍历获取table行数据
  219. for j := 0; j < len(item.DetailList); j++ {
  220. //列数据样式初始化
  221. isBold := false
  222. backgrandColor := ""
  223. fontSize := 10.0
  224. //表头数据样式
  225. if j == 0 {
  226. isBold = true
  227. backgrandColor = "gray_2"
  228. fontSize = 12.0
  229. }
  230. //获取每一列的数据
  231. tmpCellList, colErr := getColList(item.DetailList[j])
  232. if colErr != nil {
  233. err = colErr
  234. return
  235. }
  236. //定义生成table列数据切片
  237. tableCelList := make([]TableCel, 0)
  238. lenCell := len(tmpCellList)
  239. for k := 0; k < len(tmpCellList); k++ {
  240. //计算出来每一列的宽度占比 start
  241. //总宽度
  242. newDecimal := decimal.NewFromFloat(100)
  243. //总列数
  244. newDecimal2 := decimal.NewFromInt(int64(lenCell))
  245. //计算出来每一列的宽度占比(四舍五入)
  246. widthPercent, _ := newDecimal.Div(newDecimal2).Round(3).Float64()
  247. //if !ok {
  248. // err = errors.New("word普通数据表格宽度百分比计算失败")
  249. // return
  250. //}
  251. //计算出来每一列的宽度占比 end
  252. tableCel := TableCel{
  253. Value: tmpCellList[k],
  254. TextAlign: "center",
  255. //ColumnSpan int `json:"column_span";description:"需要合同的列数量"`
  256. //IsMerged bool `json:"is_merged";description:"是否需要上下行合并"`
  257. Background: backgrandColor,
  258. IsBold: isBold,
  259. FontSize: fontSize,
  260. WidthPercent: widthPercent,
  261. }
  262. tableCelList = append(tableCelList, tableCel)
  263. }
  264. //将每行数据插入到table行数据切片之中
  265. tableRow := TableRow{
  266. RowList: tableCelList,
  267. }
  268. tableRowList = append(tableRowList, tableRow)
  269. }
  270. //赋值table表格数据
  271. tableDataList.List = tableRowList
  272. tableTitle = "依照《弘则研究FICC客户服务列表2022》中 小套餐 的服务内容,详细如下:"
  273. } else {
  274. //获取预设的表格数据
  275. contractServiceTemplate, tmpErr := contract.GetContractServiceTemplateById(item.ServiceTemplateId)
  276. if tmpErr != nil {
  277. err = tmpErr
  278. return
  279. }
  280. //赋值table表格数据
  281. jsonStr := contractServiceTemplate.TableValue
  282. err = json.Unmarshal([]byte(jsonStr), &tableDataList)
  283. if err != nil {
  284. return
  285. }
  286. //表头备注信息
  287. tableTitle = contractServiceTemplate.Remark
  288. }
  289. //往word中添加表格数据
  290. tmpParagraph, tmpErr := addTable(tableTitle, tableDataList, doc, nowParagraph)
  291. if tmpErr != nil {
  292. err = tmpErr
  293. return
  294. }
  295. //fmt.Println("nowParagraph:", nowParagraph, "tmpParagraph:", tmpParagraph)
  296. //fmt.Println("doc:", doc.Paragraphs())
  297. //fmt.Println("==========:")
  298. nowParagraph = tmpParagraph
  299. }
  300. default:
  301. //fmt.Println("not modifying", r.Text())
  302. }
  303. }
  304. }
  305. doc.SaveToFile(fmt.Sprint("./static/word/系统生成合同", contractDetail.ContractId, ".docx"))
  306. return
  307. }
  308. // 添加表格数据
  309. func addTable(title string, tableDataList TableData, doc *document.Document, paragraph document.Paragraph) (nowParagraph document.Paragraph, err error) {
  310. //fmt.Println("表头名称:", title)
  311. //插入一个新的段落
  312. nowParagraph = doc.InsertParagraphBefore(paragraph)
  313. nowRun := nowParagraph.AddRun()
  314. nowRun.AddBreak()
  315. //if title != "" {
  316. // fmt.Println("表头名称:", title)
  317. // nowRun.Properties().SetSize(11)
  318. // nowRun.Properties().SetBold(true)
  319. // nowRun.AddText(title)
  320. // nowRun.AddBreak()
  321. //}
  322. //再次插入一个新段落
  323. //_ = doc.InsertParagraphAfter(nowParagraph)
  324. //表格数据
  325. {
  326. table := doc.InsertTableAfter(nowParagraph)
  327. //设置表格宽度
  328. table.Properties().SetWidth(6.5 * measurement.Inch)
  329. //表格宽度设置为自动
  330. //table.Properties().SetWidthAuto()
  331. //边框
  332. borders := table.Properties().Borders()
  333. // thin borders
  334. borders.SetAll(wml.ST_BorderSingle, color.Auto, measurement.Zero)
  335. //表格数据
  336. rowList := tableDataList.List
  337. //每一列合并单元格状态map
  338. rowIsMeged := make(map[int]bool)
  339. //table.Properties().W
  340. for i := 0; i < len(rowList); i++ {
  341. //创建新的一行
  342. row := table.AddRow()
  343. //设置行高,第二个参数是设置固定值还是自动
  344. row.Properties().SetHeight(30*measurement.Point, wml.ST_HeightRuleAtLeast)
  345. //遍历列数据
  346. rowDataList := rowList[i].RowList
  347. if rowDataList != nil {
  348. for j := 0; j < len(rowDataList); j++ {
  349. //当前列是否合并
  350. var isMeged bool
  351. isMeged, ok := rowIsMeged[j]
  352. if !ok {
  353. rowIsMeged[j] = false
  354. isMeged = false
  355. }
  356. cell := row.AddCell()
  357. cellPara := cell.AddParagraph()
  358. run := cellPara.AddRun()
  359. //列数据
  360. cellData := rowDataList[j]
  361. //如果合并列大于0,那么就合并列
  362. if cellData.ColumnSpan > 0 {
  363. // column span / merged cells
  364. cell.Properties().SetColumnSpan(cellData.ColumnSpan)
  365. //_ = row.AddCell()
  366. }
  367. //如果指定了上下单元格合并,那么去合并上下单元格
  368. if cellData.IsMerged {
  369. //将当前合并单元格状态调整为true
  370. rowIsMeged[j] = true
  371. //合并单元格类型
  372. var mergeVal wml.ST_Merge
  373. if isMeged { //如果上一层已经是合并了,那么这一层是继续合并
  374. mergeVal = wml.ST_MergeContinue
  375. } else { //如果上一层不是合并,那么这一层是开始合并
  376. mergeVal = wml.ST_MergeRestart
  377. }
  378. cell.Properties().SetVerticalMerge(mergeVal)
  379. } else {
  380. //将当前合并单元格状态调整为false,这样后续如果再次碰到合并单元格操作,就是重新开始合并了
  381. rowIsMeged[j] = false
  382. }
  383. //背景色
  384. if cellData.Background != "" {
  385. cell.Properties().SetShading(wml.ST_ShdSolid, getColorConf(cellData.Background), color.Auto)
  386. }
  387. //填充内容(文字)垂直对齐方式
  388. cell.Properties().SetVerticalAlignment(wml.ST_VerticalJcCenter)
  389. //将单元格设置为宽度百分比
  390. if cellData.WidthPercent > 0 {
  391. cell.Properties().SetWidthPercent(cellData.WidthPercent)
  392. }
  393. //文字排版(居中、左、右)
  394. if cellData.TextAlign != "" {
  395. cellPara.Properties().SetAlignment(getTextAlignConf(cellData.TextAlign))
  396. //cellPara.Properties().SetAlignment(wml.ST_JcLeft)
  397. }
  398. //cell.Properties().SetAli
  399. //设置是否加粗
  400. run.Properties().SetBold(cellData.IsBold)
  401. //设置字体大小
  402. fontSize := 10.0
  403. if cellData.FontSize > 0 {
  404. fontSize = cellData.FontSize
  405. }
  406. run.Properties().SetSize(measurement.Distance(fontSize * measurement.Point))
  407. //设置段落间的间距
  408. cellPara.Properties().Spacing().SetLineSpacing(measurement.Distance(1.4*fontSize*measurement.Point), wml.ST_LineSpacingRuleAuto)
  409. //设置段前间距
  410. cellPara.Properties().Spacing().SetBefore(measurement.Distance(0.9 * fontSize * measurement.Point))
  411. //设置段后间距
  412. cellPara.Properties().Spacing().SetAfter(measurement.Distance(0.5 * fontSize * measurement.Point))
  413. //设置字体
  414. run.Properties().SetFontFamily("宋体")
  415. //设置排序
  416. run.Properties().SetVerticalAlignment(sharedTypes.ST_VerticalAlignRunBaseline)
  417. //设置显示的文字
  418. if cellData.Value != "" {
  419. strSlice := strings.Split(cellData.Value, "<br/>")
  420. for s := 0; s < len(strSlice); s++ {
  421. if s > 0 {
  422. run.AddBreak()
  423. }
  424. run.AddText(strSlice[s])
  425. }
  426. } else {
  427. run.AddText("")
  428. }
  429. }
  430. }
  431. }
  432. }
  433. return
  434. }
  435. // 获取生成word的docx模板文件
  436. func getWordPath(templateId int) string {
  437. var path string
  438. switch templateId {
  439. case 1:
  440. path = "./static/word/template_1.docx"
  441. case 2:
  442. path = "./static/word/template_2.docx"
  443. }
  444. return path
  445. }
  446. // html转pdf数据样式
  447. type html2pdfData struct {
  448. CompanyName string `description:"甲方名称"`
  449. ContractCode string `description:"合同编号"`
  450. Address string `description:"甲方地址"`
  451. PostcodeDisplay string `description:"甲方邮编;是否展示"`
  452. Postcode string `description:"甲方邮编"`
  453. PhoneDisplay string `description:"甲方电话;是否展示"`
  454. Phone string `description:"甲方电话"`
  455. FaxDisplay string `description:"传真;是否展示"`
  456. Fax string `description:"传真"`
  457. RemarkDisplay string `description:"备注;是否展示"`
  458. Remark string `description:"备注"`
  459. PayRemark string `description:"支付备注"`
  460. StartDate string `description:"合同开始日期"`
  461. EndDate string `description:"合同结束日期"`
  462. NumYear string `description:"合同有效期"`
  463. Price string `description:"支付金额"`
  464. TableHtml string `description:"表格数据"`
  465. }
  466. // GetHtmlByContractDetail 获取合同样式预览的html
  467. func GetHtmlByContractDetail(contractDetail *contract.ContractDetail, htmlType string) (contractHtml string, err error) {
  468. tmpContractDetail := *contractDetail
  469. contractTemplate, err := contract.GetContractTemplateByTemplateId(tmpContractDetail.TemplateId)
  470. if err != nil {
  471. return
  472. }
  473. // 初始化合同中一些特定区域的文字展示配置
  474. contentConfigMap := make(map[string]string)
  475. err = json.Unmarshal([]byte(contractTemplate.ContentConfig), &contentConfigMap)
  476. if err != nil {
  477. return
  478. }
  479. htmlTpl := contractTemplate.Html
  480. if htmlType == "pdf" {
  481. htmlTpl = contractTemplate.PdfHtml
  482. }
  483. myTpl := template.Must(template.New("contract").Parse(htmlTpl))
  484. //合同有效期
  485. contractServiceAndDetailList := make([]*contract.ContractServiceAndDetail, 0) //服务内容
  486. if tmpContractDetail.ContractBusinessType == "代付合同" {
  487. if tmpContractDetail.RelationContractDetailList != nil && len(tmpContractDetail.RelationContractDetailList) > 0 {
  488. tmpContractDetail.StartDate = tmpContractDetail.RelationContractDetailList[0].StartDate
  489. tmpContractDetail.EndDate = tmpContractDetail.RelationContractDetailList[0].EndDate
  490. contractServiceAndDetailList = tmpContractDetail.RelationContractDetailList[0].Service
  491. }
  492. } else {
  493. contractServiceAndDetailList = tmpContractDetail.Service
  494. }
  495. //地址
  496. address := getContractAddress(&tmpContractDetail)
  497. data := html2pdfData{
  498. CompanyName: tmpContractDetail.CompanyName,
  499. ContractCode: tmpContractDetail.ContractCode,
  500. Address: address,
  501. PostcodeDisplay: "block",
  502. Postcode: tmpContractDetail.Postcode,
  503. PhoneDisplay: "block",
  504. Phone: tmpContractDetail.Phone,
  505. FaxDisplay: "block",
  506. Fax: tmpContractDetail.Fax,
  507. RemarkDisplay: "block",
  508. Remark: tmpContractDetail.Remark,
  509. PayRemark: tmpContractDetail.PayRemark,
  510. StartDate: tmpContractDetail.StartDate.Format("2006年01月02日"),
  511. EndDate: tmpContractDetail.EndDate.Format("2006年01月02日"),
  512. }
  513. if data.Postcode == "" {
  514. data.Postcode = "无"
  515. data.PostcodeDisplay = "none"
  516. }
  517. if data.Fax == "" {
  518. data.Fax = "无"
  519. data.FaxDisplay = "none"
  520. }
  521. if data.Phone == "" {
  522. data.Phone = "无"
  523. data.PhoneDisplay = "none"
  524. }
  525. if data.PayRemark == "" {
  526. data.PayRemark = "无"
  527. }
  528. if data.Remark == "" {
  529. data.Remark = "无"
  530. data.RemarkDisplay = "none"
  531. }
  532. //合同有效期
  533. {
  534. ////合同结束日期与合同开始日期的时间差(小时差)
  535. //newDecimal := decimal.NewFromFloat(tmpContractDetail.EndDate.Sub(tmpContractDetail.StartDate).Hours())
  536. ////分母为365天 * 24 小时
  537. //newDecimal2 := decimal.NewFromInt(24 * 365)
  538. ////计算出来相差多少年,保留一位小数(四舍五入)
  539. //numYearDecimal := newDecimal.Div(newDecimal2).Round(1)
  540. ////定义最小年份差,不能小于0.1年
  541. //minDecimal := decimal.NewFromFloat(0.1)
  542. ////如果计算出来的年份差小于0.1年,那么该年份差就赋值 0.1年
  543. //if numYearDecimal.LessThan(minDecimal) {
  544. // numYearDecimal = minDecimal
  545. //}
  546. //
  547. ////合同有效期
  548. //data.NumYear = numYearDecimal.String()
  549. tmpPrintContent, tmpErr := utils.CalculationDate(tmpContractDetail.StartDate, tmpContractDetail.EndDate)
  550. if tmpErr != nil {
  551. err = tmpErr
  552. return
  553. }
  554. data.NumYear = tmpPrintContent
  555. }
  556. //合同金额
  557. {
  558. priceStr := ""
  559. //originalPrice := strconv.FormatFloat(tmpContractDetail.OriginalPrice, 'E', -1, 64)
  560. //优惠前金额(小写)
  561. //newDecimal := decimal.NewFromFloat(tmpContractDetail.OriginalPrice)
  562. originalPrice := utils.FormatPrice(tmpContractDetail.OriginalPrice)
  563. priceStr += "小写:" + originalPrice + "元,"
  564. //优惠前金额(大写)
  565. originalCnyPrice, cnyErr := utils.ConvertNumToCny(tmpContractDetail.OriginalPrice)
  566. if cnyErr != nil {
  567. err = cnyErr
  568. return
  569. }
  570. priceStr += "大写:" + originalCnyPrice
  571. //如果实际支付金额与订单原金额不符
  572. if tmpContractDetail.OriginalPrice != tmpContractDetail.Price {
  573. //优惠后的金额(小写)
  574. //newDecimal := decimal.NewFromFloat(tmpContractDetail.Price)
  575. price := utils.FormatPrice(tmpContractDetail.Price)
  576. priceStr += ",经甲乙双方友好协商,优惠至:" + price + "元,"
  577. //优惠后的金额(大写)
  578. cnyPrice, cnyErr := utils.ConvertNumToCny(tmpContractDetail.Price)
  579. if cnyErr != nil {
  580. err = cnyErr
  581. return
  582. }
  583. priceStr += "大写:" + cnyPrice
  584. }
  585. data.Price = priceStr
  586. }
  587. buf := new(bytes.Buffer) //实现了读写方法的可变大小的字节缓冲
  588. tplErr := myTpl.Execute(buf, data)
  589. if tplErr != nil {
  590. err = tplErr
  591. return
  592. }
  593. contractHtml = buf.String()
  594. //服务内容
  595. {
  596. tableStr := ""
  597. tableDataSlice := make([]TableData, 0)
  598. tableTitleSlice := make([]string, 0)
  599. title := ``
  600. if tmpTitle, ok := contentConfigMap["title1"]; ok {
  601. title = tmpTitle
  602. }
  603. for i := 0; i < len(contractServiceAndDetailList); i++ {
  604. //表格数据
  605. var tableDataList TableData
  606. item := contractServiceAndDetailList[i]
  607. //表头备注信息
  608. tableTitleSlice = append(tableTitleSlice, item.Title)
  609. //表格数据
  610. if item.HasDetail == "是" && len(item.DetailList) > 0 {
  611. //表格每行数据切片
  612. tableRowList := make([]TableRow, 0)
  613. //遍历获取table行数据
  614. for j := 0; j < len(item.DetailList); j++ {
  615. //列数据样式初始化
  616. isBold := false
  617. backgrandColor := ""
  618. fontSize := 13.0
  619. //表头数据样式
  620. if j == 0 {
  621. isBold = true
  622. backgrandColor = "gray_2"
  623. fontSize = 13.0
  624. }
  625. //获取每一列的数据
  626. tmpCellList, colErr := getColList(item.DetailList[j])
  627. if colErr != nil {
  628. err = colErr
  629. return
  630. }
  631. //定义生成table列数据切片
  632. tableCelList := make([]TableCel, 0)
  633. lenCell := len(tmpCellList)
  634. for k := 0; k < len(tmpCellList); k++ {
  635. //默认30%的宽度,如果不是第一列,那么需要额外计算
  636. widthPercent := 30.0
  637. if k > 0 {
  638. //计算出来每一列的宽度占比 start
  639. //总宽度
  640. newDecimal := decimal.NewFromFloat(70)
  641. //总列数
  642. newDecimal2 := decimal.NewFromInt(int64(lenCell) - 1)
  643. //计算出来每一列的宽度占比(四舍五入)
  644. tmpWidthPercent, _ := newDecimal.Div(newDecimal2).Round(3).Float64()
  645. //if !ok {
  646. // err = errors.New("word普通数据表格宽度百分比计算失败")
  647. // return
  648. //}
  649. widthPercent = tmpWidthPercent
  650. //计算出来每一列的宽度占比 end
  651. }
  652. tableCel := TableCel{
  653. Value: tmpCellList[k],
  654. TextAlign: "center",
  655. //ColumnSpan int `json:"column_span";description:"需要合同的列数量"`
  656. //IsMerged bool `json:"is_merged";description:"是否需要上下行合并"`
  657. Background: backgrandColor,
  658. IsBold: isBold,
  659. FontSize: fontSize,
  660. WidthPercent: widthPercent,
  661. }
  662. tableCelList = append(tableCelList, tableCel)
  663. }
  664. //将每行数据插入到table行数据切片之中
  665. tableRow := TableRow{
  666. RowList: tableCelList,
  667. }
  668. tableRowList = append(tableRowList, tableRow)
  669. }
  670. //赋值table表格数据
  671. tableDataList.List = tableRowList
  672. } else {
  673. //赋值table表格数据
  674. jsonStr := item.TableValue
  675. tmpEerr := json.Unmarshal([]byte(jsonStr), &tableDataList)
  676. if tmpEerr != nil {
  677. err = tmpEerr
  678. return
  679. }
  680. }
  681. tableDataSlice = append(tableDataSlice, tableDataList)
  682. }
  683. titleStr := strings.Join(tableTitleSlice, "、")
  684. title += titleStr + "的服务内容,详细如下:"
  685. if htmlType == "pdf" {
  686. tableStr += `<p style="">` + title + `</p>`
  687. } else {
  688. tableStr = `<p style="font-size: 13pt; line-height: 40px">` + title + `</p>`
  689. }
  690. for _, tableDataList := range tableDataSlice {
  691. //往word中添加表格数据
  692. if htmlType == "pdf" {
  693. tableStr += getTableStrByPdf(tableDataList)
  694. } else {
  695. tableStr += getTableStr(tableDataList)
  696. }
  697. }
  698. data.TableHtml = tableStr
  699. }
  700. //fmt.Println("TableHtml:", data.TableHtml)
  701. contractHtml = strings.Replace(contractHtml, `\{\{\{TableHtml\}\}\}`, data.TableHtml, -1)
  702. return
  703. //生成pdf
  704. //pdfPath := fmt.Sprint("./static/word/系统生成合同", contractDetail.ContractCode, ".pdf")
  705. //err = Html2Pdf(contractHtml, pdfPath)
  706. //if err != nil {
  707. // return
  708. //}
  709. ////defer func() {
  710. //// //删除对应的Pdf
  711. //// os.Remove(pdfPath)
  712. ////}()
  713. //
  714. //return
  715. }
  716. // 生成合同服务的预览表格html代码
  717. func getTableStr(tableDataList TableData) (tableStr string) {
  718. //如果表格需要分页,那么在table的style里面添加该配置:page-break-inside: avoid !important
  719. tableStr += `<table style="width: 100%;border-collapse: collapse;font-size: 13pt;margin-bottom:30px;page-break-inside: avoid !important;"><tbody>`
  720. rowList := tableDataList.List
  721. for i := 0; i < len(rowList); i++ {
  722. //创建新的一行
  723. tableStr += `<tr style="`
  724. tableStr += `page-break-before: always;page-break-after: always;page-break-inside: avoid !important;`
  725. //background-color: #F0F2F5;
  726. tableStr += `">`
  727. //<td style="border-right:1px solid #808181;border-bottom:1px solid #808181;padding: 15px 10px;font-weight: bold;" colspan="5">2.市场跟踪类报告</td>
  728. //row := table.AddRow()
  729. ////设置行高,第二个参数是设置固定值还是自动
  730. //row.Properties().SetHeight(30*measurement.Point, wml.ST_HeightRuleAtLeast)
  731. //
  732. //遍历列数据
  733. rowDataList := rowList[i].RowList
  734. cellStr := ""
  735. if rowDataList != nil {
  736. for j := 0; j < len(rowDataList); j++ {
  737. //当前列是否合并
  738. // <td style="font-weight: bold;" colspan="5">2.市场跟踪类报告</td>
  739. // <td style="" align="center" rowspan="3">市场跟踪</td>
  740. // <td style="" align="center">市场估值</td>
  741. tdStr := `<td `
  742. //单元格样式
  743. styleStr := `style="`
  744. styleStr += `border:1px solid #808181;padding: 15px 10px;line-height: 1.5;`
  745. //其他参数
  746. cellOtherStr := ` valign="middle" `
  747. //列数据
  748. cellData := rowDataList[j]
  749. //如果合并列大于0,那么就合并列
  750. if cellData.ColumnSpan > 0 {
  751. // column span / merged cells
  752. cellOtherStr += ` colspan="` + strconv.Itoa(cellData.ColumnSpan) + `" `
  753. }
  754. //如果指定了上下单元格合并,那么去合并上下单元格
  755. if cellData.IsMerged {
  756. if cellData.IsFirstMerged {
  757. cellOtherStr += ` rowspan="` + strconv.Itoa(cellData.RowSpan) + `" `
  758. } else {
  759. //如果是合并行,且不是第一行,那么就退出当前单元格循环,进入下一个循环
  760. continue
  761. }
  762. }
  763. //背景色
  764. if cellData.Background != "" {
  765. styleStr += `background-color: #F0F2F5;`
  766. }
  767. //将单元格设置为宽度百分比
  768. if cellData.WidthPercent > 0 {
  769. widthDecimal := decimal.NewFromFloat(cellData.WidthPercent)
  770. cellOtherStr += ` width="` + widthDecimal.String() + `%" `
  771. }
  772. //文字排版(居中、左、右)
  773. if cellData.TextAlign != "" {
  774. cellOtherStr += ` align="` + cellData.TextAlign + `" `
  775. }
  776. //cell.Properties().SetAli
  777. //设置是否加粗
  778. if cellData.IsBold {
  779. styleStr += `font-weight:bold;`
  780. }
  781. //设置字体大小
  782. fontSize := 10.0
  783. if cellData.FontSize > 0 {
  784. fontSize = cellData.FontSize
  785. }
  786. fontDecimal := decimal.NewFromFloat(fontSize)
  787. styleStr += `font-size: ` + fontDecimal.String() + `pt;`
  788. bodyStr := cellData.Value
  789. styleStr += `" `
  790. cellStr += tdStr + styleStr + cellOtherStr + `>` + bodyStr + `</td>`
  791. }
  792. }
  793. tableStr += cellStr + `</tr>`
  794. }
  795. tableStr += `</tbody></table>`
  796. return
  797. }
  798. // getTableStrByPdf 生成合同服务的pdf表格html代码
  799. func getTableStrByPdf(tableDataList TableData) (tableStr string) {
  800. //如果表格需要分页,那么在table的style里面添加该配置:page-break-inside: avoid !important
  801. tableStr += `<table style="width: 100%;border-collapse: collapse;margin-top:10pt;page-break-inside: avoid !important;"><tbody>`
  802. rowList := tableDataList.List
  803. for i := 0; i < len(rowList); i++ {
  804. //创建新的一行
  805. tableStr += `<tr style="`
  806. tableStr += `page-break-before: always;page-break-after: always;page-break-inside: avoid !important;`
  807. //background-color: #F0F2F5;
  808. tableStr += `">`
  809. //<td style="border-right:1px solid #808181;border-bottom:1px solid #808181;padding: 15px 10px;font-weight: bold;" colspan="5">2.市场跟踪类报告</td>
  810. //row := table.AddRow()
  811. ////设置行高,第二个参数是设置固定值还是自动
  812. //row.Properties().SetHeight(30*measurement.Point, wml.ST_HeightRuleAtLeast)
  813. //
  814. //遍历列数据
  815. rowDataList := rowList[i].RowList
  816. cellStr := ""
  817. if rowDataList != nil {
  818. for j := 0; j < len(rowDataList); j++ {
  819. //当前列是否合并
  820. // <td style="font-weight: bold;" colspan="5">2.市场跟踪类报告</td>
  821. // <td style="" align="center" rowspan="3">市场跟踪</td>
  822. // <td style="" align="center">市场估值</td>
  823. tdStr := `<td `
  824. //单元格样式
  825. styleStr := `style="`
  826. styleStr += `border:1px solid #808181;padding:4pt 10pt;`
  827. //其他参数
  828. cellOtherStr := ` valign="middle" `
  829. //列数据
  830. cellData := rowDataList[j]
  831. //如果合并列大于0,那么就合并列
  832. if cellData.ColumnSpan > 0 {
  833. // column span / merged cells
  834. cellOtherStr += ` colspan="` + strconv.Itoa(cellData.ColumnSpan) + `" `
  835. }
  836. //如果指定了上下单元格合并,那么去合并上下单元格
  837. if cellData.IsMerged {
  838. if cellData.IsFirstMerged {
  839. cellOtherStr += ` rowspan="` + strconv.Itoa(cellData.RowSpan) + `" `
  840. } else {
  841. //如果是合并行,且不是第一行,那么就退出当前单元格循环,进入下一个循环
  842. continue
  843. }
  844. }
  845. //背景色
  846. if cellData.Background != "" {
  847. styleStr += `background-color: #F0F2F5;`
  848. }
  849. //将单元格设置为宽度百分比
  850. if cellData.WidthPercent > 0 {
  851. widthDecimal := decimal.NewFromFloat(cellData.WidthPercent)
  852. cellOtherStr += ` width="` + widthDecimal.String() + `%" `
  853. }
  854. //文字排版(居中、左、右)
  855. if cellData.TextAlign != "" {
  856. cellOtherStr += ` align="` + cellData.TextAlign + `" `
  857. }
  858. //cell.Properties().SetAli
  859. //设置是否加粗
  860. if cellData.IsBold {
  861. styleStr += `font-weight:bold;`
  862. }
  863. //设置字体大小
  864. fontSize := 10.0
  865. if cellData.FontSize > 0 {
  866. fontSize = cellData.FontSize
  867. }
  868. fontDecimal := decimal.NewFromFloat(fontSize)
  869. styleStr += `font-size: ` + fontDecimal.String() + `pt;`
  870. bodyStr := cellData.Value
  871. styleStr += `" `
  872. cellStr += tdStr + styleStr + cellOtherStr + `>` + bodyStr + `</td>`
  873. }
  874. }
  875. tableStr += cellStr + `</tr>`
  876. }
  877. tableStr += `</tbody></table>`
  878. return
  879. }
  880. // Html2Pdf 根据html生成pdf
  881. func Html2Pdf(htmlStr, pdfPath string) (err error) {
  882. pdfg, err := wkhtml.NewPDFGenerator()
  883. if err != nil {
  884. fmt.Println("err:", err)
  885. return
  886. }
  887. //通过html生成page
  888. page := wkhtml.NewPageReader(strings.NewReader(htmlStr))
  889. //页眉设置
  890. //page.HeaderLeft.Set("弘则弥道(上海)投资咨询有限公司")
  891. //page.HeaderFontName.Set("宋体")
  892. //page.HeaderFontSize.Set(8)
  893. //page.HeaderSpacing.Set(4)
  894. //page.HeaderLine.Set(true)
  895. //page.HeaderSpacing.Set(10)
  896. //页脚设置
  897. page.FooterFontSize.Set(8)
  898. page.FooterRight.Set("[page]")
  899. page.FooterSpacing.Set(4)
  900. //page.FooterLine.Set(true)
  901. //page.EnableForms.Set(false)
  902. //转换HTML表单为PDF表单
  903. //page.EnableForms.Set(true)
  904. //使用打印媒体类型而不是屏幕
  905. //page.PrintMediaType.Set(true)
  906. //允许从标题链接到目录
  907. page.EnableTocBackLinks.Set(true)
  908. //将该page插入到pdf中
  909. pdfg.AddPage(page)
  910. //pdfg.PageSize.Set(wkhtml.PageSizeA4)
  911. //pdfg.MarginTop.Set(20)
  912. //pdfg.MarginBottom.Set(5)
  913. //pdfg.MarginLeft.Set(0)
  914. //pdfg.
  915. err = pdfg.Create()
  916. if err != nil {
  917. return
  918. }
  919. err = pdfg.WriteFile(pdfPath)
  920. return
  921. }
  922. // getColList 获取表格列数据
  923. func getColList(item *contract.ContractServiceDetail) (cellList []string, err error) {
  924. cellList = make([]string, 0)
  925. var serviceDetailReq request.AddContractServiceDetailReq
  926. tmpItem := *item
  927. t := reflect.TypeOf(tmpItem)
  928. v := reflect.ValueOf(tmpItem)
  929. for k := 0; k < t.NumField(); k++ {
  930. //获取结构体的参数名
  931. tmpName := t.Field(k).Name
  932. if strings.Contains(tmpName, "Col") {
  933. //获取结构体该参数名的值
  934. tmpValue := v.Field(k).String()
  935. //如果值不为空的话,那么做下json转换
  936. if tmpValue != "" {
  937. err = json.Unmarshal([]byte(tmpValue), &serviceDetailReq)
  938. if err != nil {
  939. return
  940. } else {
  941. cellList = append(cellList, serviceDetailReq.Value)
  942. }
  943. }
  944. }
  945. }
  946. return
  947. }
  948. type WordElement struct {
  949. ElementType string `json:"element_type" description:"元素类型"`
  950. ElementName string `json:"element_name" description:"元素名称"`
  951. RelationName string `json:"relation_name" description:"关联元素名称"`
  952. Content string `json:"content" description:"元素内容"`
  953. Background string `json:"background" description:"背景色"`
  954. IsBold bool `json:"is_bold" description:"是否加粗显示"`
  955. TextAlign string `json:"text_align" description:"对齐方式"`
  956. FontSize float64 `json:"font_size" description:"字体大小"`
  957. ElementList []WordElement `json:"list" description:"子元素"`
  958. }
  959. // GenerateWordV2 生成word
  960. func GenerateWordV2(contractDetail *contract.ContractDetail, wordPath string) (err error) {
  961. //临时合同信息
  962. tmpContractDetail := *contractDetail
  963. //合同服务
  964. contractServiceAndDetailList := make([]*contract.ContractServiceAndDetail, 0) //服务内容
  965. if tmpContractDetail.ContractBusinessType == "代付合同" {
  966. if contractDetail.RelationContractDetailList != nil && len(contractDetail.RelationContractDetailList) > 0 {
  967. tmpContractDetail.StartDate = tmpContractDetail.RelationContractDetailList[0].StartDate
  968. tmpContractDetail.EndDate = tmpContractDetail.RelationContractDetailList[0].EndDate
  969. contractServiceAndDetailList = tmpContractDetail.RelationContractDetailList[0].Service
  970. }
  971. } else {
  972. contractServiceAndDetailList = tmpContractDetail.Service
  973. }
  974. contractTemplate, err := contract.GetContractTemplateByTemplateId(tmpContractDetail.TemplateId)
  975. if err != nil {
  976. return
  977. }
  978. // 初始化合同中一些特定区域的文字展示配置
  979. contentConfigMap := make(map[string]string)
  980. err = json.Unmarshal([]byte(contractTemplate.ContentConfig), &contentConfigMap)
  981. if err != nil {
  982. return
  983. }
  984. //合同信息参数
  985. jsonStr := contractTemplate.WordConfig
  986. var contractData []WordElement
  987. err = json.Unmarshal([]byte(jsonStr), &contractData)
  988. if err != nil {
  989. fmt.Println("json字符串解析失败,ERR:", err)
  990. return
  991. }
  992. doc := document.New()
  993. //word的属性设置,类型,作者之类的
  994. cp := doc.CoreProperties
  995. // And change them as well
  996. cp.SetTitle("弘则弥道(上海)投资咨询有限公司 & 研究服务合同")
  997. cp.SetAuthor("弘则弥道(上海)投资咨询有限公司")
  998. cp.SetCategory("合同")
  999. //cp.SetContentStatus("Draft")
  1000. cp.SetLastModifiedBy("弘则弥道(上海)投资咨询有限公司")
  1001. cp.SetCreated(time.Now())
  1002. cp.SetModified(time.Now())
  1003. cp.SetDescription("弘则弥道(上海)投资咨询有限公司 研究服务合同")
  1004. cp.SetLanguage("中文")
  1005. tableFontSize := 10.5 //默认表格内文字10.5
  1006. for _, data := range contractData {
  1007. fontSize := data.FontSize
  1008. if fontSize <= 0 {
  1009. fontSize = 15
  1010. }
  1011. printContent := ``
  1012. if data.ElementName == "services" {
  1013. tableTitleSlice := make([]string, 0)
  1014. title := ``
  1015. if tmpTitle, ok := contentConfigMap["title1"]; ok {
  1016. title = tmpTitle
  1017. }
  1018. TableDataListSlice := make([]TableData, 0)
  1019. //for i := len(contractServiceAndDetailList) - 1; i >= 0; i-- {
  1020. for i := 0; i < len(contractServiceAndDetailList); i++ {
  1021. //表格数据
  1022. var tableDataList TableData
  1023. item := contractServiceAndDetailList[i]
  1024. //表头备注信息
  1025. tableTitleSlice = append(tableTitleSlice, item.Title)
  1026. //表格数据
  1027. if item.HasDetail == "是" && len(item.DetailList) > 0 {
  1028. //表格每行数据切片
  1029. tableRowList := make([]TableRow, 0)
  1030. //遍历获取table行数据
  1031. for j := 0; j < len(item.DetailList); j++ {
  1032. //列数据样式初始化
  1033. isBold := false
  1034. backgrandColor := ""
  1035. fontSize := tableFontSize
  1036. //表头数据样式
  1037. if j == 0 {
  1038. isBold = true
  1039. backgrandColor = "gray_2"
  1040. }
  1041. //获取每一列的数据
  1042. tmpCellList, colErr := getColList(item.DetailList[j])
  1043. if colErr != nil {
  1044. err = colErr
  1045. return
  1046. }
  1047. //定义生成table列数据切片
  1048. tableCelList := make([]TableCel, 0)
  1049. lenCell := len(tmpCellList)
  1050. for k := 0; k < len(tmpCellList); k++ {
  1051. //计算出来每一列的宽度占比 start
  1052. //总宽度
  1053. newDecimal := decimal.NewFromFloat(100)
  1054. //总列数
  1055. newDecimal2 := decimal.NewFromInt(int64(lenCell))
  1056. //计算出来每一列的宽度占比(四舍五入)
  1057. widthPercent, _ := newDecimal.Div(newDecimal2).Round(3).Float64()
  1058. //if !ok {
  1059. // err = errors.New("word普通数据表格宽度百分比计算失败")
  1060. // return
  1061. //}
  1062. //计算出来每一列的宽度占比 end
  1063. tableCel := TableCel{
  1064. Value: tmpCellList[k],
  1065. TextAlign: "center",
  1066. //ColumnSpan int `json:"column_span";description:"需要合同的列数量"`
  1067. //IsMerged bool `json:"is_merged";description:"是否需要上下行合并"`
  1068. Background: backgrandColor,
  1069. IsBold: isBold,
  1070. FontSize: fontSize,
  1071. WidthPercent: widthPercent,
  1072. }
  1073. tableCelList = append(tableCelList, tableCel)
  1074. }
  1075. //将每行数据插入到table行数据切片之中
  1076. tableRow := TableRow{
  1077. RowList: tableCelList,
  1078. }
  1079. tableRowList = append(tableRowList, tableRow)
  1080. }
  1081. //赋值table表格数据
  1082. tableDataList.List = tableRowList
  1083. } else {
  1084. //赋值table表格数据
  1085. jsonStr := item.TableValue
  1086. err = json.Unmarshal([]byte(jsonStr), &tableDataList)
  1087. if err != nil {
  1088. return
  1089. }
  1090. }
  1091. //往word中添加表格数据
  1092. TableDataListSlice = append(TableDataListSlice, tableDataList)
  1093. }
  1094. //表格标题
  1095. titleStr := strings.Join(tableTitleSlice, "、")
  1096. title += titleStr + "的服务内容,详细如下:"
  1097. //开始一个新的段落
  1098. headerPar := doc.AddParagraph()
  1099. headerParPro := headerPar.Properties()
  1100. //headerParPro.AddTabStop()
  1101. textAlign := getTextAlignConf(data.TextAlign)
  1102. headerParPro.SetAlignment(textAlign)
  1103. //if data.ElementType == "column" {
  1104. // headerParPro.SetAlignment(wml.ST_JcBoth)
  1105. //}
  1106. headerRun := headerPar.AddRun()
  1107. headerRunPro := headerRun.Properties()
  1108. headerRunPro.SetBold(data.IsBold)
  1109. headerRunPro.SetSize(measurement.Distance(fontSize * measurement.Point))
  1110. headerRunPro.SetFontFamily("宋体")
  1111. //headerRunPro.SetKerning(measurement.Distance(2 * fontSize * measurement.Point))
  1112. headerRun.AddText(title)
  1113. //生成表格
  1114. for _, tableDataList := range TableDataListSlice {
  1115. tmpErr := addTableV2(tableDataList, doc)
  1116. if tmpErr != nil {
  1117. err = tmpErr
  1118. return
  1119. }
  1120. }
  1121. continue
  1122. } else {
  1123. isPrint, tmpPrintContent, tmpErr := getPrintData(data, &tmpContractDetail)
  1124. if tmpErr != nil {
  1125. err = tmpErr
  1126. return
  1127. }
  1128. if isPrint == false {
  1129. continue
  1130. }
  1131. printContent = tmpPrintContent
  1132. }
  1133. //分栏的宽度
  1134. //columnWidth := 240.00
  1135. printContentRune := []rune(printContent)
  1136. strLen := len(printContentRune)
  1137. //width := fontSize * float64(strLen)
  1138. //tabNum := 0.0
  1139. addTabNum := 0
  1140. printContentList := make([]map[int]string, 0)
  1141. firstLen := 17
  1142. secondLen := 14
  1143. if data.ElementType == "column" {
  1144. if strLen > firstLen {
  1145. maxLine := ((strLen - firstLen) / secondLen) + 1
  1146. for i := 0; i < maxLine; i++ {
  1147. printContentMap := make(map[int]string)
  1148. startIndex := secondLen*i + firstLen
  1149. endIndex := secondLen*(i+1) + firstLen
  1150. if endIndex > strLen {
  1151. endIndex = strLen
  1152. }
  1153. tmpPrintContent := string(printContentRune[startIndex:endIndex])
  1154. printContentMap[0] = tmpPrintContent
  1155. printContentList = append(printContentList, printContentMap)
  1156. }
  1157. printContent = string(printContentRune[:firstLen])
  1158. strLen = firstLen
  1159. //重新计算宽度
  1160. //width = fontSize * float64(strLen)
  1161. //addTabNum = 3
  1162. } else {
  1163. addTabNum = firstLen - strLen
  1164. }
  1165. addTabNum += 3
  1166. }
  1167. //开始一个新的段落
  1168. headerPar := doc.AddParagraph()
  1169. headerParPro := headerPar.Properties()
  1170. headerParPro.Spacing().SetLineSpacing(measurement.Distance(1.5*fontSize*measurement.Point), wml.ST_LineSpacingRuleAuto)
  1171. //headerParPro.AddTabStop()
  1172. textAlign := getTextAlignConf(data.TextAlign)
  1173. headerParPro.SetAlignment(textAlign)
  1174. //if data.ElementType == "column" {
  1175. // headerParPro.SetAlignment(wml.ST_JcBoth)
  1176. //}
  1177. headerRun := headerPar.AddRun()
  1178. headerRunPro := headerRun.Properties()
  1179. headerRunPro.SetBold(data.IsBold)
  1180. headerRunPro.SetSize(measurement.Distance(fontSize * measurement.Point))
  1181. headerRunPro.SetFontFamily("宋体")
  1182. //headerRunPro.SetKerning(measurement.Distance(2 * fontSize * measurement.Point))
  1183. headerRun.AddText(printContent)
  1184. for _, text := range data.ElementList {
  1185. if text.ElementName == "services" {
  1186. tableTitleSlice := make([]string, 0)
  1187. title := ``
  1188. if tmpTitle, ok := contentConfigMap["title1"]; ok {
  1189. title = tmpTitle
  1190. }
  1191. TableDataListSlice := make([]TableData, 0)
  1192. for i := len(contractServiceAndDetailList) - 1; i >= 0; i-- {
  1193. //表格数据
  1194. var tableDataList TableData
  1195. item := contractServiceAndDetailList[i]
  1196. //表头备注信息
  1197. tableTitleSlice = append(tableTitleSlice, item.Title)
  1198. //表格数据
  1199. if item.HasDetail == "是" && len(item.DetailList) > 0 {
  1200. //表格每行数据切片
  1201. tableRowList := make([]TableRow, 0)
  1202. //遍历获取table行数据
  1203. for j := 0; j < len(item.DetailList); j++ {
  1204. //列数据样式初始化
  1205. isBold := false
  1206. backgrandColor := ""
  1207. fontSize := tableFontSize
  1208. //表头数据样式
  1209. if j == 0 {
  1210. isBold = true
  1211. backgrandColor = "gray_2"
  1212. }
  1213. //获取每一列的数据
  1214. tmpCellList, colErr := getColList(item.DetailList[j])
  1215. if colErr != nil {
  1216. err = colErr
  1217. return
  1218. }
  1219. //定义生成table列数据切片
  1220. tableCelList := make([]TableCel, 0)
  1221. lenCell := len(tmpCellList)
  1222. for k := 0; k < len(tmpCellList); k++ {
  1223. //计算出来每一列的宽度占比 start
  1224. //总宽度
  1225. newDecimal := decimal.NewFromFloat(100)
  1226. //总列数
  1227. newDecimal2 := decimal.NewFromInt(int64(lenCell))
  1228. //计算出来每一列的宽度占比(四舍五入)
  1229. widthPercent, _ := newDecimal.Div(newDecimal2).Round(3).Float64()
  1230. //if !ok {
  1231. // err = errors.New("word普通数据表格宽度百分比计算失败")
  1232. // return
  1233. //}
  1234. //计算出来每一列的宽度占比 end
  1235. tableCel := TableCel{
  1236. Value: tmpCellList[k],
  1237. TextAlign: "center",
  1238. //ColumnSpan int `json:"column_span";description:"需要合同的列数量"`
  1239. //IsMerged bool `json:"is_merged";description:"是否需要上下行合并"`
  1240. Background: backgrandColor,
  1241. IsBold: isBold,
  1242. FontSize: fontSize,
  1243. WidthPercent: widthPercent,
  1244. }
  1245. tableCelList = append(tableCelList, tableCel)
  1246. }
  1247. //将每行数据插入到table行数据切片之中
  1248. tableRow := TableRow{
  1249. RowList: tableCelList,
  1250. }
  1251. tableRowList = append(tableRowList, tableRow)
  1252. }
  1253. //赋值table表格数据
  1254. tableDataList.List = tableRowList
  1255. } else {
  1256. //赋值table表格数据
  1257. jsonStr := item.TableValue
  1258. err = json.Unmarshal([]byte(jsonStr), &tableDataList)
  1259. if err != nil {
  1260. return
  1261. }
  1262. }
  1263. //往word中添加表格数据
  1264. TableDataListSlice = append(TableDataListSlice, tableDataList)
  1265. }
  1266. //表格标题
  1267. titleStr := strings.Join(tableTitleSlice, "、")
  1268. title += titleStr + "的服务内容,详细如下:"
  1269. headerRun := headerPar.AddRun()
  1270. headerRun.AddBreak()
  1271. headerRunPro := headerRun.Properties()
  1272. headerRunPro.SetBold(text.IsBold)
  1273. headerRunPro.SetSize(measurement.Distance(fontSize * measurement.Point))
  1274. headerRunPro.SetFontFamily("宋体")
  1275. //headerRunPro.SetKerning(measurement.Distance(2 * fontSize * measurement.Point))
  1276. headerRun.AddText(title)
  1277. //生成表格
  1278. for _, tableDataList := range TableDataListSlice {
  1279. tmpErr := addTableV2(tableDataList, doc)
  1280. if tmpErr != nil {
  1281. err = tmpErr
  1282. return
  1283. }
  1284. }
  1285. } else {
  1286. isPrint, printContent, tmpErr := getPrintData(text, &tmpContractDetail)
  1287. if tmpErr != nil {
  1288. err = tmpErr
  1289. return
  1290. }
  1291. if isPrint == false {
  1292. continue
  1293. }
  1294. if data.ElementType == "column" {
  1295. for j := 0; j < addTabNum; j++ {
  1296. tabStr := " "
  1297. printContent = tabStr + printContent
  1298. }
  1299. }
  1300. fontSize := text.FontSize
  1301. if fontSize <= 0 {
  1302. fontSize = 15
  1303. }
  1304. headerRun2 := headerPar.AddRun()
  1305. headerRunPro2 := headerRun2.Properties()
  1306. headerRunPro2.SetBold(text.IsBold)
  1307. headerRunPro2.SetSize(measurement.Distance(fontSize * measurement.Point))
  1308. headerRunPro2.SetFontFamily("宋体")
  1309. //headerRunPro2.SetKerning(measurement.Distance(2 * fontSize * measurement.Point))
  1310. headerRun2.AddText(printContent)
  1311. }
  1312. }
  1313. for _, printMap := range printContentList {
  1314. //开始一个新的段落
  1315. headerPar := doc.AddParagraph()
  1316. headerParPro := headerPar.Properties()
  1317. headerParPro.Spacing().SetLineSpacing(measurement.Distance(1.5*fontSize*measurement.Point), wml.ST_LineSpacingRuleAuto)
  1318. //headerParPro.AddTabStop()
  1319. textAlign := getTextAlignConf(data.TextAlign)
  1320. headerParPro.SetAlignment(textAlign)
  1321. //空出三个字符出来,避免签名顶在最前方展示
  1322. headerParPro.SetStartIndent(measurement.Distance(3 * fontSize * measurement.Point))
  1323. //if data.ElementType == "column" {
  1324. // for j := 0; j < 3; j++ {
  1325. // printContent = " " + printContent
  1326. // }
  1327. //}
  1328. //printContent = " " + printContent
  1329. headerRun := headerPar.AddRun()
  1330. headerRunPro := headerRun.Properties()
  1331. headerRunPro.SetBold(data.IsBold)
  1332. headerRunPro.SetSize(measurement.Distance(fontSize * measurement.Point))
  1333. headerRunPro.SetFontFamily("宋体")
  1334. //headerRunPro.SetKerning(measurement.Distance(2 * fontSize * measurement.Point))
  1335. headerRun.AddText(printMap[0])
  1336. }
  1337. }
  1338. //for _, data := range list {
  1339. // headerPar := doc.AddParagraph()
  1340. // headerParPro := headerPar.Properties()
  1341. // headerParPro.SetAlignment(wml.ST_JcCenter)
  1342. // headerRun := headerPar.AddRun()
  1343. // headerRunPro := headerRun.Properties()
  1344. // headerRunPro.SetBold(true)
  1345. // headerRunPro.SetSize(16)
  1346. // headerRun.AddText(data)
  1347. //}
  1348. err = doc.SaveToFile(wordPath)
  1349. return
  1350. }
  1351. // getPrintData 获取打印数据
  1352. func getPrintData(data WordElement, contractDetail *contract.ContractDetail) (isPrint bool, printContent string, err error) {
  1353. printContent = data.Content
  1354. if data.RelationName != "" {
  1355. switch data.RelationName {
  1356. case "address":
  1357. if contractDetail.Address == "" && contractDetail.Province == "" && contractDetail.City == "" {
  1358. return
  1359. }
  1360. case "postcode":
  1361. if contractDetail.Postcode == "" {
  1362. return
  1363. }
  1364. case "phone":
  1365. if contractDetail.Phone == "" {
  1366. return
  1367. }
  1368. case "fax":
  1369. if contractDetail.Fax == "" {
  1370. return
  1371. }
  1372. case "remark":
  1373. if contractDetail.Remark == "" {
  1374. return
  1375. }
  1376. case "price":
  1377. //实际金额(小写)
  1378. if contractDetail.OriginalPrice == contractDetail.Price {
  1379. return
  1380. }
  1381. case "price_cn":
  1382. //实际金额(大写)
  1383. if contractDetail.OriginalPrice == contractDetail.Price {
  1384. return
  1385. }
  1386. case "pay_remark":
  1387. if contractDetail.PayRemark == "" {
  1388. return
  1389. }
  1390. case "company_name":
  1391. if contractDetail.CompanyName == "" {
  1392. return
  1393. }
  1394. }
  1395. }
  1396. switch data.ElementName {
  1397. case "address":
  1398. if contractDetail.Address == "" && contractDetail.Province == "" && contractDetail.City == "" {
  1399. return
  1400. }
  1401. printContent = getContractAddress(contractDetail)
  1402. case "postcode":
  1403. if contractDetail.Postcode == "" {
  1404. return
  1405. }
  1406. printContent = contractDetail.Postcode
  1407. case "phone":
  1408. if contractDetail.Phone == "" {
  1409. return
  1410. }
  1411. printContent = contractDetail.Phone
  1412. case "fax":
  1413. if contractDetail.Fax == "" {
  1414. return
  1415. }
  1416. printContent = contractDetail.Fax
  1417. case "remark":
  1418. if contractDetail.Remark == "" {
  1419. return
  1420. }
  1421. printContent = contractDetail.Remark
  1422. case "start_date":
  1423. printContent = contractDetail.StartDate.Format("2006年01月02日")
  1424. case "end_date":
  1425. printContent = contractDetail.EndDate.Format("2006年01月02日")
  1426. case "num_year":
  1427. ////合同结束日期与合同开始日期的时间差(小时差)
  1428. //newDecimal := decimal.NewFromFloat(contractDetail.EndDate.Sub(contractDetail.StartDate).Hours())
  1429. ////分母为365天 * 24 小时
  1430. //newDecimal2 := decimal.NewFromInt(24 * 365)
  1431. ////计算出来相差多少年,保留一位小数(四舍五入)
  1432. //numYearDecimal := newDecimal.Div(newDecimal2).Round(1)
  1433. ////定义最小年份差,不能小于0.1年
  1434. //minDecimal := decimal.NewFromFloat(0.1)
  1435. ////如果计算出来的年份差小于0.1年,那么该年份差就赋值 0.1年
  1436. //if numYearDecimal.LessThan(minDecimal) {
  1437. // numYearDecimal = minDecimal
  1438. //}
  1439. //printContent = numYearDecimal.String()
  1440. tmpPrintContent, tmpErr := utils.CalculationDate(contractDetail.StartDate, contractDetail.EndDate)
  1441. if tmpErr != nil {
  1442. err = tmpErr
  1443. return
  1444. }
  1445. printContent = tmpPrintContent
  1446. case "original_price":
  1447. //优惠前金额(小写)
  1448. //newDecimal := decimal.NewFromFloat(contractDetail.OriginalPrice)
  1449. printContent = utils.FormatPrice(contractDetail.OriginalPrice)
  1450. case "original_price_cn":
  1451. //优惠前金额(大写)
  1452. originalCnyPrice, cnyErr := utils.ConvertNumToCny(contractDetail.OriginalPrice)
  1453. if cnyErr != nil {
  1454. err = cnyErr
  1455. return
  1456. }
  1457. printContent = originalCnyPrice
  1458. case "price":
  1459. //实际金额(小写)
  1460. if contractDetail.OriginalPrice == contractDetail.Price {
  1461. return
  1462. }
  1463. //newDecimal := decimal.NewFromFloat(contractDetail.Price)
  1464. printContent = utils.FormatPrice(contractDetail.Price)
  1465. case "price_cn":
  1466. //实际金额(大写)
  1467. if contractDetail.OriginalPrice == contractDetail.Price {
  1468. return
  1469. }
  1470. cnyPrice, cnyErr := utils.ConvertNumToCny(contractDetail.Price)
  1471. if cnyErr != nil {
  1472. err = cnyErr
  1473. return
  1474. }
  1475. printContent = cnyPrice
  1476. case "pay_remark":
  1477. if contractDetail.PayRemark == "" {
  1478. return
  1479. }
  1480. printContent = contractDetail.PayRemark
  1481. case "company_name":
  1482. if contractDetail.CompanyName == "" {
  1483. return
  1484. }
  1485. printContent = contractDetail.CompanyName
  1486. case "company_name_sign":
  1487. if contractDetail.CompanyName == "" {
  1488. return
  1489. }
  1490. printContent = "甲方:" + contractDetail.CompanyName
  1491. }
  1492. isPrint = true
  1493. return
  1494. }
  1495. // addTableV2 添加表格数据
  1496. func addTableV2(tableDataList TableData, doc *document.Document) (err error) {
  1497. //fmt.Println("表头名称:", title)
  1498. //插入一个新的段落
  1499. //nowParagraph := doc.AddParagraph()
  1500. //doc.AddParagraph()
  1501. //表格数据
  1502. doc.AddParagraph().Properties().AddSection(wml.ST_SectionMarkNextPage)
  1503. table := doc.AddTable()
  1504. //设置表格宽度
  1505. tableWidth := 6.5
  1506. table.Properties().SetWidth(measurement.Distance(tableWidth * measurement.Inch))
  1507. //表格宽度设置为自动
  1508. //table.Properties().SetWidthAuto()
  1509. //边框
  1510. borders := table.Properties().Borders()
  1511. // thin borders
  1512. borders.SetAll(wml.ST_BorderSingle, color.Auto, measurement.Zero)
  1513. //表格数据
  1514. rowList := tableDataList.List
  1515. //table.Properties().W
  1516. for i := 0; i < len(rowList); i++ {
  1517. //创建新的一行
  1518. row := table.AddRow()
  1519. //设置行高,第二个参数是设置固定值还是自动
  1520. row.Properties().SetHeight(20*measurement.Point, wml.ST_HeightRuleAtLeast)
  1521. //遍历列数据
  1522. rowDataList := rowList[i].RowList
  1523. if rowDataList != nil {
  1524. for j := 0; j < len(rowDataList); j++ {
  1525. cell := row.AddCell()
  1526. cellPara := cell.AddParagraph()
  1527. run := cellPara.AddRun()
  1528. //列数据
  1529. cellData := rowDataList[j]
  1530. //如果合并列大于0,那么就合并列
  1531. if cellData.ColumnSpan > 0 {
  1532. // column span / merged cells
  1533. cell.Properties().SetColumnSpan(cellData.ColumnSpan)
  1534. //_ = row.AddCell()
  1535. }
  1536. //如果指定了上下单元格合并,那么去合并上下单元格
  1537. if cellData.IsMerged {
  1538. //合并单元格类型
  1539. var mergeVal wml.ST_Merge
  1540. if cellData.IsFirstMerged { //如果是第一个合并行,那么开始重新合并
  1541. mergeVal = wml.ST_MergeRestart
  1542. } else { //如果不是第一个合并行,那么是继续合并
  1543. mergeVal = wml.ST_MergeContinue
  1544. }
  1545. cell.Properties().SetVerticalMerge(mergeVal)
  1546. }
  1547. //背景色
  1548. if cellData.Background != "" {
  1549. cell.Properties().SetShading(wml.ST_ShdSolid, getColorConf(cellData.Background), color.Auto)
  1550. }
  1551. //填充内容(文字)垂直对齐方式
  1552. cell.Properties().SetVerticalAlignment(wml.ST_VerticalJcCenter)
  1553. //将单元格设置为宽度百分比
  1554. if cellData.WidthPercent > 0 {
  1555. //cell.Properties().SetWidthPercent(cellData.WidthPercent)
  1556. //因为libreOffice不支持百分比的设置表格宽度
  1557. cellWidth := tableWidth * cellData.WidthPercent * measurement.Inch / 100
  1558. cell.Properties().SetWidth(measurement.Distance(cellWidth))
  1559. }
  1560. //文字排版(居中、左、右)
  1561. if cellData.TextAlign != "" {
  1562. cellPara.Properties().SetAlignment(getTextAlignConf(cellData.TextAlign))
  1563. //cellPara.Properties().SetAlignment(wml.ST_JcLeft)
  1564. }
  1565. //cell.Properties().SetAli
  1566. //设置是否加粗
  1567. run.Properties().SetBold(cellData.IsBold)
  1568. //设置字体大小
  1569. fontSize := 10.5
  1570. if cellData.FontSize > 0 {
  1571. fontSize = cellData.FontSize
  1572. }
  1573. run.Properties().SetSize(measurement.Distance(fontSize * measurement.Point))
  1574. //设置段落间的间距
  1575. cellPara.Properties().Spacing().SetLineSpacing(measurement.Distance(1.4*fontSize*measurement.Point), wml.ST_LineSpacingRuleAuto)
  1576. //设置段前间距
  1577. cellPara.Properties().Spacing().SetBefore(measurement.Distance(0.9 * fontSize * measurement.Point))
  1578. //设置段后间距
  1579. cellPara.Properties().Spacing().SetAfter(measurement.Distance(0.5 * fontSize * measurement.Point))
  1580. //设置字体
  1581. run.Properties().SetFontFamily("宋体")
  1582. //设置排序
  1583. run.Properties().SetVerticalAlignment(sharedTypes.ST_VerticalAlignRunBaseline)
  1584. //设置显示的文字
  1585. if cellData.Value != "" {
  1586. strSlice := strings.Split(cellData.Value, "<br/>")
  1587. for s := 0; s < len(strSlice); s++ {
  1588. if s > 0 {
  1589. run.AddBreak()
  1590. }
  1591. run.AddText(strSlice[s])
  1592. }
  1593. } else {
  1594. run.AddText("")
  1595. }
  1596. }
  1597. }
  1598. }
  1599. //twoParagraph := doc.AddParagraph()
  1600. //twoParagraph.AddRun()
  1601. doc.AddParagraph()
  1602. return
  1603. }
  1604. // getContractAddress 获取展示的详细地址
  1605. func getContractAddress(contractDetail *contract.ContractDetail) (address string) {
  1606. ignoreStrs := []string{"北京市", "上海市", "天津市", "重庆市"}
  1607. if strings.Contains(strings.Join(ignoreStrs, ","), contractDetail.Province) {
  1608. address = contractDetail.City + contractDetail.Address
  1609. } else {
  1610. address = contractDetail.Province + contractDetail.City + contractDetail.Address
  1611. }
  1612. return
  1613. }
  1614. //FuncDocs2Pdf
  1615. /**
  1616. *@tips libreoffice 转换指令:
  1617. * libreoffice6.2 invisible --convert-to pdf csDoc.doc --outdir /home/[转出目录]
  1618. *
  1619. * @function 实现文档类型转换为pdf或html
  1620. * @param command:libreofficed的命令(具体以版本为准);win:soffice; linux:libreoffice6.2
  1621. * fileSrcPath:转换文件的路径
  1622. * fileOutDir:转换后文件存储目录
  1623. * converterType:转换的类型pdf/html
  1624. * @return fileOutPath 转换成功生成的文件的路径 error 转换错误
  1625. */
  1626. func FuncDocs2Pdf(command string, fileSrcPath string, fileOutDir string, converterType string) (fileOutPath string, error error) {
  1627. //校验fileSrcPath
  1628. srcFile, erByOpenSrcFile := os.Open(fileSrcPath)
  1629. if erByOpenSrcFile != nil && os.IsNotExist(erByOpenSrcFile) {
  1630. return "", erByOpenSrcFile
  1631. }
  1632. //如文件输出目录fileOutDir不存在则自动创建
  1633. outFileDir, erByOpenFileOutDir := os.Open(fileOutDir)
  1634. if erByOpenFileOutDir != nil && os.IsNotExist(erByOpenFileOutDir) {
  1635. erByCreateFileOutDir := os.MkdirAll(fileOutDir, os.ModePerm)
  1636. if erByCreateFileOutDir != nil {
  1637. fmt.Println("File ouput dir create error.....", erByCreateFileOutDir.Error())
  1638. return "", erByCreateFileOutDir
  1639. }
  1640. }
  1641. //关闭流
  1642. defer func() {
  1643. _ = srcFile.Close()
  1644. _ = outFileDir.Close()
  1645. }()
  1646. //convert
  1647. cmd := exec.Command(command, "--invisible", "--convert-to", converterType,
  1648. fileSrcPath, "--outdir", fileOutDir)
  1649. _, errByCmdStart := cmd.Output()
  1650. //命令调用转换失败
  1651. if errByCmdStart != nil {
  1652. return "", errByCmdStart
  1653. }
  1654. //success
  1655. fileOutPath = fileOutDir + "/" + strings.Split(path.Base(fileSrcPath), ".")[0]
  1656. if converterType == "html" {
  1657. fileOutPath += ".html"
  1658. } else {
  1659. fileOutPath += ".pdf"
  1660. }
  1661. //fmt.Println("文件转换成功...", string(byteByStat))
  1662. return fileOutPath, nil
  1663. }