Browse Source

add:增加11个自动填写,修改冷热点数据自检、布点区域数据自检开始时间获取方式

zoie 1 month ago
parent
commit
ae5fddbd27
5 changed files with 1054 additions and 79 deletions
  1. 729 25
      controllers/TaskData.go
  2. 106 37
      controllers/TaskHandle.go
  3. 29 12
      models/Device/DeviceClassList.go
  4. 179 5
      models/Task/TaskData.go
  5. 11 0
      routers/TaskData.go

+ 729 - 25
controllers/TaskData.go

@@ -499,6 +499,25 @@ func (c *TaskDataController) TaskDataClass_List() {
 
 	List := Task.Read_TaskData_ById_ClassList(Task_r.T_task_id)
 
+	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]int) // t_id, T_Certificate_sn
+	for _, v := range dcList {
+		deviceCertificateMap[v.T_id] = v.T_terminal
+	}
+
+	for i := 0; i < len(List); i++ {
+		if terminal, ok := deviceCertificateMap[List[i].T_id]; ok {
+			List[i].T_terminal = terminal
+		}
+
+	}
+
 	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: List}
 	c.ServeJSON()
 	return
@@ -2910,6 +2929,10 @@ func (c *TaskDataController) ListJson() {
 		"空载测试结束风机停止时间",
 		"满载第一次关门温度恢复时间",
 		"空载第一次关门温度恢复时间",
+		"满载第二次关门温度恢复时间",
+		"空载第二次关门温度恢复时间",
+		"满载第三次关门温度恢复时间",
+		"空载第三次关门温度恢复时间",
 		"满载开门最长需要多少分钟恢复",
 		"空载开门最长需要多少分钟恢复",
 		"冷藏库作业口外部环境分割线最低温",
@@ -2938,6 +2961,13 @@ func (c *TaskDataController) ListJson() {
 		"监测系统配置的测点终端参数及安装位置确认(空载)结束时间",
 		"培训讲师",
 		"培训时间",
+		"作业出入口总测点",
+		"风机布点总测点",
+		"库内除风机出风口、回风口外总测点",
+		"库内除风机出风口、回风口、特殊位置布点、作业口外总测点",
+		"车内除风机出风口、回风口外总测点",
+		"预冷开始时间",
+		"预冷结束时间",
 	}
 
 	c.Data["json"] = mySlice
@@ -2983,7 +3013,11 @@ func (c *TaskDataController) A满载测试结束风机停止时间() {
 		return
 	}
 
-	list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, 均匀性布点, 开始时间, 结束时间)
+	// 获取数据波动最大的三条
+	initialData, _ := Task.Read_TaskData_ById_List_AES(Task_r.T_task_id, 均匀性布点, "", 开始时间, 结束时间, 0, 9999)
+	snList := Task.GetTopThreeWithTheGreatestFluctuations(initialData)
+
+	list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, snList, 开始时间, 结束时间)
 	fmt.Println("list:", list)
 	CalculateHumps_list := Task.CalculateHumps(list)
 
@@ -3044,7 +3078,10 @@ func (c *TaskDataController) A空载测试结束风机停止时间() {
 		return
 	}
 
-	list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, 均匀性布点, 开始时间, 结束时间)
+	// 获取数据波动最大的三条
+	initialData, _ := Task.Read_TaskData_ById_List_AES(Task_r.T_task_id, 均匀性布点, "", 开始时间, 结束时间, 0, 9999)
+	snList := Task.GetTopThreeWithTheGreatestFluctuations(initialData)
+	list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, snList, 开始时间, 结束时间)
 	CalculateHumps_list := Task.CalculateHumps(list)
 
 	if len(CalculateHumps_list) < 7 {
@@ -3099,7 +3136,9 @@ func (c *TaskDataController) A满载风机停止时间点() {
 		return
 	}
 
-	list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, 均匀性布点, 开始时间, 结束时间)
+	initialData, _ := Task.Read_TaskData_ById_List_AES(Task_r.T_task_id, 均匀性布点, "", 开始时间, 结束时间, 0, 9999)
+	snList := Task.GetTopThreeWithTheGreatestFluctuations(initialData)
+	list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, snList, 开始时间, 结束时间)
 	CalculateHumps_list := Task.CalculateHumps(list)
 
 	if len(CalculateHumps_list) == 0 {
@@ -3154,7 +3193,9 @@ func (c *TaskDataController) A空载风机停止时间点() {
 		return
 	}
 
-	list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, 均匀性布点, 开始时间, 结束时间)
+	initialData, _ := Task.Read_TaskData_ById_List_AES(Task_r.T_task_id, 均匀性布点, "", 开始时间, 结束时间, 0, 9999)
+	snList := Task.GetTopThreeWithTheGreatestFluctuations(initialData)
+	list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, snList, 开始时间, 结束时间)
 	CalculateHumps_list := Task.CalculateHumps(list)
 
 	if len(CalculateHumps_list) == 0 {
@@ -3208,7 +3249,9 @@ func (c *TaskDataController) A空载风机启动时间点() {
 		return
 	}
 
-	list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, 均匀性布点, 开始时间, 结束时间)
+	initialData, _ := Task.Read_TaskData_ById_List_AES(Task_r.T_task_id, 均匀性布点, "", 开始时间, 结束时间, 0, 9999)
+	snList := Task.GetTopThreeWithTheGreatestFluctuations(initialData)
+	list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, snList, 开始时间, 结束时间)
 	CalculateHumps_list := Task.CalculateHumps(list)
 
 	if len(CalculateHumps_list) == 0 {
@@ -3262,7 +3305,9 @@ func (c *TaskDataController) A满载风机启动时间点() {
 		return
 	}
 
-	list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, 均匀性布点, 开始时间, 结束时间)
+	initialData, _ := Task.Read_TaskData_ById_List_AES(Task_r.T_task_id, 均匀性布点, "", 开始时间, 结束时间, 0, 9999)
+	snList := Task.GetTopThreeWithTheGreatestFluctuations(initialData)
+	list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, snList, 开始时间, 结束时间)
 	CalculateHumps_list := Task.CalculateHumps(list)
 
 	if len(CalculateHumps_list) == 0 {
@@ -3544,7 +3589,13 @@ func (c *TaskDataController) A运行确认及偏差处理空载开始时间() {
 
 	柜内所有测点 := c.GetString("柜内所有测点") //  v26nplogbwt1
 	if len(柜内所有测点) == 0 {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜内所有测点 失败!"})
+		柜内所有测点 = c.GetString("库内所有测点")
+	}
+	if len(柜内所有测点) == 0 {
+		柜内所有测点 = c.GetString("车内所有测点")
+	}
+	if len(柜内所有测点) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜/库/车内所有测点 失败!"})
 		return
 	}
 	温度控制范围最高值_ := c.GetString("温度控制范围最高值") //  v26nplogbwt1
@@ -3628,7 +3679,13 @@ func (c *TaskDataController) A运行确认及偏差处理满载开始时间() {
 
 	柜内所有测点 := c.GetString("柜内所有测点") //  v26nplogbwt1
 	if len(柜内所有测点) == 0 {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜内所有测点 失败!"})
+		柜内所有测点 = c.GetString("库内所有测点")
+	}
+	if len(柜内所有测点) == 0 {
+		柜内所有测点 = c.GetString("车内所有测点")
+	}
+	if len(柜内所有测点) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜/库/车内所有测点 失败!"})
 		return
 	}
 	温度控制范围最高值_ := c.GetString("温度控制范围最高值") //  v26nplogbwt1
@@ -3711,7 +3768,13 @@ func (c *TaskDataController) A运行确认及偏差处理空载结束时间() {
 
 	柜内所有测点 := c.GetString("柜内所有测点") //  v26nplogbwt1
 	if len(柜内所有测点) == 0 {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜内所有测点 失败!"})
+		柜内所有测点 = c.GetString("库内所有测点")
+	}
+	if len(柜内所有测点) == 0 {
+		柜内所有测点 = c.GetString("车内所有测点")
+	}
+	if len(柜内所有测点) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜/库/车内所有测点 失败!"})
 		return
 	}
 	温度控制范围最高值_ := c.GetString("温度控制范围最高值") //  v26nplogbwt1
@@ -3775,7 +3838,7 @@ func (c *TaskDataController) A运行确认及偏差处理空载结束时间() {
 		return
 	}
 
-	list2 := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, startTimeData.T_id, startTimeData.T_time, 现场测试结束时间)
+	list2 := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, startTimeData.T_sn, startTimeData.T_time, 现场测试结束时间)
 	CalculateHumps_list := Task.CalculateHumps(list2)
 
 	if len(CalculateHumps_list) < 4 {
@@ -3817,7 +3880,13 @@ func (c *TaskDataController) A运行确认及偏差处理满载结束时间() {
 
 	柜内所有测点 := c.GetString("柜内所有测点") //  v26nplogbwt1
 	if len(柜内所有测点) == 0 {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜内所有测点 失败!"})
+		柜内所有测点 = c.GetString("库内所有测点")
+	}
+	if len(柜内所有测点) == 0 {
+		柜内所有测点 = c.GetString("车内所有测点")
+	}
+	if len(柜内所有测点) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜/库/车内所有测点 失败!"})
 		return
 	}
 	温度控制范围最高值_ := c.GetString("温度控制范围最高值") //  v26nplogbwt1
@@ -4999,9 +5068,15 @@ func (c *TaskDataController) A满载第一次关门温度恢复时间() {
 		return
 	}
 
-	柜内所有测点 := c.GetString("柜内所有测点") //  v26nplogbwt1
+	柜内所有测点 := c.GetString("柜内所有测点")
 	if len(柜内所有测点) == 0 {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜内所有测点 失败!"})
+		柜内所有测点 = c.GetString("均匀性布点")
+	}
+	if len(柜内所有测点) == 0 {
+		柜内所有测点 = c.GetString("产品存放区域测点")
+	}
+	if len(柜内所有测点) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜内所有测点/均匀性布点/产品存放区域测点 失败!"})
 		return
 	}
 	温度控制范围最高值_ := c.GetString("温度控制范围最高值") //  v26nplogbwt1
