Browse Source

add:添加修改存档接口

zoie 2 weeks ago
parent
commit
396828b052
6 changed files with 680 additions and 162 deletions
  1. 52 28
      controllers/TaskData.go
  2. 544 133
      controllers/TaskHandle.go
  3. 25 0
      models/Task/Task.go
  4. 10 0
      models/Task/TaskCopy.go
  5. 48 1
      models/Task/TaskData.go
  6. 1 0
      routers/TaskData.go

+ 52 - 28
controllers/TaskData.go

@@ -1836,7 +1836,7 @@ func (c *TaskDataController) DataSensorDataTrend() {
 		ttrh := first.T_rh
 
 		var valueStrings []string
-		for current.Unix() < next.Unix() {
+		for current.Unix() <= next.Unix() {
 			tt += ttInterval
 			ttrh += trhInterval
 			ttime := current.Format("2006-01-02 15:04")
@@ -2576,6 +2576,30 @@ func (c *TaskDataController) TaskDataCopy_Add() {
 
 }
 
+// 编辑存档
+func (c *TaskDataController) TaskDataCopy_Edit() {
+
+	T_copy_id := c.GetString("T_copy_id")
+	T_name := c.GetString("T_name")
+	r, err := Task.Read_TaskCopy(T_copy_id)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_copy_id 错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	r.T_time = T_name
+	if !Task.Update_TaskCopy(r, "T_time") {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: T_copy_id}
+	c.ServeJSON()
+	return
+
+}
+
 // 删除存档
 func (c *TaskDataController) TaskDataCopy_Del() {
 
@@ -4791,20 +4815,20 @@ func (c *TaskDataController) A外部环境分割线最高温() {
 		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: "获取 温度自动监测设备放置位置开始时间 失败!"})
+	现场测试开始时间 := 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: "获取 温度自动监测设备放置位置结束时间 失败!"})
+	现场测试结束时间 := c.GetString("现场测试结束时间") //  v26nplogbwt1
+	if len(现场测试结束时间) == 0 || 现场测试结束时间 == "null" {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 现场测试结束时间 失败!"})
 		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", RoundToDecimal(maxT+0.5, 1))})
 
 	// Close the connection
 	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
@@ -4830,20 +4854,20 @@ func (c *TaskDataController) A外部环境分割线最低温() {
 		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: "获取 温度自动监测设备放置位置开始时间 失败!"})
+	现场测试开始时间 := 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: "获取 温度自动监测设备放置位置结束时间 失败!"})
+	现场测试结束时间 := c.GetString("现场测试结束时间") //  v26nplogbwt1
+	if len(现场测试结束时间) == 0 || 现场测试结束时间 == "null" {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "获取 现场测试结束时间 失败!"})
 		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", RoundToDecimal(minT-0.5, 1))})
 
 	// Close the connection
 	c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
@@ -6024,7 +6048,7 @@ func (c *TaskDataController) A监测终端01() {
 		return
 	}
 
-	监测终端_list := Device.Read_DeviceClassList_List_id_By_Terminal(Task_r.T_class, true)
+	监测终端_list := Device.Read_DeviceClassList_List_id_T_remark(Task_r.T_class, "监测终端01")
 	if len(监测终端_list) > 0 {
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: 监测终端_list[0].T_sn})
 
@@ -6033,7 +6057,7 @@ func (c *TaskDataController) A监测终端01() {
 		return
 	}
 
-	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没有找到 终端01 !"})
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没有找到 监测终端01 !"})
 	return
 
 }
@@ -6051,7 +6075,7 @@ func (c *TaskDataController) A监测终端安装编号01() {
 		return
 	}
 
-	监测终端_list := Device.Read_DeviceClassList_List_id_By_Terminal(Task_r.T_class, true)
+	监测终端_list := Device.Read_DeviceClassList_List_id_T_remark(Task_r.T_class, "监测终端01")
 	if len(监测终端_list) > 0 {
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: 监测终端_list[0].T_id})
 
@@ -6060,7 +6084,7 @@ func (c *TaskDataController) A监测终端安装编号01() {
 		return
 	}
 
-	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没有找到 监测终端 1 终端!"})
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没有找到 监测终端01 终端!"})
 	return
 }
 func (c *TaskDataController) A监测终端02() {
@@ -6077,16 +6101,16 @@ func (c *TaskDataController) A监测终端02() {
 		return
 	}
 
-	监测终端_list := Device.Read_DeviceClassList_List_id_By_Terminal(Task_r.T_class, true)
-	if len(监测终端_list) > 2 {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: 监测终端_list[1].T_sn})
+	监测终端_list := Device.Read_DeviceClassList_List_id_T_remark(Task_r.T_class, "监测终端02")
+	if len(监测终端_list) > 1 {
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: 监测终端_list[0].T_sn})
 
 		// Close the connection
 		c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
 		return
 	}
 
-	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没有找到 监测终端 2 终端!"})
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没有找到 监测终端02 终端!"})
 	return
 
 }
@@ -6104,16 +6128,16 @@ func (c *TaskDataController) A监测终端安装编号02() {
 		return
 	}
 
-	监测终端_list := Device.Read_DeviceClassList_List_id_By_Terminal(Task_r.T_class, true)
+	监测终端_list := Device.Read_DeviceClassList_List_id_T_remark(Task_r.T_class, "监测终端02")
 	if len(监测终端_list) > 1 {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: 监测终端_list[1].T_id})
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 1, Msg: 监测终端_list[0].T_id})
 
 		// Close the connection
 		c.Ctx.ResponseWriter.WriteHeader(http.StatusOK)
 		return
 	}
 
-	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没有找到 监测终端 2 终端!"})
+	lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "没有找到 监测终端02 终端!"})
 	return
 }
 

+ 544 - 133
controllers/TaskHandle.go

@@ -6,6 +6,7 @@ import (
 	"ColdVerify_local/models/Device"
 	"ColdVerify_local/models/Task"
 	"ColdVerify_local/models/VerifyTemplate"
+	"errors"
 	"fmt"
 	beego "github.com/beego/beego/v2/server/web"
 	"math"
@@ -321,7 +322,7 @@ func (c *TaskDataHandleController) SSE_Interval_data_correction() {
 	var 开始时间, 结束时间, 趋势时间 string
 	开始时间, 结束时间, 趋势时间 = c.GetStartTimeAndEndTime(Task_r, 部点终端_sn_list, 温度控制范围最高值)
 	if 开始时间 == "" || 结束时间 == "" {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "未找到 开始时间 或 结束时间 结束时间!"})
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "未找到 开始时间 或 结束时间!"})
 		return
 	}
 
@@ -349,10 +350,13 @@ func (c *TaskDataHandleController) SSE_Interval_data_correction() {
 	}
 
 	// ----------获取保留数据------------
-	var 开空开, 开空开驼峰结束时间, 保空开, 保空开驼峰结束时间 string
-	var valueStrings1, valueStrings2, BWXValueStrings []string
+	//var 开空开, 保空开 string
+	//var 开空开驼峰, 保空开驼峰 Task.CalculateHumps_R
+	//var valueStrings1, valueStrings2 []string
+	var BWXValueStrings []string
+
 	if Task_r.T_device_type != "X" {
-		valueStrings1, valueStrings2, 开空开, 开空开驼峰结束时间, 保空开, 保空开驼峰结束时间 = c.GetRetainData(Task_r, 部点终端_sn_list)
+		//valueStrings1, valueStrings2, 开空开, 保空开, 开空开驼峰, 保空开驼峰 = c.GetRetainData(Task_r, 部点终端_list, false)
 	} else {
 		BWXValueStrings = c.GetBWXRetainData(Task_r, 部点终端_sn_list, 结束时间, 趋势时间)
 	}
@@ -389,6 +393,38 @@ func (c *TaskDataHandleController) SSE_Interval_data_correction() {
 			T_min_compress := RoundToDecimal(AVGClassList_i.T_min*compress, 1)
 			// 判断压缩后是否在 温度控制范围最小值-温度控制范围最高值范围内 不做处理
 			if T_max_compress <= RoundToDecimal(温度控制范围最高值-0.1, 1) && T_min_compress >= RoundToDecimal(温度控制范围最小值+0.1, 1) {
+
+				参考值 := RoundToDecimal((温度控制范围最高值+温度控制范围最小值)/2, 1)
+				中间值 := RoundToDecimal((AVGClassList_i.T_max+AVGClassList_i.T_min)/2, 1)
+
+				if 参考值 > 中间值 {
+					// 向上偏移
+					vgaca = 参考值 - 中间值
+					Task.UpdateTaskDataTemperatureAndHumidity(Task_r.T_task_id, AVGClassList_i.T_sn, AVGClassList_i.T_id, "", "", vgaca, 0)
+					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "进行处理 数据!" + lib.To_string(AVGClassList_i.T_id) +
+						" 最大值:" + lib.To_string(AVGClassList_i.T_max) + "℃  " +
+						" 最小值:" + lib.To_string(AVGClassList_i.T_min) + "℃  " +
+						" 压缩:" + lib.To_string(compress) +
+						" 压缩后最大值:" + lib.To_string(T_max_compress) + "℃  " +
+						" 压缩后最小值:" + lib.To_string(T_min_compress) + "℃  " +
+						" 向上偏移:" + lib.To_string(vgaca) + "℃ "})
+					continue
+				}
+
+				if 参考值 < 中间值 {
+					// 向下偏移
+					vgaca = 中间值 - 参考值
+					Task.UpdateTaskDataTemperatureAndHumidity(Task_r.T_task_id, AVGClassList_i.T_sn, AVGClassList_i.T_id, "", "", -vgaca, 0)
+					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "进行处理 数据!" + lib.To_string(AVGClassList_i.T_id) +
+						" 最大值:" + lib.To_string(AVGClassList_i.T_max) + "℃  " +
+						" 最小值:" + lib.To_string(AVGClassList_i.T_min) + "℃  " +
+						" 压缩:" + lib.To_string(compress) +
+						" 压缩后最大值:" + lib.To_string(T_max_compress) + "℃  " +
+						" 压缩后最小值:" + lib.To_string(T_min_compress) + "℃  " +
+						" 向下偏移:" + lib.To_string(vgaca) + "℃ "})
+					continue
+				}
+
 				lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "进行处理 数据!" + lib.To_string(AVGClassList_i.T_id) +
 					" 最大值:" + lib.To_string(AVGClassList_i.T_max) + "℃  " +
 					" 最小值:" + lib.To_string(AVGClassList_i.T_min) + "℃  " +
