Browse Source

add:下载温湿度pdf

zoie 3 months ago
parent
commit
b95733ae00

+ 26 - 1
Nats/Nats.go

@@ -195,7 +195,7 @@ func NatsInit() {
 			_ = lib.Nats.Publish(m.Reply, b)
 			return
 		}
-		List, _ := Device.Read_DeviceClassList_OrderList(task.T_class, "", "", 0, 9999)
+		List, _ := Device.Read_DeviceClassList_OrderList(task.T_class, "", "", "", 0, 9999)
 
 		t_R.Code = 200
 		t_R.Msg = "ok"
@@ -424,4 +424,29 @@ func NatsInit() {
 
 	})
 
+	_, _ = lib.Nats.QueueSubscribe("ColdVerify_Server_Del_TaskData_ByT_BindDeviceDataTime", "Del_TaskData_ByT_BindDeviceDataTime", func(m *nats.Msg) {
+
+		var t_R lib.JSONS
+		task, is := Task.Read_Task(string(m.Data))
+		if !is {
+			logs.Error("Mats", lib.FuncName())
+			t_R.Code = 202
+			t_R.Msg = "查询失败"
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+		dcList, _ := Device.Read_DeviceClassList_OrderList(task.T_class, "", "", "", 0, 9999)
+		for _, v := range dcList {
+			if !lib.IsNumeric(v.T_id) {
+				// 删除任务表指定时间数据
+				Task.Del_TaskData_t_idByT_BindDeviceDataTime(task.T_task_id, v.T_id, task.T_BindDeviceDataStartTime, task.T_BindDeviceDataEndTime)
+			} else {
+				Task.Del_TaskData_t_idByT_BindDeviceDataTime(task.T_task_id, v.T_id, task.T_VerifyDeviceDataStartTime, task.T_VerifyDeviceDataEndTime)
+
+			}
+		}
+
+	})
+
 }

+ 115 - 0
Nats/NatsServer/NatsQiniu.go

@@ -0,0 +1,115 @@
+package NatsServer
+
+import (
+	"ColdVerify_server/lib"
+	"context"
+	"fmt"
+	"github.com/beego/beego/v2/core/logs"
+	"github.com/qiniu/go-sdk/v7/auth/qbox"
+	"github.com/qiniu/go-sdk/v7/storage"
+	"github.com/vmihailenco/msgpack/v5"
+	"strings"
+	"time"
+)
+
+func Qiniu_UploadToken(T_suffix string, T_MimeLimit string) (string, bool) {
+	type Qiniu_UploadToken struct {
+		T_suffix    string
+		T_MimeLimit string
+	}
+
+	b, err := msgpack.Marshal(&Qiniu_UploadToken{
+		T_suffix:    T_suffix,
+		T_MimeLimit: T_MimeLimit,
+	})
+	if err != nil {
+		panic(err)
+	}
+
+	// 请求-响应, 向 test3 发布一个 `help me` 请求数据,设置超时间3秒,如果有多个响应,只接收第一个收到的消息
+	msg, err := lib.Nats.Request("Qiniu_UploadToken", b, 3*time.Second)
+	if err != nil {
+		fmt.Println(err)
+	} else {
+		fmt.Printf("Qiniu_UploadToken : %s\n", string(msg.Data))
+		return string(msg.Data), true
+	}
+
+	return string(msg.Data), false
+}
+
+//func Qiniu_UploadFile(localFile string, name string) (string, bool) {
+//	logs.Info("Nats =>", lib.FuncName(), localFile, name)
+//	type Qiniu_UploadFile struct {
+//		File string
+//		Name string
+//	}
+//	RR := Qiniu_UploadFile{File: localFile, Name: name}
+//	println(":", RR.File)
+//	b, err := msgpack.Marshal(&RR)
+//	if err != nil {
+//		panic(err)
+//	}
+//
+//	// 请求-响应, 向 test3 发布一个 `help me` 请求数据,设置超时间3秒,如果有多个响应,只接收第一个收到的消息
+//	msg, err := lib.Nats.Request("Qiniu_UploadFile", b, 3*time.Second)
+//	if err != nil {
+//		fmt.Println(err)
+//	} else {
+//		fmt.Printf("Qiniu_UploadFile : %s\n", string(msg.Data))
+//		return string(msg.Data), true
+//	}
+//
+//	return string(msg.Data), false
+//}
+
+func Qiniu_UploadFile(localFile string, name string) (string, bool) {
+	logs.Info("Qiniu_UploadFile =>", localFile, name)
+
+	// 获取 七牛云的 配置信息
+	msg, err := lib.Nats.Request("Qiniu_Token", []byte(""), 3*time.Second)
+	if err != nil {
+		return string(msg.Data), false
+	}
+	fmt.Printf("Qiniu_Token : %s\n", string(msg.Data))
+	Qiniu_cs := strings.Split(string(msg.Data), "|")
+	Qiniu_AccessKey := Qiniu_cs[0]
+	Qiniu_SecretKey := Qiniu_cs[1]
+	Qiniu_BUCKET := Qiniu_cs[2]
+	Qiniu_Url := Qiniu_cs[3]
+
+	// 开始上传 七牛云
+	Qiniu := qbox.NewMac(Qiniu_AccessKey, Qiniu_SecretKey)
+	// 自定义返回值结构体
+	type MyPutRet struct {
+		Key    string
+		Hash   string
+		Fsize  int
+		Bucket string
+		Name   string
+	}
+	//key := "your file save key"
+	// 使用 returnBody 自定义回复格式
+	putPolicy := storage.PutPolicy{
+		Scope:      Qiniu_BUCKET,
+		ReturnBody: `{"key":"$(key)","hash":"$(etag)","fsize":$(fsize),"bucket":"$(bucket)","name":"$(x:name)"}`,
+	}
+	//mac := qbox.NewMac(conf.Qiniu_AccessKey, conf.Qiniu_SecretKey)
+	upToken := putPolicy.UploadToken(Qiniu)
+	cfg := storage.Config{}
+	formUploader := storage.NewFormUploader(&cfg)
+	ret := MyPutRet{}
+	putExtra := storage.PutExtra{
+		Params: map[string]string{
+			"x:name": "github logo",
+		},
+	}
+	err = formUploader.PutFile(context.Background(), &ret, upToken, name, localFile, &putExtra)
+	if err != nil {
+		logs.Info("七牛云", "上传文件失败 "+localFile, err.Error())
+		return "", false
+	}
+	fmt.Println(ret.Bucket, ret.Key, ret.Fsize, ret.Hash, ret.Name)
+	return Qiniu_Url + name, true
+
+}