@@ -5085,9 +5160,15 @@ func (c *TaskDataController) A空载第一次关门温度恢复时间() {
 		return
 	}
 
-	柜内所有测点 := c.GetString("柜内所有测点") //  v26nplogbwt1
+	柜内所有测点 := c.GetString("柜内所有测点")
 	if len(柜内所有测点) == 0 {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜内所有测点 失败!"})
+		柜内所有测点 = c.GetString("均匀性布点")
+	}
+	if len(柜内所有测点) == 0 {
+		柜内所有测点 = c.GetString("产品存放区域测点")
+	}
+	if len(柜内所有测点) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜内所有测点/均匀性布点/产品存放区域测点 失败!"})
 		return
 	}
 	温度控制范围最高值_ := c.GetString("温度控制范围最高值") //  v26nplogbwt1
@@ -5157,6 +5238,382 @@ func (c *TaskDataController) A空载第一次关门温度恢复时间() {
 	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
 }
 
+func (c *TaskDataController) A满载第二次关门温度恢复时间() {
+
+	T_task_id := c.GetString("T_task_id") //  v26nplogbwt1
+	println("T_task_id:", T_task_id)
+	c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
+	c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
+	c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
+
+	Task_r, err := Task.Read_Task(T_task_id)
+	if err != nil {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取任务信息失败!"})
+		return
+	}
+
+	柜内所有测点 := c.GetString("柜内所有测点")
+	if len(柜内所有测点) == 0 {
+		柜内所有测点 = c.GetString("均匀性布点")
+	}
+	if len(柜内所有测点) == 0 {
+		柜内所有测点 = c.GetString("产品存放区域测点")
+	}
+	if len(柜内所有测点) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜内所有测点/均匀性布点/产品存放区域测点 失败!"})
+		return
+	}
+	温度控制范围最高值_ := c.GetString("温度控制范围最高值") //  v26nplogbwt1
+	if len(温度控制范围最高值_) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 温度控制范围最高值 失败!"})
+		return
+	}
+	温度控制范围最高值 := lib.To_float32(温度控制范围最高值_)
+
+	第二次开门结束时间 := c.GetString("第二次开门结束时间") //  v26nplogbwt1
+	if len(第二次开门结束时间) == 0 || 第二次开门结束时间 == "null" {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 第二次开门结束时间 失败!"})
+		return
+	}
+	第三次开门开始时间 := c.GetString("第三次开门开始时间") //  v26nplogbwt1
+	if len(第三次开门开始时间) == 0 || 第三次开门开始时间 == "null" {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 第三次开门开始时间 失败!"})
+		return
+	}
+	第二次开门结束时间_a, _ := time.Parse("2006-01-02 15:04", 第二次开门结束时间)
+	第三次开门开始时间_a, _ := time.Parse("2006-01-02 15:04", 第三次开门开始时间)
+
+	maps_Time_Min_Max_GROUP := Task.Read_TaskData_T_Min_Max_Time_Min_Max_ListGROUP(Task_r.T_task_id, 柜内所有测点, 第二次开门结束时间_a.Format("2006-01-02 15:04:05"), 第三次开门开始时间_a.Format("2006-01-02 15:04:05"))
+
+	if maps_Time_Min_Max_GROUP == nil {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到 柜内所有测点 最大最小值 数据 !"})
+		return
+	}
+
+	//  判断拐点
+	if maps_Time_Min_Max_GROUP[0].T_max <= maps_Time_Min_Max_GROUP[1].T_max &&
+		maps_Time_Min_Max_GROUP[1].T_max >= maps_Time_Min_Max_GROUP[2].T_max {
+
+		if maps_Time_Min_Max_GROUP[1].T_max > 温度控制范围最高值 {
+			// 情况1:开门有超标的情况:
+			// 柜内所有测点中任意一条数据出现超温度控制范围最高值后所有验证工具下降至温度控制范围最高值减0.5℃此时的时间
+			for _, group := range maps_Time_Min_Max_GROUP {
+				if group.T_max < 温度控制范围最高值 {
+					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: group.T_times})
+					return
+				}
+			}
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到 下降至温度控制范围最高值减0.5℃此时的时间 !"})
+			return
+		} else {
+			// 情况2:开门无超标的情况:
+			// 柜内所有测点中温度持续下降连续5分钟内,取第一条时间作为此时间点
+			list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, 柜内所有测点, maps_Time_Min_Max_GROUP[1].T_times, 第二次开门结束时间_a.Add(time.Minute*30).Format("2006-01-02 15:04:05"))
+
+			for i := 0; i < len(list)-6; i++ {
+				if maps_Time_Min_Max_GROUP[i].T_max <= maps_Time_Min_Max_GROUP[i+1].T_max &&
+					maps_Time_Min_Max_GROUP[i+1].T_max >= maps_Time_Min_Max_GROUP[i+2].T_max &&
+					maps_Time_Min_Max_GROUP[i+2].T_max >= maps_Time_Min_Max_GROUP[i+3].T_max &&
+					maps_Time_Min_Max_GROUP[i+3].T_max >= maps_Time_Min_Max_GROUP[i+4].T_max &&
+					maps_Time_Min_Max_GROUP[i+4].T_max >= maps_Time_Min_Max_GROUP[i+5].T_max {
+
+					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: maps_Time_Min_Max_GROUP[i].T_times})
+					return
+
+				}
+			}
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到 温度持续下降连续5分钟 !"})
+			return
+		}
+
+	}
+
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到数据拐点 !"})
+
+	// Close the connection
+	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
+}
+func (c *TaskDataController) A空载第二次关门温度恢复时间() {
+
+	T_task_id := c.GetString("T_task_id") //  v26nplogbwt1
+	println("T_task_id:", T_task_id)
+	c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
+	c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
+	c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
+
+	Task_r, err := Task.Read_Task(T_task_id)
+	if err != nil {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取任务信息失败!"})
+		return
+	}
+
+	柜内所有测点 := c.GetString("柜内所有测点")
+	if len(柜内所有测点) == 0 {
+		柜内所有测点 = c.GetString("均匀性布点")
+	}
+	if len(柜内所有测点) == 0 {
+		柜内所有测点 = c.GetString("产品存放区域测点")
+	}
+	if len(柜内所有测点) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜内所有测点/均匀性布点/产品存放区域测点 失败!"})
+		return
+	}
+	温度控制范围最高值_ := c.GetString("温度控制范围最高值") //  v26nplogbwt1
+	if len(温度控制范围最高值_) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 温度控制范围最高值 失败!"})
+		return
+	}
+	温度控制范围最高值 := lib.To_float32(温度控制范围最高值_)
+
+	第二次开门结束时间 := c.GetString("第二次开门结束时间") //  v26nplogbwt1
+	if len(第二次开门结束时间) == 0 || 第二次开门结束时间 == "null" {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 第二次开门结束时间 失败!"})
+		return
+	}
+	第三次开门开始时间 := c.GetString("第三次开门开始时间") //  v26nplogbwt1
+	if len(第三次开门开始时间) == 0 || 第三次开门开始时间 == "null" {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 第三次开门开始时间 失败!"})
+		return
+	}
+	第二次开门结束时间_a, _ := time.Parse("2006-01-02 15:04", 第二次开门结束时间)
+	第三次开门开始时间_a, _ := time.Parse("2006-01-02 15:04", 第三次开门开始时间)
+
+	maps_Time_Min_Max_GROUP := Task.Read_TaskData_T_Min_Max_Time_Min_Max_ListGROUP(Task_r.T_task_id, 柜内所有测点, 第二次开门结束时间_a.Format("2006-01-02 15:04:05"), 第三次开门开始时间_a.Format("2006-01-02 15:04:05"))
+	if maps_Time_Min_Max_GROUP == nil {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到 柜内所有测点 最大最小值 数据 !"})
+		return
+	}
+	//  判断拐点
+	if maps_Time_Min_Max_GROUP[0].T_max <= maps_Time_Min_Max_GROUP[1].T_max &&
+		maps_Time_Min_Max_GROUP[1].T_max >= maps_Time_Min_Max_GROUP[2].T_max {
+
+		if maps_Time_Min_Max_GROUP[1].T_max > 温度控制范围最高值 {
+			// 情况1:开门有超标的情况:
+			// 柜内所有测点中任意一条数据出现超温度控制范围最高值后所有验证工具下降至温度控制范围最高值减0.5℃此时的时间
+			for _, group := range maps_Time_Min_Max_GROUP {
+				if group.T_max < 温度控制范围最高值 {
+					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: group.T_times})
+					return
+				}
+			}
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到 下降至温度控制范围最高值减0.5℃此时的时间 !"})
+			return
+		} else {
+			// 情况2:开门无超标的情况:
+			// 柜内所有测点中温度持续下降连续5分钟内,取第一条时间作为此时间点
+			list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, 柜内所有测点, maps_Time_Min_Max_GROUP[1].T_times, 第二次开门结束时间_a.Add(time.Minute*30).Format("2006-01-02 15:04:05"))
+
+			for i := 0; i < len(list)-6; i++ {
+				if maps_Time_Min_Max_GROUP[i].T_max <= maps_Time_Min_Max_GROUP[i+1].T_max &&
+					maps_Time_Min_Max_GROUP[i+1].T_max >= maps_Time_Min_Max_GROUP[i+2].T_max &&
+					maps_Time_Min_Max_GROUP[i+2].T_max >= maps_Time_Min_Max_GROUP[i+3].T_max &&
+					maps_Time_Min_Max_GROUP[i+3].T_max >= maps_Time_Min_Max_GROUP[i+4].T_max &&
+					maps_Time_Min_Max_GROUP[i+4].T_max >= maps_Time_Min_Max_GROUP[i+5].T_max {
+
+					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: maps_Time_Min_Max_GROUP[i].T_times})
+					return
+
+				}
+			}
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到 温度持续下降连续5分钟 !"})
+			return
+		}
+
+	}
+
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到数据拐点 !"})
+
+	// Close the connection
+	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
+}
+
+func (c *TaskDataController) A满载第三次关门温度恢复时间() {
+
+	T_task_id := c.GetString("T_task_id") //  v26nplogbwt1
+	println("T_task_id:", T_task_id)
+	c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
+	c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
+	c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
+
+	Task_r, err := Task.Read_Task(T_task_id)
+	if err != nil {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取任务信息失败!"})
+		return
+	}
+
+	柜内所有测点 := c.GetString("柜内所有测点")
+	if len(柜内所有测点) == 0 {
+		柜内所有测点 = c.GetString("均匀性布点")
+	}
+	if len(柜内所有测点) == 0 {
+		柜内所有测点 = c.GetString("产品存放区域测点")
+	}
+	if len(柜内所有测点) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜内所有测点/均匀性布点/产品存放区域测点 失败!"})
+		return
+	}
+	温度控制范围最高值_ := c.GetString("温度控制范围最高值") //  v26nplogbwt1
+	if len(温度控制范围最高值_) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 温度控制范围最高值 失败!"})
+		return
+	}
+	温度控制范围最高值 := lib.To_float32(温度控制范围最高值_)
+
+	第三次开门结束时间 := c.GetString("第三次开门结束时间") //  v26nplogbwt1
+	if len(第三次开门结束时间) == 0 || 第三次开门结束时间 == "null" {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 第三次开门结束时间 失败!"})
+		return
+	}
+	现场测试结束时间 := c.GetString("现场测试结束时间") //  v26nplogbwt1
+	if len(现场测试结束时间) == 0 || 现场测试结束时间 == "null" {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 现场测试结束时间 失败!"})
+		return
+	}
+	第三次开门结束时间_a, _ := time.Parse("2006-01-02 15:04", 第三次开门结束时间)
+	现场测试结束时间_a, _ := time.Parse("2006-01-02 15:04", 现场测试结束时间)
+
+	maps_Time_Min_Max_GROUP := Task.Read_TaskData_T_Min_Max_Time_Min_Max_ListGROUP(Task_r.T_task_id, 柜内所有测点, 第三次开门结束时间_a.Format("2006-01-02 15:04:05"), 现场测试结束时间_a.Format("2006-01-02 15:04:05"))
+	if maps_Time_Min_Max_GROUP == nil {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到 柜内所有测点 最大最小值 数据 !"})
+		return
+	}
+	//  判断拐点
+	if maps_Time_Min_Max_GROUP[0].T_max <= maps_Time_Min_Max_GROUP[1].T_max &&
+		maps_Time_Min_Max_GROUP[1].T_max >= maps_Time_Min_Max_GROUP[2].T_max {
+
+		if maps_Time_Min_Max_GROUP[1].T_max > 温度控制范围最高值 {
+			// 情况1:开门有超标的情况:
+			// 柜内所有测点中任意一条数据出现超温度控制范围最高值后所有验证工具下降至温度控制范围最高值减0.5℃此时的时间
+			for _, group := range maps_Time_Min_Max_GROUP {
+				if group.T_max < 温度控制范围最高值 {
+					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: group.T_times})
+					return
+				}
+			}
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到 下降至温度控制范围最高值减0.5℃此时的时间 !"})
+			return
+		} else {
+			// 情况2:开门无超标的情况:
+			// 柜内所有测点中温度持续下降连续5分钟内,取第一条时间作为此时间点
+			list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, 柜内所有测点, maps_Time_Min_Max_GROUP[1].T_times, 第三次开门结束时间_a.Add(time.Minute*30).Format("2006-01-02 15:04:05"))
+
+			for i := 0; i < len(list)-6; i++ {
+				if maps_Time_Min_Max_GROUP[i].T_max <= maps_Time_Min_Max_GROUP[i+1].T_max &&
+					maps_Time_Min_Max_GROUP[i+1].T_max >= maps_Time_Min_Max_GROUP[i+2].T_max &&
+					maps_Time_Min_Max_GROUP[i+2].T_max >= maps_Time_Min_Max_GROUP[i+3].T_max &&
+					maps_Time_Min_Max_GROUP[i+3].T_max >= maps_Time_Min_Max_GROUP[i+4].T_max &&
+					maps_Time_Min_Max_GROUP[i+4].T_max >= maps_Time_Min_Max_GROUP[i+5].T_max {
+
+					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: maps_Time_Min_Max_GROUP[i].T_times})
+					return
+
+				}
+			}
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到 温度持续下降连续5分钟 !"})
+			return
+		}
+
+	}
+
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到数据拐点 !"})
+
+	// Close the connection
+	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
+}
+func (c *TaskDataController) A空载第三次关门温度恢复时间() {
+
+	T_task_id := c.GetString("T_task_id") //  v26nplogbwt1
+	println("T_task_id:", T_task_id)
+	c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
+	c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
+	c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
+
+	Task_r, err := Task.Read_Task(T_task_id)
+	if err != nil {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取任务信息失败!"})
+		return
+	}
+
+	柜内所有测点 := c.GetString("柜内所有测点")
+	if len(柜内所有测点) == 0 {
+		柜内所有测点 = c.GetString("均匀性布点")
+	}
+	if len(柜内所有测点) == 0 {
+		柜内所有测点 = c.GetString("产品存放区域测点")
+	}
+	if len(柜内所有测点) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜内所有测点/均匀性布点/产品存放区域测点 失败!"})
+		return
+	}
+	温度控制范围最高值_ := c.GetString("温度控制范围最高值") //  v26nplogbwt1
+	if len(温度控制范围最高值_) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 温度控制范围最高值 失败!"})
+		return
+	}
+	温度控制范围最高值 := lib.To_float32(温度控制范围最高值_)
+
+	第三次开门结束时间 := c.GetString("第三次开门结束时间") //  v26nplogbwt1
+	if len(第三次开门结束时间) == 0 || 第三次开门结束时间 == "null" {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 第三次开门结束时间 失败!"})
+		return
+	}
+	现场测试结束时间 := c.GetString("现场测试结束时间") //  v26nplogbwt1
+	if len(现场测试结束时间) == 0 || 现场测试结束时间 == "null" {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 现场测试结束时间 失败!"})
+		return
+	}
+	第三次开门结束时间_a, _ := time.Parse("2006-01-02 15:04", 第三次开门结束时间)
+	现场测试结束时间_a, _ := time.Parse("2006-01-02 15:04", 现场测试结束时间)
+
+	maps_Time_Min_Max_GROUP := Task.Read_TaskData_T_Min_Max_Time_Min_Max_ListGROUP(Task_r.T_task_id, 柜内所有测点, 第三次开门结束时间_a.Format("2006-01-02 15:04:05"), 现场测试结束时间_a.Format("2006-01-02 15:04:05"))
+	if maps_Time_Min_Max_GROUP == nil {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到 柜内所有测点 最大最小值 数据 !"})
+		return
+	}
+	//  判断拐点
+	if maps_Time_Min_Max_GROUP[0].T_max <= maps_Time_Min_Max_GROUP[1].T_max &&
+		maps_Time_Min_Max_GROUP[1].T_max >= maps_Time_Min_Max_GROUP[2].T_max {
+
+		if maps_Time_Min_Max_GROUP[1].T_max > 温度控制范围最高值 {
+			// 情况1:开门有超标的情况:
+			// 柜内所有测点中任意一条数据出现超温度控制范围最高值后所有验证工具下降至温度控制范围最高值减0.5℃此时的时间
+			for _, group := range maps_Time_Min_Max_GROUP {
+				if group.T_max < 温度控制范围最高值 {
+					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: group.T_times})
+					return
+				}
+			}
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到 下降至温度控制范围最高值减0.5℃此时的时间 !"})
+			return
+		} else {
+			// 情况2:开门无超标的情况:
+			// 柜内所有测点中温度持续下降连续5分钟内,取第一条时间作为此时间点
+			list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, 柜内所有测点, maps_Time_Min_Max_GROUP[1].T_times, 第三次开门结束时间_a.Add(time.Minute*30).Format("2006-01-02 15:04:05"))
+
+			for i := 0; i < len(list)-6; i++ {
+				if maps_Time_Min_Max_GROUP[i].T_max <= maps_Time_Min_Max_GROUP[i+1].T_max &&
+					maps_Time_Min_Max_GROUP[i+1].T_max >= maps_Time_Min_Max_GROUP[i+2].T_max &&
+					maps_Time_Min_Max_GROUP[i+2].T_max >= maps_Time_Min_Max_GROUP[i+3].T_max &&
+					maps_Time_Min_Max_GROUP[i+3].T_max >= maps_Time_Min_Max_GROUP[i+4].T_max &&
+					maps_Time_Min_Max_GROUP[i+4].T_max >= maps_Time_Min_Max_GROUP[i+5].T_max {
+
+					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: maps_Time_Min_Max_GROUP[i].T_times})
+					return
+
+				}
+			}
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到 温度持续下降连续5分钟 !"})
+			return
+		}
+
+	}
+
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没找到数据拐点 !"})
+
+	// Close the connection
+	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
+}
+
 func (c *TaskDataController) A满载开门最长需要多少分钟恢复() {
 
 	T_task_id := c.GetString("T_task_id") //  v26nplogbwt1
@@ -5226,9 +5683,9 @@ func (c *TaskDataController) A冷藏库作业口外部环境分割线最低温()
 		return
 	}
 
