فهرست منبع

精创实时数据,实时轨迹修改,添加验证到期时间以及校准到期时间

huangyan 4 ماه پیش
والد
کامیت
1ab4dd2949
11فایلهای تغییر یافته به همراه979 افزوده شده و 78 حذف شده
  1. 37 0
      Nats/Nats.go
  2. 10 2
      conf/app.conf
  3. 724 25
      controllers/Data.go
  4. 15 1
      controllers/Device.go
  5. 4 1
      controllers/Warning.go
  6. 1 1
      go.mod
  7. 2 0
      go.sum
  8. 25 17
      models/Device/Device.go
  9. 29 31
      models/Device/DeviceData.go
  10. 131 0
      models/openApi/jcOPenApi.go
  11. 1 0
      routers/Data.go

+ 37 - 0
Nats/Nats.go

@@ -703,6 +703,7 @@ func NatsInit() {
 			_ = lib.Nats.Publish(m.Reply, b)
 			return
 		}
+		t_R.Data = r
 		t_R.Code = 202
 		t_R.Msg = "查询失败当前数据为空"
 		b, _ := msgpack.Marshal(&t_R)
@@ -748,4 +749,40 @@ func NatsInit() {
 		_ = lib.Nats.Publish(m.Reply, b)
 		return
 	})
+	// 根据sn查询设备信息
+	_, _ = lib.Nats.QueueSubscribe("Read_Device_ByT_sn", "Read_Device_ByT_sn", func(m *nats.Msg) {
+		logs.Debug(fmt.Sprintf("Read_Device_ByT_sn message: %s\n", string(m.Data)))
+		type T_R struct {
+			Code int16         `xml:"Code"`
+			Msg  string        `xml:"Msg"`
+			Data Device.Device `xml:"Data"`
+		}
+		type T_Req struct {
+			T_sn string `xml:"T_sn"`
+		}
+		var t_R T_R
+		var t_Req T_Req
+		err := msgpack.Unmarshal(m.Data, &t_Req)
+		if err != nil {
+			t_R.Code = 202
+			t_R.Msg = "Unmarshal error"
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+		t, err := Device.Read_Device_ByT_sn(t_Req.T_sn)
+		if err == nil {
+			t_R.Code = 200
+			t_R.Msg = "ok"
+			t_R.Data = t
+			b, _ := msgpack.Marshal(&t_R)
+			_ = lib.Nats.Publish(m.Reply, b)
+			return
+		}
+		t_R.Code = 202
+		t_R.Msg = "查询失败当前数据为空"
+		b, _ := msgpack.Marshal(&t_R)
+		_ = lib.Nats.Publish(m.Reply, b)
+		return
+	})
 }

+ 10 - 2
conf/app.conf

@@ -8,12 +8,15 @@ Version = "/v3"
 
 # # Nats
 NatsServer_Url = "203.34.49.130:4222"
-; NatsServer_Url = "127.0.0.1:4222"
+; NatsServer_Url = "192.168.0.5:4222"
+
 
 # Mysql
+; MysqlServer_UrlPort = "192.168.0.88:3306"
 MysqlServer_UrlPort = "203.34.49.130:3306"
 MysqlServer_Database = "cold"
 MysqlServer_Username = "cold"
+; MysqlServer_Password = "yjwyEckZS7rE5H!"
 MysqlServer_Password = "yjwyEckZS7rE5H"
 MysqlServer_MaxIdleConnections = 100
 MysqlServer_MaxOpenConnections = 200
@@ -21,8 +24,10 @@ MysqlServer_Debug = true
 
 
 # Redis
+; Redis_address = "192.168.0.5:6379"
 Redis_address = "203.34.49.130:6379"
 Redis_password = "redis_JJ56d5"
+; Redis_password = "redis_wsxaMH"
 Redis_dbNum = "1"
 
 
@@ -42,7 +47,7 @@ FilterOnlyLoginCheckURL = /Menu/List,/User/Info,/User/Home,/User/Post,/UpFileTok
 
 
 MqttIds = tmqttjxit
-MqttServer_id = "tmqttjxit"
+MqttServer_id = "mqttjxit"
 
 Weixin_PwdKey = "7Nt9sJb1Xy0PoQrEl3Df5Zv2Cg6AhRkT"
 Weixin_Notify = ""
@@ -64,3 +69,6 @@ maxlines = 10000
 
 # 使用新的告警查询方式,修改为true后弃用设备报禁信息将在弃用菜单内才能查询
 UseNewWarningQuery = false
+# 对接精创数据
+apiurl = "http://192.168.0.5:8081/jc/api/"
+jcCron = "0 */2 * * * *"

+ 724 - 25
controllers/Data.go

