word.go 56 KB

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