@@ -399,7 +435,8 @@ func (c *TaskDataHandleController) SSE_Interval_data_correction() {
 			}
 			// 压缩后仍高于 温度控制范围最高值,向下偏移
 			if T_max_compress >= 温度控制范围最高值 {
-				vgaca = RoundToDecimal(T_max_compress-温度控制范围最高值+0.1, 1)
+				vgaca = RoundToDecimal((T_max_compress+T_min_compress)/2-(温度控制范围最高值+温度控制范围最小值)/2, 1)
+				//vgaca = RoundToDecimal(T_max_compress-温度控制范围最高值+0.1, 1)
 				lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "进行处理 数据!" + lib.To_string(AVGClassList_i.T_id) +
 					" 最大值:" + lib.To_string(AVGClassList_i.T_max) + "℃  " +
 					" 最小值:" + lib.To_string(AVGClassList_i.T_min) + "℃  " +
@@ -415,7 +452,9 @@ func (c *TaskDataHandleController) SSE_Interval_data_correction() {
 			// 压缩后仍低于 温度控制范围最小值,向上偏移
 			if T_min_compress <= 温度控制范围最小值 {
 				// 向上偏移
-				vgaca = RoundToDecimal(温度控制范围最小值-AVGClassList_i.T_min*compress+0.1, 1)
+				vgaca = RoundToDecimal((温度控制范围最高值+温度控制范围最小值)/2-(T_max_compress+T_min_compress)/2, 1)
+
+				//vgaca = RoundToDecimal(温度控制范围最小值-AVGClassList_i.T_min*compress+0.1, 1)
 
 				lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "进行处理 数据!" + lib.To_string(AVGClassList_i.T_id) +
 					" 最大值:" + lib.To_string(AVGClassList_i.T_max) + "℃  " +
@@ -433,7 +472,8 @@ func (c *TaskDataHandleController) SSE_Interval_data_correction() {
 		} else {
 			// 向下偏移
 			if AVGClassList_i.T_max >= 温度控制范围最高值 {
-				vgaca = RoundToDecimal(AVGClassList_i.T_max-温度控制范围最高值+0.1, 1)
+
+				vgaca = RoundToDecimal(AVGClassList_i.T_max-温度控制范围最高值+0.2, 1)
 				lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "进行处理 数据!" + lib.To_string(AVGClassList_i.T_id) +
 					" 最大值:" + lib.To_string(AVGClassList_i.T_max) + "℃  " +
 					" 最小值:" + lib.To_string(AVGClassList_i.T_min) + "℃  " +
@@ -444,7 +484,7 @@ func (c *TaskDataHandleController) SSE_Interval_data_correction() {
 				continue
 			}
 			if AVGClassList_i.T_min <= 温度控制范围最小值 {
-				vgaca = RoundToDecimal(温度控制范围最小值-AVGClassList_i.T_min+0.1, 1)
+				vgaca = RoundToDecimal(温度控制范围最小值-AVGClassList_i.T_min+0.2, 1)
 				lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "进行处理 数据!" + lib.To_string(AVGClassList_i.T_id) +
 					" 最大值:" + lib.To_string(AVGClassList_i.T_max) + "℃  " +
 					" 最小值:" + lib.To_string(AVGClassList_i.T_min) + "℃  " +
@@ -458,7 +498,8 @@ func (c *TaskDataHandleController) SSE_Interval_data_correction() {
 
 	// ----------恢复保留数据------------
 	if Task_r.T_device_type != "X" {
-		c.SaveRetainData(Task_r, 部点终端_list, valueStrings1, valueStrings2, 开空开, 开空开驼峰结束时间, 保空开, 保空开驼峰结束时间)
+		//c.SaveRetainData(Task_r, 部点终端_list, valueStrings1, valueStrings2, 开空开, 保空开, 开空开驼峰, 保空开驼峰, 温度控制范围最高值, 60)
+
 	} else {
 		c.SaveBWXRetainData(Task_r, 部点终端_list, BWXValueStrings, 结束时间, 趋势时间, 60)
 	}
@@ -515,15 +556,18 @@ func (c *TaskDataHandleController) SSE_Comparison_between_binding_points_and_ter
 	var 开始时间, 结束时间, 趋势时间 string
 	开始时间, 结束时间, 趋势时间 = c.GetStartTimeAndEndTime(Task_r, 部点终端_sn_list, 温度控制范围最高值)
 	if 开始时间 == "" || 结束时间 == "" {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "未找到 开始时间 或 结束时间 结束时间!"})
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "未找到 开始时间 或 结束时间!"})
 		return
 	}
 
 	// ----------获取保留数据------------
-	var 开空开, 开空开驼峰结束时间, 保空开, 保空开驼峰结束时间 string
-	var valueStrings1, valueStrings2, BWXValueStrings []string
+	var 开空开, 保空开 string
+	var 开空开驼峰, 保空开驼峰 Task.CalculateHumps_R
+	var BWXValueStrings []string
+	var valueStrings1, valueStrings2 []string
+
 	if Task_r.T_device_type != "X" {
-		valueStrings1, valueStrings2, 开空开, 开空开驼峰结束时间, 保空开, 保空开驼峰结束时间 = c.GetRetainData(Task_r, 部点终端_sn_list)
+		valueStrings1, valueStrings2, 开空开, 保空开, 开空开驼峰, 保空开驼峰 = c.GetRetainData(Task_r, 部点终端_list, true)
 	} else {
 		BWXValueStrings = c.GetBWXRetainData(Task_r, 部点终端_sn_list, 结束时间, 趋势时间)
 	}
@@ -618,8 +662,12 @@ func (c *TaskDataHandleController) SSE_Comparison_between_binding_points_and_ter
 		}
 		// 获取监测终端和绑定点的平均值
 		目标温湿度绑定点vga, 目标温湿度绑定点2vga, isExist := findBindingPointsOptimalAdjustment(监测终端vga, 监测终端2vga, 温湿度绑定点vga, 温湿度绑定点2vga, T_deviation)
+		目标温湿度绑定点vga = RoundToDecimal(目标温湿度绑定点vga, 1)
+		目标温湿度绑定点2vga = RoundToDecimal(目标温湿度绑定点2vga, 1)
 		if !isExist {
-			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "未找到 最优 温湿度绑定点1|温湿度绑定点2| 调整值!"})
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "监测终端01 平均值" + lib.To_string(监测终端vga) + "℃ " +
+				"监测终端02 平均值" + lib.To_string(监测终端2vga) + "℃ " +
+				"未找到 最优 温湿度绑定点1、温湿度绑定点2 调整值!"})
 			return
 		}
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "监测终端01 平均值" + lib.To_string(监测终端vga) + "℃ " +
@@ -649,13 +697,13 @@ func (c *TaskDataHandleController) SSE_Comparison_between_binding_points_and_ter
 			T_min := Task.Read_TaskData_min(T_task_id, 温湿度绑定点2.T_sn, 温湿度绑定点2.T_id, 开始时间, 结束时间)
 
 			// 平均值向下偏移