-	作业口外部测点 := c.GetString("作业口外部测点") //  v26nplogbwt1
-	if len(作业口外部测点) == 0 {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 作业口外部测点 失败!"})
+	冷藏库作业口外部环境测点 := c.GetString("冷藏库作业口外部环境测点") //  v26nplogbwt1
+	if len(冷藏库作业口外部环境测点) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 冷藏库作业口外部环境测点 失败!"})
 		return
 	}
 
@@ -5243,9 +5700,9 @@ func (c *TaskDataController) A冷藏库作业口外部环境分割线最低温()
 		return
 	}
 
-	minT, _ := Task.Read_TaskData_T_Min_Max(Task_r.T_task_id, 作业口外部测点, "", 现场测试开始时间, 现场测试结束时间)
+	minT, _ := Task.Read_TaskData_T_Min_Max(Task_r.T_task_id, 冷藏库作业口外部环境测点, "", 现场测试开始时间, 现场测试结束时间)
 
-	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: fmt.Sprintf("%.1f", math.Ceil(float64(minT*10))/10)})
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: fmt.Sprintf("%.1f", math.Ceil(float64(minT*10))/10-0.5)})
 
 	// Close the connection
 	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
@@ -5264,9 +5721,9 @@ func (c *TaskDataController) A冷藏库作业口外部环境分割线最高温()
 		return
 	}
 
