package controller

import (
	"bufio"
	"cold-delivery/app/admin/model"
	"cold-delivery/app/admin/service"
	"cold-delivery/app/admin/service/dto"
	"cold-delivery/common/actions"
	"cold-delivery/common/lib"
	"cold-delivery/common/nats/nats_server"
	"errors"
	"fmt"
	"github.com/beego/beego/v2/core/logs"
	"github.com/gin-gonic/gin"
	"github.com/gin-gonic/gin/binding"
	"github.com/golang/freetype/truetype"
	"github.com/pborman/uuid"
	"github.com/signintech/gopdf"
	"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"
	"gonum.org/v1/plot"
	"gonum.org/v1/plot/plotter"
	"gonum.org/v1/plot/vg"
	"gonum.org/v1/plot/vg/draw"
	"image/color"
	"log"
	"math"
	"net/url"
	"os"
	"path"
	"sort"
	"sync"
	"time"
)

type WaybillController struct {
	api.Api
}

// GetPage 获取运单列表
// @Summary 获取运单列表
// @Description 获取运单列表
// @Tags 运单
// @Param waybillNo query string false "运单号"
// @Param orderNo query string false "订单号"
// @Param status query int false "状态"
// @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{}
	userSvc := service.SysUser{}
	req := dto.WaybillGetPageReq{}
	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.HasPost() {
		err = s.GetPage(&req, &list, &count, p)
	} else {
		err = s.GetUserPage(&req, &list, &count, p)
	}
	if err != nil {
		e.Error(500, err, err.Error())
		return
	}
	//for i, _ := range list {
	//	var ReCheckuser model.SysUser
	//	err = userSvc.GetUser(list[i].ReCheckId, &ReCheckuser)
	//	if err != nil {
	//		e.Error(500, err, err.Error())
	//		return
	//	}
	//	list[i].ReCheck.Id = list[i].ReCheckId
	//	list[i].ReCheck.NickName = ReCheckuser.NickName
	//	list[i].ReCheck.Phone = ReCheckuser.Phone
	//}
	for i, _ := range list {
		if list[i].ReCheckId != 0 {
			var ReCheckuser model.SysUser
			err = userSvc.GetUser(list[i].ReCheckId, &ReCheckuser)
			if err != nil {
				e.Logger.Error("获取复核人信息失败", "ReCheckId", list[i].ReCheckId, "err", err)
				continue
			}
			list[i].ReCheck.Id = list[i].ReCheckId
			list[i].ReCheck.NickName = ReCheckuser.NickName
			list[i].ReCheck.Phone = ReCheckuser.Phone
		}
	}
	e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
}

// Export 导出运单列表
// @Summary 导出运单列表
// @Description 导出运单列表
// @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/export [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.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", "J", 15)
	f.SetColWidth("Sheet1", "K", "K", 30)

	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.DeliveryName)
		f.SetCellValue("Sheet1", fmt.Sprintf("J%d", line), v.DeliveryPhone)
		f.SetCellValue("Sheet1", fmt.Sprintf("K%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 data body dto.WaybillStatsReq true "data"
// @Param date query string true "日期"
// @Param type query string true "类型 month-月 year-年"
// @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
// @Router /api/waybill/home [get]
// @Security Bearer
func (e WaybillController) Home(c *gin.Context) {
	s := service.Waybill{}
	userSvc := service.SysUser{}
	req := dto.WaybillStatsReq{}
	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
	}
	var res dto.WaybillStatsRes
	if userObj.HasPost() {
		res = s.GetBasicsStats(&req, p)
	} else {
		res = s.GetUserBasicsStats(&req, p, service.GetUserBasicsStatsScopes(p.UserId))
	}
	e.OK(res, "查询成功")
}

// UserStats 用户运单数量统计
// @Summary 首页统计
// @Description 首页统计
// @Tags 运单
// @Param data body dto.WaybillUserStatsReq true "data"
// @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
// @Router /api/waybill/user-stats [post]
// @Security Bearer
func (e WaybillController) UserStats(c *gin.Context) {
	s := service.Waybill{}
	userSvc := service.SysUser{}
	req := dto.WaybillUserStatsReq{}
	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, err.Error())
		return
	}
	var res []dto.WaybillUserStats
	if req.UserType == "delivery" {
		if userObj.HasPost() {
			res = s.GetDeliveryStats(&req, p)
		} else {
			req.UserIds = []int{p.UserId}
			res = s.GetDeliveryStats(&req, p)
		}
	}
	if req.UserType == "reCheck" {
		if userObj.HasPost() {
			res = s.GetReCheckStats(&req, p)
		} else {
			req.UserIds = []int{p.UserId}
			res = s.GetReCheckStats(&req, p)
		}
	}

	e.OK(res, "查询成功")
}