-			if 温湿度绑定点vga > RoundToDecimal(目标温湿度绑定点vga, 1) {
-				c.SetAverageShiftedDownward(T_task_id, 温湿度绑定点2.T_id, 0, 目标温湿度绑定点vga, 温湿度绑定点vga, T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
+			if 温湿度绑定点2vga > RoundToDecimal(目标温湿度绑定点2vga, 1) {
+				c.SetAverageShiftedDownward(T_task_id, 温湿度绑定点2.T_id, 0, 目标温湿度绑定点2vga, 温湿度绑定点2vga, T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
 			}
 
 			// 平均值向上偏移
-			if 温湿度绑定点vga < RoundToDecimal(目标温湿度绑定点vga, 1) {
-				c.SetAverageShiftedUpward(T_task_id, 温湿度绑定点2.T_id, 0, 目标温湿度绑定点vga, 温湿度绑定点vga, T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
+			if 温湿度绑定点2vga < RoundToDecimal(目标温湿度绑定点2vga, 1) {
+				c.SetAverageShiftedUpward(T_task_id, 温湿度绑定点2.T_id, 0, 目标温湿度绑定点2vga, 温湿度绑定点2vga, T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
 			}
 		}
 
@@ -663,7 +711,7 @@ func (c *TaskDataHandleController) SSE_Comparison_between_binding_points_and_ter
 
 	// ----------恢复保留数据------------
 	if Task_r.T_device_type != "X" {
-		c.SaveRetainData(Task_r, 部点终端_list, valueStrings1, valueStrings2, 开空开, 开空开驼峰结束时间, 保空开, 保空开驼峰结束时间)
+		c.SaveRetainData(Task_r, 部点终端_list, valueStrings1, valueStrings2, 开空开, 保空开, 开空开驼峰, 保空开驼峰, 温度控制范围最高值, 60)
 	} else {
 		c.SaveBWXRetainData(Task_r, 部点终端_list, BWXValueStrings, 结束时间, 趋势时间, 60)
 	}
@@ -734,15 +782,18 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_cold_and_hot_
 	var 开始时间, 结束时间, 趋势时间 string
 	开始时间, 结束时间, 趋势时间 = c.GetStartTimeAndEndTime(Task_r, 部点终端_sn_list, 温度控制范围最高值)
 	if 开始时间 == "" || 结束时间 == "" {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "未找到 开始时间 或 结束时间 结束时间!"})
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "未找到 开始时间 或 结束时间!"})
 		return
 	}
 
 	// ----------获取保留数据------------
-	var 开空开, 开空开驼峰结束时间, 保空开, 保空开驼峰结束时间 string
-	var valueStrings1, valueStrings2, BWXValueStrings []string
+	var 开空开, 保空开 string
+	var 开空开驼峰, 保空开驼峰 Task.CalculateHumps_R
+	var BWXValueStrings []string
+	var valueStrings1, valueStrings2 []string
+
 	if Task_r.T_device_type != "X" {
-		valueStrings1, valueStrings2, 开空开, 开空开驼峰结束时间, 保空开, 保空开驼峰结束时间 = c.GetRetainData(Task_r, 部点终端_sn_list)
+		valueStrings1, valueStrings2, 开空开, 保空开, 开空开驼峰, 保空开驼峰 = c.GetRetainData(Task_r, 部点终端_list, true)
 	} else {
 		BWXValueStrings = c.GetBWXRetainData(Task_r, 部点终端_sn_list, 结束时间, 趋势时间)
 	}
@@ -869,7 +920,7 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_cold_and_hot_
 
 	// ----------恢复保留数据------------
 	if Task_r.T_device_type != "X" {
-		c.SaveRetainData(Task_r, 部点终端_list, valueStrings1, valueStrings2, 开空开, 开空开驼峰结束时间, 保空开, 保空开驼峰结束时间)
+		c.SaveRetainData(Task_r, 部点终端_list, valueStrings1, valueStrings2, 开空开, 保空开, 开空开驼峰, 保空开驼峰, 温度控制范围最高值, 60)
 	} else {
 		c.SaveBWXRetainData(Task_r, 部点终端_list, BWXValueStrings, 结束时间, 趋势时间, 60)
 	}
@@ -1026,15 +1077,18 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_Average() {
 	var 开始时间, 结束时间, 趋势时间 string
 	开始时间, 结束时间, 趋势时间 = c.GetStartTimeAndEndTime(Task_r, 部点终端_sn_list, 温度控制范围最高值)
 	if 开始时间 == "" || 结束时间 == "" {
-		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "未找到 开始时间 或 结束时间 结束时间!"})
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "未找到 开始时间 或 结束时间!"})
 		return
 	}
 
 	// ----------获取保留数据------------
-	var 开空开, 开空开驼峰结束时间, 保空开, 保空开驼峰结束时间 string
-	var valueStrings1, valueStrings2, BWXValueStrings []string
+	var 开空开, 保空开 string
+	var 开空开驼峰, 保空开驼峰 Task.CalculateHumps_R
+	var BWXValueStrings []string
+	var valueStrings1, valueStrings2 []string
+
 	if Task_r.T_device_type != "X" {
-		valueStrings1, valueStrings2, 开空开, 开空开驼峰结束时间, 保空开, 保空开驼峰结束时间 = c.GetRetainData(Task_r, 部点终端_sn_list)
+		valueStrings1, valueStrings2, 开空开, 保空开, 开空开驼峰, 保空开驼峰 = c.GetRetainData(Task_r, 部点终端_list, true)
 	} else {
 		BWXValueStrings = c.GetBWXRetainData(Task_r, 部点终端_sn_list, 结束时间, 趋势时间)
 	}
@@ -1067,6 +1121,7 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_Average() {
 		}
 	}
 	温湿度绑定点vga := Task.Read_TaskData_AVG(T_task_id, 温湿度绑定点1.T_sn, 温湿度绑定点1.T_id, 开始时间, 结束时间)
+	温湿度绑定点vga = RoundToDecimal(温湿度绑定点vga, 1)
 	if 温湿度绑定点vga == 0 {
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "温湿度绑定点1 无数据!请先处理数据!"})
 		return
@@ -1075,6 +1130,11 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_Average() {
 
 		温湿度绑定点vga = RoundToDecimal(温湿度绑定点vga, 1)
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "------ 进行 柜内所有测点|箱内所有测点|均匀性布点|产品存放区域测点 平均值处理 ------"})
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "" +
+			"温湿度绑定点1 平均值:" + lib.To_string(温湿度绑定点vga) + "℃ " +
+			"测点 平均值" + lib.To_string(originalAvg) + "℃ " +
+			"数据偏差: " + lib.To_string(RoundToDecimal(math.Abs(originalAvg-温湿度绑定点vga), 1)) + "℃ " +
+			"设置:" + lib.To_string(T_deviation) + "℃"})
 		if (originalAvg >= 温湿度绑定点vga && originalAvg <= 温湿度绑定点vga+T_deviation) || (originalAvg <= 温湿度绑定点vga && originalAvg >= 温湿度绑定点vga-T_deviation) {
 			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "" +
 				"温湿度绑定点1 平均值:" + lib.To_string(温湿度绑定点vga) + "℃ " +
@@ -1085,8 +1145,13 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_Average() {
 		} else {
 			// 平均值最低点向上偏移
 			if originalAvg < 温湿度绑定点vga-T_deviation {
-
+				k := 0
 				for originalAvg < 温湿度绑定点vga-T_deviation {
+					if k == len(部点终端_sn_list) {
+						// 调整所有平均值都不符合要求,直接停止
+						lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "调整所有测点平均值后均不符合要求!"})
+						break
+					}
 					TaskData_Average_GroupBySnId := Task.Read_TaskData_Average_GroupBySnId(Task_r.T_task_id, snList, 开始时间, 结束时间)
 					if len(TaskData_Average_GroupBySnId) == 0 {
 						break
@@ -1094,29 +1159,35 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_Average() {
 					Average_L := TaskData_Average_GroupBySnId[len(TaskData_Average_GroupBySnId)-1]
 					T_max := Task.Read_TaskData_max(T_task_id, Average_L.T_sn, Average_L.T_id, 开始时间, 结束时间)
 					T_min := Task.Read_TaskData_min(T_task_id, Average_L.T_sn, Average_L.T_id, 开始时间, 结束时间)
-					c.SetAverageShiftedUpward(T_task_id, Average_L.T_id, T_deviation, RoundToDecimal(Average_L.Average+0.1, 1), Average_L.Average, T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
+					c.SetAverageShiftedUpward(T_task_id, Average_L.T_id, T_deviation, RoundToDecimal(温湿度绑定点vga-T_deviation, 1), RoundToDecimal(Average_L.Average, 1), T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
 					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "" +
 						"温湿度绑定点1 平均值:" + lib.To_string(温湿度绑定点vga) + "℃ " +
 						"测点 平均值" + lib.To_string(originalAvg) + "℃ " +
-						"数据偏差: " + lib.To_string(math.Abs(originalAvg-温湿度绑定点vga)) + "℃ " +
+						"数据偏差: " + lib.To_string(RoundToDecimal(温湿度绑定点vga-T_deviation-originalAvg, 1)) + "℃ " +
 						"设置:" + lib.To_string(T_deviation) + "℃" +
-						"向上偏移0.1℃"})
+						"平均值向上偏移0.1℃"})
 					originalAvg = Task.Read_TaskData_Average(Task_r.T_task_id, snList, 开始时间, 结束时间)
 					originalAvg = RoundToDecimal(originalAvg, 1)
+					k++
 
 				}
 				lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "" +
 					"温湿度绑定点1 平均值:" + lib.To_string(温湿度绑定点vga) + "℃ " +
 					"测点 平均值" + lib.To_string(originalAvg) + "℃ " +
-					"数据偏差: " + lib.To_string(RoundToDecimal(math.Abs(originalAvg-温湿度绑定点vga), 1)) + "℃ " +
+					"数据偏差: " + lib.To_string(RoundToDecimal(温湿度绑定点vga-T_deviation-originalAvg, 1)) + "℃ " +
 					"设置:" + lib.To_string(T_deviation) + "℃" +
 					"符合要求!"})
 			}
 
 			// 向下偏移
 			if originalAvg > 温湿度绑定点vga+T_deviation {
-
+				l := 0
 				for originalAvg > 温湿度绑定点vga+T_deviation {
+					if l == len(部点终端_sn_list) {
+						// 调整所有平均值都不符合要求,直接停止
+						lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "调整所有测点平均值后均不符合要求!"})
+						break
+					}
 					// 热点向下偏移到高点范围
 					TaskData_Average_GroupBySnId := Task.Read_TaskData_Average_GroupBySnId(Task_r.T_task_id, snList, 开始时间, 结束时间)
 					if len(TaskData_Average_GroupBySnId) == 0 {
@@ -1127,31 +1198,30 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_Average() {
 					T_max := Task.Read_TaskData_max(T_task_id, Average_H.T_sn, Average_H.T_id, 开始时间, 结束时间)
 					T_min := Task.Read_TaskData_min(T_task_id, Average_H.T_sn, Average_H.T_id, 开始时间, 结束时间)
 
-					c.SetAverageShiftedDownward(T_task_id, Average_H.T_id, T_deviation, RoundToDecimal(Average_H.Average-0.1, 1), Average_H.Average, T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
+					c.SetAverageShiftedDownward(T_task_id, Average_H.T_id, T_deviation, RoundToDecimal(温湿度绑定点vga+T_deviation, 1), Average_H.Average, T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
 
 					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "" +
 						"温湿度绑定点1 平均值:" + lib.To_string(温湿度绑定点vga) + "℃ " +
 						"测点 平均值" + lib.To_string(originalAvg) + "℃ " +
-						"数据偏差: " + lib.To_string(RoundToDecimal(math.Abs(originalAvg-温湿度绑定点vga), 1)) + "℃ " +
-						"设置:" + lib.To_string(T_deviation) + "℃" +
-						"向下偏移0.1℃"})
+						"数据偏差: " + lib.To_string(RoundToDecimal(originalAvg-(温湿度绑定点vga+T_deviation), 1)) + "℃ " +
+						"设置:" + lib.To_string(T_deviation) + "℃"})
 					originalAvg = Task.Read_TaskData_Average(Task_r.T_task_id, snList, 开始时间, 结束时间)
 					originalAvg = RoundToDecimal(originalAvg, 1)
