Browse Source

2023-07-26 设备实时数据生成图片

zoie 1 year ago
parent
commit
40a976eed6
5 changed files with 260 additions and 35 deletions
  1. 4 1
      Nats/Nats.go
  2. 1 0
      conf/config.go
  3. 176 24
      controllers/TaskData.go
  4. 76 9
      models/Task/TaskData.go
  5. 3 1
      routers/TaskData.go

+ 4 - 1
Nats/Nats.go

@@ -27,7 +27,10 @@ func init() {
 	}
 	logs.Println("nats OK!")
 
-	//go NatsInit()
+	// 本地测试,屏蔽本地nats
+	if !conf.NatsForbidden {
+		go NatsInit()
+	}
 }
 
 type Up_TaskData_Back struct {

+ 1 - 0
conf/config.go

@@ -6,6 +6,7 @@ import (
 
 // Nats
 var NatsServer_Url, _ = beego.AppConfig.String("NatsServer_Url")
+var NatsForbidden = beego.AppConfig.DefaultBool("NatsForbidden", false)
 
 var HTTPPort, _ = beego.AppConfig.String("HTTPPort")
 var AppName, _ = beego.AppConfig.String("appname")

+ 176 - 24
controllers/TaskData.go

@@ -209,7 +209,6 @@ func (c *TaskDataController) TaskData_AddS() {
 	var T_Data_list_x = 0
 
 	snMaps := make(map[string]string)
-	var valueStrings []string
 
 	for _, v := range T_Data_list {
 		// 132|132|23.9|72.1|2023-04-30 07:03:00
@@ -227,13 +226,9 @@ func (c *TaskDataController) TaskData_AddS() {
 			c.ServeJSON()
 			return
 		}
-		t, _ := lib.ReplaceSeconds(v_list[4])
-		valueStrings = append(valueStrings, fmt.Sprintf("('%s','%s',%v,%v,'%v')", v_list[0], v_list[1], v_list[2], v_list[3], t))
-		T_Data_list_x += 1
 	}
 
 	for T_id, T_sn := range snMaps {
-
 		sn, err := Task.Read_TaskData_ByT_id(Task_r.T_task_id, T_id)
 		if err != nil && !errors.Is(err, orm.ErrNoRows) {
 			continue
@@ -265,7 +260,6 @@ func (c *TaskDataController) TaskData_AddS() {
 		}
 		v_list := strings.Split(v, "|")
 		t, _ := lib.ReplaceSeconds(v_list[4])
-
 		is := Task.Add_TaskData(Task_r.T_task_id, v_list[0], v_list[1], v_list[2], v_list[3], t)
 		if is {
 			T_Data_list_x += 1
@@ -1978,6 +1972,21 @@ func (c *TaskDataController) TaskDataCopy_Recover() {
 
 }
 
+// 查询图片生成状态
+func (c *TaskDataController) TaskData_JPGState() {
+
+	T_task_id := c.GetString("T_task_id")
+	jpg, is := Task.Redis_TaskDataJPG_Get(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "暂无图片正在生成"}
+		c.ServeJSON()
+		return
+	}
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: jpg}
+	c.ServeJSON()
+	return
+}
+
 func (c *TaskDataController) TaskData_JPG() {
 	StartTime := c.GetString("StartTime")
 	if len(StartTime) > 0 {
@@ -2021,33 +2030,26 @@ func (c *TaskDataController) TaskData_JPG() {
 		c.ServeJSON()
 		return
 	}
-	jpg, is := Task.Redis_TaskDataJPG_Get(T_task_id)
-	if !is {
-		// 生成图片
-		go Gen_JPG(StartTime, EndTime, T_task_id, SN_List, TemperatureMin, TemperatureMax)
-		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Task.TaskDataJPG{State: 1}}
-		c.ServeJSON()
-		return
-	}
-	if jpg.State == 3 {
-		Task.Redis_TaskDataJPG_Del(T_task_id)
-		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: jpg}
-		c.ServeJSON()
-		return
-	}
-	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: jpg}
+	Task.Redis_TaskDataJPG_Del(T_task_id)
+
+	// 生成图片
+	go TaskDataJPG(StartTime, EndTime, T_task_id, SN_List, TemperatureMin, TemperatureMax)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
 	c.ServeJSON()
 	return
 }
 
 // 存档生成图片
-func Gen_JPG(StartTime, EndTime, T_task_id, snList string, TemperatureMin, TemperatureMax float64) {
+func TaskDataJPG(StartTime, EndTime, T_task_id, snList string, TemperatureMin, TemperatureMax float64) {
 	Task.Redis_TaskDataJPG_Set(T_task_id, Task.TaskDataJPG{
 		State: 1,
+		Msg:   "图片生成中",
 		Url:   "",
 	})
-
+	msg := ""
 	state := 2
+	url := ""
 
 	if TemperatureMin == 0 {
 		TemperatureMin = 2
@@ -2153,22 +2155,172 @@ func Gen_JPG(StartTime, EndTime, T_task_id, snList string, TemperatureMin, Tempe
 	// 保存文件
 	if err := p.Save(10*vg.Inch, 4*vg.Inch, "ofile/"+filename+".jpg"); err != nil {
 		state = 3
+		msg = "图片生成失败"
 		logs.Error(lib.FuncName(), "生成图片失败", err)
 	}
 	if !lib.Pload_qiniu("ofile/"+filename+".jpg", "ofile/"+filename+".jpg") {
 		state = 3
+		msg = "图片上传七牛云失败"
 		logs.Error(lib.FuncName(), "上传七牛云失败")
 	}
 	//删除目录
 	os.Remove("ofile/" + filename + ".jpg")
+	if len(msg) == 0 {
+		msg = "图片生成成功"
+		url = "https://bzdcoldverifyoss.baozhida.cn/" + "ofile/" + filename + ".jpg"
+	}
 
 	Task.Redis_TaskDataJPG_Set(T_task_id, Task.TaskDataJPG{
 		State: state,
-		Url:   "https://bzdcoldverifyoss.baozhida.cn/" + "ofile/" + filename + ".jpg",
+		Msg:   msg,
+		Url:   url,
 	})
 
 }
 
+func (c *TaskDataController) DeviceData_JPG() {
+	StartTime := c.GetString("StartTime")
+	if len(StartTime) > 0 {
+		_, ok := lib.TimeStrToTime(StartTime)
+		if !ok {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误!"}
+			c.ServeJSON()
+			return
+		}
+	}
+
+	EndTime := c.GetString("EndTime")
+	if len(EndTime) > 0 {
+		_, ok := lib.TimeStrToTime(EndTime)
+		if !ok {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误!"}
+			c.ServeJSON()
+			return
+		}
+	}
+
+	TemperatureMin, _ := c.GetFloat("TemperatureMin") // 最低温度
+	TemperatureMax, _ := c.GetFloat("TemperatureMax") // 最高温度
+	if TemperatureMin == 0 {
+		TemperatureMin = 2
+	}
+	if TemperatureMax == 0 {
+		TemperatureMax = 8
+	}
+
+	T_sn := c.GetString("T_sn")
+	T_id := c.GetString("T_id")
+
+	//jpg, is := Task.Redis_TaskDataJPG_Get(T_sn)
+	//if !is {
+	//	// 生成图片
+	//	go DeviceDataJPG(StartTime, EndTime, T_sn, T_id, TemperatureMin, TemperatureMax)
+	//	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Task.TaskDataJPG{State: 1}}
+	//	c.ServeJSON()
+	//	return
+	//}
+	//if jpg.State == 3 {
+	//	Task.Redis_TaskDataJPG_Del(T_sn)
+	//	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: jpg}
+	//	c.ServeJSON()
+	//	return
+	//}
+
+	url, err := DeviceDataJPG(StartTime, EndTime, T_sn, T_id, TemperatureMin, TemperatureMax)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
+		c.ServeJSON()
+		return
+	}
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: url}
+	c.ServeJSON()
+	return
+}
+
+// 存档生成图片
+func DeviceDataJPG(StartTime, EndTime, T_sn, T_id string, TemperatureMin, TemperatureMax float64) (url string, err error) {
+	//Task.Redis_TaskDataJPG_Set(T_sn, Task.TaskDataJPG{
+	//	State: 1,
+	//	Url:   "",
+	//})
+	//
+	//state := 2
+
+	if TemperatureMin == 0 {
+		TemperatureMin = 2
+	}
+	if TemperatureMax == 0 {
+		TemperatureMax = 8
+	}
+
+	ymin, ymax, minTime, maxTime := Task.Read_DeviceData_T_Min_Max_Time_Min_Max(T_sn, T_id, StartTime, EndTime)
+	xmin, xmax := float64(minTime.Unix()), float64(maxTime.Unix())
+	// 创建一个新的绘图
+	p := plot.New()
+
+	// 设置绘图标题和标签
+	p.Title.Text = "温度折线图"
+	//p.Legend.ThumbnailWidth = 5 * vg.Inch
+	p.X.Label.Text = "时间"
+	p.Y.Label.Text = "温度"
+
+	// 添加最高,最低标准线 用红色虚线标识
+	p.Add(horizontalLine(xmin, xmax, TemperatureMin))
+
+	p.Add(horizontalLine(xmin, xmax, TemperatureMax))
+
+	list := Task.Read_DeviceData_ById_List(T_sn, T_id, StartTime, EndTime)
+
+	pts := make(plotter.XYs, len(list))
+	for j, d := range list {
+		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(0)
+	p.Add(line)
+
+	if ymax < 8 {
+		ymax = 8
+	}
+	if ymin > 0 {
+		ymin = 0
+	}
+	p.Y.Min, p.Y.Max = ymin, 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
+
+	filename := "jpg" + time.Now().Format("20060102150405")
+	// 保存文件
+	if err := p.Save(10*vg.Inch, 4*vg.Inch, "ofile/"+filename+".jpg"); err != nil {
+		logs.Error(lib.FuncName(), "生成图片失败", err)
+	}
+	if !lib.Pload_qiniu("ofile/"+filename+".jpg", "ofile/"+filename+".jpg") {
+		logs.Error(lib.FuncName(), "上传七牛云失败")
+	}
+	//删除目录
+	os.Remove("ofile/" + filename + ".jpg")
+	url = "https://bzdcoldverifyoss.baozhida.cn/" + "ofile/" + filename + ".jpg"
+	return
+
+	//Task.Redis_TaskDataJPG_Set(T_sn, Task.TaskDataJPG{
+	//	State: state,
+	//	Url:   "https://bzdcoldverifyoss.baozhida.cn/" + "ofile/" + filename + ".jpg",
+	//})
+
+}
+
 func horizontalLine(xmin, xmax, y float64) *plotter.Line {
 	pts := make(plotter.XYs, 2)
 	pts[0].X = xmin

+ 76 - 9
models/Task/TaskData.go

@@ -49,7 +49,8 @@ func init() {
 
 type TaskDataJPG struct {
 	State int    `json:"state"` //1:生成中 2:已完成 3:失败
-	Url   string `json:"url"`   //url
+	Msg   string `json:"msg"`
+	Url   string `json:"url"` //url
 }
 
 // ---------------- Redis -------------------
@@ -356,9 +357,12 @@ func Delete_TaskData_ByT_sn(T_task_id, T_sn string) error {
 // 添加
 func Add_TaskData(T_task_id string, T_sn string, T_id string, T_t string, T_rh string, T_time string) bool {
 
-	o := orm.NewOrm()
-	o.Begin()
-
+	o := orm2.NewOrm()
+	tx, err := o.Begin()
+	if err != nil {
+		logs.Error("start the transaction failed")
+		return false
+	}
 	// 开始插入数据
 	//
 	//sql := "INSERT INTO z_task_data_" + T_task_id + " (`t_sn`, `t_id`, `t_time`) " +
@@ -369,9 +373,9 @@ func Add_TaskData(T_task_id string, T_sn string, T_id string, T_t string, T_rh s
 	sql := "DELETE FROM z_task_data_" + T_task_id + "  WHERE " + " t_id = '" + T_id + "' AND " + " t_sn = '" + T_sn + "' " + "AND t_time = '" + T_time + "'  "
 	//  这里有时间优化  用于一次 prepare 多次 exec,以提高批量执行的速度
 	//fmt.Println(sql)
-	res, err := o.Raw(sql).Exec()
+	res, err := tx.Raw(sql).Exec()
 	if err != nil {
-		o.Rollback()
+		tx.Rollback()
 		logs.Error(lib.FuncName(), err)
 		return false
 	}
@@ -386,13 +390,13 @@ func Add_TaskData(T_task_id string, T_sn string, T_id string, T_t string, T_rh s
 	//	"on duplicate key update `t_t`=" + T_t + ",`t_rh`=" + T_rh
 
 	//fmt.Println(sql)
-	res, err = o.Raw(sql).Exec()
+	res, err = tx.Raw(sql).Exec()
 	if err != nil {
-		o.Rollback()
+		tx.Rollback()
 		logs.Error(lib.FuncName(), err)
 		return false
 	}
-	o.Commit()
+	tx.Commit()
 
 	//fmt.Println("mysql row affected nums: ", num)
 	return true
@@ -894,6 +898,69 @@ func Read_TaskData_T_Min_Max_Time_Min_Max(T_task_id string, SN []string, T_id []
 
 }
 
+// 获取线上设备数据
+func Read_DeviceData_T_Min_Max_Time_Min_Max(T_sn, T_id string, Time_start_ string, Time_end_ string) (minT, maxT float64, minTime, maxTime time.Time) {
+	o := orm2.NewOrmUsingDB(conf.Server_AliasName)
+
+	sql_condition := ""
+
+	if len(Time_start_) > 1 {
+		sql_condition += " AND t_time >= '" + Time_start_ + "'"
+	}
+
+	if len(Time_end_) > 1 {
+		sql_condition += " AND t_time <= '" + Time_end_ + "'"
+	}
+
+	sql_condition += " AND t_id = '" + T_id + "'"
+
+	if len(sql_condition) > 0 {
+		sql_condition = " WHERE " + strings.TrimLeft(sql_condition, " AND ")
+	}
+	//fmt.Println("maps_z;",maps_z[0][0])
+	sql := "SELECT MIN(t_t) AS min_t, MAX(t_t) AS max_t,MIN(t_time) AS min_time, MAX(t_time) AS max_time FROM z_devicedata_" + T_sn + sql_condition
+
+	fmt.Println(sql)
+	err := o.Raw(sql).QueryRow(&minT, &maxT, &minTime, &maxTime)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+	return
+
+}
+
+// 获取线上设备数据
+func Read_DeviceData_ById_List(T_sn, T_id string, Time_start_ string, Time_end_ string) []TaskData_ {
+	o := orm2.NewOrmUsingDB(conf.Server_AliasName)
+	var maps []TaskData_
+
+	sql_condition := ""
+	if len(Time_start_) > 1 {
+		sql_condition += " AND t_time >= '" + Time_start_ + "'"
+	}
+
+	if len(Time_end_) > 1 {
+		sql_condition += " AND t_time <= '" + Time_end_ + "'"
+	}
+
+	sql_condition += " AND t_id = '" + T_id + "'"
+
+	if len(sql_condition) > 0 {
+		sql_condition = " WHERE " + strings.TrimLeft(sql_condition, " AND ")
+	}
+
+	//fmt.Println("maps_z;",maps_z[0][0])
+	sql := "SELECT ID,t_id,t_t,t_rh,DATE_FORMAT(t_time,'%Y-%m-%d %H:%i:%s') AS t_times,t_time FROM z_devicedata_" + T_sn + sql_condition + " ORDER BY t_time"
+
+	fmt.Println(sql)
+	_, err := o.Raw(sql).QueryRows(&maps)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+
+	return maps
+}
+
 func Read_TaskData_ByIds_List(T_task_id string, SN []string, T_id []string, Time_start_ string, Time_end_ string) []TaskData {
 	o := orm.NewOrm()
 	var maps []TaskData

+ 3 - 1
routers/TaskData.go

@@ -46,5 +46,7 @@ func init() {
 	beego.Router("/TaskDataCopy/Del", &controllers.TaskDataController{}, "*:TaskDataCopy_Del")         // 删除数据存档
 	beego.Router("/TaskDataCopy/Recover", &controllers.TaskDataController{}, "*:TaskDataCopy_Recover") // 数据存档恢复
 
-	beego.Router("/TaskData/jpg", &controllers.TaskDataController{}, "*:TaskData_JPG") // 生成图片
+	beego.Router("/TaskData/jpg", &controllers.TaskDataController{}, "*:TaskData_JPG")            // 任务生成图片
+	beego.Router("/TaskData/JPG/State", &controllers.TaskDataController{}, "*:TaskData_JPGState") // 任务 图片生成状态
+	beego.Router("/DeviceData/jpg", &controllers.TaskDataController{}, "*:DeviceData_JPG")        // 设备生成图片
 }