// GetAppletPage 获取运单列表
// @Summary 获取运单列表
// @Description 获取运单列表
// @Tags 运单
// @Param waybillNo query string false "运单号"
// @Param status query int false "状态"
// @Success 200 {object} response.Response{data=response.Page{list=[]model.Waybill}} "{"code": 200, "data": [...]}"
// @Router /api/waybill/applet [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 int false "状态"
// @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, "查询成功")
}

// GetByWaybillNo 通过id获取运单
// @Summary 通过id获取运单
// @Description 通过id获取运单
// @Tags 运单
// @Param waybillNo path string true "运单编号-必填"
// @Success 200 {object} response.Response{data=model.Waybill} "{"code": 200, "data": [...]}"
// @Router /api/waybill/no [get]
// @Security Bearer
func (e WaybillController) GetByWaybillNo(c *gin.Context) {
	s := service.Waybill{}
	req := dto.WaybillGetByWaybillPdfReq{}
	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
	}
	var object model.Waybill

	//数据权限检查
	err = s.GetByWaybillNo(&req, &object, nil)
	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(), "添加成功")
}

// UpdateStatus 修改运单状态
// @Summary 修改运单状态
// @Description 修改运单状态
// @Tags 运单
// @Accept  application/json
// @Product application/json
// @Param data body dto.WaybillUpdateStatusReq true "body"
// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
// @Router /api/waybill/update-status [put]
// @Security Bearer
func (e WaybillController) UpdateStatus(c *gin.Context) {
	s := service.Waybill{}
	req := dto.UpdateStatusReq{}
	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.UpdateStatus(&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(), "修改成功")
}

// Audit 审核订单
// @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/audit [put]
// @Security Bearer
func (e WaybillController) Audit(c *gin.Context) {
	s := service.Waybill{}
	req := dto.WaybillUpdateReqaudit{}
	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.Audit(&req, p)
	if err != nil {
		e.Error(500, err, err.Error())
		return
	}
	e.OK(req.GetId(), "审核成功")
}

// AdminAudit 管理员审核订单
// @Summary 管理员审核订单
// @Description 审核订单
// @Tags 运单
// @Accept  application/json
// @Product application/json
// @Param data body dto.WaybillAdmin true "body"
// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
// @Router /api/waybill/adminaudit [put]
// @Security Bearer
func (e WaybillController) AdminAudit(c *gin.Context) {
	s := service.Waybill{}
	req := dto.WaybillAdmin{}
	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)
	err, userObj := service.GetUserProfile(e.Orm, p.UserId)
	if err != nil {
		e.Error(500, err, "获取用户信息失败")
		return
	}
	if !userObj.HasPost() && userObj.Id != 1 {
		e.Error(500, err, err.Error())
		return
	}
	req.SetUpdateBy(user.GetUserId(c))
	err = s.AdminAudit(&req, p)
	if err != nil {
		e.Error(500, err, err.Error())
		return
	}
	e.OK(req.GetId(), "审核成功")
}