-
+					l++
 				}
 				lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "" +
 					"温湿度绑定点1 平均值:" + lib.To_string(温湿度绑定点vga) + "℃ " +
 					"测点 平均值" + lib.To_string(originalAvg) + "℃ " +
-					"数据偏差: " + lib.To_string(RoundToDecimal(math.Abs(originalAvg-温湿度绑定点vga), 1)) + "℃ " +
+					"数据偏差: " + lib.To_string(RoundToDecimal(originalAvg-(温湿度绑定点vga+T_deviation), 1)) + "℃ " +
 					"设置:" + lib.To_string(T_deviation) + "℃" +
 					"符合要求!"})
-
 			}
 
 		}
 
 	} else if len(温湿度绑定点_list) == 2 {
 		温湿度绑定点2vga := Task.Read_TaskData_AVG(T_task_id, 温湿度绑定点2.T_sn, 温湿度绑定点2.T_id, 开始时间, 结束时间)
+		温湿度绑定点2vga = RoundToDecimal(温湿度绑定点2vga, 1)
 		if 温湿度绑定点2vga == 0 {
 			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "温湿度绑定点2 无数据!请先处理数据!"})
 			return
@@ -1160,11 +1230,26 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_Average() {
 		// 获取最优平均值
 		目标originalAvg := findAverageOptimalAdjustment(温湿度绑定点vga, 温湿度绑定点2vga, originalAvg)
 		目标originalAvg = RoundToDecimal(目标originalAvg, 1)
+
+		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "" +
+			" 温湿度绑定点1 平均值:" + lib.To_string(温湿度绑定点vga) + "℃ " +
+			" 温湿度绑定点2 平均值:" + lib.To_string(温湿度绑定点2vga) + "℃ " +
+			" 测点 平均值" + lib.To_string(originalAvg) + "℃ " +
+			" 最优 平均值" + lib.To_string(目标originalAvg) + "℃ " +
+			" 数据偏差: " + lib.To_string(RoundToDecimal(RoundToDecimal(originalAvg-目标originalAvg, 1), 1)) + "℃ " +
+			" 设置:" + lib.To_string(T_deviation) + "℃"})
+
 		if 目标originalAvg != originalAvg {
 			// 平均值最低点向上偏移
-			if originalAvg < 目标originalAvg {
 
+			if originalAvg < 目标originalAvg {
+				j := 0
 				for originalAvg < 目标originalAvg {
+					if j == len(部点终端_sn_list) {
+						// 调整所有平均值都不符合要求,直接停止
+						lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "调整所有测点平均值后均不符合要求!"})
+						break
+					}
 					TaskData_Average_GroupBySnId := Task.Read_TaskData_Average_GroupBySnId(Task_r.T_task_id, snList, 开始时间, 结束时间)
 					if len(TaskData_Average_GroupBySnId) == 0 {
 						break
@@ -1172,7 +1257,7 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_Average() {
 					Average_L := TaskData_Average_GroupBySnId[len(TaskData_Average_GroupBySnId)-1]
 					T_max := Task.Read_TaskData_max(T_task_id, Average_L.T_sn, Average_L.T_id, 开始时间, 结束时间)
 					T_min := Task.Read_TaskData_min(T_task_id, Average_L.T_sn, Average_L.T_id, 开始时间, 结束时间)
-					c.SetAverageShiftedUpward(T_task_id, Average_L.T_id, T_deviation, RoundToDecimal(Average_L.Average+0.1, 1), Average_L.Average, T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
+					c.SetAverageShiftedUpward(T_task_id, Average_L.T_id, T_deviation, 目标originalAvg, RoundToDecimal(Average_L.Average, 1), T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
 					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "" +
 						" 温湿度绑定点1 平均值:" + lib.To_string(温湿度绑定点vga) + "℃ " +
 						" 温湿度绑定点2 平均值:" + lib.To_string(温湿度绑定点2vga) + "℃ " +
@@ -1180,10 +1265,10 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_Average() {
 						" 测点 最优平均值" + lib.To_string(目标originalAvg) + "℃ " +
 						" 数据偏差: " + lib.To_string(math.Abs(originalAvg-目标originalAvg)) + "℃ " +
 						" 设置:" + lib.To_string(T_deviation) + "℃" +
-						" 冷点:" + Average_L.T_id +
-						" 向上偏移0.1℃"})
+						" 冷点:" + Average_L.T_id})
 					originalAvg = Task.Read_TaskData_Average(Task_r.T_task_id, snList, 开始时间, 结束时间)
 					originalAvg = RoundToDecimal(originalAvg, 1)
+					j++
 				}
 				lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "" +
 					" 温湿度绑定点1 平均值:" + lib.To_string(温湿度绑定点vga) + "℃ " +
@@ -1193,12 +1278,20 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_Average() {
 					" 数据偏差: " + lib.To_string(RoundToDecimal(math.Abs(originalAvg-温湿度绑定点vga), 1)) + "℃ " +
 					" 设置:" + lib.To_string(T_deviation) + "℃" +
 					" 符合要求!"})
+
 			}
 
 			// 向下偏移
+
 			if originalAvg > 目标originalAvg {
 
+				i := 0
 				for originalAvg > 目标originalAvg {
+					if i == len(部点终端_sn_list) {
+						// 调整所有平均值都不符合要求,直接停止
+						lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "调整所有测点平均值后均不符合要求!"})
+						break
+					}
 					// 热点向下偏移到高点范围
 					TaskData_Average_GroupBySnId := Task.Read_TaskData_Average_GroupBySnId(Task_r.T_task_id, snList, 开始时间, 结束时间)
 					if len(TaskData_Average_GroupBySnId) == 0 {
@@ -1209,24 +1302,24 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_Average() {
 					T_max := Task.Read_TaskData_max(T_task_id, Average_H.T_sn, Average_H.T_id, 开始时间, 结束时间)
 					T_min := Task.Read_TaskData_min(T_task_id, Average_H.T_sn, Average_H.T_id, 开始时间, 结束时间)
 
-					c.SetAverageShiftedDownward(T_task_id, Average_H.T_id, T_deviation, RoundToDecimal(Average_H.Average-0.1, 1), Average_H.Average, T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
+					c.SetAverageShiftedDownward(T_task_id, Average_H.T_id, T_deviation, 目标originalAvg, RoundToDecimal(Average_H.Average, 1), T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
 					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "" +
 						" 温湿度绑定点1 平均值:" + lib.To_string(温湿度绑定点vga) + "℃ " +
 						" 温湿度绑定点2 平均值:" + lib.To_string(温湿度绑定点2vga) + "℃ " +
 						" 测点 平均值" + lib.To_string(originalAvg) + "℃ " +
 						" 测点 最优平均值" + lib.To_string(目标originalAvg) + "℃ " +
-						" 数据偏差: " + lib.To_string(math.Abs(originalAvg-目标originalAvg)) + "℃ " +
+						" 数据偏差: " + lib.To_string(RoundToDecimal(originalAvg-目标originalAvg, 1)) + "℃ " +
 						" 设置:" + lib.To_string(T_deviation) + "℃" +
-						" 冷点:" + Average_H.T_id +
-						" 向下偏移0.1℃"})
+						" 冷点:" + Average_H.T_id})
 					originalAvg = Task.Read_TaskData_Average(Task_r.T_task_id, snList, 开始时间, 结束时间)
 					originalAvg = RoundToDecimal(originalAvg, 1)
+					i++
 				}
 				lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "" +
 					" 温湿度绑定点1 平均值:" + lib.To_string(温湿度绑定点vga) + "℃ " +
 					" 温湿度绑定点2 平均值:" + lib.To_string(温湿度绑定点2vga) + "℃ " +
 					" 测点 平均值" + lib.To_string(originalAvg) + "℃ " +
-					" 数据偏差: " + lib.To_string(RoundToDecimal(math.Abs(originalAvg-目标originalAvg), 1)) + "℃ " +
+					" 数据偏差: " + lib.To_string(RoundToDecimal(RoundToDecimal(originalAvg-目标originalAvg, 1), 1)) + "℃ " +
 					" 设置:" + lib.To_string(T_deviation) + "℃" +
 					" 符合要求!"})
 