-	作业口外部测点 := c.GetString("作业口外部测点") //  v26nplogbwt1
-	if len(作业口外部测点) == 0 {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 作业口外部测点 失败!"})
+	冷藏库作业口外部环境测点 := c.GetString("冷藏库作业口外部环境测点") //  v26nplogbwt1
+	if len(冷藏库作业口外部环境测点) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 冷藏库作业口外部环境测点 失败!"})
 		return
 	}
 
@@ -5281,9 +5738,9 @@ func (c *TaskDataController) A冷藏库作业口外部环境分割线最高温()
 		return
 	}
 
-	_, maxT := Task.Read_TaskData_T_Min_Max(Task_r.T_task_id, 作业口外部测点, "", 现场测试开始时间, 现场测试结束时间)
+	_, maxT := Task.Read_TaskData_T_Min_Max(Task_r.T_task_id, 冷藏库作业口外部环境测点, "", 现场测试开始时间, 现场测试结束时间)
 
-	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: fmt.Sprintf("%.1f", math.Ceil(float64(maxT*10))/10)})
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: fmt.Sprintf("%.1f", math.Ceil(float64(maxT*10))/10+0.5)})
 
 	// Close the connection
 	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
@@ -5924,3 +6381,250 @@ func (c *TaskDataController) A培训时间() {
 	// Close the connection
 	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
 }
+func (c *TaskDataController) A作业出入口总测点() {
+
+	T_task_id := c.GetString("T_task_id") //  v26nplogbwt1
+	println("T_task_id:", T_task_id)
+	c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
+	c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
+	c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
+
+	一号作业出入口测点 := c.GetString("1号作业出入口测点") //  v26nplogbwt1
+	二号作业出入口测点 := c.GetString("2号作业出入口测点") //  v26nplogbwt1
+
+	parts := strings.Split(strings.Trim(一号作业出入口测点, "|")+"|"+strings.Trim(二号作业出入口测点, "|"), "|")
+
+	uniqueMap := make(map[string]struct{})
+	var result []string
+
+	for _, part := range parts {
+		if _, exists := uniqueMap[part]; !exists {
+			uniqueMap[part] = struct{}{}
+			result = append(result, part)
+		}
+	}
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: strings.Join(result, "|")})
+
+	// Close the connection
+	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
+}
+func (c *TaskDataController) A风机布点总测点() {
+
+	T_task_id := c.GetString("T_task_id") //  v26nplogbwt1
+	println("T_task_id:", T_task_id)
+	c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
+	c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
+	c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
+
+	一号风机测点 := c.GetString("1号风机测点")     //  v26nplogbwt1
+	二号风机测点 := c.GetString("2号风机测点")     //  v26nplogbwt1
+	一号风机回风口 := c.GetString("1号风机回风口") //  v26nplogbwt1
+	二号风机回风口 := c.GetString("2号风机回风口") //  v26nplogbwt1
+
+	parts := strings.Split(strings.Trim(一号风机回风口, "|")+"|"+strings.Trim(一号风机测点, "|")+"|"+strings.Trim(二号风机回风口, "|")+"|"+strings.Trim(二号风机测点, "|"), "|")
+
+	uniqueMap := make(map[string]struct{})
+	var result []string
+
+	for _, part := range parts {
+		if _, exists := uniqueMap[part]; !exists {
+			uniqueMap[part] = struct{}{}
+			result = append(result, part)
+		}
+	}
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: strings.Join(result, "|")})
+
+	// Close the connection
+	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
+}
+func (c *TaskDataController) A库内除风机出风口回风口外总测点() {
+
+	T_task_id := c.GetString("T_task_id") //  v26nplogbwt1
+	println("T_task_id:", T_task_id)
+	c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
+	c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
+	c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
+
+	库内所有测点 := c.GetString("库内所有测点")     //  v26nplogbwt1
+	风机布点总测点 := c.GetString("风机布点总测点") //  v26nplogbwt1
+
+	parts1 := strings.Split(库内所有测点, "|")
+	parts2 := strings.Split(风机布点总测点, "|")
+
+	excludeMap := make(map[string]struct{})
+	for _, part := range parts2 {
+		excludeMap[part] = struct{}{}
+	}
+
+	var result []string
+	for _, part := range parts1 {
+		if _, exists := excludeMap[part]; !exists {
+			result = append(result, part)
+		}
+	}
+
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: strings.Join(result, "|")})
+
+	// Close the connection
+	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
+}
+func (c *TaskDataController) A库内除风机出风口回风口特殊位置布点作业口外总测点() {
+
+	T_task_id := c.GetString("T_task_id") //  v26nplogbwt1
+	println("T_task_id:", T_task_id)
+	c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
+	c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
+	c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
+
+	库内所有测点 := c.GetString("库内所有测点")                                           //  v26nplogbwt1
+	风机布点总测点 := c.GetString("风机布点总测点")                                       //  v26nplogbwt1
+	作业出入口总测点 := c.GetString("作业出入口总测点")                                   //  v26nplogbwt1
+	照明灯除湿机风幕机等特殊区域测点 := c.GetString("照明灯、除湿机、风幕机等特殊区域测点") //  v26nplogbwt1
+
+	parts1 := strings.Split(strings.Trim(库内所有测点, "|"), "|")
+	parts2 := strings.Split(strings.Trim(风机布点总测点, "|"), "|")
+	parts3 := strings.Split(strings.Trim(作业出入口总测点, "|"), "|")
+	parts4 := strings.Split(strings.Trim(照明灯除湿机风幕机等特殊区域测点, "|"), "|")
+
+	excludeMap := make(map[string]struct{})
+	for _, part := range parts2 {
+		excludeMap[part] = struct{}{}
+	}
+	for _, part := range parts3 {
+		excludeMap[part] = struct{}{}
+	}
+	for _, part := range parts4 {
+		excludeMap[part] = struct{}{}
+	}
+
+	var result []string
+	for _, part := range parts1 {
+		if _, exists := excludeMap[part]; !exists {
+			result = append(result, part)
+		}
+	}
+
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: strings.Join(result, "|")})
+
+	// Close the connection
+	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
+}
+func (c *TaskDataController) A车内除风机出风口回风口外总测点() {
+
+	T_task_id := c.GetString("T_task_id") //  v26nplogbwt1
+	println("T_task_id:", T_task_id)
+	c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
+	c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
+	c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
+
+	车内所有测点 := c.GetString("车内所有测点")     //  v26nplogbwt1
+	风机布点总测点 := c.GetString("风机布点总测点") //  v26nplogbwt1
+
+	parts1 := strings.Split(车内所有测点, "|")
+	parts2 := strings.Split(风机布点总测点, "|")
+
+	excludeMap := make(map[string]struct{})
+	for _, part := range parts2 {
+		excludeMap[part] = struct{}{}
+	}
+
+	var result []string
+	for _, part := range parts1 {
+		if _, exists := excludeMap[part]; !exists {
+			result = append(result, part)
+		}
+	}
+
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: strings.Join(result, "|")})
+
+	// Close the connection
+	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
+}
+func (c *TaskDataController) A预冷开始时间() {
+
+	T_task_id := c.GetString("T_task_id") //  v26nplogbwt1
+	println("T_task_id:", T_task_id)
+	c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
+	c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
+	c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
+
+	现场测试开始时间 := c.GetString("现场测试开始时间") //  v26nplogbwt1
+	if len(现场测试开始时间) == 0 || 现场测试开始时间 == "null" {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 现场测试开始时间 失败!"})
+		return
+	}
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: 现场测试开始时间})
+
+	// Close the connection
+	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
+}
+func (c *TaskDataController) A预冷结束时间() {
+
+	T_task_id := c.GetString("T_task_id") //  v26nplogbwt1
+	println("T_task_id:", T_task_id)
+	c.Ctx.ResponseWriter.Header().Set("Content-Type", "text/event-stream")
+	c.Ctx.ResponseWriter.Header().Set("Cache-Control", "no-cache")
+	c.Ctx.ResponseWriter.Header().Set("Connection", "keep-alive")
+
+	Task_r, err := Task.Read_Task(T_task_id)
+	if err != nil {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取任务信息失败!"})
+		return
+	}
+
+	车内所有测点 := c.GetString("车内所有测点") //  v26nplogbwt1
+	if len(车内所有测点) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 车内所有测点 失败!"})
+		return
+	}
+	温度控制范围最高值_ := c.GetString("温度控制范围最高值") //  v26nplogbwt1
+	if len(温度控制范围最高值_) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 温度控制范围最高值 失败!"})
+		return
+	}
+	温度控制范围最高值 := lib.To_float32(温度控制范围最高值_)
+
+	现场测试开始时间 := c.GetString("现场测试开始时间") //  v26nplogbwt1
+	if len(现场测试开始时间) == 0 || 现场测试开始时间 == "null" {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 现场测试开始时间 失败!"})
+		return
+	}
+	现场测试结束时间 := c.GetString("现场测试结束时间") //  v26nplogbwt1
+	if len(现场测试结束时间) == 0 || 现场测试结束时间 == "null" {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 现场测试结束时间 失败!"})
+		return
+	}
+
+	list, _ := Task.Read_TaskData_ById_List_AES(Task_r.T_task_id, 车内所有测点, "", 现场测试开始时间, 现场测试结束时间, 0, 9999)
+	if len(list) == 0 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 柜内所有测点|现场测试开始时间-现场测试结束时间 当前 温度数据 失败!"})
+		return
+	}
+
+	// 现场测试开开始时间温度高于温度控制范围最高值,取温度下降至“温度控制范围最高值”-0.1以下的最后一个终端时间
+
+	groupMap := make(map[string][]Task.TaskData_)
+	for _, r := range list {
+		groupMap[r.T_id] = append(groupMap[r.T_id], r)
+	}
+
+	var latest *Task.TaskData_
+
+	for _, group := range groupMap {
+		candidate := Task.FindFirstDecreasingTendency(group, 温度控制范围最高值-0.1)
+		if candidate != nil {
+			if latest == nil || lib.ParseTime(candidate.T_time).After(lib.ParseTime(latest.T_time)) {
+				latest = candidate
+			}
+		}
+	}
+	if latest == nil {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没有找到 温度下降至“温度控制范围最高值”以下 数据!"})
+		return
+	}
+
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: latest.T_time})
+
+	// Close the connection
+	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
+}

