Browse Source

智慧隧道

xu 8 tháng trước cách đây
mục cha
commit
e32915e89c

+ 16 - 0
server/api/v1/admin/tunnel.go

@@ -85,6 +85,22 @@ func (ta *TunnelApi) UpdateTunnel(c *gin.Context) {
 	response.OkWithMessage("更新隧道成功", c)
 }
 
+func (ta *TunnelApi) UpdateTactics(c *gin.Context) {
+	var tactics request.EditTactics
+	if err := c.ShouldBindJSON(&tactics); err != nil {
+		logger.Get().Error("UpdateTactics ---- " + err.Error())
+		response.FailWithMessage("参数解析失败", c)
+		return
+	}
+	err := tunnelService.UpdateTactics(tactics.Sn, tactics.Tactics)
+	if err != nil {
+		logger.Get().Error("UpdateTactics ---- " + err.Error())
+		response.FailWithMessage("更新隧道策略失败", c)
+		return
+	}
+	response.OkWithMessage("更新隧道策略成功", c)
+}
+
 func (ta *TunnelApi) UpdateTunnelsRegion(c *gin.Context) {
 	var info request.RegionTunnelsId
 	if err := c.ShouldBindJSON(&info); err != nil {

+ 20 - 0
server/dao/env_data.go

@@ -0,0 +1,20 @@
+package dao
+
+import "server/global"
+
+type EnvData struct {
+	global.GVA_MODEL
+	Sn          string  `json:"sn" gorm:"comment:编号"`
+	TunnelSn    string  `json:"tunnelSn" gorm:"comment:隧道序号"`
+	Temperature float64 `json:"temperature" gorm:"comment:温度"`
+	Humidity    float64 `json:"humidity" gorm:"comment:湿度"`
+	Illuminance int64   `json:"illuminance" gorm:"comment:光照度"`
+}
+
+func (EnvData) TableName() string {
+	return "env_data"
+}
+
+func (ed EnvData) CreateEnvData() error {
+	return global.GVA_DB.Create(&ed).Error
+}

+ 20 - 0
server/dao/optical_data.go

@@ -0,0 +1,20 @@
+package dao
+
+import (
+	"server/global"
+)
+
+type OpticalData struct {
+	global.GVA_MODEL
+	Sn          string `json:"sn" gorm:"comment:编号"`
+	TunnelSn    string `json:"tunnelSn" gorm:"comment:隧道序号"`
+	Illuminance int64  `json:"illuminance" gorm:"comment:光照度"`
+}
+
+func (OpticalData) TableName() string {
+	return "optical_data"
+}
+
+func (od OpticalData) CreateOpticalData() error {
+	return global.GVA_DB.Create(&od).Error
+}

+ 27 - 12
server/dao/tunnel.go

@@ -7,15 +7,17 @@ import (
 
 type Tunnel struct {
 	global.GVA_MODEL
-	TunnelSn   string     `json:"tunnelSn" gorm:"comment:隧道序号"`
-	Name       string     `json:"name" gorm:"comment:名称"`
-	Tactics    int        `json:"tactics" gorm:"comment:策略"`
-	RegionId   int        `json:"regionId" gorm:"column:region_id"`
-	Region     Region     `json:"region" gorm:"foreignKey:RegionId"` // 关系
-	TimeId     int        `json:"timeId" gorm:"comment:定时id"`
-	TunnelTime TunnelTime `json:"tunnelTime" gorm:"foreignKey:TimeId"`
-	Users      []SysUser  `json:"users" gorm:"many2many:user_tunnel"`
-	Devices    []Device   `json:"devices" gorm:"foreignKey:TunnelId"`
+	TunnelSn    string        `json:"tunnelSn" gorm:"comment:隧道序号"`
+	Name        string        `json:"name" gorm:"comment:名称"`
+	Tactics     int           `json:"tactics" gorm:"comment:策略"`
+	RegionId    int           `json:"regionId" gorm:"column:region_id"`
+	Region      Region        `json:"region" gorm:"foreignKey:RegionId"` // 关系
+	TimeId      int           `json:"timeId" gorm:"comment:定时id"`
+	TunnelTime  TunnelTime    `json:"tunnelTime" gorm:"foreignKey:TimeId"`
+	Users       []SysUser     `json:"users" gorm:"many2many:user_tunnel"`
+	Devices     []Device      `json:"devices" gorm:"foreignKey:TunnelId"`
+	EnvData     []EnvData     `json:"envData" gorm:"foreignKey:TunnelSn;references:TunnelSn"`
+	OpticalData []OpticalData `json:"opticalData" gorm:"foreignKey:Sn;references:TunnelSn"`
 }
 
 func (Tunnel) TableName() string {
@@ -23,11 +25,11 @@ func (Tunnel) TableName() string {
 }
 
 func QueryAllTunnels() (tunnels []Tunnel, err error) {
-	err = global.GVA_DB.Find(&tunnels).Preload("Users").Preload("TunnelTime").Preload("Devices").Preload("Region").Error
+	err = global.GVA_DB.Find(&tunnels).Preload("Users").Preload("TunnelTime").Preload("Devices").Preload("Region").Preload("EnvData").Preload("OpticalData").Error
 	return tunnels, err
 }
 
-func QueryTunnelList(name string, regionId, limit, offset int) (tunnels []Tunnel, total int64, err error) {
+func QueryTunnelList(name string, regionId, userId, limit, offset int) (tunnels []Tunnel, total int64, err error) {
 	db := global.GVA_DB.Model(Tunnel{})
 
 	if name != "" {
@@ -37,11 +39,13 @@ func QueryTunnelList(name string, regionId, limit, offset int) (tunnels []Tunnel
 	if regionId != 0 {
 		db = db.Where("region_id = ?", regionId)
 	}
+	db = db.Joins("JOIN user_tunnel ON user_tunnel.tunnel_id = tunnel.id").
+		Where("user_tunnel.sys_user_id = ?", userId)
 	err = db.Count(&total).Error
 	if err != nil {
 		return
 	}
-	err = db.Limit(limit).Offset(offset).Preload("Users").Preload("TunnelTime").Preload("Devices").Preload("Region").Find(&tunnels).Error
+	err = db.Limit(limit).Offset(offset).Preload("Users").Preload("TunnelTime").Preload("Devices").Preload("Region").Preload("EnvData").Preload("OpticalData").Find(&tunnels).Error
 	return
 }
 
@@ -50,6 +54,11 @@ func QueryNoRegionTunnels() (tunnels []Tunnel, err error) {
 	return
 }
 
+func QueryTunnelByRegionId(id int) (tunnels []Tunnel, err error) {
+	err = global.GVA_DB.Where("region_id =?", id).Find(&tunnels).Error
+	return
+}
+
 func (t Tunnel) CreateTunnel() error {
 	err := global.GVA_DB.Transaction(func(tx *gorm.DB) error {
 		err := tx.Create(&t).Error
@@ -74,6 +83,10 @@ func (t Tunnel) UpdateTunnel() error {
 	return global.GVA_DB.Where("id = ?", t.ID).Updates(&t).Error
 }
 
+func UpdateTactics(sn string, tactics int) error {
+	return global.GVA_DB.Model(&Tunnel{}).Where("tunnel_sn =?", sn).Update("tactics", tactics).Error
+}
+
 func UpdateTunnelsRegion(tunnelIds []int, regionId int) error {
 	return global.GVA_DB.Model(&Tunnel{}).Where("id in (?)", tunnelIds).Update("region_id", regionId).Error
 }
@@ -81,3 +94,5 @@ func UpdateTunnelsRegion(tunnelIds []int, regionId int) error {
 func DeleteTunnel(id int) error {
 	return global.GVA_DB.Unscoped().Where("id = ?", id).Delete(&Tunnel{}).Error
 }
+
+// 权限相关

+ 2 - 0
server/initialize/gorm.go

@@ -51,6 +51,8 @@ func RegisterTables() {
 		dao.TunnelTime{},
 		dao.Device{},
 		dao.DeviceGenre{},
+		dao.EnvData{},
+		dao.OpticalData{},
 	)
 	if err != nil {
 		global.GVA_LOG.Error("register table failed", zap.Error(err))

+ 13 - 0
server/model/common/request/common.go

@@ -1,5 +1,7 @@
 package request
 
+import "server/dao"
+
 // PageInfo Paging common input parameter structure
 type PageInfo struct {
 	Page     int    `json:"page" form:"page"`         // 页码
@@ -35,6 +37,7 @@ type DeviceSearch struct {
 type TunnelSearch struct {
 	PageInfo PageInfo `json:"pageInfo" form:"pageInfo"` // 分页信息
 	Name     string   `json:"name" form:"name"`         //隧道名称
+	UserId   int      `json:"userId" form:"userId"`     //
 	RegionId int      `json:"regionId" form:"regionId"`
 }
 
@@ -43,4 +46,14 @@ type RegionTunnelsId struct {
 	RegionId  int   `json:"regionId" form:"regionId"`
 }
 
+type EditTactics struct {
+	Sn      string `json:"sn" form:"sn"`
+	Tactics int    `json:"tactics" form:"tactics"`
+}
+
+type UserTunnels struct {
+	User      dao.SysUser `json:"user" form:"user"`
+	TunnelIds []int       `json:"tunnelIds" form:"tunnelIds"`
+}
+
 type Empty struct{}

+ 1 - 0
server/router/admin/tunnel.go

@@ -16,6 +16,7 @@ func (tr *TunnelRouter) InitTunnelRouter(Router *gin.RouterGroup) {
 		tunnelRouter.POST("queryTunnelList", tunnelRouterApi.QueryTunnelList)
 		tunnelRouter.POST("createTunnel", tunnelRouterApi.CreateTunnel)
 		tunnelRouter.PUT("updateTunnel", tunnelRouterApi.UpdateTunnel)
+		tunnelRouter.PUT("updateTactics", tunnelRouterApi.UpdateTactics)
 		tunnelRouter.PUT("updateTunnelsRegion", tunnelRouterApi.UpdateTunnelsRegion)
 		tunnelRouter.PUT("updateTunnelTime", tunnelRouterApi.UpdateTunnelTime)
 		tunnelRouter.DELETE("deleteTunnel", tunnelRouterApi.DeleteTunnel)

+ 42 - 13
server/service/admin/mqtt.go

@@ -1,10 +1,12 @@
 package admin
 
 import (
+	"encoding/json"
 	"errors"
 	"fmt"
 	"regexp"
 	"runtime"
+	"server/dao"
 	"server/utils/logger"
 	"server/utils/mqtt"
 	"server/utils/protocol"
@@ -77,17 +79,43 @@ func (o *MqttHandler) Handler() interface{} {
 			continue
 		}
 
-		_, topic, err := parseTopic(m.Topic())
-		fmt.Println(m.Topic())
-		fmt.Println(m.PayloadString())
+		sn, operate, err := ParseTopic(m.Topic())
 		if err != nil {
 			//logger.Logger.Errorf("parseTopic err")
 			continue
 		}
 
-		switch topic {
-		case protocol.TopicTunnelControlAck:
-
+		switch operate {
+		case protocol.TopicGatherDataEnv:
+			var data dao.EnvData
+			if err := json.Unmarshal(m.Payload(), &data); err != nil {
+				logger.Get().Errorf("Error unmarshalling JSON: %v", err)
+				continue
+			}
+			data.TunnelSn = sn
+			if data.Sn == "" {
+				continue
+			}
+			err = data.CreateEnvData()
+			if err != nil {
+				logger.Get().Errorf("sn:%s device:%s 新增环境信息失败: %v", sn, data.Sn, err)
+				continue
+			}
+		case protocol.TopicGatherDataOpt:
+			var data dao.OpticalData
+			if err := json.Unmarshal(m.Payload(), &data); err != nil {
+				logger.Get().Errorf("Error unmarshalling JSON: %v", err)
+				continue
+			}
+			data.TunnelSn = sn
+			if data.Sn == "" {
+				continue
+			}
+			err = data.CreateOpticalData()
+			if err != nil {
+				logger.Get().Errorf("sn:%s device:%s 新增光感信息失败: %v", sn, data.Sn, err)
+				continue
+			}
 		}
 
 	}
@@ -97,17 +125,18 @@ func (o *MqttHandler) Publish(topic string, data interface{}) error {
 	return mqtt.GetMQTTMgr().Publish(topic, data, mqtt.AtLeastOnce)
 }
 
-func (o *MqttHandler) GetTopic(deviceSn, protocol string) string {
-	return fmt.Sprintf("mini/%s/%s", deviceSn, protocol)
+func (o *MqttHandler) GetTopic(sn, protocol string) string {
+	return fmt.Sprintf("smart_tunnel/%s/%s", sn, protocol)
 }
 
-// parseTopic 获取设备SN, topic
+// ParseTopic 获取设备SN, topic
 // "mini/*****/switch_control/ack"
-func parseTopic(topic string) (string, string, error) {
+func ParseTopic(topic string) (sn string, operate string, err error) {
 	strList := strings.Split(topic, "/")
-	if len(strList) < 4 {
+	sn = strList[1]
+	operate = strList[2]
+	if len(strList) != 3 {
 		return "", "", errors.New("不支持的topic")
 	}
-	topic = strings.Join(strList[2:], "/")
-	return strList[1], topic, nil
+	return
 }

+ 23 - 1
server/service/admin/tunnel.go

@@ -1,9 +1,13 @@
 package admin
 
 import (
+	"encoding/json"
 	"fmt"
 	"server/dao"
 	"server/model/common/request"
+	"server/utils/logger"
+	"server/utils/protocol"
+	"strconv"
 )
 
 type TunnelService struct{}
@@ -15,7 +19,7 @@ func (ts *TunnelService) QueryAllTunnels() ([]dao.Tunnel, error) {
 func (ts *TunnelService) QueryTunnelList(info request.TunnelSearch) ([]dao.Tunnel, int64, error) {
 	limit := info.PageInfo.PageSize
 	offset := info.PageInfo.PageSize * (info.PageInfo.Page - 1)
-	return dao.QueryTunnelList(info.Name, info.RegionId, limit, offset)
+	return dao.QueryTunnelList(info.Name, info.RegionId, info.UserId, limit, offset)
 }
 
 func (ts *TunnelService) QueryNoRegionTunnels() ([]dao.Tunnel, error) {
@@ -30,11 +34,29 @@ func (ts *TunnelService) UpdateTunnel(tunnel dao.Tunnel) error {
 	return tunnel.UpdateTunnel()
 }
 
+func (ts *TunnelService) UpdateTactics(sn string, tactics int) error {
+	fmt.Println(sn, tactics)
+	err := MqttService.Publish(MqttService.GetTopic(sn, protocol.TopicTunnelTactics), strconv.Itoa(tactics))
+	if err != nil {
+		return fmt.Errorf("error updating: %v", err)
+	}
+	return dao.UpdateTactics(sn, tactics)
+}
+
 func (ts *TunnelService) UpdateTunnelsRegion(tunnelIds []int, regionId int) error {
 	return dao.UpdateTunnelsRegion(tunnelIds, regionId)
 }
 
 func (ts *TunnelService) UpdateTunnelTime(time dao.TunnelTime) error {
+	// 使用json.Marshal函数将结构体转换为JSON字节切片
+	jsonBytes, err := json.Marshal(time)
+	if err != nil {
+		logger.Get().Fatalf("Error marshalling to JSON: %v", err)
+	}
+	err = MqttService.Publish(MqttService.GetTopic(time.TunnelSn, protocol.TopicTunnelTiming), jsonBytes)
+	if err != nil {
+		return err
+	}
 	time.IsComplete = false
 	return time.UpdateTunnelTime()
 }

+ 0 - 1
server/utils/mqtt/mqtt.go

@@ -61,7 +61,6 @@ func handle(callback MessageHandler) paho.MessageHandler {
 // NewClient creates a new client with the specified options
 func NewClient(options ClientOptions, connhandler ConnHandler) (*Client, error) {
 	pahoOptions := paho.NewClientOptions()
-
 	// brokers
 	if options.Servers != nil && len(options.Servers) > 0 {
 		for _, server := range options.Servers {

+ 5 - 1
server/utils/protocol/protocol.go

@@ -1,5 +1,9 @@
 package protocol
 
 const (
-	TopicTunnelControlAck = "tunnel_control/ack"
+	TopicGatherDataEnv = "gatherDataEnv"
+	TopicGatherDataOpt = "gatherDataOpt"
+	TopicLampControl   = "lampControl"
+	TopicTunnelTactics = "tunnelTactics"
+	TopicTunnelTiming  = "tunnelTiming"
 )

+ 8 - 0
web/src/api/tunnel.js

@@ -38,6 +38,14 @@ export const updateTunnel = (data) => {
   })
 }
 
+export const updateTactics = (data) => {
+  return service({
+    url: '/tunnel/updateTactics',
+    method: 'put',
+    data
+  })
+}
+
 export const updateTunnelsRegion = (data) => {
   return service({
     url: '/tunnel/updateTunnelsRegion',

+ 8 - 0
web/src/api/user.js

@@ -142,6 +142,14 @@ export const setUserAuthorities = (data) => {
   })
 }
 
+export const createUserTunnels = (data) => {
+  return service({
+    url: '/user/createUserTunnels',
+    method: 'post',
+    data: data
+  })
+}
+
 // @Tags User
 // @Summary 获取用户信息
 // @Security ApiKeyAuth

+ 50 - 6
web/src/view/admin/tunnel/tunnel.vue

@@ -37,7 +37,7 @@
       <div style="margin: 0 0 20px 0 ">
         <el-button
           type="success"
-          @click="tunnelAddDialog = true"
+          @click="isTunnelAdd"
         >添加</el-button>
         <el-button
           type="primary"
@@ -56,6 +56,11 @@
           width="55"
           align="center"
         />
+        <el-table-column
+          prop="tunnelSn"
+          label="序号"
+          align="center"
+        />
         <el-table-column
           prop="name"
           label="名称"
@@ -88,6 +93,7 @@
         <el-table-column
           label="操作"
           align="center"
+          width="500"
         >
           <template #default="scope">
             <el-button
@@ -146,6 +152,12 @@
             style="width: 200px;"
           />
         </el-form-item>
+        <el-form-item label="序号">
+          <el-input
+            v-model="tunnelData.tunnelSn"
+            style="width: 200px;"
+          />
+        </el-form-item>
         <el-form-item label="地区">
           <el-select
             v-model.number="tunnelData.regionId"
@@ -190,6 +202,12 @@
             style="width: 200px;"
           />
         </el-form-item>
+        <el-form-item label="序号">
+          <el-input
+            v-model="tunnelData.tunnelSn"
+            style="width: 200px;"
+          />
+        </el-form-item>
         <el-form-item label="地区">
           <el-select
             v-model.number="tunnelData.regionId"
@@ -334,13 +352,16 @@ import { queryAllRegions } from '@/api/region'
 import {
   createTunnel,
   deleteTunnel,
-  queryTunnelList,
+  queryTunnelList, updateTactics,
   updateTunnel,
   updateTunnelsRegion,
   updateTunnelTime
 } from '@/api/tunnel'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import { generateDeviceFile } from '@/api/device'
+import { useUserStore } from '@/pinia/modules/user'
+const userData = useUserStore()
+const userInfo = userData.userInfo
 
 const searchData = ref({
   pageInfo: {
@@ -348,9 +369,9 @@ const searchData = ref({
     pageSize: 10
   },
   name: '',
-  regionId: undefined
+  regionId: undefined,
+  userId: userInfo.ID
 })
-
 // 分页
 const handleSizeChange = (val) => {
   searchData.value.pageInfo.pageSize = val
@@ -384,13 +405,33 @@ const getData = async() => {
 
 const tunnelAddDialog = ref(false)
 
+const isTunnelAdd = () => {
+  tunnelAddDialog.value = true
+  tunnelData.value.tunnelSn = 'LC' + getFormattedDateTime()
+}
+
+function getFormattedDateTime() {
+  const now = new Date()
+
+  const year = now.getFullYear()
+  const month = String(now.getMonth() + 1).padStart(2, '0') // 月份从0开始,所以需要加1
+  const day = String(now.getDate()).padStart(2, '0')
+  const hour = String(now.getHours()).padStart(2, '0')
+  const minute = String(now.getMinutes()).padStart(2, '0')
+  const second = String(now.getSeconds()).padStart(2, '0')
+
+  return `${year}${month}${day}${hour}${minute}${second}`
+}
+
 const tunnelData = ref({
   id: 0,
   name: '',
-  regionId: undefined
+  regionId: undefined,
+  tunnelSn: ''
 })
 
 const tunnelAdd = async() => {
+  tunnelData.value.id = 0
   await createTunnel(tunnelData.value).then(res => {
     tunnelAddDialog.value = false
     getData()
@@ -527,7 +568,10 @@ const changeTactics = (val) => {
     }
   )
     .then(async() => {
-      await updateTunnel(val).then(res => {
+      await updateTactics({
+        sn: val.tunnelSn,
+        tactics: val.tactics
+      }).then(res => {
         if (res.code === 0) {
           ElMessage.success('修改成功')
         }

+ 41 - 2
web/src/view/superAdmin/user/user.vue

@@ -72,6 +72,23 @@
             />
           </template>
         </el-table-column>
+        <el-table-column
+          align="left"
+          label="隧道分配"
+          min-width="200"
+        >
+          <template #default="scope">
+            <el-cascader
+              v-model="scope.row.tunnelIds"
+              :options="regions"
+              :show-all-levels="false"
+              collapse-tags
+              :props="{ checkStrictly: false,label:'name',value:'ID',children:'tunnels',emitPath:false,multiple:true}"
+              :clearable="false"
+              @visible-change="(flag)=>{assignTunnels(scope.row,flag,0)}"
+            />
+          </template>
+        </el-table-column>
         <el-table-column
           align="left"
           label="启用"
@@ -229,7 +246,7 @@ import {
   getUserList,
   setUserAuthorities,
   register,
-  deleteUser
+  deleteUser, createUserTunnels
 } from '@/api/user'
 
 import { getAuthorityList } from '@/api/authority'
@@ -240,6 +257,7 @@ import { setUserInfo, resetPassword } from '@/api/user.js'
 import { nextTick, ref } from 'vue'
 import { ElMessage, ElMessageBox } from 'element-plus'
 import SelectImage from '@/components/selectImage/selectImage.vue'
+import { queryAllRegions } from '@/api/region'
 
 defineOptions({
   name: 'User',
@@ -284,17 +302,23 @@ const handleCurrentChange = (val) => {
 }
 
 // 查询
+
+const regions = ref()
 const getTableData = async() => {
   const table = await getUserList({ page: page.value, pageSize: pageSize.value })
+  console.log(table)
   if (table.code === 0) {
     tableData.value = table.data.list
     total.value = table.data.total
     page.value = table.data.page
     pageSize.value = table.data.pageSize
   }
+  await queryAllRegions().then(res => {
+    regions.value = res.data
+    console.log(regions.value)
+  })
 }
 
-
 const initPage = async() => {
   getTableData()
   const res = await getAuthorityList({ page: 1, pageSize: 999 })
@@ -464,6 +488,21 @@ const switchEnable = async(row) => {
   }
 }
 
+// 分配隧道
+const assignTunnels = async(row, flag, removeAuth) => {
+  if (flag) {
+    return
+  }
+  await createUserTunnels({
+    user: row,
+    tunnelIds: row.tunnelIds
+  }).then(res => {
+    if (res.code === 0) {
+      ElMessage({ type: 'success', message: '隧道分配成功' })
+    }
+  })
+}
+
 </script>
 
 <style lang="scss">