// Packing 待取药装箱
// @Summary 待取药装箱
// @Description 待取药装箱（分配保温箱、冰排、防伪标签）
// @Tags 运单
// @Accept  application/json
// @Product application/json
// @Param data body dto.WaybillPackingReq true "body"
// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
// @Router /api/waybill/packing [post]
// @Security Bearer
func (e WaybillController) Packing(c *gin.Context) {
	s := service.Waybill{}
	IceRaftSvc := service.IceRaft{}
	req := dto.WaybillPackingReq{}
	err := e.MakeContext(c).
		MakeOrm().
		Bind(&req).
		MakeService(&s.Service).
		MakeService(&IceRaftSvc.Service).
		Errors
	if err != nil {
		e.Logger.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	p := actions.GetPermissionFromContext(c)
	if len(req.WaybillIds) == 0 {
		e.Error(500, err, "运单ID不能为空")
		return
	}
	oldIceRaftCode := make([]string, 0)
	if req.CoolerBoxId != 0 {
		err = IceRaftSvc.GetPageByCoolerBoxId(req.CoolerBoxId, &oldIceRaftCode, p)
		if err != nil {
			e.Error(500, err, err.Error())
			return
		}
	}
	req.SetUpdateBy(user.GetUserId(c))
	req.OldIceRaftCode = oldIceRaftCode
	err = s.Packing(&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/delivery [put]
// @Security Bearer
func (e WaybillController) Delivery(c *gin.Context) {
	s := service.Waybill{}
	IceRaftSvc := service.IceRaft{}
	req := dto.WaybillDeliveryReq{}
	err := e.MakeContext(c).
		MakeOrm().
		Bind(&req).
		MakeService(&s.Service).
		MakeService(&IceRaftSvc.Service).
		Errors
	if err != nil {
		e.Logger.Error(err)
		e.Error(500, err, err.Error())
		return
	}
	p := actions.GetPermissionFromContext(c)
	if len(req.WaybillIds) == 0 {
		e.Error(500, err, "配送员不能为空")
		return
	}
	oldIceRaftCode := make([]string, 0)
	missingIceRaftCode := make([]string, 0)
	if req.CoolerBoxId != 0 {
		err = IceRaftSvc.GetPageByCoolerBoxId(req.CoolerBoxId, &oldIceRaftCode, p)
		if err != nil {
			e.Error(500, err, err.Error())
			return
		}
	}
	req.SetUpdateBy(user.GetUserId(c))
	req.OldIceRaftCode = oldIceRaftCode
	err = s.Delivery(&req, p)
	if err != nil {
		e.Error(500, err, err.Error())
		return
	}
	missingIceRaftCode = lib.FindStrListMissingData(oldIceRaftCode, req.IceRaftCode)
	if len(missingIceRaftCode) > 0 {
		c.JSON(200, map[string]interface{}{
			"requestId": uuid.NewUUID(),
			"code":      2000,
			"msg":       "派单成功",
			"status":    "success",
			"data":      missingIceRaftCode,
		})
		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(), "删除成功")
}

// Receipt 签收
// @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/receipt [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, "提交成功")
}

// CustomerReceipt 客户签收
// @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/customer/receipt [post]
// @Security Bearer
func (e WaybillController) CustomerReceipt(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)
	//req.WaybillNo = lib.AesDecryptCBC(req.WaybillNo, lib.AesKey)
	//数据权限检查
	err = s.Receipt(&req, p)
	if err != nil {
		e.Error(500, err, err.Error())
		return
	}
	e.OK(req.WaybillNo, "签收成功")
}

// CreateSole 生成唯一订单号
// @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/createsole [get]
// @Security Bearer
func (e WaybillController) CreateSole(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
	}
	sole, err := s.CreateSole()
	if err != nil {
		e.Error(500, err, err.Error())
		return
	}
	e.OK(sole, "生成成功")
}

// Turnarounds 订单转门店
// @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/turnarounds [put]
// @Security Bearer
func (e WaybillController) Turnarounds(c *gin.Context) {
	s := service.Waybill{}
	req := dto.WaybillTurnarounds{}
	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.WaybillTurnarounds(&req, p)
	if err != nil {
		e.Error(500, err, err.Error())
		return
	}
	e.OK(req, "转门店成功")
}