+ 106 - 37
controllers/TaskHandle.go

@@ -41,7 +41,7 @@ func (c *TaskDataHandleController) SSE_Automatically_add_missing_terminal() {
 		return
 	}
 
-	DeviceClassList_r := Device.Read_DeviceClassList_List_id(Task_r.T_class)
+	DeviceClassList_r := Device.Read_DeviceClassList_List_id_By_Terminal(Task_r.T_class, false)
 	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "终端总共:" + lib.To_string(len(DeviceClassList_r)) + " 正在检查自检探头..."})
 	for _, class_ := range DeviceClassList_r {
 		_, cnt := Task.Read_TaskData_ById_List(Task_r.T_task_id, class_.T_sn, class_.T_id, "", "", 0, 1)
@@ -191,7 +191,7 @@ func (c *TaskDataHandleController) SSE_Automatically_add_missing_data() {
 	// 获取 备注 下面关联设备,数量
 	var Devicedata_list_MAX int64
 	Devicedata_list_MAX = 0 //最大值
-	DeviceClassList_list := Device.Read_DeviceClassList_List_id(Task_r.T_class)
+	DeviceClassList_list := Device.Read_DeviceClassList_List_id_By_Terminal(Task_r.T_class, false)
 	for _, DeviceClassListT_remark_r_list := range DeviceClassList_list {
 		_, cnt := Task.Read_TaskData_ById_List(Task_r.T_task_id, DeviceClassListT_remark_r_list.T_sn, DeviceClassListT_remark_r_list.T_id, "", "", 0, 9999)
 
@@ -530,9 +530,10 @@ func (c *TaskDataHandleController) SSE_Comparison_between_binding_points_and_ter
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "温湿度绑定点1 中找到 " + lib.To_string(len(温湿度绑定点1_list)) + "条,只允许 一条数据!"})
 		return
 	}
-	监测终端01_list := Device.Read_DeviceClassList_List_id_T_remark(Task_r.T_class, "监测终端01")
-	if len(监测终端01_list) != 1 {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "监测终端01 中找到 " + lib.To_string(len(监测终端01_list)) + "条,只允许 一条数据!"})
+
+	监测终端01_list := Device.Read_DeviceClassList_List_id_By_Terminal(Task_r.T_class, true)
+	if len(监测终端01_list) < 1 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "未找到 监测终端!"})
 		return
 	}
 
@@ -665,6 +666,58 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_cold_and_hot_
 		return
 	}
 
+	// 均匀性布点   产品存放区域测点
+	部点终端_list := Device.Read_DeviceClassList_List_id_T_remark(Task_r.T_class, "均匀性布点")
+	部点终端_list = append(部点终端_list, Device.Read_DeviceClassList_List_id_T_remark(Task_r.T_class, "产品存放区域测点")...)
+
+	//开始时间 := VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "运行确认及偏差处理(空载)结束时间")
+	//if len(开始时间) == 0 {
+	//	开始时间 = VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "运行确认及偏差处理(满载)结束时间")
+	//}
+	//if len(开始时间) == 0 {
+	//	开始时间 = VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "温度分布特性的测试与分析(空载)开始时间")
+	//}
+	//if len(开始时间) == 0 {
+	//	开始时间 = VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "温度分布特性的测试与分析(满载)开始时间")
+	//}
+	//if len(开始时间) == 0 {
+	//	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "未找到开始时间 标签!"})
+	//	return
+	//}
+	开始时间 := ""
+	if Task_r.T_device_type == "C" {
+		// 任务类型为C的时候,获取温度下降到最低点时间
+		// 1. 获取温度平均值
+		部点终端_sn_list := []string{}
+		for _, v := range 部点终端_list {
+			部点终端_sn_list = append(部点终端_sn_list, v.T_sn)
+		}
+		list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, strings.Join(部点终端_sn_list, "|"), "", "")
+		if len(list) < 2 {
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "均匀性布点+产品存放区域测点 数据平均值 少于2条!"})
+			return
+		}
+		// 查找最低点
+		// 找最低点
+		minRecord := list[0]
+		for i := 1; i <= len(list); i++ {
+			if list[i].T_t < minRecord.T_t {
+				minRecord = list[i]
+			}
+			if list[i].T_t > list[i-1].T_t {
+				break
+			}
+		}
+		开始时间 = minRecord.T_time
+	} else {
+		现场测试开始时间 := VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "现场测试开始时间")
+		if len(现场测试开始时间) == 0 || 现场测试开始时间 == "null" {
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 现场测试开始时间 失败!"})
+			return
+		}
+		开始时间 = 现场测试开始时间
+	}
+
 	// ------------------
 	结束时间 := VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "开空开")
 	if len(结束时间) == 0 {
@@ -681,25 +734,8 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_cold_and_hot_
 		return
 	}
 
