wkyuer 4 miesięcy temu
rodzic
commit
db264609b3
2 zmienionych plików z 487 dodań i 0 usunięć
  1. 33 0
      internal/jyutil/path.go
  2. 454 0
      internal/logic/order/contractPdf.go

+ 33 - 0
internal/jyutil/path.go

@@ -0,0 +1,33 @@
+package jyutil
+
+import (
+	"app.yhyue.com/moapp/jybase/common"
+	"context"
+	"fmt"
+	"github.com/gogf/gf/v2/frame/g"
+	"os"
+	"path/filepath"
+	"time"
+)
+
+func GetFilePath(str, filetype string) string {
+	var tmp = time.Now().Format("20060102150405001")
+	var name = tmp + common.GetComplexRandom(8, 0, 0) + "." + str
+	uploadPath := g.Cfg().MustGet(ctx, "upload_path").String()
+	var pathStr = uploadPath + filetype + "/" + tmp[:4] + "/" + tmp[4:6] + "/" + tmp[6:8] + "/"
+	if err := os.MkdirAll(pathStr, 0700); err != nil {
+		g.Log().Errorf(context.Background(), "创建文件夹 %s异常 %v", pathStr, err)
+	}
+	return pathStr + name
+}
+
+func GetRequestPath(absolutePath string) string {
+	uploadPath := g.Cfg().MustGet(ctx, "upload_path").String()
+	lastPart := filepath.Base(uploadPath)
+	relativePath, err := filepath.Rel(uploadPath, absolutePath)
+	if err != nil {
+		g.Log().Errorf(context.Background(), "获取相对路径时发生错误 %s异常 %v", absolutePath, err)
+		return ""
+	}
+	return fmt.Sprintf("/%s/%s", lastPart, relativePath)
+}

+ 454 - 0
internal/logic/order/contractPdf.go

