Browse Source

2023-04-28

zoie 1 year ago
parent
commit
2c159d7c07

+ 3 - 3
Nats/Nats.go

@@ -213,7 +213,7 @@ func NatsInit() {
 		var t_R T_R
 		t_R.Code = 200
 		t_R.Msg = "ok"
-		t_R.Data = Account.Read_Admin_List_All()
+		t_R.Data = Account.Read_User_List_All()
 
 		b, _ := msgpack.Marshal(&t_R)
 		_ = lib.Nats.Publish(m.Reply, b)
@@ -236,7 +236,7 @@ func NatsInit() {
 		var t_R T_R
 		err := msgpack.Unmarshal(m.Data, &t_Req)
 		if err != nil {
-			t_R.Code = 201
+			t_R.Code = 202
 			t_R.Msg = "Unmarshal error"
 			b, _ := msgpack.Marshal(&t_R)
 			_ = lib.Nats.Publish(m.Reply, b)
@@ -392,7 +392,7 @@ func NatsInit() {
 
 		err := msgpack.Unmarshal(m.Data, &t_Req)
 		if err != nil {
-			t_R.Code = 201
+			t_R.Code = 202
 			t_R.Msg = "Unmarshal error"
 			b, _ := msgpack.Marshal(&t_R)
 			_ = lib.Nats.Publish(m.Reply, b)

+ 17 - 17
Nats/NatsServer/NatsMqtt.go

@@ -7,92 +7,92 @@ import (
 	"github.com/vmihailenco/msgpack/v5"
 )
 
-func Read_DeviceParameter(T_SN string) {
+func Read_DeviceParameter(T_SN, T_mqttid string) {
 	logs.Println("Nats =>", lib.FuncName(), T_SN)
-	err := lib.Nats.Publish("Read_DeviceParameter", []byte(T_SN))
+	err := lib.Nats.Publish("Read_DeviceParameter"+T_mqttid, []byte(T_SN))
 	if err != nil {
 		logs.Println("Nats =>", lib.FuncName(), err)
 	}
 
 }
-func Read_DeviceSensorParameter(T_SN string) {
+func Read_DeviceSensorParameter(T_SN, T_mqttid string) {
 	logs.Println("Nats =>", lib.FuncName(), T_SN)
-	err := lib.Nats.Publish("Read_DeviceSensorParameter", []byte(T_SN))
+	err := lib.Nats.Publish("Read_DeviceSensorParameter"+T_mqttid, []byte(T_SN))
 	if err != nil {
 		logs.Println("Nats =>", lib.FuncName(), err)
 	}
 }
 
-func Pu_DeviceParameter(v Device.DeviceParameter) {
+func Pu_DeviceParameter(v Device.DeviceParameter, T_mqttid string) {
 	logs.Println("Nats =>", lib.FuncName(), v)
 	b, err := msgpack.Marshal(&v)
 	if err != nil {
 		panic(err)
 	}
 
-	err = lib.Nats.Publish("Pu_DeviceParameter", b)
+	err = lib.Nats.Publish("Pu_DeviceParameter"+T_mqttid, b)
 	if err != nil {
 		logs.Println("Nats =>", lib.FuncName(), err)
 	}
 
 }
-func Pu_DeviceParameter_Sensor(v Device.DeviceSensorParameter) {
+func Pu_DeviceParameter_Sensor(v Device.DeviceSensorParameter, T_mqttid string) {
 	logs.Println("Nats =>", lib.FuncName(), v)
 	b, err := msgpack.Marshal(&v)
 	if err != nil {
 		panic(err)
 	}
 
-	err = lib.Nats.Publish("Pu_DeviceParameter_Sensor", b)
+	err = lib.Nats.Publish("Pu_DeviceParameter_Sensor"+T_mqttid, b)
 	if err != nil {
 		logs.Println("Nats =>", lib.FuncName(), err)
 	}
 }
-func Set_DeviceTask(v Device.Device_task) {
+func Set_DeviceTask(v Device.Device_task, T_mqttid string) {
 	logs.Println("Nats =>", lib.FuncName(), v)
 	b, err := msgpack.Marshal(&v)
 	if err != nil {
 		panic(err)
 	}
 
-	err = lib.Nats.Publish("Set_DeviceTask", b)
+	err = lib.Nats.Publish("Set_DeviceTask"+T_mqttid, b)
 	if err != nil {
 		logs.Println("Nats =>", lib.FuncName(), err)
 	}
 
 }
 
-func Set_RestartShutdown(v Device.Device_task) {
+func Set_RestartShutdown(v Device.Device_task, T_mqttid string) {
 	logs.Println("Nats =>", lib.FuncName(), v)
 	b, err := msgpack.Marshal(&v)
 	if err != nil {
 		panic(err)
 	}
 
-	err = lib.Nats.Publish("Set_RestartShutdown", b)
+	err = lib.Nats.Publish("Set_RestartShutdown"+T_mqttid, b)
 	if err != nil {
 		logs.Println("Nats =>", lib.FuncName(), err)
 	}
 
 }
 
-func Del_DeviceSensor(v Device.DeviceSensor_Del) {
+func Del_DeviceSensor(v Device.DeviceSensor_Del, T_mqttid string) {
 	logs.Println("Nats =>", lib.FuncName(), v)
 	b, err := msgpack.Marshal(&v)
 	if err != nil {
 		panic(err)
 	}
 
-	err = lib.Nats.Publish("Del_DeviceSensor", b)
+	err = lib.Nats.Publish("Del_DeviceSensor"+T_mqttid, b)
 	if err != nil {
 		logs.Println("Nats =>", lib.FuncName(), err)
 	}
 
 }
 
-func Get_Device_Realtime(v string) {
-	logs.Println("Nats =>", lib.FuncName(), v)
-	err := lib.Nats.Publish("Get_Device_Realtime", []byte(v))
+func Get_Device_Realtime(v string, T_mqttid string) {
+	//logs.Println("Nats =>", lib.FuncName(), v)
+	err := lib.Nats.Publish("Get_Device_Realtime"+T_mqttid, []byte(v))
 	if err != nil {
 		logs.Println("Nats =>", lib.FuncName(), err)
 	}

+ 2 - 2
Nats/NatsServer/NatsProduct.go

@@ -7,7 +7,7 @@ import (
 	"github.com/vmihailenco/msgpack/v5"
 )
 
-func Up_ProductUpgrade(T_sn, T_version, T_file string) {
+func Up_ProductUpgrade(T_sn, T_version, T_file, T_mqttid string) {
 	t_Req := Product.ProductUpgrade_T{
 		T_sn:      T_sn,
 		T_version: T_version,
@@ -15,7 +15,7 @@ func Up_ProductUpgrade(T_sn, T_version, T_file string) {
 	}
 	b, _ := msgpack.Marshal(&t_Req)
 
-	err := lib.Nats.Publish("Up_ProductUpgrade", b)
+	err := lib.Nats.Publish("Up_ProductUpgrade"+T_mqttid, b)
 	if err != nil {
 		logs.Println("Nats =>", lib.FuncName(), err)
 	}

+ 39 - 12
conf/app.conf

@@ -3,16 +3,10 @@ HTTPPort = 6200
 runmode = dev
 EnableDocs = true
 copyrequestbody = true
-#热更新
-# Graceful = true
-#进程内监控
-# EnableAdmin = true
-# AdminAddr = "localhost"
-# AdminPort = 8088
 
 Version = "/v3"
 
-# Nats
+# # Nats
 NatsServer_Url = "127.0.0.1:43422"
 
 # Mysql
@@ -25,11 +19,40 @@ MysqlServer_MaxOpenConnections = 200
 MysqlServer_Debug = true
 
 # Redis
-# Redis
-# Redis_address = "127.0.0.1:43379"
-Redis_address = "175.178.229.79:30379"
+Redis_address = "127.0.0.1:43379"
 Redis_password = ""
-Redis_dbNum = "5"
+Redis_dbNum = "1"
+
+# Nats
+# NatsServer_Url = "175.178.229.79:4222"
+#
+# # Mysql 线上
+# MysqlServer_UrlPort = "175.178.229.79:30306"
+# MysqlServer_Database = "cold"
+# MysqlServer_Username = "root"
+# MysqlServer_Password = "root"
+# MysqlServer_MaxIdleConnections = 100
+# MysqlServer_MaxOpenConnections = 200
+#
+# # Redis
+# Redis_address = "175.178.229.79:30379"
+# Redis_password = ""
+# Redis_dbNum = "1"
+
+# # Mysql
+# MysqlServer_UrlPort = "47.111.15.17:3360"
+# MysqlServer_Database = "cold"
+# MysqlServer_Username = "cold"
+# MysqlServer_Password = "W5kjJ66Zz3Pb4CdK"
+# MysqlServer_MaxIdleConnections = 100
+# MysqlServer_MaxOpenConnections = 200
+# MysqlServer_Debug = true
+#
+# # Redis
+# Redis_address = "47.111.15.17:6379"
+# Redis_password = ""
+# Redis_dbNum = "1"
+
 
 # 静态资源
 Qiniu_AccessKey = "-8ezB_d-8-eUFTMvhOGbGzgeQRPeKQnaQ3DBcUxo"
@@ -43,4 +66,8 @@ Panel_url = "http://127.0.0.1:6204/Cold_Panel"
 FilterExcludeURL = /Login_verification,/Data/List
 # 小程序 冷链验证 /Data/List
 # 小程序接口 /DeviceWarning/DeviceSensor_List,/Device/Applet_Stat_View2,/DeviceSensor/Applet_List_View1,/DeviceSensor/Applet_List_View2,/DeviceSensorType/List,/Device/DeviceTask_Post
-FilterOnlyLoginCheckURL = /Menu/List,/User/Info,/User/Home,/User/Post,/UpFileToken,/User/WxQRCode,/Company/Get,/DeviceWarning/DeviceSensor_List,/Device/Applet_Stat_View2,/DeviceSensor/Applet_List_View1,/DeviceSensor/Applet_List_View2,/DeviceSensorType/List,/Device/DeviceTask_Post,/Data/DeviceSensor_Data_Print
+#FilterOnlyLoginCheckURL = /Menu/List,/User/Info,/User/Home,/User/Post,/UpFileToken,/User/WxQRCode,/Company/Get,/DeviceWarning/DeviceSensor_List,/Device/Applet_Stat_View2,/DeviceSensor/Applet_List_View1,/DeviceSensor/Applet_List_View2,/DeviceSensorType/List,/Device/DeviceTask_Post,/Data/DeviceSensor_Data_Print
+FilterOnlyLoginCheckURL = /Menu/List,/User/Info,/User/Home,/User/Post,/UpFileToken,/User/WxQRCode,/Company/Get,/DataSource,/Company/Bill_Excel,/WarningSend/List
+
+MqttIds = mqttjxit,mqttlodr,mqttyuht
+MqttServer_id = "mqttjxit"

+ 3 - 0
conf/config.go

@@ -40,3 +40,6 @@ var Panel_url, _ = beego.AppConfig.String("Panel_url")
 
 var FilterExcludeURL, _ = beego.AppConfig.String("FilterExcludeURL")
 var FilterOnlyLoginCheckURL, _ = beego.AppConfig.String("FilterOnlyLoginCheckURL")
+var MqttIds, _ = beego.AppConfig.String("MqttIds")
+var MqttServer_id, _ = beego.AppConfig.String("MqttServer_id")
+var WarningRateExcludePid, _ = beego.AppConfig.String("WarningRateExcludePid")

+ 169 - 368
controllers/Device.go

@@ -9,12 +9,11 @@ import (
 	"Cold_Api/models/Device"
 	"Cold_Api/models/System"
 	"Cold_Api/models/Warning"
-	"fmt"
 	beego "github.com/beego/beego/v2/server/web"
-	"github.com/xuri/excelize/v2"
+	"github.com/shopspring/decimal"
 	"math"
-	"os"
 	"strconv"
+	"strings"
 	"time"
 )
 
@@ -139,9 +138,18 @@ func (c *DeviceController) Device_Add() {
 		return
 	}
 
+	// 添加设备后自动重启
+	MqttIds := strings.Split(conf.MqttIds, ",")
+	for _, id := range MqttIds {
+		NatsServer.Set_RestartShutdown(Device.Device_task{
+			T_sn:   T_sn,
+			T_task: "1",
+		}, id)
+	}
+
 	System.Add_UserLogs_T(c.Admin_r.T_uuid, "设备管理", "设备添加", var_)
 
-	NatsServer.Read_DeviceParameter(T_sn) // 获取主机信息
+	NatsServer.Read_DeviceParameter(T_sn, "") // 获取主机信息
 
 	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
 	c.ServeJSON()
@@ -224,16 +232,84 @@ func (c *DeviceController) Device_Edit() {
 	return
 
 }
+func (c *DeviceController) Device_Applet_Get() {
+
+	T_snid := c.GetString("T_snid")
+
+	sn_id := strings.Split(strings.Trim(T_snid, "|"), ",")
+
+	if len(sn_id) != 2 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_snid err!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_sn, T_id := sn_id[0], lib.To_int(sn_id[1])
+
+	Device_r, err := Device.Read_Device_ByT_sn(T_sn)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "查询失败!"}
+		c.ServeJSON()
+		return
+	}
+	if Device_r.T_pid != c.T_pid {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "无权查看!"}
+		c.ServeJSON()
+		return
+	}
+
+	Dsp, _ := Device.Read_DeviceSensorParameter(T_sn, T_id)
+	DeviceData := Device.Read_DeviceData(T_sn, T_id)
+	type JSONS struct {
+		T_name    string // 设备名称
+		T_monitor int    // 监控状态 0 未监控 1 监控 停止记录
+		T_ist     int    // 温度   1开启   2关闭
+		T_ish     int    // 湿度   1开启   2关闭
+
+		T_t  float32 // 温度
+		T_rh float32 // 湿度
+
+		T_Tlower  float32 //  温度下限
+		T_Tupper  float32 //  温度上限
+		T_RHlower float32 //  湿度下限
+		T_RHupper float32 //  湿度上限
+	}
+
+	r_jsons := JSONS{
+		T_name:    Device_r.T_devName,
+		T_monitor: Device_r.T_monitor,
+		T_ist:     Device_r.T_ist,
+		T_ish:     Device_r.T_ish,
+		T_t:       DeviceData.T_t,
+		T_rh:      DeviceData.T_rh,
+		T_Tlower:  Dsp.T_Tlower,
+		T_Tupper:  Dsp.T_Tupper,
+		T_RHlower: Dsp.T_RHlower,
+		T_RHupper: Dsp.T_RHupper,
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+
+}
 
 // 重启/关机
 func (c *DeviceController) Device_RestartShutdown() {
 	T_sn := c.GetString("T_sn")
 	T_task := c.GetString("T_task")
 
+	device, err := Device.Read_Device_ByT_sn(T_sn)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_sn Err!"}
+		c.ServeJSON()
+		return
+	}
+
 	NatsServer.Set_RestartShutdown(Device.Device_task{
 		T_sn:   T_sn,
 		T_task: T_task,
-	})
+	}, device.T_mqttid)
 	System.Add_UserLogs(c.Admin_r.T_uuid, "设备管理", "重启/关机", T_sn+"-"+T_task)
 
 	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
@@ -247,8 +323,13 @@ func (c *DeviceController) Device_ProductUpgrade() {
 	T_sn := c.GetString("T_sn")
 	T_version := c.GetString("T_version")
 	T_file := c.GetString("T_file")
-
-	NatsServer.Up_ProductUpgrade(T_sn, T_version, T_file)
+	device, err := Device.Read_Device_ByT_sn(T_sn)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_sn Err!"}
+		c.ServeJSON()
+		return
+	}
+	NatsServer.Up_ProductUpgrade(T_sn, T_version, T_file, device.T_mqttid)
 	System.Add_UserLogs(c.Admin_r.T_uuid, "设备管理", "版本升级", T_sn+"-"+T_version+"-"+T_file)
 
 	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
@@ -350,9 +431,16 @@ func (c *DeviceController) Device_Parameter_List() {
 func (c *DeviceController) Device_Parameter_Get() {
 	Sn := c.GetString("T_sn")
 
+	device, err := Device.Read_Device_ByT_sn(Sn)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_sn Err!"}
+		c.ServeJSON()
+		return
+	}
+
 	DeviceParameter_lite := Device.Read_DeviceParameter_SN(Sn)
 	if len(DeviceParameter_lite) == 0 {
-		NatsServer.Read_DeviceParameter(Sn)
+		NatsServer.Read_DeviceParameter(Sn, device.T_mqttid)
 		c.Data["json"] = lib.JSONS{Code: 202, Msg: "未同步参数,请检查设备是否正常!"}
 		c.ServeJSON()
 		return
@@ -468,6 +556,9 @@ func (c *DeviceController) Device_Parameter_Pu() {
 	if v, err := c.GetInt("T_dormancy"); err == nil {
 		DeviceParameter.T_dormancy = v
 	}
+	if v, err := c.GetInt("T_snum"); err == nil {
+		DeviceParameter.T_snum = v
+	}
 	if v := c.GetString("T_btname"); len(v) > 0 {
 		DeviceParameter.T_btname = v
 	}
@@ -488,6 +579,8 @@ func (c *DeviceController) Device_Parameter_Pu() {
 	DeviceParameter.T_State = 2
 	DeviceParameter.T_uuid = c.Admin_r.T_uuid
 	DeviceParameter.T_SendState = 0
+	DeviceParameter.CreateTime = time.Now()
+	DeviceParameter.UpdateTime = time.Now()
 
 	Deviceparameter, is := Device.Add_DeviceParameter(DeviceParameter)
 	if !is {
@@ -496,7 +589,7 @@ func (c *DeviceController) Device_Parameter_Pu() {
 		return
 	}
 	System.Add_UserLogs_T(c.Admin_r.T_uuid, "设备管理", "设备参数操作", Deviceparameter)
-	NatsServer.Pu_DeviceParameter(Deviceparameter)
+	NatsServer.Pu_DeviceParameter(Deviceparameter, Device_r.T_mqttid)
 
 	if v := c.GetString("T_name"); len(v) > 0 {
 		// 更新名称
@@ -517,6 +610,12 @@ func (c *DeviceController) Device_Parameter_Del_Device() {
 
 	Sn := c.GetString("Sn")
 	Id, _ := c.GetInt("Id")
+	device, err := Device.Read_Device_ByT_sn(Sn)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_sn Err!"}
+		c.ServeJSON()
+		return
+	}
 
 	System.Add_UserLogs_T(c.Admin_r.T_uuid, "设备管理", "传感器 删除操作", "SN:"+Sn+" ["+strconv.Itoa(Id)+"]")
 
@@ -525,7 +624,7 @@ func (c *DeviceController) Device_Parameter_Del_Device() {
 
 	NatsServer.Del_DeviceSensor(Device.DeviceSensor_Del{
 		T_sn: Sn, T_id: Id,
-	})
+	}, device.T_mqttid)
 
 	c.Data["json"] = lib.JSONS{Code: 200, Msg: "OK"}
 	c.ServeJSON()
@@ -605,7 +704,7 @@ func (c *DeviceController) DeviceSensor_Edit() {
 	// 数据视图3D视图订阅
 	if v, err := c.GetInt("T_type"); err == nil {
 		if v == 0 {
-			c.Data["json"] = lib.JSONS{Code: 202, Msg: "类型错误!"}
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "类型不能为默认!"}
 			c.ServeJSON()
 			return
 		}
@@ -645,6 +744,13 @@ func (c *DeviceController) DeviceSensor_Del() {
 	Sn := c.GetString("T_sn")
 	Id, _ := c.GetInt("T_id")
 
+	device, err := Device.Read_Device_ByT_sn(Sn)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_sn Err!"}
+		c.ServeJSON()
+		return
+	}
+
 	_, is := Device.Read_DeviceSensor_ByT_sn(Sn, Id)
 	if !is {
 		c.Data["json"] = lib.JSONS{Code: 202, Msg: "信息错误!"}
@@ -659,7 +765,7 @@ func (c *DeviceController) DeviceSensor_Del() {
 		Device.Delete_DeviceSensor_ById(Sn, Id)
 		NatsServer.Del_DeviceSensor(Device.DeviceSensor_Del{
 			T_sn: Sn, T_id: Id,
-		})
+		}, device.T_mqttid)
 		System.Add_UserLogs_T(c.Admin_r.T_uuid, "设备管理", "传感器 删除操作", "SN:"+Sn+" ["+strconv.Itoa(Id)+"]")
 	} else {
 		Device.Delete_DeviceSensor_ById(Sn, Id)
@@ -677,10 +783,17 @@ func (c *DeviceController) DeviceSensor_Parameter_Get() {
 	Sn := c.GetString("T_sn")
 	Id, _ := c.GetInt("T_id")
 
+	device, err := Device.Read_Device_ByT_sn(Sn)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_sn Err!"}
+		c.ServeJSON()
+		return
+	}
+
 	//c.Data["DeviceSensor"], _ = Device.Read_DeviceSensor_ByTsn_Tid(Sn, Id)
 	DeviceSensorParameter_lite := Device.Read_DeviceSensorParameter_T_sn_T_id(Sn, Id)
 	if len(DeviceSensorParameter_lite) == 0 {
-		NatsServer.Read_DeviceSensorParameter(Sn)
+		NatsServer.Read_DeviceSensorParameter(Sn, device.T_mqttid)
 		c.Data["json"] = lib.JSONS{Code: 202, Msg: "未同步参数,请检查设备是否正常!"}
 		c.ServeJSON()
 		return
@@ -716,7 +829,7 @@ func (c *DeviceController) DeviceSensor_Parameter_Pu() {
 
 	T_SN := c.GetString("T_sn")
 	T_id, _ := c.GetInt("T_id")
-	_, err := Device.Read_Device_ByT_sn(T_SN)
+	device, err := Device.Read_Device_ByT_sn(T_SN)
 	if err != nil {
 		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_sn Err!"}
 		c.ServeJSON()
@@ -744,19 +857,23 @@ func (c *DeviceController) DeviceSensor_Parameter_Pu() {
 
 	T_Tlower := DeviceSensorParameter.T_Tlower
 	if v, T_Tlower_err := c.GetFloat("T_Tlower"); T_Tlower_err == nil {
-		T_Tlower = float32(v)
+		temp, _ := decimal.NewFromFloat(v).Round(2).Float64()
+		T_Tlower = float32(temp)
 	}
 	T_Tupper := DeviceSensorParameter.T_Tupper
 	if v, T_Tupper_err := c.GetFloat("T_Tupper"); T_Tupper_err == nil {
-		T_Tupper = float32(v)
+		temp, _ := decimal.NewFromFloat(v).Round(2).Float64()
+		T_Tupper = float32(temp)
 	}
 	T_RHlower := DeviceSensorParameter.T_RHlower
 	if v, T_RHlower_err := c.GetFloat("T_RHlower"); T_RHlower_err == nil {
-		T_RHlower = float32(v)
+		temp, _ := decimal.NewFromFloat(v).Round(2).Float64()
+		T_RHlower = float32(temp)
 	}
 	T_RHupper := DeviceSensorParameter.T_RHupper
 	if v, T_RHupper_err := c.GetFloat("T_RHupper"); T_RHupper_err == nil {
-		T_RHupper = float32(v)
+		temp, _ := decimal.NewFromFloat(v).Round(2).Float64()
+		T_RHupper = float32(temp)
 	}
 
 	T_enprel := DeviceSensorParameter.T_enprel
@@ -765,25 +882,33 @@ func (c *DeviceController) DeviceSensor_Parameter_Pu() {
 	}
 	T_tprel := DeviceSensorParameter.T_tprel
 	if v, T_tprel_err := c.GetFloat("T_tprel"); T_tprel_err == nil {
-		T_tprel = float32(v)
+		temp, _ := decimal.NewFromFloat(v).Round(2).Float64()
+		T_tprel = float32(temp)
 	}
 	T_tpreu := DeviceSensorParameter.T_tpreu
 	if v, T_tpreu_err := c.GetFloat("T_tpreu"); T_tpreu_err == nil {
-		T_tpreu = float32(v)
+		temp, _ := decimal.NewFromFloat(v).Round(2).Float64()
+		T_tpreu = float32(temp)
 	}
 	T_hprel := DeviceSensorParameter.T_hprel
 	if v, T_hprel_err := c.GetFloat("T_hprel"); T_hprel_err == nil {
-		T_hprel = float32(v)
+		temp, _ := decimal.NewFromFloat(v).Round(2).Float64()
+		T_hprel = float32(temp)
 	}
 	T_hpreu := DeviceSensorParameter.T_hpreu
 	if v, T_hpreu_err := c.GetFloat("T_hpreu"); T_hpreu_err == nil {
-		T_hpreu = float32(v)
+		temp, _ := decimal.NewFromFloat(v).Round(2).Float64()
+		T_hpreu = float32(temp)
 	}
 
 	T_speed := DeviceSensorParameter.T_speed
 	if v, T_speed_err := c.GetInt("T_speed"); T_speed_err == nil {
 		T_speed = v
 	}
+	T_sense := DeviceSensorParameter.T_sense
+	if v, T_sense_err := c.GetInt("T_sense"); T_sense_err == nil {
+		T_sense = v
+	}
 	T_en := DeviceSensorParameter.T_en
 	if v, T_en_err := c.GetInt("T_en"); T_en_err == nil {
 		T_en = v
@@ -801,6 +926,7 @@ func (c *DeviceController) DeviceSensor_Parameter_Pu() {
 		T_RHlower: T_RHlower,
 		T_RHupper: T_RHupper,
 		T_speed:   T_speed,
+		T_sense:   T_sense,
 		T_en:      T_en,
 		T_free:    T_free,
 
@@ -834,7 +960,7 @@ func (c *DeviceController) DeviceSensor_Parameter_Pu() {
 		System.Add_UserLogs_T(c.Admin_r.T_uuid, "设备管理", "修改传感器名称", DeviceSensor)
 	}
 
-	NatsServer.Pu_DeviceParameter_Sensor(dsp)
+	NatsServer.Pu_DeviceParameter_Sensor(dsp, device.T_mqttid)
 
 	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
 	c.ServeJSON()
@@ -972,347 +1098,23 @@ func (c *DeviceController) DeviceTask_Post() {
 	T_sn := c.GetString("T_sn")
 	T_task := c.GetString("T_task")
 
-	NatsServer.Set_DeviceTask(Device.Device_task{
-		T_sn:   T_sn,
-		T_task: T_task,
-	})
-	System.Add_UserLogs(c.Admin_r.T_uuid, "设备管理", "远程启停", T_sn+"-"+T_task)
-
-	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
-	c.ServeJSON()
-	return
-
-}
-
-// 设备告警 ------------------------------------------
-
-// 告警列表
-func (c *DeviceController) DeviceWarning_List() {
-
-	type R_JSONS struct {
-		//必须的大写开头
-		Data      []Warning.Warning_R
-		Num       int64
-		Page      int
-		Page_size int
-	}
-	var r_jsons R_JSONS
-
-	page, _ := c.GetInt("page")
-	if page < 1 {
-		page = 1
-	}
-	page_z, _ := c.GetInt("page_z")
-	if page_z < 1 {
-		page_z = conf.Page_size
-	}
-
-	T_name := c.GetString("T_name")
-	T_tp := c.GetString("T_tp")
-	Time_start := c.GetString("Time_start")
-	Time_end := c.GetString("Time_end")
-	T_handle, _ := c.GetInt("T_handle")
-
-	T_admin, _ := c.GetInt("T_admin")
-	T_history, _ := c.GetInt("T_history")
-	var T_year, T_month string
-	if T_history == 1 {
-		date, err := time.Parse("2006-01-02 15:04:05", Time_start)
-		if err != nil {
-			c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误"}
-			c.ServeJSON()
-			return
-		}
-		T_year, T_month = date.Format("2006"), date.Format("01")
-	}
-
-	if T_admin == 1 {
-		if T_history == 1 {
-			// 获取备份
-			r_jsons.Data, r_jsons.Num = Warning.Read_Admin_Warning_Backups(c.Admin_r.T_pids, T_year, T_month, T_tp, T_name, T_handle, Time_start, Time_end, page, page_z)
-		} else {
-			// 获取最新
-			r_jsons.Data, r_jsons.Num = Warning.Read_Admin_Warning_List(c.Admin_r.T_pids, T_tp, T_name, T_handle, Time_start, Time_end, page, page_z)
-		}
-		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	device, err := Device.Read_Device_ByT_sn(T_sn)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_sn Err!"}
 		c.ServeJSON()
 		return
 	}
 
-	if T_history == 1 {
-		// 获取备份
-		r_jsons.Data, r_jsons.Num = Warning.Read_Warning_Backups(c.T_pid, T_year, T_month, T_tp, T_name, T_handle, Time_start, Time_end, page, page_z)
-	} else {
-		// 获取最新
-		r_jsons.Data, r_jsons.Num = Warning.Read_Warning_List(c.T_pid, T_tp, T_name, T_handle, Time_start, Time_end, page, page_z)
-	}
-
-	r_jsons.Page = page
-	r_jsons.Page_size = int(math.Ceil(float64(r_jsons.Num) / float64(page_z)))
-
-	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
-	c.ServeJSON()
-	return
-}
-
-// 查询告警
-func (c *DeviceController) DeviceWarning_Get() {
-	id, _ := c.GetInt("T_id")
-	T_history, _ := c.GetInt("T_history")
-	T := Warning.Read_Warning_ById(int64(id))
-
-	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Warning.WarningToWarning_R(T_history, T)}
-	c.ServeJSON()
-	return
-}
-
-// 编辑告警(处理告警)
-func (c *DeviceController) DeviceWarning_Post() {
-	id, _ := c.GetInt("T_id")
-	T_Text := c.GetString("T_Text")
-	T_time := c.GetString("T_time")
-	T_history, _ := c.GetInt("T_history")
-
-	var T_year, T_month string
-	var warning Warning.Warning
-	Wtab := "warning"
-	if T_history == 1 {
-		date, err := time.Parse("2006-01-02 15:04:05", T_time)
-		if err != nil {
-			c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误"}
-			c.ServeJSON()
-			return
-		}
-		T_year, T_month = date.Format("2006"), date.Format("01")
-		Wtab += "_" + T_year + "_" + T_month
-		warning, err = Warning.Read_Warning_ById_Backups(id, T_year, T_month)
-		if err != nil {
-			c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_id Err!"}
-			c.ServeJSON()
-			return
-		}
-		warning.T_Text = T_Text
-		warning.T_State = 2
-		if is := Warning.Update_Warning_Backups(warning, T_year, T_month); !is {
-			c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
-			c.ServeJSON()
-			return
-		}
-
-	} else {
-		warning = Warning.Read_Warning_ById(int64(id))
-		if warning.Id == 0 {
-			c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_id Err!"}
-			c.ServeJSON()
-			return
-		}
-		warning.T_Text = T_Text
-		warning.T_State = 2
-		if is := Warning.Update_Warning(warning, "T_Text", "T_State"); !is {
-			c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
-			c.ServeJSON()
-			return
-		}
-	}
+	NatsServer.Set_DeviceTask(Device.Device_task{
+		T_sn:   T_sn,
+		T_task: T_task,
+	}, device.T_mqttid)
+	System.Add_UserLogs(c.Admin_r.T_uuid, "设备管理", "远程启停", T_sn+"-"+T_task)
 
-	System.Add_UserLogs(c.Admin_r.T_uuid, "设备管理", "报警处理操作", Wtab+":"+strconv.Itoa(id)+"->"+T_Text)
 	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
 	c.ServeJSON()
 	return
-}
 
-// 删除告警
-func (c *DeviceController) DeviceWarning_Del() {
-	id, _ := c.GetInt("T_id")
-	T_time := c.GetString("T_time")
-	T_history, _ := c.GetInt("T_history")
-
-	var T_year, T_month string
-	var warning Warning.Warning
-	Wtab := "warning"
-	if T_history == 1 {
-		date, err := time.Parse("2006-01-02 15:04:05", T_time)
-		if err != nil {
-			c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误"}
-			c.ServeJSON()
-			return
-		}
-		T_year, T_month = date.Format("2006"), date.Format("01")
-		Wtab += "_" + T_year + "_" + T_month
-
-		warning, err = Warning.Read_Warning_ById_Backups(id, T_year, T_month)
-		if err != nil {
-			c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_id Err!"}
-			c.ServeJSON()
-			return
-		}
-		warning.T_State = 0
-		if is := Warning.Update_Warning_Backups(warning, T_year, T_month); !is {
-			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
-			c.ServeJSON()
-			return
-		}
-
-	} else {
-		warning = Warning.Read_Warning_ById(int64(id))
-		if warning.Id == 0 {
-			c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_id Err!"}
-			c.ServeJSON()
-			return
-		}
-		warning.T_State = 0
-		if is := Warning.Update_Warning(warning, "T_Text", "T_State"); !is {
-			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
-			c.ServeJSON()
-			return
-		}
-	}
-
-	System.Add_UserLogs(c.Admin_r.T_uuid, "设备管理", "报警删除操作", Wtab+":"+strconv.Itoa(id))
-	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
-	c.ServeJSON()
-	return
-}
-
-// 导出告警
-func (c *DeviceController) DeviceWarning_Data_Excel() {
-	T_name := c.GetString("T_name")
-	T_tp := c.GetString("T_tp")
-	Time_start := c.GetString("Time_start")
-	Time_end := c.GetString("Time_end")
-	T_handle, _ := c.GetInt("T_handle")
-	T_history, _ := c.GetInt("T_history")
-
-	var T_year, T_month string
-	if T_history == 1 {
-		date, err := time.Parse("2006-01-02 15:04:05", Time_start)
-		if err != nil {
-			c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误"}
-			c.ServeJSON()
-			return
-		}
-		T_year, T_month = date.Format("2006"), date.Format("01")
-	}
-
-	var Device_data []Warning.Warning_R
-	if T_history == 1 {
-		// 获取备份
-		Device_data, _ = Warning.Read_Warning_Backups(c.T_pid, T_year, T_month, T_tp, T_name, T_handle, Time_start, Time_end, 0, 9999)
-	} else {
-		// 获取最新
-		Device_data, _ = Warning.Read_Warning_List(c.T_pid, T_tp, T_name, T_handle, Time_start, Time_end, 0, 9999)
-	}
-
-	f := excelize.NewFile() // 设置单元格的值
-	// 这里设置表头
-	f.SetCellValue("Sheet1", "A1", "报警类型")
-	f.SetCellValue("Sheet1", "B1", "Sn")
-	f.SetCellValue("Sheet1", "C1", "设备名称")
-	f.SetCellValue("Sheet1", "D1", "传感器")
-	f.SetCellValue("Sheet1", "E1", "报警内容")
-	f.SetCellValue("Sheet1", "F1", "记录时间")
-	f.SetCellValue("Sheet1", "G1", "处理")
-	f.SetCellValue("Sheet1", "H1", "处理时间")
-
-	// 设置列宽
-	f.SetColWidth("Sheet1", "A", "A", 20)
-	f.SetColWidth("Sheet1", "B", "B", 25)
-	f.SetColWidth("Sheet1", "C", "C", 30)
-	f.SetColWidth("Sheet1", "D", "D", 30)
-	f.SetColWidth("Sheet1", "G", "E", 30)
-	f.SetColWidth("Sheet1", "H", "F", 15)
-	f.SetColWidth("Sheet1", "I", "G", 30)
-	f.SetColWidth("Sheet1", "J", "H", 15)
-
-	line := 1
-
-	// 循环写入数据
-	for _, v := range Device_data {
-		line++
-		f.SetCellValue("Sheet1", fmt.Sprintf("A%d", line), Warning.Read_WarningType_Get(v.T_tp))
-		f.SetCellValue("Sheet1", fmt.Sprintf("B%d", line), fmt.Sprintf("%s[%d]", v.T_sn, v.Id))
-		f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), v.T_D_name)
-		f.SetCellValue("Sheet1", fmt.Sprintf("D%d", line), v.T_DS_name)
-		f.SetCellValue("Sheet1", fmt.Sprintf("E%d", line), v.T_Remark)
-		f.SetCellValue("Sheet1", fmt.Sprintf("F%d", line), v.T_Ut)
-		f.SetCellValue("Sheet1", fmt.Sprintf("G%d", line), v.T_Text)
-		f.SetCellValue("Sheet1", fmt.Sprintf("H%d", line), v.CreateTime)
-
-	}
-	timeStr := time.Now().Format("20060102150405")
-	// 保存文件
-	if err := f.SaveAs("ofile/" + timeStr + ".xlsx"); err != nil {
-		fmt.Println(err)
-	}
-
-	url, is := NatsServer.Qiniu_UploadFile(lib.GetCurrentDirectory()+"/ofile/"+timeStr+".xlsx", "ofile/"+timeStr+".xlsx")
-	if !is {
-		c.Data["json"] = lib.JSONS{Code: 202, Msg: "oss!"}
-		c.ServeJSON()
-		return
-	}
-	//删除文件
-	err := os.Remove("ofile/" + timeStr + ".xlsx")
-	if err != nil {
-		fmt.Println(err)
-	}
-
-	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: url}
-	c.ServeJSON()
-	return
-}
-
-// 告警提示列表
-func (c *DeviceController) DeviceWarningList_T_Tips() {
-	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Warning.Read_WarningType_All_T_Notice_mechanism()}
-	c.ServeJSON()
-	return
-}
-
-// 告警类型列表
-func (c *DeviceController) WarningType_List_All() {
-	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Warning.Read_WarningType_All()}
-	c.ServeJSON()
-	return
-}
-
-// 告警类型列表 - 权限关联列表
-func (c *DeviceController) WarningType_Power_List_All() {
-
-	power, err := Account.Read_Power_ById(c.Admin_r.T_power)
-	if err != nil {
-		c.Data["json"] = lib.JSONS{Code: 200, Msg: "获取菜单失败"}
-		c.ServeJSON()
-		return
-	}
-
-	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Warning.Read_WarningType_Power_All(power.T_warning)}
-	c.ServeJSON()
-	return
-}
-
-// 通过传感器类型获取报警列表
-func (c *DeviceController) Read_Warning_List_By_DS_T_type() {
-	var r_jsons lib.R_JSONS
-	page, _ := c.GetInt("page")
-	if page < 1 {
-		page = 1
-	}
-	page_z, _ := c.GetInt("page_z")
-	if page_z < 1 {
-		page_z = conf.Page_size
-	}
-
-	T_type, _ := c.GetInt("T_type")
-	T_name := c.GetString("T_name")
-
-	r_jsons.Data, r_jsons.Num = Warning.Read_Warning_List_By_DS_T_type(c.T_pid, T_type, T_name, page, page_z)
-	r_jsons.Page = page
-	r_jsons.Page_size = int(math.Ceil(float64(r_jsons.Num) / float64(page_z)))
-
-	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
-	c.ServeJSON()
-	return
 }
 
 // 设备分类 ------------------------------------------
@@ -2121,6 +1923,12 @@ func (c *DeviceController) DeviceSensor_Applet_List_View2() {
 
 	var deviceMap = make(map[string][]Device.DeviceSensor_Applet)
 	var num int64
+
+	type DeviceList struct {
+		T_sn             string
+		DeviceSensorList []Device.DeviceSensor_Applet
+	}
+	var deviceList []DeviceList
 	for _, ds := range dsList {
 		_, ok := deviceMap[ds.T_sn]
 		if !ok {
@@ -2128,24 +1936,17 @@ func (c *DeviceController) DeviceSensor_Applet_List_View2() {
 			var list []Device.DeviceSensor_Applet
 			list = append(list, ds)
 			deviceMap[ds.T_sn] = list
+			device := DeviceList{
+				T_sn: ds.T_sn,
+			}
+			deviceList = append(deviceList, device)
 		} else {
 			deviceMap[ds.T_sn] = append(deviceMap[ds.T_sn], ds)
 		}
 	}
 
-	type DeviceList struct {
-		T_sn             string
-		DeviceSensorList []Device.DeviceSensor_Applet
-	}
-
-	var deviceList []DeviceList
-
-	for k, v := range deviceMap {
-		device := DeviceList{
-			T_sn:             k,
-			DeviceSensorList: v,
-		}
-		deviceList = append(deviceList, device)
+	for i := 0; i < len(deviceList); i++ {
+		deviceList[i].DeviceSensorList = deviceMap[deviceList[i].T_sn]
 	}
 
 	var offset int

+ 52 - 11
controllers/DeviceReal.go

@@ -3,7 +3,10 @@ package controllers
 import (
 	"Cold_Api/Nats/NatsServer"
 	"Cold_Api/controllers/lib"
+	"Cold_Api/logs"
+	"Cold_Api/models/Device"
 	"fmt"
+	"strings"
 	"time"
 )
 
@@ -28,26 +31,64 @@ import (
 //	}
 //}
 
+//func DeviceRealTime() {
+//	fmt.Println("=====================DeviceRealTime GO===============")
+//	time.Sleep(time.Second * 3)
+//	for true {
+//		lib.DeviceRealSnMap.Range(func(k, v interface{}) bool {
+//			fmt.Println("DeviceRealSnMap:", k, " num:", v)
+//			NatsServer.Get_Device_Realtime(k.(string))
+//
+//			temp := v.(int)
+//			temp--
+//			lib.DeviceRealSnMap.Store(k, temp)
+//			if temp == 0 {
+//				lib.DeviceRealSnMap.Delete(k)
+//			}
+//			time.Sleep(time.Millisecond * 100)
+//			return true
+//		})
+//		time.Sleep(time.Second * 10)
+//	}
+//}
+
+//  DeviceRealSnMap[sn] = 3
+
 func DeviceRealTime() {
 	fmt.Println("=====================DeviceRealTime GO===============")
 	time.Sleep(time.Second * 3)
 	for true {
+		// 如果能拿到key,10s等待时间还没结束,则不继续往下执行
+		if Device.Redis_DeviceRealWait_IsExist("DeviceRealWait10Second") {
+			time.Sleep(time.Second * 1)
+			continue
+		}
 		lib.DeviceRealSnMap.Range(func(k, v interface{}) bool {
-			fmt.Println("DeviceRealSnMap:", k, " num:", v)
-			NatsServer.Get_Device_Realtime(k.(string))
-
-			temp := v.(int)
-			temp--
-			lib.DeviceRealSnMap.Store(k, temp)
-			if temp == 0 {
-				lib.DeviceRealSnMap.Delete(k)
+			sn := strings.Split(k.(string), "|")[0]
+			mqttid := strings.Split(k.(string), "|")[1]
+			num, is := Device.Redis_DeviceReal_Get(sn)
+			if !is {
+				Device.Redis_DeviceReal_Set(sn, 1)
+			} else {
+				Device.Redis_DeviceReal_Set(sn, num+1)
 			}
+			// 每次拿到Map的key后,删除该key,否则会造成死循环
+			lib.DeviceRealSnMap.Delete(k)
+			// 实时数据请求次数达到180次(30分钟*6次/分钟=180)
+			// 更新实时请求为2分钟每次(2分钟*6次/分钟=12)
+			if num > 180 && (num-180)%12 != 0 {
+				fmt.Println("num:", num)
+				return true
+			}
+
+			logs.Debug("DeviceRealSnMap:", sn, " num:", num)
+			NatsServer.Get_Device_Realtime(sn, mqttid)
+
 			time.Sleep(time.Millisecond * 100)
 			return true
 		})
-		time.Sleep(time.Second * 10)
 
+		Device.Redis_DeviceRealWait_Set("DeviceRealWait10Second")
+		time.Sleep(time.Second * 10)
 	}
 }
-
-//  DeviceRealSnMap[sn] = 3

+ 2 - 1
controllers/Product.go

@@ -95,7 +95,8 @@ func (c *ProductController) ProductUpgrade_Add() {
 	deviceList := Device.Read_Device_List_ByT_model(T_model)
 
 	for _, v := range deviceList {
-		NatsServer.Up_ProductUpgrade(v.T_sn, T_version, T_file)
+		device, _ := Device.Read_Device_ByT_sn(v.T_sn)
+		NatsServer.Up_ProductUpgrade(v.T_sn, T_version, T_file, device.T_mqttid)
 	}
 
 	System.Add_UserLogs_T(c.Admin_r.T_uuid, "设备版本升级管理", "添加", var_)

+ 463 - 20
controllers/User.go

@@ -13,7 +13,10 @@ import (
 	"github.com/beego/beego/v2/adapter/orm"
 	beego "github.com/beego/beego/v2/server/web"
 	uuid "github.com/satori/go.uuid"
+	"github.com/shopspring/decimal"
+	"github.com/xuri/excelize/v2"
 	"math"
+	"os"
 	"strconv"
 	"strings"
 	"time"
@@ -102,12 +105,13 @@ func (c *UserController) Company_Add() {
 	T_v3d := c.GetString("T_v3d")
 
 	var_ := Account.Company{
-		T_mid:   T_mid,
-		T_name:  T_name,
-		T_State: 1,
-		T_plan:  T_plan,
-		T_data:  T_data,
-		T_v3d:   T_v3d,
+		T_mid:     T_mid,
+		T_name:    T_name,
+		T_State:   1,
+		T_plan:    T_plan,
+		T_data:    T_data,
+		T_v3d:     T_v3d,
+		T_warning: 1,
 	}
 
 	id, err := Account.Add_Company(var_)
@@ -149,13 +153,46 @@ func (c *UserController) Company_Edit() {
 	}
 
 	T_name := c.GetString("T_name")
-	T_plan := c.GetString("T_plan")
-	T_data := c.GetString("T_data")
-	T_v3d := c.GetString("T_v3d")
 
 	if len(T_name) > 0 {
 		Company_r.T_name = T_name
 	}
+
+	is := Account.Update_Company(Company_r, "T_name")
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(c.Admin_r.T_uuid, "公司管理", "修改", Company_r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 数字孪生
+func (c *UserController) Company_DigitalTwin() {
+
+	Id, Id_err := c.GetInt("Id")
+	if Id_err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	Company_r, err := Account.Read_Company_ById(Id)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_plan := c.GetString("T_plan")
+	T_data := c.GetString("T_data")
+	T_v3d := c.GetString("T_v3d")
+	T_warning, _ := c.GetInt("T_warning")
+
 	if len(T_plan) > 0 {
 		Company_r.T_plan = T_plan
 	}
@@ -165,15 +202,103 @@ func (c *UserController) Company_Edit() {
 	if len(T_v3d) > 0 {
 		Company_r.T_v3d = T_v3d
 	}
+	if T_warning > 0 {
+		Company_r.T_warning = T_warning
+	}
 
-	is := Account.Update_Company(Company_r, "T_name", "T_plan", "T_data", "T_v3d")
+	is := Account.Update_Company(Company_r, "T_plan", "T_data", "T_v3d")
 	if !is {
 		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
 		c.ServeJSON()
 		return
 	}
 
-	System.Add_UserLogs_T(c.Admin_r.T_uuid, "公司管理", "修改", Company_r)
+	System.Add_UserLogs_T(c.Admin_r.T_uuid, "公司管理", "修改数字孪生", Company_r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 充值
+func (c *UserController) Company_Pay() {
+
+	Id, Id_err := c.GetInt("Id")
+	if Id_err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	Company_r, err := Account.Read_Company_ById(Id)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_balance, _ := c.GetFloat("T_balance")
+	T_money64, _ := decimal.NewFromFloat(float64(Company_r.T_money) + T_balance).Round(2).Float64()
+	Company_r.T_money = float32(T_money64)
+
+	is := Account.Update_Company(Company_r, "T_money")
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "充值失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 添加充值记录
+	bill := Company.CompanyBill{
+		T_pid:      Company_r.Id,
+		T_type:     "充值",
+		T_project:  "充值",
+		T_bill:     "充值",
+		T_charging: float32(T_balance),
+		T_balance:  float32(T_money64),
+	}
+	_, err = Company.Add_CompanyBill(bill)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "充值失败!"}
+		c.ServeJSON()
+		return
+	}
+	System.Add_UserLogs_T(c.Admin_r.T_uuid, "公司管理", "充值", Company_r)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 报警统计
+func (c *UserController) Company_Warning() {
+
+	Id, Id_err := c.GetInt("Id")
+	if Id_err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	Company_r, err := Account.Read_Company_ById(Id)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "Id Err!"}
+		c.ServeJSON()
+		return
+	}
+
+	T_warning, _ := c.GetInt("T_warning")
+
+	if T_warning > 0 {
+		Company_r.T_warning = T_warning
+	}
+
+	is := Account.Update_Company(Company_r, "T_warning")
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	System.Add_UserLogs_T(c.Admin_r.T_uuid, "公司管理", "修改报警统计", Company_r)
 	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
 	c.ServeJSON()
 	return
@@ -196,7 +321,6 @@ func (c *UserController) Company_Del() {
 	}
 
 	ids := Account.ReadCompanyIds_T_path(Company_r.T_path)
-
 	if cnt := Account.Read_Admin_Num_ByT_pid(ids); cnt > 0 {
 		c.Data["json"] = lib.JSONS{Code: 202, Msg: "有关联用户,禁止删除!"}
 		c.ServeJSON()
@@ -255,13 +379,13 @@ func (c *UserController) Company_Entry() {
 			visit = true
 		} else {
 			pids := lib.SplitStringToIntIds(c.Admin_r.T_pids, "P")
-
-			list := Account.ReadCompanyIds_T_pids(pids)
-
-			for _, v := range list {
-				if T_pid == v {
-					visit = true
-					break
+			if len(pids) > 0 {
+				list := Account.ReadCompanyIds_T_pids(pids)
+				for _, v := range list {
+					if T_pid == v {
+						visit = true
+						break
+					}
 				}
 			}
 		}
@@ -537,15 +661,24 @@ func (c *UserController) User_Home() {
 	// 验证登录
 	admin_r := c.Admin_r
 
+	type NoticeRecord struct {
+		Sms   int // 短信
+		Phone int // 电话
+	}
+
 	type Info struct {
 		T_name                string           // 姓名
+		T_pids                string           // 内部用户绑定的公司id
 		T_pid                 int              // 公司id
 		T_Days                int              // 服务天输
 		Admin                 []Account.Admin_ // 专属管理员
 		WarningNum            int64            // 报警数量
 		UntreatedWarningNum   int64            // 未处理报警数量
 		WorkOrderNum          int64            // 工单数量
+		WarningRate           float32          // 设备报警率
 		UntreatedWorkOrderNum int64            // 未处理工单数量
+		Balance               float32          // 余额
+		NoticeRecord          NoticeRecord     // 通知记录
 	}
 	var info Info
 	info.T_name = admin_r.T_name
@@ -562,8 +695,15 @@ func (c *UserController) User_Home() {
 		info.Admin = Admin_
 		info.WarningNum = Warning.Read_Warning_ALL_T_State_Count(admin_r.T_pid, 1, power.T_warning, true)
 		info.UntreatedWarningNum = Warning.Read_Warning_ALL_T_State_Count(admin_r.T_pid, 3, power.T_warning, false)
+		info.Balance = company.T_money
+		info.NoticeRecord.Sms = Warning.Get_WarningSandNum_CurrentMonth(admin_r.T_pid, 1)
+		info.NoticeRecord.Phone = Warning.Get_WarningSandNum_CurrentMonth(admin_r.T_pid, 2)
 	}
 	if admin_r.T_pid == 0 {
+		if len(admin_r.T_pids) > 0 && admin_r.T_pids != "*" {
+			info.T_pids = admin_r.T_pids
+			info.WarningRate = Warning.Read_WarningRate_Yesterday(admin_r.T_uuid)
+		}
 		info.WorkOrderNum, info.UntreatedWorkOrderNum = NatsServer.Read_WorkOrderT_State_Count(admin_r.T_pids)
 	}
 
@@ -587,9 +727,28 @@ func (c *UserController) Admin_List() {
 	}
 
 	T_name := c.GetString("T_name")
+	if c.Admin_r.T_pid > 0 {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "无权查看!"}
+		c.ServeJSON()
+		return
+	}
+	T_bind_company, _ := c.GetInt("T_bind_company") // 管理员绑定公司 0-全部 1-绑定公司
 
 	Account.Read_Power_All_Map()
-	r_jsons.Data, r_jsons.Num = Account.Read_Admin_List(0, T_name, page, page_z)
+	userList, num := Account.Read_Admin_List(0, T_name, page, page_z)
+	r_jsons.Data, r_jsons.Num = userList, num
+	// 过滤已绑定公司列表
+	if T_bind_company == 1 {
+		var adminList []Account.Admin_R
+		for _, v := range userList {
+			if len(v.T_pids) == 0 || v.T_pids == "*" {
+				continue
+			}
+			adminList = append(adminList, v)
+		}
+		r_jsons.Data = adminList
+	}
+
 	r_jsons.Page = page
 	r_jsons.Page_size = int(math.Ceil(float64(r_jsons.Num) / float64(page_z)))
 
@@ -882,6 +1041,11 @@ func (c *UserController) AdminCompanyBind_Del() {
 	}
 
 	T_pids := Account.ReadCompanyIds_T_path(Company_r.T_path)
+	if len(T_pids) == 0 {
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+		c.ServeJSON()
+		return
+	}
 
 	if err = Account.Delete_Company_bind(r, T_pids); err != nil {
 		c.Data["json"] = lib.JSONS{Code: 202, Msg: "公司绑定失败"}
@@ -1147,6 +1311,158 @@ func (c *UserController) Menu_List_All() {
 	return
 }
 
+func (c *UserController) Menu_Excel() {
+
+	filename := fmt.Sprintf("冷链3.0菜单")
+
+	f := excelize.NewFile()
+
+	Style1, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Bold: true, Size: 16, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
+		})
+
+	Style2, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Bold: true, Size: 14, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+			Border: []excelize.Border{
+				{Type: "left", Color: "000000", Style: 1},
+				{Type: "top", Color: "000000", Style: 1},
+				{Type: "bottom", Color: "000000", Style: 1},
+				{Type: "right", Color: "000000", Style: 1},
+			},
+		})
+	f.MergeCell("Sheet1", "A1", "G1")
+	f.SetRowStyle("Sheet1", 1, 1, Style1)
+	f.SetCellValue("Sheet1", "A1", "Menu")
+	f.SetRowHeight("Sheet1", 1, 30)
+
+	f.MergeCell("Sheet1", "H1", "M1")
+	f.SetRowStyle("Sheet1", 1, 1, Style1)
+	f.SetCellValue("Sheet1", "H1", "API")
+	f.SetRowHeight("Sheet1", 1, 30)
+
+	f.SetCellStyle("Sheet1", "A2", "G2", Style2)
+	f.SetRowHeight("Sheet1", 2, 25)
+	// 这里设置表头
+	f.SetCellValue("Sheet1", "A2", "ID")
+	f.SetCellValue("Sheet1", "B2", "t_mid")
+	f.SetCellValue("Sheet1", "C2", "t_name")
+	f.SetCellValue("Sheet1", "D2", "t_permission")
+	f.SetCellValue("Sheet1", "E2", "t_sort")
+	f.SetCellValue("Sheet1", "F2", "t_pid")
+	f.SetCellValue("Sheet1", "G2", "t_icon")
+
+	f.SetCellValue("Sheet1", "H2", "ID")
+	f.SetCellValue("Sheet1", "I2", "t__menu__id")
+	f.SetCellValue("Sheet1", "J2", "t_name")
+	f.SetCellValue("Sheet1", "K2", "t_uri")
+	f.SetCellValue("Sheet1", "L2", "t_method")
+	f.SetCellValue("Sheet1", "M2", "t_enable")
+
+	// 设置列宽
+	f.SetColWidth("Sheet1", "A", "M", 15)
+
+	line := 2
+
+	menu := Account.Read_Menu_All()
+
+	for _, m := range menu {
+		Menu_Call(f, m, line)
+	}
+
+	Style11, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Size: 10, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+			Border: []excelize.Border{
+				{Type: "top", Color: "000000", Style: 1},
+			},
+		})
+	Style22, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Size: 10, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+			Border: []excelize.Border{
+				{Type: "left", Color: "000000", Style: 1},
+			},
+		})
+	Style33, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Size: 10, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+			Border: []excelize.Border{
+				{Type: "right", Color: "000000", Style: 1},
+			},
+		})
+	Style44, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Size: 10, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+			Border: []excelize.Border{
+				{Type: "bottom", Color: "000000", Style: 1},
+			},
+		})
+	//// 循环写入数据
+	for _, v := range menu {
+		line1 := line
+		line = Menu_Call(f, v, line)
+		f.SetCellStyle("Sheet1", fmt.Sprintf("A%d", line1), fmt.Sprintf("M%d", line1), Style11)
+		f.SetCellStyle("Sheet1", fmt.Sprintf("A%d", line), fmt.Sprintf("A%d", line), Style22)
+		f.SetCellStyle("Sheet1", fmt.Sprintf("M%d", line), fmt.Sprintf("M%d", line), Style33)
+		f.SetCellStyle("Sheet1", fmt.Sprintf("A%d", line), fmt.Sprintf("M%d", line), Style44)
+	}
+
+	timeStr := filename + fmt.Sprintf("(%s)", lib.GetRandstring(8, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 0))
+	// 保存文件
+	if err := f.SaveAs("ofile/" + timeStr + ".xlsx"); err != nil {
+		fmt.Println(err)
+	}
+
+	var url string
+	////// 上传 OSS
+	//url, is := NatsServer.Qiniu_UploadFile(lib.GetCurrentDirectory()+"/ofile/"+timeStr+".xlsx", "ofile/"+timeStr+".xlsx")
+	//if !is {
+	//	c.Data["json"] = lib.JSONS{Code: 202, Msg: "oss!"}
+	//	c.ServeJSON()
+	//	return
+	//}
+	////删除目录
+	//err = os.Remove("ofile/" + timeStr + ".xlsx")
+	//if err != nil {
+	//	fmt.Println(err)
+	//}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: url}
+	c.ServeJSON()
+	return
+
+}
+
+func Menu_Call(f *excelize.File, v Account.Menu, line int) int {
+	line++
+	f.SetCellValue("Sheet1", fmt.Sprintf("A%d", line), v.Id)
+	f.SetCellValue("Sheet1", fmt.Sprintf("B%d", line), v.T_mid)
+	f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), v.T_name)
+	f.SetCellValue("Sheet1", fmt.Sprintf("D%d", line), v.T_permission)
+	f.SetCellValue("Sheet1", fmt.Sprintf("E%d", line), v.T_sort)
+	f.SetCellValue("Sheet1", fmt.Sprintf("F%d", line), v.T_pid)
+	f.SetCellValue("Sheet1", fmt.Sprintf("G%d", line), v.T_icon)
+	apiList := Account.Read_API_List_ByMenuId(v.Id)
+	for _, api := range apiList {
+		f.SetCellValue("Sheet1", fmt.Sprintf("H%d", line), api.Id)
+		f.SetCellValue("Sheet1", fmt.Sprintf("I%d", line), api.T_Menu_Id)
+		f.SetCellValue("Sheet1", fmt.Sprintf("J%d", line), api.T_name)
+		f.SetCellValue("Sheet1", fmt.Sprintf("K%d", line), api.T_uri)
+		f.SetCellValue("Sheet1", fmt.Sprintf("L%d", line), api.T_method)
+		f.SetCellValue("Sheet1", fmt.Sprintf("M%d", line), api.T_enable)
+		line++
+	}
+	return line
+}
+
 // 流量池
 func (c *UserController) Flow_Pool() {
 	var r_jsons lib.R_JSONS
@@ -1157,3 +1473,130 @@ func (c *UserController) Flow_Pool() {
 	c.ServeJSON()
 	return
 }
+
+// 账单下载
+func (c *UserController) CompanyBill_Excel() {
+
+	T_month := c.GetString("T_month")
+	_, err := time.Parse("2006-01", T_month)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "日期格式错误!"}
+		c.ServeJSON()
+		return
+	}
+
+	year, month := strings.Split(T_month, "-")[0], strings.Split(T_month, "-")[1]
+
+	company, _ := Account.Read_Company_ById(c.Admin_r.T_pid)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "查询失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	filename := fmt.Sprintf("%s%s年%s月账单", company.T_name, year, month)
+
+	f := excelize.NewFile()
+
+	Style1, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Bold: true, Size: 16, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center"},
+		})
+
+	Style2, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Bold: true, Size: 14, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+			Border: []excelize.Border{
+				{Type: "left", Color: "000000", Style: 1},
+				{Type: "top", Color: "000000", Style: 1},
+				{Type: "bottom", Color: "000000", Style: 1},
+				{Type: "right", Color: "000000", Style: 1},
+			},
+		})
+	f.MergeCell("Sheet1", "A1", "G1")
+	f.SetRowStyle("Sheet1", 1, 1, Style1)
+	f.SetCellValue("Sheet1", "A1", filename)
+	f.SetRowHeight("Sheet1", 1, 30)
+
+	f.SetCellStyle("Sheet1", "A2", "G2", Style2)
+	f.SetRowHeight("Sheet1", 2, 25)
+	// 这里设置表头
+	f.SetCellValue("Sheet1", "A2", "编号")
+	f.SetCellValue("Sheet1", "B2", "项目")
+	f.SetCellValue("Sheet1", "C2", "说明")
+	f.SetCellValue("Sheet1", "D2", "扣费/充值")
+	f.SetCellValue("Sheet1", "E2", "金额(元)")
+	f.SetCellValue("Sheet1", "F2", "余额(元)")
+	f.SetCellValue("Sheet1", "G2", "时间")
+	// 设置列宽
+	f.SetColWidth("Sheet1", "A", "A", 10)
+	f.SetColWidth("Sheet1", "B", "B", 50)
+	f.SetColWidth("Sheet1", "C", "C", 15)
+	f.SetColWidth("Sheet1", "D", "D", 12)
+	f.SetColWidth("Sheet1", "E", "E", 15)
+	f.SetColWidth("Sheet1", "F", "F", 15)
+	f.SetColWidth("Sheet1", "G", "G", 20)
+
+	line := 2
+
+	CompanyBill_List, err := Company.Read_CompanyBill_List(c.Admin_r.T_pid, T_month)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "查询失败!"}
+		c.ServeJSON()
+		return
+	}
+
+	// 循环写入数据
+	for i, v := range CompanyBill_List {
+		line++
+
+		f.SetCellValue("Sheet1", fmt.Sprintf("A%d", line), i+1)
+		f.SetCellValue("Sheet1", fmt.Sprintf("B%d", line), v.T_project)
+		f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), v.T_bill)
+		f.SetCellValue("Sheet1", fmt.Sprintf("D%d", line), v.T_type)
+		f.SetCellValue("Sheet1", fmt.Sprintf("E%d", line), v.T_charging)
+		f.SetCellValue("Sheet1", fmt.Sprintf("F%d", line), v.T_balance)
+		f.SetCellValue("Sheet1", fmt.Sprintf("G%d", line), v.CreateTime.Format("2006-01-02"))
+
+	}
+	Style4, _ := f.NewStyle(
+		&excelize.Style{
+			Font:      &excelize.Font{Size: 12, Family: "宋体"},
+			Alignment: &excelize.Alignment{Horizontal: "center", Vertical: "center", WrapText: true},
+			Border: []excelize.Border{
+				{Type: "left", Color: "000000", Style: 1},
+				{Type: "top", Color: "000000", Style: 1},
+				{Type: "bottom", Color: "000000", Style: 1},
+				{Type: "right", Color: "000000", Style: 1},
+			},
+		})
+
+	f.SetCellStyle("Sheet1", "A2", fmt.Sprintf("G%d", line), Style4)
+
+	timeStr := filename + fmt.Sprintf("(%s)", lib.GetRandstring(8, "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", 0))
+	// 保存文件
+	if err = f.SaveAs("ofile/" + timeStr + ".xlsx"); err != nil {
+		fmt.Println(err)
+	}
+
+	var url string
+	//// 上传 OSS
+	url, is := NatsServer.Qiniu_UploadFile(lib.GetCurrentDirectory()+"/ofile/"+timeStr+".xlsx", "ofile/"+timeStr+".xlsx")
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "oss!"}
+		c.ServeJSON()
+		return
+	}
+	//删除目录
+	err = os.Remove("ofile/" + timeStr + ".xlsx")
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: url}
+	c.ServeJSON()
+	return
+
+}

+ 569 - 0
controllers/Warning.go

@@ -0,0 +1,569 @@
+package controllers
+
+import (
+	"Cold_Api/Nats/NatsServer"
+	"Cold_Api/conf"
+	"Cold_Api/controllers/lib"
+	"Cold_Api/logs"
+	"Cold_Api/models/Account"
+	"Cold_Api/models/Device"
+	"Cold_Api/models/System"
+	"Cold_Api/models/Warning"
+	"fmt"
+	"github.com/robfig/cron/v3"
+	"github.com/xuri/excelize/v2"
+	"math"
+	"os"
+	"strconv"
+	"time"
+)
+
+// 设备告警 ------------------------------------------
+
+// 告警列表
+func (c *DeviceController) DeviceWarning_List() {
+
+	type R_JSONS struct {
+		//必须的大写开头
+		Data      []Warning.Warning_R
+		Num       int64
+		Page      int
+		Page_size int
+	}
+	var r_jsons R_JSONS
+
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_name := c.GetString("T_name")
+	T_tp := c.GetString("T_tp")
+	Time_start := c.GetString("Time_start")
+	Time_end := c.GetString("Time_end")
+	T_handle, _ := c.GetInt("T_handle")
+
+	T_admin, _ := c.GetInt("T_admin")
+	T_history, _ := c.GetInt("T_history")
+	var tpList []string
+	if len(T_tp) > 0 {
+		tpList = lib.SplitStringIds(T_tp, "T")
+	} else {
+		power, _ := Account.Read_Power_ById(c.Admin_r.T_power)
+		tpList = lib.SplitStringIds(power.T_warning, "W")
+	}
+
+	var T_year, T_month string
+	if T_history == 1 {
+		date, err := time.Parse("2006-01-02 15:04:05", Time_start)
+		if err != nil {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误"}
+			c.ServeJSON()
+			return
+		}
+		T_year, T_month = date.Format("2006"), date.Format("01")
+	}
+
+	if T_admin == 1 {
+		if T_history == 1 {
+			// 获取备份
+			r_jsons.Data, r_jsons.Num = Warning.Read_Admin_Warning_Backups(c.Admin_r.T_pids, T_year, T_month, tpList, T_name, T_handle, Time_start, Time_end, page, page_z)
+		} else {
+			// 获取最新
+			r_jsons.Data, r_jsons.Num = Warning.Read_Admin_Warning_List(c.Admin_r.T_pids, tpList, T_name, T_handle, Time_start, Time_end, page, page_z)
+		}
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+		c.ServeJSON()
+		return
+	}
+
+	if T_history == 1 {
+		r_jsons.Data, r_jsons.Num = Warning.Read_Warning_Backups(c.T_pid, T_year, T_month, tpList, T_name, T_handle, Time_start, Time_end, page, page_z)
+	} else {
+		// 获取最新
+		r_jsons.Data, r_jsons.Num = Warning.Read_Warning_List(c.T_pid, tpList, T_name, T_handle, Time_start, Time_end, page, page_z)
+	}
+
+	r_jsons.Page = page
+	r_jsons.Page_size = int(math.Ceil(float64(r_jsons.Num) / float64(page_z)))
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+// 查询告警
+func (c *DeviceController) DeviceWarning_Get() {
+	id, _ := c.GetInt("T_id")
+	T_history, _ := c.GetInt("T_history")
+	T := Warning.Read_Warning_ById(int64(id))
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Warning.WarningToWarning_R(T_history, T)}
+	c.ServeJSON()
+	return
+}
+
+// 编辑告警(处理告警)
+func (c *DeviceController) DeviceWarning_Post() {
+	id, _ := c.GetInt("T_id")
+	T_Text := c.GetString("T_Text")
+	T_time := c.GetString("T_time")
+	T_history, _ := c.GetInt("T_history")
+
+	var T_year, T_month string
+	var warning Warning.Warning
+	Wtab := "warning"
+	if T_history == 1 {
+		date, err := time.Parse("2006-01-02 15:04:05", T_time)
+		if err != nil {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误"}
+			c.ServeJSON()
+			return
+		}
+		T_year, T_month = date.Format("2006"), date.Format("01")
+		Wtab += "_" + T_year + "_" + T_month
+		warning, err = Warning.Read_Warning_ById_Backups(id, T_year, T_month)
+		if err != nil {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_id Err!"}
+			c.ServeJSON()
+			return
+		}
+		warning.T_Text = T_Text
+		warning.T_State = 2
+		if is := Warning.Update_Warning_Backups(warning, T_year, T_month); !is {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+			c.ServeJSON()
+			return
+		}
+
+	} else {
+		warning = Warning.Read_Warning_ById(int64(id))
+		if warning.Id == 0 {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_id Err!"}
+			c.ServeJSON()
+			return
+		}
+		warning.T_Text = T_Text
+		warning.T_State = 2
+		if is := Warning.Update_Warning(warning, "T_Text", "T_State"); !is {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "修改失败!"}
+			c.ServeJSON()
+			return
+		}
+	}
+
+	System.Add_UserLogs(c.Admin_r.T_uuid, "设备管理", "报警处理操作", Wtab+":"+strconv.Itoa(id)+"->"+T_Text)
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 删除告警
+func (c *DeviceController) DeviceWarning_Del() {
+	id, _ := c.GetInt("T_id")
+	T_time := c.GetString("T_time")
+	T_history, _ := c.GetInt("T_history")
+
+	var T_year, T_month string
+	var warning Warning.Warning
+	Wtab := "warning"
+	if T_history == 1 {
+		date, err := time.Parse("2006-01-02 15:04:05", T_time)
+		if err != nil {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误"}
+			c.ServeJSON()
+			return
+		}
+		T_year, T_month = date.Format("2006"), date.Format("01")
+		Wtab += "_" + T_year + "_" + T_month
+
+		warning, err = Warning.Read_Warning_ById_Backups(id, T_year, T_month)
+		if err != nil {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_id Err!"}
+			c.ServeJSON()
+			return
+		}
+		warning.T_State = 0
+		if is := Warning.Update_Warning_Backups(warning, T_year, T_month); !is {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+			c.ServeJSON()
+			return
+		}
+
+	} else {
+		warning = Warning.Read_Warning_ById(int64(id))
+		if warning.Id == 0 {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "T_id Err!"}
+			c.ServeJSON()
+			return
+		}
+		warning.T_State = 0
+		if is := Warning.Update_Warning(warning, "T_Text", "T_State"); !is {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "删除失败!"}
+			c.ServeJSON()
+			return
+		}
+	}
+
+	System.Add_UserLogs(c.Admin_r.T_uuid, "设备管理", "报警删除操作", Wtab+":"+strconv.Itoa(id))
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!"}
+	c.ServeJSON()
+	return
+}
+
+// 导出告警
+func (c *DeviceController) DeviceWarning_Data_Excel() {
+	T_name := c.GetString("T_name")
+	T_tp := c.GetString("T_tp")
+	Time_start := c.GetString("Time_start")
+	Time_end := c.GetString("Time_end")
+	T_handle, _ := c.GetInt("T_handle")
+	T_history, _ := c.GetInt("T_history")
+	var tpList []string
+	if len(T_tp) > 0 {
+		tpList = lib.SplitStringIds(T_tp, "T")
+	} else {
+		power, _ := Account.Read_Power_ById(c.Admin_r.T_power)
+		tpList = lib.SplitStringIds(power.T_warning, "W")
+	}
+
+	var T_year, T_month string
+	if T_history == 1 {
+		date, err := time.Parse("2006-01-02 15:04:05", Time_start)
+		if err != nil {
+			c.Data["json"] = lib.JSONS{Code: 202, Msg: "时间格式错误"}
+			c.ServeJSON()
+			return
+		}
+		T_year, T_month = date.Format("2006"), date.Format("01")
+	}
+
+	var Device_data []Warning.Warning_R
+	if T_history == 1 {
+		// 获取备份
+		Device_data, _ = Warning.Read_Warning_Backups(c.T_pid, T_year, T_month, tpList, T_name, T_handle, Time_start, Time_end, 0, 9999)
+	} else {
+		// 获取最新
+		Device_data, _ = Warning.Read_Warning_List(c.T_pid, tpList, T_name, T_handle, Time_start, Time_end, 0, 9999)
+	}
+
+	f := excelize.NewFile() // 设置单元格的值
+	// 这里设置表头
+	f.SetCellValue("Sheet1", "A1", "报警类型")
+	f.SetCellValue("Sheet1", "B1", "Sn")
+	f.SetCellValue("Sheet1", "C1", "设备名称")
+	f.SetCellValue("Sheet1", "D1", "传感器")
+	f.SetCellValue("Sheet1", "E1", "报警内容")
+	f.SetCellValue("Sheet1", "F1", "记录时间")
+	f.SetCellValue("Sheet1", "G1", "处理")
+	f.SetCellValue("Sheet1", "H1", "处理时间")
+
+	// 设置列宽
+	f.SetColWidth("Sheet1", "A", "A", 20)
+	f.SetColWidth("Sheet1", "B", "B", 25)
+	f.SetColWidth("Sheet1", "C", "C", 30)
+	f.SetColWidth("Sheet1", "D", "D", 30)
+	f.SetColWidth("Sheet1", "G", "E", 30)
+	f.SetColWidth("Sheet1", "H", "F", 15)
+	f.SetColWidth("Sheet1", "I", "G", 30)
+	f.SetColWidth("Sheet1", "J", "H", 15)
+
+	line := 1
+
+	// 循环写入数据
+	for _, v := range Device_data {
+		line++
+		f.SetCellValue("Sheet1", fmt.Sprintf("A%d", line), Warning.Read_WarningType_Get(v.T_tp))
+		f.SetCellValue("Sheet1", fmt.Sprintf("B%d", line), fmt.Sprintf("%s[%d]", v.T_sn, v.Id))
+		f.SetCellValue("Sheet1", fmt.Sprintf("C%d", line), v.T_D_name)
+		f.SetCellValue("Sheet1", fmt.Sprintf("D%d", line), v.T_DS_name)
+		f.SetCellValue("Sheet1", fmt.Sprintf("E%d", line), v.T_Remark)
+		f.SetCellValue("Sheet1", fmt.Sprintf("F%d", line), v.T_Ut)
+		f.SetCellValue("Sheet1", fmt.Sprintf("G%d", line), v.T_Text)
+		f.SetCellValue("Sheet1", fmt.Sprintf("H%d", line), v.CreateTime)
+
+	}
+	timeStr := time.Now().Format("20060102150405")
+	// 保存文件
+	if err := f.SaveAs("ofile/" + timeStr + ".xlsx"); err != nil {
+		fmt.Println(err)
+	}
+
+	url, is := NatsServer.Qiniu_UploadFile(lib.GetCurrentDirectory()+"/ofile/"+timeStr+".xlsx", "ofile/"+timeStr+".xlsx")
+	if !is {
+		c.Data["json"] = lib.JSONS{Code: 202, Msg: "oss!"}
+		c.ServeJSON()
+		return
+	}
+	//删除文件
+	err := os.Remove("ofile/" + timeStr + ".xlsx")
+	if err != nil {
+		fmt.Println(err)
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: url}
+	c.ServeJSON()
+	return
+}
+
+// 告警提示列表
+func (c *DeviceController) DeviceWarningList_T_Tips() {
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Warning.Read_WarningType_All_T_Notice_mechanism()}
+	c.ServeJSON()
+	return
+}
+
+// 告警类型列表
+func (c *DeviceController) WarningType_List_All() {
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Warning.Read_WarningType_All()}
+	c.ServeJSON()
+	return
+}
+
+// 告警类型列表 - 权限关联列表
+func (c *DeviceController) WarningType_Power_List_All() {
+
+	power, err := Account.Read_Power_ById(c.Admin_r.T_power)
+	if err != nil {
+		c.Data["json"] = lib.JSONS{Code: 200, Msg: "获取菜单失败"}
+		c.ServeJSON()
+		return
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Warning.Read_WarningType_Power_All(power.T_warning)}
+	c.ServeJSON()
+	return
+}
+
+// 通过传感器类型获取报警列表
+func (c *DeviceController) Read_Warning_List_By_DS_T_type() {
+	var r_jsons lib.R_JSONS
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_type, _ := c.GetInt("T_type")
+	T_name := c.GetString("T_name")
+
+	r_jsons.Data, r_jsons.Num = Warning.Read_Warning_List_By_DS_T_type(c.T_pid, T_type, T_name, page, page_z)
+	r_jsons.Page = page
+	r_jsons.Page_size = int(math.Ceil(float64(r_jsons.Num) / float64(page_z)))
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+func (c *DeviceController) Read_WarningSend_List() {
+
+	var r_jsons lib.R_JSONS
+
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_ntype, _ := c.GetInt("T_ntype")
+
+	r_jsons.Data, r_jsons.Num = Warning.Read_WarningSand_List(c.T_pid, T_ntype, page, page_z)
+
+	r_jsons.Page = page
+	r_jsons.Page_size = int(math.Ceil(float64(r_jsons.Num) / float64(page_z)))
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: r_jsons}
+	c.ServeJSON()
+	return
+}
+
+func (c *DeviceController) Read_WarningRate_List() {
+
+	page, _ := c.GetInt("page")
+	if page < 1 {
+		page = 1
+	}
+	page_z, _ := c.GetInt("page_z")
+	if page_z < 1 {
+		page_z = conf.Page_size
+	}
+
+	T_type := c.GetString("T_type")
+	T_uuid := c.GetString("T_uuid")
+	T_year, _ := c.GetInt("T_year")
+	T_month, _ := c.GetInt("T_month")
+	var startTime, endTime string
+	now := time.Now()
+	var month time.Month
+	// 默认本月
+	if T_year == 0 {
+		T_year = now.Year()
+	}
+	if T_month == 0 {
+		month = now.Month()
+	} else {
+		month = time.Month(T_month)
+	}
+
+	if T_type == Warning.WarningRateDay {
+		startTime = time.Date(T_year, month, 1, 0, 0, 0, 0, time.Local).Format("2006-01-02")
+		endTime = time.Date(T_year, month+1, -1, 0, 0, 0, 0, time.Local).Format("2006-01-02")
+	}
+
+	// 默认本年
+	if T_type == Warning.WarningRateMonth {
+		startTime = time.Date(T_year, 1, 0, 0, 0, 0, 0, time.Local).Format("2006-01")
+		endTime = time.Date(T_year, 12, 0, 0, 0, 0, 0, time.Local).Format("2006-01")
+	}
+
+	if len(T_uuid) == 0 {
+		T_uuid = c.Admin_r.T_uuid
+	}
+
+	c.Data["json"] = lib.JSONS{Code: 200, Msg: "ok!", Data: Warning.Read_WarningRate_List(T_uuid, T_type, startTime, endTime)}
+	c.ServeJSON()
+	return
+}
+
+func Cron_WarningRate() {
+
+	//创建一个定时任务对象
+	c := cron.New(cron.WithSeconds())
+	//给对象增加定时任务
+	// @daily 每日运行一次
+	//c.AddFunc("0 */1 * * * ?", Cron_WarningRateDay_Add)
+	//c.AddFunc("0 */1 * * * ?", Cron_WarningRateMonth_Add)
+	c.AddFunc("@daily", Cron_WarningRateDay_Add)
+	c.AddFunc("@monthly", Cron_WarningRateMonth_Add)
+
+	//启动定时任务
+	c.Start()
+	defer c.Stop()
+
+	//查询语句,阻塞,让main函数不退出,保持程序运行
+	select {}
+
+}
+
+// 保存每天的设备报警率
+func Cron_WarningRateDay_Add() {
+
+	T_date := time.Now().AddDate(0, 0, -1).Format("2006-01-02")
+	logs.Info("开始统计" + T_date + "设备报警率")
+
+	// 获取管理员用户列表
+	adminList := Account.Read_Admin_List_All()
+
+	// 获取排除的pid及其子id
+	//Exclude_Pids := Get_Exclude_Pids()
+
+	// 获取内部用户关联的pid
+	for _, admin := range adminList {
+		// 内部用户已绑定公司,* 绑定所有公司
+		if len(admin.T_pids) == 0 || admin.T_pids == "*" {
+			continue
+		}
+		// 获取排除后的pid
+		T_pids := lib.SplitStringToIntIds(admin.T_pids, "P")
+		if len(T_pids) == 0 {
+			continue
+		}
+		pids := Account.ReadCompanyWarningIds_T_pids(T_pids)
+		if len(pids) == 0 {
+			continue
+		}
+		// 获取探头数量
+		dsCnt := Device.Read_DeviceSensorCount_ByT_pids(pids)
+		// 获取当天报警数量
+		warningCount := Warning.Read_WarningCount_byDay(pids)
+		T_rate, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", float64(warningCount)/float64(dsCnt)), 64) // 保留2位小数
+		// 保存设备报警率
+		warningRate := Warning.WarningRate{
+			T_uuid:        admin.T_uuid,
+			T_date:        T_date,
+			T_type:        Warning.WarningRateDay,
+			T_device_num:  dsCnt,
+			T_warning_num: warningCount,
+			T_rate:        float32(T_rate),
+		}
+		Warning.Add_WarningRate(warningRate)
+
+	}
+
+}
+
+// 保存每月的设备报警率
+func Cron_WarningRateMonth_Add() {
+
+	now := time.Now()
+	// fixme 测试
+	//now := time.Now().AddDate(0, 1, 0)
+
+	T_date := now.AddDate(0, -1, 0).Format("2006-01")
+	firstOfMonth := time.Date(now.Year(), now.Month(), 1, 0, 0, 0, 0, time.Local)
+	startTime := firstOfMonth.AddDate(0, -1, 0).Format("2006-01-02") // 上月第一天
+	endTime := firstOfMonth.AddDate(0, 0, -1).Format("2006-01-02")   // 上月最后一天
+
+	logs.Info("开始统计" + T_date + "设备报警率")
+	logs.Info("开始时间" + startTime)
+	logs.Info("结束时间" + endTime)
+
+	rateAvgList := Warning.Read_WarningRateAvg_Month(startTime, endTime)
+	// 获取内部用户关联的pid
+	for _, rate := range rateAvgList {
+		T_rate, _ := strconv.ParseFloat(fmt.Sprintf("%.2f", float64(rate.T_warning_num)/float64(rate.T_device_num)), 64) // 保留2位小数
+
+		// 保存设备报警率
+		warningRate := Warning.WarningRate{
+			T_uuid:        rate.T_uuid,
+			T_date:        T_date,
+			T_type:        Warning.WarningRateMonth,
+			T_device_num:  rate.T_device_num,
+			T_warning_num: rate.T_warning_num,
+			T_rate:        float32(T_rate),
+		}
+		Warning.Add_WarningRate(warningRate)
+
+	}
+
+}
+
+// 获取排除的pids
+func Get_Exclude_Pids() map[int]struct{} {
+	ColdExcludePidList := lib.SplitStringToIntIds(conf.WarningRateExcludePid, ",")
+	// 获取排除的pid
+	ExcludeList := Account.ReadCompanyIds_T_pids(ColdExcludePidList)
+	ExcludeListMap := make(map[int]struct{})
+	for _, v := range ExcludeList {
+		ExcludeListMap[v] = struct{}{}
+	}
+	return ExcludeListMap
+}
+
+// 获取用户排除后的pids
+func Get_AfterExclude_Pids(excludePids map[int]struct{}, adminPids string) []int {
+	var list []int
+	T_pids := lib.SplitStringToIntIds(adminPids, "P")
+	userPids := Account.ReadCompanyIds_T_pids(T_pids)
+	if len(T_pids) == 0 {
+		return userPids
+	}
+	for _, v := range userPids {
+		if _, ok := excludePids[v]; ok {
+			continue
+		}
+		list = append(list, v)
+	}
+	return list
+}

+ 1 - 1
controllers/lib/Qiniu.go

@@ -71,7 +71,7 @@ func Pload_qiniu(localFile string, name string) bool {
 func UploadToken(T_suffix string) string {
 	Tokey := strconv.FormatInt(time.Now().Unix(), 10) + uuid.NewV4().String()
 	if len(T_suffix) == 0 {
-		T_suffix = ".png"
+		T_suffix = "png"
 	}
 	putPolicy := storage.PutPolicy{
 		Scope:      conf.Qiniu_BUCKET,

+ 8 - 0
controllers/lib/libString.go

@@ -101,3 +101,11 @@ func IntIdsDistinct(Ids []int) (result []int) {
 	}
 	return result
 }
+
+func StringListToDotStr(str []string) (r string) {
+	for _, v := range str {
+		r += v + ","
+	}
+	r = strings.TrimRight(r, ",")
+	return r
+}

+ 2 - 0
go.mod

@@ -35,7 +35,9 @@ require (
 	github.com/prometheus/procfs v0.8.0 // indirect
 	github.com/richardlehane/mscfb v1.0.4 // indirect
 	github.com/richardlehane/msoleps v1.0.3 // indirect
+	github.com/robfig/cron/v3 v3.0.1 // indirect
 	github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 // indirect
+	github.com/shopspring/decimal v1.3.1 // indirect
 	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
 	github.com/xuri/efp v0.0.0-20220603152613-6918739fd470 // indirect
 	github.com/xuri/nfp v0.0.0-20220409054826-5e722a1d9e22 // indirect

+ 4 - 0
go.sum

@@ -272,6 +272,8 @@ github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7
 github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
 github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM=
 github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg=
+github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
+github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
 github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
 github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
 github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
@@ -281,6 +283,8 @@ github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdh
 github.com/shiena/ansicolor v0.0.0-20151119151921-a422bbe96644/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18 h1:DAYUYH5869yV94zvCES9F51oYtN5oGlwjxJJz7ZCnik=
 github.com/shiena/ansicolor v0.0.0-20200904210342-c7312218db18/go.mod h1:nkxAfR/5quYxwPZhyDxgasBMnRtBZd0FCEpawpjMUFg=
+github.com/shopspring/decimal v1.3.1 h1:2Usl1nmF/WZucqkFZhnfFYxxxu8LG21F6nPQBE5gKV8=
+github.com/shopspring/decimal v1.3.1/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
 github.com/siddontang/go v0.0.0-20170517070808-cb568a3e5cc0/go.mod h1:3yhqj7WBBfRhbBlzyOC3gUxftwsU0u8gqevxwIHQpMw=
 github.com/siddontang/goredis v0.0.0-20150324035039-760763f78400/go.mod h1:DDcKzU3qCuvj/tPnimWSsZZzvk9qvkvrIL5naVBPh5s=
 github.com/siddontang/rdb v0.0.0-20150307021120-fc89ed2e418d/go.mod h1:AMEsy7v5z92TR1JKMkLLoaOQk++LVnOKL3ScbJ8GNGA=

+ 14 - 9
main.go

@@ -78,6 +78,9 @@ func main() {
 	go Warning.Read_WarningType_All_Maps()   // 初始化报警类型
 	go Product.Read_ProductType_All_Map()    // 初始化产品类型
 	go Device.Read_DeviceSensorTypeAll_Map() // 初始化传感器类型
+	if conf.MqttServer_id == "mqttjxit" {
+		go controllers.Cron_WarningRate() // 只在一台机启动定时任务
+	}
 
 	fmt.Println("======= beego.Run ======")
 	beego.Run()
@@ -98,16 +101,18 @@ func RecoverPanic(ctx *context.Context, config *beego.Config) {
 		}
 		//显示错误
 		data := map[string]interface{}{
-			"ret":           4000,
-			"AppError":      fmt.Sprintf("%v", err),
-			"RequestMethod": ctx.Input.Method(),
-			"RequestURL":    ctx.Input.URI(),
-			"RemoteAddr":    ctx.Input.IP(),
-			"Stack":         stack,
-			"GoVersion":     runtime.Version(),
-			"Code":          500,
-			"Msg":           "请稍后重试!",
+			"AppError": fmt.Sprintf("%v", err),
+			"Code":     500,
+			"Msg":      "请稍后重试!",
+		}
+		if conf.RunMode == "dev" {
+			data["RequestMethod"] = ctx.Input.Method()
+			data["RequestURL"] = ctx.Input.URI()
+			data["RemoteAddr"] = ctx.Input.IP()
+			data["Stack"] = stack
+			data["GoVersion"] = runtime.Version()
 		}
+
 		_ = ctx.Output.JSON(data, true, true)
 		//if ctx.Output.Status != 0 {
 		//	ctx.ResponseWriter.WriteHeader(ctx.Output.Status)

+ 56 - 9
models/Account/Admin.go

@@ -13,17 +13,18 @@ import (
 	_ "github.com/go-sql-driver/mysql"
 	"strconv"
 	"strings"
+	"sync"
 	"time"
 )
 
 type Admin struct {
 	Id      int    `orm:"column(ID);size(11);auto;pk"`
-	T_uuid  string `orm:"size(256);null"`     //  用户编号
-	T_pid   int    `orm:"size(200);null"`     //  绑定公司 ( 只有创建公司用户时添加,内部人员 为0)
-	T_pids  string `orm:"size(200);null"`     //  绑定公司管理 Pid| 如 P1|P2
-	T_power int    `orm:"size(2);default(0)"` // 权限 (关联权限表)
-	T_user  string `orm:"size(256);null"`     // 用户名 (唯一)
-	T_pass  string `orm:"size(256);null"`     // MD5
+	T_uuid  string `orm:"size(256);null"`      // 用户编号
+	T_pid   int    `orm:"size(200);null"`      // 绑定公司 ( 只有创建公司用户时添加,内部人员 为0)
+	T_pids  string `orm:"size(200);null"`      // 绑定公司管理 Pid| 如 P1|P2
+	T_power int    `orm:"size(20);default(0)"` // 权限 (关联权限表)
+	T_user  string `orm:"size(256);null"`      // 用户名 (唯一)
+	T_pass  string `orm:"size(256);null"`      // MD5
 
 	T_name  string `orm:"size(256);null"` // 姓名
 	T_phone string `orm:"size(256);null"` // 电话
@@ -81,10 +82,12 @@ func (t *Admin) TableName() string {
 }
 
 var redisCache_Admin cache.Cache
+var AdminMap *sync.Map // 泛型
 
 func init() {
 	//注册模型
 	orm.RegisterModel(new(Admin))
+	AdminMap = new(sync.Map)
 
 	config := fmt.Sprintf(`{"key":"%s","conn":"%s","dbNum":"%s","password":"%s"}`,
 		"redis_User_Admin", conf.Redis_address, conf.Redis_dbNum, conf.Redis_password)
@@ -250,6 +253,7 @@ func Read_Admin_ByUuid(T_uuid string) (r Admin, err error) {
 	if err != nil {
 		logs.Error(lib.FuncName(), err)
 	}
+	Redis_Admin_Set(r)
 	return r, err
 }
 
@@ -291,6 +295,31 @@ func Read_Admin_List(T_pid int, T_name string, page int, page_z int) (AdminList
 	return AdminList, cnt
 }
 
+// 获取所有管理员用户列表
+func Read_Admin_List_All() (AdminList []Admin_R) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+
+	qs := o.QueryTable(new(Admin))
+	var maps []Admin
+	cond := orm.NewCondition()
+
+	cond1 := cond.And("T_State", 1).And("T_pid", 0).AndNot("T_pids", "")
+
+	_, err := qs.SetCond((*orm2.Condition)(cond1)).OrderBy("-Id").All(&maps)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return AdminList
+	}
+
+	for _, v := range maps {
+		AdminList = append(AdminList, AdminToAdmin_R(v))
+	}
+
+	return AdminList
+}
+
 func Read_Admin_List_T_pids(T_pid int) (AdminList []Admin_R) {
 
 	o := orm.NewOrm()
@@ -354,7 +383,9 @@ func Read_Admin_Num_ByT_power(T_power int) int {
 
 // 查询 用户关联的公司总数
 func Read_Admin_Num_ByT_pid(T_pids []int) int {
-
+	if len(T_pids) == 0 {
+		return 0
+	}
 	o := orm.NewOrm()
 	// 也可以直接使用 Model 结构体作为表名
 	qs := o.QueryTable(new(Admin))
@@ -366,8 +397,8 @@ func Read_Admin_Num_ByT_pid(T_pids []int) int {
 	return int(cnt)
 }
 
-// 获取列表
-func Read_Admin_List_All() (AdminList []Admin_R) {
+// 获取所有用户列表
+func Read_User_List_All() (AdminList []Admin_R) {
 
 	o := orm.NewOrm()
 	// 也可以直接使用 Model 结构体作为表名
@@ -454,3 +485,19 @@ func Delete_Company_bind_T_pids(o orm.Ormer, T_pid int) (err error) {
 	return err
 
 }
+
+func Read_Admin_All_Map(A []Admin_R) {
+	for _, v := range A {
+		AdminMap.Store(v.T_uuid, v)
+	}
+}
+
+func Read_Admin_T_name_Get(T_uuid string) string {
+	// 有先加入 给全部人发消息
+	v, ok := AdminMap.Load(T_uuid) /*如果确定是真实的,则存在,否则不存在 */
+	if ok {
+		return v.(Admin_R).T_name
+	} else {
+		return ""
+	}
+}

+ 65 - 16
models/Account/Company.go

@@ -25,25 +25,26 @@ type Company struct {
 	T_data string `orm:"type(text);null"` //  大数据
 	T_v3d  string `orm:"type(text);null"` //  3D 视图
 
-	T_path string `orm:"size(256);null"` // 公司路径 /0/1/5/
-
+	T_path     string    `orm:"size(256);null"` // 公司路径 /0/1/5/
 	T_money    float32   `orm:"digits(12);decimals(2)"`
-	T_State    int       `orm:"size(200);default(1)"`                                  //  0删除  1 正常
-	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now 每次 model 保存时都会对时间自动更新
-	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now_add 第一次保存时才设置时间
+	T_State    int       `orm:"size(200);default(1)"`                                  // 0删除  1正常
+	T_warning  int       `orm:"size(20);default(1)"`                                   // 是否处理报警信息 1处理 2不处理
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` // auto_now 每次 model 保存时都会对时间自动更新
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     // auto_now_add 第一次保存时才设置时间
 
 	Children []Company `orm:"-"`
 }
 
 type Company_R struct {
-	Id       int
-	T_mid    int     // 上一级 ID
-	T_name   string  // 公司名称
-	T_plan   string  // 平面图
-	T_data   string  // 大数据
-	T_v3d    string  // 3D 视图
-	T_money  float32 // 余额
-	Children []Company_R
+	Id        int
+	T_mid     int     // 上一级 ID
+	T_name    string  // 公司名称
+	T_plan    string  // 平面图
+	T_data    string  // 大数据
+	T_v3d     string  // 3D 视图
+	T_money   float32 // 余额
+	T_warning int     // 报警统计
+	Children  []Company_R
 }
 
 func CompanyToCompany_R(r Company) (v Company_R) {
@@ -54,6 +55,7 @@ func CompanyToCompany_R(r Company) (v Company_R) {
 	v.T_data = r.T_data
 	v.T_v3d = r.T_v3d
 	v.T_money = r.T_money
+	v.T_warning = r.T_warning
 	return v
 }
 
@@ -241,7 +243,9 @@ func Read_Company_Tree(admin_r Admin, T_name string) (CompanyList []Company_R) {
 	// 内部用户已绑定公司,* 绑定所有公司
 	if len(admin_r.T_pids) > 0 && admin_r.T_pids != "*" {
 		T_pids := lib.SplitStringToIntIds(admin_r.T_pids, "P")
-		cond1 = cond1.And("Id__in", ReadCompanyIds_T_pids(T_pids))
+		if len(T_pids) > 0 {
+			cond1 = cond1.And("Id__in", ReadCompanyIds_T_pids(T_pids))
+		}
 	}
 
 	if len(T_name) > 0 {
@@ -287,11 +291,17 @@ func Read_Company_Tree(admin_r Admin, T_name string) (CompanyList []Company_R) {
 
 func ReadCompanyIds_T_pids(T_pids []int) []int {
 
-	var companyList []Company
 	var companyIds []int
+	if len(T_pids) == 0 {
+		return companyIds
+	}
+
+	var companyList []Company
 	o := orm.NewOrm()
 	qs := o.QueryTable(new(Company))
+
 	_, err := qs.Filter("Id__in", T_pids).Filter("T_State", 1).All(&companyList)
+
 	if err != nil {
 		logs.Error(lib.FuncName(), err)
 		return companyIds
@@ -320,6 +330,46 @@ func ReadCompanyIds_T_path(T_path string) (companyIds []int) {
 	return companyIds
 }
 
+func ReadCompanyWarningIds_T_pids(T_pids []int) []int {
+
+	var companyList []Company
+	var companyIds []int
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Company))
+	if len(T_pids) == 0 {
+		return companyIds
+	}
+
+	_, err := qs.Filter("Id__in", T_pids).Filter("T_State", 1).Filter("T_warning", 1).All(&companyList)
+
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return companyIds
+	}
+	for _, company := range companyList {
+		subIds := ReadCompanyWarningIds_T_path(company.T_path)
+		companyIds = append(companyIds, subIds...)
+	}
+
+	return lib.IntIdsDistinct(companyIds)
+}
+
+// 通过T_pid查询所有子id
+func ReadCompanyWarningIds_T_path(T_path string) (companyIds []int) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Company))
+	var CompanyList []Company
+	_, err := qs.Filter("T_path__startswith", T_path).Filter("T_State", 1).Filter("T_warning", 1).All(&CompanyList)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return companyIds
+	}
+	for _, v := range CompanyList {
+		companyIds = append(companyIds, v.Id)
+	}
+	return companyIds
+}
+
 func Read_Company_List(T_name string) (CompanyList []Company_R) {
 
 	o := orm.NewOrm()
@@ -415,7 +465,6 @@ func Read_Company_List_All_ByT_name(T_name string) (maps []Company) {
 
 	qs := o.QueryTable(new(Company))
 	cond := orm.NewCondition()
-
 	if len(T_name) > 0 {
 		cond = cond.And("T_name__icontains", T_name)
 	}

+ 38 - 4
models/Account/Menu.go

@@ -221,6 +221,9 @@ func Read_Menu_ById(Id int) (r Menu, e error) {
 
 // 获取列表
 func Read_Menu_Bind_List(Power_Id int, Bind_Menu string, T_pid int) (r Menu_Permission) {
+	if len(Bind_Menu) == 0 {
+		return r
+	}
 	if r, is := Redis_Menu_Get(Power_Id, T_pid); is {
 		return r
 	}
@@ -328,6 +331,21 @@ func Read_Menu_List_All() (maps []Menu, menu_ids []int) {
 	return m, menu_ids
 }
 
+func Read_Menu_All() (maps []Menu) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+
+	qs := o.QueryTable(new(Menu))
+	_, err := qs.Filter("T_State", 1).OrderBy("Id").All(&maps)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+
+	return maps
+}
+
 // Menu_Call 构建菜单树
 // [{"Id":70,"T_mid":0,"T_name":"工单管理","T_permission":"workorder","T_sort":0,"T_pid":1,"T_bind":false,"Children":[{"Id":71,"T_mid":70,"T_name":"工单列表","T_permission":"workorder:list","T_sort":0,"T_pid":1,"T_bind":false,"Children":[]}]}]
 func Menu_Call(list []Menu, parentId int) []Menu {
@@ -419,11 +437,19 @@ func Read_API_ById(Id int) (r API, e error) {
 	return r, e
 }
 
+func Read_API_List_ByMenuId(MenuId int) (r []API) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(API))
+	qs.Filter("T_Menu_Id", MenuId).All(&r)
+	return r
+}
+
 // 获取列表
 func Read_API_List_ByPower_Id(Power_Id int, Menu_Bind string) (maps []API) {
-
+	if len(Menu_Bind) == 0 {
+		return
+	}
 	if r, is := Redis_API_Get(strconv.Itoa(Power_Id)); is {
-		//println("Redis_Get  OK")
 		return r
 	}
 
@@ -432,8 +458,12 @@ func Read_API_List_ByPower_Id(Power_Id int, Menu_Bind string) (maps []API) {
 
 	qs := o.QueryTable(new(API))
 
-	list := lib.SplitStringIds(Menu_Bind, "M")
-	_, err := qs.Filter("T_Menu_Id__in", list).All(&maps)
+	list := lib.SplitStringToIntIds(Menu_Bind, "M")
+	AllIds := list
+	if err := recursiveMenu(1, list, &AllIds); err != nil {
+		return
+	}
+	_, err := qs.Filter("T_Menu_Id__in", lib.IntIdsDistinct(AllIds)).All(&maps)
 	if err != nil {
 		logs.Error(lib.FuncName(), err)
 		return
@@ -443,6 +473,10 @@ func Read_API_List_ByPower_Id(Power_Id int, Menu_Bind string) (maps []API) {
 }
 
 func Read_API_List_By_Menu_Bind(Menu_Bind string) (maps []API) {
+	if len(Menu_Bind) == 0 {
+		return
+	}
+
 	o := orm.NewOrm()
 	// 也可以直接使用 Model 结构体作为表名
 

+ 75 - 0
models/Company/CompanyBill.go

@@ -0,0 +1,75 @@
+package Company
+
+import (
+	"Cold_Api/controllers/lib"
+	"Cold_Api/logs"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+type CompanyBill struct {
+	Id         int     `orm:"column(ID);size(11);auto;pk"`
+	T_pid      int     `orm:"index;size(256);"`       // Account.Company 绑定公司
+	T_type     string  `orm:"size(256);"`             // 扣费/充值
+	T_project  string  `orm:"size(256);"`             // 项目
+	T_bill     string  `orm:"type(text);"`            // 说明
+	T_charging float32 `orm:"digits(12);decimals(2)"` // 金额
+	T_balance  float32 `orm:"digits(12);decimals(2)"` // 余额(扣费后)
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+}
+
+func (t *CompanyBill) TableName() string {
+	return "company_bill" // 数据库名称   // ************** 替换 DesignDeviceNotice **************
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(CompanyBill))
+}
+
+func Add_CompanyBill(r CompanyBill) (id int64, err error) {
+	o := orm.NewOrm()
+	id, err = o.Insert(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+	return
+}
+
+func Read_CompanyBill_newest(T_pid int) (r CompanyBill, err error) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(CompanyBill))
+	cond := orm.NewCondition()
+	cond = cond.And("T_pid", T_pid)
+	var maps []CompanyBill
+	_, err = qs.Limit(1, 0).SetCond((*orm2.Condition)(cond)).OrderBy("-Id").All(&maps)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, err
+	}
+	if len(maps) == 0 {
+		return
+	}
+	return maps[0], nil
+}
+
+func Read_CompanyBill_List(T_pid int, T_month string) (r []CompanyBill, err error) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(CompanyBill))
+	cond := orm.NewCondition()
+	cond = cond.And("T_pid", T_pid).And("CreateTime__startswith", T_month)
+
+	var maps []CompanyBill
+	_, err = qs.SetCond((*orm2.Condition)(cond)).OrderBy("-Id").All(&maps)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, err
+	}
+	if len(maps) == 0 {
+		return
+	}
+	return maps, nil
+}

+ 1 - 1
models/Company/CompanyNotice.go

@@ -409,7 +409,7 @@ func Delete_CompanyNotice_Bind_By_T_uuid(T_uuid string) bool {
 
 }
 
-// 获取全部列表
+// 删除报警策略
 func Delete_CompanyNotice_Bind_By_T_uuid_T_pid(T_uuid string, T_pids []int) bool {
 
 	o := orm.NewOrm()

+ 8 - 6
models/Device/DeviceParameter.go

@@ -23,10 +23,11 @@ type DeviceParameter struct {
 	T_lostA int `orm:"size(5);null"` //传感器掉线报警触发间隔  s(0,60~600) 为0时只触发一次 默认:60  *
 	T_bat   int `orm:"size(5);null"` //电池电量下限   %(0~30) 默认:20 *
 
-	T_warn     int `orm:"size(5);null"` // 超限预警触发间隔 s(0,60~600)为0时只触发一次 默认:60  *
-	T_warnD    int `orm:"size(5);null"` // 超限预警延时   s(0~600) 默认:0 *
-	T_speed    int `orm:"size(5);null"` // 传感器采样率   s(1~240) 默认:15 *
-	T_dormancy int `orm:"size(5);null"` // 是否进入休眠  0:关闭 1:开启    默认:0
+	T_warn     int `orm:"size(5);null"`       // 超限预警触发间隔 s(0,60~600)为0时只触发一次 默认:60  *
+	T_warnD    int `orm:"size(5);null"`       // 超限预警延时   s(0~600) 默认:0 *
+	T_speed    int `orm:"size(5);null"`       // 传感器采样率   s(1~240) 默认:15 *
+	T_dormancy int `orm:"size(5);null"`       // 是否进入休眠  0:关闭 1:开启    默认:0
+	T_snum     int `orm:"size(5);default(0)"` // 【管理主机】 - 传感器数量  (范围0~255)
 
 	T_btname string `orm:"size(256);null"` //蓝牙打印机名称
 	T_btsid  int    `orm:"size(256);null"` //打印机服务号
@@ -34,8 +35,8 @@ type DeviceParameter struct {
 
 	T_uuid      string `orm:"size(256);null"`      // 处理 人员
 	T_Msid      int64  `orm:"size(50);default(0)"` // 消息识别ID
-	T_SendState int    `orm:"size(2);;default(1)"` // 发送状态  0 待发送   1 发送成功  2 发送失败  3 丢弃
-	T_State     int    `orm:"size(2);;default(1)"` //  1 系统获取   2 用户提交
+	T_SendState int    `orm:"size(2);default(1)"`  // 发送状态  0 待发送   1 发送成功  2 发送失败  3 丢弃
+	T_State     int    `orm:"size(2);default(1)"`  //  1 系统获取   2 用户提交
 
 	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
 	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
@@ -99,6 +100,7 @@ func DeviceParameter_T_text(r DeviceParameter) string {
 	s += " 超限预警延时:" + strconv.Itoa(r.T_warnD)
 	s += " 传感器采样率:" + strconv.Itoa(r.T_speed)
 	s += " 是否进入休眠:" + strconv.Itoa(r.T_dormancy)
+	s += " 传感器数量:" + strconv.Itoa(r.T_snum)
 	s += " 蓝牙打印机名称:" + r.T_btname
 	s += " 打印机服务号:" + strconv.Itoa(r.T_btsid)
 	s += " 蓝牙特征码:" + strconv.Itoa(r.T_btchar)

+ 73 - 0
models/Device/DeviceReal.go

@@ -0,0 +1,73 @@
+package Device
+
+import (
+	"Cold_Api/conf"
+	"Cold_Api/controllers/lib"
+	"Cold_Api/logs"
+	"encoding/json"
+	"fmt"
+	"github.com/astaxie/beego/cache"
+	_ "github.com/astaxie/beego/cache/redis"
+	"time"
+)
+
+var redisCache_DeviceReal cache.Cache
+
+func init() {
+
+	deviceRealConfig := fmt.Sprintf(`{"key":"%s","conn":"%s","dbNum":"%s","password":"%s"}`,
+		"redis_DeviceReal", conf.Redis_address, conf.Redis_dbNum, conf.Redis_password)
+	fmt.Println(deviceRealConfig)
+	var err error
+	redisCache_DeviceReal, err = cache.NewCache("redis", deviceRealConfig)
+	if err != nil || redisCache_DeviceReal == nil {
+		errMsg := "failed to init redis api"
+		logs.Error(errMsg, err)
+		panic(errMsg)
+	}
+}
+
+// ---------------- Redis -------------------
+func Redis_DeviceReal_Set(sn string, num int) (err error) {
+	err = redisCache_DeviceReal.Put(sn, num, 1*time.Minute)
+	if err != nil {
+		logs.Error("redis_DeviceReal_Set", "set key:", sn, ",value:", num, err)
+	}
+	return
+}
+
+func Redis_DeviceReal_Get(key string) (r int, is bool) {
+	if redisCache_DeviceReal.IsExist(key) {
+		//println("找到key:",key)
+		v := redisCache_DeviceReal.Get(key)
+
+		err := json.Unmarshal(v.([]byte), &r)
+		if err != nil {
+			logs.Error(lib.FuncName(), err)
+			return r, false
+		}
+		return r, true
+	}
+	//println("没有 找到key:",key)
+	return r, false
+}
+
+func Redis_DeviceReal_DelK(key string) (err error) {
+	err = redisCache_DeviceReal.Delete(key)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+	return
+}
+
+func Redis_DeviceRealWait_Set(key string) (err error) {
+	err = redisCache_DeviceReal.Put(key, "", 10*time.Second)
+	if err != nil {
+		logs.Error("Redis_DeviceRealWait_Set", "set key:", key, err)
+	}
+	return
+}
+
+func Redis_DeviceRealWait_IsExist(key string) (is bool) {
+	return redisCache_DeviceReal.IsExist(key)
+}

+ 36 - 9
models/Device/DeviceSensor.go

@@ -191,8 +191,11 @@ func Redis_DeviceSensor_DelK(r DeviceSensor) (err error) {
 // ---------------- 特殊方法 -------------------
 
 func DeviceSensorToDeviceSensor_R(DeviceSensor_ DeviceSensor) (DeviceSensor_r DeviceSensor_R) {
+
+	device, _ := Read_Device_ByT_sn(DeviceSensor_.T_sn)
+
 	//lib.DeviceRealSnMap[DeviceSensor_.T_sn] = 3 // 连续请求 实时数据
-	lib.DeviceRealSnMap.Store(DeviceSensor_.T_sn, 3) // 连续请求 实时数据
+	lib.DeviceRealSnMap.Store(DeviceSensor_.T_sn+"|"+device.T_mqttid, 0) // 连续请求 实时数据
 
 	DeviceSensor_r.T_sn = DeviceSensor_.T_sn
 	DeviceSensor_r.T_id = DeviceSensor_.T_id
@@ -223,7 +226,6 @@ func DeviceSensorToDeviceSensor_R(DeviceSensor_ DeviceSensor) (DeviceSensor_r De
 	DeviceData := Read_DeviceData(DeviceSensor_.T_sn, DeviceSensor_.T_id)
 	//DeviceData, _ := RedisDeviceData_Get(DeviceSensor_.T_sn + "|" + strconv.Itoa(DeviceSensor_.T_id))
 
-	device, _ := Read_Device_ByT_sn(DeviceSensor_.T_sn)
 	DeviceSensor_r.T_DeviceSensorData = DeviceDataToDeviceData_R2(device, DeviceSensor_r.T_DeviceSensorParameter, DeviceData)
 
 	deviceSensorType := Read_DeviceSensorType_Get(DeviceSensor_.T_type)
@@ -232,8 +234,10 @@ func DeviceSensorToDeviceSensor_R(DeviceSensor_ DeviceSensor) (DeviceSensor_r De
 }
 
 func DeviceSensorToDeviceSensor_Applet(DeviceSensor_ DeviceSensor) (DeviceSensor_r DeviceSensor_Applet) {
+	device, _ := Read_Device_ByT_sn(DeviceSensor_.T_sn)
+
 	//lib.DeviceRealSnMap[DeviceSensor_.T_sn] = 3 // 连续请求 实时数据
-	lib.DeviceRealSnMap.Store(DeviceSensor_.T_sn, 3) // 连续请求 实时数据
+	lib.DeviceRealSnMap.Store(DeviceSensor_.T_sn+"|"+device.T_mqttid, 0) // 连续请求 实时数据
 
 	DeviceSensor_r.T_sn = DeviceSensor_.T_sn
 	DeviceSensor_r.T_id = DeviceSensor_.T_id
@@ -261,7 +265,6 @@ func DeviceSensorToDeviceSensor_Applet(DeviceSensor_ DeviceSensor) (DeviceSensor
 	// 最新数据
 	DeviceData := Read_DeviceData(DeviceSensor_.T_sn, DeviceSensor_.T_id)
 
-	device, _ := Read_Device_ByT_sn(DeviceSensor_.T_sn)
 	DeviceSensor_r.T_DeviceSensorData = DeviceDataToDeviceData_R2(device, DeviceSensor_r.T_DeviceSensorParameter, DeviceData)
 
 	deviceSensorType := Read_DeviceSensorType_Get(DeviceSensor_.T_type)
@@ -804,7 +807,7 @@ func Read_DeviceSensorManageList(admin_r *Account.Admin, T_pid int, T_name strin
 	// -------------
 	sql := "SELECT COUNT(ds.ID) FROM " + "device_sensor ds " +
 		"LEFT JOIN ( SELECT t_sn AS tsn,t_id AS tid,t_en,t_free " +
-		"FROM device_sensor_parameter WHERE id IN (SELECT MAX(id) FROM device_sensor_parameter GROUP BY t_sn,t_id)) AS dsp " +
+		"FROM device_sensor_parameter WHERE id IN (SELECT MAX(id) FROM device_sensor_parameter WHERE t__state=1 GROUP BY t_sn,t_id)) AS dsp " +
 		"ON ds.t_sn = dsp.tsn AND ds.t_id = dsp.tid" + " WHERE " + sql_WHERE
 	fmt.Println(sql)
 	_, err := o.Raw(sql).ValuesList(&maps_z)
@@ -818,7 +821,7 @@ func Read_DeviceSensorManageList(admin_r *Account.Admin, T_pid int, T_name strin
 	//fmt.Println("maps_z;",maps_z[0][0])
 	sql = "SELECT * FROM device_sensor ds " +
 		"LEFT JOIN ( SELECT t_sn AS tsn,t_id AS tid,t_en,t_free,t__tlower,t__tupper,t__r_hlower,t__r_hupper,t_enprel,t_tprel,t_tpreu,t_hprel,t_hpreu " +
-		"FROM device_sensor_parameter WHERE id IN (SELECT MAX(id) FROM device_sensor_parameter GROUP BY t_sn,t_id)) AS dsp " +
+		"FROM device_sensor_parameter WHERE id IN (SELECT MAX(id) FROM device_sensor_parameter WHERE t__state=1 GROUP BY t_sn,t_id)) AS dsp " +
 		"ON ds.t_sn = dsp.tsn AND ds.t_id = dsp.tid " +
 		"WHERE " + sql_WHERE + sql_ORDER
 
@@ -871,7 +874,9 @@ func Read_DeviceSensor_List_For_Data(T_pid int, T_name string, T_Class_id, T_typ
 	if len(T_name) == 16 {
 		cond1 = cond1.And("T_sn", T_name)
 	} else if len(T_name) > 0 {
-		cond1 = cond1.And("T_name__icontains", T_name).And("T_datashow", 1)
+		cond1 = cond1.AndCond(cond.Or("T_name__icontains", T_name).Or("T_sn__icontains", T_name)).And("T_datashow", 1)
+	} else {
+		cond1 = cond1.And("T_datashow", 1)
 	}
 
 	if T_MapShow == 1 {
@@ -963,7 +968,7 @@ func Read_DeviceSensor_List_For_Applet(T_pid int, T_name, T_online string, T_Rea
 	if len(T_name) == 16 {
 		cond1 = cond1.And("T_sn", T_name)
 	} else if len(T_name) > 0 {
-		cond1 = cond1.And("T_name__icontains", T_name).And("T_datashow", 1)
+		cond1 = cond1.AndCond(cond.Or("T_name__icontains", T_name).Or("T_sn__icontains", T_name)).And("T_datashow", 1)
 	} else {
 		cond1 = cond1.And("T_datashow", 1)
 	}
@@ -1001,7 +1006,7 @@ func Read_DeviceSensor_List_For_Applet(T_pid int, T_name, T_online string, T_Rea
 	return DeviceSensor_r, cnt
 }
 
-// 数据展示菜单下 传感器参数列表
+// 小程序-传感器类型
 func Read_DeviceSensor_T_sn_ByT_type(T_pid, T_type int) (lists orm2.ParamsList, err error) {
 
 	o := orm.NewOrm()
@@ -1017,3 +1022,25 @@ func Read_DeviceSensor_T_sn_ByT_type(T_pid, T_type int) (lists orm2.ParamsList,
 
 	return pl_lists, nil
 }
+
+func Read_DeviceSensorCount_ByT_pids(T_pids []int) (cnt int64) {
+
+	o := orm.NewOrm()
+	// 也可以直接使用 Model 结构体作为表名
+
+	qs := o.QueryTable(new(DeviceSensor))
+	cond := orm.NewCondition()
+	cond1 := cond.And("T_pid__in", T_pids).And("T_State", 1)
+
+	//// 不是内部权限(T_pid>0),T_State=1 0 屏蔽  1 正常
+	//cond1 = cond1.And("T_State", 1)
+	//// 0 屏蔽数据展示  1 正常数据展示
+	//cond1 = cond1.And("T_datashow", 1)
+
+	cnt, err := qs.SetCond((*orm2.Condition)(cond1)).Count()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+
+	return cnt
+}

+ 4 - 0
models/Device/DeviceSensorParameter.go

@@ -37,6 +37,7 @@ type DeviceSensorParameter struct {
 	T_hpreu  float32 `orm:"size(200);null"`     //  温度预警上限
 
 	T_speed int `orm:"size(5);null"`       // 传感器采样率   s(1~240) 默认:15 *
+	T_sense int `orm:"size(5);"`           // 传感器灵敏度   s(0~10) 默认:5
 	T_en    int `orm:"size(2);default(1)"` // en:是否启用传感器,   0 停用  1 启用
 	T_free  int `orm:"size(2);default(1)"` // free:监测点是否为闲置状态(空库,只监测不报警)    0 正常   1 空库
 
@@ -65,6 +66,7 @@ type DeviceSensorParameter_R struct {
 	T_hpreu  float32 //  温度预警上限
 
 	T_speed int // 传感器采样率   s(1~240) 默认:15 *
+	T_sense int  // 传感器灵敏度   s(0~10) 默认:5
 	T_en    int // en:是否启用传感器,
 	T_free  int // free:监测点是否为闲置状态(空库,只监测不报警)
 
@@ -97,6 +99,7 @@ func DeviceSensorParameterToDeviceSensorParameter_R(r DeviceSensorParameter) (t
 	t.T_hprel = r.T_hprel
 	t.T_hpreu = r.T_hpreu
 	t.T_speed = r.T_speed
+	t.T_sense = r.T_sense
 	t.T_en = r.T_en
 	t.T_free = r.T_free
 	t.T_time.Time = r.CreateTime
@@ -135,6 +138,7 @@ func DeviceSensorParameter_T_text(r DeviceSensorParameter) string {
 	s += fmt.Sprintf(" 温度预警上限:%.2f", r.T_hpreu)
 
 	s += fmt.Sprintf(" 传感器采样率:%d", r.T_speed)
+	s += fmt.Sprintf(" 传感器灵敏度:%d", r.T_sense)
 	s += fmt.Sprintf(" 是否启用传感器:%d", r.T_en)
 	s += fmt.Sprintf(" 监测点是否为闲置状态:%d", r.T_free)
 

+ 35 - 20
models/Warning/Warning.go

@@ -225,7 +225,7 @@ func Update_Warning_Backups(r Warning, T_year string, T_month string) bool {
 }
 
 // 获取列表
-func Read_Warning_List(T_pid int, T_tp, T_name string, T_handle int, Time_start_ string, Time_end_ string, page int, page_z int) (r []Warning_R, cnt int64) {
+func Read_Warning_List(T_pid int, tpList []string, T_name string, T_handle int, Time_start_ string, Time_end_ string, page int, page_z int) (r []Warning_R, cnt int64) {
 	o := orm.NewOrm()
 	// 也可以直接使用 Model 结构体作为表名
 	var map_r []Warning
@@ -242,12 +242,10 @@ func Read_Warning_List(T_pid int, T_tp, T_name string, T_handle int, Time_start_
 	cond1 := cond.And("T_State__gt", 0)
 
 	if T_pid > 0 {
-		cond1 = cond.AndCond(cond1).And("T_pid", T_pid)
+		cond1 = cond1.And("T_pid", T_pid)
 	}
-	if len(T_tp) > 0 {
-		list := lib.SplitStringIds(T_tp, "T")
-		cond1 = cond1.And("T_tp__in", list)
-
+	if len(tpList) > 0 {
+		cond1 = cond1.And("T_tp__in", tpList)
 	}
 	if len(T_name) > 0 {
 		cond1 = cond1.AndCond(cond.Or("T_sn__icontains", T_name).Or("T_D_name__icontains", T_name).Or("T_id__icontains", T_name).Or("T_DS_name", T_name))
@@ -295,7 +293,7 @@ func Read_Warning_List(T_pid int, T_tp, T_name string, T_handle int, Time_start_
 }
 
 // 管理员报警列表
-func Read_Admin_Warning_List(T_pids, T_tp, T_name string, T_handle int, Time_start_ string, Time_end_ string, page int, page_z int) (r []Warning_R, cnt int64) {
+func Read_Admin_Warning_List(T_pids string, T_tp []string, T_name string, T_handle int, Time_start_ string, Time_end_ string, page int, page_z int) (r []Warning_R, cnt int64) {
 
 	if len(T_pids) == 0 {
 		return r, cnt
@@ -319,13 +317,12 @@ func Read_Admin_Warning_List(T_pids, T_tp, T_name string, T_handle int, Time_sta
 
 	cond1 := cond.And("T_State__gt", 0)
 
-	if T_pids != "*" {
+	if T_pids != "*" && len(T_pids) > 0 {
 		list := lib.SplitStringIds(T_pids, "P")
 		cond1 = cond1.And("T_pid__in", list)
 	}
 	if len(T_tp) > 0 {
-		list := lib.SplitStringIds(T_tp, "T")
-		cond1 = cond1.And("T_tp__in", list)
+		cond1 = cond1.And("T_tp__in", T_tp)
 
 	}
 	if len(T_name) > 0 {
@@ -365,7 +362,7 @@ func Read_Admin_Warning_List(T_pids, T_tp, T_name string, T_handle int, Time_sta
 }
 
 // 获取列表备份
-func Read_Warning_Backups(T_pid int, T_year string, T_month string, T_tp, T_name string, T_handle int, Time_start_ string, Time_end_ string, page int, page_z int) (r []Warning_R, cnt int64) {
+func Read_Warning_Backups(T_pid int, T_year string, T_month string, tpList []string, T_name string, T_handle int, Time_start_ string, Time_end_ string, page int, page_z int) (r []Warning_R, cnt int64) {
 
 	o := orm.NewOrm()
 	var maps []Warning
@@ -392,9 +389,9 @@ func Read_Warning_Backups(T_pid int, T_year string, T_month string, T_tp, T_name
 		sql_WHERE += " AND t_pid = " + strconv.Itoa(T_pid)
 	}
 
-	if len(T_tp) > 0 {
-		list := lib.SplitStringToDotStr(T_tp, "T")
-		sql_WHERE += fmt.Sprintf(" AND t_tp in (%s)", list)
+	if len(tpList) > 0 {
+		tp := lib.StringListToDotStr(tpList)
+		sql_WHERE += fmt.Sprintf(" AND t_tp in (%s)", tp)
 
 	}
 	if len(T_name) > 0 {
@@ -458,7 +455,7 @@ func Read_Warning_Backups(T_pid int, T_year string, T_month string, T_tp, T_name
 }
 
 // 获取管理员列表备份
-func Read_Admin_Warning_Backups(T_pids string, T_year string, T_month string, T_tp, T_name string, T_handle int, Time_start_ string, Time_end_ string, page int, page_z int) (r []Warning_R, cnt int64) {
+func Read_Admin_Warning_Backups(T_pids string, T_year string, T_month string, T_tp []string, T_name string, T_handle int, Time_start_ string, Time_end_ string, page int, page_z int) (r []Warning_R, cnt int64) {
 
 	if len(T_pids) == 0 {
 		return r, cnt
@@ -491,8 +488,8 @@ func Read_Admin_Warning_Backups(T_pids string, T_year string, T_month string, T_
 	}
 
 	if len(T_tp) > 0 {
-		list := lib.SplitStringToDotStr(T_tp, "T")
-		sql_WHERE += fmt.Sprintf(" AND t_tp in (%s)", list)
+		tp := lib.StringListToDotStr(T_tp)
+		sql_WHERE += fmt.Sprintf(" AND t_tp in (%s)", tp)
 
 	}
 	if len(T_name) > 0 {
@@ -562,11 +559,12 @@ func Read_Warning_ALL_T_State_Count(T_pid, T_handle int, T_Warning string, Is_To
 	cond1 := cond.And("T_State__gt", 0).And("T_pid", T_pid)
 
 	if Is_Today {
-		today := time.Now().Format("2006-01-02") + " 00:00:00"
-		cond1 = cond.And("CreateTime__gte", today)
+		startTime := time.Now().Format("2006-01-02") + " 00:00:00"
+		endTime := time.Now().Format("2006-01-02") + " 23:59:59"
+		cond1 = cond1.And("T_Ut__gte", startTime).And("T_Ut__lte", endTime)
 	}
 
-	if T_Warning != "*" {
+	if len(T_Warning) > 0 && T_Warning != "*" {
 		list := lib.SplitStringIds(T_Warning, "W")
 		cond1 = cond1.And("T_tp__in", list)
 	}
@@ -699,3 +697,20 @@ func Read_Warning_List_By_DS_T_type(T_pid, DS_T_type int, T_name string, page in
 	return r, cnt
 
 }
+
+// 获取当天设备报警总数
+func Read_WarningCount_byDay(T_pids []int) (cnt int64) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(Warning))
+	cond := orm.NewCondition()
+	yesterday := time.Now().AddDate(0, 0, -1).Format("2006-01-02")
+	cond = cond.And("T_State__gt", 0).And("T_pid__in", T_pids).And("T_tp__in", RateType).And("CreateTime__gte", yesterday+" 00:00:00").And("CreateTime__lte", yesterday+" 23:59:59")
+
+	cnt, err := qs.SetCond((*orm2.Condition)(cond)).Count()
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+
+	return cnt
+
+}

+ 124 - 0
models/Warning/WarningRate.go

@@ -0,0 +1,124 @@
+package Warning
+
+import (
+	"Cold_Api/controllers/lib"
+	"Cold_Api/logs"
+	"github.com/beego/beego/v2/adapter/orm"
+	orm2 "github.com/beego/beego/v2/client/orm"
+	"time"
+)
+
+var (
+	WarningRateDay   = "Day"
+	WarningRateMonth = "Month"
+)
+
+// 报警率
+type WarningRate struct {
+	Id            int     `orm:"column(ID);size(11);auto;pk"`
+	T_uuid        string  `orm:"index;size(64);null"`    // 用户uuid
+	T_date        string  `orm:"size(64);null"`          // 记薪日期,2023-03-01
+	T_device_num  int64   `orm:"size(20);default(0)"`    // 探头数量
+	T_warning_num int64   `orm:"size(20);default(0)"`    // 报警数量
+	T_type        string  `orm:"size(20);default(0)"`    // 类型 Day-每日 Month-每月
+	T_rate        float32 `orm:"digits(12);decimals(2)"` // 报警率
+
+	CreateTime time.Time `orm:"column(create_time);type(timestamp);null;auto_now_add"` //auto_now_add 第一次保存时才设置时间
+	UpdateTime time.Time `orm:"column(update_time);type(timestamp);null;auto_now"`     //auto_now 每次 model 保存时都会对时间自动更新
+}
+
+type WarningRate_R struct {
+	Id            int
+	T_uuid        string  // 用户uuid
+	T_date        string  // 记薪日期,2023-03-01
+	T_device_num  int64   // 探头数量
+	T_warning_num int64   // 报警数量
+	T_rate        float32 // 报警率
+}
+type WarningRate_User struct {
+	T_uuid string // 用户uuid
+	T_name string // 用户名
+}
+
+func WarningRateToWarningRate_R(t WarningRate) (r WarningRate_R) {
+	r.Id = t.Id
+	r.T_uuid = t.T_uuid
+	r.T_date = t.T_date
+	r.T_device_num = t.T_device_num
+	r.T_warning_num = t.T_warning_num
+	r.T_rate = t.T_rate
+	return r
+}
+
+func (t *WarningRate) TableName() string {
+	return "warning_rate"
+}
+
+func init() {
+	//注册模型
+	orm.RegisterModel(new(WarningRate))
+}
+
+func Add_WarningRate(m WarningRate) (id int64, err error) {
+	o := orm.NewOrm()
+	id, err = o.Insert(&m)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+	return id, err
+}
+
+func Read_WarningRate_List(T_uuid, T_type string, startTime, endTime string) (r []WarningRate_R) {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(WarningRate))
+	cond := orm.NewCondition()
+	var maps []WarningRate
+
+	cond = cond.And("T_uuid", T_uuid).And("T_type", T_type)
+	if len(startTime) > 0 {
+		cond = cond.And("T_date__gte", startTime)
+	}
+	if len(endTime) > 0 {
+		cond = cond.And("T_date__lte", endTime)
+	}
+
+	_, err := qs.SetCond((*orm2.Condition)(cond)).OrderBy("T_date").All(&maps)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+
+	for _, v := range maps {
+		r = append(r, WarningRateToWarningRate_R(v))
+	}
+
+	return r
+}
+
+// 获取每月平均值
+func Read_WarningRateAvg_Month(startTime, endTime string) (r []WarningRate_R) {
+	o := orm.NewOrm()
+
+	sql := "SELECT t_uuid, ROUND(avg(t_device_num)) as t_device_num ,ROUND(avg(t_warning_num)) as t_warning_num FROM warning_rate WHERE `t_type` = '" + WarningRateDay + "' AND T_date >= '" + startTime + "' AND T_date <= '" + endTime + "'" +
+		" GROUP BY t_uuid"
+
+	_, err := o.Raw(sql).QueryRows(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+
+	return r
+}
+
+// 获取昨天的设备报警率
+func Read_WarningRate_Yesterday(T_uuid string) float32 {
+	o := orm.NewOrm()
+	qs := o.QueryTable(new(WarningRate))
+	var r WarningRate
+	T_date := time.Now().AddDate(0, -1, 0).Format("2006-01-02")
+	err := qs.Filter("T_uuid", T_uuid).Filter("T_date", T_date).Filter("T_type", WarningRateDay).One(&r)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+	}
+	return r.T_rate
+}

+ 103 - 1
models/Warning/WarningSand.go

@@ -1,12 +1,15 @@
 package Warning
 
 import (
+	"Cold_Api/controllers/lib"
+	"Cold_Api/logs"
 	"Cold_Api/models/Account"
 	"fmt"
-	"github.com/beego/beego/v2/adapter/orm"
+	"github.com/beego/beego/v2/client/orm"
 	orm2 "github.com/beego/beego/v2/client/orm"
 	_ "github.com/go-sql-driver/mysql"
 	"strconv"
+	"strings"
 	"time"
 )
 
@@ -33,6 +36,33 @@ func init() {
 	orm.RegisterModel(new(WarningSand))
 }
 
+type WarningSand_R struct {
+	Id         int
+	T_pid      int // Account.Company 绑定公司, -1:未知   0:管理员  >0 :绑定公司
+	T_tp       int // 报警类型   ->WarningList
+	T_tp_name  string
+	T_Notice   string   // 18888888888
+	T_type     int      // 1 短信   2 电话
+	T_Remark   []string // 备注
+	CreateTime string   //auto_now_add 第一次保存时才设置时间
+}
+
+func WarningSandToWarningSand_R(t WarningSand) (r WarningSand_R) {
+	r.Id = t.Id
+	r.T_pid = t.T_pid
+	r.T_tp = t.T_tp
+	r.T_tp_name = Read_WarningType_Get(t.T_tp)
+	r.T_Notice = t.T_Notice
+	r.T_type = t.T_type
+	//r.T_Remark = t.T_Remark
+	if len(t.T_Remark) > 0 {
+		r.T_Remark = strings.Split(strings.TrimRight(t.T_Remark, "\n"), "\n")
+	}
+
+	r.CreateTime = t.CreateTime.Format("2006-01-02 15:04:05")
+	return r
+}
+
 // ---------------- 特殊方法 -------------------
 
 // 获取 ById
@@ -140,3 +170,75 @@ func Read_WarningSand_ALL_T_Bind_TIME_Count(user_ Account.Admin, T_sn string) (c
 	key, _ := strconv.Atoi(maps_z[0][0].(string))
 	return key
 }
+
+// 获取 发送统计数量
+func Get_WarningSandNum(TABLE_name string, Pid, Ntype int, StartTine, EndTime string) int {
+	o := orm.NewOrm()
+	var maps []orm.Params
+	num, err := o.Raw("SELECT count(ID) AS count FROM " + TABLE_name + " WHERE `t_pid` = " + strconv.Itoa(Pid) + " AND `t__ntype` = " + strconv.Itoa(Ntype) + " AND `create_time` >= '" + StartTine + "' AND `create_time` <= '" + EndTime + "'").Values(&maps)
+	if err == nil && num > 0 {
+		intx, _ := strconv.Atoi(lib.To_string(maps[0]["count"]))
+		logs.Println("Get_WarningSandNum:", TABLE_name, Pid, Ntype, StartTine, EndTime, intx) // slene
+		return intx
+	}
+	logs.Error("执行错误!!!", "Get_WarningSandNum:", TABLE_name, Pid, Ntype, StartTine, EndTime, maps) // slene
+	return 0
+}
+
+// 获取本月通知数量
+func Get_WarningSandNum_CurrentMonth(T_pid, Ntype int) int {
+	o := orm.NewOrm()
+	var maps []orm.Params
+	tableName := fmt.Sprintf("warning_sand_%s", time.Now().Format("200601"))
+	_, err := o.Raw("SELECT count(ID) AS count FROM " + tableName + " WHERE `t_pid` = " + strconv.Itoa(T_pid) + " AND `t__ntype` = " + strconv.Itoa(Ntype)).Values(&maps)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return 0
+	}
+	intx, _ := strconv.Atoi(lib.To_string(maps[0]["count"]))
+	return intx
+}
+
+func Read_WarningSand_List(T_pid, Ntype int, page int, page_z int) (r []WarningSand_R, cnt int64) {
+	o := orm.NewOrm()
+
+	var offset int
+	if page <= 1 {
+		offset = 0
+	} else {
+		offset = (page - 1) * page_z
+	}
+	var maps []WarningSand
+	var maps_z []orm2.ParamsList
+
+	tableName := fmt.Sprintf("warning_sand_%s", time.Now().Format("200601"))
+
+	sql := "SELECT count(ID) FROM " + tableName + " WHERE `t_pid` = " + strconv.Itoa(T_pid) + " AND `t__ntype` = " + strconv.Itoa(Ntype)
+
+	_, err := o.Raw(sql).ValuesList(&maps_z)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return r, 0
+	}
+	if len(maps_z) == 0 {
+		return r, 0
+	}
+	sql = "SELECT * FROM " + tableName + " WHERE `t_pid` = " + strconv.Itoa(T_pid) + " AND `t__ntype` = " + strconv.Itoa(Ntype)
+
+	if page_z != 9999 {
+		sql = sql + " LIMIT " + strconv.Itoa(offset) + "," + strconv.Itoa(page_z)
+	}
+	_, err = o.Raw(sql).QueryRows(&maps)
+	if err != nil {
+		logs.Error(lib.FuncName(), err)
+		return
+	}
+
+	key, _ := strconv.ParseInt(maps_z[0][0].(string), 10, 64)
+
+	for _, v := range maps {
+		r = append(r, WarningSandToWarningSand_R(v))
+	}
+
+	return r, key
+}

+ 5 - 1
models/Warning/WarningType.go

@@ -21,6 +21,7 @@ type WarningType struct {
 }
 
 var DeviceLogType = [3]int{101, 102, 103}
+var RateType = [8]int{1, 2, 3, 4, 6, 7, 8, 9}
 
 //3
 //tp   报警类型
@@ -139,6 +140,10 @@ func Read_WarningType_All() (r []WarningType_) {
 
 // 报警列表 返回权限拥有的报警类型列表
 func Read_WarningType_Power_All(T_warning string) (r []WarningType_) {
+	if len(T_warning) == 0 {
+		return r
+	}
+
 	o := orm.NewOrm()
 	var maps []WarningType
 	qs := o.QueryTable(new(WarningType))
@@ -204,7 +209,6 @@ func Read_WarningType_All_Maps() {
 
 }
 func Read_WarningType_Get(id int) string {
-	// 有先加入 给全部人发消息
 	v, ok := WarningType_list.Load(id) /*如果确定是真实的,则存在,否则不存在 */
 	if ok {
 		return v.(string)

+ 1 - 0
routers/Device.go

@@ -37,6 +37,7 @@ func init() {
 			beego.NSRouter("/DeviceNoticeBind_List", &controllers.DeviceController{}, "*:DeviceNoticeBind_List"), // 设备传感器绑定的报警策略列表
 
 			beego.NSRouter("/Applet_Stat_View2", &controllers.DeviceController{}, "*:Device_Applet_Stat"), // 设备统计 - 小程序
+			beego.NSRouter("/Applet_Get", &controllers.DeviceController{}, "*:Device_Applet_Get"),         // 获取设备 - 小程序
 		),
 
 		// 传感器

+ 12 - 7
routers/User.go

@@ -46,15 +46,20 @@ func init() {
 		// 菜单
 		beego.NSRouter("/Menu/List", &controllers.UserController{}, "*:User_Menu_List"),    // 用户权限绑定的菜单
 		beego.NSRouter("/Menu/List_All", &controllers.UserController{}, "*:Menu_List_All"), // 权限管理-菜单列表
+		beego.NSRouter("/Menu/Excel", &controllers.UserController{}, "*:Menu_Excel"),       // 导出菜单列表
 
 		// 公司管理
-		beego.NSRouter("/Company/Tree", &controllers.UserController{}, "*:Company_Tree"),   // 公司列表
-		beego.NSRouter("/Company/List", &controllers.UserController{}, "*:Company_List"),   // 所有公司列表
-		beego.NSRouter("/Company/Add", &controllers.UserController{}, "*:Company_Add"),     // 添加公司
-		beego.NSRouter("/Company/Get", &controllers.UserController{}, "*:Company_Get"),     // 添加公司
-		beego.NSRouter("/Company/Edit", &controllers.UserController{}, "*:Company_Edit"),   // 修改公司
-		beego.NSRouter("/Company/Del", &controllers.UserController{}, "*:Company_Del"),     // 删除公司
-		beego.NSRouter("/Company/Entry", &controllers.UserController{}, "*:Company_Entry"), // 删除公司
+		beego.NSRouter("/Company/Tree", &controllers.UserController{}, "*:Company_Tree"),               // 公司列表
+		beego.NSRouter("/Company/List", &controllers.UserController{}, "*:Company_List"),               // 所有公司列表
+		beego.NSRouter("/Company/Add", &controllers.UserController{}, "*:Company_Add"),                 // 添加公司
+		beego.NSRouter("/Company/Get", &controllers.UserController{}, "*:Company_Get"),                 // 添加公司
+		beego.NSRouter("/Company/Edit", &controllers.UserController{}, "*:Company_Edit"),               // 修改公司
+		beego.NSRouter("/Company/Del", &controllers.UserController{}, "*:Company_Del"),                 // 删除公司
+		beego.NSRouter("/Company/Entry", &controllers.UserController{}, "*:Company_Entry"),             // 删除公司
+		beego.NSRouter("/Company/Bill_Excel", &controllers.UserController{}, "*:CompanyBill_Excel"),    // 公司账单
+		beego.NSRouter("/Company/DigitalTwin", &controllers.UserController{}, "*:Company_DigitalTwin"), // 数字孪生
+		beego.NSRouter("/Company/Pay", &controllers.UserController{}, "*:Company_Pay"),                 // 充值
+		beego.NSRouter("/Company/Warning", &controllers.UserController{}, "*:Company_Warning"),         // 报警统计
 
 	)
 

+ 8 - 0
routers/Warning.go

@@ -24,6 +24,14 @@ func init() {
 			beego.NSRouter("/List_All", &controllers.DeviceController{}, "*:WarningType_List_All"),         // 添加权限-告警类型列表
 			beego.NSRouter("/Power_List", &controllers.DeviceController{}, "*:WarningType_Power_List_All"), // 报警搜索-告警类型列表
 		),
+		// 报警发送
+		beego.NSNamespace("/WarningSend",
+			beego.NSRouter("/List", &controllers.DeviceController{}, "*:Read_WarningSend_List"), // 报警发送列表
+		),
+		// 内部用户设备报警率
+		beego.NSNamespace("/WarningRate",
+			beego.NSRouter("/List", &controllers.DeviceController{}, "*:Read_WarningRate_List"), // 内部用户设备报警率列表
+		),
 	)
 
 	beego.AddNamespace(ns)