// SecondaryDistribution 二次分配订单
// @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/SecondaryDistribution [put]
// @Security Bearer
func (e WaybillController) SecondaryDistribution(c *gin.Context) {
	s := service.Waybill{}
	req := dto.WaybillAssignment{}
	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.SecondaryDistribution(&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 orderNo query string false "订单号"
// @Param status query int false "状态"
// @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 orderNo query string false "订单号"
// @Param status query int false "状态"
// @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.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", "I", 15)
	f.SetColWidth("Sheet1", "J", "J", 15)
	f.SetColWidth("Sheet1", "K", "K", 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.DeliveryName)
		f.SetCellValue("Sheet1", fmt.Sprintf("J%d", line), v.DeliveryPhone)
		f.SetCellValue("Sheet1", fmt.Sprintf("K%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))
	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
	}

	rows, _ := xlsx.GetRows("Sheet1")
	for indexRow, row := range rows {
		if indexRow == 0 {
			continue
		}
		if len(row) < 10 {
			for i := 0; i < 10-len(row); i++ {
				row = append(row, "")
			}
		}
		for i, colCell := range row {
			fmt.Println(i, ":", colCell)
		}
		//quantity, _ := strconv.Atoi(row[8])
		obj := dto.WaybillInsertReq{
			Status:                  1,
			ConsigneeAddressName:    row[0],
			ConsigneeAddressPhone:   row[1],
			ConsigneeAddressDetails: row[2],
			TamperProofLabel:        row[3], // 防拆标签
			Remark:                  row[4],
			ReCheckId:               p.UserId,
			DeliveryId:              p.UserId,
		}
		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
// @Success 200 {string} string	"{"code": 200, "message": "添加成功"}"
// @Success 200 {string} string	"{"code": -1, "message": "添加失败"}"
// @Router /api/waybill/export-template [get]
// @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 导出温度记录
// @Summary  导出温度记录
// @Description  导出温度记录
// @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 [get]
// @Security Bearer
func (e WaybillController) TemperaturePDF(c *gin.Context) {
	s := service.Waybill{}
	req := dto.WaybillGetByWaybillPdfReq{}
	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
	}
	var waybill model.Waybill
	//p := actions.GetPermissionFromContext(c)
	//err = s.GetByWaybillNo(&req, &waybill, p)
	err = s.GetByWaybillNo(&req, &waybill, nil)
	if err != nil {
		e.Error(500, err, err.Error())
		return
	}
	DeviceSensor_data, waybillPDF, err := s.GetAllData(&dto.WaybillGetByWaybillNoReq{WaybillNo: req.WaybillNo})
	// 最高温度、最低温度、最高湿度、最低湿度
	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

	var lastTime string
	var isFirst, isSecond = true, false
	var first_column, second_column []nats_server.DeviceData_R

	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

		}
		var sn string
		for _, w := range waybillPDF {
			for _, data := range w.Data {
				if len(lastTime) > 0 {
					if lastTime != data.T_time && isFirst == true {
						isFirst = false
						isSecond = true
					} else if lastTime != data.T_time && isSecond == true {
						isFirst = true
						isSecond = false
					}
				}
				if len(sn) > 0 && sn != data.T_sn && len(first_column)%2 == 1 {
					isFirst, isSecond = isSecond, isFirst
				}
				if isFirst {
					first_column = append(first_column, data)
					lastTime = data.T_time
					sn = data.T_sn
				}
				if isSecond {
					second_column = append(second_column, data)
					lastTime = data.T_time
					sn = data.T_sn
				}
			}
		}

		// 平均温度
		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()
	title := "运单" + req.WaybillNo + "温度记录"
	if req.HumidityShow {
		title = "运单" + req.WaybillNo + "温湿度记录"
	}
	var y float64 = 40
	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)
	//pdf.SetFont("wts", "", 10)
	//y += 20
	//pdf.SetXY(10, y)
	//pdf.Text(fmt.Sprintf("主机名称：%s", device.T_devName))
	//pdf.SetXY(300, y)
	//pdf.Text(fmt.Sprintf("主机编号：%s", device.T_sn))

	y += 25
	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 req.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 req.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(waybill.Remark) > 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 += 15
	//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 = DeviceDataTemperatureJPG2(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 {
		// 图片结束直接分页
		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 = 10
	var w float64 = 112
	lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
	x = x + w
	w = 101
	lib.RectFillColor(pdf, "名称", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)

	if req.HumidityShow {
		x = x + w
		w = 37
		lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
		x = x + w
		w = 37
		lib.RectFillColor(pdf, "湿度%", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
	} else {
		x = x + w
		w = 37 * 2
		lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
	}
	x = x + w
	w = 112
	lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
	x = x + w
	w = 101
	lib.RectFillColor(pdf, "名称", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)

	if req.HumidityShow {
		x = x + w
		w = 37
		lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
		x = x + w
		w = 37
		lib.RectFillColor(pdf, "湿度%", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
	} else {
		x = x + w
		w = 37 * 2
		lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
	}
	y += 20
	var textH float64 = 25 // if text height is 25px.
	for i, v := range first_column {
		pdf.SetNewY(y, textH)
		y = pdf.GetY()
		x, w = 10, 112

		lib.RectFillColor(pdf, v.T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
		x = x + w
		w = 101
		lib.RectFillColor(pdf, v.T_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)

		// 显示温湿度
		if req.HumidityShow {
			x = x + w
			w = 37
			lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", v.T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
			x = x + w
			w = 37
			lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", v.T_rh), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
		} else {
			x = x + w
			w = 37 * 2
			lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", v.T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
		}
		if i < len(second_column) {
			x = x + w
			w = 112
			lib.RectFillColor(pdf, second_column[i].T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
			x = x + w
			w = 101
			lib.RectFillColor(pdf, second_column[i].T_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)

			if req.HumidityShow {
				x = x + w
				w = 37
				lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
				x = x + w
				w = 37
				lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_rh), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
			} else {
				x = x + w
				w = 37 * 2
				lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
			}
		}

		y += 20
	}
	if len(second_column) > len(first_column) {
		for i := len(first_column); i < len(second_column); i++ {
			pdf.SetNewY(y, textH)
			y = pdf.GetY()
			x, w = 297, 112
			lib.RectFillColor(pdf, second_column[i].T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
			x = x + w
			w = 101
			lib.RectFillColor(pdf, second_column[i].T_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)

			if req.HumidityShow {
				x = x + w
				w = 37
				lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
				x = x + w
				w = 37
				lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_rh), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
			} else {
				x = x + w
				w = 37 * 2
				lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)

			}
			y += 20
		}
	}
	filename := "运单" + req.WaybillNo + "温湿度记录" + time.Now().Format("20060102150405") + ".pdf"
	filePath := "ofile/" + filename

	err = pdf.WritePdf(filePath)
	if err != nil {
		return
	}
	defer func() {
		//os.Remove(tempFilepath)
		//os.Remove(humidityFilepath)
		os.Remove(filePath)
	}()

	c.Header("Content-Disposition", "attachment; filename="+url.PathEscape(filename))
	c.Header("Content-Transfer-Encoding", "binary")
	c.File(filePath)

}

// 获取温度图片
func DeviceDataTemperatureJPG(startTime, endTime string, waybillPDF []service.WaybillPDF) (string, error) {

	if len(waybillPDF) == 0 {
		return "", errors.New("暂无数据可生成图片")
	}

	// 创建一个新的绘图
	p := plot.New()

	// 设置绘图标题和标签
	p.Title.Text = "temperature"
	//p.Legend.ThumbnailWidth = 20

	deviceSensorList := []nats_server.DeviceSensor_R{}
	dataList := []nats_server.DeviceData_R{}

	for _, w := range waybillPDF {
		deviceSensorList = append(deviceSensorList, w.DeviceSensorList...)
		dataList = append(dataList, w.Data...)
	}

	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
		}
	}

	var chData = make(chan int, 10)
	var jobGroup sync.WaitGroup
	// 创建温度线
	for i := 0; i < len(deviceSensorList); i++ {
		chData <- 1
		jobGroup.Add(1)
		go func(index int) {
			defer func() {
				<-chData        // 完成时chan取出1个
				jobGroup.Done() // 完成时将等待组值减1
			}()
			sn, id := deviceSensorList[index].T_sn, deviceSensorList[index].T_id
			r_maps := []nats_server.DeviceData_R{}
			for _, data := range dataList {
				if data.T_sn == sn && data.T_id == id {
					r_maps = append(r_maps, data)
				}
			}

			fmt.Println(r_maps)
			if len(r_maps) == 0 {
				return
			}
			sort.Slice(r_maps, func(i, j int) bool {
				return r_maps[i].T_time < r_maps[j].T_time
			})

			pts := make(plotter.XYs, len(r_maps))
			for j, d := range r_maps {
				t, _ := lib.TimeStrToTime(d.T_time)
				pts[j].X = float64(t.Unix())
				pts[j].Y = float64(d.T_t)
			}

			line, err := plotter.NewLine(pts)
			if err != nil {
				return
			}
			line.Color = randomColor(index)
			p.Add(line)
		}(i)
	}
	jobGroup.Wait()

	st, _ := lib.TimeStrToTime(startTime)
	et, _ := lib.TimeStrToTime(endTime)
	xmin, xmax := float64(st.Unix()), float64(et.Unix())
	// 添加最高，最低标准线 用红色虚线标识
	p.Add(horizontalLine(xmin, xmax, float64(TemperatureMin)))
	p.Add(horizontalLine(xmin, xmax, float64(TemperatureMax)))

	if ymax < TemperatureMax {
		ymax = TemperatureMax
	}
	if ymin > 0 {
		ymin = 0
	}

	p.Y.Min, p.Y.Max = float64(ymin), float64(ymax)

	p.X.Min, p.X.Max = xmin, xmax
	p.Y.Tick.Marker = commaTicks{}
	p.X.Tick.Marker = timeTicks{}
	p.X.Tick.Label.Rotation = math.Pi / 5
	p.X.Tick.Label.YAlign = draw.YCenter
	p.X.Tick.Label.XAlign = draw.XRight

	filepath := "ofile/" + "temperature" + deviceSensorList[0].T_sn + ".jpg"
	// 保存文件
	if err := p.Save(10*vg.Inch, 4*vg.Inch, filepath); err != nil {

		logs.Error(lib.FuncName(), "生成图片失败", err)
		return "", err
	}

	return filepath, nil

}
func DeviceDataTemperatureJPG2(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{}

	for _, w := range waybillPDF {
		deviceSensorList = append(deviceSensorList, w.DeviceSensorList...)
		dataList = append(dataList, w.Data...)
	}
	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
		}
	}
	series := make([]chart.Series, 0)
	var chData = make(chan int, 10)
	var jobGroup sync.WaitGroup
	// 创建温度线
	for i := 0; i < len(deviceSensorList); i++ {
		chData <- 1
		jobGroup.Add(1)
		go func(index int) {
			defer func() {
				<-chData        // 完成时chan取出1个
				jobGroup.Done() // 完成时将等待组值减1
			}()
			sn, id := deviceSensorList[index].T_sn, deviceSensorList[index].T_id
			r_maps := []nats_server.DeviceData_R{}
			for _, data := range dataList {
				if data.T_sn == sn && data.T_id == id {
					r_maps = append(r_maps, data)
				}
			}

			fmt.Println(r_maps)
			if len(r_maps) == 0 {
				return
			}
			sort.Slice(r_maps, func(i, j int) bool {
				return r_maps[i].T_time < r_maps[j].T_time
			})

			xValues := make([]time.Time, len(r_maps))
			yValues := make([]float64, len(r_maps))

			for j := 0; j < len(r_maps); j++ {
				t, _ := lib.TimeStrToTime(r_maps[j].T_time)
				xValues[j] = t
				yValues[j] = float64(r_maps[j].T_t)
			}
			series = append(series, chart.TimeSeries{
				Name:    fmt.Sprintf("%s-%d", sn, id),
				XValues: xValues,
				YValues: yValues,
			})
		}(i)
	}
	jobGroup.Wait()
	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: 15,
		},
		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

}

