From f5749b87dc3b3a1e89b432c772d59bc120348cb3 Mon Sep 17 00:00:00 2001 From: gjs Date: Fri, 9 Oct 2026 17:57:16 +0800 Subject: [PATCH] print --- pkg/utils/tools.go | 13 + services/express/internal/dao/code.go | 1 + .../internal/logic/expressCompanyLogic.go | 57 ---- .../internal/logic/printBarCodeLogic.go | 50 +++- .../internal/logic/printBarCodePrintLogic.go | 37 ++- .../express/internal/logic/printBindLogic.go | 7 +- .../internal/logic/printExpressLogic.go | 64 ++++- .../internal/logic/printExpressPrintLogic.go | 259 +++++++++++++++++- .../internal/logic/printProductLogic.go | 81 +++++- services/express/internal/svc/print.go | 204 ++++++++++++++ services/express/validator/print.go | 22 +- 11 files changed, 714 insertions(+), 81 deletions(-) delete mode 100644 services/express/internal/logic/expressCompanyLogic.go create mode 100644 services/express/internal/svc/print.go diff --git a/pkg/utils/tools.go b/pkg/utils/tools.go index 3ab4427..0ebb56d 100644 --- a/pkg/utils/tools.go +++ b/pkg/utils/tools.go @@ -597,6 +597,19 @@ func UniqueStr(arr []string) []string { return res } +func initRandGenerator() { + // 创建随机数源 + source := rand.NewSource(time.Now().UnixNano()) + // 基于源创建生成器 + randGen = rand.New(source) +} +func GetRandNum(number int) int { + // 首次调用时初始化,后续调用直接复用,无重复初始化开销 + once.Do(initRandGenerator) + // 生成0-9999随机数,格式化补零为4位 + return randGen.Intn(number) +} + // Float 泛型约束,只允许 float32 / float64 type Float interface { ~float32 | ~float64 diff --git a/services/express/internal/dao/code.go b/services/express/internal/dao/code.go index 33cfebf..7861949 100644 --- a/services/express/internal/dao/code.go +++ b/services/express/internal/dao/code.go @@ -2,6 +2,7 @@ package dao const ( CodeStatusBind = 3 //为绑定 + BacCode = "Lone" ) type CodeCreate struct { diff --git a/services/express/internal/logic/expressCompanyLogic.go b/services/express/internal/logic/expressCompanyLogic.go deleted file mode 100644 index f6e5e9b..0000000 --- a/services/express/internal/logic/expressCompanyLogic.go +++ /dev/null @@ -1,57 +0,0 @@ -package logic - -import ( - "context" - "lone-services/pkg/utils" - "lone-services/rpc/express/pb" - "lone-services/services/express/internal/svc" - "lone-services/services/express/validator" - - "github.com/zeromicro/go-zero/core/logx" -) - -type ExpressCompanyLogic struct { - ctx context.Context - svcCtx *svc.ServiceContext - logx.Logger - BaseLogic -} - -func NewExpressCompanyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ExpressCompanyLogic { - return &ExpressCompanyLogic{ - ctx: ctx, - svcCtx: svcCtx, - Logger: logx.WithContext(ctx), - } -} - -// ExpressCompany 获取可选的打印公司 -func (l *ExpressCompanyLogic) ExpressCompany(in *express.ExpressCompanyRequest) (*express.Response, error) { - var v validator.CompanyItemsValidator - if fail := l.checkParams(in, &v); fail != nil { - return fail, nil - } - adminInfo := utils.GetUserFromCtx(l.ctx) - if adminInfo.ID < utils.NumberOne { - return l.fail(utils.ErrorNoLoginInfo) - } - sf := utils.GetConfigInt("transit.sf_send_code_" + in.Code) - jd := utils.GetConfigInt("transit.jd_send_code_" + in.Code) - if sf < utils.NumberOne || jd < utils.NumberOne { - return l.fail(utils.ErrorNotFund) - } - type retData struct { - Name string `json:"name"` - Id int `json:"id"` - } - var data []retData - data = append(data, retData{ - Name: "顺丰", - Id: sf, - }) - data = append(data, retData{ - Name: "京东", - Id: jd, - }) - return l.ok(data) -} diff --git a/services/express/internal/logic/printBarCodeLogic.go b/services/express/internal/logic/printBarCodeLogic.go index 0c65979..51b56f5 100644 --- a/services/express/internal/logic/printBarCodeLogic.go +++ b/services/express/internal/logic/printBarCodeLogic.go @@ -2,6 +2,13 @@ package logic import ( "context" + "fmt" + "lone-services/pkg/utils" + "lone-services/services/express/internal/dao" + "lone-services/services/express/internal/model" + "lone-services/services/express/validator" + "strconv" + "time" "lone-services/rpc/express/pb" "lone-services/services/express/internal/svc" @@ -13,6 +20,7 @@ type PrintBarCodeLogic struct { ctx context.Context svcCtx *svc.ServiceContext logx.Logger + BaseLogic } func NewPrintBarCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PrintBarCodeLogic { @@ -24,7 +32,45 @@ func NewPrintBarCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Prin } func (l *PrintBarCodeLogic) PrintBarCode(in *express.PrintBarCodeRequest) (*express.Response, error) { - // todo: add your logic here and delete this line + var v validator.PrintBarCodeValidator + if fail := l.checkParams(in, &v); fail != nil { + return fail, nil + } + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return l.fail(utils.ErrorNoLoginInfo) + } - return &express.Response{}, nil + var info []dao.CodeInfo + modelObj := model.CodeModel{}.Init() + for i := utils.NumberOne; i <= int(in.Number); i++ { + tmp := dao.CodeCreate{ + Code: l.getCode(in.ProductId, adminInfo.ID), + ProductId: int(in.ProductId), + AdminId: int(adminInfo.ID), + AdminName: adminInfo.Name, + Status: utils.StatusOk, + } + err := modelObj.Create(&tmp) + if err != nil { + l.Logger.Error(err) + } else { + info = append(info, dao.CodeInfo{ + Id: tmp.Id, + ProductId: tmp.ProductId, + Code: tmp.Code, + Status: utils.StatusOk, + }) + } + } + + return l.ok(info) +} + +func (l *PrintBarCodeLogic) getCode(productId, uId int64) string { + now := time.Now() + code := dao.BacCode + fmt.Sprintf("%04d", productId) + + fmt.Sprintf("%04d", uId) + now.Format("20060102150405") + + strconv.Itoa(utils.GetRandNum(1000)) + return code } diff --git a/services/express/internal/logic/printBarCodePrintLogic.go b/services/express/internal/logic/printBarCodePrintLogic.go index f15befd..612f440 100644 --- a/services/express/internal/logic/printBarCodePrintLogic.go +++ b/services/express/internal/logic/printBarCodePrintLogic.go @@ -2,6 +2,12 @@ package logic import ( "context" + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/services/express/internal/dao" + "lone-services/services/express/internal/model" + "lone-services/services/express/validator" + "strconv" "lone-services/rpc/express/pb" "lone-services/services/express/internal/svc" @@ -13,6 +19,7 @@ type PrintBarCodePrintLogic struct { ctx context.Context svcCtx *svc.ServiceContext logx.Logger + BaseLogic } func NewPrintBarCodePrintLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PrintBarCodePrintLogic { @@ -24,7 +31,33 @@ func NewPrintBarCodePrintLogic(ctx context.Context, svcCtx *svc.ServiceContext) } func (l *PrintBarCodePrintLogic) PrintBarCodePrint(in *express.PrintBarCodePrintRequest) (*express.Response, error) { - // todo: add your logic here and delete this line + var v validator.PrintBarCodeUseValidator + if fail := l.checkParams(in, &v); fail != nil { + return fail, nil + } + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return l.fail(utils.ErrorNoLoginInfo) + } - return &express.Response{}, nil + var info dao.CodeCreate + w := modelbase.Params{Eq: map[string]string{"status": utils.StatusFailString, "id": strconv.Itoa(int(in.Id))}} + err := model.CodeModel{}.Init().GetOne(w, &info) + if err != nil { + l.Logger.Error(err) + return l.fail(utils.Fail) + } + if info.Id < utils.NumberOne { + return l.fail(utils.ErrorNotFund) + } + info.Status = utils.StatusOk + info.AdminId = int(adminInfo.ID) + info.AdminName = adminInfo.Name + _, err = model.CodeModel{}.Init().Edit(w, &info) + if err != nil { + l.Logger.Error(err) + return l.fail(utils.Fail) + } + + return l.ok(utils.NumberOne) } diff --git a/services/express/internal/logic/printBindLogic.go b/services/express/internal/logic/printBindLogic.go index 85279ba..ee8be8c 100644 --- a/services/express/internal/logic/printBindLogic.go +++ b/services/express/internal/logic/printBindLogic.go @@ -2,6 +2,7 @@ package logic import ( "context" + "lone-services/services/express/validator" "lone-services/rpc/express/pb" "lone-services/services/express/internal/svc" @@ -13,6 +14,7 @@ type PrintBindLogic struct { ctx context.Context svcCtx *svc.ServiceContext logx.Logger + BaseLogic } func NewPrintBindLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PrintBindLogic { @@ -25,7 +27,10 @@ func NewPrintBindLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PrintBi // 不需要登录 func (l *PrintBindLogic) PrintBind(in *express.PrintBindRequest) (*express.Response, error) { - // todo: add your logic here and delete this line + var v validator.PrintTransitBindValidator + if fail := l.checkParams(in, &v); fail != nil { + return fail, nil + } return &express.Response{}, nil } diff --git a/services/express/internal/logic/printExpressLogic.go b/services/express/internal/logic/printExpressLogic.go index c8d9af9..167f6b3 100644 --- a/services/express/internal/logic/printExpressLogic.go +++ b/services/express/internal/logic/printExpressLogic.go @@ -2,9 +2,14 @@ package logic import ( "context" - + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" "lone-services/rpc/express/pb" + "lone-services/services/express/internal/dao" + "lone-services/services/express/internal/model" "lone-services/services/express/internal/svc" + "lone-services/services/express/validator" + "strconv" "github.com/zeromicro/go-zero/core/logx" ) @@ -13,6 +18,7 @@ type PrintExpressLogic struct { ctx context.Context svcCtx *svc.ServiceContext logx.Logger + BaseLogic } func NewPrintExpressLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PrintExpressLogic { @@ -24,7 +30,59 @@ func NewPrintExpressLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Prin } func (l *PrintExpressLogic) PrintExpress(in *express.PrintExpressRequest) (*express.Response, error) { - // todo: add your logic here and delete this line + var v validator.PrintOrderValidator + if fail := l.checkParams(in, &v); fail != nil { + return fail, nil + } + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return l.fail(utils.ErrorNoLoginInfo) + } - return &express.Response{}, nil + var info []dao.DeliveryOrderPrint + w := modelbase.Params{ + In: map[string][]string{"status": {strconv.Itoa(dao.SendStatusOk), strconv.Itoa(dao.SendStatusIn), strconv.Itoa(dao.SendStatusWait)}}, + } + if v.Status == utils.NumberOne { + w.Page = utils.NumberOne + w.Size = utils.SIZE + w.Order = "id desc" + } + + if v.Status == utils.NumberZero { + w.Page = utils.NumberOne + w.Size = utils.SIZE + w.Order = "print_status desc, id desc" + } + + w.Eq = make(map[string]string) + if v.Status > utils.NumberZero { + w.Eq["print_status"] = strconv.Itoa(int(v.Status)) + } + + if len(v.OrderSn) > utils.NumberZero { + w.Eq["obj_sn"] = v.OrderSn + } + + startTime, endTime := utils.TimeToStartAndEnd(v.Time, utils.NumberOne) + if len(startTime) > utils.NumberZero { + betweenTimeKey := "create_time" + if v.Status == utils.NumberOne { + betweenTimeKey = "update_time" + } + w.Between = map[string][2]string{betweenTimeKey: {startTime, endTime}} + } + + items, err := model.DeliveryOrderModel{}.Init().Page(w, &info) + + if err != nil { + l.Logger.Error(err) + return l.fail(utils.Fail) + } + + obj := svc.Print{} + obj.GetOrderInfo(l.svcCtx.ProductSvcName, &info) + items.Items = info + + return l.ok(items) } diff --git a/services/express/internal/logic/printExpressPrintLogic.go b/services/express/internal/logic/printExpressPrintLogic.go index 1a9cbb2..9379e5d 100644 --- a/services/express/internal/logic/printExpressPrintLogic.go +++ b/services/express/internal/logic/printExpressPrintLogic.go @@ -2,6 +2,19 @@ package logic import ( "context" + "errors" + "io" + "lone-services/pkg/modelbase" + "lone-services/pkg/utils" + "lone-services/services/express/internal/dao" + "lone-services/services/express/internal/model" + "lone-services/services/express/internal/transit" + "lone-services/services/express/validator" + "net/http" + "os" + "path/filepath" + "strconv" + "strings" "lone-services/rpc/express/pb" "lone-services/services/express/internal/svc" @@ -13,6 +26,7 @@ type PrintExpressPrintLogic struct { ctx context.Context svcCtx *svc.ServiceContext logx.Logger + BaseLogic } func NewPrintExpressPrintLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PrintExpressPrintLogic { @@ -24,7 +38,248 @@ func NewPrintExpressPrintLogic(ctx context.Context, svcCtx *svc.ServiceContext) } func (l *PrintExpressPrintLogic) PrintExpressPrint(in *express.PrintExpressPrintRequest) (*express.Response, error) { - // todo: add your logic here and delete this line + var v validator.PrintOrderUseValidator + if fail := l.checkParams(in, &v); fail != nil { + return fail, nil + } + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return l.fail(utils.ErrorNoLoginInfo) + } - return &express.Response{}, nil + var itemsEdit []dao.DeliveryOrderPrintEdit + w := modelbase.Params{ + Eq: map[string]string{"id": strconv.FormatInt(in.Id, utils.NumberTen)}} + modelObj := model.DeliveryOrderModel{}.Init() + err := modelObj.Items(w, &itemsEdit) + if err != nil { + l.Logger.Error(err) + return l.fail(utils.Fail) + } + + if len(itemsEdit) < utils.NumberOne { + return l.fail(utils.ErrorNotFund) + } + + if itemsEdit[utils.NumberZero].Status == dao.SendStatusOk || + itemsEdit[utils.NumberZero].Status == dao.SendStatusOver { + return l.fail(utils.SetError(utils.ErrorNotFund, "该订单已完结")) + } + + if in.TransitId < utils.NumberOne { + in.TransitId = int64(utils.GetConfigInt("transit.send_id")) + } + tw := modelbase.Params{Eq: map[string]string{"id": strconv.FormatInt(in.TransitId, utils.NumberTen)}} + var transitInfo dao.ExpressSend + err = model.ExpressModel{}.Init().GetOne(tw, &transitInfo) + if err != nil { + l.Logger.Error("发货地址信息没有找到", in.TransitId, err) + return l.fail(utils.SetError(utils.ErrorNotFund, "没有查询到发货信息")) + } + if transitInfo.Id < utils.NumberOne { + return l.fail(utils.SetError(utils.ErrorNotFund, "没有查询到发货信息")) + } + + var items []dao.DeliveryOrderPrint + items = append(items, dao.DeliveryOrderPrint{ + DeliveryOrderPrintEdit: itemsEdit[utils.NumberZero], + }) + svc.Print{}.GetOrderInfo(l.svcCtx.ProductSvcName, &items) + info := itemsEdit[utils.NumberZero] + //更新使用的快递类型 + info.TransitType = transitInfo.TransitId + + info.OrderSn = svc.Print{}.GetOrderSn(info.TransitType, int(adminInfo.ID)) + items[utils.NumberZero].OrderSn = info.OrderSn + client, res, cErr := l.createTransit(items[utils.NumberZero], transitInfo) + if cErr != utils.Ok { + return l.fail(cErr) + } + info.TransitInfo = res.PostInfo + info.TransitContent = res.RequestInfo + info.TransitSn = strings.Join(res.WaybillNo, utils.DecollatorComma) + + items[utils.NumberZero].AdminName = adminInfo.Name + res2, gErr := l.getDown(client, res.WaybillNo, items[utils.NumberZero]) + if gErr != nil { + retStatus := svc.Cancel(client, w, info, dao.SendStatusCancel, l.svcCtx.OrderSvcName) + if retStatus != utils.Ok { + return l.fail(retStatus) + } + l.Logger.Error(res2, gErr) + return l.fail(utils.SetError(utils.ErrorNotFund, "下载发货单出错")) + } + + info.Express = utils.StructToJson(res2.Files) + info.PrintStatus = utils.StatusOk + info.AdminId = int(adminInfo.ID) + info.AdminName = adminInfo.Name + info.TransitId = int(in.TransitId) + info.TransitName = transitInfo.Name + info.Status = dao.SendStatusOk + info.SendTime = utils.Now() + + items[utils.NumberZero].PrintStatus = info.PrintStatus + items[utils.NumberZero].AdminId = info.AdminId + items[utils.NumberZero].AdminName = info.AdminName + items[utils.NumberZero].TransitId = info.TransitId + items[utils.NumberZero].TransitInfo = info.TransitInfo + items[utils.NumberZero].TransitContent = info.TransitContent + items[utils.NumberZero].TransitSn = info.TransitSn + items[utils.NumberZero].TransitName = info.TransitName + items[utils.NumberZero].Status = info.Status + items[utils.NumberZero].Express = info.Express + + var history dao.DeliveryHistoryCreate + history.DeliverId = info.Id + history.TransitName = dao.DeliverySendType[info.TransitType] + history.TransitInfo = info.TransitInfo + history.TransitContent = info.TransitContent + history.TransitType = info.TransitType + history.OrderSn = info.OrderSn + + var exps []dao.DeliveryExpCreate + for i := 0; i < len(res.WaybillNo); i++ { + exps = append(exps, dao.DeliveryExpCreate{ + DeliveryOrderId: info.Id, + TransitType: info.TransitType, + ExpSn: res.WaybillNo[i], + OrderSn: info.OrderSn, + }) + } + + sErr := l.saveDelever(w, &info, &history, &exps) + if sErr != utils.Ok { + retStatus := svc.Cancel(client, w, info, dao.SendStatusCancel, l.svcCtx.OrderSvcName) + if retStatus != utils.Ok { + return l.fail(retStatus) + } + l.Logger.Error(res2, sErr) + return l.fail(sErr) + } + + return l.ok(items[utils.NumberZero]) +} + +func (l *PrintExpressPrintLogic) createTransit(info dao.DeliveryOrderPrint, transitInfo dao.ExpressSend) (transit.Transit, transit.TransitResult, utils.Status) { + var client transit.Transit + switch transitInfo.TransitId { + case dao.ExpressCompanySf: + client = transit.NewSfClient(transitInfo) + case dao.ExpressCompanyJd: + client = transit.NewJdClient(transitInfo) + default: + return client, transit.TransitResult{}, utils.SetError(utils.Fail, "不支持的快递公司") + } + res, err := client.Create(info) + if err != nil || res.ErrorCode != utils.StringStatusOk { + l.Logger.Error("create transit err", err, res) + return client, res, utils.SetError(utils.Fail, res.ApiErrorMsg) + } + + return client, res, utils.Ok +} + +func (l *PrintExpressPrintLogic) getDown(client transit.Transit, orders []string, info dao.DeliveryOrderPrint) (transit.TransitResult, error) { + ret, err := client.DownSheet(orders, info) + if err != nil || len(ret.Files) < utils.NumberOne { + l.Logger.Error("get down err ", orders, err, ret) + if len(ret.Files) < utils.NumberOne { + err = errors.New("files is empty") + } + return ret, err + } + path := utils.GetConfigString("transit.path") + "/" + var tmpFiles []transit.TransitFiles + for i := 0; i < len(ret.Files); i++ { + tName := ret.Files[i].WaybillNo + ".pdf" + err := l.downloadSfPDF(ret.Files[i], path+tName) + if err != nil { + l.Logger.Error("get down err ", orders, err, ret) + return ret, err + } + + tmpFiles = append(tmpFiles, transit.TransitFiles{ + File: tName, + WaybillNo: ret.Files[i].WaybillNo, + }) + } + + ret.Files = tmpFiles + + return ret, nil +} + +func (l *PrintExpressPrintLogic) downloadSfPDF(file transit.TransitFiles, path string) error { + req, err := http.NewRequest("GET", file.Url, nil) + if err != nil { + return err + } + + // 2. 必须加这个请求头(顺丰强制) + req.Header.Add("X-Auth-token", file.Token) + // 3. 发送请求 + client := &http.Client{} + resp, err := client.Do(req) + if err != nil { + return err + } + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + utils.Logger.Error(err) + } + }(resp.Body) + // 4. 创建目录 + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return err + } + // 5. 创建文件并保存 + outFile, err := os.Create(path) + if err != nil { + return err + } + defer func(outFile *os.File) { + err = outFile.Close() + if err != nil { + utils.Logger.Error(err) + } + }(outFile) + // 6. 拷贝数据 + _, err = io.Copy(outFile, resp.Body) + return err +} + +func (l *PrintExpressPrintLogic) saveDelever(w modelbase.Params, info *dao.DeliveryOrderPrintEdit, history *dao.DeliveryHistoryCreate, exps *[]dao.DeliveryExpCreate) utils.Status { + modelObj := model.DeliveryOrderModel{}.Init() + modelObj.Begin() + edit, err := modelObj.Edit(w, info) + if err != nil || edit < utils.NumberOne { + modelObj.Rollback() + l.Logger.Error("save deliver goods err ", err) + return utils.SetError(utils.Fail, "生成快递单失败") + } + + err = model.DeliveryOrderExpModel{}.Init().CreateMulti(exps) + if err != nil { + modelObj.Rollback() + l.Logger.Error("save exp err ", err) + return utils.SetError(utils.Fail, "生成EXP失败") + } + + err = model.DeliveryHistoryModel{}.Init().Create(history) + if err != nil { + modelObj.Rollback() + l.Logger.Error("save history err ", err) + return utils.SetError(utils.Fail, "生成订单历史失败") + } + s := svc.UpOrderDeliverStatus(l.svcCtx.OrderSvcName, info.ObjId, int(info.Type), int32(info.Status)) + if s != utils.Ok { + modelObj.Rollback() + l.Logger.Error("save update order err ", err) + return s + } + + modelObj.Commit() + return utils.Ok } diff --git a/services/express/internal/logic/printProductLogic.go b/services/express/internal/logic/printProductLogic.go index f2207d9..c11de9a 100644 --- a/services/express/internal/logic/printProductLogic.go +++ b/services/express/internal/logic/printProductLogic.go @@ -2,9 +2,14 @@ package logic import ( "context" - + "encoding/base64" + "io" + "lone-services/pkg/utils" "lone-services/rpc/express/pb" + product "lone-services/rpc/product/pb" + "lone-services/services/express/internal/dao" "lone-services/services/express/internal/svc" + "net/http" "github.com/zeromicro/go-zero/core/logx" ) @@ -13,6 +18,7 @@ type PrintProductLogic struct { ctx context.Context svcCtx *svc.ServiceContext logx.Logger + BaseLogic } func NewPrintProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *PrintProductLogic { @@ -24,7 +30,76 @@ func NewPrintProductLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Prin } func (l *PrintProductLogic) PrintProduct(in *express.EmtpyRequest) (*express.Response, error) { - // todo: add your logic here and delete this line + adminInfo := utils.GetUserFromCtx(l.ctx) + if adminInfo.ID < utils.NumberOne { + return l.fail(utils.ErrorNoLoginInfo) + } - return &express.Response{}, nil + items, err := l.getProducts() + if err != utils.Ok { + return l.fail(err) + } + + return l.ok(items) +} + +func (l *PrintProductLogic) getProducts() ([]dao.ProductPrint, utils.Status) { + cli, err := svc.GetRpcClient(l.svcCtx.ProductSvcName) + if err != nil { + l.Logger.Error(err) + return nil, utils.ErrorInternalServer + } + + var Type []uint32 + Status := []uint32{utils.StatusOk, utils.StatusFail} + productClient := product.NewProductClient(cli.Conn()) + productItems, err := productClient.InternalItems(l.ctx, &product.InternalItemsReq{Status: Status, Type: Type}) + if err != nil { + logx.Errorf("get products err: %v", err) + return nil, utils.SetError(utils.Fail, "获取产品信息错误") + } + + var info []dao.ProductPrint + for _, val := range productItems.Items { + client := &http.Client{ + CheckRedirect: func(req *http.Request, via []*http.Request) error { + return http.ErrUseLastResponse + }, + } + resp, err := client.Get(val.Waybill) + if err != nil { + return info, utils.Fail + } + defer func(Body io.ReadCloser) { + err := Body.Close() + if err != nil { + utils.Logger.Error(err) + } + }(resp.Body) + + // 读取图片二进制内容 + imgData, err := io.ReadAll(resp.Body) + if err != nil { + utils.Logger.Error(err) + return info, utils.Fail + } + + // 自动识别图片类型(png/jpg/gif 等) + contentType := http.DetectContentType(imgData) + + // 转 base64 + base64Str := base64.StdEncoding.EncodeToString(imgData) + + // 拼接成可直接在 img 标签显示的格式 + imageBase64 := "data:" + contentType + ";base64," + base64Str + info = append(info, dao.ProductPrint{ + Id: int(val.Id), + Name: val.Name, + Weight: float32(val.Weight), + Cubage: val.Cubage, + Waybill: imageBase64, + }) + } + + return info, utils.Ok } diff --git a/services/express/internal/svc/print.go b/services/express/internal/svc/print.go new file mode 100644 index 0000000..3bac682 --- /dev/null +++ b/services/express/internal/svc/print.go @@ -0,0 +1,204 @@ +package svc + +import ( + "context" + "encoding/json" + "fmt" + "lone-services/pkg/utils" + product "lone-services/rpc/product/pb" + "lone-services/services/express/internal/dao" + "lone-services/services/express/internal/transit" + "math" + "math/rand" + "strconv" + "strings" + "time" + + "github.com/zeromicro/go-zero/core/logx" +) + +type Print struct { +} + +func (s Print) GetOrderInfo(name string, items *[]dao.DeliveryOrderPrint) { + products := s.getProducts(name) + for value, item := range *items { + obj := &(*items)[value] + mobile, aErr := utils.Crypto{}.AESDecryptECB(item.Mobile) + if aErr == nil { + obj.Mobile = mobile + } + obj.Url = utils.GetConfigString("transit.url") + obj.Number, obj.Weight, obj.ProductItems = s.getProductInfo(item.ObjSn, item.ProductInfo, &products) + } +} + +func (s Print) getProducts(name string) map[int]dao.ProductPrint { + products := make(map[int]dao.ProductPrint) + + cli, err := GetRpcClient(name) + if err != nil { + logx.Error(err) + return products + } + + var Type []uint32 + var status []uint32 + productClient := product.NewProductClient(cli.Conn()) + productItems, err := productClient.InternalItems(context.Background(), &product.InternalItemsReq{Status: status, Type: Type}) + if err != nil { + logx.Errorf("get products err: %v", err) + return products + } + + for _, item := range productItems.Items { + products[int(item.Id)] = dao.ProductPrint{ + Id: int(item.Id), + Name: item.Name, + Weight: float32(item.Weight), + Cubage: item.Cubage, + Waybill: item.Waybill, + } + } + + return products +} + +func (s Print) getProductInfo(orderSn string, info string, product *map[int]dao.ProductPrint) (int, float32, []dao.DeliveryOrderProduct) { + var items []dao.DeliveryOrderProduct + totalNum := 0 + totalWeight := float32(0) + + if len(info) == utils.NumberZero { + return totalNum, totalWeight, items + } + + // 1. 解析JSON + data, err := s.jsonToMap(info) + if err != nil { + logx.Error("JSON解析商品信息失败", err, info) + return totalNum, totalWeight, items + } + + for _, item := range data { + itemMap, ok := item.(map[string]interface{}) + if !ok { + continue + } + + tmp := s.orderInfo(orderSn, itemMap, product) + items = append(items, tmp) + + // 统计总数、总重量 + totalNum += tmp.ProductNumber + totalWeight += tmp.ProductWeight + } + + return totalNum, totalWeight, items +} + +// 解析JSON数组 +func (s Print) jsonToMap(info string) ([]interface{}, error) { + var data []interface{} + err := json.Unmarshal([]byte(info), &data) + return data, err +} + +// 构建单个商品对象 +func (s Print) orderInfo(orderSn string, itemMap map[string]interface{}, product *map[int]dao.ProductPrint) dao.DeliveryOrderProduct { + tmp := dao.DeliveryOrderProduct{OrderSn: orderSn} + + s.getProduct(itemMap, &tmp) + s.getBox(&tmp, product) + + return tmp +} + +func (s Print) getProduct(itemMap map[string]interface{}, tmp *dao.DeliveryOrderProduct) { + if val, ok := itemMap["product_id"].(float64); ok { + tmp.ProductId = int(val) + } + if val, ok := itemMap["number"].(float64); ok { + tmp.ProductNumber = int(val) + } + if val, ok := itemMap["product_name"].(string); ok { + tmp.ProductName = val + } + if val, ok := itemMap["price"].(float64); ok { + tmp.Price = float32(val) + } +} + +// 长度高 +func (s Print) getBoxInfo(cubage []string, index int) float32 { + if index >= len(cubage) { + return utils.NumberZero + } + + val, err := strconv.ParseFloat(strings.TrimSpace(cubage[index]), 64) + if err != nil { + return utils.NumberZero + } + + return s.toFixed3(float32(val)) +} + +// 保留3位小数 +func (s Print) toFixed3(f float32) float32 { + return float32(math.Round(float64(f)*1000) / 1000) +} + +func (s Print) GetOrderSn(orderType uint8, adminId int) string { + first := dao.DeliverySendType[orderType] + + sn := first + time.Now().Format("20060102150405") + sn += fmt.Sprintf("%d%d", orderType, adminId) + randomNum := rand.Intn(90000000) + 10000000 + sn += fmt.Sprintf("%d", randomNum) + + return sn +} + +func (s Print) getTransitInfo(transitInfo dao.ExpressSend) (transit.Transit, utils.Status) { + var client transit.Transit + switch transitInfo.TransitId { + case dao.ExpressCompanySf: + client = transit.NewSfClient(transitInfo) + case dao.ExpressCompanyJd: + client = transit.NewJdClient(transitInfo) + default: + return client, utils.SetError(utils.ErrorNotFund, "没有找到快递公司") + } + + return client, utils.Ok +} + +func (s Print) getSfMap(items []dao.ExpressQueryItems) map[string]bool { + ret := make(map[string]bool) + for _, item := range items { + ret[item.LastMd5] = true + } + return ret +} + +// 体积 +func (s Print) getBox(tmp *dao.DeliveryOrderProduct, product *map[int]dao.ProductPrint) { + if product == nil { + return + } + + p, exists := (*product)[tmp.ProductId] + if !exists { + return + } + + tmp.ProductWeight = s.toFixed3(p.Weight * float32(tmp.ProductNumber)) + + cubage := strings.Split(p.Cubage, "*") + tmp.ProductLength = s.getBoxInfo(cubage, 0) + tmp.ProductWidth = s.getBoxInfo(cubage, 1) + tmp.ProductHeight = s.getBoxInfo(cubage, 2) + + // 计算体积 + tmp.ProductCubage = s.toFixed3(tmp.ProductLength * tmp.ProductWidth * tmp.ProductHeight) +} diff --git a/services/express/validator/print.go b/services/express/validator/print.go index e4b5f8e..a8df9b3 100644 --- a/services/express/validator/print.go +++ b/services/express/validator/print.go @@ -3,8 +3,8 @@ package validator import "lone-services/pkg/validate" type PrintLoginValidator struct { - Username int `form:"username" json:"username" validate:"required"` - Password int `form:"password" json:"password" validate:"required"` + Username string `form:"username" json:"username" validate:"required"` + Password string `form:"password" json:"password" validate:"required"` } // GetMessage 提示消息 @@ -25,12 +25,12 @@ func (p PrintExpressTransitValidator) GetMessage() validate.ValidatorMessages { } } -type PrintETransitBindValidator struct { - Codes string `form:"codes" json:"c" binding:"required"` +type PrintTransitBindValidator struct { + Codes string `form:"codes" json:"codes" binding:"required"` } // GetMessage 提示消息 -func (p PrintETransitBindValidator) GetMessage() validate.ValidatorMessages { +func (p PrintTransitBindValidator) GetMessage() validate.ValidatorMessages { return validate.ValidatorMessages{ "Codes.required": "codes不能为空", } @@ -38,8 +38,8 @@ func (p PrintETransitBindValidator) GetMessage() validate.ValidatorMessages { // PrintBarCodeValidator 创建产品 type PrintBarCodeValidator struct { - Number int `form:"number" json:"number"` - ProductId int `form:"product_id" json:"product_id" validate:"required"` + Number int32 `form:"number" json:"number"` + ProductId int64 `form:"product_id" json:"product_id" validate:"required"` } // GetMessage 提示消息 @@ -50,7 +50,7 @@ func (p PrintBarCodeValidator) GetMessage() validate.ValidatorMessages { } type PrintBarCodeUseValidator struct { - Id int `form:"id" json:"id" validate:"required"` + Id int64 `form:"id" json:"id" validate:"required"` } // GetMessage 提示消息 @@ -61,7 +61,7 @@ func (p PrintBarCodeUseValidator) GetMessage() validate.ValidatorMessages { } type PrintOrderValidator struct { - Status uint8 `form:"status" json:"status"` + Status int32 `form:"status" json:"status"` OrderSn string `form:"order_sn" json:"order_sn"` Time string `form:"time" json:"time"` } @@ -72,8 +72,8 @@ func (p PrintOrderValidator) GetMessage() validate.ValidatorMessages { } type PrintOrderUseValidator struct { - Id int `form:"id" json:"id" validate:"required"` - TransitId int `form:"transit_id" json:"transit_id"` + Id int64 `form:"id" json:"id" validate:"required"` + TransitId int64 `form:"transit_id" json:"transit_id"` } // GetMessage 提示消息