-	开始时间 := VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "运行确认及偏差处理(空载)结束时间")
-	if len(开始时间) == 0 {
-		开始时间 = VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "运行确认及偏差处理(满载)结束时间")
-	}
-	if len(开始时间) == 0 {
-		开始时间 = VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "温度分布特性的测试与分析(空载)开始时间")
-	}
-	if len(开始时间) == 0 {
-		开始时间 = VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "温度分布特性的测试与分析(满载)开始时间")
-	}
-	if len(开始时间) == 0 {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "未找到开始时间 标签!"})
-		return
-	}
-	温度分布特性的测试与分析_开始时间 := 开始时间
 	温度分布特性的测试与分析_结束时间 := 结束时间
-	// 均匀性布点   产品存放区域测点
-	部点终端_list := Device.Read_DeviceClassList_List_id_T_remark(Task_r.T_class, "均匀性布点")
-	部点终端_list = append(部点终端_list, Device.Read_DeviceClassList_List_id_T_remark(Task_r.T_class, "产品存放区域测点")...)
+
 	if len(部点终端_list) <= 2 {
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "均匀性布点,产品存放区域测点 太少了,至少两条以上!"})
 		return
@@ -710,7 +746,7 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_cold_and_hot_
 	}
 	var AVGClassList_r []AVGClassList
 	for _, i2 := range 部点终端_list {
-		AVGClassList_r = append(AVGClassList_r, AVGClassList{T_id: i2.T_id, T_vga: Task.Read_TaskData_AVG(T_task_id, i2.T_sn, i2.T_id, 温度分布特性的测试与分析_开始时间, 温度分布特性的测试与分析_结束时间)})
+		AVGClassList_r = append(AVGClassList_r, AVGClassList{T_id: i2.T_id, T_vga: Task.Read_TaskData_AVG(T_task_id, i2.T_sn, i2.T_id, 开始时间, 温度分布特性的测试与分析_结束时间)})
 	}
 	// 使用 sort.Slice 对切片进行排序
 	sort.Slice(AVGClassList_r, func(i, j int) bool {
@@ -732,8 +768,8 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_cold_and_hot_
 		温湿度绑定点2_list = 温湿度绑定点1_list
 		温湿度绑定点2_list_is = false
 	}
-	温湿度绑定点1vga := Task.Read_TaskData_AVG(T_task_id, 温湿度绑定点1_list[0].T_sn, 温湿度绑定点1_list[0].T_id, 温度分布特性的测试与分析_开始时间, 温度分布特性的测试与分析_结束时间)
-	温湿度绑定点2vga := Task.Read_TaskData_AVG(T_task_id, 温湿度绑定点2_list[0].T_sn, 温湿度绑定点2_list[0].T_id, 温度分布特性的测试与分析_开始时间, 温度分布特性的测试与分析_结束时间)
+	温湿度绑定点1vga := Task.Read_TaskData_AVG(T_task_id, 温湿度绑定点1_list[0].T_sn, 温湿度绑定点1_list[0].T_id, 开始时间, 温度分布特性的测试与分析_结束时间)
+	温湿度绑定点2vga := Task.Read_TaskData_AVG(T_task_id, 温湿度绑定点2_list[0].T_sn, 温湿度绑定点2_list[0].T_id, 开始时间, 温度分布特性的测试与分析_结束时间)
 
 	if 温湿度绑定点1vga == 温湿度绑定点2vga {
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "温湿度绑定点1 与 温湿度绑定点2 平均值相等,将 进行上下偏移处理!"})
@@ -769,13 +805,13 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_cold_and_hot_
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "进行缩放 数据!热点" + lib.To_string(AVGClassList_r[0].T_id) + " 平均值:" + lib.To_string(AVGClassList_r[0].T_vga) +
 			"℃ 高点 " + lib.To_string(温湿度绑定点vga_H.T_id) + " 平均值" + lib.To_string(温湿度绑定点vga_H.T_vga) + "℃ 数据偏差: " + lib.To_string(vgaca) + "℃ 设置:" + lib.To_string(T_deviation) + "℃"})
 
-		Task.UpdateTaskDataTemperatureAndHumidityByGeometric_id(T_task_id, AVGClassList_r[0].T_id, 温度分布特性的测试与分析_开始时间, 温度分布特性的测试与分析_结束时间, 0.95)
+		Task.UpdateTaskDataTemperatureAndHumidityByGeometric_id(T_task_id, AVGClassList_r[0].T_id, 开始时间, 温度分布特性的测试与分析_结束时间, 0.95)
 
 		// 偏移
 		// 均匀性布点   产品存放区域测点
 		AVGClassList_r = AVGClassList_r[:0] // 清空切片
 		for _, i2 := range 部点终端_list {
-			AVGClassList_r = append(AVGClassList_r, AVGClassList{T_id: i2.T_id, T_vga: Task.Read_TaskData_AVG(T_task_id, i2.T_sn, i2.T_id, 温度分布特性的测试与分析_开始时间, 温度分布特性的测试与分析_结束时间)})
+			AVGClassList_r = append(AVGClassList_r, AVGClassList{T_id: i2.T_id, T_vga: Task.Read_TaskData_AVG(T_task_id, i2.T_sn, i2.T_id, 开始时间, 温度分布特性的测试与分析_结束时间)})
 		}
 		// 使用 sort.Slice 对切片进行排序
 		sort.Slice(AVGClassList_r, func(i, j int) bool {
@@ -788,12 +824,12 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_cold_and_hot_
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "进行偏移 数据!热点" + lib.To_string(AVGClassList_r[0].T_id) + " 平均值:" + lib.To_string(AVGClassList_r[0].T_vga) +
 			"℃ 高点 " + lib.To_string(温湿度绑定点vga_H.T_id) + " 平均值" + lib.To_string(温湿度绑定点vga_H.T_vga) + "℃ 数据偏差: " + lib.To_string(vgaca) + "℃ 设置:" + lib.To_string(T_deviation) + "℃"})
 
-		Task.UpdateTaskDataTemperatureAndHumidityByGeometricAVG(T_task_id, AVGClassList_r[0].T_id, 温度分布特性的测试与分析_开始时间, 温度分布特性的测试与分析_结束时间, math.Round(((vgaca)*0.8)*100)/100.0)
+		Task.UpdateTaskDataTemperatureAndHumidityByGeometricAVG(T_task_id, AVGClassList_r[0].T_id, 开始时间, 温度分布特性的测试与分析_结束时间, math.Round(((vgaca)*0.8)*100)/100.0)
 
 		// 均匀性布点   产品存放区域测点
 		AVGClassList_r = AVGClassList_r[:0] // 清空切片
 		for _, i2 := range 部点终端_list {
-			AVGClassList_r = append(AVGClassList_r, AVGClassList{T_id: i2.T_id, T_vga: Task.Read_TaskData_AVG(T_task_id, i2.T_sn, i2.T_id, 温度分布特性的测试与分析_开始时间, 温度分布特性的测试与分析_结束时间)})
+			AVGClassList_r = append(AVGClassList_r, AVGClassList{T_id: i2.T_id, T_vga: Task.Read_TaskData_AVG(T_task_id, i2.T_sn, i2.T_id, 开始时间, 温度分布特性的测试与分析_结束时间)})
 		}
 		// 使用 sort.Slice 对切片进行排序
 		sort.Slice(AVGClassList_r, func(i, j int) bool {
@@ -822,13 +858,13 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_cold_and_hot_
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "进行缩放 数据!冷点" + lib.To_string(AVGClassList_r[len(AVGClassList_r)-1].T_id) + " 平均值:" + lib.To_string(AVGClassList_r[len(AVGClassList_r)-1].T_vga) +
 			"℃ 低点 " + lib.To_string(温湿度绑定点vga_L.T_id) + " 平均值" + lib.To_string(温湿度绑定点vga_L.T_vga) + "℃ 数据偏差: " + lib.To_string(vgaca) + "℃ 设置:" + lib.To_string(T_deviation) + "℃"})
 
-		Task.UpdateTaskDataTemperatureAndHumidityByGeometric_id(T_task_id, AVGClassList_r[len(AVGClassList_r)-1].T_id, 温度分布特性的测试与分析_开始时间, 温度分布特性的测试与分析_结束时间, 0.95)
+		Task.UpdateTaskDataTemperatureAndHumidityByGeometric_id(T_task_id, AVGClassList_r[len(AVGClassList_r)-1].T_id, 开始时间, 温度分布特性的测试与分析_结束时间, 0.95)
 
 		// 偏移
 		// 均匀性布点   产品存放区域测点
 		AVGClassList_r = AVGClassList_r[:0] // 清空切片
 		for _, i2 := range 部点终端_list {
-			AVGClassList_r = append(AVGClassList_r, AVGClassList{T_id: i2.T_id, T_vga: Task.Read_TaskData_AVG(T_task_id, i2.T_sn, i2.T_id, 温度分布特性的测试与分析_开始时间, 温度分布特性的测试与分析_结束时间)})
+			AVGClassList_r = append(AVGClassList_r, AVGClassList{T_id: i2.T_id, T_vga: Task.Read_TaskData_AVG(T_task_id, i2.T_sn, i2.T_id, 开始时间, 温度分布特性的测试与分析_结束时间)})
 		}
 		// 使用 sort.Slice 对切片进行排序
 		sort.Slice(AVGClassList_r, func(i, j int) bool {
@@ -841,12 +877,12 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_cold_and_hot_
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "进行偏移 数据!冷点" + lib.To_string(AVGClassList_r[len(AVGClassList_r)-1].T_id) + " 平均值:" + lib.To_string(AVGClassList_r[len(AVGClassList_r)-1].T_vga) +
 			"℃ 低点 " + lib.To_string(温湿度绑定点vga_L.T_id) + " 平均值" + lib.To_string(温湿度绑定点vga_L.T_vga) + "℃ 数据偏差: " + lib.To_string(vgaca) + "℃ 设置:" + lib.To_string(T_deviation) + "℃"})
 