@@ -863,6 +863,13 @@ func (c *DataController) Device_Sensor_Data_PDF() {
 		e_time = fmt.Sprintf("%s", DeviceSensor_data[len(DeviceSensor_data)-1].T_time)
 	}
 	lib.RectFillColor(pdf, "历史数据["+e_time+" / "+s_time+"]", 14, 22, 80, 550, 40, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+	pdf.SetFont("wts", "", 10)
+	pages := pdf.GetNumberOfPages()
+	pagenums := fmt.Sprintf("第 %d 页", pages)
+	pagenum, _ := pdf.MeasureTextWidth(pagenums)
+	pdf.SetX((595 / 2) - (pagenum / 2))
+	pdf.SetY(830)
+	pdf.Cell(nil, pagenums)
 	var y float64 = 120
 	if T_ist == 1 {
 		lib.RectFillColor(pdf, fmt.Sprintf("最高温度: %.1f ", maxTemp), 12, 22, y, 183, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
@@ -938,6 +945,12 @@ func (c *DataController) Device_Sensor_Data_PDF() {
 
 			lib.RectFillColor(pdf, "记录时间", 12, 412, y, 120, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
 			lib.RectFillColor(pdf, "备注", 12, 532, y, 40, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			pages := pdf.GetNumberOfPages()
+			pagenums := fmt.Sprintf("第 %d 页", pages)
+			pagenum, _ := pdf.MeasureTextWidth(pagenums)
+			pdf.SetX((595 / 2) - (pagenum / 2))
+			pdf.SetY(830) // 设置页码位置
+			pdf.Cell(nil, pagenums)
 			y += 20
 		}
 		//pdf.SetX(x) // must after pdf.SetNewY() called.
@@ -988,7 +1001,6 @@ func (c *DataController) Device_Sensor_Data_PDF() {
 		y += 20
 	}
 	timeStr := "ofile/" + time.Now().Format("20060102150405") + ".pdf"
-
 	err = pdf.WritePdf(timeStr)
 	if err != nil {
 		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
@@ -1337,13 +1349,19 @@ func Device_Sensor_Data_ChartShow_PDF1(companyName, T_snid, Time_start, Time_end
 		pdf.ImageByHolder(imgH, 10, y, &gopdf.Rect{W: 575, H: 315})
 		y += 315
 	}
+	pdf.SetFont("wts", "", 10)
+	pages := pdf.GetNumberOfPages()
+	pagenums := fmt.Sprintf("第 %d 页", pages)
+	pagenum, _ := pdf.MeasureTextWidth(pagenums)
+	pdf.SetX((595 / 2) - (pagenum / 2))
+	pdf.SetY(830) // 设置页码位置
+	pdf.Cell(nil, pagenums)
 	y += 35
 	if y > 841.89 {
 		// 图片结束直接分页
 		pdf.AddPage()
 		y = 40
 	}
-
 	pdf.SetFont("wts", "", 16)
 	pdf.SetXY(10, y)
 	pdf.Text("记录数据信息")
@@ -1374,15 +1392,59 @@ func Device_Sensor_Data_ChartShow_PDF1(companyName, T_snid, Time_start, Time_end
 		x = x + w
 		w = 74
 		lib.RectFillColor(pdf, "T1", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
-
+		count := 0
 		for i, v := range Pdf_data {
+			//y = pdf.GetY()
+			//if y <= 20 {
+			//	var x float64 = 19
+			//	var w float64 = 112
+			//	fmt.Println(pdf.GetY())
+			//	lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			//	x = x + w
+			//	w = 74
+			//	lib.RectFillColor(pdf, "T1", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			//	x = x + w
+			//	w = 110
+			//	lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			//	x = x + w
+			//	w = 74
+			//	lib.RectFillColor(pdf, "T1", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			//	x = x + w
+			//	w = 110
+			//	lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			//	x = x + w
+			//	w = 74
+			//	lib.RectFillColor(pdf, "T1", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			//	y += 20
+			//}
 			if i%3 == 0 {
 				y += 20
 				x, w = 19, 112
 				var textH float64 = 25 // if text height is 25px.
 				pdf.SetNewY(y, textH)
 				y = pdf.GetY()
-
+				if y <= 20 {
+					var x float64 = 19
+					var w float64 = 112
+					fmt.Println(pdf.GetY())
+					lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x = x + w
+					w = 74
+					lib.RectFillColor(pdf, "T1", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x = x + w
+					w = 110
+					lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x = x + w
+					w = 74
+					lib.RectFillColor(pdf, "T1", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x = x + w
+					w = 110
+					lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x = x + w
+					w = 74
+					lib.RectFillColor(pdf, "T1", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					y += 20
+				}
 				lib.RectFillColor(pdf, v.T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
 				x = x + w
 				w = 74
@@ -1404,8 +1466,25 @@ func Device_Sensor_Data_ChartShow_PDF1(companyName, T_snid, Time_start, Time_end
 				w = 74
 				lib.RectFillColor(pdf, lib.Float32_to_string(v.T_id1), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
 			}
-
+			if pdf.GetY() >= 804 {
+				count++
+				if count == 3 {
+					count = 0
+					pages := pdf.GetNumberOfPages()
+					pagenums := fmt.Sprintf("第 %d 页", pages)
+					pagenum, _ := pdf.MeasureTextWidth(pagenums)
+					pdf.SetX((595 / 2) - (pagenum / 2))
+					pdf.SetY(830) // 设置页码位置
+					pdf.Cell(nil, pagenums)
+				}
+			}
 		}
+		pages := pdf.GetNumberOfPages()
+		pagenums := fmt.Sprintf("第 %d 页", pages)
+		pagenum, _ := pdf.MeasureTextWidth(pagenums)
+		pdf.SetX((595 / 2) - (pagenum / 2))
+		pdf.SetY(830) // 设置页码位置
+		pdf.Cell(nil, pagenums)
 	}
 	if len(snidNum) == 2 {
 		var x float64 = 19
@@ -1434,13 +1513,42 @@ func Device_Sensor_Data_ChartShow_PDF1(companyName, T_snid, Time_start, Time_end
 		lib.RectFillColor(pdf, "T1", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
 		x = x + w
 		lib.RectFillColor(pdf, "T2", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
-
+		count := 0
 		for i, v := range Pdf_data {
 			if i%3 == 0 {
 				y += 20
 				var textH float64 = 25 // if text height is 25px.
 				pdf.SetNewY(y, textH)
 				y = pdf.GetY()
+				if y <= 20 {
+					var x float64 = 19
+					var w float64 = 112
+					lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x = x + w
+					w = 37
+					lib.RectFillColor(pdf, "T1", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x = x + w
+					lib.RectFillColor(pdf, "T2", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+
+					x = x + w
+					w = 112
+					lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x = x + w
+					w = 37
+					lib.RectFillColor(pdf, "T1", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x = x + w
+					lib.RectFillColor(pdf, "T2", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+
+					x = x + w
+					w = 112
+					lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x = x + w
+					w = 37
+					lib.RectFillColor(pdf, "T1", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x = x + w
+					lib.RectFillColor(pdf, "T2", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					y += 20
+				}
 				x, w = 19, 112
 				lib.RectFillColor(pdf, v.T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
 				x = x + w
@@ -1469,8 +1577,25 @@ func Device_Sensor_Data_ChartShow_PDF1(companyName, T_snid, Time_start, Time_end
 				x = x + w
 				lib.RectFillColor(pdf, lib.Float32_to_string(v.T_id2), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
 			}
-
+			if pdf.GetY() >= 804 {
+				count++
+				if count == 3 {
+					count = 0
+					pages := pdf.GetNumberOfPages()
+					pagenums := fmt.Sprintf("第 %d 页", pages)
+					pagenum, _ := pdf.MeasureTextWidth(pagenums)
+					pdf.SetX((595 / 2) - (pagenum / 2))
+					pdf.SetY(830) // 设置页码位置
+					pdf.Cell(nil, pagenums)
+				}
+			}
 		}
+		pages := pdf.GetNumberOfPages()
+		pagenums := fmt.Sprintf("第 %d 页", pages)
+		pagenum, _ := pdf.MeasureTextWidth(pagenums)
+		pdf.SetX((595 / 2) - (pagenum / 2))
+		pdf.SetY(830) // 设置页码位置
+		pdf.Cell(nil, pagenums)
 	}
 
 	timeStr := "ofile/" + time.Now().Format("20060102150405") + ".pdf"
@@ -1786,6 +1911,13 @@ func Device_Sensor_Data_ChartShow_PDF0(companyName, T_snid, Time_start, Time_end
 		y += 315
 	}
 	y += 35
+	pdf.SetFont("wts", "", 10)
+	pages := pdf.GetNumberOfPages()
+	pagenums := fmt.Sprintf("第 %d 页", pages)
+	pagenum, _ := pdf.MeasureTextWidth(pagenums)
+	pdf.SetX((595 / 2) - (pagenum / 2))
+	pdf.SetY(830) // 设置页码位置
+	pdf.Cell(nil, pagenums)
 	if y > 841.89 {
 		// 图片结束直接分页
 		pdf.AddPage()
@@ -1857,6 +1989,65 @@ func Device_Sensor_Data_ChartShow_PDF0(companyName, T_snid, Time_start, Time_end
 	for i, v := range first_column {
 		pdf.SetNewY(y, textH)
 		y = pdf.GetY()
+		if y <= 20 {
+			pages := pdf.GetNumberOfPages()
+			pagenums := fmt.Sprintf("第 %d 页", pages)
+			pagenum, _ := pdf.MeasureTextWidth(pagenums)
+			pdf.SetX((595 / 2) - (pagenum / 2))
+			pdf.SetY(830) // 设置页码位置
+			pdf.Cell(nil, pagenums)
+			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 T_temp_show == 1 && T_Humidity_show == 1 {
+				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)
+			}
+			if T_temp_show == 1 && T_Humidity_show == 0 {
+				x = x + w
+				w = 74
+				lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			}
+			if T_temp_show == 0 && T_Humidity_show == 1 {
+				x = x + w
+				w = 74
+				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 T_temp_show == 1 && T_Humidity_show == 1 {
+				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)
+			}
+			if T_temp_show == 1 && T_Humidity_show == 0 {
+				x = x + w
+				w = 74
+				lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			}
+			if T_temp_show == 0 && T_Humidity_show == 1 {
+				x = x + w
+				w = 74
+				lib.RectFillColor(pdf, "湿度%", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			}
+			y += 20
+		}
 		x, w = 10, 112
 
 		lib.RectFillColor(pdf, v.T_time, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
@@ -1913,14 +2104,79 @@ func Device_Sensor_Data_ChartShow_PDF0(companyName, T_snid, Time_start, Time_end
 				lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_rh), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
 			}
 		}
-
 		y += 20
+		if y >= 820 {
+			pages := pdf.GetNumberOfPages()
+			pagenums := fmt.Sprintf("第 %d 页", pages)
+			pagenum, _ := pdf.MeasureTextWidth(pagenums)
+			pdf.SetX((595 / 2) - (pagenum / 2))
+			pdf.SetY(830) // 设置页码位置
+			pdf.Cell(nil, pagenums)
+		}
 	}
 	if len(second_column) > len(first_column) {
 		for i := len(first_column); i < len(second_column); i++ {
-
 			pdf.SetNewY(y, textH)
 			y = pdf.GetY()
+			if y <= 20 {
+				pages := pdf.GetNumberOfPages()
+				pagenums := fmt.Sprintf("第 %d 页", pages)
+				pagenum, _ := pdf.MeasureTextWidth(pagenums)
+				pdf.SetX((595 / 2) - (pagenum / 2))
+				pdf.SetY(830) // 设置页码位置
+				pdf.Cell(nil, pagenums)
+				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 T_temp_show == 1 && T_Humidity_show == 1 {
+					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)
+				}
+				if T_temp_show == 1 && T_Humidity_show == 0 {
+					x = x + w
+					w = 74
+					lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				}
+				if T_temp_show == 0 && T_Humidity_show == 1 {
+					x = x + w
+					w = 74
+					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 T_temp_show == 1 && T_Humidity_show == 1 {
+					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)
+				}
+				if T_temp_show == 1 && T_Humidity_show == 0 {
+					x = x + w
+					w = 74
+					lib.RectFillColor(pdf, "温度℃", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				}
+				if T_temp_show == 0 && T_Humidity_show == 1 {
+					x = x + w
+					w = 74
+					lib.RectFillColor(pdf, "湿度%", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				}
+				y += 20
+			}
 			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
@@ -1946,10 +2202,17 @@ func Device_Sensor_Data_ChartShow_PDF0(companyName, T_snid, Time_start, Time_end
 				lib.RectFillColor(pdf, fmt.Sprintf(" %.1f ", second_column[i].T_rh), 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
 			}
 			y += 20
+			if y >= 820 {
+				pages := pdf.GetNumberOfPages()
+				pagenums := fmt.Sprintf("第 %d 页", pages)
+				pagenum, _ := pdf.MeasureTextWidth(pagenums)
+				pdf.SetX((595 / 2) - (pagenum / 2))
+				pdf.SetY(830) // 设置页码位置
+				pdf.Cell(nil, pagenums)
+			}
 		}
 	}
 	timeStr := "ofile/" + time.Now().Format("20060102150405") + ".pdf"
-
 	err = pdf.WritePdf(timeStr)
 	if err != nil {
 		return
@@ -2113,7 +2376,18 @@ func (c *DataController) Device_Sensor_Data_BackUp_PDF() {
 	lib.RectFillColor(pdf, "温度范围", 12, 272, 120, 100, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
 	lib.RectFillColor(pdf, "湿度范围", 12, 362, 120, 100, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
 	lib.RectFillColor(pdf, "记录时间", 12, 452, 120, 120, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
-
+	err = pdf.SetFont("wts", "", 10)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
+		c.ServeJSON()
+		return
+	}
+	pages := pdf.GetNumberOfPages()
+	pagenums := fmt.Sprintf("第 %d 页", pages)
+	pagenum, _ := pdf.MeasureTextWidth(pagenums)
+	pdf.SetX((595 / 2) - (pagenum / 2))
+	pdf.SetY(830) // 设置页码位置
+	pdf.Cell(nil, pagenums)
 	var y float64 = 140
 
 	err = pdf.SetFont("wts", "", 10)
@@ -2360,39 +2634,170 @@ var upgrader = websocket.Upgrader{
 	},
 }
 
+type DeviceTrajData struct {
+	List  []Device.DeviceData_
+	Lists []Device.DeviceData_R2
+}
+
+var deviceTrajDataMap map[string]DeviceTrajData
+
+//func (c *DataController) GetNewLocus_() {
+//	ws, err := upgrader.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)
+//	if err != nil {
+//		log.Println("设置websocket升级失败:", err)
+//		return
+//	}
+//	defer ws.Close()
+//	deviceTrajDataMap = make(map[string]DeviceTrajData)
+//	type Responses struct {
+//		Sn  string `json:"sn"`
+//		Tid int    `json:"tid"`
+//	}
+//
+//	type Response struct {
+//		Code   int32                  `protobuf:"varint,2,opt,name=code,proto3" json:"code,omitempty"`
+//		Msg    string                 `protobuf:"bytes,3,opt,name=msg,proto3" json:"msg,omitempty"`
+//		Data   []Device.DeviceData_R2 `json:"data"`
+//		Sn     string                 `json:"sn"`
+//		T_name string                 `json:"t_name"` // 设备名称
+//	}
+//	_, message, err := ws.ReadMessage()
+//	if err != nil {
+//		logs.Error(lib.FuncName(), "读取参数失败: %v", err)
+//		return
+//	}
+//	log.Printf("Received: %s", message)
+//
+//	var r Responses
+//	err = json.Unmarshal(message, &r)
+//	if err != nil {
+//		logs.Error(lib.FuncName(), "解析参数失败: %v", err)
+//		ws.WriteMessage(websocket.TextMessage, []byte("参数解析失败"))
+//		return
+//	}
+//	device, err := Device.Read_Device_ByT_sn(r.Sn)
+//	if err != nil {
+//		logs.Error(lib.FuncName(), "设备不存在: %v", err)
+//		ws.WriteMessage(websocket.TextMessage, []byte("设备不存在"))
+//		return
+//	}
+//	// 根据设备序列号获取对应的数据结构,如果不存在则初始化一个
+//	deviceData, ok := deviceTrajDataMap[r.Sn]
+//	if !ok {
+//		deviceData = DeviceTrajData{
+//			List:  make([]Device.DeviceData_, 0),
+//			Lists: make([]Device.DeviceData_R2, 0),
+//		}
+//	}
+//	for {
+//		err = Device.GetNewLocus(r.Sn, r.Tid, &deviceData.List)
+//		if err != nil {
+//			// 处理获取轨迹失败的情况,构造并发送错误响应给客户端
+//			response := Response{
+//				Code: 500,
+//				Msg:  "获取轨迹失败",
+//				Data: nil,
+//			}
+//			data, _ := json.Marshal(response)
+//			ws.WriteMessage(websocket.TextMessage, data)
+//			continue
+//		}
+//
+//		updatedLists := make([]Device.DeviceData_R2, 0)
+//		for i := range deviceData.List {
+//			updatedLists = append(updatedLists, Device.DeviceData_R2{
+//				DeviceData_: Device.DeviceData_{
+//					T_id:   deviceData.List[i].T_id,
+//					T_rh:   deviceData.List[i].T_rh,
+//					T_site: deviceData.List[i].T_site,
+//					T_sp:   deviceData.List[i].T_sp,
+//					T_time: deviceData.List[i].T_time,
+//					T_t:    deviceData.List[i].T_t,
+//				},
+//				Sn:     r.Sn,
+//				T_name: device.T_devName,
+//			})
+//		}
+//		deviceData.Lists = updatedLists
+//		deviceTrajDataMap[r.Sn] = deviceData
+//
+//		response := Response{
+//			Code:   200,
+//			Msg:    "ok!",
+//			Data:   deviceData.Lists,
+//			Sn:     r.Sn,
+//			T_name: device.T_devName,
+//		}
+//		data, _ := json.Marshal(response)
+//		ws.WriteMessage(websocket.TextMessage, data)
+//		// 检查客户端是否断开连接
+//		_, _, err = ws.ReadMessage()
+//		if err != nil {
+//			if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway, websocket.CloseNoStatusReceived) {
+//				log.Println("客户端已断开连接")
+//				break
+//			}
+//			log.Println("读取消息时发生错误:", err)
+//		}
+//		// 回复消息
+//		time.Sleep(10 * time.Second)
+//	}
+//}
+
 func (c *DataController) GetNewLocus_() {
 	ws, err := upgrader.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)
 	if err != nil {
-		log.Println("Failed to set websocket upgrade:", err)
+		log.Println("设置websocket升级失败:", err)
 		return
 	}
 	defer ws.Close()
+	deviceTrajDataMap = make(map[string]DeviceTrajData)
 	type Responses struct {
 		Sn  string `json:"sn"`
 		Tid int    `json:"tid"`
 	}
-	var list []Device.DeviceData_
+
 	type Response struct {
-		Code int32                `protobuf:"varint,2,opt,name=code,proto3" json:"code,omitempty"`
-		Msg  string               `protobuf:"bytes,3,opt,name=msg,proto3" json:"msg,omitempty"`
-		Data []Device.DeviceData_ `json:"data"`
+		Code   int32                  `protobuf:"varint,2,opt,name=code,proto3" json:"code,omitempty"`
+		Msg    string                 `protobuf:"bytes,3,opt,name=msg,proto3" json:"msg,omitempty"`
+		Data   []Device.DeviceData_R2 `json:"data"`
+		Sn     string                 `json:"sn"`
+		T_name string                 `json:"t_name"` // 设备名称
 	}
 	_, message, err := ws.ReadMessage()
 	if err != nil {
 		logs.Error(lib.FuncName(), "读取参数失败: %v", err)
+		return
 	}
 	log.Printf("Received: %s", message)
+
 	var r Responses
-	//var rs Response
 	err = json.Unmarshal(message, &r)
 	if err != nil {
 		logs.Error(lib.FuncName(), "解析参数失败: %v", err)
 		ws.WriteMessage(websocket.TextMessage, []byte("参数解析失败"))
+		return
 	}
+	device, err := Device.Read_Device_ByT_sn(r.Sn)
+	if err != nil {
+		logs.Error(lib.FuncName(), "设备不存在: %v", err)
+		ws.WriteMessage(websocket.TextMessage, []byte("设备不存在"))
+		return
+	}
+	// 根据设备序列号获取对应的数据结构,如果不存在则初始化一个
+	deviceData, ok := deviceTrajDataMap[r.Sn]
+	if !ok {
+		deviceData = DeviceTrajData{
+			List:  make([]Device.DeviceData_, 0),
+			Lists: make([]Device.DeviceData_R2, 0),
+		}
+	}
+
+	isFirstRequest := true // 新增标识,用于判断是否是首次请求
 	for {
-		err = Device.GetNewLocus(r.Sn, r.Tid, &list)
+		err = Device.GetNewLocus(r.Sn, r.Tid, &deviceData.List)
 		if err != nil {
-			logs.Error(lib.FuncName(), "获取轨迹失败s: %v, sn: %s, tid: %d", err, r.Sn, r.Tid)
+			// 处理获取轨迹失败的情况,构造并发送错误响应给客户端
 			response := Response{
 				Code: 500,
 				Msg:  "获取轨迹失败",
@@ -2400,16 +2805,310 @@ func (c *DataController) GetNewLocus_() {
 			}
 			data, _ := json.Marshal(response)
 			ws.WriteMessage(websocket.TextMessage, data)
-			break
+			continue
 		}
+
+		updatedLists := make([]Device.DeviceData_R2, 0)
+		for i := range deviceData.List {
+			updatedLists = append(updatedLists, Device.DeviceData_R2{
+				DeviceData_: Device.DeviceData_{
+					T_id:   deviceData.List[i].T_id,
+					T_rh:   deviceData.List[i].T_rh,
+					T_site: deviceData.List[i].T_site,
+					T_sp:   deviceData.List[i].T_sp,
+					T_time: deviceData.List[i].T_time,
+					T_t:    deviceData.List[i].T_t,
+				},
+				Sn:     r.Sn,
+				T_name: device.T_devName,
+			})
+		}
+		deviceData.Lists = updatedLists
+		deviceTrajDataMap[r.Sn] = deviceData
+
 		response := Response{
-			Code: 200,
-			Msg:  "ok!",
-			Data: list,
+			Code:   200,
+			Msg:    "ok!",
+			Data:   deviceData.Lists,
+			Sn:     r.Sn,
+			T_name: device.T_devName,
 		}
 		data, _ := json.Marshal(response)
 		ws.WriteMessage(websocket.TextMessage, data)
-		// 回复消息
-		time.Sleep(10 * time.Second)
+
+		// 检查客户端是否断开连接
+		_, _, err = ws.ReadMessage()
+		if err != nil {
+			if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway, websocket.CloseNoStatusReceived) {
+				log.Println("客户端已断开连接")
+				break
+			}
+			log.Println("读取消息时发生错误:", err)
+		}
+
+		if isFirstRequest {
+			isFirstRequest = false // 首次请求处理完后,将标识设为false
+		} else {
+			// 非首次请求,按照间隔时间休眠后再进行下一次循环获取数据
+			time.Sleep(10 * time.Second)
+		}
 	}
 }
+
+//	func (c *DataController) GetNewLocus_() {
+//		ws, err := upgrader.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)
+//		if err != nil {
+//			log.Println("设置websocket升级失败:", err)
+//			return
+//		}
+//		defer ws.Close()
+//
+//		type Responses struct {
+//			Sn  string `json:"sn"`
+//			Tid int    `json:"tid"`
+//		}
+//
+//		type Response struct {
+//			Code   int32                  `protobuf:"varint,2,opt,name=code,proto3" json:"code,omitempty"`
+//			Msg    string                 `protobuf:"bytes,3,opt,name=msg,proto3" json:"msg,omitempty"`
+//			Data   []Device.DeviceData_R2 `json:"data"`
+//			Sn     string                 `json:"sn"`
+//			T_name string                 `json:"t_name"` // 设备名称
+//		}
+//
+//		heartbeatInterval := 10 * time.Second
+//		timeoutInterval := 20 * time.Second
+//		heartbeatTicker := time.NewTicker(heartbeatInterval)
+//		defer heartbeatTicker.Stop()
+//
+//		for {
+//			select {
+//			case <-heartbeatTicker.C:
+//				// 发送心跳消息
+//				if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil {
+//					log.Println("发送心跳消息失败:", err)
+//					return
+//				}
+//				// 设置读取超时时间
+//				ws.SetReadDeadline(time.Now().Add(timeoutInterval))
+//			default:
+//				_, message, err := ws.ReadMessage()
+//				if err != nil {
+//					if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway, websocket.CloseNoStatusReceived) {
+//						log.Println("客户端已断开连接")
+//					} else {
+//						logs.Error(lib.FuncName(), "读取参数失败: %v", err)
+//					}
+//					return
+//				}
+//				log.Printf("Received: %s", message)
+//
+//				var r Responses
+//				err = json.Unmarshal(message, &r)
+//				if err != nil {
+//					logs.Error(lib.FuncName(), "解析参数失败: %v", err)
+//					ws.WriteMessage(websocket.TextMessage, []byte("参数解析失败"))
+//					continue
+//				}
+//
+//				sn, err := Device.Read_Device_ByT_sn(r.Sn)
+//				if err != nil {
+//					logs.Error(lib.FuncName(), "设备不存在: %v", err)
+//					ws.WriteMessage(websocket.TextMessage, []byte("设备不存在"))
+//					continue
+//				}
+//
+//				var list []Device.DeviceData_
+//				var lists []Device.DeviceData_R2
+//
+//				err = Device.GetNewLocus(r.Sn, r.Tid, &list)
+//				if err != nil {
+//					logs.Error(lib.FuncName(), "获取轨迹失败: %v, sn: %s, tid: %d", err, r.Sn, r.Tid)
+//					response := Response{
+//						Code: 500,
+//						Msg:  "获取轨迹失败",
+//						Data: nil,
+//					}
+//					data, _ := json.Marshal(response)
+//					ws.WriteMessage(websocket.TextMessage, data)
+//					continue
+//				}
+//
+//				for i := range list {
+//					lists = append(lists, Device.DeviceData_R2{
+//						DeviceData_: Device.DeviceData_{
+//							T_id:   list[i].T_id,
+//							T_rh:   list[i].T_rh,
+//							T_site: list[i].T_site,
+//							T_sp:   list[i].T_sp,
+//							T_time: list[i].T_time,
+//							T_t:    list[i].T_t,
+//						},
+//						Sn:     r.Sn,
+//						T_name: sn.T_devName,
+//					})
+//				}
+//
+//				response := Response{
+//					Code:   200,
+//					Msg:    "ok!",
+//					Data:   lists,
+//					Sn:     r.Sn,
+//					T_name: sn.T_devName,
+//				}
+//				data, _ := json.Marshal(response)
+//				ws.WriteMessage(websocket.TextMessage, data)
+//
+//				// 设置读取超时时间
+//				ws.SetReadDeadline(time.Now().Add(timeoutInterval))
+//			}
+//		}
+//	}
+
+//func (c *DataController) GetNewLocus_() {
+//	ws, err := upgrader.Upgrade(c.Ctx.ResponseWriter, c.Ctx.Request, nil)
+//	if err != nil {
+//		log.Println("设置websocket升级失败:", err)
+//		return
+//	}
+//	defer ws.Close()
+//
+//	type Responses struct {
+//		Sn  string `json:"sn"`
+//		Tid int    `json:"tid"`
+//	}
+//
+//	var r Responses
+//	_, message, err := ws.ReadMessage()
+//	if err != nil {
+//		logs.Error(lib.FuncName(), "读取参数失败: %v", err)
+//		return
+//	}
+//	log.Printf("Received: %s", message)
+//
+//	err = json.Unmarshal(message, &r)
+//	if err != nil {
+//		logs.Error(lib.FuncName(), "解析参数失败: %v", err)
+//		ws.WriteMessage(websocket.TextMessage, []byte("参数解析失败"))
+//		return
+//	}
+//
+//	devices, err := Device.Read_Device_ByT_sn(r.Sn)
+//	if err != nil {
+//		logs.Error(lib.FuncName(), "设备不存在: %v", err)
+//		ws.WriteMessage(websocket.TextMessage, []byte("设备不存在"))
+//		return
+//	}
+//
+//	ctx, cancel := context.WithCancel(context.Background())
+//	defer cancel()
+//
+//	// 启动一个新的goroutine来处理每个设备的轨迹数据
+//	go func(sn string, tid int, ctx context.Context) {
+//		type Response struct {
+//			Code   int32                  `json:"code,omitempty"`
+//			Msg    string                 `json:"msg,omitempty"`
+//			Data   []Device.DeviceData_R2 `json:"data"`
+//			Sn     string                 `json:"sn"`
+//			T_name string                 `json:"t_name"` // 设备名称
+//		}
+//
+//		for {
+//			select {
+//			case <-ctx.Done():
+//				log.Println("goroutine 被取消")
+//				return
+//			default:
+//				// 检查连接是否仍然打开
+//				err := pingWebSocket(ws)
+//				if err != nil {
+//					log.Println("心跳检测失败:", err)
+//					cancel()
+//					break
+//				}
+//
+//				var list []Device.DeviceData_
+//				err = Device.GetNewLocus(sn, tid, &list)
+//				if err != nil {
+//					logs.Error(lib.FuncName(), "获取轨迹失败: %v, sn: %s, tid: %d", err, sn, tid)
+//					response := Response{
+//						Code: 500,
+//						Msg:  "获取轨迹失败",
+//						Data: nil,
+//					}
+//					data, marshalErr := json.Marshal(response)
+//					if marshalErr == nil {
+//						sendMessage(ws, data)
+//					}
+//					cancel()
+//					break
+//				}
+//
+//				lists := make([]Device.DeviceData_R2, len(list))
+//				for i, item := range list {
+//					lists[i] = Device.DeviceData_R2{
+//						DeviceData_: Device.DeviceData_{
+//							T_id:   item.T_id,
+//							T_rh:   item.T_rh,
+//							T_site: item.T_site,
+//							T_sp:   item.T_sp,
+//							T_time: item.T_time,
+//							T_t:    item.T_t,
+//						},
+//						Sn:     sn,
+//						T_name: devices.T_devName,
+//					}
+//				}
+//
+//				response := Response{
+//					Code:   200,
+//					Msg:    "ok!",
+//					Data:   lists,
+//					Sn:     sn,
+//					T_name: devices.T_devName,
+//				}
+//				data, marshalErr := json.Marshal(response)
+//				if marshalErr == nil {
+//					sendMessage(ws, data)
+//				} else {
+//					log.Println("JSON 序列化失败:", marshalErr)
+//				}
+//
+//				time.Sleep(10 * time.Second)
+//			}
+//		}
+//	}(r.Sn, r.Tid, ctx)
+//
+//	// 启动一个goroutine用于监听连接关闭事件
+//	go func() {
+//		for {
+//			_, _, err := ws.ReadMessage()
+//			if err != nil {
+//				if websocket.IsCloseError(err, websocket.CloseNormalClosure, websocket.CloseGoingAway, websocket.CloseNoStatusReceived) {
+//					log.Println("客户端已断开连接")
+//				} else {
+//					log.Println("读取消息时发生错误:", err)
+//				}
+//				cancel()
+//				return
+//			}
+//		}
+//	}()
+//}
+//
+//// pingWebSocket 发送一个ping帧以确认连接是否仍然活跃
+//func pingWebSocket(ws *websocket.Conn) error {
+//	err := ws.WriteControl(websocket.PingMessage, []byte{}, time.Now().Add(time.Second*5))
+//	if err != nil {
+//		return fmt.Errorf("发送心跳失败: %v", err)
+//	}
+//	return nil
+//}
+//
+//// sendMessage 封装了发送消息的过程,包括错误处理
+//func sendMessage(ws *websocket.Conn, data []byte) {
+//	err := ws.WriteMessage(websocket.TextMessage, data)
+//	if err != nil {
+//		log.Println("发送消息失败:", err)
+//	}
+//}

+ 15 - 1
controllers/Device.go

@@ -214,6 +214,20 @@ func (c *DeviceController) Device_Edit() {
 		Device_r.T_VerifyTime = VerifyTime
 		clos = append(clos, "T_VerifyTime")
 	}
+	// 验证到期时间
+	T_Verify_End_Time := c.GetString("T_VerifyEndTime")
+	Verify_End_Time, Verify_End_Time_is := lib.TimeStrToTime(T_Verify_End_Time)
+	if Verify_End_Time_is {
+		Device_r.T_VerifyEndTime = Verify_End_Time
+		clos = append(clos, "T_VerifyEndTime")
+	}
+	// 校准到期时间
+	T_Calibration_End_Time := c.GetString("T_CalibrationEndTime")
+	Calibration_End_Time, Calibration_End_Time_is := lib.TimeStrToTime(T_Calibration_End_Time)
+	if Calibration_End_Time_is {
+		Device_r.T_CalibrationEndTime = Calibration_End_Time
+		clos = append(clos, "T_CalibrationEndTime")
+	}
 
 	// 校准时间
 	T_CalibrationTime := c.GetString("T_CalibrationTime")
@@ -221,7 +235,7 @@ func (c *DeviceController) Device_Edit() {
 	if CalibrationTime_is {
 		Device_r.T_CalibrationTime = CalibrationTime
 		clos = append(clos, "T_CalibrationTime")
-		// 同步冷链验证校准到期时间
+		// 同步冷链验证校准开始时间
 		NatsServer.Update_Task_BySN(T_SN, CalibrationTime)
 	}
 

+ 4 - 1
controllers/Warning.go

@@ -9,9 +9,11 @@ import (
 	"Cold_Api/models/Device"
 	"Cold_Api/models/System"
 	"Cold_Api/models/Warning"
+	"Cold_Api/models/openApi"
 	"encoding/json"
 	"fmt"
 	"github.com/beego/beego/v2/core/logs"
+	beego "github.com/beego/beego/v2/server/web"
 	"github.com/robfig/cron/v3"
 	"github.com/xuri/excelize/v2"
 	"math"
@@ -1360,9 +1362,10 @@ func Cron_WarningRate() {
 	// @daily 每日运行一次
 	// c.AddFunc("0 */1 * * * ?", Cron_WarningRateDay_Add)
 	// c.AddFunc("0 */1 * * * ?", Cron_WarningRateMonth_Add)
+	jc, _ := beego.AppConfig.String("jcCron")
 	c.AddFunc("@daily", Cron_WarningRateDay_Add)
 	c.AddFunc("@monthly", Cron_WarningRateMonth_Add)
-
+	c.AddFunc(jc, openApi.GetRealtime)
 	// 启动定时任务
 	c.Start()
 	defer c.Stop()

+ 1 - 1
go.mod

@@ -12,7 +12,7 @@ require (
 	github.com/mssola/user_agent v0.6.0
 	github.com/nats-io/nats.go v1.22.1
 	github.com/qiniu/go-sdk/v7 v7.14.0
-	github.com/robfig/cron/v3 v3.0.1
+	github.com/robfig/cron/v3 v3.0.0
 	github.com/satori/go.uuid v1.2.0
 	github.com/shopspring/decimal v1.3.1
 	github.com/signintech/gopdf v0.15.1

+ 2 - 0
go.sum

@@ -282,6 +282,8 @@ github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7
 github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
 github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM=
 github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
+github.com/robfig/cron/v3 v3.0.0 h1:kQ6Cb7aHOHTSzNVNEhmp8EcWKLb4CbiMW9h9VyIhO4E=
+github.com/robfig/cron/v3 v3.0.0/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
 github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
 github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=

+ 25 - 17
models/Device/Device.go

@@ -19,27 +19,29 @@ import (
 
 // 设备
 type Device struct {
-	T_sn              string    `orm:"pk;size(256);null"`    // 设备序列号
-	T_pid             int       `orm:"index;size(256);null"` // Account.Company 绑定公司
-	T_devName         string    `orm:"size(256);null"`       // 设备名称  20字
-	T_protocol        int       `orm:"size(2);default(3)"`   // 冷链通讯协议 1 :1.0协议   2 :2.0协议    3 :3.0协议
-	T_mqttid          string    `orm:"size(256);null"`       // MQTT 服务ID
-	T_VerifyTime      time.Time `orm:"type(timestamp);null"` // 验证时间
-	T_CalibrationTime time.Time `orm:"type(timestamp);null"` // 校准时间
-	T_PatrolTime      time.Time `orm:"type(timestamp);null"` // 巡检时间
-	T_abandonTime     time.Time `orm:"type(timestamp);null"` // 弃用时间
-	T_ist             int       `orm:"size(2);default(1)"`   // 温度   1开启   2关闭
-	T_ish             int       `orm:"size(2);default(1)"`   // 湿度   1开启   2关闭
+	T_sn                 string    `orm:"pk;size(256);null"`    // 设备序列号
+	T_pid                int       `orm:"index;size(256);null"` // Account.Company 绑定公司
+	T_devName            string    `orm:"size(256);null"`       // 设备名称  20字
+	T_protocol           int       `orm:"size(2);default(3)"`   // 冷链通讯协议 1 :1.0协议   2 :2.0协议    3 :3.0协议
+	T_mqttid             string    `orm:"size(256);null"`       // MQTT 服务ID
+	T_VerifyTime         time.Time `orm:"type(timestamp);null"` // 验证时间
+	T_VerifyEndTime      time.Time `orm:"type(timestamp);null"` // 验证到期时间
+	T_CalibrationTime    time.Time `orm:"type(timestamp);null"` // 校准时间
+	T_CalibrationEndTime time.Time `orm:"type(timestamp);null"` // 校准到期时间
+	T_PatrolTime         time.Time `orm:"type(timestamp);null"` // 巡检时间
+	T_abandonTime        time.Time `orm:"type(timestamp);null"` // 弃用时间
+	T_ist                int       `orm:"size(2);default(1)"`   // 温度   1开启   2关闭
+	T_ish                int       `orm:"size(2);default(1)"`   // 湿度   1开启   2关闭
 
 	T_State int `orm:"index;size(2);default(1)"` // 0 屏蔽   1 正常  (屏蔽后 只有内部管理员才能看到,用户 输入SN\名称 搜索时 也能看到)
 
 	// 设备同步参数
-	T_Dattery  int    `orm:"size(4);null"`             // 电量
-	T_Site     string `orm:"size(200);null"`           // GPS
-	T_monitor  int    `orm:"index;size(2);null"`       // 监控状态 0 未监控 1 监控  停止记录
-	T_online   int    `orm:"index;size(2);default(0)"` // 在线状态 0 未启用  1 在线  2 离线
-	T_online_s int    `orm:"index;size(2);default(0)"` // 在线状态-备用  0 未启用  1 在线  2 离线
-
+	T_Dattery  int    `orm:"size(4);null"`                       // 电量
+	T_Site     string `orm:"size(200);null"`                     // GPS
+	T_monitor  int    `orm:"index;size(2);null"`                 // 监控状态 0 未监控 1 监控  停止记录
+	T_online   int    `orm:"index;size(2);default(0)"`           // 在线状态 0 未启用  1 在线  2 离线
+	T_online_s int    `orm:"index;size(2);default(0)"`           // 在线状态-备用  0 未启用  1 在线  2 离线
+	IsLocal    int    `orm:"size(2);default(0);column(Islocal)"` //是否本公司设备
 	// 硬件信息
 	T_model string `orm:"size(200);null"` // KF200BG  设备型号
 	T_sver  string `orm:"size(200);null"` // "1.0.0",//软件版本
@@ -118,6 +120,12 @@ func DeviceToDevice_R(r Device) (t Device_R) {
 	if !r.T_VerifyTime.IsZero() {
 		t.T_VerifyTime = r.T_VerifyTime.Format("2006-01-02 15:04:05")
 	}
+	if !r.T_VerifyEndTime.IsZero() {
+		t.T_VerifyTime = r.T_VerifyTime.Format("2006-01-02 15:04:05")
+	}
+	if !r.T_CalibrationEndTime.IsZero() {
+		t.T_VerifyTime = r.T_VerifyTime.Format("2006-01-02 15:04:05")
+	}
 	if !r.T_CalibrationTime.IsZero() {
 		t.T_CalibrationTime = r.T_CalibrationTime.Format("2006-01-02 15:04:05")
 	}

+ 29 - 31
models/Device/DeviceData.go

@@ -58,6 +58,12 @@ type DeviceData_R struct {
 	T_ish    int     // 湿度   1开启   2关闭
 	T_free   int     // 空库
 	T_remark string  // 备注
+	Sorts    int     // 排序
+}
+type DeviceData_R2 struct {
+	DeviceData_
+	Sn     string `json:"sn"`
+	T_name string `json:"t_name"` // 设备名称
 }
 
 // 模板
@@ -521,16 +527,15 @@ func Read_DeviceData_By_T_snid_List(T_snid string, Time_start_ string, Time_end_
 	var maps []DeviceData_R
 	var maps_num int64
 	var offset, offset_z int
-
 	for _, v := range T_snid_list {
 		sn_id := strings.Split(v, ",")
-
-		if len(sn_id) == 2 {
+		if len(sn_id) == 3 {
 			Read_DeviceSensorParameter_All_Map(sn_id[0], lib.To_int(sn_id[1]))
 			r_maps, r_maps_num := Read_DeviceData_ById_List(sn_id[0], lib.To_int(sn_id[1]), Time_start_, Time_end_, 0, 9999)
-			//for i, _ := range r_maps {
-			//	r_maps[i].T_sn = sn_id[0]
-			//}
+			for i, _ := range r_maps {
+				atoi, _ := strconv.Atoi(sn_id[2])
+				r_maps[i].Sorts = atoi
+			}
 			maps = append(maps, r_maps...)
 			maps_num = maps_num + int64(r_maps_num)
 
@@ -544,20 +549,11 @@ func Read_DeviceData_By_T_snid_List(T_snid string, Time_start_ string, Time_end_
 
 	// 倒序
 	sort.Slice(maps, func(i, j int) bool {
-		if maps[i].T_time > maps[j].T_time {
-			return true
+		if maps[i].T_time == maps[j].T_time {
+			return maps[i].Sorts < maps[j].Sorts
 		}
-		return false
+		return maps[i].T_time > maps[j].T_time
 	})
-
-	//sort.Slice(maps, func(i, j int) bool {
-	//	// 先按 T_time 字段排序,如果 T_time 相同则按 T_id 字段排序
-	//	if maps[i].T_time == maps[j].T_time {
-	//		return maps[i].T_name < maps[j].T_name
-	//	}
-	//	return maps[i].T_time > maps[j].T_time
-	//})
-
 	if page <= 1 {
 		offset = 0
 	} else {
@@ -825,19 +821,21 @@ func appendUniqueDeviceData(list []DeviceData_, newData []DeviceData_) []DeviceD
 	}
 	for _, d := range newData {
 		if !uniqueMap[d.T_time] {
-			split := strings.Split(d.T_site, ",")
-			defer func() {
-				if r := recover(); r != nil {
-					fmt.Println("数组下标越界:", r)
-				}
-			}()
-			Lng := split[0]
-			Lat := split[1]
-			Lngs, _ := strconv.ParseFloat(Lng, 64)
-			Lats, _ := strconv.ParseFloat(Lat, 64)
-			mLng, mLat := lib.Wgs84ToGcj02(Lngs, Lats)
-			d.T_site = fmt.Sprintf("%v,%v", mLng, mLat)
-			list = append(list, d)
+			if len(d.T_site) > 0 {
+				split := strings.Split(d.T_site, ",")
+				defer func() {
+					if r := recover(); r != nil {
+						fmt.Println("数组下标越界:", r)
+					}
+				}()
+				Lng := split[0]
+				Lat := split[1]
+				Lngs, _ := strconv.ParseFloat(Lng, 64)
+				Lats, _ := strconv.ParseFloat(Lat, 64)
+				mLng, mLat := lib.Wgs84ToGcj02(Lngs, Lats)
+				d.T_site = fmt.Sprintf("%v,%v", mLng, mLat)
+				list = append(list, d)
+			}
 		}
 	}
 	//排序

+ 131 - 0
models/openApi/jcOPenApi.go

@@ -0,0 +1,131 @@
+package openApi
+
+import (
+	"Cold_Api/models/Device"
+	"bytes"
+	"encoding/json"
+	"github.com/beego/beego/v2/adapter/orm"
+	"github.com/beego/beego/v2/core/logs"
+	beego "github.com/beego/beego/v2/server/web"
+	"io"
+	"net/http"
+	"strconv"
+	"strings"
+	"time"
+)
+
+type T struct {
+	Msg  string `json:"msg"`
+	Code int    `json:"code"`
+	Data struct {
+		Code int `json:"code"`
+		Data []struct {
+			DeviceGuid      string `json:"deviceGuid"`
+			SubUid          int    `json:"subUid"`
+			DeviceName      string `json:"deviceName"`
+			Tmp1            string `json:"tmp1"`
+			Tmp2            string `json:"tmp2"`
+			Tmp3            string `json:"tmp3"`
+			Tmp4            string `json:"tmp4"`
+			Hum1            string `json:"hum1"`
+			Hum2            string `json:"hum2"`
+			Lux1            string `json:"lux1"`
+			Power           string `json:"power"`
+			Signal          string `json:"signal"`
+			Position        string `json:"position"`
+			Address         string `json:"address"`
+			LastDataTime    int64  `json:"lastDataTime"`
+			LastSessionTime int64  `json:"lastSessionTime"`
+			LastAddressTime string `json:"lastAddressTime"`
+			AlarmState      bool   `json:"alarmState"`
+			WarnState       bool   `json:"warnState"`
+			WaybillStart    string `json:"waybillStart"`
+			WaybillEnd      string `json:"waybillEnd"`
+			WaybillState    string `json:"waybillState"`
+		} `json:"data"`
+		Time    string `json:"time"`
+		Message string `json:"message"`
+		Error   string `json:"error"`
+	} `json:"data"`
+}
+
+func GetRealtime() {
+	url, err := beego.AppConfig.String("apiurl")
+	if err != nil {
+		logs.Debug("无法获取apiurl:", err)
+		return
+	}
+	o := orm.NewOrm()
+	var DeviceList []string
+	//查询设备表中精创设备
+	sql := "select t_sn from device where Islocal = '1'"
+	rows, err := o.Raw(sql).QueryRows(&DeviceList)
+	if rows == 0 {
+		logs.Debug("未查询到设备")
+		return
+	}
+	if err != nil {
+		logs.Debug("查询设备表失败:", err)
+		return
+	}
+	marshal, err := json.Marshal(DeviceList)
+	if err != nil {
+		logs.Debug("json转换失败:", err)
+		return
+	}
+	resp, err := http.Post(url+"getRealTimeData", "application/json", bytes.NewReader(marshal))
+	if err != nil {
+		logs.Debug("请求失败:", err)
+		return
+	}
+	defer resp.Body.Close()
+	body, _ := io.ReadAll(resp.Body)
+	var temp T
+	err = json.Unmarshal(body, &temp)
+	if err != nil {
+		logs.Error("解析失败:", err)
+		return
+	}
+	if temp.Code != 0 {
+		logs.Error("请求失败:", temp.Msg)
+		return
+	}
+	for _, v := range temp.Data.Data {
+		var T_t, T_rh float64
+		if len(v.Tmp1) != 0 {
+			Tmp1 := strings.Trim(v.Tmp1, "℃")
+			T_t, err = strconv.ParseFloat(Tmp1, 32)
+			if err != nil {
+				logs.Error("转换温度失败:", err)
+				return
+			}
+
+		}
+		if len(v.Hum1) != 0 {
+			Hum1 := strings.Trim(v.Hum1, "%RH")
+			T_rh, err = strconv.ParseFloat(Hum1, 32)
+			if err != nil {
+				logs.Error("转换湿度失败:", err)
+				return
+			}
+		}
+		var T_time time.Time
+		if v.LastSessionTime != 0 {
+			T_time = time.Unix(v.LastSessionTime, 0).Local()
+		}
+		key := v.DeviceGuid + "|" + strconv.Itoa(v.SubUid+1)
+		r, is := Device.Read_DeviceSensorParameter(v.DeviceGuid, v.SubUid+1)
+		if !is {
+			logs.Error("获取最新设备参数失败:", err)
+			return
+		}
+		Device.RedisDeviceData_Set(key, Device.DeviceData_{
+			T_rh:   float32(T_rh),
+			T_t:    float32(T_t),
+			T_time: T_time,
+			T_site: v.Position,
+			T_sp:   r.Id,
+			T_id:   v.SubUid + 1,
+		})
+	}
+}

+ 1 - 0
routers/Data.go

@@ -36,6 +36,7 @@ func init() {
 			beego.NSRouter("/Raw", &controllers.RawSqlController{}, "*:Raw"), // 执行 SQL
 		),
 	)
+	//药监接口
 	beego.Router("/docking/Real_Data", &controllers.DataController{}, "*:Docking_Real_Data")
 	beego.Router("/docking/Note_Data", &controllers.DataController{}, "*:Docking_Note_Data")