@@ -1240,7 +1333,6 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_Average() {
 	温控传感器绑定点_list := Device.Read_DeviceClassList_List_id_T_remark(Task_r.T_class, "温控传感器绑定点1|温控传感器绑定点2")
 	if len(温控传感器绑定点_list) == 0 {
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "没有找到温控传感器绑定点!"})
-		return
 	}
 
 	for i, classList := range 温控传感器绑定点_list {
@@ -1258,26 +1350,16 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_Average() {
 			// 平均值最低点向上偏移
 			if 温控传感器绑定点OriginalAvg < originalAvg-T_deviation {
 
-				for 温控传感器绑定点OriginalAvg < originalAvg-T_deviation {
-
-					T_max := Task.Read_TaskData_max(T_task_id, classList.T_sn, classList.T_id, 开始时间, 结束时间)
-					T_min := Task.Read_TaskData_min(T_task_id, classList.T_sn, classList.T_id, 开始时间, 结束时间)
-					c.SetAverageShiftedUpward(T_task_id, classList.T_id, T_deviation, RoundToDecimal(温控传感器绑定点OriginalAvg+0.1, 1), 温控传感器绑定点OriginalAvg, T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
+				T_max := Task.Read_TaskData_max(T_task_id, classList.T_sn, classList.T_id, 开始时间, 结束时间)
+				T_min := Task.Read_TaskData_min(T_task_id, classList.T_sn, classList.T_id, 开始时间, 结束时间)
+				c.SetAverageShiftedUpward(T_task_id, classList.T_id, T_deviation, RoundToDecimal(originalAvg-T_deviation, 1), 温控传感器绑定点OriginalAvg, T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
 
-					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "温控传感器绑定点" + lib.To_string(i+1) + " 平均值:" + lib.To_string(温控传感器绑定点OriginalAvg) + "℃ " +
-						"测点平均值" + lib.To_string(originalAvg) + "℃ " +
-						"数据偏差: " + lib.To_string(RoundToDecimal(math.Abs(温控传感器绑定点OriginalAvg-originalAvg), 1)) + "℃ " +
-						"设置:" + lib.To_string(T_deviation) + "℃" +
-						"平均值向上偏移:0.1℃"})
-					温控传感器绑定点OriginalAvg = Task.Read_TaskData_Average(Task_r.T_task_id, classList.T_sn, 开始时间, 结束时间)
-					温控传感器绑定点OriginalAvg = RoundToDecimal(温控传感器绑定点OriginalAvg, 1)
-
-				}
-				lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "温控传感器绑定点" + lib.To_string(i+1) + " 平均值:" + lib.To_string(温控传感器绑定点OriginalAvg) + "℃ " +
+				lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "温控传感器绑定点" + lib.To_string(i+1) + "" +
+					" 平均值:" + lib.To_string(温控传感器绑定点OriginalAvg) + "℃ " +
 					"测点平均值" + lib.To_string(originalAvg) + "℃ " +
-					"数据偏差: " + lib.To_string(RoundToDecimal(math.Abs(温控传感器绑定点OriginalAvg-originalAvg), 1)) + "℃ " +
+					"数据偏差: " + lib.To_string(RoundToDecimal(温控传感器绑定点OriginalAvg-(originalAvg-T_deviation), 1)) + "℃ " +
 					"设置:" + lib.To_string(T_deviation) + "℃" +
-					"符合要求"})
+					"温控传感器绑定点平均值向上偏移"})
 
 				continue
 			}
@@ -1285,27 +1367,18 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_Average() {
 			// 向下偏移
 			if 温控传感器绑定点OriginalAvg > originalAvg+T_deviation {
 
-				for 温控传感器绑定点OriginalAvg > originalAvg+T_deviation {
-					// 热点向下偏移到高点范围
-					T_max := Task.Read_TaskData_max(T_task_id, classList.T_sn, classList.T_id, 开始时间, 结束时间)
-					T_min := Task.Read_TaskData_min(T_task_id, classList.T_sn, classList.T_id, 开始时间, 结束时间)
-
-					c.SetAverageShiftedDownward(T_task_id, classList.T_id, T_deviation, RoundToDecimal(温控传感器绑定点OriginalAvg-0.1, 1), 温控传感器绑定点OriginalAvg, T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
+				// 热点向下偏移到高点范围
+				T_max := Task.Read_TaskData_max(T_task_id, classList.T_sn, classList.T_id, 开始时间, 结束时间)
+				T_min := Task.Read_TaskData_min(T_task_id, classList.T_sn, classList.T_id, 开始时间, 结束时间)
 
-					lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "温控传感器绑定点" + lib.To_string(i+1) + " 平均值:" + lib.To_string(温控传感器绑定点OriginalAvg) + "℃ " +
-						"测点平均值" + lib.To_string(originalAvg) + "℃ " +
-						"数据偏差: " + lib.To_string(RoundToDecimal(math.Abs(温控传感器绑定点OriginalAvg-originalAvg), 1)) + "℃ " +
-						"设置:" + lib.To_string(T_deviation) + "℃" +
-						"平均值向下偏移:0.1℃"})
-					温控传感器绑定点OriginalAvg = Task.Read_TaskData_Average(Task_r.T_task_id, classList.T_sn, 开始时间, 结束时间)
-					温控传感器绑定点OriginalAvg = RoundToDecimal(温控传感器绑定点OriginalAvg, 1)
+				c.SetAverageShiftedDownward(T_task_id, classList.T_id, T_deviation, RoundToDecimal(originalAvg+T_deviation, 1), 温控传感器绑定点OriginalAvg, T_min, T_max, 温度控制范围最小值, 温度控制范围最高值, "", "")
 
-				}
-				lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "温控传感器绑定点" + lib.To_string(i+1) + " 平均值:" + lib.To_string(温控传感器绑定点OriginalAvg) + "℃ " +
+				lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "温控传感器绑定点" + lib.To_string(i+1) + "" +
+					" 平均值:" + lib.To_string(温控传感器绑定点OriginalAvg) + "℃ " +
 					"测点平均值" + lib.To_string(originalAvg) + "℃ " +
-					"数据偏差: " + lib.To_string(RoundToDecimal(math.Abs(温控传感器绑定点OriginalAvg-originalAvg), 1)) + "℃ " +
+					"数据偏差: " + lib.To_string(RoundToDecimal(温控传感器绑定点OriginalAvg-(originalAvg+T_deviation), 1)) + "℃ " +
 					"设置:" + lib.To_string(T_deviation) + "℃" +
-					"符合要求"})
+					"温控传感器绑定点平均值向下偏移"})
 
 			}
 
@@ -1314,7 +1387,7 @@ func (c *TaskDataHandleController) SSE_Compare_binding_points_with_Average() {
 
 	// ----------恢复保留数据------------
 	if Task_r.T_device_type != "X" {
-		c.SaveRetainData(Task_r, 部点终端_list, valueStrings1, valueStrings2, 开空开, 开空开驼峰结束时间, 保空开, 保空开驼峰结束时间)
+		c.SaveRetainData(Task_r, 部点终端_list, valueStrings1, valueStrings2, 开空开, 保空开, 开空开驼峰, 保空开驼峰, 温度控制范围最高值, 60)
 	} else {
 		c.SaveBWXRetainData(Task_r, 部点终端_list, BWXValueStrings, 结束时间, 趋势时间, 60)
 	}
@@ -1353,14 +1426,20 @@ func (c *TaskDataHandleController) SetAverageShiftedDownward(T_task_id, T_id str
 			" 数据偏差:" + lib.To_string(vgaca) + "℃ " +
 			" 向下偏移:" + lib.To_string(vgaca) + "℃ "})
 	} else {
-		compress1 := RoundToDecimal((minLimit+0.3-目标avg)/(T_min-originalAvg), 1)
-		compress2 := RoundToDecimal((maxLimit-0.3-目标avg)/(T_max-originalAvg), 1)
-		compress := math.Min(compress1, compress2)
-		if RoundToDecimal(T_max*compress, 1) < maxLimit && RoundToDecimal(T_min*compress, 1) > minLimit {
-			vgaca = 0
-		} else {
-			vgaca = RoundToDecimal(目标avg-compress*originalAvg, 1)
+		var err error
+		var compress float64
+		compress, vgaca, err = GetLinearTransformationValue(目标avg, originalAvg, T_min, T_max, minLimit, maxLimit)
+		if err != nil {
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "进行处理 数据!" +
+				" 测点" + lib.To_string(T_id) +
+				" 最大值:" + lib.To_string(T_max) + "℃  " +
+				" 最小值:" + lib.To_string(T_min) + "℃  " +
+				" 参考平均值:" + lib.To_string(RoundToDecimal(targetAvg, 1)) + "℃  " +
+				" 原始平均值:" + lib.To_string(RoundToDecimal(originalAvg, 1)) + "℃  " +
+				" 无合法解: 无法满足所有约束条件!"})
+			return
 		}
+
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "进行处理 数据!" +
 			" 测点" + lib.To_string(T_id) +
 			" 最大值:" + lib.To_string(T_max) + "℃  " +
@@ -1382,6 +1461,68 @@ func (c *TaskDataHandleController) SetAverageShiftedDownward(T_task_id, T_id str
 
 }
 