-		Task.UpdateTaskDataTemperatureAndHumidityByGeometricAVG(T_task_id, AVGClassList_r[len(AVGClassList_r)-1].T_id, 温度分布特性的测试与分析_开始时间, 温度分布特性的测试与分析_结束时间, math.Round(((vgaca)*0.8)*100)/100.0)
+		Task.UpdateTaskDataTemperatureAndHumidityByGeometricAVG(T_task_id, AVGClassList_r[len(AVGClassList_r)-1].T_id, 开始时间, 温度分布特性的测试与分析_结束时间, math.Round(((vgaca)*0.8)*100)/100.0)
 
 		// 均匀性布点   产品存放区域测点
 		AVGClassList_r = AVGClassList_r[:0] // 清空切片
 		for _, i2 := range 部点终端_list {
-			AVGClassList_r = append(AVGClassList_r, AVGClassList{T_id: i2.T_id, T_vga: Task.Read_TaskData_AVG(T_task_id, i2.T_sn, i2.T_id, 温度分布特性的测试与分析_开始时间, 温度分布特性的测试与分析_结束时间)})
+			AVGClassList_r = append(AVGClassList_r, AVGClassList{T_id: i2.T_id, T_vga: Task.Read_TaskData_AVG(T_task_id, i2.T_sn, i2.T_id, 开始时间, 温度分布特性的测试与分析_结束时间)})
 		}
 		// 使用 sort.Slice 对切片进行排序
 		sort.Slice(AVGClassList_r, func(i, j int) bool {
@@ -915,9 +951,42 @@ func (c *TaskDataHandleController) SSE_Interval_data_correction() {
 	//List_data, _ := Task.Read_TaskData_ById_List(Task_r.T_task_id, 部点终端_list[0].T_sn, 部点终端_list[0].T_id, "", "", 0, 9999)
 	//开始时间 := List_data[len(List_data) - 1].T_time
 
-	开始时间 := VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "运行确认及偏差处理(空载)开始时间")
-	if len(开始时间) == 0 {
-		开始时间 = VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "运行确认及偏差处理(满载)开始时间")
+	//开始时间 := VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "运行确认及偏差处理(空载)开始时间")
+	//if len(开始时间) == 0 {
+	//	开始时间 = VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "运行确认及偏差处理(满载)开始时间")
+	//}
+	开始时间 := ""
+	if Task_r.T_device_type == "C" {
+		// 任务类型为C的时候,获取温度下降到最低点时间
+		// 1. 获取温度平均值
+		部点终端_sn_list := []string{}
+		for _, v := range 部点终端_list {
+			部点终端_sn_list = append(部点终端_sn_list, v.T_sn)
+		}
+		list := Task.Read_TaskData_ById_AVG(Task_r.T_task_id, strings.Join(部点终端_sn_list, "|"), "", "")
+		if len(list) < 2 {
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "均匀性布点+产品存放区域测点 数据平均值 少于2条!"})
+			return
+		}
+		// 查找最低点
+		// 找最低点
+		minRecord := list[0]
+		for i := 1; i <= len(list); i++ {
+			if list[i].T_t < minRecord.T_t {
+				minRecord = list[i]
+			}
+			if list[i].T_t > list[i-1].T_t {
+				break
+			}
+		}
+		开始时间 = minRecord.T_time
+	} else {
+		现场测试开始时间 := VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "现场测试开始时间")
+		if len(现场测试开始时间) == 0 || 现场测试开始时间 == "null" {
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 现场测试开始时间 失败!"})
+			return
+		}
+		开始时间 = 现场测试开始时间
 	}
 	if len(开始时间) == 0 {
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "未找到开始时间 标签!"})

+ 29 - 12
models/Device/DeviceClassList.go

