Browse Source

ADD:更新校准证书与布局编号关联

zoie 10 months ago
parent
commit
68924bc867

+ 71 - 1
Nats/NatsServer/NatsServer.go

@@ -4,6 +4,8 @@ import (
 	"ColdVerify_local/conf"
 	"ColdVerify_local/lib"
 	"ColdVerify_local/logs"
+	"ColdVerify_local/models/Account"
+	"ColdVerify_local/models/Device"
 	"ColdVerify_local/models/Task"
 	"errors"
 	"github.com/nats-io/nats.go"
@@ -46,7 +48,7 @@ func Update_Task(v Task.Task) error {
 func Read_Task(T_task_id string) (task Task.Task, err error) {
 	logs.Println("Nats =>", lib.FuncName(), T_task_id)
 
-	if !lib.Nats.IsConnected() {
+	if lib.Nats == nil || !lib.Nats.IsConnected() {
 		lib.Nats, err = nats.Connect("nats://" + conf.NatsServer_Url)
 		if err != nil {
 			logs.Println("无法重新连接到 NATS:", err)
@@ -81,3 +83,71 @@ func Read_Task(T_task_id string) (task Task.Task, err error) {
 	return t_R.Data, nil
 
 }
+func Read_User(T_uuid string) (user Account.User, err error) {
+	logs.Println("Nats =>", lib.FuncName(), T_uuid)
+
+	msg, err := lib.Nats.Request("ColdVerify_Server_Read_User", []byte(T_uuid), 3*time.Second)
+	if err != nil {
+		logs.Error(lib.FuncName(), err.Error())
+		return user, err
+	}
+
+	type T_R struct {
+		Code int16        `xml:"Code"`
+		Msg  string       `xml:"Msg"`
+		Data Account.User `xml:"Data"`
+	}
+	var t_R T_R
+
+	err = msgpack.Unmarshal(msg.Data, &t_R)
+	if err != nil {
+		logs.Error(lib.FuncName(), err.Error())
+		return user, err
+	}
+	if t_R.Code != 200 {
+		err = errors.New(t_R.Msg)
+		logs.Error(lib.FuncName(), err.Error())
+		return user, err
+	}
+
+	return t_R.Data, nil
+
+}
+func Device_Class_List(T_task_id string) (list []Device.DeviceClassList, err error) {
+	logs.Println("Nats =>", lib.FuncName(), T_task_id)
+
+	if !lib.Nats.IsConnected() {
+		lib.Nats, err = nats.Connect("nats://" + conf.NatsServer_Url)
+		if err != nil {
+			logs.Println("无法重新连接到 NATS:", err)
+		}
+		logs.Println("成功重新连接到 NATS...")
+	}
+
+	msg, err := lib.Nats.Request("ColdVerify_Server_Device_Class_List", []byte(T_task_id), 3*time.Second)
+	if err != nil {
+		logs.Error(lib.FuncName(), err.Error())
+		return list, err
+	}
+
+	type T_R struct {
+		Code int16                    `xml:"Code"`
+		Msg  string                   `xml:"Msg"`
+		Data []Device.DeviceClassList `xml:"Data"`
+	}
+	var t_R T_R
+
+	err = msgpack.Unmarshal(msg.Data, &t_R)
+	if err != nil {
+		logs.Error(lib.FuncName(), err.Error())
+		return list, err
+	}
+	if t_R.Code != 200 {
+		err = errors.New(t_R.Msg)
+		logs.Error(lib.FuncName(), err.Error())
+		return list, err
+	}
+
+	return t_R.Data, nil
+
+}

+ 196 - 0
controllers/TaskData.go

@@ -13,6 +13,7 @@ import (
 	"fmt"
 	"github.com/beego/beego/v2/client/orm"
 	beego "github.com/beego/beego/v2/server/web"
+	"github.com/signintech/gopdf"
 	"github.com/vmihailenco/msgpack/v5"
 	"github.com/xuri/excelize/v2"
 	"gonum.org/v1/plot"
@@ -21,6 +22,7 @@ import (
 	"gonum.org/v1/plot/vg/draw"
 	"math"
 	"os"
+	"sort"
 	"strconv"
 	"strings"
 	"sync"
@@ -62,8 +64,22 @@ func (c *TaskDataController) TaskData_List() {
 		return
 	}
 
+	dcList, err := NatsServer.Device_Class_List(T_task_id)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "获取设备列表失败!"}
+		c.ServeJSON()
+		return
+	}
+	// 保存布局编号和校准证书对应关系
+	var deviceCertificateMap = make(map[string]string) // t_id, T_Certificate_sn
+	for _, v := range dcList {
+		deviceCertificateMap[v.T_id] = v.T_Certificate_sn
+	}
 	var cnt int64
 	List, cnt := Task.Read_TaskData_ById_List(Task_r.T_task_id, T_sn, T_id, Time_start, Time_end, page, page_z)
+	for i := 0; i < len(List); i++ {
+		List[i].T_Certificate_sn = deviceCertificateMap[List[i].T_id]
+	}
 	page_size := math.Ceil(float64(cnt) / float64(page_z))
 	r_jsons.List = List
 	r_jsons.Page = page
@@ -75,6 +91,186 @@ func (c *TaskDataController) TaskData_List() {
 	c.ServeJSON()
 	return
 }
+func (c *TaskDataController) TaskData_Pdf() {
+
+	Time_start := c.GetString("Time_start")
+	Time_end := c.GetString("Time_end")
+	T_snid := c.GetString("T_snid")
+
+	T_task_id := c.GetString("T_task_id")
+	Task_r, err := NatsServer.Read_Task(T_task_id)
+	if err != nil {
+		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
+	}
+	user, err := NatsServer.Read_User(Task_r.T_uuid)
+	var T_snid_list []string
+	if len(T_snid) > 0 {
+		T_snid_list = strings.Split(strings.Trim(T_snid, "|"), "|")
+	}
+
+	dataMap := make(map[string]string)
+	timeMap := make(map[string]bool)
+	//classList := Task.Read_TaskData_ById_ClassList(Task_r.T_task_id)
+	//for _, i2 := range classList {
+	//	T_snid_list = append(T_snid_list, fmt.Sprintf("%s,%s", i2.T_sn, i2.T_id))
+	//}
+	for _, v := range T_snid_list {
+		sn_id := strings.Split(v, ",")
+		if len(sn_id) == 2 {
+			List, _ := Task.Read_TaskData_ById_List(Task_r.T_task_id, sn_id[0], sn_id[1], Time_start, Time_end, 0, 9999)
+
+			for _, data := range List {
+				k := fmt.Sprintf("%s,%s", data.T_time, data.T_id)
+				dataMap[k] = fmt.Sprintf("%.1f", data.T_t)
+				if _, ok := timeMap[data.T_time]; !ok {
+					timeMap[data.T_time] = true
+				}
+			}
+		}
+	}
+
+	var timeList []string
+	for k, _ := range timeMap {
+		timeList = append(timeList, k)
+	}
+	sort.Slice(timeList, func(i, j int) bool {
+		return timeList[i] < timeList[j]
+	})
+
+	pdf := &gopdf.GoPdf{}
+	pdf.Start(gopdf.Config{PageSize: gopdf.Rect{W: 595.28, H: 841.89}}) //595.28, 841.89 = A4
+
+	err = pdf.AddTTFFont("wts", "static/fonts/MiSans-Medium.ttf")
+	if err != nil {
+		return
+	}
+	err = pdf.SetFont("wts", "", 15)
+	if err != nil {
+		return
+	}
+
+	pdf.SetGrayFill(0.5)
+
+	pdf.SetMargins(0, 20, 0, 20)
+	pdf.AddPage()
+	imgH, _ := gopdf.ImageHolderByPath("./ofile/logo.jpg")
+	err = pdf.ImageByHolder(imgH, 10, 10, &gopdf.Rect{W: 93, H: 32})
+	name := user.T_name
+
+	var y float64 = 40
+	textw, _ := pdf.MeasureTextWidth(name)
+	pdf.SetX((595 / 2) - (textw / 2))
+	pdf.SetY(y)
+	pdf.Text(name)
+
+	y += 20
+	title := Task_r.T_name + "验证数据"
+	textw, _ = pdf.MeasureTextWidth(title)
+	pdf.SetX((595 / 2) - (textw / 2))
+	pdf.SetY(y)
+	pdf.Text(title)
+
+	if len(timeList) > 0 {
+		y += 20
+		timeStr := fmt.Sprintf("%s - %s", timeList[0], timeList[len(timeList)-1])
+		textw, _ = pdf.MeasureTextWidth(timeStr)
+		pdf.SetX((595 / 2) - (textw / 2))
+		pdf.SetY(y)
+		pdf.Text(timeStr)
+	}
+
+	err = pdf.SetFont("wts", "", 10)
+	if err != nil {
+		return
+	}
+
+	y += 20
+	var x float64 = 10
+	var w float64 = 120
+
+	chunks := chunkBy(T_snid_list, 15)
+	for _, list := range chunks {
+		x = 10
+		w = 120
+		lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+		x += w
+		w = 30
+		for _, v2 := range list {
+			sn_id2 := strings.Split(v2, ",")
+			id2 := sn_id2[1]
+			lib.RectFillColor(pdf, id2, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			x += w
+		}
+		y += 20
+
+		for _, t := range timeList {
+			x = 10
+			var textH float64 = 20 // if text height is 25px.
+			pdf.SetNewY(y, textH)
+			y = pdf.GetY()
+			if y == 20 {
+				w = 120
+				lib.RectFillColor(pdf, "时间", 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+				w = 30
+				for _, v2 := range list {
+					sn_id2 := strings.Split(v2, ",")
+					id2 := sn_id2[1]
+					lib.RectFillColor(pdf, id2, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+					x += w
+				}
+				y += 20
+				x = 10
+			}
+			w = 120
+			lib.RectFillColor(pdf, t, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+			x += w
+			w = 30
+			for _, v := range list {
+				sn_id := strings.Split(v, ",")
+				id := sn_id[1]
+				t_t := dataMap[fmt.Sprintf("%s,%s", t, id)]
+				lib.RectFillColor(pdf, t_t, 12, x, y, w, 20, 255, 255, 255, lib.AlignCenter, lib.ValignMiddle)
+				x += w
+			}
+			y += 20
+
+		}
+		y += 20
+	}
+	filename := time.Now().Format("20060102150405") + ".pdf"
+	timeStr := "ofile/" + filename
+
+	err = pdf.WritePdf(timeStr)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: err.Error()}
+		c.ServeJSON()
+		return
+	}
+
+	defer func() {
+		//删除目录
+		os.Remove(timeStr)
+	}()
+
+	c.Ctx.Output.Download(timeStr)
+
+}
+
+func chunkBy[T any](list []T, size int) [][]T {
+	var chunks [][]T
+	for size < len(list) {
+		list, chunks = list[size:], append(chunks, list[0:size:size])
+	}
+	return append(chunks, list)
+}
 
 // 列表 -
 func (c *TaskDataController) TaskDataClass_List() {

+ 16 - 0
models/Account/User.go

@@ -0,0 +1,16 @@
+package Account
+
+import "time"
+
+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)"`                                    // 权限
+	T_name     string    `orm:"size(256);null"`                                        // 某某公司名称
+	T_pass     string    `orm:"size(256);null"`                                        // 密码 MD5
+	T_passstr  string    `orm:"size(256);null"`                                        // 密码明文
+	T_Show     int       `orm:"size(200);default(1)"`                                  // 0隐藏  1公开
+	T_State    int       `orm:"size(200);default(1)"`                                  // 0删除  1正常
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now 每次 model 保存时都会对时间自动更新
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now_add 第一次保存时才设置时间
+}

+ 12 - 12
models/Certificate/Certificate.go

@@ -32,30 +32,30 @@ func Read_Certificate_List(T_task_id, T_sn string, page, page_z int) ([]Certific
 	}
 
 	var maps []Certificate_
-	snList := []string{}
-	sql := "SELECT t_sn FROM z_task_data_" + T_task_id + " GROUP BY t_sn"
+	idList := []string{}
+	sql := "SELECT t_id FROM z_task_data_" + T_task_id + " GROUP BY t_id"
 	fmt.Println(sql)
-	_, err := localOrm.Raw(sql).QueryRows(&snList)
+	_, err := localOrm.Raw(sql).QueryRows(&idList)
 
 	if err != nil {
 		logs.Error(lib.FuncName(), err)
 		return maps, 0
 	}
 
-	snListStr := ""
-	for _, id := range snList {
-		if snListStr != "" {
-			snListStr = snListStr + ","
+	idListStr := ""
+	for _, id := range idList {
+		if idListStr != "" {
+			idListStr = idListStr + ","
 		}
-		snListStr = snListStr + "'" + id + "'"
+		idListStr = idListStr + "'" + id + "'"
 	}
 
 	sql_condition := " t__state=1"
-	if len(snListStr) > 0 {
-		sql_condition += " AND t_sn not in (" + snListStr + ")"
+	if len(idListStr) > 0 {
+		sql_condition += " AND t_layout_no not in (" + idListStr + ")"
 	}
 	if len(T_sn) > 0 {
-		sql_condition += " AND t_sn='" + T_sn + "'"
+		sql_condition += " AND t_layout_no='" + T_sn + "'"
 	}
 
 	sql = "SELECT count(*) FROM certificate WHERE" + sql_condition
@@ -69,7 +69,7 @@ func Read_Certificate_List(T_task_id, T_sn string, page, page_z int) ([]Certific
 	//sql = "SELECT * FROM certificate WHERE t__state=1 AND t_sn not in (" + strings.Join(snList, ",") + ") ORDER BY t_layout_no"
 
 	// fixme 冷脸验证线上更新后再部署如下代码
-	sql = "SELECT * FROM certificate WHERE" + sql_condition
+	sql = "SELECT ID,t_layout_no FROM certificate WHERE" + sql_condition
 	if page_z != 9999 {
 		sql = sql + " LIMIT " + strconv.Itoa(offset) + "," + strconv.Itoa(pagez)
 	}

+ 20 - 0
models/Device/DeviceClassList.go

@@ -0,0 +1,20 @@
+package Device
+
+import "time"
+
+// 模板
+type DeviceClassList struct {
+	Id int `orm:"column(ID);size(11);auto;pk"`
+
+	T_class          int    `orm:"size(200);null"`  // 分类
+	T_id             string `orm:"size(20);null"`   // 设备id
+	T_sn             string `orm:"size(256);null"`  // 设备序列号 KF开头,环境监测主机。 YD开头,温途监测主机
+	T_failure_time   string `orm:"size(256);null"`  // 失效时间
+	T_pdf            string `orm:"size(256);null"`  // pdf链接
+	T_Certificate_sn string `orm:"size(256);null"`  // 证书编号
+	T_remark         string `orm:"size(1024);null"` // 备注
+
+	T_State    int       `orm:"size(2);default(1)"`                                    // 0 删除   1 正常
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}

+ 7 - 6
models/Task/TaskData.go

@@ -135,12 +135,13 @@ func Truncate_TaskData(alias_name, T_task_id string) bool {
 }
 
 type TaskData_ struct {
-	ID     int     `orm:"column(ID);size(100);null"`   // ID
-	T_sn   string  `orm:"column(t_sn);size(256);null"` // sn
-	T_id   string  `orm:"column(t_id);size(256);null"` // 标题
-	T_t    float32 `orm:"column(t_t);size(10);null"`   // 温度
-	T_rh   float32 `orm:"column(t_rh);size(10);null"`  // 湿度
-	T_time string  `orm:"column(t_times);null;"`       // 采集时间
+	ID               int     `orm:"column(ID);size(100);null"`   // ID
+	T_sn             string  `orm:"column(t_sn);size(256);null"` // sn
+	T_id             string  `orm:"column(t_id);size(256);null"` // 标题
+	T_t              float32 `orm:"column(t_t);size(10);null"`   // 温度
+	T_rh             float32 `orm:"column(t_rh);size(10);null"`  // 湿度
+	T_time           string  `orm:"column(t_times);null;"`       // 采集时间
+	T_Certificate_sn string  `orm:"size(256);null"`              // 证书编号
 }
 type TaskDataClass_ struct {
 	T_sn string `orm:"column(t_sn);size(256);null"` // 标题

+ 1 - 0
routers/TaskData.go

@@ -12,6 +12,7 @@ func init() {
 	beego.Router("/TaskData/TaskDataClass_Edit", &controllers.TaskDataController{}, "*:TaskDataClass_Edit")
 	beego.Router("/TaskData/TaskDataClass_Del", &controllers.TaskDataController{}, "*:TaskDataClass_Del")
 	beego.Router("/TaskData/List", &controllers.TaskDataController{}, "*:TaskData_List")
+	beego.Router("/TaskData/pdf", &controllers.TaskDataController{}, "*:TaskData_Pdf")
 	beego.Router("/TaskData/Add", &controllers.TaskDataController{}, "*:TaskData_Add")               //
 	beego.Router("/TaskData/AddS", &controllers.TaskDataController{}, "*:TaskData_AddS")             //
 	beego.Router("/TaskData/Up", &controllers.TaskDataController{}, "*:TaskData_Up")                 //