+func GetLinearTransformationValue(targetAvg, originalAvg, T_min, T_max, minLimit, maxLimit float64) (float64, float64, error) {
+
+	//var vgaca float64
+	//compress1 := RoundToDecimal((minLimit+0.3-targetAvg)/(T_min-originalAvg), 1)
+	//compress2 := RoundToDecimal((maxLimit-0.3-targetAvg)/(T_max-originalAvg), 1)
+	//compress := math.Min(compress1, compress2)
+	//if RoundToDecimal(T_max*compress, 1) < RoundToDecimal(maxLimit, 1) && RoundToDecimal(T_min*compress, 1) > RoundToDecimal(minLimit, 1) {
+	//	vgaca = 0
+	//} else {
+	//	vgaca = RoundToDecimal(targetAvg-compress*originalAvg, 1)
+	//}
+	//for _, x := range []float64{T_min, T_max} {
+	//	newVal := RoundToDecimal(compress*x+vgaca, 1)
+	//	if newVal < minLimit || newVal > maxLimit {
+	//		return 0, 0, errors.New("无合法解: 无法满足所有约束条件")
+	//	}
+	//}
+	//
+	//return compress, vgaca, nil
+
+	minLimit = RoundToDecimal(minLimit+0.2, 1)
+	maxLimit = RoundToDecimal(maxLimit-0.2, 1)
+	// 策略1: 使用最小边界值 (使变换后最小值 = minBound)
+	k1 := (targetAvg - minLimit) / (originalAvg - T_min)
+	b1 := minLimit - k1*T_min
+	valid1 := true
+	for _, x := range []float64{T_min, T_max} {
+		newVal := RoundToDecimal(k1*x+b1, 1)
+		if newVal < minLimit || newVal > maxLimit {
+			valid1 = false
+			break
+		}
+	}
+
+	// 策略2: 使用最大边界值 (使变换后最大值 = maxBound),策略1失败时使用
+	k2 := float64(0)
+	b2 := float64(0)
+	valid2 := false
+	if !valid1 {
+		k2 = (maxLimit - targetAvg) / (T_max - originalAvg)
+		b2 = targetAvg - k2*originalAvg
+		valid2 = true
+		for _, x := range []float64{T_min, T_max} {
+			newVal := RoundToDecimal(k2*x+b2, 1)
+			if newVal < minLimit || newVal > maxLimit {
+				valid2 = false
+				break
+			}
+		}
+	}
+
+	// 根据结果选择有效策略
+	switch {
+	case valid1:
+		return k1, b1, nil
+	case valid2:
+		return k2, b2, nil
+	default:
+		return 0, 0, errors.New("无合法解: 无法满足所有约束条件")
+	}
+}
+
 /*
 平均值上移
 targetAvg 参考平均值
@@ -1406,13 +1547,18 @@ func (c *TaskDataHandleController) SetAverageShiftedUpward(T_task_id, T_id strin
 			" 数据偏差:" + lib.To_string(vgaca) + "℃ " +
 			" 向上偏移:" + lib.To_string(vgaca) + "℃ "})
 	} else {
-		compress1 := RoundToDecimal((minLimit+0.3-目标avg)/(T_min-originalAvg), 1)
-		compress2 := RoundToDecimal((maxLimit-0.3-目标avg)/(T_max-originalAvg), 1)
-		compress := math.Min(compress1, compress2)
-		if RoundToDecimal(T_max*compress, 1) < maxLimit && RoundToDecimal(T_min*compress, 1) > minLimit {
-			vgaca = 0
-		} else {
-			vgaca = RoundToDecimal(目标avg-compress*originalAvg, 1)
+		var err error
+		var compress float64
+		compress, vgaca, err = GetLinearTransformationValue(目标avg, originalAvg, T_min, T_max, minLimit, maxLimit)
+		if err != nil {
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 2, Msg: "进行处理 数据!" +
+				" 测点" + lib.To_string(T_id) +
+				" 最大值:" + lib.To_string(T_max) + "℃  " +
+				" 最小值:" + lib.To_string(T_min) + "℃  " +
+				" 参考平均值:" + lib.To_string(RoundToDecimal(targetAvg, 1)) + "℃  " +
+				" 原始平均值:" + lib.To_string(RoundToDecimal(originalAvg, 1)) + "℃  " +
+				" 无合法解: 无法满足所有约束条件!"})
+			return
 		}
 
 		lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "进行处理 数据!" +
@@ -1436,26 +1582,82 @@ func (c *TaskDataHandleController) SetAverageShiftedUpward(T_task_id, T_id strin
 
 }
 
-func (c *TaskDataHandleController) GetMetadata(T_task_id, SN, startTime string) (valueStrings []string, endTime string) {
-	list := Task.Read_TaskData_ById_AVG(T_task_id, SN, startTime, "")
-	// 获取第一个驼峰结束时间点
-	CalculateHumps_list := Task.CalculateHumpsByThreeDots(list)
-	if len(CalculateHumps_list) < 1 {
+func (c *TaskDataHandleController) GetCalculateHumps(T_task_id string, SN_list []Device.DeviceClassList, startTime, types string) (calculateHumps Task.CalculateHumps_R) {
+	SN := Device.JoinDeviceClassListSnToString(SN_list)
+	var is bool
+	calculateHumps, is = Task.Redis_CalculateHumps_Get(T_task_id + types)
+	if !is {
+		list := Task.Read_TaskData_ById_AVG(T_task_id, SN, startTime, "")
+		// 获取第一个驼峰结束时间点
+		CalculateHumps_list := Task.CalculateHumpsByThreeDots(list)
+		if len(CalculateHumps_list) < 1 {
+			return
+		}
+		calculateHumps = CalculateHumps_list[0]
+		Task.Redis_CalculateHumps_Set(T_task_id+types, calculateHumps)
+	}
+	return calculateHumps
+
+}
+
+func (c *TaskDataHandleController) GetMetadata(T_task_id string, SN_list []Device.DeviceClassList, startTime, types string) (valueStrings []string, calculateHumps Task.CalculateHumps_R) {
+	SN := Device.JoinDeviceClassListSnToString(SN_list)
+	var is bool
+	calculateHumps, is = Task.Redis_CalculateHumps_Get(T_task_id + types)
+	if !is {
 		return
 	}
-	endTime = CalculateHumps_list[0].End.T_time
+
+	endTime := calculateHumps.End.T_time
 
 	data1, _ := Task.Read_TaskData_ById_List_AES(T_task_id, SN, "", startTime, endTime, 0, 9999)
 	for _, v := range data1 {
 		valueStrings = append(valueStrings, fmt.Sprintf("('%s','%s',%v,%v,'%s')", v.T_sn, v.T_id, v.T_t, v.T_rh, v.T_time))
 	}
-	return valueStrings, endTime
+
+	return valueStrings, calculateHumps
+
+}
+
+func (c *TaskDataHandleController) GetCalculateHumpsMaps(T_task_id string, SN_list []Device.DeviceClassList, startTime string) map[string]Task.CalculateHumps_R {
+	var CalculateHumpsMaps = make(map[string]Task.CalculateHumps_R)
+
+	SN := Device.JoinDeviceClassListSnToString(SN_list)
+	allList := Task.Read_TaskData_ById_AVG(T_task_id, SN, startTime, "")
+	// 获取第一个驼峰结束时间点
+	CalculateHumps_list := Task.CalculateHumpsByThreeDots(allList)
+	if len(CalculateHumps_list) < 1 {
+		return CalculateHumpsMaps
+	}
+
+	for _, device := range SN_list {
+		list := Task.Read_TaskData_ById_AVG(T_task_id, device.T_sn, startTime, "")
+		//获取第一个驼峰结束时间点
+		CalculateHumps := Task.CalculateHumpsByThreeDots(list)
+
+		if len(CalculateHumps) < 1 {
+			CalculateHumpsMaps[device.T_sn] = CalculateHumps_list[0]
+			continue
+		}
+		if CalculateHumps[0].Peak.T_time != CalculateHumps_list[0].Peak.T_time {
+			CalculateHumps[0].Peak.T_time = CalculateHumps_list[0].Peak.T_time
+		}
+		et1, _ := lib.TimeStrToTime(CalculateHumps_list[0].End.T_time)
+		et2, _ := lib.TimeStrToTime(CalculateHumps[0].End.T_time)
+		if et1.Before(et2) {
+			CalculateHumps[0].End.T_time = CalculateHumps_list[0].End.T_time
+		}
+		CalculateHumpsMaps[device.T_sn] = CalculateHumps[0]
+	}
+
+	return CalculateHumpsMaps
 }
 
 // 获取保留数据
-func (c *TaskDataHandleController) GetRetainData(Task_r Task.Task, SN string) (valueStrings1, valueStrings2 []string,
-	kkkStartTime, kkkEndTime, bkkStartTime, bkkEndTime string) {
-	var 开空开, 保空开, 开空开驼峰结束时间, 保空开驼峰结束时间 string
+func (c *TaskDataHandleController) GetRetainData(Task_r Task.Task, SN_list []Device.DeviceClassList, useCache bool) (valueStrings1, valueStrings2 []string,
+	kkkStartTime, bkkStartTime string, kkkCalculateHumps, bkkCalculateHumps Task.CalculateHumps_R) {
+	var 开空开, 保空开 string
+	var 开空开驼峰, 保空开驼峰 Task.CalculateHumps_R
 	if Task_r.T_device_type != "X" {
 		开空开 = VerifyTemplate.Read_VerifyTemplateMapData_T_name(Task_r.T_task_id, Task_r.T_VerifyTemplate_id, "开空开")
 		if len(开空开) == 0 {
@@ -1465,48 +1667,191 @@ func (c *TaskDataHandleController) GetRetainData(Task_r Task.Task, SN string) (v
 			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 {
-			保空开 = 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
+		//保空开 = 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 !useCache {
+		//	开空开驼峰 = c.GetCalculateHumps(Task_r.T_task_id, SN_list, 开空开, "kkk")
+		//	保空开驼峰 = c.GetCalculateHumps(Task_r.T_task_id, SN_list, 保空开, "bkk")
+		//}
+		//
+		//valueStrings1, 开空开驼峰 = c.GetMetadata(Task_r.T_task_id, SN_list, 开空开, "kkk")
+		//valueStrings2, 保空开驼峰 = c.GetMetadata(Task_r.T_task_id, SN_list, 保空开, "bkk")
+
+		SN := Device.JoinDeviceClassListSnToString(SN_list)
+		data1, _ := Task.Read_TaskData_ById_List_AES(Task_r.T_task_id, SN, "", 开空开, "", 0, 9999)
+		for _, v := range data1 {
+			valueStrings1 = append(valueStrings1, fmt.Sprintf("('%s','%s',%v,%v,'%s')", v.T_sn, v.T_id, v.T_t, v.T_rh, v.T_time))
 		}
-		valueStrings1, 开空开驼峰结束时间 = c.GetMetadata(Task_r.T_task_id, SN, 开空开)
-		valueStrings2, 保空开驼峰结束时间 = c.GetMetadata(Task_r.T_task_id, SN, 保空开)
+
 	}
-	return valueStrings1, valueStrings2, 开空开, 开空开驼峰结束时间, 保空开, 保空开驼峰结束时间
+	return valueStrings1, valueStrings2, 开空开, 保空开, 开空开驼峰, 保空开驼峰
 }
 
 // 获取保留数据
 func (c *TaskDataHandleController) SaveRetainData(Task_r Task.Task, SN_list []Device.DeviceClassList, valueStrings1, valueStrings2 []string,
-	kkkStartTime, kkkEndTime, bkkStartTime, bkkEndTime string) {
+	kkkStartTime, bkkStartTime string, kkkCalculateHumps, bkkCalculateHumps Task.CalculateHumps_R, maxLimit float64, saveTime int) {
 	var err error
 	if len(valueStrings1) > 0 {
-		//将开空开/开满开时间开始第一个驼峰 写入原始数据
-		for _, device := range SN_list {
-			Task.DeleteTaskDataByTimeRange(Task_r.T_task_id, device.T_sn, device.T_id, kkkStartTime, kkkEndTime)
 
-		}
+		//将开空开/开满开时间开始第一个驼峰 写入原始数据
+		//将 开空开/开满开时间 后时间写入原始数据
+		SN := Device.JoinDeviceClassListSnToString(SN_list)
+		Task.DeleteTaskAllDataByTimeRange(Task_r.T_task_id, SN, kkkStartTime, kkkCalculateHumps.End.T_time)
 		err = Task.Batch_Adds_TaskData(Task_r.T_task_id, valueStrings1)
 		if err == nil {
-			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: fmt.Sprintf("恢复开空开/开满开时间点后驼峰 %s ~ %s 数据 %d/%d", kkkStartTime, kkkEndTime, len(valueStrings1), len(valueStrings1))})
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: fmt.Sprintf("恢复 开空开/开满开 时间点后驼峰 %s ~ %s 数据 %d/%d", kkkStartTime, kkkCalculateHumps.End.T_time, len(valueStrings1), len(valueStrings1))})
 		}
 	}
 	if len(valueStrings2) > 0 {
 		//将开空开/开满开时间开始第一个驼峰 写入原始数据
-		for _, device := range SN_list {
-			Task.DeleteTaskDataByTimeRange(Task_r.T_task_id, device.T_sn, device.T_id, bkkStartTime, bkkEndTime)
-
-		}
+		SN := Device.JoinDeviceClassListSnToString(SN_list)
+		Task.DeleteTaskAllDataByTimeRange(Task_r.T_task_id, SN, bkkStartTime, bkkCalculateHumps.End.T_time)
 		err = Task.Batch_Adds_TaskData(Task_r.T_task_id, valueStrings2)
 		if err == nil {
-			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: fmt.Sprintf("恢复保空开/保满开时间点后驼峰 %s ~ %s 数据 %d/%d", bkkStartTime, bkkEndTime, len(valueStrings2), len(valueStrings2))})
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: fmt.Sprintf("恢复 保空开/保满开 时间点后驼峰 %s ~ %s 数据 %d/%d", kkkStartTime, kkkCalculateHumps.End.T_time, len(valueStrings1), len(valueStrings1))})
+		}
+	}
+
+	//c.SaveRetainDataAndTrend(Task_r, SN_list, valueStrings1, kkkStartTime, kkkCalculateHumps, maxLimit, saveTime)
+	//c.SaveRetainDataAndTrend(Task_r, SN_list, valueStrings2, bkkStartTime, bkkCalculateHumps, maxLimit, saveTime)
+
+}
+
+// 获取保留数据
+func (c *TaskDataHandleController) SaveRetainDataTrend(Task_r Task.Task, SN_list []Device.DeviceClassList, valueStrings1, valueStrings2 []string,
+	kkkStartTime, bkkStartTime string, kkkCalculateHumps, bkkCalculateHumps Task.CalculateHumps_R, maxLimit float64, saveTime int) {
+	c.SaveRetainDataAndTrend(Task_r, SN_list, valueStrings1, kkkStartTime, kkkCalculateHumps, maxLimit, saveTime)
+	c.SaveRetainDataAndTrend(Task_r, SN_list, valueStrings2, bkkStartTime, bkkCalculateHumps, maxLimit, saveTime)
+}
+
+func (c *TaskDataHandleController) SaveRetainDataAndTrend(Task_r Task.Task, SN_list []Device.DeviceClassList, valueStrings1 []string,
+	kkkStartTime string, kkkCalculateHumps Task.CalculateHumps_R, maxLimit float64, saveTime int) {
+	var err error
+	if len(valueStrings1) > 0 {
+		//将开空开/开满开时间开始第一个驼峰 写入原始数据
+		SN := Device.JoinDeviceClassListSnToString(SN_list)
+		Task.DeleteTaskAllDataByTimeRange(Task_r.T_task_id, SN, kkkStartTime, kkkCalculateHumps.End.T_time)
+		err = Task.Batch_Adds_TaskData(Task_r.T_task_id, valueStrings1)
+		if err == nil {
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: fmt.Sprintf("恢复 开空开/开满开 保空开/保满开 时间点后驼峰 %s ~ %s 数据 %d/%d", kkkStartTime, kkkCalculateHumps.End.T_time, len(valueStrings1), len(valueStrings1))})
+		}
+
+		startTimeT, _ := lib.TimeStrToTime(kkkStartTime)
+		startTime := startTimeT.Add(-time.Minute).Format("2006-01-02 15:04")
+		endTimeT, _ := lib.TimeStrToTime(kkkCalculateHumps.End.T_time)
+		endTime := endTimeT.Add(time.Minute).Format("2006-01-02 15:04")
+		// 执行数据平滑
+		for _, v := range SN_list {
+
+			sn := v.T_sn
+			id_str := v.T_id
+			//AllList, _ := Task.Read_TaskData_ById_List_AES(Task_r.T_task_id, sn, id_str, startTime, kkkCalculateHumps.End.T_time, 0, 9999)
+			var trendTime, declineTrendTime string
+			trendTime = kkkCalculateHumps.Peak.T_time
+			declineTrendTime = kkkCalculateHumps.Peak.T_time
+
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "执行数据上升趋势"})
+
+			if len(trendTime) > 0 {
+				list, _ := Task.Read_TaskData_ById_List_AES(Task_r.T_task_id, sn, id_str, startTime, trendTime, 0, 9999)
+				if len(list) <= 2 {
+					continue
+				}
+				first := list[0]
+				var last Task.TaskData_
+				if len(list) > 10 {
+					last = list[len(list)-2]
+				} else {
+					last = list[len(list)-1]
+				}
+
+				current, _ := time.Parse("2006-01-02 15:04", first.T_time)
+				next, _ := time.Parse("2006-01-02 15:04", last.T_time)
+				interval := next.Sub(current).Seconds() / float64(saveTime)
+
+				//ttInterval := (last.T_t - first.T_t) / float32(interval)
+				trhInterval := (last.T_rh - first.T_rh) / float32(interval)
+				ttList := generateRisingCurve(float64(first.T_t), float64(last.T_t), int(interval+1))
+				//tt := first.T_t
+				ttrh := first.T_rh
+
+				var valueStrings []string
+				for i := 0; i <= int(interval); i++ {
+					//tt += ttInterval
+					ttrh += trhInterval
+					ttime := current.Format("2006-01-02 15:04")
+					valueStrings = append(valueStrings, fmt.Sprintf("('%s','%s',%v,%v,'%s')", first.T_sn, id_str, ttList[i], ttrh, ttime))
+					current = current.Add(time.Second * time.Duration(saveTime))
+				}
+
+				//for current.Unix() <= next.Unix() {
+				//
+				//	tt += ttInterval
+				//	ttrh += trhInterval
+				//	ttime := current.Format("2006-01-02 15:04")
+				//	valueStrings = append(valueStrings, fmt.Sprintf("('%s','%s',%v,%v,'%s')", first.T_sn, id_str, tt, ttrh, ttime))
+				//	current = current.Add(time.Second * time.Duration(saveTime))
+				//}
+				Task.DeleteTaskDataByTimeRange(Task_r.T_task_id, sn, id_str, first.T_time, last.T_time)
+
+				Task.Batch_Adds_TaskData(Task_r.T_task_id, valueStrings)
+			}
+
+			lib.SseWriteJSON(c.Ctx.ResponseWriter, lib.JSONSSE{State: 0, Msg: "执行数据下降趋势"})
+			if len(declineTrendTime) > 0 {
+				list, _ := Task.Read_TaskData_ById_List_AES(Task_r.T_task_id, sn, id_str, declineTrendTime, endTime, 0, 9999)
+				if len(list) <= 2 {
+					continue
+				}
+				if list[len(list)-1].T_t > list[len(list)-2].T_t {
+					continue
+				}
+
+				var first Task.TaskData_
+				if len(list) > 10 {
+					first = list[1]
+				} else {
+					first = list[0]
+				}
+
+				last := list[len(list)-1]
+
+				current, _ := time.Parse("2006-01-02 15:04", first.T_time)
+				next, _ := time.Parse("2006-01-02 15:04", last.T_time)
+				interval := next.Sub(current).Seconds() / float64(saveTime)
+
+				//ttInterval := (last.T_t - first.T_t) / float32(interval)
+				trhInterval := (last.T_rh - first.T_rh) / float32(interval)
+
+				ttList := generateTemperatureCurve(float64(first.T_t), float64(last.T_t), int(interval+1))
+
+				//tt := first.T_t
+				ttrh := first.T_rh
+				var valueStrings []string
+				for i := 0; i <= int(interval); i++ {
+					//tt += ttInterval
+					ttrh += trhInterval
+					ttime := current.Format("2006-01-02 15:04")
+					valueStrings = append(valueStrings, fmt.Sprintf("('%s','%s',%v,%v,'%s')", first.T_sn, id_str, ttList[i], ttrh, ttime))
+					current = current.Add(time.Second * time.Duration(saveTime))
+				}
+
+				Task.DeleteTaskDataByTimeRange(Task_r.T_task_id, sn, id_str, first.T_time, last.T_time)
+				Task.Batch_Adds_TaskData(Task_r.T_task_id, valueStrings)
+
+			}
 		}
+
 	}
 }
 
+// 获取保留数据
 func (c *TaskDataHandleController) GetBWXRetainData(Task_r Task.Task, SN string, endTime, trendTime string) (BWXValueStrings []string) {
 	if endTime != trendTime {
 		data1, _ := Task.Read_TaskData_ById_List_AES(Task_r.T_task_id, SN, "", trendTime, "", 0, 9999)
@@ -1517,7 +1862,8 @@ func (c *TaskDataHandleController) GetBWXRetainData(Task_r Task.Task, SN string,
 	return
 }
 
-func (c *TaskDataHandleController) SaveBWXRetainData(Task_r Task.Task, SN_list []Device.DeviceClassList, BWXValueStrings []string, endTime, trendTime string, saveTime int) {
+func (c *TaskDataHandleController) SaveBWXRetainData(Task_r Task.Task, SN_list []Device.DeviceClassList,
+	BWXValueStrings []string, endTime, trendTime string, saveTime int) {
 	var err error
 	if endTime != trendTime && len(BWXValueStrings) > 0 {
 		//将开空开/开满开时间开始第一个驼峰 写入原始数据
@@ -1561,7 +1907,7 @@ func (c *TaskDataHandleController) SaveBWXRetainData(Task_r Task.Task, SN_list [
 			ttrh := first.T_rh
 
 			var valueStrings []string
-			for current.Unix() < next.Unix() {
+			for current.Unix() <= next.Unix() {
 				tt += ttInterval
 				ttrh += trhInterval
 				ttime := current.Format("2006-01-02 15:04")
@@ -1725,3 +2071,68 @@ func findAverageOptimalAdjustment(A, B, C float64) float64 {
 	}
 	return optimalC
 }
+
+func generateTemperatureCurve(startTemp, minTemp float64, steps int) []float64 {
+	if steps <= 0 {
+		return []float64{}
+	}
+
+	// 计算动态参数确保严格递减且高于最低温度
+	base := minTemp + 0.1 // 确保所有值高于minTemp
+	decayFactor := math.Log((startTemp-base)/(minTemp+0.5-base)) / float64(steps-1)
+
+	temperatures := make([]float64, steps)
+	prevTemp := startTemp
+
+	for i := 0; i < steps; i++ {
+		// 使用指数衰减模型确保严格单调递减
+		temp := base + (startTemp-base)*math.Exp(-decayFactor*float64(i))
+
+		// 确保严格递减且高于最低温度
+		if temp >= prevTemp {
+			temp = prevTemp - 0.1
+		}
+		if temp <= minTemp {
+			temp = minTemp + 0.01 + 0.05*float64(steps-i)/float64(steps)
+		}
+
+		// 保持精度并确保唯一性
+		temp = math.Round(temp*100) / 100
+		temperatures[i] = temp
+		prevTemp = temp
+	}
+
+	return temperatures
+}
+
+func generateRisingCurve(minTemp, maxTemp float64, steps int) []float64 {
+	if steps <= 0 {
+		return []float64{}
+	}
+
+	// 计算动态参数确保严格递增且低于最高温度
+	growthFactor := math.Log((maxTemp-minTemp-0.1)/0.1) / float64(steps-1)
+
+	temperatures := make([]float64, steps)
+	prevTemp := minTemp
+
+	for i := 0; i < steps; i++ {
+		// 使用指数增长模型确保严格单调递增
+		temp := minTemp + (maxTemp-minTemp)*(1-math.Exp(-growthFactor*float64(i)))
+
+		// 确保严格递增且低于最高温度
+		if temp <= prevTemp {
+			temp = prevTemp + 0.1
+		}
+		if temp >= maxTemp {
+			temp = maxTemp - 0.01 - 0.05*float64(steps-i-1)/float64(steps)
+		}
+
+		// 保持精度并确保唯一性
+		temp = math.Round(temp*100) / 100
+		temperatures[i] = temp
+		prevTemp = temp
+	}
+
+	return temperatures
+}

+ 25 - 0
models/Task/Task.go

@@ -143,6 +143,30 @@ func Redis_Task_Get(key string) (r Task, is bool) {
 	logs.Println("没有 找到key:", key)
 	return Task{}, false
 }
+func Redis_CalculateHumps_Set(key string, r CalculateHumps_R) (err error) {
+	//json序列化
+	str, err := json.Marshal(r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+	err = redisCache_Task.Put(key, str, 30*time.Minute)
+	if err != nil {
+		logs.Println("set key:", key, ",value:", str, err)
+	}
+	return
+}
+
+func Redis_CalculateHumps_Get(key string) (r CalculateHumps_R, is bool) {
+	if redisCache_Task.IsExist(key) {
+		logs.Println("找到key:", key)
+		v := redisCache_Task.Get(key)
+		json.Unmarshal(v.([]byte), &r)
+		return r, true
+	}
+	logs.Println("没有 找到key:", key)
+	return CalculateHumps_R{}, false
+}
 func Redis_Task_Set(key string, r Task) (err error) {
 	//json序列化
 	str, err := json.Marshal(r)
@@ -156,6 +180,7 @@ func Redis_Task_Set(key string, r Task) (err error) {
 	}
 	return
 }
+
 func Read_Task(T_task_id string) (r Task, err error) {
 	if task, is := Redis_Task_Get(T_task_id); is == true {
 		return task, nil

+ 10 - 0
models/Task/TaskCopy.go

@@ -72,6 +72,16 @@ func Read_TaskCopy(T_copy_id string) (r TaskCopy, err error) {
 	return r, nil
 }
 
+// 修改
+func Update_TaskCopy(r TaskCopy, cols ...string) bool {
+	o := orm.NewOrm()
+	if num, err := o.Update(&r, cols...); err == nil {
+		logs.Println("Number of records updated in database:", num)
+		return true
+	}
+	return false
+}
+
 // 添加
 func Add_TaskCopy(r TaskCopy) (string, bool) {
 	o := orm.NewOrm()

+ 48 - 1
models/Task/TaskData.go

@@ -1221,6 +1221,52 @@ func DeleteTaskDataByTimeRange(T_task_id, sn string, id string, startTime, endTi
 	logs.Println(fmt.Sprintf("从 %s - %s 时间段删除了%d条数据", startTime, endTime, affected))
 }
 
+func DeleteTaskAllDataByTimeRange(T_task_id, SN string, startTime, endTime string) {
+	sqlStatement := fmt.Sprintf("delete from z_task_data_%s where ", T_task_id)
+
+	sql_condition := ""
+	if len(SN) > 0 {
+		if strings.Contains(SN, "|") {
+			// 将字符串按 | 分割
+			ids := strings.Split(strings.TrimSuffix(SN, "|"), "|")
+
+			// 构建 SQL 查询
+			query := "t_sn IN ("
+			// 动态添加每个 id
+			for i, id := range ids {
+				query += "'" + id + "'"
+				if i < len(ids)-1 {
+					query += ", " // 添加逗号分隔
+				}
+			}
+			query += ") " // 结束 SQL 查询
+			sql_condition += query
+
+		} else {
+			sql_condition += "t_sn = '" + SN + "'"
+		}
+	}
+	if len(sql_condition) == 0 {
+		logs.Println(fmt.Sprintf("SN 为空,禁止删除"))
+		return
+	}
+	sqlStatement += sql_condition
+
+	if len(startTime) > 0 {
+		sqlStatement += " AND t_time >='" + startTime + "'"
+	}
+	if len(endTime) > 0 {
+		sqlStatement += " AND t_time <= '" + endTime + "'"
+	}
+	o := orm.NewOrm()
+	exec, err := o.Raw(sqlStatement).Exec()
+	if err != nil {
+		fmt.Println(err.Error())
+	}
+	affected, _ := exec.RowsAffected()
+	logs.Println(fmt.Sprintf("从 %s - %s 时间段删除了%d条数据", startTime, endTime, affected))
+}
+
 // UpdateTaskDataTemperatureAndHumidityRandom 随机更新
 func UpdateTaskDataTemperatureAndHumidityRandom(T_task_id, sn, id, startTime, endTime string, ttMax, ttMin, trhMax, trhMin int) {
 
@@ -1237,7 +1283,8 @@ func UpdateTaskDataTemperatureAndHumidityRandom(T_task_id, sn, id, startTime, en
 
 // UpdateTaskDataTemperatureAndHumidity 更新设备探头数据温湿度 固定偏移
 func UpdateTaskDataTemperatureAndHumidity(T_task_id, sn, id, startTime, endTime string, temperature, humidity float64) {
-	sqlStatement := fmt.Sprintf("update z_task_data_%s set t_t = t_t + %f , t_rh = t_rh + %f where t_id = '%s' and  t_sn = '%s' ", T_task_id, temperature, humidity, id, sn)
+	sqlStatement := fmt.Sprintf("update z_task_data_%s set t_t = t_t + %f , t_rh = t_rh + %f where t_id = '%s' and  t_sn = '%s' ",
+		T_task_id, temperature, humidity, id, sn)
 	if len(startTime) > 0 && len(endTime) > 0 {
 		sqlStatement += " AND t_time BETWEEN '" + startTime + "' AND '" + endTime + "'"
 	}

+ 1 - 0
routers/TaskData.go

@@ -34,6 +34,7 @@ func init() {
 
 	beego.Router("/TaskDataCopy/List", &controllers.TaskDataController{}, "*:TaskDataCopy_List")       // 数据存档列表
 	beego.Router("/TaskDataCopy/Add", &controllers.TaskDataController{}, "*:TaskDataCopy_Add")         // 添加数据存档
+	beego.Router("/TaskDataCopy/Edit", &controllers.TaskDataController{}, "*:TaskDataCopy_Edit")       // 添加数据存档
 	beego.Router("/TaskDataCopy/Del", &controllers.TaskDataController{}, "*:TaskDataCopy_Del")         // 删除数据存档
 	beego.Router("/TaskDataCopy/Recover", &controllers.TaskDataController{}, "*:TaskDataCopy_Recover") // 数据存档恢复