zoie 1 vuosi sitten
vanhempi
commit
eaf570bd49
13 muutettua tiedostoa jossa 591 lisäystä ja 60 poistoa
  1. 9 4
      Nats/Nats.go
  2. 2 0
      conf/app.conf
  3. 1 0
      conf/config.go
  4. 49 12
      controllers/DeviceClass.go
  5. 310 0
      controllers/Task.go
  6. 7 7
      controllers/User.go
  7. 19 9
      go.mod
  8. 60 12
      go.sum
  9. 21 2
      lib/libString.go
  10. 6 6
      models/Account/User.go
  11. 100 4
      models/Device/DeviceData.go
  12. 4 4
      models/Task/Task.go
  13. 3 0
      routers/Task.go

+ 9 - 4
Nats/Nats.go

@@ -26,8 +26,10 @@ func init() {
 		panic(err)
 	}
 	logs.Println("nats OK!")
-
-	go NatsInit()
+	// 本地测试,屏蔽本地nats
+	if !conf.NatsForbidden {
+		go NatsInit()
+	}
 }
 
 type Extract_TaskData_Back struct {
@@ -122,7 +124,7 @@ func NatsInit() {
 			col = append(col, "T_delivery_state")
 		}
 
-		if !Task.Update_Task(t_Req, "T_collection_state", "T_delivery_state") {
+		if !Task.Update_Task(t_Req, col...) {
 			logs.Error("Mats", lib.FuncName(), err)
 			t_R.Code = 202
 			t_R.Msg = err.Error()
@@ -131,6 +133,9 @@ func NatsInit() {
 			return
 		}
 
+		Task.Add_TaskLogs_T("nats", t_Req.T_task_id, "任务管理", "修改", t_R)
+		System.Add_UserLogs_T("nats", "任务管理", "修改", t_R)
+
 		t_R.Code = 200
 		t_R.Msg = "ok"
 
@@ -140,7 +145,7 @@ func NatsInit() {
 	})
 
 	_, _ = lib.Nats.QueueSubscribe("ColdVerify_Server_Read_Task", "Read_Task", func(m *nats.Msg) {
-		fmt.Printf("ColdVerify_Server_Read_Task message: %+v\n", string(m.Data))
+		logs.Println("ColdVerify_Server_Read_Task message: %+v\n", string(m.Data))
 
 		var t_R lib.JSONS
 		task, is := Task.Read_Task(string(m.Data))

+ 2 - 0
conf/app.conf

@@ -5,8 +5,10 @@ Graceful = true
 EnableDocs = true
 copyrequestbody = true
 
+
 # Nats
 NatsServer_Url = "127.0.0.1:43422"
+NatsForbidden = true
 
 # Mysql
 # MysqlServer_UrlPort = "47.111.15.17:3306"

+ 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")

+ 49 - 12
controllers/DeviceClass.go

@@ -258,7 +258,7 @@ func (c *DeviceClassController) List_Add() {
 
 	_, is := Device.Read_DeviceClass_ById(T_class)
 	if !is {
-		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_class 错误!"}
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_class 错误"}
 		c.ServeJSON()
 		return
 	}
@@ -266,6 +266,8 @@ func (c *DeviceClassController) List_Add() {
 	list := strings.Split(strings.TrimRight(T_layout_no_list, ","), ",")
 	snMap := make(map[string]string)
 	excludeId := make(map[string]struct{})
+	errList := []string{}
+	var successNum int // 成功数量
 	for _, v := range list {
 		if strings.Contains(v, "!") {
 			excludeId[fmt.Sprintf("%03d", lib.To_int(strings.TrimLeft(strings.Trim(v, "!"), "0")))] = struct{}{}
@@ -284,9 +286,12 @@ func (c *DeviceClassController) List_Add() {
 				T_id := fmt.Sprintf("%03d", i)
 				cert, is := Certificate.Read_Certificate_ByT_layout_no(T_id)
 				if !is {
-					c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("%s布局编号不存在!", T_id)}
-					c.ServeJSON()
-					return
+					//c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("%s布局编号不存在!", T_id)}
+					//c.ServeJSON()
+					//return
+
+					errList = append(errList, fmt.Sprintf("%s布局编号不存在!", T_id))
+					continue
 				}
 				snMap[T_id] = cert.T_sn
 			}
@@ -294,15 +299,19 @@ func (c *DeviceClassController) List_Add() {
 			// 001,002
 			cert, is := Certificate.Read_Certificate_ByT_layout_no(v)
 			if !is {
-				c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("%s布局编号不存在!", v)}
-				c.ServeJSON()
-				return
+				//c.Data["json"] = lib.JSONS{Code: 202, Msg: fmt.Sprintf("%s布局编号不存在!", v)}
+				//c.ServeJSON()
+				//return
+
+				errList = append(errList, v)
+				continue
 			}
 			snMap[v] = cert.T_sn
 		}
 
 	}
-
+	errList2 := []string{}
+	succesId := []string{}
 	for T_id, T_sn := range snMap {
 		if _, ok := excludeId[T_id]; ok {
 			continue
@@ -315,6 +324,7 @@ func (c *DeviceClassController) List_Add() {
 		//}
 
 		if dc, is := Device.Read_DeviceClassList_T_class_T_sn(T_class, T_sn); is && dc.Id > 0 {
+			successNum += 1
 			continue
 		}
 
@@ -336,14 +346,41 @@ func (c *DeviceClassController) List_Add() {
 
 		_, is = Device.Add_DeviceClassList(var_)
 		if !is {
-			c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
-			c.ServeJSON()
-			return
+			//c.Data["json"] = lib.JSONS{Code: 202, Msg: "添加失败!"}
+			//c.ServeJSON()
+			//return
+
+			errList2 = append(errList2, T_id)
+			continue
 		}
+		successNum += 1
+		succesId = append(succesId, T_id)
 		System.Add_UserLogs_T(User_r.T_uuid, "分类设备管理", "添加", var_)
 	}
 
-	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	if len(errList) == 0 && len(errList2) == 0 {
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: successNum}
+		c.ServeJSON()
+		return
+	}
+	var errStr string
+	if len(errList) > 0 {
+		errStr += strings.Join(errList, ",") + "编号不存在"
+	}
+	if len(errList2) > 0 {
+		if len(errStr) > 0 {
+			errStr += ","
+		}
+		errStr += strings.Join(errList2, ",") + "添加失败"
+	}
+	//if len(succesId) > 0 {
+	//	if len(errStr) > 0 {
+	//		errStr += ","
+	//	}
+	//	errStr += strings.Join(succesId, ",") + "添加成功"
+	//}
+
+	c.Data["json"] = lib.JSONS{Code: 210, Msg: errStr, Data: successNum}
 	c.ServeJSON()
 	return
 }

+ 310 - 0
controllers/Task.go

@@ -4,12 +4,22 @@ import (
 	"ColdVerify_server/Nats/NatsServer"
 	"ColdVerify_server/conf"
 	"ColdVerify_server/lib"
+	"ColdVerify_server/logs"
 	"ColdVerify_server/models/Account"
 	"ColdVerify_server/models/Device"
 	"ColdVerify_server/models/System"
 	"ColdVerify_server/models/Task"
+	"fmt"
 	beego "github.com/beego/beego/v2/server/web"
+	"gonum.org/v1/plot"
+	"gonum.org/v1/plot/plotter"
+	"gonum.org/v1/plot/vg"
+	"gonum.org/v1/plot/vg/draw"
+	"image/color"
 	"math"
+	"os"
+	"sync"
+	"time"
 )
 
 type TaskController struct {
@@ -263,6 +273,7 @@ func (c *TaskController) Up() {
 	T_deadline := c.GetString("T_deadline")
 	T_scheme := c.GetString("T_scheme")
 	T_collection := c.GetString("T_collection")
+	T_collection_state, _ := c.GetInt("T_collection_state")
 	T_reporting := c.GetString("T_reporting")
 	T_delivery := c.GetString("T_delivery")
 	T_doc1 := c.GetString("T_doc1")
@@ -319,6 +330,11 @@ func (c *TaskController) Up() {
 		clos = append(clos, "T_delivery")
 	}
 
+	if T_collection_state == 4 {
+		r.T_collection_state = T_collection_state
+		clos = append(clos, "T_collection_state")
+	}
+
 	if len(T_doc1) > 0 {
 		r.T_doc1 = T_doc1
 		clos = append(clos, "T_doc1")
@@ -435,3 +451,297 @@ func (c *TaskController) Logs_List() {
 	c.ServeJSON()
 	return
 }
+
+// 查询图片生成状态
+func (c *TaskController) DeviceData_JPGState() {
+
+	T_task_id := c.GetString("T_task_id")
+	jpg, is := Device.Redis_DeviceDataJPG_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 *TaskController) 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_task_id := c.GetString("T_task_id")
+	Task_r, is := Task.Read_Task(T_task_id)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_task_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+	if Task_r.T_collection_state == 2 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "数据采集中,请稍后!"}
+		c.ServeJSON()
+		return
+	}
+
+	deviceClassList, _ := Device.Read_DeviceClassList_OrderList(Task_r.T_class, "", 0, 9999)
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_class 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	Device.Redis_DeviceDataJPG_Del(T_task_id)
+
+	// 生成图片
+	go DeviceDataJPG(StartTime, EndTime, T_task_id, deviceClassList, TemperatureMin, TemperatureMax)
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 存档生成图片
+func DeviceDataJPG(StartTime, EndTime, T_task_id string, deviceList []Device.DeviceClassList, TemperatureMin, TemperatureMax float64) {
+	Device.Redis_DeviceDataJPG_Set(T_task_id, Device.DeviceDataJPG{
+		State: 1,
+		Msg:   "图片生成中",
+		Url:   "",
+	})
+	msg := ""
+	state := 2
+	url := ""
+
+	if TemperatureMin == 0 {
+		TemperatureMin = 2
+	}
+	if TemperatureMax == 0 {
+		TemperatureMax = 8
+	}
+	var ymin, ymax float64
+	var xminT, xmaxT time.Time
+	if len(deviceList) > 0 {
+		ymin, ymax, xminT, xmaxT = Device.Read_DeviceData_T_Min_Max_Time_Min_Max(deviceList[0].T_sn, StartTime, EndTime)
+	}
+
+	// 创建一个新的绘图
+	p := plot.New()
+
+	// 设置绘图标题和标签
+	p.Title.Text = "温度折线图"
+	//p.Legend.ThumbnailWidth = 5 * vg.Inch
+	p.X.Label.Text = "时间"
+	p.Y.Label.Text = "温度"
+
+	var chData = make(chan int, 10)
+	var jobGroup sync.WaitGroup
+	var device = make([]Device.DeviceCount, len(deviceList))
+
+	// 创建温度线
+	for i := 0; i < len(deviceList); i++ {
+		chData <- 1
+		jobGroup.Add(1)
+		go func(index int) {
+			//go func(index int, wg *sync.WaitGroup, p *plot.Plot) {
+			defer func() {
+				<-chData        // 完成时chan取出1个
+				jobGroup.Done() // 完成时将等待组值减1
+			}()
+			sn, id := deviceList[index].T_sn, deviceList[index].T_id
+			ymin_, ymax_, minTime_, maxTime_ := Device.Read_DeviceData_T_Min_Max_Time_Min_Max(sn, StartTime, EndTime)
+
+			if ymin > ymin_ {
+				ymin = ymin_
+			}
+			if ymax < ymax_ {
+				ymax = ymax_
+			}
+			if minTime_.Unix() < 0 {
+				fmt.Println(minTime_)
+			}
+
+			if xminT.After(minTime_) {
+				xminT = minTime_
+			}
+
+			if xmaxT.Before(maxTime_) {
+				xmaxT = maxTime_
+			}
+
+			r_maps, r_maps_num := Device.Read_DeviceSensorData_ById_List(sn, StartTime, EndTime, 0, 9999)
+			device[index] = Device.DeviceCount{
+				T_id: id,
+				Num:  r_maps_num,
+			}
+			if r_maps_num == 0 {
+				return
+			}
+
+			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()
+
+	xmin, xmax := float64(xminT.Unix()), float64(xmaxT.Unix())
+	// 添加最高,最低标准线 用红色虚线标识
+	p.Add(horizontalLine(xmin, xmax, TemperatureMin))
+
+	p.Add(horizontalLine(xmin, xmax, TemperatureMax))
+
+	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 {
+		Device.Redis_DeviceDataJPG_Set(T_task_id, Device.DeviceDataJPG{
+			State: 3,
+			Msg:   "图片生成失败",
+			Url:   url,
+		})
+		logs.Error(lib.FuncName(), "生成图片失败", err)
+		return
+	}
+	if !lib.Pload_qiniu("ofile/"+filename+".jpg", "ofile/"+filename+".jpg") {
+		Device.Redis_DeviceDataJPG_Set(T_task_id, Device.DeviceDataJPG{
+			State: 3,
+			Msg:   "图片上传七牛云失败",
+			Url:   url,
+		})
+		logs.Error(lib.FuncName(), "上传七牛云失败")
+		return
+	}
+	//删除目录
+	os.Remove("ofile/" + filename + ".jpg")
+
+	msg = "图片生成成功"
+	url = "https://bzdcoldverifyoss.baozhida.cn/" + "ofile/" + filename + ".jpg"
+
+	Device.Redis_DeviceDataJPG_Set(T_task_id, Device.DeviceDataJPG{
+		State:  state,
+		Msg:    msg,
+		Url:    url,
+		Device: device,
+	})
+	return
+
+}
+
+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)]
+}

+ 7 - 7
controllers/User.go

@@ -88,13 +88,13 @@ func (c *UserController) Add() {
 		return
 	}
 
-	T_power, _ := c.GetInt("T_power")
+	//T_power, _ := c.GetInt("T_power")
 	T_name := c.GetString("T_name")
 	T_pass := c.GetString("T_pass")
 	T_passstr := c.GetString("T_passstr")
 
 	var_ := Account.User{
-		T_power:   T_power,
+		//T_power:   T_power,
 		T_name:    T_name,
 		T_pass:    T_pass,
 		T_passstr: T_passstr,
@@ -131,7 +131,7 @@ func (c *UserController) Up() {
 		return
 	}
 
-	T_power, T_power_err := c.GetInt("T_power")
+	//T_power, T_power_err := c.GetInt("T_power")
 	T_name := c.GetString("T_name")
 	T_pass := c.GetString("T_pass")
 	T_passstr := c.GetString("T_passstr")
@@ -151,9 +151,9 @@ func (c *UserController) Up() {
 	}
 
 	// .......
-	if T_power_err == nil {
-		r.T_power = T_power
-	}
+	//if T_power_err == nil {
+	//	r.T_power = T_power
+	//}
 	if len(T_name) > 0 {
 		r.T_name = T_name
 	}
@@ -168,7 +168,7 @@ func (c *UserController) Up() {
 	}
 
 	// .......
-	if !Account.Update_User(r, "T_power", "T_name", "T_pass", "T_passstr", "T_Show") {
+	if !Account.Update_User(r, "T_name", "T_pass", "T_passstr", "T_Show") {
 		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
 		c.ServeJSON()
 		return

+ 19 - 9
go.mod

@@ -6,25 +6,35 @@ require (
 	github.com/astaxie/beego v1.12.3
 	github.com/beego/beego/v2 v2.0.7
 	github.com/go-sql-driver/mysql v1.7.0
+	github.com/nats-io/nats.go v1.27.0
 	github.com/qiniu/go-sdk/v7 v7.14.0
 	github.com/satori/go.uuid v1.2.0
 	github.com/signintech/gopdf v0.15.1
+	github.com/vmihailenco/msgpack/v5 v5.3.5
 	github.com/xuri/excelize/v2 v2.7.0
+	gonum.org/v1/plot v0.13.0
 )
 
 require (
+	git.sr.ht/~sbinet/gg v0.4.1 // indirect
+	github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b // indirect
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/cespare/xxhash/v2 v2.1.2 // indirect
+	github.com/go-fonts/liberation v0.3.1 // indirect
+	github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9 // indirect
+	github.com/go-pdf/fpdf v0.8.0 // indirect
+	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
 	github.com/golang/protobuf v1.5.2 // indirect
 	github.com/gomodule/redigo v2.0.0+incompatible // indirect
 	github.com/hashicorp/golang-lru v0.5.4 // indirect
+	github.com/klauspost/compress v1.16.5 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
 	github.com/mitchellh/mapstructure v1.5.0 // indirect
 	github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect
-	github.com/nats-io/nats.go v1.24.0 // indirect
-	github.com/nats-io/nkeys v0.3.0 // indirect
+	github.com/nats-io/nats-server/v2 v2.9.20 // indirect
+	github.com/nats-io/nkeys v0.4.4 // indirect
 	github.com/nats-io/nuid v1.0.1 // indirect
-	github.com/phpdave11/gofpdi v1.0.11 // indirect
+	github.com/phpdave11/gofpdi v1.0.13 // indirect
 	github.com/pkg/errors v0.9.1 // indirect
 	github.com/prometheus/client_golang v1.14.0 // indirect
 	github.com/prometheus/client_model v0.3.0 // indirect
@@ -33,15 +43,15 @@ require (
 	github.com/richardlehane/mscfb v1.0.4 // indirect
 	github.com/richardlehane/msoleps v1.0.3 // indirect
 	github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
-	github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
 	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
 	github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 // indirect
 	github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect
-	golang.org/x/crypto v0.5.0 // indirect
-	golang.org/x/net v0.5.0 // indirect
-	golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 // indirect
-	golang.org/x/sys v0.4.0 // indirect
-	golang.org/x/text v0.6.0 // indirect
+	golang.org/x/crypto v0.9.0 // indirect
+	golang.org/x/image v0.7.0 // indirect
+	golang.org/x/net v0.10.0 // indirect
+	golang.org/x/sync v0.1.0 // indirect
+	golang.org/x/sys v0.8.0 // indirect
+	golang.org/x/text v0.9.0 // indirect
 	google.golang.org/protobuf v1.28.1 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gopkg.in/yaml.v3 v3.0.1 // indirect

+ 60 - 12
go.sum

@@ -31,9 +31,16 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
 cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
 cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
+git.sr.ht/~sbinet/cmpimg v0.1.0 h1:E0zPRk2muWuCqSKSVZIWsgtU9pjsw3eKHi8VmQeScxo=
+git.sr.ht/~sbinet/gg v0.4.1 h1:YccqPPS57/TpqX2fFnSRlisrqQ43gEdqVm3JtabPrp0=
+git.sr.ht/~sbinet/gg v0.4.1/go.mod h1:xKrQ22W53kn8Hlq+gzYeyyohGMwR8yGgSMlVpY/mHGc=
 github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
 github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
 github.com/Knetic/govaluate v3.0.0+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0=
+github.com/ajstarks/deck v0.0.0-20200831202436-30c9fc6549a9/go.mod h1:JynElWSGnm/4RlzPXRlREEwqTHAN3T56Bv2ITsFT3gY=
+github.com/ajstarks/deck/generate v0.0.0-20210309230005-c3f852c02e19/go.mod h1:T13YZdzov6OU0A1+RfKZiZN9ca6VeKdBdyDV+BY97Tk=
+github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b h1:slYM766cy2nI3BwyRiyQj/Ud48djTMtMebDqepE95rw=
+github.com/ajstarks/svgo v0.0.0-20211024235047-1546f124cd8b/go.mod h1:1KcenG0jGWcpt8ov532z81sp/kMMUG485J2InIOyADM=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -81,6 +88,10 @@ github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1m
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
 github.com/glendc/gopher-json v0.0.0-20170414221815-dc4743023d0c/go.mod h1:Gja1A+xZ9BoviGJNA2E9vFkPjjsl+CoJxSXiQM1UXtw=
+github.com/go-fonts/dejavu v0.1.0 h1:JSajPXURYqpr+Cu8U9bt8K+XcACIHWqWrvWCKyeFmVQ=
+github.com/go-fonts/latin-modern v0.3.1 h1:/cT8A7uavYKvglYXvrdDw4oS5ZLkcOU22fa2HJ1/JVM=
+github.com/go-fonts/liberation v0.3.1 h1:9RPT2NhUpxQ7ukUvz3jeUckmN42T9D9TpjtQcqK/ceM=
+github.com/go-fonts/liberation v0.3.1/go.mod h1:jdJ+cqF+F4SUL2V+qxBth8fvBpBDS7yloUL5Fi8GTGY=
 github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
 github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -88,10 +99,14 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
 github.com/go-kit/kit v0.9.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
 github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY=
 github.com/go-kit/log v0.2.0/go.mod h1:NwTd00d/i8cPZ3xOwwiv2PO5MOcx78fFErGNcVmBjv0=
+github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9 h1:NxXI5pTAtpEaU49bpLpQoDsu1zrteW/vxzTz8Cd2UAs=
+github.com/go-latex/latex v0.0.0-20230307184459-12ec69307ad9/go.mod h1:gWuR/CrFDDeVRFQwHPvsv9soJVB/iqymhuZQuJ3a9OM=
 github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
 github.com/go-logfmt/logfmt v0.5.1/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs=
+github.com/go-pdf/fpdf v0.8.0 h1:IJKpdaagnWUeSkUFUjTcSzTppFxmv8ucGQyNPQWxYOQ=
+github.com/go-pdf/fpdf v0.8.0/go.mod h1:gfqhcNwXrsd3XYKte9a7vM3smvU/jB4ZRDrmWSxpfdc=
 github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
 github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
 github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
@@ -104,6 +119,8 @@ github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ
 github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
 github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
 github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
 github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
 github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
 github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
@@ -177,6 +194,8 @@ github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/X
 github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
 github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
 github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
+github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI=
+github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
 github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
 github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
@@ -196,6 +215,7 @@ github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJK
 github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
 github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
 github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
+github.com/minio/highwayhash v1.0.2 h1:Aak5U0nElisjDCfPSG79Tgzkn2gl66NxOMspRrKnA/g=
 github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
@@ -207,10 +227,13 @@ github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9
 github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8=
 github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
 github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
-github.com/nats-io/nats.go v1.24.0 h1:CRiD8L5GOQu/DcfkmgBcTTIQORMwizF+rPk6T0RaHVQ=
-github.com/nats-io/nats.go v1.24.0/go.mod h1:dVQF+BK3SzUZpwyzHedXsvH3EO38aVKuOPkkHlv5hXA=
-github.com/nats-io/nkeys v0.3.0 h1:cgM5tL53EvYRU+2YLXIK0G2mJtK12Ft9oeooSZMA2G8=
-github.com/nats-io/nkeys v0.3.0/go.mod h1:gvUNGjVcM2IPr5rCsRsC6Wb3Hr2CQAm08dsxtV6A5y4=
+github.com/nats-io/jwt/v2 v2.4.1 h1:Y35W1dgbbz2SQUYDPCaclXcuqleVmpbRa7646Jf2EX4=
+github.com/nats-io/nats-server/v2 v2.9.20 h1:bt1dW6xsL1hWWwv7Hovm+EJt5L6iplyqlgEFkoEUk0k=
+github.com/nats-io/nats-server/v2 v2.9.20/go.mod h1:aTb/xtLCGKhfTFLxP591CMWfkdgBmcUUSkiSOe5A3gw=
+github.com/nats-io/nats.go v1.27.0 h1:3o9fsPhmoKm+yK7rekH2GtWoE+D9jFbw8N3/ayI1C00=
+github.com/nats-io/nats.go v1.27.0/go.mod h1:XpbWUlOElGwTYbMR7imivs7jJj9GtK7ypv321Wp6pjc=
+github.com/nats-io/nkeys v0.4.4 h1:xvBJ8d69TznjcQl9t6//Q5xXuVhyYiSos6RPtvQNTwA=
+github.com/nats-io/nkeys v0.4.4/go.mod h1:XUkxdLPTufzlihbamfzQ7mw/VGx6ObUs+0bN5sNvt64=
 github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw=
 github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c=
 github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
@@ -220,8 +243,9 @@ github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7J
 github.com/pelletier/go-toml v1.0.1/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
 github.com/peterh/liner v1.0.1-0.20171122030339-3681c2a91233/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc=
-github.com/phpdave11/gofpdi v1.0.11 h1:wsBNx+3S0wy1dEp6fzv281S74ogZGgIdYWV2PugWgho=
 github.com/phpdave11/gofpdi v1.0.11/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
+github.com/phpdave11/gofpdi v1.0.13 h1:o61duiW8M9sMlkVXWlvP92sZJtGKENvW3VExs6dZukQ=
+github.com/phpdave11/gofpdi v1.0.13/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
 github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
 github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -310,6 +334,7 @@ github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22/go.mod h1:WwHg+CVyzlv/TX9
 github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
+github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
 github.com/yuin/gopher-lua v0.0.0-20171031051903-609c9cd26973/go.mod h1:aEV29XrmTYFr3CiRxZeGHpkvbwq+prZduBqMaascyCU=
 go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
@@ -323,11 +348,11 @@ golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8U
 golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
 golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
 golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
+golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
+golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -338,10 +363,12 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
 golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
 golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
 golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
+golang.org/x/exp v0.0.0-20230510235704-dd950f8aeaea h1:vLCWI/yYrdEHyN2JzIzPO3aaQJHQdp89IZBA/+azVC4=
 golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
 golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
-golang.org/x/image v0.0.0-20220902085622-e7cb96979f69 h1:Lj6HJGCSn5AjxRAH2+r35Mir4icalbqku+CLUtjnvXY=
 golang.org/x/image v0.0.0-20220902085622-e7cb96979f69/go.mod h1:doUCurBvlfPMKfmIpRIywoHmhN3VyhnoFDbvIEWF4hY=
+golang.org/x/image v0.7.0 h1:gzS29xtG1J5ybQlv0PuyfE3nmc6R4qB73m6LUUmvFuw=
+golang.org/x/image v0.7.0/go.mod h1:nd/q4ef1AKKYl/4kft7g+6UyGbdiqWqTP1ZAbRoV7Rg=
 golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
 golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
 golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -361,6 +388,7 @@ golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzB
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
+golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
 golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -390,13 +418,16 @@ golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/
 golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
+golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
-golang.org/x/net v0.5.0 h1:GyT4nK/YDHSqa1c4753ouYCDajOYKTja9Xb/OHtgvSw=
 golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
+golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -412,9 +443,11 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
 golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -448,7 +481,9 @@ golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -459,11 +494,14 @@ golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.4.0 h1:Zr2JFtRQNX3BCZ8YtxRE9hNJYC8J6I1MVbMg6owUp18=
 golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
+golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -471,11 +509,14 @@ golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.6.0 h1:3XmdazWV+ubf7QgHSTWeykHOci5oeekaGJBLkrkaw4k=
 golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
+golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
 golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
+golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
@@ -516,11 +557,16 @@ golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roY
 golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
 golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
 golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
+golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
+golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+gonum.org/v1/gonum v0.13.0 h1:a0T3bh+7fhRyqeNbiC3qVHYmkiQgit3wnNan/2c0HMM=
+gonum.org/v1/plot v0.13.0 h1:yb2Z/b8bY5h/xC4uix+ujJ+ixvPUvBmUOtM73CJzpsw=
+gonum.org/v1/plot v0.13.0/go.mod h1:mV4Bpu4PWTgN2CETURNF8hCMg7EtlZqJYCcmYo/t4Co=
 google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
 google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
 google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
@@ -628,6 +674,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
 honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
 honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
 honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
+honnef.co/go/tools v0.1.3/go.mod h1:NgwopIslSNH47DimFoV78dnkksY2EFtX0ajyb3K/las=
 rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
+rsc.io/pdf v0.1.1 h1:k1MczvYDUvJBe93bYd7wrZLLUEcLZAuF824/I4e5Xr4=
 rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
 rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=

+ 21 - 2
lib/libString.go

@@ -6,7 +6,7 @@ import (
 	"time"
 )
 
-//#取得随机字符串:通过打乱slice来操作
+// #取得随机字符串:通过打乱slice来操作
 func GetRandstring(length int, char string, rand_x int64) string {
 	if length < 1 {
 		return ""
@@ -34,4 +34,23 @@ func IsDateStr(date string) bool {
 		return false
 	}
 	return true
-}
+}
+
+// 转化
+func TimeStrToTime(T_time string) (time.Time, bool) {
+	stamp, err := time.ParseInLocation("2006-01-02 15:04:05", T_time, time.Local) // +8
+	if err != nil {
+		return time.Time{}, false
+	}
+
+	return stamp, true
+}
+
+func TimeStrToTime2(T_time string) (time.Time, bool) {
+	stamp, err := time.ParseInLocation("2006-01-02 15:04:05", T_time, time.Local) // +8
+	if err != nil {
+		return time.Time{}, false
+	}
+
+	return stamp, true
+}

+ 6 - 6
models/Account/User.go

@@ -12,9 +12,9 @@ import (
 )
 
 type User struct {
-	Id         int       `orm:"column(ID);size(11);auto;pk"`
-	T_uuid     string    `orm:"size(256);null"`                                        //
-	T_power    int       `orm:"size(2);default(0)"`                                    // 权限
+	Id     int    `orm:"column(ID);size(11);auto;pk"`
+	T_uuid string `orm:"size(256);null"` //
+	//T_power    int       `orm:"size(2);default(0)"`                                    // 权限
 	T_name     string    `orm:"size(256);null"`                                        // 某某公司名称
 	T_pass     string    `orm:"size(256);null"`                                        // 密码 MD5
 	T_passstr  string    `orm:"size(256);null"`                                        // 密码明文
@@ -24,8 +24,8 @@ type User struct {
 	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now_add 第一次保存时才设置时间
 }
 type User_R struct {
-	T_uuid    string //
-	T_power   int    // 权限
+	T_uuid string //
+	//T_power   int    // 权限
 	T_name    string // 某某公司名称
 	T_passstr string // 密码明文
 	T_Show    int    //  0  1
@@ -45,7 +45,7 @@ func init() {
 // -------------------------------------------------------------
 func UserToUser_R(T User) (T_r User_R) {
 	T_r.T_uuid = T.T_uuid
-	T_r.T_power = T.T_power
+	//T_r.T_power = T.T_power
 	T_r.T_name = T.T_name
 	T_r.T_passstr = T.T_passstr
 	T_r.T_Show = T.T_Show

+ 100 - 4
models/Device/DeviceData.go

@@ -34,11 +34,15 @@ func (t *DeviceData) TableName() string {
 }
 
 var redisCache_DeviceData cache.Cache
+var redisCache_DeviceDataJPG cache.Cache
 
 func init() {
 
 	config := fmt.Sprintf(`{"key":"%s","conn":"%s","dbNum":"%s","password":"%s"}`,
 		"redis_DeviceData", conf.Redis_address, conf.Redis_dbNum, conf.Redis_password)
+
+	configJPG := fmt.Sprintf(`{"key":"%s","conn":"%s","dbNum":"%s","password":"%s"}`,
+		"redis_DeviceDataJPG", conf.Redis_address, conf.Redis_dbNum, conf.Redis_password)
 	fmt.Println(config)
 	var err error
 	redisCache_DeviceData, err = cache.NewCache("redis", config)
@@ -47,6 +51,13 @@ func init() {
 		fmt.Println(errMsg, err)
 
 	}
+
+	redisCache_DeviceDataJPG, err = cache.NewCache("redis", configJPG)
+	if err != nil || redisCache_DeviceDataJPG == nil {
+		errMsg := "failed to init redis"
+		fmt.Println(errMsg, err)
+
+	}
 }
 
 func DeviceData_Set(key string) (err error) {
@@ -84,6 +95,52 @@ func RedisDeviceData_Get(key string) (r DeviceData_New, is bool) {
 	return r, true
 }
 
+type DeviceCount struct {
+	T_id string `json:"T_id"`
+	Num  int    `json:"Num"`
+}
+
+type DeviceDataJPG struct {
+	State  int           `json:"State"` //1:生成中 2:已完成 3:失败
+	Msg    string        `json:"Msg"`
+	Url    string        `json:"Url"` //url
+	Device []DeviceCount `json:"Device"`
+}
+
+// ---------------- Redis -------------------
+// Redis_Set(m.T_sn,m) // Redis 更新缓存
+func Redis_DeviceDataJPG_Set(key string, r DeviceDataJPG) (err error) {
+	//json序列化
+	str, err := json.Marshal(r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+	err = redisCache_DeviceDataJPG.Put(key, str, 5*time.Minute)
+	if err != nil {
+		logs.Println("set key:", key, ",value:", str, err)
+	}
+	return
+}
+
+// if r,is :=Redis_Get(T_sn);is{
+// return r,nil
+// }
+func Redis_DeviceDataJPG_Get(key string) (r DeviceDataJPG, is bool) {
+	if redisCache_DeviceDataJPG.IsExist(key) {
+		logs.Println("找到key:", key)
+		v := redisCache_DeviceDataJPG.Get(key)
+		json.Unmarshal(v.([]byte), &r)
+		return r, true
+	}
+	logs.Println("没有 找到key:", key)
+	return DeviceDataJPG{}, false
+}
+func Redis_DeviceDataJPG_Del(key string) (err error) {
+	err = redisCache_DeviceDataJPG.Delete(key)
+	return
+}
+
 // 创建数据库  Device.CREATE_DeviceData("")
 func CREATE_DeviceData(SN string) bool {
 	o := orm.NewOrm()
@@ -170,7 +227,7 @@ type DeviceData_New struct {
 	T_time time.Time `orm:"column(t_time);type(timestamp);null;"` // 采集时间
 }
 
-func Read_DeviceSensorData_ById_List(SN string, T_id int, Time_start_ string, Time_end_ string, page int, page_z int) ([]DeviceData_, int) {
+func Read_DeviceSensorData_ById_List(SN string, Time_start_ string, Time_end_ string, page int, page_z int) ([]DeviceData_, int) {
 	o := orm.NewOrm()
 	var maps []DeviceData_
 	var maps_z []orm2.ParamsList
@@ -194,7 +251,14 @@ func Read_DeviceSensorData_ById_List(SN string, T_id int, Time_start_ string, Ti
 		sql_time += " t_time <= '" + Time_end_ + "' AND "
 	}
 
-	sql := "SELECT COUNT(ID) FROM z_devicedata_" + SN + " WHERE " + sql_time + " t_id = " + strconv.Itoa(T_id)
+	if len(sql_time) > 0 {
+		sql_time = strings.TrimRight(sql_time, "AND ")
+	}
+
+	sql := "SELECT COUNT(ID) FROM z_devicedata_" + SN
+	if len(sql_time) > 0 {
+		sql += " WHERE " + sql_time
+	}
 	fmt.Println(sql)
 	_, err := o.Raw(sql).ValuesList(&maps_z)
 	if err != nil {
@@ -204,7 +268,11 @@ func Read_DeviceSensorData_ById_List(SN string, T_id int, Time_start_ string, Ti
 		return maps, 0
 	}
 	//fmt.Println("maps_z;",maps_z[0][0])
-	sql = "SELECT t_name,t_id,t_t,t_rh,t_tl,t_tu,t_rhl,t_rhu,t_site,DATE_FORMAT(t_time,'%Y-%c-%d %H:%i:%s') AS t_time  FROM z_devicedata_" + SN + " WHERE " + sql_time + " t_id = " + strconv.Itoa(T_id) + " ORDER BY t_time DESC "
+	sql = "SELECT t_id,t_t,t_rh,DATE_FORMAT(t_time,'%Y-%m-%d %H:%i:%s') AS t_time  FROM z_devicedata_" + SN
+	if len(sql_time) > 0 {
+		sql += " WHERE " + sql_time
+	}
+	sql += " ORDER BY t_time"
 	if page_z != 9999 {
 		sql = sql + " LIMIT " + strconv.Itoa(offset) + "," + strconv.Itoa(pagez)
 	}
@@ -383,7 +451,7 @@ func Read_DeviceSensorData_By_T_snid_List(T_snid string, Time_start_ string, Tim
 		sn_id := strings.Split(v, ",")
 
 		if len(sn_id) == 2 {
-			r_maps, r_maps_num := Read_DeviceSensorData_ById_List(sn_id[0], lib.To_int(sn_id[1]), Time_start_, Time_end_, 0, 9999)
+			r_maps, r_maps_num := Read_DeviceSensorData_ById_List(sn_id[0], Time_start_, Time_end_, 0, 9999)
 			maps = append(maps, r_maps...)
 			maps_num = maps_num + r_maps_num
 
@@ -476,3 +544,31 @@ func Read_DeviceSensorData_List_GROUP_BY_t_time(SN string, Time_start_ string, T
 	o.Raw(sql).ValuesList(&maps_z)
 	return maps_z
 }
+
+func Read_DeviceData_T_Min_Max_Time_Min_Max(SN string, Time_start_ string, Time_end_ string) (minT, maxT float64, minTime, maxTime time.Time) {
+	o := orm.NewOrm()
+
+	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_ + "'"
+	}
+
+	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_" + SN + sql_condition
+
+	fmt.Println(sql)
+	err := o.Raw(sql).QueryRow(&minT, &maxT, &minTime, &maxTime)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+	return
+
+}

+ 4 - 4
models/Task/Task.go

@@ -28,7 +28,7 @@ type Task struct {
 	T_reporting            string `orm:"size(256);null"`       // 报告编写 负责人UUID
 	T_delivery             string `orm:"size(256);null"`       // 交付审核 负责人UUID
 	T_scheme_state         int    `orm:"size(2);default(0)"`   // 实施方案 状态 0 未完成 1 已完成
-	T_collection_state     int    `orm:"size(2);default(0)"`   // 数据采集 状态 0 未完成 1 已完成 2 处理中 3 已采集-无数据
+	T_collection_state     int    `orm:"size(2);default(0)"`   // 数据采集 状态 0 未完成 1 数据来源已完成 2 处理中 3 已采集-无数据 4-数据编辑已完成
 	T_reporting_state      int    `orm:"size(2);default(0)"`   // 报告编写 状态 0 未完成 1 已完成
 	T_delivery_state       int    `orm:"size(2);default(0)"`   // 交付审核 状态 0 未完成 1 已完成 2 处理中
 
@@ -230,7 +230,7 @@ func Read_Task(T_task_id string) (r Task, is bool) {
 	o := orm.NewOrm()
 	qs := o.QueryTable(new(Task))
 	//err := qs.Filter("T_task_id", T_task_id).Filter("T_State", 1).One(&r)
-	err := qs.Filter("T_task_id", T_task_id).One(&r)
+	err := qs.Filter("T_task_id", T_task_id).Filter("T_State", 1).One(&r)
 	if err != nil {
 		return r, false
 	}
@@ -375,7 +375,7 @@ func Read_UserTask_List(T_uuid string, T_name string, userMap, adminMap map[stri
 	}
 	cond := orm.NewCondition()
 	//cond1 := cond.And("T_name__icontains", T_name).And("T_State", 1)
-	cond1 := cond.And("T_name__icontains", T_name).And("T_Show", 1)
+	cond1 := cond.And("T_name__icontains", T_name).And("T_Show", 1).And("T_State", 1)
 	if len(T_uuid) > 0 {
 		cond1 = cond1.And("T_uuid", T_uuid)
 	}
@@ -407,7 +407,7 @@ func Read_Task_List(T_uuid, T_admin string, T_name string, userMap, adminMap map
 	}
 	cond := orm.NewCondition()
 	//cond1 := cond.And("T_name__icontains", T_name).And("T_State", 1)
-	cond1 := cond.And("T_name__icontains", T_name)
+	cond1 := cond.And("T_name__icontains", T_name).And("T_State", 1)
 	if len(T_uuid) > 0 {
 		cond1 = cond1.And("T_uuid", T_uuid)
 

+ 3 - 0
routers/Task.go

@@ -40,4 +40,7 @@ func init() {
 	beego.Router("/UserTask/List", &controllers.TaskController{}, "*:UserTaskList")              // 公司用户任务列表
 	beego.Router("/UserTaskData/List", &controllers.TaskDataController{}, "*:UserTaskData_List") // 公司用户任务数据列表
 
+	beego.Router("/Task/jpg", &controllers.TaskController{}, "*:DeviceData_JPG")            // 任务生成图片
+	beego.Router("/Task/JPG/State", &controllers.TaskController{}, "*:DeviceData_JPGState") // 任务 图片生成状态
+
 }