+ 1 - 1
controllers/Device.go

@@ -195,7 +195,7 @@ func (c *DeviceController) Device_Class() {
 
 	var cnt int64
 	//DeviceList, cnt := Device.Read_DeviceClassList_List(T_class, T_sn, page, 9999)
-	DeviceList, cnt := Device.Read_DeviceClassList_OrderList(T_class, T_sn, "", page, 9999)
+	DeviceList, cnt := Device.Read_DeviceClassList_OrderList(T_class, T_sn, "", "", page, 9999)
 
 	for _, v := range DeviceList {
 		Device_r, _ := Device.Read_Device(v.T_sn)

+ 2 - 2
controllers/DeviceClass.go

@@ -227,7 +227,7 @@ func (c *DeviceClassController) List_List() {
 
 	var cnt int64
 	//List, cnt := Device.Read_DeviceClassList_List(T_class, T_sn, page, 9999)
-	List, cnt := Device.Read_DeviceClassList_OrderList(T_class, T_sn, T_remark, page, 9999)
+	List, cnt := Device.Read_DeviceClassList_OrderList(T_class, T_sn, "", T_remark, page, 9999)
 
 	page_size := math.Ceil(float64(cnt) / float64(page_z))
 	r_jsons.List = List
@@ -515,7 +515,7 @@ func (c *DeviceClassController) List_Copy() {
 		return
 	}
 
-	copyList, cnt := Device.Read_DeviceClassList_OrderList(copy_task.T_class, "", "", 0, 9999)
+	copyList, cnt := Device.Read_DeviceClassList_OrderList(copy_task.T_class, "", "", "", 0, 9999)
 	var successNum int // 成功数量
 	errList := []string{}
 	for _, v := range copyList {

+ 22 - 1
controllers/Task.go

@@ -317,6 +317,10 @@ func (c *TaskController) Up() {
 	T_pdf2 := c.GetString("T_pdf2")
 	T_doc3 := c.GetString("T_doc3")
 	T_pdf3 := c.GetString("T_pdf3")
+	T_VerifyDeviceDataStartTime := c.GetString("T_VerifyDeviceDataStartTime") // 验证设备数据开始时间
+	T_VerifyDeviceDataEndTime := c.GetString("T_VerifyDeviceDataEndTime")     // 验证设备数据开始时间
+	T_BindDeviceDataStartTime := c.GetString("T_BindDeviceDataStartTime")     // 绑定设备数据开始时间
+	T_BindDeviceDataEndTime := c.GetString("T_BindDeviceDataEndTime")         // 绑定设备数据结束时间
 
 	T_task_id := c.GetString("T_task_id")
 	r, is := Task.Read_Task(T_task_id)
@@ -401,6 +405,23 @@ func (c *TaskController) Up() {
 		clos = append(clos, "T_pdf3")
 	}
 
+	if len(T_VerifyDeviceDataStartTime) > 0 {
+		r.T_VerifyDeviceDataStartTime = T_VerifyDeviceDataStartTime
+		clos = append(clos, "T_VerifyDeviceDataStartTime")
+	}
+	if len(T_VerifyDeviceDataEndTime) > 0 {
+		r.T_VerifyDeviceDataEndTime = T_VerifyDeviceDataEndTime
+		clos = append(clos, "T_VerifyDeviceDataEndTime")
+	}
+	if len(T_BindDeviceDataStartTime) > 0 {
+		r.T_BindDeviceDataStartTime = T_BindDeviceDataStartTime
+		clos = append(clos, "T_BindDeviceDataStartTime")
+	}
+	if len(T_BindDeviceDataEndTime) > 0 {
+		r.T_BindDeviceDataEndTime = T_BindDeviceDataEndTime
+		clos = append(clos, "T_BindDeviceDataEndTime")
+	}
+
 	// .......
 	// "T_name", "T_Show", "T_VerifyTemplate_id", "T_deadline",
 	//		"T_collection", "T_reporting", "T_delivery",
@@ -547,7 +568,7 @@ func (c *TaskController) DeviceData_JPG() {
 		return
 	}
 
-	deviceClassList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, "", T_remark, 0, 9999)
+	deviceClassList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, "", "", T_remark, 0, 9999)
 	if !is {
 		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_class 错误!"}
 		c.ServeJSON()

+ 440 - 15
controllers/TaskData.go

@@ -9,6 +9,7 @@ import (
 	"ColdVerify_server/models/Device"
 	"ColdVerify_server/models/System"
 	"ColdVerify_server/models/Task"
+	"errors"
 	"fmt"
 	beego "github.com/beego/beego/v2/server/web"
 	"github.com/signintech/gopdf"
@@ -16,6 +17,7 @@ import (
 	"github.com/xuri/excelize/v2"
 	"math"
 	"os"
+	"sort"
 	"strconv"
 	"strings"
 	"time"
@@ -157,11 +159,7 @@ func (c *TaskDataController) TaskData_List() {
 	Time_start := c.GetString("Time_start")
 	Time_end := c.GetString("Time_end")
 	T_sn := c.GetString("T_sn")
-	T_id, err := c.GetInt("T_id")
-	if err != nil {
-		T_id = -1
-
-	}
+	T_id := c.GetString("T_id")
 
 	T_task_id := c.GetString("T_task_id")
 	Task_r, is := Task.Read_Task(T_task_id)
@@ -176,7 +174,7 @@ func (c *TaskDataController) TaskData_List() {
 		return
 	}
 	// 查询设备列表
-	dcList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, T_sn, "", page, 9999)
+	dcList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, T_sn, "", "", page, 9999)
 	// 保存布局编号和校准证书对应关系
 	var deviceCertificateMap = make(map[string]string) // t_id, T_Certificate_sn
 	for _, v := range dcList {
@@ -223,11 +221,7 @@ func (c *TaskDataController) UserTaskData_List() {
 	Time_start := c.GetString("Time_start")
 	Time_end := c.GetString("Time_end")
 	T_sn := c.GetString("T_sn")
-	T_id, err := c.GetInt("T_id")
-	if err != nil {
-		T_id = -1
-
-	}
+	T_id := c.GetString("T_id")
 
 	T_task_id := c.GetString("T_task_id")
 	Task_r, is := Task.Read_Task(T_task_id)
@@ -248,9 +242,15 @@ func (c *TaskDataController) UserTaskData_List() {
 		c.ServeJSON()
 		return
 	}
+	if len(Time_start) == 0 {
+		Time_start = Task_r.T_VerifyDeviceDataStartTime
+	}
+	if len(Time_end) == 0 {
+		Time_end = Task_r.T_VerifyDeviceDataEndTime
+	}
 
 	// 查询设备列表
-	dcList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, T_sn, "", page, 9999)
+	dcList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, T_sn, "", "", page, 9999)
 	// 保存布局编号和校准证书对应关系
 	var deviceCertificateMap = make(map[string]string) // t_id, T_Certificate_sn
 	for _, v := range dcList {
@@ -549,7 +549,7 @@ func (c *TaskDataController) Export_Data_Excel() {
 	T_sn_list := strings.Split(T_sn_str, ",")
 	DeviceSensor_data_list := []Task.TaskData_{}
 	for _, v := range T_sn_list {
-		DeviceSensor_data, _ := Task.Read_TaskData_ById_List(Task_r.T_task_id, v, -1, Time_start, Time_end, 1, 9999)
+		DeviceSensor_data, _ := Task.Read_TaskData_ById_List(Task_r.T_task_id, v, "", Time_start, Time_end, 1, 9999)
 		DeviceSensor_data_list = append(DeviceSensor_data_list, DeviceSensor_data...)
 	}
 
@@ -631,7 +631,7 @@ func (c *TaskDataController) Export_Data_PDF() {
 		c.ServeJSON()
 		return
 	}
-	dcList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, "", "", 0, 9999)
+	dcList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, "", "", "", 0, 9999)
 	// 查询设备列表
 	// 保存布局编号和校准证书对应关系
 	var deviceCertificateMap = make(map[string]string) // t_id, T_Certificate_sn
@@ -642,7 +642,7 @@ func (c *TaskDataController) Export_Data_PDF() {
 	T_sn_list := strings.Split(T_sn_str, ",")
 	DeviceSensor_data_list := []Task.TaskData_{}
 	for _, v := range T_sn_list {
-		DeviceSensor_data, _ := Task.Read_TaskData_ById_List(Task_r.T_task_id, v, -1, Time_start, Time_end, 1, 9999)
+		DeviceSensor_data, _ := Task.Read_TaskData_ById_List(Task_r.T_task_id, v, "", Time_start, Time_end, 1, 9999)
 		DeviceSensor_data_list = append(DeviceSensor_data_list, DeviceSensor_data...)
 		for i := 0; i < len(DeviceSensor_data_list); i++ {
 			DeviceSensor_data_list[i].T_Certificate_sn = deviceCertificateMap[DeviceSensor_data_list[i].T_id]
@@ -873,3 +873,428 @@ func (c *TaskDataController) Check() {
 	c.ServeJSON()
 	return
 }
+
+func (c *TaskDataController) TaskData_Temperature_Pdf() {
+	// 验证登录管理员 User_is, User_r
+	_, User_Admin_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+
+	// 验证登录用户 User_is, User_r
+	_, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+
+	if !User_Admin_is && !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Time_start := c.GetString("Time_start")
+	Time_end := c.GetString("Time_end")
+	T_sn := c.GetString("T_sn")
+	T_id := c.GetString("T_id")
+
+	T_task_id := c.GetString("T_task_id")
+
+	err := c.TaskData_Pdf(Time_start, Time_end, T_task_id, T_sn, T_id, Task.Temperature)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
+		c.ServeJSON()
+		return
+	}
+
+}
+func (c *TaskDataController) TaskData_Humidity_Pdf() {
+	// 验证登录管理员 User_is, User_r
+	_, User_Admin_is := Account.Verification_Admin(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+
+	// 验证登录用户 User_is, User_r
+	_, User_is := Account.Verification(c.Ctx.GetCookie("User_tokey"), c.GetString("User_tokey"))
+
+	if !User_Admin_is && !User_is {
+		c.Data["json"] = lib.JSONS{Code: 201, Msg: "请重新登录!"}
+		c.ServeJSON()
+		return
+	}
+
+	Time_start := c.GetString("Time_start")
+	Time_end := c.GetString("Time_end")
+	T_sn := c.GetString("T_sn")
+	T_id := c.GetString("T_id")
+
+	T_task_id := c.GetString("T_task_id")
+
+	err := c.TaskData_Pdf(Time_start, Time_end, T_task_id, T_sn, T_id, Task.Humidity)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
+		c.ServeJSON()
+		return
+	}
+
+}
+func (c *TaskDataController) TaskData_Pdf(Time_start, Time_end, T_task_id, T_sn, T_id, T_type string) (err error) {
+
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		return errors.New("T_task_id 错误!")
+	}
+	user, is := Account.Read_User(Task_r.T_uuid)
+	if !is {
+		return errors.New("Task uuid 错误!")
+	}
+
+	if Task_r.T_delivery_state == 2 {
+		return errors.New("数据采集中,请稍后!")
+	}
+
+	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", "", 15)
+	if err != nil {
+		return
+	}
+
+	pdf.SetGrayFill(0.5)
+
+	pdf.SetMargins(0, 20, 0, 20)
+	pdf.AddPage()
+	imgH, _ := gopdf.ImageHolderByPath("./static/logo.jpg")
+	err = pdf.ImageByHolder(imgH, 10, 10, &gopdf.Rect{W: 93, H: 32})
+	name := user.T_name
+
+	var y float64 = 40
+	textw, _ := pdf.MeasureTextWidth(name)
+	pdf.SetX((595 / 2) - (textw / 2))
+	pdf.SetY(y)
+	pdf.Text(name)
+
+	y += 20
+	T_type_name := ""
+	if T_type == Task.Temperature {
+		T_type_name = "温度"
+	}
+	if T_type == Task.Humidity {
+		T_type_name = "湿度"
+	}
+	title := Task_r.T_name + T_type_name + "验证数据"
+	textw, _ = pdf.MeasureTextWidth(title)
+	pdf.SetX((595 / 2) - (textw / 2))
+	pdf.SetY(y)
+	pdf.Text(title)
+
+	// 查询设备列表
+	//dcList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, T_sn, T_id, "", 0, 9999)
+	dcList := []Device.DeviceClassList{}
+	dataList, _ := Task.Read_TaskData_ById_List(Task_r.T_task_id, T_sn, T_id, Time_start, Time_end, 0, 9999)
+	dataListMap := make(map[string][]Task.TaskData_)
+	dcListMap := make(map[string]string)
+	for _, data := range dataList {
+		dataListMap[data.T_id] = append(dataListMap[data.T_id], data)
+		if _, ok := dcListMap[data.T_id]; !ok {
+			dcListMap[data.T_id] = data.T_sn
+		}
+	}
+	for id, sn := range dcListMap {
+		dcList = append(dcList, Device.DeviceClassList{T_id: id, T_sn: sn})
+	}
+	for id, list := range dataListMap {
+		sort.Slice(list, func(i, j int) bool {
+			return list[i].T_time < list[j].T_time
+		})
+		dataListMap[id] = list
+	}
+
+	dataMap := make(map[string]string)
+	timeMap := make(map[string]bool)
+	for _, data := range dataList {
+		k := fmt.Sprintf("%s,%s", data.T_time, data.T_id)
+		if T_type == Task.Temperature {
+			dataMap[k] = fmt.Sprintf("%.1f", data.T_t)
+		}
+		if T_type == Task.Humidity {
+			dataMap[k] = fmt.Sprintf("%.1f", data.T_rh)
+		}
+		if _, ok := timeMap[data.T_time]; !ok {
+			timeMap[data.T_time] = true
+		}
+	}
+
+	var timeList []string
+	for k, _ := range timeMap {
+		timeList = append(timeList, k)
+	}
+	sort.Slice(timeList, func(i, j int) bool {
+		return timeList[i] < timeList[j]
+	})
+	err = pdf.SetFont("wts", "", 12)
+	if err != nil {
+		return
+	}
+	if len(timeList) > 0 {
+		y += 20
+		timeStr := fmt.Sprintf("%s - %s", timeList[0], timeList[len(timeList)-1])
+		textw, _ = pdf.MeasureTextWidth(timeStr)
+		pdf.SetX((595 / 2) - (textw / 2))
+		pdf.SetY(y)
+		pdf.Text(timeStr)
+	}
+
+	y += 20
+	var x float64 = 10
+	var w float64 = 120
+
+	err = pdf.SetFont("wts", "", 10)
+	if err != nil {
+		return
+	}
+	idWidthMap := make(map[string]float64)
+	dcList1 := make([]Device.DeviceClassList, 0)
+	for _, list := range dcList {
+		idw, _ := pdf.MeasureTextWidth(list.T_id)
+		if !lib.IsNumeric(list.T_id) {
+			dcList1 = append(dcList1, list)
+		}
+		if idw > 20 {
+			idWidthMap[list.T_id] = idw + 12
+		} else {
+			idWidthMap[list.T_id] = 30.3
+		}
+	}
+	sort.Slice(dcList1, func(i, j int) bool {
+		return dcList1[i].T_id < dcList1[j].T_id
+	})
+	for _, dc := range dcList1 {
+
+		dataList2, _ := dataListMap[dc.T_id]
+
+		err = pdf.SetFont("wts", "", 15)
+		if err != nil {
+			return
+		}
+		var textH float64 = 20 // if text height is 25px.
+		y += 20
+		pdf.SetNewY(y, textH)
+		y = pdf.GetY()
+		if y > 790 {
+			pdf.AddPage()
+			y = 30
+		}
+
+		textw, _ = pdf.MeasureTextWidth(dc.T_id)
+		pdf.SetX((595 / 2) - (textw / 2))
+		pdf.SetY(y)
+		pdf.Text(dc.T_id)
+		y += 10
+
+		err = pdf.SetFont("wts", "", 10)
+		if err != nil {
+			return
+		}
+		pdf.SetNewY(y, textH)
+		y = pdf.GetY()
+		if y < 790 {
+			x = 10
+			for i := 0; i < 4; i++ {
+				w = 113.8
+				lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+				w = 30
+				lib.RectFillColor(pdf, T_type_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+			}
+			y += 20
+		} else {
+			pdf.AddPage()
+			y = 20
+			x = 10
+			for i := 0; i < 4; i++ {
+				w = 113.8
+				lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+				w = 30
+				lib.RectFillColor(pdf, T_type_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+			}
+			y += 20
+		}
+		for i := 0; i < len(dataList2); i++ {
+			temp := i % 4
+			x = 10 + 143.8*float64(temp)
+			w = 113.8
+
+			lib.RectFillColor(pdf, dataList2[i].T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			x += w
+			w = 30
+			if T_type == Task.Temperature {
+				lib.RectFillColor(pdf, fmt.Sprintf("%.1f", dataList2[i].T_t), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			}
+			if T_type == Task.Humidity {
+				lib.RectFillColor(pdf, fmt.Sprintf("%.1f", dataList2[i].T_rh), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			}
+			if temp == 3 {
+				y += 20
+				pdf.SetNewY(y, textH)
+				y = pdf.GetY()
+				// 每页添加表头
+				if y == 20 {
+					x = 10
+					for k := 0; k < 4; k++ {
+						w = 113.8
+						lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+						x += w
+						w = 30
+						lib.RectFillColor(pdf, T_type_name, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+						x += w
+					}
+					y += 20
+				}
+			}
+		}
+		y += 25
+
+	}
+
+	//chunks := chunkBy(dcList, 15)
+	y += 20
+	dcList2 := listSubtract(dcList, dcList1)
+	sort.Slice(dcList2, func(i, j int) bool {
+		return dcList2[i].T_id < dcList2[j].T_id
+	})
+	chunks := splitData(dcList2, 454.5, idWidthMap)
+	for _, list := range chunks {
+		var textH float64 = 20 // if text height is 25px.
+		pdf.SetNewY(y, textH)
+		y = pdf.GetY()
+		if y < 790 {
+			x = 10
+			w = 120.7
+			lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			x += w
+			w = 30.3
+			for _, v2 := range list {
+				w = idWidthMap[v2.T_id]
+				lib.RectFillColor(pdf, v2.T_id, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+			}
+			y += 20
+		} else {
+			pdf.AddPage()
+			y = 20
+		}
+
+		for _, t := range timeList {
+			x = 10
+			textH = 20 // if text height is 25px.
+			pdf.SetNewY(y, textH)
+			y = pdf.GetY()
+			if y == 20 {
+				w = 120.7
+				lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+				w = 30.3
+				for _, v2 := range list {
+					w = idWidthMap[v2.T_id]
+					lib.RectFillColor(pdf, v2.T_id, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x += w
+				}
+				y += 20
+				x = 10
+			}
+			w = 120.7
+			lib.RectFillColor(pdf, t, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			x += w
+			w = 30.3
+			for _, v := range list {
+				t_t := dataMap[fmt.Sprintf("%s,%s", t, v.T_id)]
+				w = idWidthMap[v.T_id]
+				lib.RectFillColor(pdf, t_t, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+			}
+			y += 20
+
+		}
+		y += 20
+	}
+	filename := time.Now().Format("20060102150405") + ".pdf"
+	timeStr := "ofile/" + T_type_name + filename
+
+	err = pdf.WritePdf(timeStr)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
+		c.ServeJSON()
+		return
+	}
+
+	// 上传 OSS
+	//url, is := NatsServer.Qiniu_UploadFile(lib.GetCurrentDirectory()+"/ofile/"+timeStr, timeStr)
+	//url, is := NatsServer.Qiniu_UploadFile("/Users/zoie/work/bzd_project/ColdVerify_server/"+timeStr, timeStr)
+	//if !is {
+	//	err = errors.New("oss!")
+	//	return
+	//}
+
+	defer func() {
+		//删除目录
+		os.Remove(timeStr)
+	}()
+
+	c.Ctx.Output.Download(timeStr)
+	//c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: url}
+	//c.ServeJSON()
+	//return
+	return nil
+
+}
+
+func listSubtract(sliceA, sliceB []Device.DeviceClassList) []Device.DeviceClassList {
+	// 创建一个集合用于存储 sliceB 的元素
+	elementsToRemove := make(map[string]Device.DeviceClassList)
+	for _, item := range sliceB {
+		elementsToRemove[item.T_id] = item
+	}
+
+	// 构建新切片,包含 sliceA 中不在 elementsToRemove 中的元素
+	var result []Device.DeviceClassList
+	for _, item := range sliceA {
+		if _, found := elementsToRemove[item.T_id]; !found {
+			result = append(result, item)
+		}
+	}
+
+	return result
+}
+func chunkBy1[T any](list []T, size int) [][]T {
+	var chunks [][]T
+	for size < len(list) {
+		list, chunks = list[size:], append(chunks, list[0:size:size])
+	}
+	return append(chunks, list)
+}
+func splitData(data []Device.DeviceClassList, threshold float64, idWidthMap map[string]float64) [][]Device.DeviceClassList {
+	var result [][]Device.DeviceClassList
+	var currentBatch []Device.DeviceClassList
+	var currentSum float64
+
+	for _, item := range data {
+		wd := idWidthMap[item.T_id]
+		if currentSum+wd > threshold+0.1 {
+			// 当前批次超过阈值,切分
+			result = append(result, currentBatch)
+			// 重置当前批次和当前总和
+			currentBatch = []Device.DeviceClassList{}
+			currentSum = 0
+		}
+		currentBatch = append(currentBatch, item)
+		currentSum += wd
+	}
+
+	// 添加最后一批
+	if len(currentBatch) > 0 {
+		result = append(result, currentBatch)
+	}
+
+	return result
+}

+ 8 - 0
lib/lib.go

@@ -7,6 +7,7 @@ import (
 	"github.com/signintech/gopdf"
 	"math/rand"
 	"os"
+	"path/filepath"
 	"runtime"
 	"sort"
 	"strconv"
@@ -418,3 +419,10 @@ func FuncName() string {
 	f := runtime.FuncForPC(pc[0])
 	return f.Name()
 }
+
+// golang获取程序运行路径
+func GetCurrentDirectory() string {
+	dir, _ := filepath.Abs(filepath.Dir(os.Args[0]))
+
+	return strings.Replace(dir, "\\", "/", -1)
+}

+ 8 - 0
lib/libString.go

@@ -2,6 +2,7 @@ package lib
 
 import (
 	"math/rand"
+	"regexp"
 	"strings"
 	"time"
 )
@@ -54,3 +55,10 @@ func TimeStrToTime2(T_time string) (time.Time, bool) {
 
 	return stamp, true
 }
+
+// 判断字符串是否为纯数字
+func IsNumeric(str string) bool {
+	// 定义一个正则表达式来匹配纯数字字符串
+	re := regexp.MustCompile(`^\d+$`)
+	return re.MatchString(str)
+}

+ 4 - 2
models/Device/DeviceClassList.go

@@ -232,7 +232,7 @@ func Read_DeviceClassList_List(T_class int, T_sn string, page int, page_z int) (
 	cnt, _ = qs.SetCond((*orm2.Condition)(cond1)).Count()
 	return r, cnt
 }
-func Read_DeviceClassList_OrderList(T_class int, T_sn, T_remark string, page int, page_z int) (r []DeviceClassList, cnt int64) {
+func Read_DeviceClassList_OrderList(T_class int, T_sn, T_id, T_remark string, page int, page_z int) (r []DeviceClassList, cnt int64) {
 
 	o := orm.NewOrm()
 	var maps_z []orm2.ParamsList
@@ -247,10 +247,12 @@ func Read_DeviceClassList_OrderList(T_class int, T_sn, T_remark string, page int
 	}
 
 	sqlWhere := "t_class = " + strconv.Itoa(T_class) + " AND t__state = 1"
-
 	if len(T_sn) > 1 {
 		sqlWhere += " AND t_sn like \"%" + T_sn + "%\""
 	}
+	if len(T_id) > 1 {
+		sqlWhere += " AND T_id like \"%" + T_id + "%\""
+	}
 	if len(T_remark) > 0 {
 		sqlWhere += " AND t_remark like \"%" + T_remark + "%\""
 	}

+ 63 - 42
models/Task/Task.go

@@ -32,6 +32,11 @@ type Task struct {
 	T_reporting_state      int    `orm:"size(2);default(0)"`   // 报告编写 状态 0 未完成 1 已完成
 	T_delivery_state       int    `orm:"size(2);default(0)"`   // 交付审核 状态 0 未完成 1 已完成 2 处理中
 
+	T_VerifyDeviceDataStartTime string `orm:"size(256);null"` // 验证设备数据开始时间
+	T_VerifyDeviceDataEndTime   string `orm:"size(256);null"` // 验证设备数据开始时间
+	T_BindDeviceDataStartTime   string `orm:"size(256);null"` // 绑定设备数据开始时间
+	T_BindDeviceDataEndTime     string `orm:"size(256);null"` // 绑定设备数据结束时间
+
 	T_doc1 string `orm:"type(text);null"` // 封面
 	T_pdf1 string `orm:"type(text);null"` // 封面
 	T_doc2 string `orm:"type(text);null"` // 报告
@@ -47,52 +52,60 @@ type Task struct {
 }
 
 type Task_R struct {
-	T_task_id  string // id
-	T_name     string // 标题
-	T_doc1     string // 封面
-	T_pdf1     string // 封面
-	T_doc2     string // 报告
-	T_pdf2     string // 报告
-	T_doc3     string // 证书
-	T_pdf3     string // 证书
-	T_Show     int    // 公开/隐藏
-	T_Visit    int    // 浏览量
-	T_State    int    // 0    1
-	CreateTime string
-	UpdateTime string
+	T_task_id              string    // id
+	T_name                 string    // 标题
+	T_doc1                 string    // 封面
+	T_pdf1                 string    // 封面
+	T_doc2                 string    // 报告
+	T_pdf2                 string    // 报告
+	T_doc3                 string    // 证书
+	T_pdf3                 string    // 证书
+	T_Show                 int       // 公开/隐藏
+	T_Visit                int       // 浏览量
+	T_State                int       // 0    1
+	T_scheme_state         int       // 实施方案 状态 0 未完成 1 已完成
+	T_collection_state     int       // 数据采集 状态 0 未完成 1 已完成
+	T_reporting_state      int       // 报告编写 状态 0 未完成 1 已完成
+	T_delivery_state       int       // 交付审核 状态 0 未完成 1 已完成
+	T_VerifyDeviceDataTime [2]string // 验证设备数据开始-结束时间
+	T_BindDeviceDataTime   [2]string // 绑定设备数据开始-结束时间
+	CreateTime             string
+	UpdateTime             string
 }
 
 type Task_ struct {
 	Id                     int
-	T_class                int    // 分类ID
-	T_task_id              string // 任务ID
-	T_uuid                 string // 用户 UUID
-	T_user_name            string // 用户 UUID
-	T_name                 string // 标题
-	T_VerifyTemplate_class string // 任务模板id
-	T_VerifyTemplate_id    string // 任务模板id
-	T_deadline             string // 截止时间
-	T_scheme               string // 实施方案 负责人UUID
-	T_collection           string // 数据采集 负责人UUID
-	T_reporting            string // 报告编写 负责人UUID
-	T_delivery             string // 交付审核 负责人UUID
-	T_scheme_state         int    // 实施方案 状态 0 未完成 1 已完成
-	T_collection_state     int    // 数据采集 状态 0 未完成 1 已完成
-	T_reporting_state      int    // 报告编写 状态 0 未完成 1 已完成
-	T_delivery_state       int    // 交付审核 状态 0 未完成 1 已完成
-	T_scheme_name          string // 实施方案 负责人姓名
-	T_collection_name      string // 数据采集 负责人姓名
-	T_reporting_name       string // 报告编写 负责人姓名
-	T_delivery_name        string // 交付审核 负责人姓名
-	T_doc1                 string // 封面
-	T_pdf1                 string // 封面
-	T_doc2                 string // 报告
-	T_pdf2                 string // 报告
-	T_doc3                 string // 证书
-	T_pdf3                 string // 证书
-	T_Show                 int    // 0 公开 1 隐藏
-	T_Visit                int    // 浏览量
-	T_State                int    // 0 删除 1 正常
+	T_class                int       // 分类ID
+	T_task_id              string    // 任务ID
+	T_uuid                 string    // 用户 UUID
+	T_user_name            string    // 用户 UUID
+	T_name                 string    // 标题
+	T_VerifyTemplate_class string    // 任务模板id
+	T_VerifyTemplate_id    string    // 任务模板id
+	T_deadline             string    // 截止时间
+	T_scheme               string    // 实施方案 负责人UUID
+	T_collection           string    // 数据采集 负责人UUID
+	T_reporting            string    // 报告编写 负责人UUID
+	T_delivery             string    // 交付审核 负责人UUID
+	T_scheme_state         int       // 实施方案 状态 0 未完成 1 已完成
+	T_collection_state     int       // 数据采集 状态 0 未完成 1 已完成
+	T_reporting_state      int       // 报告编写 状态 0 未完成 1 已完成
+	T_delivery_state       int       // 交付审核 状态 0 未完成 1 已完成
+	T_scheme_name          string    // 实施方案 负责人姓名
+	T_collection_name      string    // 数据采集 负责人姓名
+	T_reporting_name       string    // 报告编写 负责人姓名
+	T_delivery_name        string    // 交付审核 负责人姓名
+	T_VerifyDeviceDataTime [2]string // 验证设备数据开始-结束时间
+	T_BindDeviceDataTime   [2]string // 绑定设备数据开始-结束时间
+	T_doc1                 string    // 封面
+	T_pdf1                 string    // 封面
+	T_doc2                 string    // 报告
+	T_pdf2                 string    // 报告
+	T_doc3                 string    // 证书
+	T_pdf3                 string    // 证书
+	T_Show                 int       // 0 公开 1 隐藏
+	T_Visit                int       // 浏览量
+	T_State                int       // 0 删除 1 正常
 }
 
 func (t *Task) TableName() string {
@@ -130,6 +143,12 @@ func TaskToTask_R(T Task) (T_r Task_R) {
 	T_r.T_Show = T.T_Show
 	T_r.T_State = T.T_State
 	T_r.T_Visit = T.T_Visit
+	T_r.T_scheme_state = T.T_scheme_state
+	T_r.T_collection_state = T.T_collection_state
+	T_r.T_reporting_state = T.T_reporting_state
+	T_r.T_delivery_state = T.T_delivery_state
+	T_r.T_VerifyDeviceDataTime = [2]string{T.T_VerifyDeviceDataStartTime, T.T_VerifyDeviceDataEndTime}
+	T_r.T_BindDeviceDataTime = [2]string{T.T_BindDeviceDataStartTime, T.T_BindDeviceDataEndTime}
 	T_r.UpdateTime = T.UpdateTime.Format("2006-01-02 15:04:05")
 	T_r.CreateTime = T.CreateTime.Format("2006-01-02 15:04:05")
 
@@ -159,6 +178,8 @@ func TaskToTask_(T Task, userMap, adminMap map[string]string) (T_ Task_) {
 	T_.T_collection_name = adminMap[T.T_collection]
 	T_.T_reporting_name = adminMap[T.T_reporting]
 	T_.T_delivery_name = adminMap[T.T_delivery]
+	T_.T_VerifyDeviceDataTime = [2]string{T.T_VerifyDeviceDataStartTime, T.T_VerifyDeviceDataEndTime}
+	T_.T_BindDeviceDataTime = [2]string{T.T_BindDeviceDataStartTime, T.T_BindDeviceDataEndTime}
 	T_.T_doc1 = T.T_doc1
 	T_.T_pdf1 = T.T_pdf1
 	T_.T_doc2 = T.T_doc2

+ 26 - 3
models/Task/TaskData.go

@@ -13,6 +13,11 @@ import (
 	"time"
 )
 
+const (
+	Temperature = "Temperature"
+	Humidity    = "Humidity"
+)
+
 // 模板
 type TaskData struct {
 	Id int `orm:"column(ID);size(11);auto;pk"`
@@ -184,7 +189,7 @@ type TaskDataClass_ struct {
 	T_id int    `orm:"column(t_id);size(10);null"`  // ID
 }
 
-func Read_TaskData_ById_List(T_task_id string, SN string, T_id int, Time_start_ string, Time_end_ string, page int, page_z int) ([]TaskData_, int64) {
+func Read_TaskData_ById_List(T_task_id string, SN string, T_id string, Time_start_ string, Time_end_ string, page int, page_z int) ([]TaskData_, int64) {
 	o := orm.NewOrm()
 	var maps []TaskData_
 	var maps_z []orm2.ParamsList
@@ -207,8 +212,8 @@ func Read_TaskData_ById_List(T_task_id string, SN string, T_id int, Time_start_
 		sql_condition += " AND t_time <= '" + Time_end_ + "'"
 	}
 
-	if T_id != -1 {
-		sql_condition += " AND t_id = " + strconv.Itoa(T_id)
+	if len(T_id) > 0 {
+		sql_condition += " AND t_id = '" + T_id + "'"
 	}
 	if len(SN) > 0 {
 		sql_condition += " AND t_sn = '" + SN + "'"
@@ -386,3 +391,21 @@ func Del_TaskData_t_id(T_task_id string, Id string) bool {
 	//logs.Println("mysql row affected nums: ", num)
 	return true
 }
+func Del_TaskData_t_idByT_BindDeviceDataTime(T_task_id, Id, startTime, endTime string) bool {
+
+	o := orm.NewOrm()
+
+	// 开始插入数据 UPDATE `cold_verify`.`Z_TaskData_d8qMyeXLzIxn` SET `t_t` = 20.2 WHERE `ID` = 69
+	sql := "DELETE FROM z_task_data_" + T_task_id + " WHERE t_id = " + Id + " AND NOT BETWEEN '" + startTime + "' AND '" + endTime + "'"
+	//  这里有时间优化  用于一次 prepare 多次 exec,以提高批量执行的速度
+	logs.Println(sql)
+	res, err := o.Raw(sql).Exec()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return false
+	}
+	res.RowsAffected()
+
+	//logs.Println("mysql row affected nums: ", num)
+	return true
+}

+ 5 - 0
routers/Task.go

@@ -34,6 +34,11 @@ func init() {
 	beego.Router("/TaskData/Export_Data_Excel", &controllers.TaskDataController{}, "*:Export_Data_Excel") // 导出任务数据excel
 	beego.Router("/TaskData/Export_Data_PDF", &controllers.TaskDataController{}, "*:Export_Data_PDF")     // 导出任务数据pdf
 
+	// 导出温度
+	beego.Router("/TaskData/Temperature_Pdf", &controllers.TaskDataController{}, "*:TaskData_Temperature_Pdf")
+	// 导出湿度
+	beego.Router("/TaskData/Humidity_Pdf", &controllers.TaskDataController{}, "*:TaskData_Humidity_Pdf")
+
 	// 校验
 	beego.Router("/TaskData/Check", &controllers.TaskDataController{}, "*:Check") // 检查数据
 

BIN
static/logo.jpg