word.go 56 KB

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