@@ -0,0 +1,454 @@
+package order
+
+import (
+	"app.yhyue.com/moapp/jybase/common"
+	"app.yhyue.com/moapp/jybase/date"
+	"app.yhyue.com/moapp/jybase/redis"
+	"context"
+	"crypto/md5"
+	"encoding/hex"
+	"fmt"
+	"github.com/gogf/gf/v2/errors/gerror"
+	"github.com/gogf/gf/v2/frame/g"
+	"github.com/gogf/gf/v2/util/gconv"
+	"github.com/lukasjarosch/go-docx"
+	"github.com/pkg/errors"
+	cncap "github.com/rosbit/cn-capitalizer"
+	"jyOrderManager/internal/jyutil"
+	"jyOrderManager/internal/model"
+	"log"
+	"math/rand"
+	"os/exec"
+	"path/filepath"
+	"runtime"
+	"strconv"
+	"strings"
+	"time"
+)
+
+const (
+	bigMemberContractNoFlag = "JYDZ05"
+	subVipContractNoFlag    = "JYDZ06"
+
+	/*
+	  1  超级订阅:https://www.kdocs.cn/l/cpqTn293crus
+	  2 大会员(购买主体“企业”,非单省版):https://www.kdocs.cn/l/cv9HKtmoO3tj
+	  3 大会员(购买主体“企业”,单省版):https://www.kdocs.cn/l/cm6OWJbTgmhE
+	  4 大会员(购买主体“个人”,非单省版-有子账号):https://www.kdocs.cn/l/cgtyiJGraYmd
+	  5 大会员(购买主体“个人”,非单省版-无子账号):https://www.kdocs.cn/l/clxt7vdFZ5Ea
+	  6 大会员(购买主体“个人”,单省版-无子账号):https://www.kdocs.cn/l/cscOCLIvvG1a;
+	  7  大会员(购买主体“个人”,单省版-有子账号):https://www.kdocs.cn/l/cfPHDdQsROBh
+	*/
+	ContractTemplate_SUBVIP                             = "剑鱼标讯超级订阅产品服务协议书"
+	ContractTemplate_MEMBER_ENT_NOTSINGLE               = "剑鱼标讯大会员产品服务协议书-(企业-非单省版)"
+	ContractTemplate_MEMBER_ENT_SINGLE                  = "剑鱼标讯大会员产品服务协议书-(企业-单省版)"
+	ContractTemplate_MEMBER_PERSON_NOTSINGLE_ACCOUNT    = "剑鱼标讯大会员产品服务协议书-(个人-非单省版-有子账号)"
+	ContractTemplate_MEMBER_PERSON_NOTSINGLE_NOTACCOUNT = "剑鱼标讯大会员产品服务协议书-(个人-非单省版-无子账号)"
+	ContractTemplate_MEMBER_PERSON_SINGLE_NOTACCOUNT    = "剑鱼标讯大会员产品服务协议书-(个人-单省版-无子账号)"
+	ContractTemplate_MEMBER_PERSON_SINGLE_ACCOUNT       = "剑鱼标讯大会员产品服务协议书-(个人-单省版-有子账号)"
+)
+
+func GetContractPdf(ctx context.Context, orderCode, userName string) (interface{}, error) {
+	detail, orderQueryErr := func() (map[string]interface{}, error) {
+		if num, _ := g.DB().GetCount(ctx, "SELECT count(*) FROM jy_order_detail WHERE order_code=?", orderCode); num != 1 {
+			return nil, fmt.Errorf("当前订单不支持合同下载")
+		}
+		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)
+		if err != nil {
+			return nil, err
+		}
+
+		if orderRes.IsEmpty() {
+			return nil, fmt.Errorf("未找到订单")
+		}
+		return orderRes.Map(), nil
+	}()
+
+	if orderQueryErr != nil {
+		return nil, gerror.Wrapf(orderQueryErr, "GetContractPdf orderQueryErr %s订单查询异常 %v\n", orderCode, orderQueryErr)
+	}
+
+	filterMap := *common.ObjToMap(detail["filter"])
+	contractPass := func() error {
+		/*
+			判断是否符合合同
+			(1)订单审核状态是“已通过”;
+			(2)签约主体为“北京剑鱼信息技术有限公司”,注:如签约主体为拓普则线下生成合同;
+			(3)协议状态为“签协议”(“已签协议”文案修改为“签协议”,涉及:创建订单、订单审核、订单详情)
+			(4)产品类型是“超级订阅”(且付费类型为“购买”、“续费”),或产品类型是“大会员”且会员套餐为“商机版2.0”、“专家版2.0”(且服务类型为“新购服务”、“延长服务”),注:超级订阅/大会员升级和其他产品类型,线下生成合同。
+		*/
+		if common.IntAll(detail["audit_status"]) != 3 {
+			return fmt.Errorf("订单未审核通过")
+		}
+		if common.ObjToString(detail["signing_subject"]) != "h01" {
+			return fmt.Errorf("当前签约主体不支持生成电子合同")
+		}
+		if common.IntAll(detail["contract_status"]) != 1 {
+			return fmt.Errorf("协议状态不需要")
+		}
+		var service_type = gconv.Int(detail["service_type"])
+		switch common.ObjToString(detail["product_type"]) {
+		case "VIP订阅":
+			// 'vip订阅-0:购买 1:续费 2:升级',3试用
+			if !(service_type == 1 || service_type == 4) {
+				return fmt.Errorf("超级订阅当前订单不支持生成电子合同")
+			}
+		case "大会员":
+			level := common.IntAll(filterMap["comboId"])
+			if !(service_type == 1 || service_type == 4) && (level == 6 || level == 7) {
+				return fmt.Errorf("大会员当前订单不支持生成电子合同")
+			}
+		default:
+			return fmt.Errorf("当前订单类型不支持生成电子合同")
+		}
+		return nil
+	}()
+
+	if contractPass != nil {
+		log.Printf("GetContractPdf contractPass %s合同校验异常 %v\n", orderCode, contractPass)
+		return nil, contractPass
+	}
+
+	//
+	contractDetail, err := func() (*ContractDetail, error) {
+		remark := common.ObjToString(detail["remark"])
+		ctd := &ContractDetail{
+			ContractFromInfo: &ContractFromInfo{
+				SealType:      common.IntAll(detail["seal_type"]),
+				PartyAType:    common.IntAll(detail["partyA_type"]),
+				PartyAName:    common.ObjToString(detail["partyA_name"]),
+				PartyAPerson:  common.ObjToString(detail["partyA_person"]),
+				PartyAContact: common.ObjToString(detail["partyA_tel"]),
+				PartyAAddress: common.ObjToString(detail["partyA_address"]),
+				PartyBPerson:  common.ObjToString(detail["partyB_person"]),
+				Remark:        common.ObjToString(common.If(remark != "", remark, "无")),
+			},
+			Amount: common.Float64All(detail["contract_money"]),
+		}
+		buy_subject := common.IntAll(detail["buy_subject"])
+
+		switch common.ObjToString(detail["product_type"]) {
+		case "VIP订阅":
+			var filter model.VipCycleFilter
+			if err := gconv.Struct(filterMap, &filter); err != nil {
+				return nil, gerror.Wrapf(err, "格式化超级订阅内容异常")
+			}
+			//时间
+			switch filter.BuyType { //1天 2月 3年 4季度
+			case 1:
+				ctd.ServiceTime = fmt.Sprintf("%d天(自然日)", filter.BuyCycle)
+			case 2:
+				ctd.ServiceTime = fmt.Sprintf("%d个月", filter.BuyCycle)
+			case 3:
+				ctd.ServiceTime = fmt.Sprintf("%d个月", filter.BuyCycle*12)
+			case 4:
+				ctd.ServiceTime = fmt.Sprintf("%d个月", filter.BuyCycle*3)
+			default:
+				return nil, fmt.Errorf("未知周期单位")
+			}
+			switch filter.GiftType { //1天 2月 3年 4季度
+			case 1:
+				ctd.ServiceTime = fmt.Sprintf("送%d天(自然日)", filter.GiftCycle)
+			case 2:
+				ctd.ServiceTime = fmt.Sprintf("送%d个月", filter.GiftCycle)
+			case 3:
+				ctd.ServiceTime = fmt.Sprintf("送%d个月", filter.GiftCycle*12)
+			case 4:
+				ctd.ServiceTime = fmt.Sprintf("送%d个月", filter.GiftCycle*3)
+			}
+
+			if num := filter.BuyAccountCount; num > 0 {
+				ctd.Service = fmt.Sprintf("省份版超级订阅(%d个省)", num)
+			} else {
+				ctd.Service = "全国版超级订阅"
+			}
+			if buy_subject == 1 {
+				ctd.AccountNum = 1
+			} else {
+				ctd.AccountNum = 1 + filter.BuyAccountCount + filter.GiftAccountCount
+			}
+			ctd.ContractFlag = subVipContractNoFlag
+			ctd.ContractTemplate = ContractTemplate_SUBVIP
+		case "大会员":
+			level := common.IntAll(filterMap["comboId"])
+			isSINGLE := common.IntAll(filterMap["areaCount"]) == 1                                              //是单省版
+			hasACCOUNT := common.IntAll(filterMap["free_sub_num"])+common.IntAll(filterMap["pay_sub_num"]) >= 1 //有子账号
+			if buy_subject == 2 {
+				ctd.AccountNum = common.IntAll(detail["buy_count"])
+			}
+			if level == 6 {
+				if isSINGLE {
+					ctd.Service = "大会员商机版2.0(单省版)"
+				} else {
+					ctd.Service = "大会员商机版2.0"
+				}
+			} else if level == 7 {
+				ctd.Service = "大会员专家版2.0"
+			}
+
+			cycleType := common.IntAll(filterMap["cycleType"])
+			if cycleType == 1 {
+				ctd.ServiceTime = fmt.Sprintf("%d天(自然日)", common.IntAll(filterMap["cycle"]))
+			} else {
+				ctd.ServiceTime = fmt.Sprintf("%d个月", common.IntAll(filterMap["cycle"]))
+			}
+
+			if buy_subject == 1 { //个人
+				ctd.AccountNum = common.IntAll(filterMap["free_sub_num"]) + common.IntAll(filterMap["pay_sub_num"]) + 1
+				if isSINGLE {
+					if hasACCOUNT {
+						ctd.ContractTemplate = ContractTemplate_MEMBER_PERSON_SINGLE_ACCOUNT
+					} else {
+						ctd.ContractTemplate = ContractTemplate_MEMBER_PERSON_SINGLE_NOTACCOUNT
+					}
+				} else {
+					if hasACCOUNT {
+						ctd.ContractTemplate = ContractTemplate_MEMBER_PERSON_NOTSINGLE_ACCOUNT
+					} else {
+						ctd.ContractTemplate = ContractTemplate_MEMBER_PERSON_NOTSINGLE_NOTACCOUNT
+					}
+				}
+			} else { //企业
+				if isSINGLE {
+					ctd.ContractTemplate = ContractTemplate_MEMBER_ENT_SINGLE
+				} else {
+					ctd.ContractTemplate = ContractTemplate_MEMBER_ENT_NOTSINGLE
+				}
+			}
+			ctd.ContractFlag = bigMemberContractNoFlag
+		}
+		return ctd, nil
+	}()
+	if err != nil {
+		return nil, gerror.Wrapf(err, "获取合同内容出错")
+	}
+	filePath, getFilePathErr := func() (string, error) {
+		md5Str := contractDetail.GetMd5()
+		contract, err := g.DB().GetOne(ctx, "SELECT file_path FROM contract_pdf WHERE order_code=? and md5=?", orderCode, md5Str)
+		if err != nil {
+			return "", gerror.Wrapf(err, "获取pdf电子合同异常")
+		}
+		if contract.IsEmpty() {
+			now := time.Now()
+			docxAbsolutePath, err := contractDetail.getDocxFile(now)
+			if err != nil {
+				return "", errors.Wrap(err, "生成电子合同docx文件异常")
+			}
+			if err = contractDetail.convertWordToPDF(docxAbsolutePath); err != nil {
+				return "", errors.Wrap(err, "生成电子合同pdf文件异常")
+			}
+			// 获取访问路径
+			var (
+				pdfFilePath  = jyutil.GetRequestPath(strings.Replace(docxAbsolutePath, ".docx", ".pdf", 1))
+				contractCode = contractDetail.GetContractNoStr(now)
+			)
+			if _, err := g.DB().Save(ctx, "contract_pdf", g.Map{
+				"order_code":    orderCode,
+				"code":          contractCode,
+				"md5":           md5Str,
+				"create_person": userName,
+				"file_path":     pdfFilePath,
+				"create_time":   now.Format(date.Date_Full_Layout),
+			}); err != nil {
+				return "", errors.Wrapf(err, "保存pdf内容异常")
+			}
+			if _, err := g.DB().Update(ctx, "contract", g.Map{
+				"contract_code": contractCode,
+			}, "order_code=?", orderCode); err != nil {
+				return "", errors.Wrapf(err, "更新合同异常")
+			}
+			return pdfFilePath, nil
+		}
+		return gconv.String(contract.Map()["file_path"]), nil
+	}()
+	if getFilePathErr != nil {
+		log.Printf("GetContractPdf getFilePathErr %s合同生成异常 %v\n", orderCode, getFilePathErr)
+		return nil, getFilePathErr
+	}
+	return filePath, nil
+}
+
+type ContractFromInfo struct {
+	SealType      int    `json:"seal_type" doc:"协议类型 1:有电子章 2:无电子章"`
+	PartyAType    int    `json:"partyAType" doc:"甲方类型 1:个人,2:企业"`
+	PartyAName    string `json:"partyAName" doc:"甲方名称"`
+	PartyAPerson  string `json:"partyAPerson" doc:"甲方联系人"`
+	PartyAContact string `json:"partyAContact" doc:"甲方联系方式"`
+	PartyAAddress string `json:"partyAAddresst" doc:"甲方联系地址"`
+	PartyBPerson  string `json:"partyBPerson" doc:"乙方联系人"`
+	Remark        string `json:"remark" doc:"协议备注"`
+}
+
+type ContractDetail struct {
+	*ContractFromInfo
+	Service          string  `json:"service" doc:"服务内容"`
+	AccountNum       int     `json:"accountNum" doc:"账户个数"`
+	ServiceTime      string  `json:"serviceTime" doc:"时长"`
+	Amount           float64 `json:"amount" doc:"金额"`
+	ContractNo       string  `json:"contractNo" doc:"协议编号"`
+	ContractFlag     string  `json:"contractFlag" doc:"协议编号标识"`
+	ContractTemplate string  `json:"contractTemplate" doc:"模版名字"`
+}
+
+// GetMd5 计算合同md5 (甲方+甲方类型+联系人+联系方式+地址+备注+乙方联系人+是否有电子章+服务内容+金额+账户个数+时长)
+func (detail *ContractDetail) GetMd5() string {
+	hasher := md5.New()
+	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,
+		detail.PartyAAddress, detail.Remark, detail.PartyBPerson, detail.SealType, detail.Service, detail.Amount, detail.AccountNum, detail.ServiceTime)))
+	hashInBytes := hasher.Sum(nil)
+	return hex.EncodeToString(hashInBytes)
+}
+
+func (detail *ContractDetail) getDocxFile(createTime time.Time) (filePath string, err error) {
+	replaceMap := docx.PlaceholderMap{
+		"PartyA.Name":             detail.PartyAName,                                   //甲方名字 {PartyA.Name}
+		"PartyA.Person":           detail.PartyAPerson,                                 //甲方联系人 {PartyA.Person}
+		"PartyA.Tel":              detail.PartyAContact,                                //甲方联系方式 {PartyA.Tel}
+		"PartyA.Addr":             detail.PartyAAddress,                                //甲方地址 {PartyA.Addr}
+		"Contract.No":             detail.GetContractNoStr(createTime),                 //合同编号 {Contract.No}
+		"Contract.Service.Detail": detail.Service,                                      //会员服务 {Contract.Service.Detail}
+		"Contract.Service.Time":   detail.ServiceTime,                                  //服务时长 {Contract.Service.Time}
+		"Contract.Account.Num":    detail.AccountNum,                                   //账号个数 {Contract.Account.Num}
+		"Contract.Remark":         detail.Remark,                                       //合同备注 {Contract.Remark}
+		"Contract.Amount":         strconv.FormatFloat(detail.Amount/100, 'f', -1, 64), //合同金额 {Contract.Amount}
+		"Contract.Amount.Font":    cncap.CapitalizeCurrency(detail.Amount / 100.0),     //合同大写金额 {Contract.Amount.Font}
+		"PartyB.Person":           detail.PartyBPerson,                                 //乙方联系人 {PartyB.Person}
+		"PartyB.Date.Y":           createTime.Year(),                                   //乙方日期-年 {PartyB.Date.Year}
+		"PartyB.Date.M":           fmt.Sprintf("%02d", int(createTime.Month())),        //乙方日期-月 {PartyB.Date.Month}
+		"PartyB.Date.D":           fmt.Sprintf("%02d", createTime.Day()),               //乙方日期-日 {PartyB.Date.Day}
+	}
+	if detail.PartyAType == 2 {
+		replaceMap["PartyA.EndName"] = detail.PartyAName
+	} else {
+		replaceMap["PartyA.EndName"] = ""
+	}
+	numPageEmptyRows := 0
+	longNum := len([]rune(fmt.Sprintf("%s%s%d%s", detail.Service, detail.ServiceTime, detail.AccountNum, detail.Remark)))
+
+	if longNum <= 30 { //备注过短时,公章上移 18+13
+		numPageEmptyRows = 3
+	} else if longNum > 30 && longNum <= 88 {
+		numPageEmptyRows = 2
+	} else if longNum > 88 && longNum <= 146 {
+		numPageEmptyRows = 1
+	}
+	replaceMap["PageEmptyRows"] = strings.Repeat(" ", numPageEmptyRows*180)
+	//计算第一页空行数,把落款固定到最下部
+
+	// read and parse the template docx
+	doc, err := docx.Open(fmt.Sprintf("web/static/contract/%s.docx", detail.ContractTemplate))
+	if err != nil {
+		return "", errors.Wrap(err, "docx文件模版文件异常")
+	}
+
+	// replace the keys with values from replaceMap
+	err = doc.ReplaceAll(replaceMap)
+	if err != nil {
+		return "", errors.Wrap(err, "docx文件模版文件参数替换异常")
+	}
+	fileAbsolutePath := jyutil.GetFilePath("docx", "contract")
+
+	// write out a new file
+	err = doc.WriteToFile(fileAbsolutePath)
+	if err != nil {
+		return "", errors.Wrap(err, "docx文件生成异常")
+	}
+	return fileAbsolutePath, nil
+}
+
+// GetContractNoStr 获取生成协议编号
+func (detail *ContractDetail) GetContractNoStr(createTime time.Time) string {
+	if detail.ContractNo != "" {
+		return detail.ContractNo
+	}
+	dataStr := createTime.Format(date.Date_yyyyMMdd)
+	key := fmt.Sprintf("%s_%s", detail.ContractFlag, dataStr)
+	detail.ContractNo = fmt.Sprintf("%s【%s】第%03d号", detail.ContractFlag, dataStr, redis.Incr("newother", key))
+	return detail.ContractNo
+}
+
+// convertWordToPDF word转pdf
+func (detail *ContractDetail) convertWordToPDF(inputDocxPath string) error {
+	var commandName string
+	var commandArg string
+
+	switch runtime.GOOS {
+	case "windows":
+		commandName = "cmd"
+		commandArg = "/c"
+	case "linux", "darwin":
+		commandName = "sh"
+		commandArg = "-c"
+	default:
+		return fmt.Errorf("unsupported operating system: %s", runtime.GOOS)
+	}
+
+	fileDir := filepath.Dir(inputDocxPath)
+	fileFullName := filepath.Base(inputDocxPath)
+	fileName := strings.TrimSuffix(fileFullName, filepath.Ext(fileFullName))
+	pdfFileFullPath := fmt.Sprintf("%s/%s.pdf", fileDir, fileName) //生成pdf路径
+	pngFileFullPath := fmt.Sprintf("%s/%s.png", fileDir, fileName) //生成图片路径
+	pngsMatchPath := fmt.Sprintf("%s/%s-*.png", fileDir, fileName) //生成图片路径
+
+	// 一、soffice 生成pdf文件
+	createPdfFile := exec.Command(commandName, commandArg, fmt.Sprintf("soffice --headless --invisible --convert-to pdf %s --outdir %s", inputDocxPath, fileDir))
+	if _, err := createPdfFile.CombinedOutput(); err != nil {
+		fmt.Printf(fmt.Sprintf("soffice --headless --invisible --convert-to pdf %s --outdir %s", inputDocxPath, fileDir))
+		return errors.Wrap(err, "Command execution createPdfFile failed:")
+	}
+	// 二、convert pdf内容转为图片
+	var hasSeal bool = detail.SealType == 1
+	if hasSeal {
+		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))
+		if _, err := createPngFile.CombinedOutput(); err != nil {
+			fmt.Printf("convert -density 300x300 -units pixelsperinch %s -background white -alpha remove -alpha off -quality 100 -antialias -resize 100%% %s ", pdfFileFullPath, pngFileFullPath)
+			return errors.Wrap(err, "Command execution createPngFile failed:")
+		}
+		//每张图片
+		cmd := exec.Command("sh", "-c", fmt.Sprintf("ls %s", pngsMatchPath))
+		out, err := cmd.CombinedOutput()
+		if err != nil || len(out) == 0 {
+			return errors.Wrap(err, "Command execution ls pngs  failed:")
+		}
+		for index, fileName := range strings.Split(string(out), "\n") {
+			if fileTmpPath := strings.TrimSpace(fileName); fileTmpPath != "" {
+				var x, y int64
+				rand.Seed(time.Now().UnixNano())
+				// 随机盖章位置 生成一个随机整数
+				if index == 0 { //首页需要盖着日期
+					x = 680 + rand.Int63n(10)
+					y = 130 + rand.Int63n(30)
+					//if len([]rune(fmt.Sprintf("%s%s%d%s", detail.Service, detail.ServiceTime, detail.AccountNum, detail.Remark))) <= 32 { //备注过短时,公章上移
+					//	y = y + 50
+					//}
+				} else {
+					x = 300 + rand.Int63n(200)
+					y = 500 + rand.Int63n(200)
+				}
+
+				exeSeal := exec.Command(commandName, commandArg, fmt.Sprintf("convert %s \\( %s -resize 50%% \\) -gravity southeast -geometry +%d+%d -composite  %s", fileTmpPath, "web/static/contract/z.png", x, y, fileTmpPath))
+				if _, err := exeSeal.CombinedOutput(); err != nil {
+					return errors.Wrap(err, "Command execution exeSeal failed:")
+				}
+			}
+		}
+		createPngPdfFile := exec.Command(commandName, commandArg, fmt.Sprintf("convert %s %s", pngsMatchPath, pdfFileFullPath))
+		if _, err := createPngPdfFile.CombinedOutput(); err != nil {
+			fmt.Printf("convert %s %s", pngsMatchPath, pdfFileFullPath)
+			return errors.Wrap(err, "Command execution createPngFile failed:")
+		}
+	} else {
+		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))
+		if _, err := createPngPdfFile.CombinedOutput(); err != nil {
+			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))
+			return errors.Wrap(err, "Command execution createPngFile failed:")
+		}
+	}
+
+	// 三、清除多余文件
+	clearFileCmd := exec.Command(commandName, commandArg, fmt.Sprintf("chmod -x %s  && rm -rf %s %s", pngsMatchPath, pngsMatchPath, inputDocxPath))
+	if err := clearFileCmd.Run(); err != nil {
+		return errors.Wrap(err, "Command execution clearFileCmd failed:")
+	}
+	return nil
+}