@@ -20,13 +20,14 @@ import (
 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_class          int    `orm:"size(200);null"`     // 分类
+	T_id             string `orm:"size(20);null"`      // 设备id
+	T_sn             string `orm:"size(256);null"`     // 设备序列号 KF开头,环境监测主机。 YD开头,温途监测主机
+	T_terminal       int    `orm:"size(2);default(1)"` // 1-测点 2-终端
+	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 第一次保存时才设置时间
@@ -122,7 +123,6 @@ func Read_DeviceClassList(T_sn string) (r DeviceClassList, is bool) {
 	return r, true
 }
 
-
 // 添加
 func Read_DeviceClassList_T_class_T_sn(T_class int, T_sn string) (r DeviceClassList, is bool) {
 	o := orm.NewOrm()
@@ -298,18 +298,35 @@ func Read_DeviceClassList_List_id(T_class_Id int) (r []DeviceClassList) {
 	return r
 }
 
+// 排除终端
+func Read_DeviceClassList_List_id_By_Terminal(T_class_Id int, T_Terminal bool) (r []DeviceClassList) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+
+	qs := o.QueryTable(new(DeviceClassList))
+
+	if T_Terminal == true {
+		qs.Filter("T_class", T_class_Id).Filter("T_State", 1).Filter("T_terminal", 2).All(&r)
+		return r
+	}
+	// T_terminal = 1 测点
+	qs.Filter("T_class", T_class_Id).Filter("T_State", 1).Filter("T_terminal", 1).All(&r)
+	return r
+}
+
 // 获取列表
-func Read_DeviceClassList_List_id_T_remark(T_class_Id int,T_remark string) (r []DeviceClassList) {
+func Read_DeviceClassList_List_id_T_remark(T_class_Id int, T_remark string) (r []DeviceClassList) {
 
 	o := orm.NewOrm()
 	// 也可以直接使用 Model 结构体作为表名
 
 	qs := o.QueryTable(new(DeviceClassList))
-	T_remark_s := strings.Split(T_remark,"|")
+	T_remark_s := strings.Split(T_remark, "|")
 	cond := orm.NewCondition()
 	cond1 := orm.NewCondition()
 
-	for _,v := range T_remark_s{
+	for _, v := range T_remark_s {
 		if len(T_remark_s) > 0 {
 			cond1 = cond1.Or("T_remark__icontains", v) // .AndNot("status__in", 1).Or("profile__age__gt", 2000)
 
@@ -326,7 +343,7 @@ func Read_DeviceClassList_List_id_T_remark(T_class_Id int,T_remark string) (r []
 }
 
 // 获取列表
-func Read_DeviceClassList_List_id_T_sn(T_class_Id int,T_sn string) (r []DeviceClassList) {
+func Read_DeviceClassList_List_id_T_sn(T_class_Id int, T_sn string) (r []DeviceClassList) {
 
 	o := orm.NewOrm()
 	// 也可以直接使用 Model 结构体作为表名

+ 179 - 5
models/Task/TaskData.go

@@ -13,6 +13,7 @@ import (
 	"github.com/go-sql-driver/mysql"
 	_ "github.com/go-sql-driver/mysql"
 	"math"
+	"sort"
 	"strconv"
 	"strings"
 	"time"
@@ -164,8 +165,9 @@ type TaskData_ struct {
 	T_Certificate_sn string  `orm:"size(256);null"`              // 证书编号
 }
 type TaskDataClass_ struct {
-	T_sn string `orm:"column(t_sn);size(256);null"` // 标题
-	T_id string `orm:"column(t_id);size(256);null"` // 名称
+	T_sn       string `orm:"column(t_sn);size(256);null"` // 标题
+	T_id       string `orm:"column(t_id);size(256);null"` // 名称
+	T_terminal int
 }
 type TaskData_AVG struct {
 	T_t    float32 `orm:"column(t_t);size(10);null"` // 温度
@@ -1288,8 +1290,8 @@ func Read_TaskData_T_Min_Max_Time_Min_Max_ListGROUP(T_task_id string, SN string,
 }
 
 // 按照 t_id 分组数据
-func GroupDataByTID(data []TaskData) map[string][]TaskData {
-	groupedData := make(map[string][]TaskData)
+func GroupDataByTID(data []TaskData_) map[string][]TaskData_ {
+	groupedData := make(map[string][]TaskData_)
 	for _, d := range data {
 		groupedData[d.T_id] = append(groupedData[d.T_id], d)
 	}
@@ -1507,7 +1509,7 @@ func CalculateHumps(data []TaskData_AVG) []CalculateHumps_R {
 	i := 0
 	for i < n-5 {
 		// 寻找开始的最低点
-		for !(data[i].T_t <= data[i+1].T_t && data[i+1].T_t <= data[i+2].T_t) {
+		for !(data[i].T_t <= data[i+1].T_t && data[i+1].T_t <= data[i+2].T_t && data[i+2].T_t <= data[i+3].T_t) {
 			i++
 			if i > n-5 {
 				break
@@ -1551,6 +1553,55 @@ func CalculateHumps(data []TaskData_AVG) []CalculateHumps_R {
 		}
 	}
 
+	if len(humps) == 0 {
+		i = 0
+		for i < n-3 {
+			// 寻找开始的最低点
+			for !(data[i].T_t <= data[i+1].T_t && data[i+1].T_t <= data[i+2].T_t) {
+				i++
+				if i > n-3 {
+					break
+				}
+			}
+			start := i
+
+			// 寻找最高点
+			for !(data[i].T_t >= data[i+1].T_t && data[i+1].T_t > data[i+2].T_t) {
+				i++
+				if i > n-3 {
+					break
+				}
+			}
+			peak := i
+			Abs_peak := math.Abs(float64(data[start].T_t - data[peak].T_t))
+			if Abs_peak < 0.2 {
+				continue
+			}
+
+			// 寻找结束的最低点
+			for !(data[i].T_t <= data[i+1].T_t && data[i+1].T_t < data[i+2].T_t) {
+				i++
+				if i > n-3 {
+					break
+				}
+			}
+			end := i
+			Abs_end := math.Abs(float64(data[end].T_t - data[peak].T_t))
+			if Abs_end < 0.3 {
+				continue
+			}
+			// 如果找到了一个完整的驼峰
+			if start < peak && peak < end {
+				CalculateHumps_ := CalculateHumps_R{
+					Start: data[start],
+					Peak:  data[peak],
+					End:   data[end],
+				}
+				humps = append(humps, CalculateHumps_)
+			}
+		}
+	}
+
 	return humps
 }
 
@@ -1635,6 +1686,7 @@ func GetFirstTimeData(data []TaskData_) (list []TaskData_) {
 
 }
 
+// 温度下降到指定温度 或者下降到最低点+0.2℃
 func FindFirstDecreasingToNumber(data []TaskData_, number float32) *TaskData_ {
 	if len(data) < 2 {
 		return nil
@@ -1719,3 +1771,125 @@ func FindFirstDecreasingToNumber(data []TaskData_, number float32) *TaskData_ {
 
 	return nil
 }
+
+// 第一个持续下降趋势 到指定温度
+func FindFirstDecreasingTendency(data []TaskData_, number float32) *TaskData_ {
+	if len(data) < 2 {
+		return nil
+	}
+
+	startIndex := -1
+	for i := 0; i < len(data); i++ {
+		if data[i].T_t > number {
+			startIndex = i
+			break
+		}
+	}
+	if startIndex == -1 {
+		return nil
+	}
+
+	inDecreasing := false
+	record := data[startIndex:]
+	prev := record[0]
+
+	for i := 1; i < len(record); i++ {
+		curr := record[i]
+		if curr.T_t < prev.T_t {
+			// 下降趋势
+			if !inDecreasing {
+				inDecreasing = true
+			}
+			// 判断是否到达 8
+			if curr.T_t <= number {
+				return &curr
+			}
+		} else {
+			// 趋势中断,重置
+			inDecreasing = false
+		}
+		prev = curr
+	}
+
+	return nil
+}
+
+// 按照 t_id 分组数据
+func GroupDataByTSN(data []TaskData_) map[string][]TaskData_ {
+	groupedData := make(map[string][]TaskData_)
+	for _, d := range data {
+		groupedData[d.T_sn] = append(groupedData[d.T_sn], d)
+	}
+	return groupedData
+}
+
+// 计算样本标准差(n-1分母)
+func calculateStdDev(values []float64) float64 {
+	n := len(values)
+	if n < 2 {
+		return 0 // 单点数据无波动
+	}
+
+	// 计算均值
+	sum := 0.0
+	for _, v := range values {
+		sum += v
+	}
+	mean := sum / float64(n)
+
+	// 计算方差
+	variance := 0.0
+	for _, v := range values {
+		diff := v - mean
+		variance += diff * diff
+	}
+	variance /= float64(n - 1) // 样本方差分母n-1
+
+	return math.Sqrt(variance) // 标准差
+}
+
+// 获取波动度最大的三条数据集
+func GetTopThreeWithTheGreatestFluctuations(data []TaskData_) string {
+	// 存储波动度结果
+	type Result struct {
+		T_sn       string
+		StdDev     float64
+		DataPoints []TaskData_
+	}
+	dataSets := GroupDataByTSN(data)
+	results := make([]Result, len(dataSets))
+
+	// 计算每条数据集的波动度
+	for T_sn, dataset := range dataSets {
+		values := make([]float64, len(dataset))
+		for j, dp := range dataset {
+			values[j] = float64(dp.T_t)
+		}
+		results = append(results, Result{
+			T_sn:       T_sn,
+			StdDev:     calculateStdDev(values),
+			DataPoints: dataset,
+		})
+	}
+
+	// 按波动度降序排序
+	sort.Slice(results, func(i, j int) bool {
+		return results[i].StdDev > results[j].StdDev
+	})
+
+	// 输出波动最大的三条
+	fmt.Println("波动最大的三条数据集:")
+	for i, res := range results[:3] {
+		fmt.Printf("%d. 数据集%d (标准差=%.4f)\n", i+1, res.T_sn, res.StdDev)
+	}
+	snList := make([]string, 3)
+	if len(results) >= 3 {
+		snList = []string{results[0].T_sn, results[1].T_sn, results[2].T_sn}
+	} else {
+		for _, v := range results {
+			snList = append(snList, v.T_sn)
+		}
+	}
+
+	return strings.Join(snList, "|")
+}

+ 11 - 0
routers/TaskData.go

@@ -129,6 +129,10 @@ func init() {
 	beego.Router("/TaskDataContent/SSE_空载测试结束风机停止时间", &controllers.TaskDataController{}, "*:A空载测试结束风机停止时间")
 	beego.Router("/TaskDataContent/SSE_满载第一次关门温度恢复时间", &controllers.TaskDataController{}, "*:A满载第一次关门温度恢复时间")
 	beego.Router("/TaskDataContent/SSE_空载第一次关门温度恢复时间", &controllers.TaskDataController{}, "*:A空载第一次关门温度恢复时间")
+	beego.Router("/TaskDataContent/SSE_满载第二次关门温度恢复时间", &controllers.TaskDataController{}, "*:A满载第二次关门温度恢复时间")
+	beego.Router("/TaskDataContent/SSE_空载第二次关门温度恢复时间", &controllers.TaskDataController{}, "*:A空载第二次关门温度恢复时间")
+	beego.Router("/TaskDataContent/SSE_满载第三次关门温度恢复时间", &controllers.TaskDataController{}, "*:A满载第三次关门温度恢复时间")
+	beego.Router("/TaskDataContent/SSE_空载第三次关门温度恢复时间", &controllers.TaskDataController{}, "*:A空载第三次关门温度恢复时间")
 	beego.Router("/TaskDataContent/SSE_满载开门最长需要多少分钟恢复", &controllers.TaskDataController{}, "*:A满载开门最长需要多少分钟恢复")
 	beego.Router("/TaskDataContent/SSE_空载开门最长需要多少分钟恢复", &controllers.TaskDataController{}, "*:A空载开门最长需要多少分钟恢复")
 	beego.Router("/TaskDataContent/SSE_冷藏库作业口外部环境分割线最低温", &controllers.TaskDataController{}, "*:A冷藏库作业口外部环境分割线最低温")
@@ -157,5 +161,12 @@ func init() {
 	beego.Router("/TaskDataContent/SSE_监测系统配置的测点终端参数及安装位置确认空载结束时间", &controllers.TaskDataController{}, "*:A监测系统配置的测点终端参数及安装位置确认空载结束时间")
 	beego.Router("/TaskDataContent/SSE_培训讲师", &controllers.TaskDataController{}, "*:A培训讲师")
 	beego.Router("/TaskDataContent/SSE_培训时间", &controllers.TaskDataController{}, "*:A培训时间")
+	beego.Router("/TaskDataContent/SSE_作业出入口总测点", &controllers.TaskDataController{}, "*:A作业出入口总测点")
+	beego.Router("/TaskDataContent/SSE_风机布点总测点", &controllers.TaskDataController{}, "*:A风机布点总测点")
+	beego.Router("/TaskDataContent/SSE_库内除风机出风口回风口外总测点", &controllers.TaskDataController{}, "*:A库内除风机出风口回风口外总测点")
+	beego.Router("/TaskDataContent/SSE_库内除风机出风口回风口特殊位置布点作业口外总测点", &controllers.TaskDataController{}, "*:A库内除风机出风口回风口特殊位置布点作业口外总测点")
+	beego.Router("/TaskDataContent/SSE_车内除风机出风口回风口外总测点", &controllers.TaskDataController{}, "*:A车内除风机出风口回风口外总测点")
+	beego.Router("/TaskDataContent/SSE_预冷开始时间", &controllers.TaskDataController{}, "*:A预冷开始时间")
+	beego.Router("/TaskDataContent/SSE_预冷结束时间", &controllers.TaskDataController{}, "*:A预冷结束时间")
 
 }