// 获取湿度图片
func DeviceDataHumidityJPG(startTime, endTime string, waybillPDF []service.WaybillPDF) (string, error) {

	if len(waybillPDF) == 0 {
		return "", errors.New("暂无数据可生成图片")
	}

	// 创建一个新的绘图
	p := plot.New()

	// 设置绘图标题和标签
	p.Title.Text = "humidity"

	deviceSensorList := []nats_server.DeviceSensor_R{}
	dataList := []nats_server.DeviceData_R{}

	for _, w := range waybillPDF {
		deviceSensorList = append(deviceSensorList, w.DeviceSensorList...)
		dataList = append(dataList, w.Data...)
	}

	humidityMin := deviceSensorList[0].T_DeviceSensorParameter.T_RHlower
	humidityMax := deviceSensorList[0].T_DeviceSensorParameter.T_RHupper

	var ymin, ymax float32
	for i, r := range dataList {
		if i == 0 {
			ymin = r.T_rh
			ymax = r.T_rh
		}
		if ymin > r.T_rh {
			ymin = r.T_rh
		}
		if ymax < r.T_rh {
			ymax = r.T_rh
		}
	}

	var chData = make(chan int, 10)
	var jobGroup sync.WaitGroup
	// 创建温度线
	for i := 0; i < len(deviceSensorList); i++ {
		chData <- 1
		jobGroup.Add(1)
		go func(index int) {
			defer func() {
				<-chData        // 完成时chan取出1个
				jobGroup.Done() // 完成时将等待组值减1
			}()
			sn, id := deviceSensorList[index].T_sn, deviceSensorList[index].T_id
			r_maps := []nats_server.DeviceData_R{}
			for _, data := range dataList {
				if data.T_sn == sn && data.T_id == id {
					r_maps = append(r_maps, data)
				}
			}
			if len(r_maps) == 0 {
				return
			}
			sort.Slice(r_maps, func(i, j int) bool {
				return r_maps[i].T_time < r_maps[j].T_time
			})

			pts := make(plotter.XYs, len(r_maps))
			for j, d := range r_maps {
				t, _ := lib.TimeStrToTime(d.T_time)
				pts[j].X = float64(t.Unix())
				pts[j].Y = float64(d.T_rh)
			}

			line, err := plotter.NewLine(pts)
			if err != nil {
				return
			}
			line.Color = randomColor(index)
			p.Add(line)
		}(i)
	}
	jobGroup.Wait()

	st, _ := lib.TimeStrToTime(startTime)
	et, _ := lib.TimeStrToTime(endTime)
	xmin, xmax := float64(st.Unix()), float64(et.Unix())
	// 添加最高，最低标准线 用红色虚线标识
	p.Add(horizontalLine(xmin, xmax, float64(humidityMin)))
	p.Add(horizontalLine(xmin, xmax, float64(humidityMax)))

	if ymax < humidityMax {
		ymax = humidityMax
	}
	if ymin > 0 {
		ymin = 0
	}

	p.Y.Min, p.Y.Max = float64(ymin), float64(ymax)

	p.X.Min, p.X.Max = xmin, xmax
	p.Y.Tick.Marker = commaTicks{}
	//p.X.Tick.Marker = plot.TimeTicks{Format: "2006-01-02 15:04:05"}
	p.X.Tick.Marker = timeTicks{}
	p.X.Tick.Label.Rotation = math.Pi / 5
	p.X.Tick.Label.YAlign = draw.YCenter
	p.X.Tick.Label.XAlign = draw.XRight

	filepath := "ofile/" + "humidity" + deviceSensorList[0].T_sn + ".jpg"
	// 保存文件
	if err := p.Save(10*vg.Inch, 4*vg.Inch, filepath); err != nil {

		logs.Error(lib.FuncName(), "生成图片失败", err)
		return "", err
	}

	return filepath, nil

}
func DeviceDataHumidityJPG2(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{}

	for _, w := range waybillPDF {
		deviceSensorList = append(deviceSensorList, w.DeviceSensorList...)
		dataList = append(dataList, w.Data...)
	}
	humidityMin := deviceSensorList[0].T_DeviceSensorParameter.T_RHlower
	humidityMax := deviceSensorList[0].T_DeviceSensorParameter.T_RHupper

	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
		}
	}
	series := make([]chart.Series, 0)
	var chData = make(chan int, 10)
	var jobGroup sync.WaitGroup
	// 创建温度线
	for i := 0; i < len(deviceSensorList); i++ {
		chData <- 1
		jobGroup.Add(1)
		go func(index int) {
			defer func() {
				<-chData        // 完成时chan取出1个
				jobGroup.Done() // 完成时将等待组值减1
			}()
			sn, id := deviceSensorList[index].T_sn, deviceSensorList[index].T_id
			r_maps := []nats_server.DeviceData_R{}
			for _, data := range dataList {
				if data.T_sn == sn && data.T_id == id {
					r_maps = append(r_maps, data)
				}
			}

			if len(r_maps) == 0 {
				return
			}
			sort.Slice(r_maps, func(i, j int) bool {
				return r_maps[i].T_time < r_maps[j].T_time
			})

			xValues := make([]time.Time, len(r_maps))
			yValues := make([]float64, len(r_maps))

			for j := 0; j < len(r_maps); j++ {
				t, _ := lib.TimeStrToTime(r_maps[j].T_time)
				xValues[j] = t
				yValues[j] = float64(r_maps[j].T_rh)
			}
			series = append(series, chart.TimeSeries{
				Name:    fmt.Sprintf("%s-%d", sn, id),
				XValues: xValues,
				YValues: yValues,
			})
		}(i)
	}
	jobGroup.Wait()
	if ymax < humidityMax {
		ymax = humidityMax
	}
	if ymin > 0 {
		ymin = 0
	}

	if ymin > humidityMin {
		ymin = humidityMin
	}

	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(humidityMin), float64(humidityMin)},
	})
	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(humidityMax), float64(humidityMax)},
	})
	font := getZWFont()
	graph := chart.Chart{
		Title: "湿度记录",
		TitleStyle: chart.Style{
			FontSize: 15,
		},
		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/" + "humidity" + deviceSensorList[0].T_sn + ".jpg"
	f, _ := os.Create(filepath)
	defer f.Close()
	graph.Render(chart.PNG, f)

	return filepath, nil

}

