contractPdf.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455
  1. package order
  2. import (
  3. "app.yhyue.com/moapp/jybase/common"
  4. "app.yhyue.com/moapp/jybase/date"
  5. "app.yhyue.com/moapp/jybase/redis"
  6. "context"
  7. "crypto/md5"
  8. "encoding/hex"
  9. "fmt"
  10. "github.com/gogf/gf/v2/errors/gerror"
  11. "github.com/gogf/gf/v2/frame/g"
  12. "github.com/gogf/gf/v2/util/gconv"
  13. "github.com/lukasjarosch/go-docx"
  14. "github.com/pkg/errors"
  15. cncap "github.com/rosbit/cn-capitalizer"
  16. "jyOrderManager/internal/jyutil"
  17. "jyOrderManager/internal/model"
  18. "log"
  19. "math/rand"
  20. "os/exec"
  21. "path/filepath"
  22. "runtime"
  23. "strconv"
  24. "strings"
  25. "time"
  26. )
  27. const (
  28. bigMemberContractNoFlag = "JYDZ05"
  29. subVipContractNoFlag = "JYDZ06"
  30. staticSourceDir = "resources/static/contract/"
  31. /*
  32. 1 超级订阅:https://www.kdocs.cn/l/cpqTn293crus
  33. 2 大会员(购买主体“企业”,非单省版):https://www.kdocs.cn/l/cv9HKtmoO3tj
  34. 3 大会员(购买主体“企业”,单省版):https://www.kdocs.cn/l/cm6OWJbTgmhE
  35. 4 大会员(购买主体“个人”,非单省版-有子账号):https://www.kdocs.cn/l/cgtyiJGraYmd
  36. 5 大会员(购买主体“个人”,非单省版-无子账号):https://www.kdocs.cn/l/clxt7vdFZ5Ea
  37. 6 大会员(购买主体“个人”,单省版-无子账号):https://www.kdocs.cn/l/cscOCLIvvG1a;
  38. 7 大会员(购买主体“个人”,单省版-有子账号):https://www.kdocs.cn/l/cfPHDdQsROBh
  39. */
  40. ContractTemplate_SUBVIP = "剑鱼标讯超级订阅产品服务协议书"
  41. ContractTemplate_MEMBER_ENT_NOTSINGLE = "剑鱼标讯大会员产品服务协议书-(企业-非单省版)"
  42. ContractTemplate_MEMBER_ENT_SINGLE = "剑鱼标讯大会员产品服务协议书-(企业-单省版)"
  43. ContractTemplate_MEMBER_PERSON_NOTSINGLE_ACCOUNT = "剑鱼标讯大会员产品服务协议书-(个人-非单省版-有子账号)"
  44. ContractTemplate_MEMBER_PERSON_NOTSINGLE_NOTACCOUNT = "剑鱼标讯大会员产品服务协议书-(个人-非单省版-无子账号)"
  45. ContractTemplate_MEMBER_PERSON_SINGLE_NOTACCOUNT = "剑鱼标讯大会员产品服务协议书-(个人-单省版-无子账号)"
  46. ContractTemplate_MEMBER_PERSON_SINGLE_ACCOUNT = "剑鱼标讯大会员产品服务协议书-(个人-单省版-有子账号)"
  47. )
  48. func GetContractPdf(ctx context.Context, orderCode, userName string) (interface{}, error) {
  49. detail, orderQueryErr := func() (map[string]interface{}, error) {
  50. if num, _ := g.DB().GetCount(ctx, "SELECT * FROM jy_order_detail WHERE order_code=?", orderCode); num != 1 {
  51. return nil, fmt.Errorf("当前订单不支持合同下载")
  52. }
  53. orderRes, err := g.DB().GetOne(ctx, "SELECT c.filter,c.service_type,a.audit_status,c.product_type,a.vip_type,a.salesperson,a.buy_subject,a.signing_subject,b.contract_status,b.seal_type,b.partyA_type,b.partyA_name,b.partyA_person,b.partyA_tel,b.partyA_address,b.partyB_person,b.remark,b.contract_money FROM dataexport_order a INNER JOIN jy_order_detail c ON a.order_code=c.order_code INNER JOIN contract b ON a.order_code=b.order_code WHERE a.order_code=? ", orderCode)
  54. if err != nil {
  55. return nil, err
  56. }
  57. if orderRes.IsEmpty() {
  58. return nil, fmt.Errorf("未找到订单")
  59. }
  60. return orderRes.Map(), nil
  61. }()
  62. if orderQueryErr != nil {
  63. return nil, gerror.Wrapf(orderQueryErr, "GetContractPdf orderQueryErr %s订单查询异常 %v\n", orderCode, orderQueryErr)
  64. }
  65. filterMap := *common.ObjToMap(detail["filter"])
  66. contractPass := func() error {
  67. /*
  68. 判断是否符合合同
  69. (1)订单审核状态是“已通过”;
  70. (2)签约主体为“北京剑鱼信息技术有限公司”,注:如签约主体为拓普则线下生成合同;
  71. (3)协议状态为“签协议”(“已签协议”文案修改为“签协议”,涉及:创建订单、订单审核、订单详情)
  72. (4)产品类型是“超级订阅”(且付费类型为“购买”、“续费”),或产品类型是“大会员”且会员套餐为“商机版2.0”、“专家版2.0”(且服务类型为“新购服务”、“延长服务”),注:超级订阅/大会员升级和其他产品类型,线下生成合同。
  73. */
  74. if common.IntAll(detail["audit_status"]) != 3 {
  75. return fmt.Errorf("订单未审核通过")
  76. }
  77. if common.ObjToString(detail["signing_subject"]) != "h01" {
  78. return fmt.Errorf("当前签约主体不支持生成电子合同")
  79. }
  80. if common.IntAll(detail["contract_status"]) != 1 {
  81. return fmt.Errorf("协议状态不需要")
  82. }
  83. var service_type = gconv.Int(detail["service_type"])
  84. switch common.ObjToString(detail["product_type"]) {
  85. case "VIP订阅":
  86. // 'vip订阅-0:购买 1:续费 2:升级',3试用
  87. if !(service_type == 1 || service_type == 4) {
  88. return fmt.Errorf("超级订阅当前订单不支持生成电子合同")
  89. }
  90. case "大会员":
  91. level := common.IntAll(filterMap["comboId"])
  92. if !(service_type == 1 || service_type == 4) && (level == 6 || level == 7) {
  93. return fmt.Errorf("大会员当前订单不支持生成电子合同")
  94. }
  95. default:
  96. return fmt.Errorf("当前订单类型不支持生成电子合同")
  97. }
  98. return nil
  99. }()
  100. if contractPass != nil {
  101. log.Printf("GetContractPdf contractPass %s合同校验异常 %v\n", orderCode, contractPass)
  102. return nil, contractPass
  103. }
  104. //
  105. contractDetail, err := func() (*ContractDetail, error) {
  106. remark := common.ObjToString(detail["remark"])
  107. ctd := &ContractDetail{
  108. ContractFromInfo: &ContractFromInfo{
  109. SealType: common.IntAll(detail["seal_type"]),
  110. PartyAType: common.IntAll(detail["partyA_type"]),
  111. PartyAName: common.ObjToString(detail["partyA_name"]),
  112. PartyAPerson: common.ObjToString(detail["partyA_person"]),
  113. PartyAContact: common.ObjToString(detail["partyA_tel"]),
  114. PartyAAddress: common.ObjToString(detail["partyA_address"]),
  115. PartyBPerson: common.ObjToString(detail["partyB_person"]),
  116. Remark: common.ObjToString(common.If(remark != "", remark, "无")),
  117. },
  118. Amount: common.Float64All(detail["contract_money"]),
  119. }
  120. buy_subject := common.IntAll(detail["buy_subject"])
  121. switch common.ObjToString(detail["product_type"]) {
  122. case "VIP订阅":
  123. var filter model.VipCycleFilter
  124. if err := gconv.Struct(filterMap, &filter); err != nil {
  125. return nil, gerror.Wrapf(err, "格式化超级订阅内容异常")
  126. }
  127. //时间
  128. switch filter.BuyType { //1天 2月 3年 4季度
  129. case 1:
  130. ctd.ServiceTime = fmt.Sprintf("%d天(自然日)", filter.BuyCycle)
  131. case 2:
  132. ctd.ServiceTime = fmt.Sprintf("%d个月", filter.BuyCycle)
  133. case 3:
  134. ctd.ServiceTime = fmt.Sprintf("%d个月", filter.BuyCycle*12)
  135. case 4:
  136. ctd.ServiceTime = fmt.Sprintf("%d个月", filter.BuyCycle*3)
  137. default:
  138. return nil, fmt.Errorf("未知周期单位")
  139. }
  140. switch filter.GiftType { //1天 2月 3年 4季度
  141. case 1:
  142. ctd.ServiceTime = fmt.Sprintf("送%d天(自然日)", filter.GiftCycle)
  143. case 2:
  144. ctd.ServiceTime = fmt.Sprintf("送%d个月", filter.GiftCycle)
  145. case 3:
  146. ctd.ServiceTime = fmt.Sprintf("送%d个月", filter.GiftCycle*12)
  147. case 4:
  148. ctd.ServiceTime = fmt.Sprintf("送%d个月", filter.GiftCycle*3)
  149. }
  150. if num := filter.BuyAccountCount; num > 0 {
  151. ctd.Service = fmt.Sprintf("省份版超级订阅(%d个省)", num)
  152. } else {
  153. ctd.Service = "全国版超级订阅"
  154. }
  155. if buy_subject == 1 {
  156. ctd.AccountNum = 1
  157. } else {
  158. ctd.AccountNum = 1 + filter.BuyAccountCount + filter.GiftAccountCount
  159. }
  160. ctd.ContractFlag = subVipContractNoFlag
  161. ctd.ContractTemplate = ContractTemplate_SUBVIP
  162. case "大会员":
  163. level := common.IntAll(filterMap["comboId"])
  164. isSINGLE := common.IntAll(filterMap["areaCount"]) == 1 //是单省版
  165. hasACCOUNT := common.IntAll(filterMap["free_sub_num"])+common.IntAll(filterMap["pay_sub_num"]) >= 1 //有子账号
  166. if buy_subject == 2 {
  167. ctd.AccountNum = common.IntAll(detail["buy_count"])
  168. }
  169. if level == 6 {
  170. if isSINGLE {
  171. ctd.Service = "大会员商机版2.0(单省版)"
  172. } else {
  173. ctd.Service = "大会员商机版2.0"
  174. }
  175. } else if level == 7 {
  176. ctd.Service = "大会员专家版2.0"
  177. }
  178. cycleType := common.IntAll(filterMap["cycleType"])
  179. if cycleType == 1 {
  180. ctd.ServiceTime = fmt.Sprintf("%d天(自然日)", common.IntAll(filterMap["cycle"]))
  181. } else {
  182. ctd.ServiceTime = fmt.Sprintf("%d个月", common.IntAll(filterMap["cycle"]))
  183. }
  184. if buy_subject == 1 { //个人
  185. ctd.AccountNum = common.IntAll(filterMap["free_sub_num"]) + common.IntAll(filterMap["pay_sub_num"]) + 1
  186. if isSINGLE {
  187. if hasACCOUNT {
  188. ctd.ContractTemplate = ContractTemplate_MEMBER_PERSON_SINGLE_ACCOUNT
  189. } else {
  190. ctd.ContractTemplate = ContractTemplate_MEMBER_PERSON_SINGLE_NOTACCOUNT
  191. }
  192. } else {
  193. if hasACCOUNT {
  194. ctd.ContractTemplate = ContractTemplate_MEMBER_PERSON_NOTSINGLE_ACCOUNT
  195. } else {
  196. ctd.ContractTemplate = ContractTemplate_MEMBER_PERSON_NOTSINGLE_NOTACCOUNT
  197. }
  198. }
  199. } else { //企业
  200. if isSINGLE {
  201. ctd.ContractTemplate = ContractTemplate_MEMBER_ENT_SINGLE
  202. } else {
  203. ctd.ContractTemplate = ContractTemplate_MEMBER_ENT_NOTSINGLE
  204. }
  205. }
  206. ctd.ContractFlag = bigMemberContractNoFlag
  207. }
  208. return ctd, nil
  209. }()
  210. if err != nil {
  211. return nil, gerror.Wrapf(err, "获取合同内容出错")
  212. }
  213. filePath, getFilePathErr := func() (string, error) {
  214. md5Str := contractDetail.GetMd5()
  215. contract, err := g.DB().GetOne(ctx, "SELECT file_path FROM contract_pdf WHERE order_code=? and md5=?", orderCode, md5Str)
  216. if err != nil {
  217. return "", gerror.Wrapf(err, "获取pdf电子合同异常")
  218. }
  219. if contract.IsEmpty() {
  220. now := time.Now()
  221. docxAbsolutePath, err := contractDetail.getDocxFile(now)
  222. if err != nil {
  223. return "", errors.Wrap(err, "生成电子合同docx文件异常")
  224. }
  225. if err = contractDetail.convertWordToPDF(docxAbsolutePath); err != nil {
  226. return "", errors.Wrap(err, "生成电子合同pdf文件异常")
  227. }
  228. // 获取访问路径
  229. var (
  230. pdfFilePath = jyutil.GetRequestPath(strings.Replace(docxAbsolutePath, ".docx", ".pdf", 1))
  231. contractCode = contractDetail.GetContractNoStr(now)
  232. )
  233. if _, err := g.DB().Save(ctx, "contract_pdf", g.Map{
  234. "order_code": orderCode,
  235. "code": contractCode,
  236. "md5": md5Str,
  237. "create_person": userName,
  238. "file_path": pdfFilePath,
  239. "create_time": now.Format(date.Date_Full_Layout),
  240. }); err != nil {
  241. return "", errors.Wrapf(err, "保存pdf内容异常")
  242. }
  243. if _, err := g.DB().Update(ctx, "contract", g.Map{
  244. "contract_code": contractCode,
  245. }, "order_code=?", orderCode); err != nil {
  246. return "", errors.Wrapf(err, "更新合同异常")
  247. }
  248. return pdfFilePath, nil
  249. }
  250. return gconv.String(contract.Map()["file_path"]), nil
  251. }()
  252. if getFilePathErr != nil {
  253. log.Printf("GetContractPdf getFilePathErr %s合同生成异常 %v\n", orderCode, getFilePathErr)
  254. return nil, getFilePathErr
  255. }
  256. return filePath, nil
  257. }
  258. type ContractFromInfo struct {
  259. SealType int `json:"seal_type" doc:"协议类型 1:有电子章 2:无电子章"`
  260. PartyAType int `json:"partyAType" doc:"甲方类型 1:个人,2:企业"`
  261. PartyAName string `json:"partyAName" doc:"甲方名称"`
  262. PartyAPerson string `json:"partyAPerson" doc:"甲方联系人"`
  263. PartyAContact string `json:"partyAContact" doc:"甲方联系方式"`
  264. PartyAAddress string `json:"partyAAddresst" doc:"甲方联系地址"`
  265. PartyBPerson string `json:"partyBPerson" doc:"乙方联系人"`
  266. Remark string `json:"remark" doc:"协议备注"`
  267. }
  268. type ContractDetail struct {
  269. *ContractFromInfo
  270. Service string `json:"service" doc:"服务内容"`
  271. AccountNum int `json:"accountNum" doc:"账户个数"`
  272. ServiceTime string `json:"serviceTime" doc:"时长"`
  273. Amount float64 `json:"amount" doc:"金额"`
  274. ContractNo string `json:"contractNo" doc:"协议编号"`
  275. ContractFlag string `json:"contractFlag" doc:"协议编号标识"`
  276. ContractTemplate string `json:"contractTemplate" doc:"模版名字"`
  277. }
  278. // GetMd5 计算合同md5 (甲方+甲方类型+联系人+联系方式+地址+备注+乙方联系人+是否有电子章+服务内容+金额+账户个数+时长)
  279. func (detail *ContractDetail) GetMd5() string {
  280. hasher := md5.New()
  281. hasher.Write([]byte(fmt.Sprintf("%s_%d_%s_%s_%s_%s_%s_%d_%s_%d_%d_%s", detail.PartyAName, detail.PartyAType, detail.PartyAPerson, detail.PartyAContact,
  282. detail.PartyAAddress, detail.Remark, detail.PartyBPerson, detail.SealType, detail.Service, detail.Amount, detail.AccountNum, detail.ServiceTime)))
  283. hashInBytes := hasher.Sum(nil)
  284. return hex.EncodeToString(hashInBytes)
  285. }
  286. func (detail *ContractDetail) getDocxFile(createTime time.Time) (filePath string, err error) {
  287. replaceMap := docx.PlaceholderMap{
  288. "PartyA.Name": detail.PartyAName, //甲方名字 {PartyA.Name}
  289. "PartyA.Person": detail.PartyAPerson, //甲方联系人 {PartyA.Person}
  290. "PartyA.Tel": detail.PartyAContact, //甲方联系方式 {PartyA.Tel}
  291. "PartyA.Addr": detail.PartyAAddress, //甲方地址 {PartyA.Addr}
  292. "Contract.No": detail.GetContractNoStr(createTime), //合同编号 {Contract.No}
  293. "Contract.Service.Detail": detail.Service, //会员服务 {Contract.Service.Detail}
  294. "Contract.Service.Time": detail.ServiceTime, //服务时长 {Contract.Service.Time}
  295. "Contract.Account.Num": detail.AccountNum, //账号个数 {Contract.Account.Num}
  296. "Contract.Remark": detail.Remark, //合同备注 {Contract.Remark}
  297. "Contract.Amount": strconv.FormatFloat(detail.Amount/100, 'f', -1, 64), //合同金额 {Contract.Amount}
  298. "Contract.Amount.Font": cncap.CapitalizeCurrency(detail.Amount / 100.0), //合同大写金额 {Contract.Amount.Font}
  299. "PartyB.Person": detail.PartyBPerson, //乙方联系人 {PartyB.Person}
  300. "PartyB.Date.Y": createTime.Year(), //乙方日期-年 {PartyB.Date.Year}
  301. "PartyB.Date.M": fmt.Sprintf("%02d", int(createTime.Month())), //乙方日期-月 {PartyB.Date.Month}
  302. "PartyB.Date.D": fmt.Sprintf("%02d", createTime.Day()), //乙方日期-日 {PartyB.Date.Day}
  303. }
  304. if detail.PartyAType == 2 {
  305. replaceMap["PartyA.EndName"] = detail.PartyAName
  306. } else {
  307. replaceMap["PartyA.EndName"] = ""
  308. }
  309. numPageEmptyRows := 0
  310. longNum := len([]rune(fmt.Sprintf("%s%s%d%s", detail.Service, detail.ServiceTime, detail.AccountNum, detail.Remark)))
  311. if longNum <= 30 { //备注过短时,公章上移 18+13
  312. numPageEmptyRows = 3
  313. } else if longNum > 30 && longNum <= 88 {
  314. numPageEmptyRows = 2
  315. } else if longNum > 88 && longNum <= 146 {
  316. numPageEmptyRows = 1
  317. }
  318. replaceMap["PageEmptyRows"] = strings.Repeat(" ", numPageEmptyRows*180)
  319. //计算第一页空行数,把落款固定到最下部
  320. // read and parse the template docx
  321. doc, err := docx.Open(fmt.Sprintf("%s%s.docx", staticSourceDir, detail.ContractTemplate))
  322. if err != nil {
  323. return "", errors.Wrap(err, "docx文件模版文件异常")
  324. }
  325. // replace the keys with values from replaceMap
  326. err = doc.ReplaceAll(replaceMap)
  327. if err != nil {
  328. return "", errors.Wrap(err, "docx文件模版文件参数替换异常")
  329. }
  330. fileAbsolutePath := jyutil.GetFilePath("docx", "contract")
  331. // write out a new file
  332. err = doc.WriteToFile(fileAbsolutePath)
  333. if err != nil {
  334. return "", errors.Wrap(err, "docx文件生成异常")
  335. }
  336. return fileAbsolutePath, nil
  337. }
  338. // GetContractNoStr 获取生成协议编号
  339. func (detail *ContractDetail) GetContractNoStr(createTime time.Time) string {
  340. if detail.ContractNo != "" {
  341. return detail.ContractNo
  342. }
  343. dataStr := createTime.Format(date.Date_yyyyMMdd)
  344. key := fmt.Sprintf("%s_%s", detail.ContractFlag, dataStr)
  345. detail.ContractNo = fmt.Sprintf("%s【%s】第%03d号", detail.ContractFlag, dataStr, redis.Incr("newother", key))
  346. return detail.ContractNo
  347. }
  348. // convertWordToPDF word转pdf
  349. func (detail *ContractDetail) convertWordToPDF(inputDocxPath string) error {
  350. var commandName string
  351. var commandArg string
  352. switch runtime.GOOS {
  353. case "windows":
  354. commandName = "cmd"
  355. commandArg = "/c"
  356. case "linux", "darwin":
  357. commandName = "sh"
  358. commandArg = "-c"
  359. default:
  360. return fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
  361. }
  362. fileDir := filepath.Dir(inputDocxPath)
  363. fileFullName := filepath.Base(inputDocxPath)
  364. fileName := strings.TrimSuffix(fileFullName, filepath.Ext(fileFullName))
  365. pdfFileFullPath := fmt.Sprintf("%s/%s.pdf", fileDir, fileName) //生成pdf路径
  366. pngFileFullPath := fmt.Sprintf("%s/%s.png", fileDir, fileName) //生成图片路径
  367. pngsMatchPath := fmt.Sprintf("%s/%s-*.png", fileDir, fileName) //生成图片路径
  368. // 一、soffice 生成pdf文件
  369. createPdfFile := exec.Command(commandName, commandArg, fmt.Sprintf("soffice --headless --invisible --convert-to pdf %s --outdir %s", inputDocxPath, fileDir))
  370. if _, err := createPdfFile.CombinedOutput(); err != nil {
  371. fmt.Printf(fmt.Sprintf("soffice --headless --invisible --convert-to pdf %s --outdir %s", inputDocxPath, fileDir))
  372. return errors.Wrap(err, "Command execution createPdfFile failed:")
  373. }
  374. // 二、convert pdf内容转为图片
  375. var hasSeal bool = detail.SealType == 1
  376. if hasSeal {
  377. createPngFile := exec.Command(commandName, commandArg, fmt.Sprintf("convert -density 300x300 -units pixelsperinch %s -background white -alpha remove -alpha off -quality 100 -antialias -resize 100%% %s ", pdfFileFullPath, pngFileFullPath))
  378. if _, err := createPngFile.CombinedOutput(); err != nil {
  379. fmt.Printf("convert -density 300x300 -units pixelsperinch %s -background white -alpha remove -alpha off -quality 100 -antialias -resize 100%% %s ", pdfFileFullPath, pngFileFullPath)
  380. return errors.Wrap(err, "Command execution createPngFile failed:")
  381. }
  382. //每张图片
  383. cmd := exec.Command("sh", "-c", fmt.Sprintf("ls %s", pngsMatchPath))
  384. out, err := cmd.CombinedOutput()
  385. if err != nil || len(out) == 0 {
  386. return errors.Wrap(err, "Command execution ls pngs failed:")
  387. }
  388. for index, fileName := range strings.Split(string(out), "\n") {
  389. if fileTmpPath := strings.TrimSpace(fileName); fileTmpPath != "" {
  390. var x, y int64
  391. rand.Seed(time.Now().UnixNano())
  392. // 随机盖章位置 生成一个随机整数
  393. if index == 0 { //首页需要盖着日期
  394. x = 680 + rand.Int63n(10)
  395. y = 130 + rand.Int63n(30)
  396. //if len([]rune(fmt.Sprintf("%s%s%d%s", detail.Service, detail.ServiceTime, detail.AccountNum, detail.Remark))) <= 32 { //备注过短时,公章上移
  397. // y = y + 50
  398. //}
  399. } else {
  400. x = 300 + rand.Int63n(200)
  401. y = 500 + rand.Int63n(200)
  402. }
  403. exeSeal := exec.Command(commandName, commandArg, fmt.Sprintf("convert %s \\( %s -resize 50%% \\) -gravity southeast -geometry +%d+%d -composite %s", fileTmpPath, fmt.Sprintf("%sz.png", staticSourceDir), x, y, fileTmpPath))
  404. if _, err := exeSeal.CombinedOutput(); err != nil {
  405. return errors.Wrap(err, "Command execution exeSeal failed:")
  406. }
  407. }
  408. }
  409. createPngPdfFile := exec.Command(commandName, commandArg, fmt.Sprintf("convert %s %s", pngsMatchPath, pdfFileFullPath))
  410. if _, err := createPngPdfFile.CombinedOutput(); err != nil {
  411. fmt.Printf("convert %s %s", pngsMatchPath, pdfFileFullPath)
  412. return errors.Wrap(err, "Command execution createPngFile failed:")
  413. }
  414. } else {
  415. createPngPdfFile := exec.Command(commandName, commandArg, fmt.Sprintf("convert -density 300x300 -units pixelsperinch %s -background white -alpha remove -alpha off -quality 100 -antialias -resize 100%% %s && convert %s %s", pdfFileFullPath, pngFileFullPath, pngsMatchPath, pdfFileFullPath))
  416. if _, err := createPngPdfFile.CombinedOutput(); err != nil {
  417. fmt.Println(fmt.Sprintf("convert -density 300x300 -units pixelsperinch %s -background white -alpha remove -alpha off -quality 100 -antialias -resize 100%% %s && convert %s %s", pdfFileFullPath, pngFileFullPath, pngsMatchPath, pdfFileFullPath))
  418. return errors.Wrap(err, "Command execution createPngFile failed:")
  419. }
  420. }
  421. // 三、清除多余文件
  422. clearFileCmd := exec.Command(commandName, commandArg, fmt.Sprintf("chmod -x %s && rm -rf %s %s", pngsMatchPath, pngsMatchPath, inputDocxPath))
  423. if err := clearFileCmd.Run(); err != nil {
  424. return errors.Wrap(err, "Command execution clearFileCmd failed:")
  425. }
  426. return nil
  427. }