word.go 56 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838
  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客户服务列表2022》中 小套餐 的服务内容,详细如下:"
  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. contentConfigMap := make(map[string]string)
  581. err = json.Unmarshal([]byte(contractTemplate.ContentConfig), &contentConfigMap)
  582. if err != nil {
  583. return
  584. }
  585. //服务内容
  586. {
  587. tableStr := ""
  588. tableDataSlice := make([]TableData, 0)
  589. tableTitleSlice := make([]string, 0)
  590. title := ``
  591. if tmpTitle, ok := contentConfigMap["title1"]; ok {
  592. title = tmpTitle
  593. }
  594. for i := 0; i < len(contractDetail.Service); i++ {
  595. //表格数据
  596. var tableDataList TableData
  597. item := contractDetail.Service[i]
  598. //表头备注信息
  599. tableTitleSlice = append(tableTitleSlice, item.Title)
  600. //表格数据
  601. if item.HasDetail == "是" && len(item.DetailList) > 0 {
  602. //表格每行数据切片
  603. tableRowList := make([]TableRow, 0)
  604. //遍历获取table行数据
  605. for j := 0; j < len(item.DetailList); j++ {
  606. //列数据样式初始化
  607. isBold := false
  608. backgrandColor := ""
  609. fontSize := 13.0
  610. //表头数据样式
  611. if j == 0 {
  612. isBold = true
  613. backgrandColor = "gray_2"
  614. fontSize = 13.0
  615. }
  616. //获取每一列的数据
  617. tmpCellList, colErr := getColList(item.DetailList[j])
  618. if colErr != nil {
  619. err = colErr
  620. return
  621. }
  622. //定义生成table列数据切片
  623. tableCelList := make([]TableCel, 0)
  624. lenCell := len(tmpCellList)
  625. for k := 0; k < len(tmpCellList); k++ {
  626. //默认30%的宽度,如果不是第一列,那么需要额外计算
  627. widthPercent := 30.0
  628. if k > 0 {
  629. //计算出来每一列的宽度占比 start
  630. //总宽度
  631. newDecimal := decimal.NewFromFloat(70)
  632. //总列数
  633. newDecimal2 := decimal.NewFromInt(int64(lenCell) - 1)
  634. //计算出来每一列的宽度占比(四舍五入)
  635. tmpWidthPercent, _ := newDecimal.Div(newDecimal2).Round(3).Float64()
  636. //if !ok {
  637. // err = errors.New("word普通数据表格宽度百分比计算失败")
  638. // return
  639. //}
  640. widthPercent = tmpWidthPercent
  641. //计算出来每一列的宽度占比 end
  642. }
  643. tableCel := TableCel{
  644. Value: tmpCellList[k],
  645. TextAlign: "center",
  646. //ColumnSpan int `json:"column_span" description:"需要合同的列数量"`
  647. //IsMerged bool `json:"is_merged" description:"是否需要上下行合并"`
  648. Background: backgrandColor,
  649. IsBold: isBold,
  650. FontSize: fontSize,
  651. WidthPercent: widthPercent,
  652. }
  653. tableCelList = append(tableCelList, tableCel)
  654. }
  655. //将每行数据插入到table行数据切片之中
  656. tableRow := TableRow{
  657. RowList: tableCelList,
  658. }
  659. tableRowList = append(tableRowList, tableRow)
  660. }
  661. //赋值table表格数据
  662. tableDataList.List = tableRowList
  663. } else {
  664. //赋值table表格数据
  665. jsonStr := item.TableValue
  666. tmpEerr := json.Unmarshal([]byte(jsonStr), &tableDataList)
  667. if tmpEerr != nil {
  668. err = tmpEerr
  669. return
  670. }
  671. }
  672. tableDataSlice = append(tableDataSlice, tableDataList)
  673. }
  674. titleStr := strings.Join(tableTitleSlice, "、")
  675. title += titleStr + "的服务内容,详细如下:"
  676. if htmlType == "pdf" {
  677. tableStr += `<p style="">` + title + `</p>`
  678. } else {
  679. tableStr = `<p style="font-size: 13pt; line-height: 40px">` + title + `</p>`
  680. }
  681. for _, tableDataList := range tableDataSlice {
  682. //往word中添加表格数据
  683. if htmlType == "pdf" {
  684. tableStr += getTableStrByPdf(tableDataList)
  685. } else {
  686. tableStr += getTableStr(tableDataList)
  687. }
  688. }
  689. data.TableHtml = tableStr
  690. }
  691. //fmt.Println("TableHtml:", data.TableHtml)
  692. contractHtml = strings.Replace(contractHtml, `\{\{\{TableHtml\}\}\}`, data.TableHtml, -1)
  693. return
  694. //生成pdf
  695. //pdfPath := fmt.Sprint("./static/word/系统生成合同", contractDetail.ContractCode, ".pdf")
  696. //err = Html2Pdf(contractHtml, pdfPath)
  697. //if err != nil {
  698. // return
  699. //}
  700. ////defer func() {
  701. //// //删除对应的Pdf
  702. //// os.Remove(pdfPath)
  703. ////}()
  704. //
  705. //return
  706. }
  707. //生成合同服务的预览表格html代码
  708. func getTableStr(tableDataList TableData) (tableStr string) {
  709. //如果表格需要分页,那么在table的style里面添加该配置:page-break-inside: avoid !important
  710. tableStr += `<table style="width: 100%;border-collapse: collapse;font-size: 13pt;margin-bottom:30px;page-break-inside: avoid !important;"><tbody>`
  711. rowList := tableDataList.List
  712. for i := 0; i < len(rowList); i++ {
  713. //创建新的一行
  714. tableStr += `<tr style="`
  715. tableStr += `page-break-before: always;page-break-after: always;page-break-inside: avoid !important;`
  716. //background-color: #F0F2F5;
  717. tableStr += `">`
  718. //<td style="border-right:1px solid #808181;border-bottom:1px solid #808181;padding: 15px 10px;font-weight: bold;" colspan="5">2.市场跟踪类报告</td>
  719. //row := table.AddRow()
  720. ////设置行高,第二个参数是设置固定值还是自动
  721. //row.Properties().SetHeight(30*measurement.Point, wml.ST_HeightRuleAtLeast)
  722. //
  723. //遍历列数据
  724. rowDataList := rowList[i].RowList
  725. cellStr := ""
  726. if rowDataList != nil {
  727. for j := 0; j < len(rowDataList); j++ {
  728. //当前列是否合并
  729. // <td style="font-weight: bold;" colspan="5">2.市场跟踪类报告</td>
  730. // <td style="" align="center" rowspan="3">市场跟踪</td>
  731. // <td style="" align="center">市场估值</td>
  732. tdStr := `<td `
  733. //单元格样式
  734. styleStr := `style="`
  735. styleStr += `border:1px solid #808181;padding: 15px 10px;line-height: 1.5;`
  736. //其他参数
  737. cellOtherStr := ` valign="middle" `
  738. //列数据
  739. cellData := rowDataList[j]
  740. //如果合并列大于0,那么就合并列
  741. if cellData.ColumnSpan > 0 {
  742. // column span / merged cells
  743. cellOtherStr += ` colspan="` + strconv.Itoa(cellData.ColumnSpan) + `" `
  744. }
  745. //如果指定了上下单元格合并,那么去合并上下单元格
  746. if cellData.IsMerged {
  747. if cellData.IsFirstMerged {
  748. cellOtherStr += ` rowspan="` + strconv.Itoa(cellData.RowSpan) + `" `
  749. } else {
  750. //如果是合并行,且不是第一行,那么就退出当前单元格循环,进入下一个循环
  751. continue
  752. }
  753. }
  754. //背景色
  755. if cellData.Background != "" {
  756. styleStr += `background-color: #F0F2F5;`
  757. }
  758. //将单元格设置为宽度百分比
  759. if cellData.WidthPercent > 0 {
  760. widthDecimal := decimal.NewFromFloat(cellData.WidthPercent)
  761. cellOtherStr += ` width="` + widthDecimal.String() + `%" `
  762. }
  763. //文字排版(居中、左、右)
  764. if cellData.TextAlign != "" {
  765. cellOtherStr += ` align="` + cellData.TextAlign + `" `
  766. }
  767. //cell.Properties().SetAli
  768. //设置是否加粗
  769. if cellData.IsBold {
  770. styleStr += `font-weight:bold;`
  771. }
  772. //设置字体大小
  773. fontSize := 10.0
  774. if cellData.FontSize > 0 {
  775. fontSize = cellData.FontSize
  776. }
  777. fontDecimal := decimal.NewFromFloat(fontSize)
  778. styleStr += `font-size: ` + fontDecimal.String() + `pt;`
  779. bodyStr := cellData.Value
  780. styleStr += `" `
  781. cellStr += tdStr + styleStr + cellOtherStr + `>` + bodyStr + `</td>`
  782. }
  783. }
  784. tableStr += cellStr + `</tr>`
  785. }
  786. tableStr += `</tbody></table>`
  787. return
  788. }
  789. //生成合同服务的pdf表格html代码
  790. func getTableStrByPdf(tableDataList TableData) (tableStr string) {
  791. //如果表格需要分页,那么在table的style里面添加该配置:page-break-inside: avoid !important
  792. tableStr += `<table style="width: 100%;border-collapse: collapse;margin-top:10pt;page-break-inside: avoid !important;"><tbody>`
  793. rowList := tableDataList.List
  794. for i := 0; i < len(rowList); i++ {
  795. //创建新的一行
  796. tableStr += `<tr style="`
  797. tableStr += `page-break-before: always;page-break-after: always;page-break-inside: avoid !important;`
  798. //background-color: #F0F2F5;
  799. tableStr += `">`
  800. //<td style="border-right:1px solid #808181;border-bottom:1px solid #808181;padding: 15px 10px;font-weight: bold;" colspan="5">2.市场跟踪类报告</td>
  801. //row := table.AddRow()
  802. ////设置行高,第二个参数是设置固定值还是自动
  803. //row.Properties().SetHeight(30*measurement.Point, wml.ST_HeightRuleAtLeast)
  804. //
  805. //遍历列数据
  806. rowDataList := rowList[i].RowList
  807. cellStr := ""
  808. if rowDataList != nil {
  809. for j := 0; j < len(rowDataList); j++ {
  810. //当前列是否合并
  811. // <td style="font-weight: bold;" colspan="5">2.市场跟踪类报告</td>
  812. // <td style="" align="center" rowspan="3">市场跟踪</td>
  813. // <td style="" align="center">市场估值</td>
  814. tdStr := `<td `
  815. //单元格样式
  816. styleStr := `style="`
  817. styleStr += `border:1px solid #808181;padding:4pt 10pt;`
  818. //其他参数
  819. cellOtherStr := ` valign="middle" `
  820. //列数据
  821. cellData := rowDataList[j]
  822. //如果合并列大于0,那么就合并列
  823. if cellData.ColumnSpan > 0 {
  824. // column span / merged cells
  825. cellOtherStr += ` colspan="` + strconv.Itoa(cellData.ColumnSpan) + `" `
  826. }
  827. //如果指定了上下单元格合并,那么去合并上下单元格
  828. if cellData.IsMerged {
  829. if cellData.IsFirstMerged {
  830. cellOtherStr += ` rowspan="` + strconv.Itoa(cellData.RowSpan) + `" `
  831. } else {
  832. //如果是合并行,且不是第一行,那么就退出当前单元格循环,进入下一个循环
  833. continue
  834. }
  835. }
  836. //背景色
  837. if cellData.Background != "" {
  838. styleStr += `background-color: #F0F2F5;`
  839. }
  840. //将单元格设置为宽度百分比
  841. if cellData.WidthPercent > 0 {
  842. widthDecimal := decimal.NewFromFloat(cellData.WidthPercent)
  843. cellOtherStr += ` width="` + widthDecimal.String() + `%" `
  844. }
  845. //文字排版(居中、左、右)
  846. if cellData.TextAlign != "" {
  847. cellOtherStr += ` align="` + cellData.TextAlign + `" `
  848. }
  849. //cell.Properties().SetAli
  850. //设置是否加粗
  851. if cellData.IsBold {
  852. styleStr += `font-weight:bold;`
  853. }
  854. //设置字体大小
  855. fontSize := 10.0
  856. if cellData.FontSize > 0 {
  857. fontSize = cellData.FontSize
  858. }
  859. fontDecimal := decimal.NewFromFloat(fontSize)
  860. styleStr += `font-size: ` + fontDecimal.String() + `pt;`
  861. bodyStr := cellData.Value
  862. styleStr += `" `
  863. cellStr += tdStr + styleStr + cellOtherStr + `>` + bodyStr + `</td>`
  864. }
  865. }
  866. tableStr += cellStr + `</tr>`
  867. }
  868. tableStr += `</tbody></table>`
  869. return
  870. }
  871. //根据html生成pdf
  872. func Html2Pdf(htmlStr, pdfPath string) (err error) {
  873. pdfg, err := wkhtml.NewPDFGenerator()
  874. if err != nil {
  875. fmt.Println("err:", err)
  876. return
  877. }
  878. //通过html生成page
  879. page := wkhtml.NewPageReader(strings.NewReader(htmlStr))
  880. //页眉设置
  881. //page.HeaderLeft.Set("弘则弥道(上海)投资咨询有限公司")
  882. //page.HeaderFontName.Set("宋体")
  883. //page.HeaderFontSize.Set(8)
  884. //page.HeaderSpacing.Set(4)
  885. //page.HeaderLine.Set(true)
  886. //page.HeaderSpacing.Set(10)
  887. //页脚设置
  888. page.FooterFontSize.Set(8)
  889. page.FooterRight.Set("[page]")
  890. page.FooterSpacing.Set(4)
  891. //page.FooterLine.Set(true)
  892. //page.EnableForms.Set(false)
  893. //转换HTML表单为PDF表单
  894. //page.EnableForms.Set(true)
  895. //使用打印媒体类型而不是屏幕
  896. //page.PrintMediaType.Set(true)
  897. //允许从标题链接到目录
  898. page.EnableTocBackLinks.Set(true)
  899. //将该page插入到pdf中
  900. pdfg.AddPage(page)
  901. //pdfg.PageSize.Set(wkhtml.PageSizeA4)
  902. //pdfg.MarginTop.Set(20)
  903. //pdfg.MarginBottom.Set(5)
  904. //pdfg.MarginLeft.Set(0)
  905. //pdfg.
  906. err = pdfg.Create()
  907. if err != nil {
  908. return
  909. }
  910. err = pdfg.WriteFile(pdfPath)
  911. return
  912. }
  913. //获取表格列数据
  914. func getColList(item *contract_service_detail.ContractServiceDetail) (cellList []string, err error) {
  915. cellList = make([]string, 0)
  916. var serviceDetailReq contractReq.AddContractServiceDetailReq
  917. tmpItem := *item
  918. t := reflect.TypeOf(tmpItem)
  919. v := reflect.ValueOf(tmpItem)
  920. for k := 0; k < t.NumField(); k++ {
  921. //获取结构体的参数名
  922. tmpName := t.Field(k).Name
  923. if strings.Contains(tmpName, "Col") {
  924. //获取结构体该参数名的值
  925. tmpValue := v.Field(k).String()
  926. //如果值不为空的话,那么做下json转换
  927. if tmpValue != "" {
  928. err = json.Unmarshal([]byte(tmpValue), &serviceDetailReq)
  929. if err != nil {
  930. return
  931. } else {
  932. cellList = append(cellList, serviceDetailReq.Value)
  933. }
  934. }
  935. }
  936. }
  937. return
  938. }
  939. type WordElement struct {
  940. ElementType string `json:"element_type" description:"元素类型"`
  941. ElementName string `json:"element_name" description:"元素名称"`
  942. RelationName string `json:"relation_name" description:"关联元素名称"`
  943. Content string `json:"content" description:"元素内容"`
  944. Background string `json:"background" description:"背景色"`
  945. IsBold bool `json:"is_bold" description:"是否加粗显示"`
  946. TextAlign string `json:"text_align" description:"对齐方式"`
  947. FontSize float64 `json:"font_size" description:"字体大小"`
  948. ElementList []WordElement `json:"list" description:"子元素"`
  949. }
  950. // GenerateWordV2 生成word
  951. func GenerateWordV2(contractDetail *contract.ContractDetail, wordPath string) (err error) {
  952. //临时合同信息
  953. tmpContractDetail := *contractDetail
  954. //合同服务
  955. contractServiceAndDetailList := make([]*contractCustom.ContractServiceAndDetail, 0) //服务内容
  956. if tmpContractDetail.ContractBusinessType == "代付合同" {
  957. if contractDetail.RelationContractDetailList != nil && len(contractDetail.RelationContractDetailList) > 0 {
  958. tmpContractDetail.StartDate = tmpContractDetail.RelationContractDetailList[0].StartDate
  959. tmpContractDetail.EndDate = tmpContractDetail.RelationContractDetailList[0].EndDate
  960. contractServiceAndDetailList = tmpContractDetail.RelationContractDetailList[0].Service
  961. }
  962. } else {
  963. contractServiceAndDetailList = tmpContractDetail.Service
  964. }
  965. //模板信息
  966. contractTemplate, err := contract_template.GetContractTemplateByTemplateId(contractDetail.TemplateId)
  967. if err != nil {
  968. return
  969. }
  970. jsonStr := contractTemplate.WordConfig
  971. var contractData []WordElement
  972. err = json.Unmarshal([]byte(jsonStr), &contractData)
  973. if err != nil {
  974. fmt.Println("json字符串解析失败,ERR:", err)
  975. return
  976. }
  977. // 初始化合同中一些特定区域的文字展示配置
  978. contentConfigMap := make(map[string]string)
  979. err = json.Unmarshal([]byte(contractTemplate.ContentConfig), &contentConfigMap)
  980. if err != nil {
  981. return
  982. }
  983. doc := document.New()
  984. //word的属性设置,类型,作者之类的
  985. cp := doc.CoreProperties
  986. // And change them as well
  987. cp.SetTitle("弘则弥道(上海)投资咨询有限公司 & 研究服务合同")
  988. cp.SetAuthor("弘则弥道(上海)投资咨询有限公司")
  989. cp.SetCategory("合同")
  990. //cp.SetContentStatus("Draft")
  991. cp.SetLastModifiedBy("弘则弥道(上海)投资咨询有限公司")
  992. cp.SetCreated(time.Now())
  993. cp.SetModified(time.Now())
  994. cp.SetDescription("弘则弥道(上海)投资咨询有限公司 研究服务合同")
  995. cp.SetLanguage("中文")
  996. tableFontSize := 10.5 //默认表格内文字10.5
  997. for _, data := range contractData {
  998. fontSize := data.FontSize
  999. if fontSize <= 0 {
  1000. fontSize = 15
  1001. }
  1002. printContent := ``
  1003. if data.ElementName == "services" {
  1004. tableTitleSlice := make([]string, 0)
  1005. title := ``
  1006. if tmpTitle, ok := contentConfigMap["title1"]; ok {
  1007. title = tmpTitle
  1008. }
  1009. TableDataListSlice := make([]TableData, 0)
  1010. //for i := len(contractServiceAndDetailList) - 1; i >= 0; i-- {
  1011. for i := 0; i < len(contractServiceAndDetailList); i++ {
  1012. //表格数据
  1013. var tableDataList TableData
  1014. item := contractServiceAndDetailList[i]
  1015. //表头备注信息
  1016. tableTitleSlice = append(tableTitleSlice, item.Title)
  1017. //表格数据
  1018. if item.HasDetail == "是" && len(item.DetailList) > 0 {
  1019. //表格每行数据切片
  1020. tableRowList := make([]TableRow, 0)
  1021. //遍历获取table行数据
  1022. for j := 0; j < len(item.DetailList); j++ {
  1023. //列数据样式初始化
  1024. isBold := false
  1025. backgrandColor := ""
  1026. fontSize := tableFontSize
  1027. //表头数据样式
  1028. if j == 0 {
  1029. isBold = true
  1030. backgrandColor = "gray_2"
  1031. }
  1032. //获取每一列的数据
  1033. tmpCellList, colErr := getColList(item.DetailList[j])
  1034. if colErr != nil {
  1035. err = colErr
  1036. return
  1037. }
  1038. //定义生成table列数据切片
  1039. tableCelList := make([]TableCel, 0)
  1040. lenCell := len(tmpCellList)
  1041. for k := 0; k < len(tmpCellList); k++ {
  1042. //计算出来每一列的宽度占比 start
  1043. //总宽度
  1044. newDecimal := decimal.NewFromFloat(100)
  1045. //总列数
  1046. newDecimal2 := decimal.NewFromInt(int64(lenCell))
  1047. //计算出来每一列的宽度占比(四舍五入)
  1048. widthPercent, _ := newDecimal.Div(newDecimal2).Round(3).Float64()
  1049. //if !ok {
  1050. // err = errors.New("word普通数据表格宽度百分比计算失败")
  1051. // return
  1052. //}
  1053. //计算出来每一列的宽度占比 end
  1054. tableCel := TableCel{
  1055. Value: tmpCellList[k],
  1056. TextAlign: "center",
  1057. //ColumnSpan int `json:"column_span";description:"需要合同的列数量"`
  1058. //IsMerged bool `json:"is_merged";description:"是否需要上下行合并"`
  1059. Background: backgrandColor,
  1060. IsBold: isBold,
  1061. FontSize: fontSize,
  1062. WidthPercent: widthPercent,
  1063. }
  1064. tableCelList = append(tableCelList, tableCel)
  1065. }
  1066. //将每行数据插入到table行数据切片之中
  1067. tableRow := TableRow{
  1068. RowList: tableCelList,
  1069. }
  1070. tableRowList = append(tableRowList, tableRow)
  1071. }
  1072. //赋值table表格数据
  1073. tableDataList.List = tableRowList
  1074. } else {
  1075. //赋值table表格数据
  1076. jsonStr := item.TableValue
  1077. err = json.Unmarshal([]byte(jsonStr), &tableDataList)
  1078. if err != nil {
  1079. return
  1080. }
  1081. }
  1082. //往word中添加表格数据
  1083. TableDataListSlice = append(TableDataListSlice, tableDataList)
  1084. }
  1085. //表格标题
  1086. titleStr := strings.Join(tableTitleSlice, "、")
  1087. title += titleStr + "的服务内容,详细如下:"
  1088. //开始一个新的段落
  1089. headerPar := doc.AddParagraph()
  1090. headerParPro := headerPar.Properties()
  1091. //headerParPro.AddTabStop()
  1092. textAlign := getTextAlignConf(data.TextAlign)
  1093. headerParPro.SetAlignment(textAlign)
  1094. //if data.ElementType == "column" {
  1095. // headerParPro.SetAlignment(wml.ST_JcBoth)
  1096. //}
  1097. headerRun := headerPar.AddRun()
  1098. headerRunPro := headerRun.Properties()
  1099. headerRunPro.SetBold(data.IsBold)
  1100. headerRunPro.SetSize(measurement.Distance(fontSize * measurement.Point))
  1101. headerRunPro.SetFontFamily("宋体")
  1102. //headerRunPro.SetKerning(measurement.Distance(2 * fontSize * measurement.Point))
  1103. headerRun.AddText(title)
  1104. //生成表格
  1105. for _, tableDataList := range TableDataListSlice {
  1106. tmpErr := addTableV2(tableDataList, doc)
  1107. if tmpErr != nil {
  1108. err = tmpErr
  1109. return
  1110. }
  1111. }
  1112. continue
  1113. } else {
  1114. isPrint, tmpPrintContent, tmpErr := getPrintData(data, contractDetail)
  1115. if tmpErr != nil {
  1116. err = tmpErr
  1117. return
  1118. }
  1119. if isPrint == false {
  1120. continue
  1121. }
  1122. printContent = tmpPrintContent
  1123. }
  1124. //分栏的宽度
  1125. printContentRune := []rune(printContent)
  1126. strLen := len(printContentRune)
  1127. addTabNum := 0
  1128. printContentList := make([]map[int]string, 0)
  1129. firstLen := 17
  1130. secondLen := 14
  1131. if data.ElementType == "column" {
  1132. if strLen > firstLen {
  1133. maxLine := ((strLen - firstLen) / secondLen) + 1
  1134. for i := 0; i < maxLine; i++ {
  1135. printContentMap := make(map[int]string)
  1136. startIndex := secondLen*i + firstLen
  1137. endIndex := secondLen*(i+1) + firstLen
  1138. if endIndex > strLen {
  1139. endIndex = strLen
  1140. }
  1141. tmpPrintContent := string(printContentRune[startIndex:endIndex])
  1142. printContentMap[0] = tmpPrintContent
  1143. printContentList = append(printContentList, printContentMap)
  1144. }
  1145. printContent = string(printContentRune[:firstLen])
  1146. strLen = firstLen
  1147. //重新计算宽度
  1148. //width = fontSize * float64(strLen)
  1149. //addTabNum = 3
  1150. } else {
  1151. addTabNum = firstLen - strLen
  1152. }
  1153. addTabNum += 3
  1154. }
  1155. //开始一个新的段落
  1156. headerPar := doc.AddParagraph()
  1157. headerParPro := headerPar.Properties()
  1158. headerParPro.Spacing().SetLineSpacing(measurement.Distance(1.5*fontSize*measurement.Point), wml.ST_LineSpacingRuleAuto)
  1159. //headerParPro.AddTabStop()
  1160. textAlign := getTextAlignConf(data.TextAlign)
  1161. headerParPro.SetAlignment(textAlign)
  1162. //if data.ElementType == "column" {
  1163. // headerParPro.SetAlignment(wml.ST_JcBoth)
  1164. //}
  1165. headerRun := headerPar.AddRun()
  1166. headerRunPro := headerRun.Properties()
  1167. headerRunPro.SetBold(data.IsBold)
  1168. headerRunPro.SetSize(measurement.Distance(fontSize * measurement.Point))
  1169. headerRunPro.SetFontFamily("宋体")
  1170. //headerRunPro.SetKerning(measurement.Distance(2 * fontSize * measurement.Point))
  1171. headerRun.AddText(printContent)
  1172. for _, text := range data.ElementList {
  1173. if text.ElementName == "services" {
  1174. tableTitleSlice := make([]string, 0)
  1175. title := ``
  1176. if tmpTitle, ok := contentConfigMap["title1"]; ok {
  1177. title = tmpTitle
  1178. }
  1179. TableDataListSlice := make([]TableData, 0)
  1180. for i := len(contractServiceAndDetailList) - 1; i >= 0; i-- {
  1181. //表格数据
  1182. var tableDataList TableData
  1183. item := contractServiceAndDetailList[i]
  1184. //表头备注信息
  1185. tableTitleSlice = append(tableTitleSlice, item.Title)
  1186. //表格数据
  1187. if item.HasDetail == "是" && len(item.DetailList) > 0 {
  1188. //表格每行数据切片
  1189. tableRowList := make([]TableRow, 0)
  1190. //遍历获取table行数据
  1191. for j := 0; j < len(item.DetailList); j++ {
  1192. //列数据样式初始化
  1193. isBold := false
  1194. backgrandColor := ""
  1195. fontSize := tableFontSize
  1196. //表头数据样式
  1197. if j == 0 {
  1198. isBold = true
  1199. backgrandColor = "gray_2"
  1200. }
  1201. //获取每一列的数据
  1202. tmpCellList, colErr := getColList(item.DetailList[j])
  1203. if colErr != nil {
  1204. err = colErr
  1205. return
  1206. }
  1207. //定义生成table列数据切片
  1208. tableCelList := make([]TableCel, 0)
  1209. lenCell := len(tmpCellList)
  1210. for k := 0; k < len(tmpCellList); k++ {
  1211. //计算出来每一列的宽度占比 start
  1212. //总宽度
  1213. newDecimal := decimal.NewFromFloat(100)
  1214. //总列数
  1215. newDecimal2 := decimal.NewFromInt(int64(lenCell))
  1216. //计算出来每一列的宽度占比(四舍五入)
  1217. widthPercent, _ := newDecimal.Div(newDecimal2).Round(3).Float64()
  1218. //if !ok {
  1219. // err = errors.New("word普通数据表格宽度百分比计算失败")
  1220. // return
  1221. //}
  1222. //计算出来每一列的宽度占比 end
  1223. tableCel := TableCel{
  1224. Value: tmpCellList[k],
  1225. TextAlign: "center",
  1226. //ColumnSpan int `json:"column_span";description:"需要合同的列数量"`
  1227. //IsMerged bool `json:"is_merged";description:"是否需要上下行合并"`
  1228. Background: backgrandColor,
  1229. IsBold: isBold,
  1230. FontSize: fontSize,
  1231. WidthPercent: widthPercent,
  1232. }
  1233. tableCelList = append(tableCelList, tableCel)
  1234. }
  1235. //将每行数据插入到table行数据切片之中
  1236. tableRow := TableRow{
  1237. RowList: tableCelList,
  1238. }
  1239. tableRowList = append(tableRowList, tableRow)
  1240. }
  1241. //赋值table表格数据
  1242. tableDataList.List = tableRowList
  1243. } else {
  1244. //赋值table表格数据
  1245. jsonStr := item.TableValue
  1246. err = json.Unmarshal([]byte(jsonStr), &tableDataList)
  1247. if err != nil {
  1248. return
  1249. }
  1250. }
  1251. //往word中添加表格数据
  1252. TableDataListSlice = append(TableDataListSlice, tableDataList)
  1253. }
  1254. //表格标题
  1255. titleStr := strings.Join(tableTitleSlice, "、")
  1256. title += titleStr + "的服务内容,详细如下:"
  1257. headerRun := headerPar.AddRun()
  1258. headerRun.AddBreak()
  1259. headerRunPro := headerRun.Properties()
  1260. headerRunPro.SetBold(text.IsBold)
  1261. headerRunPro.SetSize(measurement.Distance(fontSize * measurement.Point))
  1262. headerRunPro.SetFontFamily("宋体")
  1263. //headerRunPro.SetKerning(measurement.Distance(2 * fontSize * measurement.Point))
  1264. headerRun.AddText(title)
  1265. //生成表格
  1266. for _, tableDataList := range TableDataListSlice {
  1267. tmpErr := addTableV2(tableDataList, doc)
  1268. if tmpErr != nil {
  1269. err = tmpErr
  1270. return
  1271. }
  1272. }
  1273. } else {
  1274. isPrint, printContent, tmpErr := getPrintData(text, contractDetail)
  1275. if tmpErr != nil {
  1276. err = tmpErr
  1277. return
  1278. }
  1279. if isPrint == false {
  1280. continue
  1281. }
  1282. if data.ElementType == "column" {
  1283. for j := 0; j < addTabNum; j++ {
  1284. //headerRun.AddTab()
  1285. tabStr := " "
  1286. printContent = tabStr + printContent
  1287. }
  1288. }
  1289. fontSize := text.FontSize
  1290. if fontSize <= 0 {
  1291. fontSize = 15
  1292. }
  1293. headerRun2 := headerPar.AddRun()
  1294. headerRunPro2 := headerRun2.Properties()
  1295. headerRunPro2.SetBold(text.IsBold)
  1296. headerRunPro2.SetSize(measurement.Distance(fontSize * measurement.Point))
  1297. headerRunPro2.SetFontFamily("宋体")
  1298. //headerRunPro2.SetKerning(measurement.Distance(2 * fontSize * measurement.Point))
  1299. headerRun2.AddText(printContent)
  1300. }
  1301. }
  1302. for _, printMap := range printContentList {
  1303. //开始一个新的段落
  1304. headerPar := doc.AddParagraph()
  1305. headerParPro := headerPar.Properties()
  1306. headerParPro.Spacing().SetLineSpacing(measurement.Distance(1.5*fontSize*measurement.Point), wml.ST_LineSpacingRuleAuto)
  1307. //headerParPro.AddTabStop()
  1308. textAlign := getTextAlignConf(data.TextAlign)
  1309. headerParPro.SetAlignment(textAlign)
  1310. //空出三个字符出来,避免签名顶在最前方展示
  1311. headerParPro.SetStartIndent(measurement.Distance(3 * fontSize * measurement.Point))
  1312. headerRun := headerPar.AddRun()
  1313. headerRunPro := headerRun.Properties()
  1314. headerRunPro.SetBold(data.IsBold)
  1315. headerRunPro.SetSize(measurement.Distance(fontSize * measurement.Point))
  1316. headerRunPro.SetFontFamily("宋体")
  1317. //headerRunPro.SetKerning(measurement.Distance(2 * fontSize * measurement.Point))
  1318. headerRun.AddText(printMap[0])
  1319. }
  1320. }
  1321. //for _, data := range list {
  1322. // headerPar := doc.AddParagraph()
  1323. // headerParPro := headerPar.Properties()
  1324. // headerParPro.SetAlignment(wml.ST_JcCenter)
  1325. // headerRun := headerPar.AddRun()
  1326. // headerRunPro := headerRun.Properties()
  1327. // headerRunPro.SetBold(true)
  1328. // headerRunPro.SetSize(16)
  1329. // headerRun.AddText(data)
  1330. //}
  1331. err = doc.SaveToFile(wordPath)
  1332. return
  1333. }
  1334. // getPrintData 获取打印数据
  1335. func getPrintData(data WordElement, contractDetail *contract.ContractDetail) (isPrint bool, printContent string, err error) {
  1336. printContent = data.Content
  1337. if data.RelationName != "" {
  1338. switch data.RelationName {
  1339. case "address":
  1340. if contractDetail.Address == "" && contractDetail.Province == "" && contractDetail.City == "" {
  1341. return
  1342. }
  1343. case "postcode":
  1344. if contractDetail.Postcode == "" {
  1345. return
  1346. }
  1347. case "phone":
  1348. if contractDetail.Phone == "" {
  1349. return
  1350. }
  1351. case "fax":
  1352. if contractDetail.Fax == "" {
  1353. return
  1354. }
  1355. case "remark":
  1356. if contractDetail.Remark == "" {
  1357. return
  1358. }
  1359. case "price":
  1360. //实际金额(小写)
  1361. if contractDetail.OriginalPrice == contractDetail.Price {
  1362. return
  1363. }
  1364. case "price_cn":
  1365. //实际金额(大写)
  1366. if contractDetail.OriginalPrice == contractDetail.Price {
  1367. return
  1368. }
  1369. case "pay_remark":
  1370. if contractDetail.PayRemark == "" {
  1371. return
  1372. }
  1373. case "company_name":
  1374. if contractDetail.CompanyName == "" {
  1375. return
  1376. }
  1377. }
  1378. }
  1379. switch data.ElementName {
  1380. case "address":
  1381. if contractDetail.Address == "" && contractDetail.Province == "" && contractDetail.City == "" {
  1382. return
  1383. }
  1384. printContent = getContractAddress(contractDetail)
  1385. case "postcode":
  1386. if contractDetail.Postcode == "" {
  1387. return
  1388. }
  1389. printContent = contractDetail.Postcode
  1390. case "phone":
  1391. if contractDetail.Phone == "" {
  1392. return
  1393. }
  1394. printContent = contractDetail.Phone
  1395. case "fax":
  1396. if contractDetail.Fax == "" {
  1397. return
  1398. }
  1399. printContent = contractDetail.Fax
  1400. case "remark":
  1401. if contractDetail.Remark == "" {
  1402. return
  1403. }
  1404. printContent = contractDetail.Remark
  1405. case "start_date":
  1406. printContent = contractDetail.StartDate.Format("2006年01月02日")
  1407. case "end_date":
  1408. printContent = contractDetail.EndDate.Format("2006年01月02日")
  1409. case "num_year":
  1410. ////合同结束日期与合同开始日期的时间差(小时差)
  1411. //newDecimal := decimal.NewFromFloat(contractDetail.EndDate.Sub(contractDetail.StartDate).Hours())
  1412. ////分母为365天 * 24 小时
  1413. //newDecimal2 := decimal.NewFromInt(24 * 365)
  1414. ////计算出来相差多少年,保留一位小数(四舍五入)
  1415. //numYearDecimal := newDecimal.Div(newDecimal2).Round(1)
  1416. ////定义最小年份差,不能小于0.1年
  1417. //minDecimal := decimal.NewFromFloat(0.1)
  1418. ////如果计算出来的年份差小于0.1年,那么该年份差就赋值 0.1年
  1419. //if numYearDecimal.LessThan(minDecimal) {
  1420. // numYearDecimal = minDecimal
  1421. //}
  1422. //printContent = numYearDecimal.String()
  1423. tmpPrintContent, tmpErr := utils.CalculationDate(contractDetail.StartDate, contractDetail.EndDate)
  1424. if tmpErr != nil {
  1425. err = tmpErr
  1426. return
  1427. }
  1428. printContent = tmpPrintContent
  1429. case "original_price":
  1430. //优惠前金额(小写)
  1431. //newDecimal := decimal.NewFromFloat(contractDetail.OriginalPrice)
  1432. printContent = utils.FormatPrice(contractDetail.OriginalPrice)
  1433. case "original_price_cn":
  1434. //优惠前金额(大写)
  1435. originalCnyPrice, cnyErr := utils.ConvertNumToCny(contractDetail.OriginalPrice)
  1436. if cnyErr != nil {
  1437. err = cnyErr
  1438. return
  1439. }
  1440. printContent = originalCnyPrice
  1441. case "price":
  1442. //实际金额(小写)
  1443. if contractDetail.OriginalPrice == contractDetail.Price {
  1444. return
  1445. }
  1446. //newDecimal := decimal.NewFromFloat(contractDetail.Price)
  1447. printContent = utils.FormatPrice(contractDetail.Price)
  1448. case "price_cn":
  1449. //实际金额(大写)
  1450. if contractDetail.OriginalPrice == contractDetail.Price {
  1451. return
  1452. }
  1453. cnyPrice, cnyErr := utils.ConvertNumToCny(contractDetail.Price)
  1454. if cnyErr != nil {
  1455. err = cnyErr
  1456. return
  1457. }
  1458. printContent = cnyPrice
  1459. case "pay_remark":
  1460. if contractDetail.PayRemark == "" {
  1461. return
  1462. }
  1463. printContent = contractDetail.PayRemark
  1464. case "company_name":
  1465. if contractDetail.CompanyName == "" {
  1466. return
  1467. }
  1468. printContent = contractDetail.CompanyName
  1469. case "company_name_sign":
  1470. if contractDetail.CompanyName == "" {
  1471. return
  1472. }
  1473. printContent = "甲方:" + contractDetail.CompanyName
  1474. }
  1475. isPrint = true
  1476. return
  1477. }
  1478. // addTableV2 添加表格数据
  1479. func addTableV2(tableDataList TableData, doc *document.Document) (err error) {
  1480. //fmt.Println("表头名称:", title)
  1481. //插入一个新的段落
  1482. //nowParagraph := doc.AddParagraph()
  1483. ////表格数据
  1484. //table := doc.InsertTableAfter(nowParagraph)
  1485. //表格数据
  1486. doc.AddParagraph().Properties().AddSection(wml.ST_SectionMarkNextPage) //分页符
  1487. table := doc.AddTable()
  1488. //设置表格宽度
  1489. tableWidth := 6.5
  1490. table.Properties().SetWidth(measurement.Distance(tableWidth * measurement.Inch))
  1491. //表格宽度设置为自动
  1492. //table.Properties().SetWidthAuto()
  1493. //边框
  1494. borders := table.Properties().Borders()
  1495. // thin borders
  1496. borders.SetAll(wml.ST_BorderSingle, color.Auto, measurement.Zero)
  1497. //表格数据
  1498. rowList := tableDataList.List
  1499. //table.Properties().W
  1500. for i := 0; i < len(rowList); i++ {
  1501. //创建新的一行
  1502. row := table.AddRow()
  1503. //设置行高,第二个参数是设置固定值还是自动
  1504. row.Properties().SetHeight(30*measurement.Point, wml.ST_HeightRuleAtLeast)
  1505. //遍历列数据
  1506. rowDataList := rowList[i].RowList
  1507. if rowDataList != nil {
  1508. for j := 0; j < len(rowDataList); j++ {
  1509. cell := row.AddCell()
  1510. cellPara := cell.AddParagraph()
  1511. run := cellPara.AddRun()
  1512. //列数据
  1513. cellData := rowDataList[j]
  1514. //如果合并列大于0,那么就合并列
  1515. if cellData.ColumnSpan > 0 {
  1516. // column span / merged cells
  1517. cell.Properties().SetColumnSpan(cellData.ColumnSpan)
  1518. //_ = row.AddCell()
  1519. }
  1520. //如果指定了上下单元格合并,那么去合并上下单元格
  1521. if cellData.IsMerged {
  1522. //合并单元格类型
  1523. var mergeVal wml.ST_Merge
  1524. if cellData.IsFirstMerged { //如果是第一个合并行,那么开始重新合并
  1525. mergeVal = wml.ST_MergeRestart
  1526. } else { //如果不是第一个合并行,那么是继续合并
  1527. mergeVal = wml.ST_MergeContinue
  1528. }
  1529. cell.Properties().SetVerticalMerge(mergeVal)
  1530. }
  1531. //背景色
  1532. if cellData.Background != "" {
  1533. cell.Properties().SetShading(wml.ST_ShdSolid, getColorConf(cellData.Background), color.Auto)
  1534. }
  1535. //填充内容(文字)垂直对齐方式
  1536. cell.Properties().SetVerticalAlignment(wml.ST_VerticalJcCenter)
  1537. //将单元格设置为宽度百分比
  1538. if cellData.WidthPercent > 0 {
  1539. //cell.Properties().SetWidthPercent(cellData.WidthPercent)
  1540. //因为libreOffice不支持百分比的设置表格宽度
  1541. cellWidth := tableWidth * cellData.WidthPercent * measurement.Inch / 100
  1542. cell.Properties().SetWidth(measurement.Distance(cellWidth))
  1543. }
  1544. //文字排版(居中、左、右)
  1545. if cellData.TextAlign != "" {
  1546. cellPara.Properties().SetAlignment(getTextAlignConf(cellData.TextAlign))
  1547. //cellPara.Properties().SetAlignment(wml.ST_JcLeft)
  1548. }
  1549. //cell.Properties().SetAli
  1550. //设置是否加粗
  1551. run.Properties().SetBold(cellData.IsBold)
  1552. //设置字体大小
  1553. fontSize := 10.0
  1554. if cellData.FontSize > 0 {
  1555. fontSize = cellData.FontSize
  1556. }
  1557. run.Properties().SetSize(measurement.Distance(fontSize * measurement.Point))
  1558. //设置段落间的间距
  1559. cellPara.Properties().Spacing().SetLineSpacing(measurement.Distance(1.4*fontSize*measurement.Point), wml.ST_LineSpacingRuleAuto)
  1560. //设置段前间距
  1561. cellPara.Properties().Spacing().SetBefore(measurement.Distance(0.9 * fontSize * measurement.Point))
  1562. //设置段后间距
  1563. cellPara.Properties().Spacing().SetAfter(measurement.Distance(0.5 * fontSize * measurement.Point))
  1564. //设置字体
  1565. run.Properties().SetFontFamily("宋体")
  1566. //设置排序
  1567. run.Properties().SetVerticalAlignment(sharedTypes.ST_VerticalAlignRunBaseline)
  1568. //设置显示的文字
  1569. if cellData.Value != "" {
  1570. strSlice := strings.Split(cellData.Value, "<br/>")
  1571. for s := 0; s < len(strSlice); s++ {
  1572. if s > 0 {
  1573. run.AddBreak()
  1574. }
  1575. run.AddText(strSlice[s])
  1576. }
  1577. } else {
  1578. run.AddText("")
  1579. }
  1580. }
  1581. }
  1582. }
  1583. doc.AddParagraph()
  1584. return
  1585. }
  1586. // getContractAddress 获取展示的详细地址
  1587. func getContractAddress(contractDetail *contract.ContractDetail) (address string) {
  1588. ignoreStrs := []string{"北京市", "上海市", "天津市", "重庆市"}
  1589. if strings.Contains(strings.Join(ignoreStrs, ","), contractDetail.Province) {
  1590. address = contractDetail.City + contractDetail.Address
  1591. } else {
  1592. address = contractDetail.Province + contractDetail.City + contractDetail.Address
  1593. }
  1594. return
  1595. }
  1596. /**
  1597. *@tips libreoffice 转换指令:
  1598. * libreoffice6.2 invisible --convert-to pdf csDoc.doc --outdir /home/[转出目录]
  1599. *
  1600. * @function 实现文档类型转换为pdf或html
  1601. * @param command:libreofficed的命令(具体以版本为准);win:soffice; linux:libreoffice6.2
  1602. * fileSrcPath:转换文件的路径
  1603. * fileOutDir:转换后文件存储目录
  1604. * converterType:转换的类型pdf/html
  1605. * @return fileOutPath 转换成功生成的文件的路径 error 转换错误
  1606. */
  1607. func FuncDocs2Pdf(command string, fileSrcPath string, fileOutDir string, converterType string) (fileOutPath string, error error) {
  1608. //校验fileSrcPath
  1609. srcFile, erByOpenSrcFile := os.Open(fileSrcPath)
  1610. if erByOpenSrcFile != nil && os.IsNotExist(erByOpenSrcFile) {
  1611. return "", erByOpenSrcFile
  1612. }
  1613. //如文件输出目录fileOutDir不存在则自动创建
  1614. outFileDir, erByOpenFileOutDir := os.Open(fileOutDir)
  1615. if erByOpenFileOutDir != nil && os.IsNotExist(erByOpenFileOutDir) {
  1616. erByCreateFileOutDir := os.MkdirAll(fileOutDir, 0766)
  1617. if erByCreateFileOutDir != nil {
  1618. fmt.Println("File ouput dir create error.....", erByCreateFileOutDir.Error())
  1619. return "", erByCreateFileOutDir
  1620. }
  1621. }
  1622. //关闭流
  1623. defer func() {
  1624. _ = srcFile.Close()
  1625. _ = outFileDir.Close()
  1626. }()
  1627. //convert
  1628. cmd := exec.Command(command, "--invisible", "--convert-to", converterType,
  1629. fileSrcPath, "--outdir", fileOutDir)
  1630. byteByStat, errByCmdStart := cmd.Output()
  1631. //命令调用转换失败
  1632. if errByCmdStart != nil {
  1633. return "", errByCmdStart
  1634. }
  1635. //success
  1636. fileOutPath = fileOutDir + "/" + strings.Split(path.Base(fileSrcPath), ".")[0]
  1637. if converterType == "html" {
  1638. fileOutPath += ".html"
  1639. } else {
  1640. fileOutPath += ".pdf"
  1641. }
  1642. fmt.Println("文件转换成功...", string(byteByStat))
  1643. return fileOutPath, nil
  1644. }