package controller import ( "bufio" "cold-logistics/app/admin/model" "cold-logistics/app/admin/service" "cold-logistics/app/admin/service/dto" "cold-logistics/common/actions" "cold-logistics/common/file_store" "cold-logistics/common/lib" "cold-logistics/common/nats/nats_server" "cold-logistics/conf" "errors" "fmt" "github.com/beego/beego/v2/core/logs" "github.com/boombuler/barcode" "github.com/boombuler/barcode/code128" "github.com/gin-gonic/gin" "github.com/gin-gonic/gin/binding" "github.com/golang/freetype/truetype" "github.com/jordan-wright/email" "github.com/ser163/png2j" "github.com/signintech/gopdf" "github.com/skip2/go-qrcode" "github.com/wcharczuk/go-chart/v2" "github.com/wcharczuk/go-chart/v2/drawing" "github.com/xuri/excelize/v2" "gogs.baozhida.cn/zoie/OAuth-core/api" "gogs.baozhida.cn/zoie/OAuth-core/pkg/jwtauth/user" _ "gogs.baozhida.cn/zoie/OAuth-core/pkg/response" "image" "image/jpeg" "image/png" "log" "net/smtp" "net/url" "os" "path" "sort" "strconv" "strings" "time" ) type WaybillController struct { api.Api } // GetPage 获取运单列表 // @Summary 获取运单列表 // @Description 获取运单列表 // @Tags 运单 // @Param waybillNo query string false "运单号" // @Param status query string false "状态:1待派单 2待装车 3待入库 4已装车 5已入库 6已下车 7已出库 8已签收 9待装箱 10已装箱 11已出箱" // @Param orderStartTime query string false "下单开始时间" // @Param orderEndTime query string false "下单结束时间" // @Param pageSize query int false "页条数" // @Param page query int false "页码" // @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}" // @Router /api/waybill [get] // @Security Bearer func (e WaybillController) GetPage(c *gin.Context) { s := service.Waybill{} req := dto.WaybillGetPageReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.Query). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //数据权限检查 p := actions.GetPermissionFromContext(c) list := make([]model.Waybill, 0) var count int64 err = s.GetPage(&req, &list, &count, p) if err != nil { e.Error(500, err, err.Error()) return } e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") } // Export 导出运单excel // @Summary 导出运单excel // @Description 导出运单excel // @Tags 运单 // @Param waybillNo query string false "运单号" // @Param status query string false "状态:1待派单 2待装车 3待入库 4已装车 5已入库 6已下车 7已出库 8已签收 9待装箱 10已装箱 11已出箱" // @Param orderStartTime query string false "下单开始时间" // @Param orderEndTime query string false "下单结束时间" // @Param pageSize query int false "页条数" // @Param page query int false "页码" // @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}" // @Router /api/waybill [get] // @Security Bearer func (e WaybillController) Export(c *gin.Context) { s := service.Waybill{} req := dto.WaybillGetPageReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.Query). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //数据权限检查 p := actions.GetPermissionFromContext(c) list := make([]model.Waybill, 0) var count int64 req.PageSize = 9999 err = s.GetPage(&req, &list, &count, p) if err != nil { e.Error(500, err, err.Error()) return } f := excelize.NewFile() // 设置单元格的值 // 这里设置表头ÒÒ f.SetCellValue("Sheet1", "A1", "序号") f.SetCellValue("Sheet1", "B1", "状态") f.SetCellValue("Sheet1", "C1", "寄件人名称") f.SetCellValue("Sheet1", "D1", "寄件人电话") f.SetCellValue("Sheet1", "E1", "寄件人地址") f.SetCellValue("Sheet1", "F1", "收件人名称") f.SetCellValue("Sheet1", "G1", "收件人电话") f.SetCellValue("Sheet1", "H1", "收件人地址") f.SetCellValue("Sheet1", "I1", "温度要求") f.SetCellValue("Sheet1", "J1", "配送要求") f.SetCellValue("Sheet1", "K1", "货物类型") f.SetCellValue("Sheet1", "L1", "运输备注") // 设置列宽 f.SetColWidth("Sheet1", "A", "A", 6) f.SetColWidth("Sheet1", "B", "B", 8) f.SetColWidth("Sheet1", "C", "C", 14) f.SetColWidth("Sheet1", "D", "D", 14) f.SetColWidth("Sheet1", "E", "E", 30) f.SetColWidth("Sheet1", "F", "F", 14) f.SetColWidth("Sheet1", "G", "G", 14) f.SetColWidth("Sheet1", "H", "H", 30) f.SetColWidth("Sheet1", "I", "K", 15) f.SetColWidth("Sheet1", "L", "L", 15) line := 1 // 循环写入数据 for i, v := range list { line++ f.SetCellValue("Sheet1", fmt.Sprintf("A%d", line), i+1) f.SetCellValue("Sheet1", fmt.Sprintf("B%d", line), model.WaybillStatusMap[v.Status]) f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), v.SenderAddressName) f.SetCellValue("Sheet1", fmt.Sprintf("D%d", line), v.SenderAddressPhone) f.SetCellValue("Sheet1", fmt.Sprintf("E%d", line), v.SenderAddressDetails) f.SetCellValue("Sheet1", fmt.Sprintf("F%d", line), v.ConsigneeAddressName) f.SetCellValue("Sheet1", fmt.Sprintf("G%d", line), v.ConsigneeAddressPhone) f.SetCellValue("Sheet1", fmt.Sprintf("H%d", line), v.ConsigneeAddressDetails) f.SetCellValue("Sheet1", fmt.Sprintf("I%d", line), v.TemperatureInterval) f.SetCellValue("Sheet1", fmt.Sprintf("J%d", line), v.DeliveryCondition) f.SetCellValue("Sheet1", fmt.Sprintf("K%d", line), v.CargoType) f.SetCellValue("Sheet1", fmt.Sprintf("L%d", line), v.Remark) } timeStr := time.Now().Format("20060102150405") filePath := "ofile/" + "运单" + timeStr + ".xlsx" // 保存文件 if err = f.SaveAs(filePath); err != nil { logs.Error("保存运单失败:", err) } defer func() { os.Remove(filePath) }() c.Header("Content-Type", "application/vnd.ms-excel;charset=utf8") // PathEscape 函数对中文做处理 c.Header("Content-Disposition", "attachment; filename="+url.PathEscape("运单"+timeStr+".xlsx")) c.Header("Content-Transfer-Encoding", "binary") c.File(filePath) } // Home 首页统计 // @Summary 首页统计 // @Description 首页统计 // @Tags 运单 // @Param date query string false "日期" // @Param type query string false "类型 month-月 year-年" // @Param pageSize query int false "页条数" // @Param page query int false "页码" // @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}" // @Router /api/waybill [get] // @Security Bearer func (e WaybillController) Home(c *gin.Context) { s := service.Waybill{} req := dto.WaybillStatsReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.Query). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //数据权限检查 p := actions.GetPermissionFromContext(c) res := s.GetBasicsStats(&req, p) e.OK(res, "查询成功") } // GetAppletPage 获取运单列表 // @Summary 获取运单列表 // @Description 获取运单列表 // @Tags 运单 // @Param waybillNo query string false "运单号" // @Param status query string false "状态:1待派单 2待装车 3待入库 4已装车 5已入库 6已下车 7已出库 8已签收 9待装箱 10已装箱 11已出箱" // @Param pageSize query int false "页条数" // @Param page query int false "页码" // @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}" // @Router /api/waybill [get] // @Security Bearer func (e WaybillController) GetAppletPage(c *gin.Context) { s := service.Waybill{} req := dto.WaybillGetAppletPageReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.Query). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //数据权限检查 p := actions.GetPermissionFromContext(c) list := make([]model.Waybill, 0) var count int64 err = s.GetAppletPage(&req, &list, &count, p) if err != nil { e.Error(500, err, err.Error()) return } e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") } // GetAppletCount 获取app运单统计数量 // @Summary 获取app运单统计数量 // @Description 获取app运单统计数量 // @Tags 运单 // @Param waybillNo query string false "运单号" // @Param status query string false "状态:1待派单 2待装车 3待入库 4已装车 5已入库 6已下车 7已出库 8已签收 9待装箱 10已装箱 11已出箱" // @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}" // @Router /api/waybill/applet-count [get] // @Security Bearer func (e WaybillController) GetAppletCount(c *gin.Context) { s := service.Waybill{} userSvc := service.SysUser{} req := dto.WaybillGetAppletPageReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.Query). MakeService(&s.Service). MakeService(&userSvc.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //数据权限检查 p := actions.GetPermissionFromContext(c) var userObj model.SysUser err = userSvc.Get(&dto.SysUserGetReq{Id: p.UserId}, nil, &userObj) if err != nil { e.Error(500, err, err.Error()) return } list := make([]model.Waybill, 0) var count int64 if userObj.UserType == "customer" { r := dto.WaybillGetCustomerPageReq{} r.PageSize = 9999 r.CustomerId = p.UserId err = s.GetCustomerPage(&r, &list, &count, p) var statusCount = make(map[int]int) statusCount[0] = int(count) for _, waybill := range list { if _, ok := statusCount[waybill.Status]; ok { statusCount[waybill.Status] += 1 } else { statusCount[waybill.Status] = 1 } } e.OK(statusCount, "查询成功") return } err = s.GetAppletCount(&list, &count, p) if err != nil { e.Error(500, err, err.Error()) return } var statusCount = make(map[int]int) statusCount[0] = int(count) for _, waybill := range list { if _, ok := statusCount[waybill.Status]; ok { statusCount[waybill.Status] += 1 } else { statusCount[waybill.Status] = 1 } } e.OK(statusCount, "查询成功") } // Get 通过id获取运单 // @Summary 通过id获取运单 // @Description 通过id获取运单 // @Tags 运单 // @Param id path string true "运单id" // @Success 200 {object} response.Response{data=model.Waybill} "{"code": 200, "data": [...]}" // @Router /api/waybill/{id} [get] // @Security Bearer func (e WaybillController) Get(c *gin.Context) { s := service.Waybill{} req := dto.WaybillGetReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, nil). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } var object model.Waybill p := actions.GetPermissionFromContext(c) //数据权限检查 err = s.Get(&req, &object, p) if err != nil { e.Error(500, err, err.Error()) return } e.OK(object, "查询成功") } // Insert 添加运单 // @Summary 添加运单 // @Description 添加运单 // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillInsertReq true "data" // @Success 200 {string} string "{"code": 200, "message": "添加成功"}" // @Success 200 {string} string "{"code": -1, "message": "添加失败"}" // @Router /api/waybill [post] // @Security Bearer func (e WaybillController) Insert(c *gin.Context) { s := service.Waybill{} req := dto.WaybillInsertReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.JSON). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } p := actions.GetPermissionFromContext(c) // 设置创建人 req.SetCreateBy(user.GetUserId(c)) req.SetDeptId(p.DeptId) err = s.Insert(&req) if err != nil { e.Error(500, err, err.Error()) return } e.OK(req.GetId(), "添加成功") } // AppletInsert 添加运单app // @Summary 添加运单app // @Description 添加运单app // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillInsertReq true "data" // @Success 200 {string} string "{"code": 200, "message": "添加成功"}" // @Success 200 {string} string "{"code": -1, "message": "添加失败"}" // @Router /api/waybill [post] // @Security Bearer func (e WaybillController) AppletInsert(c *gin.Context) { s := service.Waybill{} req := dto.WaybillInsertReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.JSON). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } p := actions.GetPermissionFromContext(c) err = s.AppletInsert(&req, p) if err != nil { e.Error(500, err, err.Error()) return } e.OK(req.GetId(), "添加成功") } // Update 修改运单 // @Summary 修改运单 // @Description 修改运单 // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillUpdateReq true "body" // @Success 200 {string} string "{"code": 200, "message": "修改成功"}" // @Success 200 {string} string "{"code": -1, "message": "修改失败"}" // @Router /api/waybill [put] // @Security Bearer func (e WaybillController) Update(c *gin.Context) { s := service.Waybill{} req := dto.WaybillUpdateReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } p := actions.GetPermissionFromContext(c) req.SetUpdateBy(user.GetUserId(c)) err = s.Update(&req, p) if err != nil { e.Error(500, err, err.Error()) return } e.OK(req.GetId(), "修改成功") } // Delivery 派单 // @Summary 派单 // @Description 派单 // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillDeliveryReq true "body" // @Success 200 {string} string "{"code": 200, "message": "派单成功"}" // @Success 200 {string} string "{"code": -1, "message": "派单失败"}" // @Router /api/waybill [put] // @Security Bearer func (e WaybillController) Delivery(c *gin.Context) { s := service.Waybill{} req := dto.WaybillDeliveryReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } p := actions.GetPermissionFromContext(c) req.SetUpdateBy(user.GetUserId(c)) err = s.Delivery(&req, p) if err != nil { e.Error(500, err, err.Error()) return } e.OK(req.GetId(), "派单成功") } // Delete 删除运单 // @Summary 删除运单 // @Description 删除运单 // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillDeleteReq true "body" // @Success 200 {string} string "{"code": 200, "message": "删除成功"}" // @Success 200 {string} string "{"code": -1, "message": "删除失败"}" // @Router /api/waybill [delete] // @Security Bearer func (e WaybillController) Delete(c *gin.Context) { s := service.Waybill{} req := dto.WaybillDeleteReq{} userSvc := service.SysUser{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.JSON, nil). MakeService(&s.Service). MakeService(&userSvc.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //数据权限检查 p := actions.GetPermissionFromContext(c) err = s.Remove(&req, p) if err != nil { e.Error(500, err, err.Error()) return } e.OK(req.GetId(), "删除成功") } // WarehouseIn 入库 // @Summary 入库 // @Description 入库 // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillInOutReq true "body" // @Success 200 {string} string "{"code": 200, "message": "入库成功"}" // @Success 200 {string} string "{"code": -1, "message": "入库失败"}" // @Router /api/waybill/warehouse-in [post] // @Security Bearer func (e WaybillController) WarehouseIn(c *gin.Context) { s := service.Waybill{} req := dto.WaybillInOutReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.JSON, nil). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //数据权限检查 p := actions.GetPermissionFromContext(c) err = s.WarehouseIn(&req, p) if err != nil { e.Error(500, err, err.Error()) return } e.OK(req.WaybillNoList, "入库成功") } // WarehouseOut 出库 // @Summary 出库 // @Description 出库 // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillInOutReq true "body" // @Success 200 {string} string "{"code": 200, "message": "出库成功"}" // @Success 200 {string} string "{"code": -1, "message": "出库失败"}" // @Router /api/waybill/warehouse-out [post] // @Security Bearer func (e WaybillController) WarehouseOut(c *gin.Context) { s := service.Waybill{} req := dto.WaybillInOutReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.JSON, nil). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //数据权限检查 p := actions.GetPermissionFromContext(c) err = s.WarehouseOut(&req, p) if err != nil { e.Error(500, err, err.Error()) return } e.OK(req.WaybillNoList, "出库成功") } // CarIn 装车 // @Summary 装车 // @Description 装车 // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillInOutReq true "body" // @Success 200 {string} string "{"code": 200, "message": "装车成功"}" // @Success 200 {string} string "{"code": -1, "message": "装车失败"}" // @Router /api/waybill/car-in [post] // @Security Bearer func (e WaybillController) CarIn(c *gin.Context) { s := service.Waybill{} req := dto.WaybillInOutReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.JSON, nil). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //数据权限检查 p := actions.GetPermissionFromContext(c) err = s.CarIn(&req, p) if err != nil { e.Error(500, err, err.Error()) return } e.OK(req.WaybillNoList, "装车成功") } // CarOut 下车 // @Summary 下车 // @Description 下车 // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillInOutReq true "body" // @Success 200 {string} string "{"code": 200, "message": "下车成功"}" // @Success 200 {string} string "{"code": -1, "message": "下车失败"}" // @Router /api/waybill/car-out [post] // @Security Bearer func (e WaybillController) CarOut(c *gin.Context) { s := service.Waybill{} req := dto.WaybillInOutReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.JSON, nil). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //数据权限检查 p := actions.GetPermissionFromContext(c) err = s.CarOut(&req, p) if err != nil { e.Error(500, err, err.Error()) return } e.OK(req.WaybillNoList, "下车成功") } // CoolerBoxIn 装箱 // @Summary 装箱 // @Description 装箱 // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillCoolerBoxInReq true "body" // @Success 200 {string} string "{"code": 200, "message": "装箱成功"}" // @Success 200 {string} string "{"code": -1, "message": "装箱失败"}" // @Router /api/waybill/cooler-box-in [post] // @Security Bearer func (e WaybillController) CoolerBoxIn(c *gin.Context) { s := service.Waybill{} req := dto.WaybillCoolerBoxInReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.JSON, nil). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //数据权限检查 p := actions.GetPermissionFromContext(c) err = s.CoolerBoxIn(&req, p) if err != nil { e.Error(500, err, err.Error()) return } e.OK(req.WaybillNoList, "装箱成功") } // StopRecord 停止记录 // @Summary 停止记录 // @Description 停止记录 // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillStopRecordReq true "body" // @Success 200 {string} string "{"code": 200, "message": "停止记录成功"}" // @Success 200 {string} string "{"code": -1, "message": "停止记录失败"}" // @Router /api/waybill/stop-record [post] // @Security Bearer func (e WaybillController) StopRecord(c *gin.Context) { s := service.Waybill{} req := dto.WaybillStopRecordReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.JSON, nil). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //数据权限检查 p := actions.GetPermissionFromContext(c) err = s.StopRecord(&req, p) if err != nil { e.Error(500, err, err.Error()) return } e.OK(req.WaybillNo, "停止记录成功") } // Receipt 签收 // @Summary 签收 // @Description 签收 // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillReceiptReq true "body" // @Success 200 {string} string "{"code": 200, "message": "签收成功"}" // @Success 200 {string} string "{"code": -1, "message": "签收失败"}" // @Router /api/waybill/car-out [post] // @Security Bearer func (e WaybillController) Receipt(c *gin.Context) { s := service.Waybill{} req := dto.WaybillReceiptReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.JSON, nil). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //数据权限检查 p := actions.GetPermissionFromContext(c) err = s.Receipt(&req, p) if err != nil { e.Error(500, err, err.Error()) return } e.OK(req.WaybillNo, "签收成功") } // GetCustomerPage 获取客户运单列表 // @Summary 获取客户运单列表 // @Description 获取客户运单列表 // @Tags 运单 // @Param waybillNo query string false "运单号" // @Param status query int false "状态:1未发货 2已发货 3已签收 4已处理" // @Param orderStartTime query string false "下单开始时间" // @Param orderEndTime query string false "下单开始时间" // @Param pageSize query int false "页条数" // @Param page query int false "页码" // @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}" // @Router /api/waybill/customer [get] // @Security Bearer func (e WaybillController) GetCustomerPage(c *gin.Context) { s := service.Waybill{} req := dto.WaybillGetCustomerPageReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.Query). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //数据权限检查 p := actions.GetPermissionFromContext(c) list := make([]model.Waybill, 0) var count int64 req.CustomerId = p.UserId err = s.GetCustomerPage(&req, &list, &count, p) if err != nil { e.Error(500, err, err.Error()) return } e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功") } // CustomerExport 运单管理-客户导出 // @Summary 运单管理-客户导出 // @Description 运单管理-客户导出 // @Tags 运单 // @Param waybillNo query string false "运单号" // @Param status query int false "状态:1未发货 2已发货 3已签收 4已处理" // @Param orderStartTime query string false "下单开始时间" // @Param orderEndTime query string false "下单开始时间" // @Param pageSize query int false "页条数" // @Param page query int false "页码" // @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}" // @Router /api/waybill/customer/export [get] // @Security Bearer func (e WaybillController) CustomerExport(c *gin.Context) { s := service.Waybill{} req := dto.WaybillGetCustomerPageReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.Query). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //数据权限检查 p := actions.GetPermissionFromContext(c) list := make([]model.Waybill, 0) var count int64 req.CustomerId = p.UserId req.PageSize = 9999 err = s.GetCustomerPage(&req, &list, &count, p) if err != nil { e.Error(500, err, err.Error()) return } f := excelize.NewFile() // 设置单元格的值 // 这里设置表头ÒÒ f.SetCellValue("Sheet1", "A1", "序号") f.SetCellValue("Sheet1", "B1", "状态") f.SetCellValue("Sheet1", "C1", "寄件人名称") f.SetCellValue("Sheet1", "D1", "寄件人电话") f.SetCellValue("Sheet1", "E1", "寄件人地址") f.SetCellValue("Sheet1", "F1", "收件人名称") f.SetCellValue("Sheet1", "G1", "收件人电话") f.SetCellValue("Sheet1", "H1", "收件人地址") f.SetCellValue("Sheet1", "I1", "温度要求") f.SetCellValue("Sheet1", "J1", "配送要求") f.SetCellValue("Sheet1", "K1", "货物类型") f.SetCellValue("Sheet1", "L1", "运输备注") // 设置列宽 f.SetColWidth("Sheet1", "A", "A", 6) f.SetColWidth("Sheet1", "B", "B", 8) f.SetColWidth("Sheet1", "C", "C", 14) f.SetColWidth("Sheet1", "D", "D", 14) f.SetColWidth("Sheet1", "E", "E", 30) f.SetColWidth("Sheet1", "F", "F", 14) f.SetColWidth("Sheet1", "G", "G", 14) f.SetColWidth("Sheet1", "H", "H", 30) f.SetColWidth("Sheet1", "I", "K", 15) f.SetColWidth("Sheet1", "L", "L", 15) line := 1 // 循环写入数据 for i, v := range list { line++ f.SetCellValue("Sheet1", fmt.Sprintf("A%d", line), i+1) f.SetCellValue("Sheet1", fmt.Sprintf("B%d", line), model.GetCustomerWaybillStatus(v.Status)) f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), v.SenderAddressName) f.SetCellValue("Sheet1", fmt.Sprintf("D%d", line), v.SenderAddressPhone) f.SetCellValue("Sheet1", fmt.Sprintf("E%d", line), v.SenderAddressDetails) f.SetCellValue("Sheet1", fmt.Sprintf("F%d", line), v.ConsigneeAddressName) f.SetCellValue("Sheet1", fmt.Sprintf("G%d", line), v.ConsigneeAddressPhone) f.SetCellValue("Sheet1", fmt.Sprintf("H%d", line), v.ConsigneeAddressDetails) f.SetCellValue("Sheet1", fmt.Sprintf("I%d", line), v.TemperatureInterval) f.SetCellValue("Sheet1", fmt.Sprintf("J%d", line), v.DeliveryCondition) f.SetCellValue("Sheet1", fmt.Sprintf("K%d", line), v.CargoType) f.SetCellValue("Sheet1", fmt.Sprintf("L%d", line), v.Remark) } timeStr := time.Now().Format("20060102150405") filePath := "ofile/" + "运单" + timeStr + ".xlsx" defer func() { os.Remove(filePath) }() // 保存文件 if err = f.SaveAs(filePath); err != nil { logs.Error("保存运单失败:", err) } c.Header("Content-Type", "application/vnd.ms-excel;charset=utf8") // PathEscape 函数对中文做处理 c.Header("Content-Disposition", "attachment; filename="+url.PathEscape("运单"+timeStr+".xlsx")) c.Header("Content-Transfer-Encoding", "binary") c.File(filePath) } // CustomerInsert 客户添加运单 // @Summary 客户添加运单 // @Description 客户添加运单 // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillInsertReq true "data" // @Success 200 {string} string "{"code": 200, "message": "添加成功"}" // @Success 200 {string} string "{"code": -1, "message": "添加失败"}" // @Router /api/waybill/customer [post] // @Security Bearer func (e WaybillController) CustomerInsert(c *gin.Context) { s := service.Waybill{} userSvc := service.SysUser{} req := dto.WaybillInsertReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.JSON). MakeService(&s.Service). MakeService(&userSvc.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } p := actions.GetPermissionFromContext(c) var userObj model.SysUser err = userSvc.Get(&dto.SysUserGetReq{Id: p.UserId}, nil, &userObj) if err != nil { e.Error(500, err, "获取用户信息失败") return } if p.DeptId == 0 && req.DeptId == 0 { e.Error(500, err, "请先选择运输公司") return } // 设置创建人 req.SetCreateBy(user.GetUserId(c)) req.CustomerId = p.UserId req.CustomerName = userObj.NickName if p.DeptId > 0 { req.SetDeptId(p.DeptId) } err = s.Insert(&req) if err != nil { e.Error(500, err, err.Error()) return } e.OK(req.GetId(), "添加成功") } // Import 导入运单 // @Summary 导入运单 // @Description 导入运单 // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillImportReq true "data" // @Success 200 {string} string "{"code": 200, "message": "添加成功"}" // @Success 200 {string} string "{"code": -1, "message": "添加失败"}" // @Router /api/waybill/import [post] // @Security Bearer func (e WaybillController) Import(c *gin.Context) { s := service.Waybill{} userSvc := service.SysUser{} req := dto.WaybillImportReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.Form). MakeService(&s.Service). MakeService(&userSvc.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } //读取第一fileName的文件 fileHeader, err := c.FormFile("file") if err != nil { err = errors.New("文件格式错误" + err.Error()) e.Logger.Error(err) e.Error(500, err, err.Error()) return } if fileHeader.Size > 1024*1024*2 { err = errors.New("文件大小超过2M") e.Logger.Error(err) e.Error(500, err, err.Error()) return } file, err := fileHeader.Open() if err != nil { err = errors.New("文件格式错误" + err.Error()) e.Logger.Error(err) e.Error(500, err, err.Error()) return } defer file.Close() xlsx, err := excelize.OpenReader(bufio.NewReader(file)) if err != nil { err = errors.New("文件格式错误" + err.Error()) e.Logger.Error(err) e.Error(500, err, err.Error()) return } p := actions.GetPermissionFromContext(c) if p.DeptId == 0 { e.Error(500, err, "获取用户信息失败") return } var userObj model.SysUser err = userSvc.Get(&dto.SysUserGetReq{Id: p.UserId}, nil, &userObj) if err != nil { e.Error(500, err, "获取用户信息失败") return } var customerId int //customerName := req.CustomerName if userObj.UserType == model.UserTypeCustomer { customerId = userObj.Id //customerName = userObj.NickName } rows, _ := xlsx.GetRows("Sheet1") for indexRow, row := range rows { if indexRow == 0 { continue } if len(row) < 12 { for i := 0; i < 12-len(row); i++ { row = append(row, "") } } for i, colCell := range row { fmt.Println(i, ":", colCell) } quantity, _ := strconv.Atoi(row[10]) obj := dto.WaybillInsertReq{ Status: 1, SenderAddressName: row[0], SenderAddressPhone: row[1], SenderAddressDetails: row[2], CustomerName: row[3], ConsigneeAddressName: row[4], ConsigneeAddressPhone: row[5], ConsigneeAddressDetails: row[6], TemperatureInterval: row[7], DeliveryCondition: row[8], CargoType: row[9], Quantity: quantity, Remark: row[11], CustomerId: customerId, } obj.SetDeptId(p.DeptId) obj.SetCreateBy(user.GetUserId(c)) err = s.Insert(&obj) if err != nil { e.Error(500, err, err.Error()) return } } e.OK(len(rows)-1, "导入成功") } // ExportTemplate 导出运单模板 // @Summary 导出运单模板 // @Description 导出运单模板 // @Tags 运单 // @Accept application/json // @Product application/json // @Router /api/waybill/export-template [post] // @Security Bearer func (e WaybillController) ExportTemplate(c *gin.Context) { s := service.Waybill{} err := e.MakeContext(c). MakeOrm(). MakeService(&s.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } filePath := "./ofile/运单导入模板.xlsx" //打开文件 fileTmp, errByOpenFile := os.Open(filePath) defer fileTmp.Close() //获取文件的名称 fileName := path.Base(filePath) if errByOpenFile != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } c.Header("Content-Type", "application/vnd.ms-excel;charset=utf8") // PathEscape 函数对中文做处理 c.Header("Content-Disposition", "attachment; filename="+url.PathEscape(fileName)) c.Header("Content-Transfer-Encoding", "binary") c.File(filePath) } // TemperaturePDF 导出温度记录pdf // @Summary 导出温度记录pdf // @Description 导出温度记录pdf // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillGetByWaybillPdfReq true "data" // @Success 200 {string} string "{"code": 200, "message": "添加成功"}" // @Success 200 {string} string "{"code": -1, "message": "添加失败"}" // @Router /api/waybill/temperature-pdf [post] // @Security Bearer func (e WaybillController) TemperaturePDF(c *gin.Context) { s := service.Waybill{} companySvc := service.Company{} req := dto.WaybillGetByWaybillPdfReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.JSON, nil). MakeService(&s.Service). MakeService(&companySvc.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } var waybill model.Waybill err = s.GetByWaybillNo(&req, &waybill, nil) if err != nil { e.Error(500, err, err.Error()) return } var company model.SysDept err = companySvc.Get(&dto.CompanyGetReq{Id: waybill.DeptId}, &company) if err != nil { e.Error(500, err, err.Error()) return } filename, filePath, err := PDF(s, waybill, company, req.WaybillTaskIds, req.HumidityShow) defer func() { os.Remove(filePath) }() c.Header("Content-Disposition", "attachment; filename="+url.PathEscape(filename)) c.Header("Content-Transfer-Encoding", "binary") c.File(filePath) } // TemperaturePDFUrl 导出温度记录pdf链接 // @Summary 导出温度记录pdf链接 // @Description 导出温度记录pdf链接 // @Tags 运单 // @Accept application/json // @Product application/json // @Param data body dto.WaybillGetByWaybillPdfReq true "data" // @Success 200 {string} string "{"code": 200, "message": "添加成功"}" // @Success 200 {string} string "{"code": -1, "message": "添加失败"}" // @Router /api/waybill/temperature-pdf [post] // @Security Bearer func (e WaybillController) TemperaturePDFUrl(c *gin.Context) { s := service.Waybill{} companySvc := service.Company{} req := dto.WaybillGetByWaybillPdfReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.JSON, nil). MakeService(&s.Service). MakeService(&companySvc.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } var waybill model.Waybill err = s.GetByWaybillNo(&req, &waybill, nil) if err != nil { e.Error(500, err, err.Error()) return } var company model.SysDept err = companySvc.Get(&dto.CompanyGetReq{Id: waybill.DeptId}, &company) if err != nil { e.Error(500, err, err.Error()) return } filename, filePath, err := PDF(s, waybill, company, req.WaybillTaskIds, req.HumidityShow) defer func() { os.Remove(filePath) }() err = file_store.QiniuFileStore.UpLoad(filename, filePath) if err != nil { c.JSON(400, gin.H{"error": "文件上传失败"}) return } e.Custom(gin.H{ "code": 200, "data": conf.ExtConfig.Qiniu.Endpoint + filename, "msg": "success", }) } func PDF(s service.Waybill, waybill model.Waybill, company model.SysDept, waybillTaskIds []int, humidityShow bool) (filename, filePath string, err error) { DeviceSensor_data, Pdf_data, waybillPDF, err := s.GetTwoDeviceSensorData(&dto.WaybillPdfReq{WaybillNo: waybill.WaybillNo, WaybillTaskIds: waybillTaskIds}) // 最高温度、最低温度、最高湿度、最低湿度 var maxTemp, minTemp, maxHumidity, minHumidity float32 // 最高温度时间、最低温度时间、最高湿度时间、最低湿度时间 var maxTempTime, minTempTime, maxHumidityTime, minHumidityTime string // 总温度 总湿度 var totalTemp, totalHumidity float32 // 平均温度 平均湿度 var avgTemp, avgHumidity float32 // 温度阈值,湿度阈值 var tempThreshold, humidityThreshold string // 记录开始时间,记录结束时间 var s_time, e_time string if len(DeviceSensor_data) > 0 { tempThreshold = fmt.Sprintf("%.1f-%.1f", DeviceSensor_data[0].T_tl, DeviceSensor_data[0].T_tu) humidityThreshold = fmt.Sprintf("%.1f-%.1f", DeviceSensor_data[0].T_rhl, DeviceSensor_data[0].T_rhu) s_time = DeviceSensor_data[0].T_time e_time = DeviceSensor_data[len(DeviceSensor_data)-1].T_time // 最高温度及时刻 maxTemp = DeviceSensor_data[0].T_t maxTempTime = DeviceSensor_data[0].T_time // 最低温度及时刻 minTemp = DeviceSensor_data[0].T_t minTempTime = DeviceSensor_data[0].T_time // 最高湿度及时刻 maxHumidity = DeviceSensor_data[0].T_rh maxHumidityTime = DeviceSensor_data[0].T_time // 获取最低湿度及时刻 minHumidity = DeviceSensor_data[0].T_rh minHumidityTime = DeviceSensor_data[0].T_time for i := 0; i < len(DeviceSensor_data); i++ { data := DeviceSensor_data[i] if data.T_t > maxTemp { maxTemp = data.T_t maxTempTime = data.T_time } if data.T_t < minTemp { minTemp = data.T_t minTempTime = data.T_time } totalTemp += data.T_t if data.T_rh > maxHumidity { maxHumidity = data.T_rh maxHumidityTime = data.T_time } if data.T_rh < minHumidity { minHumidity = data.T_rh minHumidityTime = data.T_time } totalHumidity += data.T_rh } // 平均温度 avgTemp = totalTemp / float32(len(DeviceSensor_data)) // 平均湿度 avgHumidity = totalHumidity / float32(len(DeviceSensor_data)) } // -------------------获取最高温湿度、温蒂温湿度、平均温湿度结束 pdf := &gopdf.GoPdf{} pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4 err = pdf.AddTTFFont("wts", "static/fonts/MiSans-Medium.ttf") if err != nil { return } err = pdf.SetFont("wts", "", 20) if err != nil { return } pdf.SetGrayFill(0.5) pdf.SetMargins(0, 20, 0, 20) pdf.AddPage() var fileName2 string if len(company.Logo) > 0 { imgH, errImg := lib.GetImage(company.Logo) if errImg != nil { err = errors.New("获取图片失败") return } imgWidth := float64(imgH.Bounds().Dx()) imgHeight := float64(imgH.Bounds().Dy()) H := 60. W := (imgWidth * H) / imgHeight if strings.Contains(company.Logo, ".png") { err = pdf.ImageFrom(imgH, 10, 0, &gopdf.Rect{W: W, H: H}) if err != nil { err = errors.New("写入图片失败") return } } else { fileName := "./ofile/" + time.Now().Format("20060102150405") + ".png" f, _ := os.Create(fileName) defer f.Close() defer func() { os.Remove(fileName) }() png.Encode(f, imgH) err = pdf.Image(fileName, 10, 0, &gopdf.Rect{W: W, H: H}) if err != nil { if err.Error() == "16-bit depth not supported" { fileName2 = "./ofile/" + time.Now().Format("20060102150405") + ".png" f2, _ := os.Create(fileName2) defer f.Close() defer func() { os.Remove(fileName2) }() jpeg.Encode(f2, imgH, &jpeg.Options{100}) err = pdf.Image(fileName2, 10, 0, &gopdf.Rect{W: W, H: H}) } if err != nil { err = errors.New("写入图片失败") return } } } } var imgHSeal image.Image var existSealImg bool if len(company.Seal) > 0 { existSealImg = true var errImg error imgHSeal, errImg = lib.GetImage(company.Seal) if errImg != nil { err = errors.New("获取图片失败") return } } title := "运单" + waybill.WaybillNo + "温度记录" if humidityShow { title = "运单" + waybill.WaybillNo + "温湿度记录" } var y float64 = 70 textw, _ := pdf.MeasureTextWidth(title) pdf.SetX((595 / 2) - (textw / 2)) pdf.SetY(y) pdf.Text(title) y += 30 pdf.SetFont("wts", "", 16) pdf.SetXY(10, y) pdf.Text("记录概要信息") // 线 y += 10 pdf.SetLineWidth(0.5) pdf.SetStrokeColor(169, 169, 169) pdf.Line(10, y, 585, y) y += 20 pdf.SetFont("wts", "", 10) pdf.SetXY(10, y) pdf.Text(fmt.Sprintf("记录开始时间:%s", s_time)) pdf.SetXY(240, y) pdf.Text(fmt.Sprintf("记录结束时间:%s", e_time)) sTime, _ := lib.TimeStrToTime(s_time) eTime, _ := lib.TimeStrToTime(e_time) pdf.SetXY(470, y) minutes := int(eTime.Sub(sTime).Minutes()) hours := minutes / 60 remainingMinutes := minutes % 60 pdf.Text(fmt.Sprintf("记录总时间:%dh%dmin", hours, remainingMinutes)) // -------------最高温/湿度 最低温/湿度 平均温/湿度 y += 15 pdf.SetXY(10, y) pdf.Text(fmt.Sprintf("最高温度:%.1f℃,%s", lib.RoundToDecimal(float64(maxTemp), 1), maxTempTime)) pdf.SetXY(240, y) pdf.Text(fmt.Sprintf("最低温度:%.1f℃,%s", lib.RoundToDecimal(float64(minTemp), 1), minTempTime)) pdf.SetXY(470, y) pdf.Text(fmt.Sprintf("平均温度:%.1f℃", lib.RoundToDecimal(float64(avgTemp), 1))) if humidityShow { y += 15 pdf.SetXY(10, y) pdf.Text(fmt.Sprintf("最高湿度:%.1f%%RH,%s", lib.RoundToDecimal(float64(maxHumidity), 1), maxHumidityTime)) pdf.SetXY(240, y) pdf.Text(fmt.Sprintf("最低湿度:%.1f%%RH,%s", lib.RoundToDecimal(float64(minHumidity), 1), minHumidityTime)) pdf.SetXY(470, y) pdf.Text(fmt.Sprintf("平均湿度:%.1f%%RH", lib.RoundToDecimal(float64(avgHumidity), 1))) } // -------------温/湿度阈值 y += 15 pdf.SetXY(10, y) pdf.Text(fmt.Sprintf("温度阈值:%s℃", tempThreshold)) if humidityShow { pdf.SetXY(240, y) pdf.Text(fmt.Sprintf("温度阈值:%s%%", humidityThreshold)) } //-------------发货单位,收货单位,备注 y += 15 pdf.SetXY(10, y) T_forwarding_unit_temp := []rune(waybill.SenderAddressName) if len(T_forwarding_unit_temp) > 17 { pdf.Text(fmt.Sprintf("发货人:%s", string(T_forwarding_unit_temp[0:17]))) pdf.SetXY(60, y+15) pdf.Text(fmt.Sprintf("%s", string(T_forwarding_unit_temp[17:]))) } else { pdf.Text(fmt.Sprintf("发货人:%s", string(T_forwarding_unit_temp))) } pdf.SetXY(240, y) T_consignee_unit_temp := []rune(waybill.ConsigneeAddressName) if len(T_consignee_unit_temp) > 17 { pdf.Text(fmt.Sprintf("收货人:%s", string(T_consignee_unit_temp[0:17]))) pdf.SetXY(290, y+15) pdf.Text(fmt.Sprintf("%s", string(T_consignee_unit_temp[17:]))) } else { pdf.Text(fmt.Sprintf("收货人:%s", string(T_consignee_unit_temp))) } // 承运方 y += 15 pdf.SetXY(10, y) company_name := []rune(waybill.Dept.Name) pdf.Text(fmt.Sprintf("承运方:%s", string(company_name))) y += 15 pdf.SetXY(10, y) T_remark_temp := []rune(waybill.Remark) if len(T_remark_temp) > 35 { pdf.Text(fmt.Sprintf("备注:%s", string(T_remark_temp[0:35]))) pdf.SetXY(10, y+15) pdf.Text(fmt.Sprintf("%s", string(T_remark_temp[35:]))) } else { pdf.Text(fmt.Sprintf("备注: %s", string(T_remark_temp))) } y += 35 pdf.SetFont("wts", "", 16) pdf.SetXY(10, y) pdf.Text("记录曲线信息") // 线 y += 10 pdf.SetLineWidth(0.5) pdf.SetStrokeColor(169, 169, 169) pdf.Line(10, y, 585, y) y += 1 var tempFilepath string tempFilepath, err = DeviceDataTemperatureJPG(s_time, e_time, waybillPDF) if err == nil { imgH, _ := gopdf.ImageHolderByPath(tempFilepath) pdf.ImageByHolder(imgH, 10, y, &gopdf.Rect{W: 575, H: 315}) y += 315 } //var humidityFilepath string //if req.HumidityShow { // humidityFilepath, err = DeviceDataHumidityJPG2(s_time, e_time, waybillPDF) // if err == nil { // imgH, _ := gopdf.ImageHolderByPath(humidityFilepath) // pdf.ImageByHolder(imgH, 10, y, &gopdf.Rect{W: 575, H: 315}) // y += 315 // } //} if y > 841.89 { // 图片结束直接分页 addStampImage(pdf, existSealImg, imgHSeal, 455, 660) pdf.AddPage() y = 20 } y += 20 pdf.SetFont("wts", "", 16) pdf.SetXY(10, y) pdf.Text("记录数据信息") // 线 y += 10 pdf.SetLineWidth(0.5) pdf.SetStrokeColor(169, 169, 169) pdf.Line(10, y, 585, y) y += 10 pdf.SetFont("wts", "", 10) var x float64 = 12 var w float64 = 110 lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w w = 100 lib.RectFillColor(pdf, "名称", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w w = 37 lib.RectFillColor(pdf, "T1", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w lib.RectFillColor(pdf, "T2", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w w = 110 lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w w = 100 lib.RectFillColor(pdf, "名称", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w w = 37 lib.RectFillColor(pdf, "T1", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w lib.RectFillColor(pdf, "T2", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) for i, v := range Pdf_data { if i%2 == 0 { y += 20 //var textH float64 = 25 // if text height is 25px. //pdf.SetNewY(y, textH) if y > 800 { addStampImage(pdf, existSealImg, imgHSeal, 455, y-130) pdf.AddPage() y = 20 x = 12 w = 110 lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w w = 100 lib.RectFillColor(pdf, "名称", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w w = 37 lib.RectFillColor(pdf, "T1", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w lib.RectFillColor(pdf, "T2", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w w = 110 lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w w = 100 lib.RectFillColor(pdf, "名称", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w w = 37 lib.RectFillColor(pdf, "T1", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w lib.RectFillColor(pdf, "T2", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) y += 20 } //y = pdf.GetY() x, w = 12, 110 lib.RectFillColor(pdf, v.T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w w = 100 lib.RectFillColor(pdf, v.T_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w w = 37 lib.RectFillColor(pdf, lib.Float32_to_string_forPDF(v.T_id1), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w lib.RectFillColor(pdf, lib.Float32_to_string_forPDF(v.T_id2), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) } if i%2 == 1 { x = x + w w = 110 lib.RectFillColor(pdf, v.T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w w = 100 lib.RectFillColor(pdf, v.T_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w w = 37 lib.RectFillColor(pdf, lib.Float32_to_string_forPDF(v.T_id1), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) x = x + w lib.RectFillColor(pdf, lib.Float32_to_string_forPDF(v.T_id2), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle) } } if y <= 800 { if y < 150 { y = 20 } else { y = y - 130 } addStampImage(pdf, existSealImg, imgHSeal, 455, y) } filename = "运单" + waybill.WaybillNo + "温度记录" + time.Now().Format("20060102150405") + ".pdf" filePath = "ofile/" + filename err = pdf.WritePdf(filePath) if err != nil { return } defer func() { os.Remove(tempFilepath) os.Remove(fileName2) }() return filename, filePath, nil } // WaybillPDF 导出运单pdf // @Summary 导出运单pdf // @Description 导出运单pdf // @Tags 运单 // @Param waybillNo query string false "运单号" // @Param pageSize query int false "页条数" // @Param page query int false "页码" // @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}" // @Router /api/waybill/waybill-pdf [get] // @Security Bearer func (e WaybillController) WaybillPDF(c *gin.Context) { s := service.Waybill{} companySvc := service.Company{} req := dto.WaybillGetByWaybillPdfReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.Query). MakeService(&s.Service). MakeService(&companySvc.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } var waybill model.Waybill var company model.SysDept //err = s.GetByWaybillNo(&req, &waybill, p) err = s.GetByWaybillNo(&req, &waybill, nil) if err != nil { e.Error(500, err, err.Error()) return } err = companySvc.Get(&dto.CompanyGetReq{Id: waybill.DeptId}, &company) if err != nil { e.Error(500, err, err.Error()) return } // -------------------生成运单条码 // 运单条码 cs, _ := code128.Encode(waybill.WaybillNo) // 创建一个要输出数据的文件 imgPath := "ofile/img/" + waybill.WaybillNo + ".png" file, _ := os.Create(imgPath) defer file.Close() // 设置图片像素大小 barCode, _ := barcode.Scale(cs, 205, 50) // 将code128的条形码编码为png图片 png.Encode(file, barCode) imgPath2 := "ofile/img/" + waybill.WaybillNo + ".jpg" png2j.Con2jpg(imgPath, imgPath2) qrcode, err := qrcode.Encode(fmt.Sprintf("%s/WaybillInquiry?waybillNo=%s", conf.ExtConfig.Service.Domain, waybill.WaybillNo), qrcode.Medium, 70) if err != nil { e.Error(500, err, err.Error()) return } qrCodeImgH, err := gopdf.ImageHolderByBytes(qrcode) if err != nil { e.Error(500, err, err.Error()) return } pdf := &gopdf.GoPdf{} pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: 283.46, H: 283.46}}) //595.28, 841.89 = A4 //pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4 err = pdf.AddTTFFont("wts", "static/fonts/MiSans-Medium.ttf") if err != nil { return } pdf.SetGrayFill(0.5) pdf.SetMargins(0, 10, 0, 10) for i := 0; i < waybill.Quantity; i++ { pdf.AddPage() var y float64 = 20 pdf.SetFont("wts", "", 10) //y += 12 pdf.SetXY(250, 20) pdf.SetFont("wts", "", 13) if waybill.Quantity > 1 { pdf.Text(fmt.Sprintf("%d/%d", i+1, waybill.Quantity)) } pdf.SetFont("wts", "", 10) y += 10 pdf.Image(imgPath2, 20, y, &gopdf.Rect{W: 240, H: 30}) y += 43 textw, _ := pdf.MeasureTextWidth(waybill.WaybillNo) pdf.SetX((283.46 / 2) - (textw / 2)) pdf.SetY(y) pdf.Text(waybill.WaybillNo) if len(company.Logo) > 0 { imgH, errImg := lib.GetImage(company.Logo) if errImg != nil { err = errors.New("获取图片失败") e.Error(500, err, err.Error()) return } imgWidth := float64(imgH.Bounds().Dx()) imgHeight := float64(imgH.Bounds().Dy()) H := 30. W := (imgWidth * H) / imgHeight if strings.Contains(company.Logo, ".png") { err = pdf.ImageFrom(imgH, 10, 0, &gopdf.Rect{W: W, H: H}) if err != nil { err = errors.New("写入图片失败") e.Error(500, err, err.Error()) return } } else { fileName := "./ofile/" + time.Now().Format("20060102150405") + ".png" f, _ := os.Create(fileName) defer f.Close() defer func() { os.Remove(fileName) }() png.Encode(f, imgH) err = pdf.Image(fileName, 10, 0, &gopdf.Rect{W: W, H: H}) if err != nil { if err.Error() == "16-bit depth not supported" { fileName2 := "./ofile/" + time.Now().Format("20060102150405") + ".png" f2, _ := os.Create(fileName2) defer f.Close() defer func() { os.Remove(fileName2) }() jpeg.Encode(f2, imgH, &jpeg.Options{100}) err = pdf.Image(fileName2, 10, 0, &gopdf.Rect{W: W, H: H}) } if err != nil { err = errors.New("写入图片失败") e.Error(500, err, err.Error()) return } } } } else { title := "#" + company.Name pdf.SetXY(10, 20) pdf.Text(title) } // 线 y += 6 pdf.SetLineWidth(0.5) pdf.SetLineType("dotted") pdf.Line(10, y, 273, y) y += 28 pdf.SetFont("wts", "", 18) pdf.SetXY(12, y+3) pdf.Text("收") pdf.SetFont("wts", "", 10) y -= 5 pdf.SetXY(40, y) pdf.Text(fmt.Sprintf("%s %s", lib.MaskStr(waybill.ConsigneeAddressName), lib.MaskPhoneNumber(waybill.ConsigneeAddressPhone))) y += 15 pdf.SetXY(40, y) pdf.Text(waybill.ConsigneeAddressDetails) // 线 y += 8 pdf.SetLineWidth(0.5) pdf.SetLineType("dotted") pdf.Line(10, y, 273, y) y += 22 pdf.SetFont("wts", "", 13) pdf.SetXY(14, y+3) pdf.Text("寄") pdf.SetFont("wts", "", 10) y -= 5 pdf.SetXY(40, y) pdf.Text(fmt.Sprintf("%s %s", lib.MaskStr(waybill.SenderAddressName), lib.MaskPhoneNumber(waybill.SenderAddressPhone))) y += 15 pdf.SetXY(40, y) pdf.Text(waybill.SenderAddressDetails) // 线 y += 10 pdf.SetLineWidth(0.5) //pdf.SetLineType("dashed") pdf.SetLineType("dotted") pdf.Line(10, y, 273, y) y += 12 pdf.SetXY(10, y) pdf.SetFont("wts", "", 8) pdf.Text("下单时间:" + waybill.OrderTime.String()) // 线 y += 6 pdf.SetLineWidth(0.5) pdf.SetLineType("dotted") pdf.Line(10, y, 273, y) pdf.SetFont("wts", "", 10) y += 20 pdf.SetXY(10, y) pdf.Text("备注:") pdf.SetFont("wts", "", 8) y += 15 pdf.SetXY(30, y) pdf.Text("货物类型:" + waybill.CargoType) y += 15 pdf.SetXY(30, y) pdf.Text("温度要求:" + waybill.TemperatureInterval) y += 15 pdf.SetXY(30, y) pdf.Text("配送要求:" + waybill.DeliveryCondition) x := 170. //pdf.Image(qrcodeImgPath2, x, y-55, &gopdf.Rect{W: 70, H: 70}) pdf.ImageByHolder(qrCodeImgH, x, y-63, &gopdf.Rect{W: 70, H: 70}) pdf.SetFont("wts", "", 8) y += 10 textw, _ = pdf.MeasureTextWidth("扫码查询") pdf.SetX(x + 35 - (textw / 2)) pdf.SetY(y) pdf.Text("扫码查询") y += 10 textw, _ = pdf.MeasureTextWidth("物流温湿度信息") pdf.SetX(x + 35 - (textw / 2)) pdf.SetY(y) pdf.Text("物流温湿度信息") } filename := "运单" + req.WaybillNo + ".pdf" filePath := "ofile/" + filename err = pdf.WritePdf(filePath) if err != nil { return } defer func() { os.Remove(filePath) os.Remove(imgPath) os.Remove(imgPath2) }() c.Header("Content-Disposition", "attachment; filename="+url.PathEscape(filename)) c.Header("Content-Transfer-Encoding", "binary") c.File(filePath) } // SendMail 发送邮件 // @Summary 发送邮件 // @Description 发送邮件 // @Tags 运单 // @Param data body dto.WaybillSendMailPdfReq true "data" // @Success 200 {object} response.Response{data=model.Waybill} "{"code": 200, "data": [...]}" // @Router /api/waybill/send-mail [post] // @Security Bearer func (e WaybillController) SendMail(c *gin.Context) { s := service.Waybill{} companySvc := service.Company{} req := dto.WaybillSendMailPdfReq{} err := e.MakeContext(c). MakeOrm(). Bind(&req, binding.JSON, nil). MakeService(&s.Service). MakeService(&companySvc.Service). Errors if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } var waybill model.Waybill err = s.GetByWaybillNo(&dto.WaybillGetByWaybillPdfReq{WaybillNo: req.WaybillNo, HumidityShow: req.HumidityShow}, &waybill, nil) if err != nil { e.Error(500, err, err.Error()) return } var company model.SysDept err = companySvc.Get(&dto.CompanyGetReq{Id: waybill.DeptId}, &company) if err != nil { e.Error(500, err, err.Error()) return } _, filePath, err := PDF(s, waybill, company, req.WaybillTaskIds, req.HumidityShow) defer func() { os.Remove(filePath) }() em := email.NewEmail() em.From = "冷链物流运输 " em.To = req.To em.Subject = fmt.Sprintf("【冷链物流运输】运单%s温湿度记录", waybill.WaybillNo) em.Text = []byte(fmt.Sprintf("运单%s温湿度记录", waybill.WaybillNo)) // 主要就是在这个位置添加了附件,注意:这里AttachFile是Email结构体的方法而不是字段,所以不是用等于而是括号 em.AttachFile(filePath) err = em.Send("smtp.163.com:25", smtp.PlainAuth("", "bzdcold@163.com", "ZIZXBCDKVTMPJMVX", "smtp.163.com")) if err != nil { e.Logger.Error(err) e.Error(500, err, err.Error()) return } e.OK(nil, "发送成功") } // 获取温度图片 func DeviceDataTemperatureJPG(startTime, endTime string, waybillPDF []service.WaybillPDF) (string, error) { if len(waybillPDF) == 0 { return "", errors.New("暂无数据可生成图片") } deviceSensorList := []nats_server.DeviceSensor_R{} dataList := []nats_server.DeviceData_R{} deviceDataPdfList := []service.DeviceDataPdf{} for _, w := range waybillPDF { deviceSensorList = append(deviceSensorList, w.DeviceSensorList...) dataList = append(dataList, w.Data...) deviceDataPdfList = append(deviceDataPdfList, w.DeviceDataPdf...) } TemperatureMin := deviceSensorList[0].T_DeviceSensorParameter.T_Tlower TemperatureMax := deviceSensorList[0].T_DeviceSensorParameter.T_Tupper var ymin, ymax float32 for i, r := range dataList { if i == 0 { ymin = r.T_t ymax = r.T_t } if ymin > r.T_t { ymin = r.T_t } if ymax < r.T_t { ymax = r.T_t } } sort.Slice(deviceDataPdfList, func(i, j int) bool { return deviceDataPdfList[i].T_time < deviceDataPdfList[j].T_time }) series := make([]chart.Series, 0) // 创建温度线 xValues1 := make([]time.Time, len(deviceDataPdfList)) xValues2 := make([]time.Time, 0) yValues1 := make([]float64, len(deviceDataPdfList)) yValues2 := make([]float64, len(deviceDataPdfList)) for i := 0; i < len(deviceDataPdfList); i++ { t, _ := lib.TimeStrToTime(deviceDataPdfList[i].T_time) xValues1[i] = t if deviceDataPdfList[i].T_id1 != nil { yValues1[i] = float64(*deviceDataPdfList[i].T_id1) } if deviceDataPdfList[i].T_id2 != nil { xValues2 = append(xValues2, t) yValues2[i] = float64(*deviceDataPdfList[i].T_id2) } } series = append(series, chart.TimeSeries{ Name: "T1", XValues: xValues1, YValues: yValues1, }) series = append(series, chart.TimeSeries{ Name: "T2", XValues: xValues2, YValues: yValues2, }) if ymax < TemperatureMax { ymax = TemperatureMax } if ymin > 0 { ymin = 0 } if ymin > TemperatureMin { ymin = TemperatureMin } st, _ := lib.TimeStrToTime(startTime) et, _ := lib.TimeStrToTime(endTime) series = append(series, chart.TimeSeries{ Style: chart.Style{ StrokeColor: drawing.ColorRed, StrokeDashArray: []float64{5.0, 5.0}, }, XValues: []time.Time{st, et}, YValues: []float64{float64(TemperatureMin), float64(TemperatureMin)}, }) series = append(series, chart.TimeSeries{ Style: chart.Style{ StrokeColor: drawing.ColorRed, StrokeDashArray: []float64{5.0, 5.0}, }, XValues: []time.Time{st, et}, YValues: []float64{float64(TemperatureMax), float64(TemperatureMax)}, }) font := getZWFont() graph := chart.Chart{ Title: "温度记录", TitleStyle: chart.Style{ FontSize: 14, }, Background: chart.Style{ Padding: chart.Box{ Top: 20, }, }, Font: font, XAxis: chart.XAxis{ Name: "时间", ValueFormatter: chart.TimeValueFormatterWithFormat("2006-01-02 15:04"), }, YAxis: chart.YAxis{ Name: "温度", Range: &chart.ContinuousRange{ Min: float64(ymin), Max: float64(ymax + 2), }, }, Series: series, } //graph.Elements = []chart.Renderable{ // chart.Legend(&graph), //} filepath := "ofile/" + "temperature" + deviceSensorList[0].T_sn + ".jpg" f, _ := os.Create(filepath) defer f.Close() graph.Render(chart.PNG, f) return filepath, nil } // getZWFont 加载字体 func getZWFont() *truetype.Font { fontFile := "./static/fonts/MiSans-Medium.ttf" fontBytes, err := os.ReadFile(fontFile) if err != nil { log.Println(err) return nil } font, err := truetype.Parse(fontBytes) if err != nil { log.Println(err) return nil } return font } func addStampImage(pdf *gopdf.GoPdf, existSealImg bool, imgHSeal image.Image, x, y float64) { if !existSealImg { return } if x < 10 { x = 10 } if y < 20 { y = 20 } err := pdf.ImageFrom(imgHSeal, x, y, &gopdf.Rect{W: 123, H: 128.6}) if err != nil { log.Print(err.Error()) } }