word.go 56 KB

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