func horizontalLine(xmin, xmax, y float64) *plotter.Line {
	pts := make(plotter.XYs, 2)
	pts[0].X = xmin
	pts[0].Y = y
	pts[1].X = xmax
	pts[1].Y = y
	line, err := plotter.NewLine(pts)
	if err != nil {
		panic(err)
	}
	line.LineStyle.Dashes = []vg.Length{vg.Points(8), vg.Points(5), vg.Points(1), vg.Points(5)}
	line.Color = color.RGBA{R: 255, A: 255}
	return line
}

type timeTicks struct{}

func (timeTicks) Ticks(min, max float64) []plot.Tick {
	tks := plot.TimeTicks{}.Ticks(min, max)
	for i, t := range tks {
		//if t.Label == "" { // Skip minor ticks, they are fine.
		//	continue
		//}
		tks[i].Label = time.Unix(int64(t.Value), 0).Format("2006-01-02 15:04:05")
	}

	return tks
}

type commaTicks struct{}

// Ticks computes the default tick marks, but inserts commas
// into the labels for the major tick marks.
func (commaTicks) Ticks(min, max float64) []plot.Tick {
	tks := plot.DefaultTicks{}.Ticks(min, max)
	for i, t := range tks {
		//if t.Label == "" { // Skip minor ticks, they are fine.
		//	continue
		//}
		tks[i].Label = fmt.Sprintf("%.0f", t.Value)
	}

	return tks
}

// 生成随机颜色的辅助函数
func randomColor(i int) color.RGBA {
	var colors []color.RGBA
	colors = append(colors,
		color.RGBA{R: 52, G: 152, B: 219, A: 255},
		color.RGBA{R: 230, G: 126, B: 34, A: 255},
		color.RGBA{R: 142, G: 68, B: 173, A: 255},
		color.RGBA{R: 211, G: 84, B: 0, A: 255},
		color.RGBA{R: 231, G: 76, B: 60, A: 255},
		color.RGBA{R: 26, G: 188, B: 156, A: 255},
		color.RGBA{R: 243, G: 156, B: 18, A: 255},
		color.RGBA{R: 22, G: 160, B: 133, A: 255},
		color.RGBA{R: 46, G: 204, B: 113, A: 255},
		color.RGBA{R: 39, G: 174, B: 96, A: 255},
		color.RGBA{R: 41, G: 128, B: 185, A: 255},
		color.RGBA{R: 155, G: 89, B: 182, A: 255},
		color.RGBA{R: 192, G: 57, B: 43, A: 255},
		color.RGBA{R: 241, G: 196, B: 15, A: 255},
	)

	return colors[i%len(colors)]
}
func randomColor2(i int) drawing.Color {
	var colors []drawing.Color
	colors = append(colors,
		drawing.Color{R: 52, G: 152, B: 219, A: 255},
		drawing.Color{R: 230, G: 126, B: 34, A: 255},
		drawing.Color{R: 142, G: 68, B: 173, A: 255},
		drawing.Color{R: 211, G: 84, B: 0, A: 255},
		drawing.Color{R: 231, G: 76, B: 60, A: 255},
		drawing.Color{R: 26, G: 188, B: 156, A: 255},
		drawing.Color{R: 243, G: 156, B: 18, A: 255},
		drawing.Color{R: 22, G: 160, B: 133, A: 255},
		drawing.Color{R: 46, G: 204, B: 113, A: 255},
		drawing.Color{R: 39, G: 174, B: 96, A: 255},
		drawing.Color{R: 41, G: 128, B: 185, A: 255},
		drawing.Color{R: 155, G: 89, B: 182, A: 255},
		drawing.Color{R: 192, G: 57, B: 43, A: 255},
		drawing.Color{R: 241, G: 196, B: 15, A: 255},
	)
	return colors[i%len(colors)]
}

// 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
}
