Explorar el Código

Add 继续完成表计增删改查模块

YueYunyun hace 2 años
padre
commit
3bb88f3c68
Se han modificado 36 ficheros con 957 adiciones y 450 borrados
  1. 133 65
      SERVER/IotAdmin/app/iot/apis/device.go
  2. 11 6
      SERVER/IotAdmin/app/iot/models/device.go
  3. 7 2
      SERVER/IotAdmin/app/iot/router/device.go
  4. 41 7
      SERVER/IotAdmin/app/iot/service/device.go
  5. 59 5
      SERVER/IotAdmin/app/iot/service/dto/device.go
  6. 1 1
      SERVER/IotAdmin/app/other/apis/tools/gen.go
  7. 17 3
      SERVER/IotAdmin/app/system/apis/sys_org.go
  8. 2 0
      SERVER/IotAdmin/app/system/service/dto/sys_api.go
  9. 2 1
      SERVER/IotAdmin/app/system/service/dto/sys_config.go
  10. 2 0
      SERVER/IotAdmin/app/system/service/dto/sys_dict_data.go
  11. 2 2
      SERVER/IotAdmin/app/system/service/dto/sys_dict_type.go
  12. 23 19
      SERVER/IotAdmin/app/system/service/dto/sys_org.go
  13. 2 0
      SERVER/IotAdmin/app/system/service/dto/sys_role.go
  14. 1 0
      SERVER/IotAdmin/app/system/service/dto/sys_user.go
  15. 65 30
      SERVER/IotAdmin/app/system/service/sys_org.go
  16. 1 1
      SERVER/IotAdmin/app/system/service/sys_role.go
  17. 7 7
      SERVER/IotAdmin/common/middleware/logger.go
  18. 11 6
      SERVER/IotAdmin/common/permission/data.go
  19. 1 1
      SERVER/IotAdmin/common/permission/role.go
  20. 60 5
      SERVER/IotAdmin/config/sql/db.sql
  21. 10 0
      SERVER/IotAdmin/core/sdk/pkg/security.go
  22. 12 8
      SERVER/IotAdmin/iot/db/device.go
  23. 2 2
      SERVER/IotAdmin/iot/service/downService/service.go
  24. 1 0
      SERVER/IotAdmin/template/v4/vue-view.go.template
  25. 1 1
      UI/IOTADMIN.VUE/src/api/_sys.ts
  26. 48 40
      UI/IOTADMIN.VUE/src/api/iot/_device.ts
  27. 7 7
      UI/IOTADMIN.VUE/src/api/system/_org.ts
  28. 1 1
      UI/IOTADMIN.VUE/src/components/tree/OrgTree.vue
  29. 1 1
      UI/IOTADMIN.VUE/src/views/account/profile/index.vue
  30. 85 81
      UI/IOTADMIN.VUE/src/views/iot/device/_gateway.vue
  31. 218 97
      UI/IOTADMIN.VUE/src/views/iot/device/_meter.vue
  32. 52 12
      UI/IOTADMIN.VUE/src/views/iot/device/index.vue
  33. 23 1
      UI/IOTADMIN.VUE/src/views/iot/group/index.vue
  34. 38 28
      UI/IOTADMIN.VUE/src/views/system/org/index.vue
  35. 6 6
      UI/IOTADMIN.VUE/src/views/system/role/index.vue
  36. 4 4
      UI/IOTADMIN.VUE/src/views/system/user/index.vue

+ 133 - 65
SERVER/IotAdmin/app/iot/apis/device.go

@@ -1,13 +1,14 @@
 package apis
 
 import (
-    "fmt"
+	"fmt"
 
-	"github.com/gin-gonic/gin"
 	"IotAdmin/core/sdk/api"
 	"IotAdmin/core/sdk/pkg/jwt-auth/user"
 	_ "IotAdmin/core/sdk/pkg/response"
 
+	"github.com/gin-gonic/gin"
+
 	"IotAdmin/app/iot/models"
 	"IotAdmin/app/iot/service"
 	"IotAdmin/app/iot/service/dto"
@@ -34,27 +35,29 @@ type IotDeviceApi struct {
 // @Router /api/iot-device [get]
 // @Security Bearer
 func (e IotDeviceApi) GetPage(c *gin.Context) {
-    req := dto.IotDeviceGetPageReq{}
-    s := service.IotDeviceService{}
-    err := e.MakeContext(c).
-        MakeOrm().
-        Bind(&req).
-        MakeService(&s.Service).
-        Errors
-   	if err != nil {
-   		e.Logger.Error(err)
-   		e.Error(500, err, err.Error())
-   		return
-   	}
-
-	p :=  permission.GetPermissionFromContext(c)
+	req := dto.IotDeviceGetPageReq{}
+	s := service.IotDeviceService{}
+	err := e.MakeContext(c).MakeOrm().Bind(&req).MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+
+	p := permission.GetPermissionFromContext(c)
+	if req.OrgId != 0 {
+		// 传入orgId ,就查询该组织及以下的数据
+		p.DataScope = permission.DataPermissionSelfOrgChildren
+		p.OrgId = req.OrgId
+	}
 	list := make([]models.IotDevice, 0)
 	var count int64
 
 	err = s.GetPage(&req, p, &list, &count)
 	if err != nil {
 		e.Error(500, err, fmt.Sprintf("获取设备失败,\r\n失败信息 %s", err.Error()))
-        return
+		return
 	}
 
 	e.PageOK(list, int(count), req.GetPageIndex(), req.GetPageSize(), "查询成功")
@@ -71,7 +74,7 @@ func (e IotDeviceApi) GetPage(c *gin.Context) {
 func (e IotDeviceApi) Get(c *gin.Context) {
 	req := dto.IotDeviceGetReq{}
 	s := service.IotDeviceService{}
-    err := e.MakeContext(c).
+	err := e.MakeContext(c).
 		MakeOrm().
 		Bind(&req).
 		MakeService(&s.Service).
@@ -83,14 +86,14 @@ func (e IotDeviceApi) Get(c *gin.Context) {
 	}
 	var object models.IotDevice
 
-	p :=  permission.GetPermissionFromContext(c)
+	p := permission.GetPermissionFromContext(c)
 	err = s.Get(&req, p, &object)
 	if err != nil {
 		e.Error(500, err, fmt.Sprintf("获取设备失败,\r\n失败信息 %s", err.Error()))
-        return
+		return
 	}
 
-	e.OK( object, "查询成功")
+	e.OK(object, "查询成功")
 }
 
 // Insert 添加设备
@@ -104,25 +107,26 @@ func (e IotDeviceApi) Get(c *gin.Context) {
 // @Router /api/iot-device [post]
 // @Security Bearer
 func (e IotDeviceApi) Insert(c *gin.Context) {
-    req := dto.IotDeviceInsertReq{}
-    s := service.IotDeviceService{}
-    err := e.MakeContext(c).
-        MakeOrm().
-        Bind(&req).
-        MakeService(&s.Service).
-        Errors
-    if err != nil {
-        e.Logger.Error(err)
-        e.Error(500, err, err.Error())
-        return
-    }
+	req := dto.IotDeviceInsertReq{}
+	s := service.IotDeviceService{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
 	// 设置创建人
 	req.SetCreateBy(user.GetUserId(c))
 
-	err = s.Insert(&req)
+	p := permission.GetPermissionFromContext(c)
+	err = s.Insert(&req, p)
 	if err != nil {
 		e.Error(500, err, fmt.Sprintf("添加设备失败,\r\n失败信息 %s", err.Error()))
-        return
+		return
 	}
 
 	e.OK(req.GetId(), "添加成功")
@@ -140,27 +144,27 @@ func (e IotDeviceApi) Insert(c *gin.Context) {
 // @Router /api/iot-device/{id} [put]
 // @Security Bearer
 func (e IotDeviceApi) Update(c *gin.Context) {
-    req := dto.IotDeviceUpdateReq{}
-    s := service.IotDeviceService{}
-    err := e.MakeContext(c).
-        MakeOrm().
-        Bind(&req).
-        MakeService(&s.Service).
-        Errors
-    if err != nil {
-        e.Logger.Error(err)
-        e.Error(500, err, err.Error())
-        return
-    }
+	req := dto.IotDeviceUpdateReq{}
+	s := service.IotDeviceService{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
 	req.SetUpdateBy(user.GetUserId(c))
-	p :=  permission.GetPermissionFromContext(c)
+	p := permission.GetPermissionFromContext(c)
 
 	err = s.Update(&req, p)
 	if err != nil {
 		e.Error(500, err, fmt.Sprintf("修改设备失败,\r\n失败信息 %s", err.Error()))
-        return
+		return
 	}
-	e.OK( req.GetId(), "修改成功")
+	e.OK(req.GetId(), "修改成功")
 }
 
 // Delete 删除设备
@@ -172,26 +176,90 @@ func (e IotDeviceApi) Update(c *gin.Context) {
 // @Router /api/iot-device [delete]
 // @Security Bearer
 func (e IotDeviceApi) Delete(c *gin.Context) {
-    s := service.IotDeviceService{}
-    req := dto.IotDeviceDeleteReq{}
-    err := e.MakeContext(c).
-        MakeOrm().
-        Bind(&req).
-        MakeService(&s.Service).
-        Errors
-    if err != nil {
-        e.Logger.Error(err)
-        e.Error(500, err, err.Error())
-        return
-    }
+	s := service.IotDeviceService{}
+	req := dto.IotDeviceDeleteReq{}
+	err := e.MakeContext(c).
+		MakeOrm().
+		Bind(&req).
+		MakeService(&s.Service).
+		Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
 
 	// req.SetUpdateBy(user.GetUserId(c))
-	p :=  permission.GetPermissionFromContext(c)
+	p := permission.GetPermissionFromContext(c)
 
 	err = s.Remove(&req, p)
 	if err != nil {
 		e.Error(500, err, fmt.Sprintf("删除设备失败,\r\n失败信息 %s", err.Error()))
-        return
+		return
+	}
+	e.OK(req.GetId(), "删除成功")
+}
+
+// Refresh 刷新设备列表
+// @Summary 刷新设备列表
+// @Description 刷新设备列表
+// @Tags 设备管理
+// @Param data body dto.IotDeviceDeleteReq true "body"
+// @Success 200 {object} response.Response	"{"code": 200, "message": "刷新成功"}"
+// @Router /api/iot-device/refresh [post]
+// @Security Bearer
+func (e IotDeviceApi) Refresh(c *gin.Context) {
+	s := service.IotDeviceService{}
+	err := e.MakeContext(c).MakeOrm().MakeService(&s.Service).Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	err = s.Refresh()
+	if err != nil {
+		return
+	}
+
+	e.OK("", "刷新成功")
+}
+
+// GetDeviceProtocols 获取表计协议列表
+// @Summary 获取表计协议列表
+// @Description 获取表计协议列表
+// @Tags 设备管理
+// @Success 200 {object} response.Response{data=models.IotDevice} "{"code": 200, "data": [...]}"
+// @Router /api/iot-device/device-protocol [get]
+// @Security Bearer
+func (e IotDeviceApi) GetDeviceProtocols(c *gin.Context) {
+	s := &service.IotDeviceService{}
+	err := e.MakeContext(c).MakeOrm().MakeService(&s.Service).Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
+	}
+	list := make([]string, 0)
+	s.GetDeviceProtocols(&list)
+	e.OK(list, "查询成功")
+}
+
+// GetReportProtocols 获取上报协议列表
+// @Summary 获取上报协议列表
+// @Description 获取上报协议列表
+// @Tags 设备管理
+// @Success 200 {object} response.Response{data=models.IotDevice} "{"code": 200, "data": [...]}"
+// @Router /api/iot-device/report-protocol [get]
+// @Security Bearer
+func (e IotDeviceApi) GetReportProtocols(c *gin.Context) {
+	s := &service.IotDeviceService{}
+	err := e.MakeContext(c).MakeOrm().MakeService(&s.Service).Errors
+	if err != nil {
+		e.Logger.Error(err)
+		e.Error(500, err, err.Error())
+		return
 	}
-	e.OK( req.GetId(), "删除成功")
+	list := make([]string, 0)
+	s.GetReportProtocols(&list)
+	e.OK(list, "查询成功")
 }

+ 11 - 6
SERVER/IotAdmin/app/iot/models/device.go

@@ -5,8 +5,8 @@ import (
 	"IotAdmin/core/logger"
 	"IotAdmin/iot/constant"
 	iotStruct "IotAdmin/iot/struct"
+	"database/sql"
 	"strings"
-	"time"
 
 	"gorm.io/gorm"
 )
@@ -16,7 +16,7 @@ type IotDevice struct {
 	models.Model
 	ParentId     int                       `json:"parentId" gorm:"rel(fk);type:bigint(20);comment:父ID"`
 	GroupId      int                       `json:"groupId" gorm:"type:bigint(20);comment:分组ID"`
-	Sn           string                    `json:"sn" gorm:"type:varchar(50);comment:设备编码"`
+	Sn           string                    `json:"sn" gorm:"type:varchar(50);comment:设备SN"`
 	Name         string                    `json:"name" gorm:"type:varchar(50);comment:设备名称"`
 	Type         int                       `json:"type" gorm:"type:bigint(20);comment:设备类型 1:网关 2:表计"`
 	Mode         int                       `json:"mode" gorm:"type:bigint(20);comment:设备模式 1:下发指令查询 2:表计主动上报"`
@@ -28,10 +28,12 @@ type IotDevice struct {
 	BmYz         string                    `json:"bmYz" gorm:"type:text;comment:编码因子"`
 	OtherConfig  string                    `json:"otherConfig" gorm:"type:text;comment:其他配置"`
 	OnlineStatus int                       `json:"onlineStatus" gorm:"type:tinyint(1);comment:在线状态"`
-	TimeOnline   time.Time                 `json:"timeOnline" gorm:"type:datetime;comment:上线时间"`
-	TimeOffline  time.Time                 `json:"timeOffline" gorm:"type:datetime;comment:离线时间"`
-	GroupName    string                    `json:"groupName" `
-	ReportConfig *[]iotStruct.ReportConfig `json:"reportConfigs" gorm:"-"`
+	TimeOnline   sql.NullTime              `json:"timeOnline" gorm:"type:datetime;comment:上线时间"`
+	TimeOffline  sql.NullTime              `json:"timeOffline" gorm:"type:datetime;comment:离线时间"`
+	Group        *IotGroup                 `json:"-"`
+	GroupName    string                    `json:"groupName" gorm:"-"`
+	ReportConfig *[]iotStruct.ReportConfig `json:"reportConfig" gorm:"-"`
+	Last         *IotDevice                `json:"-" gorm:"-"`
 	models.ControlBy
 	models.ModelTime
 }
@@ -63,6 +65,9 @@ func (e *IotDevice) BeforeCreate(_ *gorm.DB) error {
 //}
 
 func (e *IotDevice) AfterFind(_ *gorm.DB) error {
+	if e.Group != nil {
+		e.GroupName = e.Group.Name
+	}
 	if e.Type == constant.IotDeviceTypeGateway || e.Dsn == "" {
 		return nil
 	}

+ 7 - 2
SERVER/IotAdmin/app/iot/router/device.go

@@ -1,9 +1,10 @@
 package router
 
 import (
-	"github.com/gin-gonic/gin"
 	jwt "IotAdmin/core/sdk/pkg/jwt-auth"
 
+	"github.com/gin-gonic/gin"
+
 	"IotAdmin/app/iot/apis"
 	"IotAdmin/common/middleware"
 )
@@ -22,5 +23,9 @@ func registerIotDeviceRouter(v1 *gin.RouterGroup, authMiddleware *jwt.GinJWTMidd
 		r.POST("", api.Insert)
 		r.PUT("/:id", api.Update)
 		r.DELETE("", api.Delete)
+		r.POST("/refresh", api.Refresh)
+		r.GET("/device-protocols", api.GetDeviceProtocols)
+		r.GET("/report-protocols", api.GetReportProtocols)
 	}
-}
+
+}

+ 41 - 7
SERVER/IotAdmin/app/iot/service/device.go

@@ -6,6 +6,7 @@ import (
 	"IotAdmin/core/sdk"
 	"IotAdmin/core/sdk/service"
 	"IotAdmin/iot/constant"
+	iotProtocol "IotAdmin/iot/protocol"
 	"errors"
 
 	"gorm.io/gorm"
@@ -32,9 +33,10 @@ func (e *IotDeviceService) GetPage(c *dto.IotDeviceGetPageReq, p *permission.Dat
 		permission.Permission(data.TableName(), p),
 	)
 	if c.Type == constant.IotDeviceTypeGateway {
-		db = db.Joins("left join iot_group as g on g.id=iot_device.group_id").Select("iot_device.id,g.name as group_name,iot_device.name,type,group_id,sn,cycle,online_status,time_online,time_offline,iot_device.created_at")
+		//db = db.Joins("left join iot_group as g on g.id=iot_device.group_id").Select("iot_device.id,g.name as group_name,iot_device.name,type,group_id,sn,cycle,online_status,time_online,time_offline,iot_device.created_at")
+		db.Preload("Group").Select("iot_device.id,iot_device.name,type,group_id,sn,cycle,online_status,time_online,time_offline,iot_device.created_at")
 	} else {
-		db = db.Select("id,name,type,sn,protocol,mode,address,bm_yz,other_config,created_at")
+		db = db.Where("parent_id = ?", c.ParentId).Select("id,name,type,sn,protocol,mode,address,bm_yz,other_config,created_at")
 	}
 	err = db.Find(list).Limit(-1).Offset(-1).Count(count).Error
 	if err != nil {
@@ -63,11 +65,28 @@ func (e *IotDeviceService) Get(d *dto.IotDeviceGetReq, p *permission.DataPermiss
 }
 
 // Insert 添加设备对象
-func (e *IotDeviceService) Insert(c *dto.IotDeviceInsertReq) error {
+func (e *IotDeviceService) Insert(c *dto.IotDeviceInsertReq, p *permission.DataPermission) error {
 	var err error
-	var data models.IotDevice
-	c.Generate(&data)
-	err = e.Orm.Create(&data).Error
+	data := &models.IotDevice{}
+	last := &models.IotDevice{}
+	e.Orm.Model(data).Scopes(
+		permission.Permission(data.TableName(), p),
+	).Select("sn").Where("parent_id = ? AND type = ?", c.ParentId, c.Type).Order("created_at desc,id desc").Find(last)
+	last.Type = c.Type
+	if c.Type == constant.IotDeviceTypeMeter && last.Sn == "" {
+		parent := &models.IotDevice{}
+		e.Orm.Model(parent).First(parent, "id = ?", c.ParentId)
+		if parent.Sn == "" {
+			return errors.New("父设备编码为空")
+		}
+		last.Sn = parent.Sn
+	}
+	data.Last = last
+	c.Generate(data)
+	if data.Type == constant.IotDeviceTypeMeter && data.Dsn == "" {
+		return errors.New("设备上报配置解析失败")
+	}
+	err = e.Orm.Create(data).Error
 	if err != nil {
 		e.Log.Errorf("IotDeviceService Insert error:%s \r\n", err)
 		return err
@@ -91,7 +110,9 @@ func (e *IotDeviceService) Update(c *dto.IotDeviceUpdateReq, p *permission.DataP
 		permission.Permission(data.TableName(), p),
 	).First(&data, c.GetId())
 	c.Generate(&data)
-
+	if data.Type == constant.IotDeviceTypeMeter && data.Dsn == "" {
+		return errors.New("设备上报配置解析失败")
+	}
 	db := e.Orm.Save(&data)
 	if err = db.Error; err != nil {
 		e.Log.Errorf("IotDeviceService Save error:%s \r\n", err)
@@ -141,6 +162,19 @@ func (e *IotDeviceService) Remove(d *dto.IotDeviceDeleteReq, p *permission.DataP
 	return nil
 }
 
+func (e *IotDeviceService) GetDeviceProtocols(list *[]string) {
+	*list = iotProtocol.GetMeterProtocols()
+}
+
+func (e *IotDeviceService) GetReportProtocols(list *[]string) {
+	*list = iotProtocol.GetPlatProtocols()
+}
+
+func (e *IotDeviceService) Refresh() error {
+	err := updateDeviceMap(0)
+	return err
+}
+
 func updateDeviceMap(deviceId int) error {
 	q := sdk.Runtime.GetMemoryQueue("")
 	mp := make(map[string]interface{})

+ 59 - 5
SERVER/IotAdmin/app/iot/service/dto/device.go

@@ -4,14 +4,22 @@ import (
 	"IotAdmin/app/iot/models"
 	"IotAdmin/common/dto"
 	comModels "IotAdmin/common/models"
+	"IotAdmin/core/sdk/pkg"
 	"IotAdmin/iot/constant"
 	iotStruct "IotAdmin/iot/struct"
+	"strconv"
+	"strings"
 
 	"time"
 )
 
 type IotDeviceGetPageReq struct {
 	dto.Pagination `search:"-"`
+	OrgId          int    `form:"orgId" search:"-"`
+	ParentId       int    `form:"parentId" search:"type:exact;column:parent_id;table:iot_device" comment:"父设备ID"`
+	GroupId        int    `form:"groupId" search:"type:exact;column:group_id;table:iot_device" comment:"设备分组"`
+	Sn             string `form:"sn" search:"type:icontains;column:sn;table:iot_device" comment:"设备SN"`
+	Name           string `form:"name" search:"type:icontains;column:name;table:iot_device" comment:"设备名称"`
 	Type           int    `form:"type" search:"type:exact;column:type;table:iot_device" comment:"设备类型"`
 	BeginTime      string `form:"beginTime" search:"type:gte;column:created_at;table:iot_device" comment:"创建时间"`
 	EndTime        string `form:"endTime" search:"type:lte;column:created_at;table:iot_device" comment:"创建时间"`
@@ -42,7 +50,8 @@ type IotDeviceInsertReq struct {
 	Description  string                    `json:"description" comment:"设备描述"`
 	Protocol     string                    `json:"protocol" comment:"表计协议"`
 	Address      int                       `json:"address" comment:"表计地址"`
-	ReportConfig *[]iotStruct.ReportConfig `json:"reportConfigs"  comment:"上报配置"`
+	BmYz         string                    `json:"bmYz" comment:"编码因子"`
+	ReportConfig *[]iotStruct.ReportConfig `json:"reportConfig"  comment:"上报配置"`
 	comModels.ControlBy
 }
 
@@ -52,7 +61,7 @@ func (s *IotDeviceInsertReq) Generate(model *models.IotDevice) {
 	}
 	model.ParentId = s.ParentId
 	model.GroupId = s.GroupId
-	model.Sn = s.Sn
+	model.Sn = GenSn(model.Last)
 	model.Name = s.Name
 	model.Type = s.Type
 	model.Mode = s.Mode
@@ -60,13 +69,52 @@ func (s *IotDeviceInsertReq) Generate(model *models.IotDevice) {
 	model.Description = s.Description
 	model.Protocol = s.Protocol
 	model.Address = s.Address
+	model.BmYz = s.BmYz
 	model.CreateBy = s.CreateBy // 添加这而,需要记录是被谁创建的
 	model.Dsn = ""
-	if model.Type == constant.IotDeviceTypeMeter {
+	if model.Type == constant.IotDeviceTypeMeter && s.ReportConfig != nil {
 		model.Dsn = BuildDsnString(s.ReportConfig)
 	}
 }
 
+func GenSn(model *models.IotDevice) string {
+	str := ""
+	if model.Type == constant.IotDeviceTypeGateway {
+		today := time.Now().Format("0601")
+		str += today
+		snLen := len(model.Sn)
+		// 截取sn的前4位
+		if model.Sn == "" || model.Sn[0:4] != today {
+			str += "101"
+		} else {
+			// 截取sn第5位到后3位
+			nStr := model.Sn[4 : snLen-3]
+			num, err := strconv.Atoi(nStr)
+			if err != nil {
+				return ""
+			}
+			num++
+			str += strconv.Itoa(num)
+		}
+		// 生成3位随机数
+		str += pkg.GenerateRandomNumber(3)
+	} else {
+		arr := strings.Split(model.Sn, "_")
+		str += arr[0]
+		if len(arr) > 1 {
+			num, err := strconv.Atoi(arr[1])
+			if err != nil {
+				return ""
+			}
+			num++
+			str += "_" + strconv.Itoa(num)
+		} else {
+			str += "_101"
+		}
+	}
+	return str
+}
+
 func (s *IotDeviceInsertReq) GetId() interface{} {
 	return s.Id
 }
@@ -84,7 +132,8 @@ type IotDeviceUpdateReq struct {
 	Description  string                    `json:"description" comment:"设备描述"`
 	Protocol     string                    `json:"protocol" comment:"表计协议"`
 	Address      int                       `json:"address" comment:"表计地址"`
-	ReportConfig *[]iotStruct.ReportConfig `json:"reportConfigs"  comment:"上报配置"`
+	BmYz         string                    `json:"bmYz" comment:"编码因子"`
+	ReportConfig *[]iotStruct.ReportConfig `json:"reportConfig"  comment:"上报配置"`
 	comModels.ControlBy
 }
 
@@ -102,6 +151,7 @@ func (s *IotDeviceUpdateReq) Generate(model *models.IotDevice) {
 	model.Description = s.Description
 	model.Protocol = s.Protocol
 	model.Address = s.Address
+	model.BmYz = s.BmYz
 	model.UpdateBy = s.UpdateBy // 添加这而,需要记录是被谁更新的
 	model.Dsn = ""
 	if model.Type == constant.IotDeviceTypeMeter {
@@ -119,7 +169,11 @@ func BuildDsnString(configs *[]iotStruct.ReportConfig) string {
 		if i > 0 {
 			str += constant.DsnSplitString
 		}
-		str += cfg.Host + constant.DsnChildSplitString + cfg.Protocol + constant.DsnChildSplitString + cfg.ST + constant.DsnChildSplitString + cfg.MN
+		host := strings.Replace(cfg.Host, ":", ":", 1)
+		if !strings.Contains(host, ":") || cfg.Protocol == "" || cfg.ST == "" || cfg.MN == "" {
+			return ""
+		}
+		str += host + constant.DsnChildSplitString + cfg.Protocol + constant.DsnChildSplitString + cfg.ST + constant.DsnChildSplitString + cfg.MN
 		if cfg.User != "" {
 			str += constant.DsnChildSplitString + cfg.User + constant.DsnChildSplitString + cfg.Pwd
 		}

+ 1 - 1
SERVER/IotAdmin/app/other/apis/tools/gen.go

@@ -526,7 +526,7 @@ func (e Gen) genCreateBtn(tab tools.SysTables, menuId int) error {
 			return err
 		}
 	}
-	MCreate.MenuName = "创建" + tab.FunctionName
+	MCreate.MenuName = "新增" + tab.FunctionName
 	MCreate.Icon = menuIcon
 	MCreate.Path = menuPath
 	MCreate.MenuType = global.Button

+ 17 - 3
SERVER/IotAdmin/app/system/apis/sys_org.go

@@ -43,8 +43,14 @@ func (e SysOrgApi) GetPage(c *gin.Context) {
 		return
 	}
 	p := permission.GetPermissionFromContext(c)
+	if user.GetRoleKey(c) == "admin" {
+		req.OrgId = 0
+	} else {
+		p.DataScope = permission.DataPermissionSelfOrgChildren
+		p.OrgId = req.OrgId
+	}
 	list := make([]models.SysOrg, 0)
-	list, err = s.SetOrgPage(&req, p)
+	list, err = s.GetOrgPage(&req, p)
 	if err != nil {
 		e.Error(500, err, "查询失败")
 		return
@@ -201,9 +207,17 @@ func (e SysOrgApi) Get2Tree(c *gin.Context) {
 		e.Error(500, err, err.Error())
 		return
 	}
-	p := permission.GetPermissionFromContext(c)
+
+	var p *permission.DataPermission
+	p = permission.GetPermissionFromContext(c)
+	if user.GetRoleKey(c) == "admin" {
+		req.Id = 0
+	} else {
+		p.DataScope = permission.DataPermissionSelfOrgChildren
+		p.OrgId = req.Id
+	}
 	list := make([]dto.OrgLabel, 0)
-	list, err = s.SetOrgTree(&req, p)
+	list, err = s.GetOrgTree(&req, p)
 	if err != nil {
 		e.Error(500, err, "查询失败")
 		return

+ 2 - 0
SERVER/IotAdmin/app/system/service/dto/sys_api.go

@@ -46,6 +46,7 @@ func (s *SysApiInsertReq) Generate(model *models.SysApi) {
 	model.Path = s.Path
 	model.Type = s.Type
 	model.Action = s.Action
+	model.CreateBy = s.CreateBy
 }
 
 func (s *SysApiInsertReq) GetId() interface{} {
@@ -72,6 +73,7 @@ func (s *SysApiUpdateReq) Generate(model *models.SysApi) {
 	model.Path = s.Path
 	model.Type = s.Type
 	model.Action = s.Action
+	model.UpdateBy = s.UpdateBy
 }
 
 func (s *SysApiUpdateReq) GetId() interface{} {

+ 2 - 1
SERVER/IotAdmin/app/system/service/dto/sys_config.go

@@ -59,7 +59,8 @@ func (s *SysConfigControl) Generate(model *models.SysConfig) {
 	model.ConfigType = s.ConfigType
 	model.IsFrontend = s.IsFrontend
 	model.Remark = s.Remark
-
+	model.CreateBy = s.CreateBy
+	model.UpdateBy = s.UpdateBy
 }
 
 // GetId 获取数据对应的ID

+ 2 - 0
SERVER/IotAdmin/app/system/service/dto/sys_dict_data.go

@@ -53,6 +53,7 @@ func (s *SysDictDataInsertReq) Generate(model *models.SysDictData) {
 	model.Status = s.Status
 	model.Default = s.Default
 	model.Remark = s.Remark
+	model.CreateBy = s.CreateBy
 }
 
 func (s *SysDictDataInsertReq) GetId() interface{} {
@@ -86,6 +87,7 @@ func (s *SysDictDataUpdateReq) Generate(model *models.SysDictData) {
 	model.Status = s.Status
 	model.Default = s.Default
 	model.Remark = s.Remark
+	model.UpdateBy = s.UpdateBy
 }
 
 func (s *SysDictDataUpdateReq) GetId() interface{} {

+ 2 - 2
SERVER/IotAdmin/app/system/service/dto/sys_dict_type.go

@@ -40,7 +40,7 @@ func (s *SysDictTypeInsertReq) Generate(model *models.SysDictType) {
 	model.DictType = s.DictType
 	model.Status = s.Status
 	model.Remark = s.Remark
-
+	model.CreateBy = s.CreateBy
 }
 
 func (s *SysDictTypeInsertReq) GetId() interface{} {
@@ -64,7 +64,7 @@ func (s *SysDictTypeUpdateReq) Generate(model *models.SysDictType) {
 	model.DictType = s.DictType
 	model.Status = s.Status
 	model.Remark = s.Remark
-
+	model.UpdateBy = s.UpdateBy
 }
 
 func (s *SysDictTypeUpdateReq) GetId() interface{} {

+ 23 - 19
SERVER/IotAdmin/app/system/service/dto/sys_org.go

@@ -7,7 +7,7 @@ import (
 
 // SysOrgGetPageReq 列表或者搜索使用结构体
 type SysOrgGetPageReq struct {
-	OrgId    int    `form:"orgId" search:"type:exact;column:org_id;table:sys_org" comment:"id"`           //id
+	OrgId    int    `form:"orgId" search:"-" comment:"id"`                                                //id
 	ParentId int    `form:"parentId" search:"type:exact;column:parent_id;table:sys_org" comment:"上级组织机构"` //上级组织机构
 	OrgPath  string `form:"orgPath" search:"type:exact;column:org_path;table:sys_org" comment:""`         //路径
 	OrgName  string `form:"orgName" search:"type:exact;column:org_name;table:sys_org" comment:"组织机构名称"`   //组织机构名称
@@ -23,15 +23,16 @@ func (m *SysOrgGetPageReq) GetNeedSearch() interface{} {
 }
 
 type SysOrgInsertReq struct {
-	OrgId    int    `uri:"id" comment:"编码"`                                         // 编码
-	ParentId int    `json:"parentId" comment:"上级组织机构" vd:"?"`                       //上级组织机构
-	OrgPath  string `json:"orgPath" comment:""`                                     //路径
-	OrgName  string `json:"orgName" comment:"组织机构名称" vd:"len($)>0"`                 //组织机构名称
-	Sort     int    `json:"sort" comment:"排序" vd:"?"`                               //排序
-	Leader   string `json:"leader" comment:"负责人" vd:"@:len($)>0; msg:'leader不能为空'"` //负责人
-	Phone    string `json:"phone" comment:"手机" vd:"?"`                              //手机
-	Email    string `json:"email" comment:"邮箱" vd:"?"`                              //邮箱
-	Status   int    `json:"status" comment:"状态" vd:"$>0"`                           //状态
+	OrgId    int    `uri:"id" comment:"编码"`                         // 编码
+	ParentId int    `json:"parentId" comment:"上级组织机构" vd:"?"`       //上级组织机构
+	OrgPath  string `json:"orgPath" comment:""`                     //路径
+	OrgName  string `json:"orgName" comment:"组织机构名称" vd:"len($)>0"` //组织机构名称
+	Sort     int    `json:"sort" comment:"排序" vd:"?"`               //排序
+	//Leader   string `json:"leader" comment:"负责人" vd:"@:len($)>0; msg:'leader不能为空'"` //负责人
+	Leader string `json:"leader" comment:"负责人" vd:"?"`  //负责人
+	Phone  string `json:"phone" comment:"手机" vd:"?"`    //手机
+	Email  string `json:"email" comment:"邮箱" vd:"?"`    //邮箱
+	Status int    `json:"status" comment:"状态" vd:"$>0"` //状态
 	common.ControlBy
 }
 
@@ -47,6 +48,7 @@ func (s *SysOrgInsertReq) Generate(model *models.SysOrg) {
 	model.Phone = s.Phone
 	model.Email = s.Email
 	model.Status = s.Status
+	model.CreateBy = s.CreateBy
 }
 
 // GetId 获取数据对应的ID
@@ -55,15 +57,16 @@ func (s *SysOrgInsertReq) GetId() interface{} {
 }
 
 type SysOrgUpdateReq struct {
-	OrgId    int    `uri:"id" comment:"编码"`                                         // 编码
-	ParentId int    `json:"parentId" comment:"上级组织机构" vd:"?"`                       //上级组织机构
-	OrgPath  string `json:"orgPath" comment:""`                                     //路径
-	OrgName  string `json:"orgName" comment:"组织机构名称" vd:"len($)>0"`                 //组织机构名称
-	Sort     int    `json:"sort" comment:"排序" vd:"?"`                               //排序
-	Leader   string `json:"leader" comment:"负责人" vd:"@:len($)>0; msg:'leader不能为空'"` //负责人
-	Phone    string `json:"phone" comment:"手机" vd:"?"`                              //手机
-	Email    string `json:"email" comment:"邮箱" vd:"?"`                              //邮箱
-	Status   int    `json:"status" comment:"状态" vd:"$>0"`                           //状态
+	OrgId    int    `uri:"id" comment:"编码"`                         // 编码
+	ParentId int    `json:"parentId" comment:"上级组织机构" vd:"?"`       //上级组织机构
+	OrgPath  string `json:"orgPath" comment:""`                     //路径
+	OrgName  string `json:"orgName" comment:"组织机构名称" vd:"len($)>0"` //组织机构名称
+	Sort     int    `json:"sort" comment:"排序" vd:"?"`               //排序
+	//Leader   string `json:"leader" comment:"负责人" vd:"@:len($)>0; msg:'leader不能为空'"` //负责人
+	Leader string `json:"leader" comment:"负责人" vd:"?"`  //负责人
+	Phone  string `json:"phone" comment:"手机" vd:"?"`    //手机
+	Email  string `json:"email" comment:"邮箱" vd:"?"`    //邮箱
+	Status int    `json:"status" comment:"状态" vd:"$>0"` //状态
 	common.ControlBy
 }
 
@@ -80,6 +83,7 @@ func (s *SysOrgUpdateReq) Generate(model *models.SysOrg) {
 	model.Phone = s.Phone
 	model.Email = s.Email
 	model.Status = s.Status
+	model.UpdateBy = s.UpdateBy
 }
 
 // GetId 获取数据对应的ID

+ 2 - 0
SERVER/IotAdmin/app/system/service/dto/sys_role.go

@@ -64,6 +64,7 @@ func (s *SysRoleInsertReq) Generate(model *models.SysRole) {
 	model.DataScope = s.DataScope
 	model.Menus = &s.Menus
 	model.Orgs = &s.Orgs
+	model.CreateBy = s.CreateBy
 }
 
 func (s *SysRoleInsertReq) GetId() interface{} {
@@ -101,6 +102,7 @@ func (s *SysRoleUpdateReq) Generate(model *models.SysRole) {
 	model.DataScope = s.DataScope
 	model.Menus = &s.Menus
 	model.Orgs = &s.Orgs
+	model.UpdateBy = s.UpdateBy
 }
 
 func (s *SysRoleUpdateReq) GetId() interface{} {

+ 1 - 0
SERVER/IotAdmin/app/system/service/dto/sys_user.go

@@ -159,6 +159,7 @@ func (s *SysUserUpdateReq) Generate(model *models.SysUser) {
 	model.PostId = s.PostId
 	model.Remark = s.Remark
 	model.Status = s.Status
+	model.UpdateBy = s.UpdateBy
 }
 
 func (s *SysUserUpdateReq) GetId() interface{} {

+ 65 - 30
SERVER/IotAdmin/app/system/service/sys_org.go

@@ -20,7 +20,7 @@ type SysOrgService struct {
 	service.Service
 }
 
-// GetPage 获取SysDept列表
+// GetPage 获取SysOrg列表
 //func (e *SysOrgService) GetPage(c *dto.SysOrgGetPageReq, list *[]models.SysOrgService) error {
 //	var err error
 //	var data models.SysOrgService
@@ -150,12 +150,10 @@ func (e *SysOrgService) getList(c *dto.SysOrgGetPageReq, list *[]models.SysOrg,
 	var err error
 	var data models.SysOrg
 
-	err = e.Orm.Model(&data).
-		Scopes(
-			cDto.MakeCondition(c.GetNeedSearch()),
-			permission.Permission(data.TableName(), p),
-		).
-		Find(list).Error
+	err = e.Orm.Model(&data).Scopes(
+		cDto.MakeCondition(c.GetNeedSearch()),
+		permission.Permission(data.TableName(), p),
+	).Find(list).Error
 	if err != nil {
 		e.Log.Errorf("db error:%s", err)
 		return err
@@ -163,30 +161,44 @@ func (e *SysOrgService) getList(c *dto.SysOrgGetPageReq, list *[]models.SysOrg,
 	return nil
 }
 
-// SetOrgTree 设置组织数据
-func (e *SysOrgService) SetOrgTree(c *dto.SysOrgGetReq, p *permission.DataPermission) (m []dto.OrgLabel, err error) {
+// GetOrgTree 获取组织数据
+func (e *SysOrgService) GetOrgTree(c *dto.SysOrgGetReq, p *permission.DataPermission) (m []dto.OrgLabel, err error) {
 	var list []models.SysOrg
 	var data models.SysOrg
-	err = e.Orm.Model(&data).Scopes(
+	db := e.Orm.Model(&data)
+
+	db = e.Orm.Model(&data).Scopes(
 		permission.Permission(data.TableName(), p),
-	).Where("status = ?", 2).Where("org_id = ? or parent_id = ? ", c.GetId(), c.GetId()).Find(&list).Error
+	)
+	err = db.Where("status = ?", 2).Find(&list).Error
 	if err != nil {
 		e.Log.Errorf("db error:%s", err)
 		return
 	}
-
+	org := &models.SysOrg{}
 	m = make([]dto.OrgLabel, 0)
-	for i := 0; i < len(list); i++ {
-		if list[i].ParentId != 0 {
-			continue
-		}
+	if c.GetId() != 0 {
+		e.Orm.Model(&data).First(&org, c.GetId())
+	}
+	if c.GetId() != 0 {
 		e := dto.OrgLabel{}
-		e.Id = list[i].OrgId
-		e.Label = list[i].OrgName
+		e.Id = org.OrgId
+		e.Label = org.OrgName
 		orgInfo := orgTreeCall(&list, e)
-
 		m = append(m, orgInfo)
+	} else {
+		for i := 0; i < len(list); i++ {
+			if list[i].ParentId != c.Id {
+				continue
+			}
+			e := dto.OrgLabel{}
+			e.Id = list[i].OrgId
+			e.Label = list[i].OrgName
+			orgInfo := orgTreeCall(&list, e)
+			m = append(m, orgInfo)
+		}
 	}
+
 	return
 }
 
@@ -206,25 +218,48 @@ func orgTreeCall(orgList *[]models.SysOrg, org dto.OrgLabel) dto.OrgLabel {
 	return org
 }
 
-// SetOrgPage 设置org页面数据
-func (e *SysOrgService) SetOrgPage(c *dto.SysOrgGetPageReq, p *permission.DataPermission) (m []models.SysOrg, err error) {
+// GetOrgPage 设置org页面数据
+func (e *SysOrgService) GetOrgPage(c *dto.SysOrgGetPageReq, p *permission.DataPermission) (m []models.SysOrg, err error) {
 	var list []models.SysOrg
-	err = e.getList(c, &list, p)
-	for i := 0; i < len(list); i++ {
-		if list[i].ParentId != 0 {
-			continue
+	var data models.SysOrg
+
+	db := e.Orm.Model(&data).Scopes(
+		cDto.MakeCondition(c.GetNeedSearch()),
+		permission.Permission(data.TableName(), p),
+	)
+	err = db.Find(&list).Error
+	if err != nil {
+		e.Log.Errorf("db error:%s", err)
+		return
+	}
+	org := &models.SysOrg{}
+	if c.OrgId != 0 {
+		if e.Orm.Model(&data).First(&org, c.OrgId).Error != nil {
+			e.Log.Errorf("db error:%s", err)
+			return
 		}
-		info := e.orgPageCall(&list, list[i])
+	}
+	if p != nil && org.OrgId != 0 {
+		info := (&SysOrgService{}).orgPageCall(&list, *org)
 		m = append(m, info)
+	} else {
+		for i := 0; i < len(list); i++ {
+			if list[i].ParentId != 0 {
+				continue
+			}
+			info := (&SysOrgService{}).orgPageCall(&list, list[i])
+			m = append(m, info)
+		}
 	}
+
 	return
 }
 
-func (e *SysOrgService) orgPageCall(orgList *[]models.SysOrg, menu models.SysOrg) models.SysOrg {
+func (e *SysOrgService) orgPageCall(orgList *[]models.SysOrg, org models.SysOrg) models.SysOrg {
 	list := *orgList
 	orgArr := make([]models.SysOrg, 0)
 	for j := 0; j < len(list); j++ {
-		if menu.OrgId != list[j].ParentId {
+		if org.OrgId != list[j].ParentId {
 			continue
 		}
 		mi := models.SysOrg{}
@@ -242,8 +277,8 @@ func (e *SysOrgService) orgPageCall(orgList *[]models.SysOrg, menu models.SysOrg
 		ms := e.orgPageCall(orgList, mi)
 		orgArr = append(orgArr, ms)
 	}
-	menu.Children = orgArr
-	return menu
+	org.Children = orgArr
+	return org
 }
 
 // GetWithRoleId 获取角色的部门ID集合

+ 1 - 1
SERVER/IotAdmin/app/system/service/sys_role.go

@@ -149,7 +149,7 @@ func (e *SysRoleService) Update(c *dto.SysRoleUpdateReq, cb *casbin.SyncedEnforc
 	if err = checkRoleAllowed(model, roleKey); err != nil {
 		return err
 	}
-	tx.Preload("SysApis").Where("menu_id in ?", c.MenuIds).Find(&mList)
+	tx.Preload("SysApi").Where("menu_id in ?", c.MenuIds).Find(&mList)
 	err = tx.Model(&model).Association("Menus").Delete(model.Menus)
 	if err != nil {
 		e.Log.Errorf("delete policy error:%s", err)

+ 7 - 7
SERVER/IotAdmin/common/middleware/logger.go

@@ -163,21 +163,21 @@ func GetFuncMethod(url string, method string) string {
 		m = LOGIN
 	} else if strings.Index(url, "/api/refresh-token") > -1 {
 		m = LOGIN
-	} else if strings.Index(url, "/import/") > -1 {
+	} else if strings.Index(url, "/import") > -1 {
 		m = IMPORT
-	} else if strings.Index(url, "/export/") > -1 {
+	} else if strings.Index(url, "/export") > -1 {
 		m = EXPORT
-	} else if strings.Index(url, "/auth/") > -1 {
+	} else if strings.Index(url, "/auth") > -1 {
 		m = AUTH
-	} else if strings.Index(url, "/start/") > -1 {
+	} else if strings.Index(url, "/start") > -1 {
 		m = START
-	} else if strings.Index(url, "/stop/") > -1 {
+	} else if strings.Index(url, "/stop") > -1 {
 		m = STOP
 	} else if strings.Index(url, "/api/sys/gen-") > -1 {
 		m = GEN
-	} else if strings.Index(url, "/clean/") > -1 {
+	} else if strings.Index(url, "/clean") > -1 {
 		m = CLEAN
-	} else if strings.Index(url, "/refresh/") > -1 {
+	} else if strings.Index(url, "/refresh") > -1 {
 		m = REFRESH
 	} else {
 		switch method {

+ 11 - 6
SERVER/IotAdmin/common/permission/data.go

@@ -13,11 +13,16 @@ import (
 )
 
 const (
-	DataPermissionKey = "dataPermission"
+	DataPermissionKey             = "dataPermission"
+	DataPermissionALL             = "1"
+	DataPermissionCustom          = "2"
+	DataPermissionSelfOrg         = "3"
+	DataPermissionSelfOrgChildren = "4"
+	DataPermissionSelf            = "5"
 )
 
 type DataPermission struct {
-	DataScope string
+	DataScope string // 数据范围 1 全部 2 自定义 3 本部门 4 本部门及以下 5 仅自己
 	UserId    int
 	OrgId     int
 	RoleId    int
@@ -80,13 +85,13 @@ func Permission(tableName string, p *DataPermission) func(db *gorm.DB) *gorm.DB
 			return db
 		}
 		switch p.DataScope {
-		case "2":
+		case DataPermissionCustom:
 			return db.Where(tableName+".create_by in (select sys_user.user_id from sys_role_org left join sys_user on sys_user.org_id=sys_role_org.org_id where sys_role_org.role_id = ?)", p.RoleId)
-		case "3":
+		case DataPermissionSelfOrg:
 			return db.Where(tableName+".create_by in (SELECT user_id from sys_user where org_id = ? )", p.OrgId)
-		case "4":
+		case DataPermissionSelfOrgChildren:
 			return db.Where(tableName+".create_by in (SELECT user_id from sys_user where sys_user.org_id in(select org_id from sys_org where org_path like ? ))", "%/"+pkg.IntToString(p.OrgId)+"/%")
-		case "5":
+		case DataPermissionSelf:
 			return db.Where(tableName+".create_by = ?", p.UserId)
 		default:
 			return db

+ 1 - 1
SERVER/IotAdmin/common/permission/role.go

@@ -37,7 +37,7 @@ func CheckRoleApi(c *gin.Context, v jwtauth.MapClaims, e *casbin.SyncedEnforcer)
 		response.Error(c, 500, err, "")
 		return false
 	}
-	return
+	return res
 }
 
 type UrlInfo struct {

+ 60 - 5
SERVER/IotAdmin/config/sql/db.sql

@@ -1,8 +1,8 @@
 -- 开始初始化数据 ;
-INSERT INTO sys_menu VALUES (1, 0, '系统管理', 'system','terminal',     '/0/1', 'M', '', '', 'Layout','','', 1, true,  false, false, 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
-INSERT INTO sys_menu VALUES (2, 0, '定时任务', 'schedule', 'clock',  '/0/4', 'M', '', '', 'Layout','','', 2, false, false, false, 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
-INSERT INTO sys_menu VALUES (3, 0, '系统工具', 'sys-tools', 'display', '0/3', 'M', '', '', 'Layout','','', 3, false, false, false, 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
-INSERT INTO sys_menu VALUES (4, 0, '开发工具', 'dev-tools', 'display',      '/0/2', 'M', '', '', 'Layout','','', 4, false, false, false, 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
+INSERT INTO sys_menu VALUES (1, 0, '系统信息维护', 'system','terminal',     '/0/1', 'M', '', '', 'Layout','','', 1, true,  false, false, 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
+INSERT INTO sys_menu VALUES (2, 0, '定时任务维护', 'schedule', 'clock',  '/0/4', 'M', '', '', 'Layout','','', 2, false, false, false, 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
+INSERT INTO sys_menu VALUES (3, 0, '系统工具维护', 'sys-tools', 'display', '0/3', 'M', '', '', 'Layout','','', 3, false, false, false, 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
+INSERT INTO sys_menu VALUES (4, 0, '开发工具维护', 'dev-tools', 'display',      '/0/2', 'M', '', '', 'Layout','','', 4, false, false, false, 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
 
 
 INSERT INTO sys_menu VALUES (11,1, '系统用户管理', 'user', 'person-circle', '/0/1/11', 'C', '', 'system:user',  '/system/user/index','','', 1, false,false, false, 0, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
@@ -299,6 +299,53 @@ INSERT INTO sys_api VALUES  (220,'','生成代码','/api/sys/gen-code/:tableId',
 INSERT INTO sys_api VALUES  (221,'','生成菜单及接口','/api/sys/gen-menu-api/:tableId','GET','SYS', 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
 
 
+INSERT INTO sys_menu VALUES (207, 0, '设备信息维护', 'iot', 'pass', '/0/207', 'M', '', '', 'Layout', '', '', 0, 0, 0, 0, 1, 0, '2024-03-28 16:46:11.291', '2024-04-01 09:09:56.511', NULL);
+INSERT INTO sys_menu VALUES (208, 207, '分组管理', 'group', 'app-indicator', '/0/207/208', 'C', '', 'iot:group', '/iot/group/index', '', '', 1, 0, 0, 0, 1, 1, '2024-03-28 16:46:11.764', '2024-04-01 09:09:56.511', NULL);
+INSERT INTO sys_menu VALUES (209, 208, '查询分组', '#', 'eye', '/0/207/208/209', 'F', '', 'iot:group:query', '', '', '', 1, 0, 1, 0, 1, 1, '2024-03-28 16:46:11.984', '2024-04-01 09:09:56.511', NULL);
+INSERT INTO sys_menu VALUES (210, 208, '新增分组', '#', 'plus-square', '/0/207/208/210', 'F', '', 'iot:group:add', '', 'btn btn-light-primary', 'handleCreate', 2, 0, 0, 0, 1, 1, '2024-03-28 16:46:12.296', '2024-04-01 09:09:56.511', NULL);
+INSERT INTO sys_menu VALUES (211, 208, '修改分组', '#', 'pencil-square', '/0/207/208/211', 'F', '', 'iot:group:edit', '', 'btn btn-light-success', 'handleUpdate@1', 3, 0, 0, 0, 1, 1, '2024-03-28 16:46:12.593', '2024-04-01 09:09:56.511', NULL);
+INSERT INTO sys_menu VALUES (212, 208, '删除分组', '#', 'dash-square', '/0/207/208/212', 'F', '', 'iot:group:remove', '', 'btn btn-light-danger', 'handleDelete@0', 4, 0, 0, 0, 1, 1, '2024-03-28 16:46:12.899', '2024-04-01 09:09:56.511', NULL);
+INSERT INTO sys_menu VALUES (213, 207, '设备管理', 'device', 'app-indicator', '/0/207/213', 'C', '', 'iot:device', '/iot/device/index', '', '', 1, 0, 0, 0, 1, 1, '2024-03-28 16:46:17.681', '2024-04-01 09:09:56.511', NULL);
+INSERT INTO sys_menu VALUES (214, 213, '查询设备网关', '#', 'eye', '/0/207/213/214', 'F', '', 'iot:device:query', '', '', '', 1, 0, 1, 0, 1, 1, '2024-03-28 16:46:17.904', '2024-04-01 09:09:56.511', NULL);
+INSERT INTO sys_menu VALUES (215, 213, '新增网关', '#', 'plus-square', '/0/207/213/215', 'F', '', 'iot:device:add', '', 'btn btn-light-primary', 'handleCreate', 2, 0, 0, 0, 1, 1, '2024-03-28 16:46:18.297', '2024-04-01 09:09:56.511', NULL);
+INSERT INTO sys_menu VALUES (216, 213, '修改网关', '#', 'pencil-square', '/0/207/213/216', 'F', '', 'iot:device:edit', '', 'btn btn-light-success', 'handleUpdate@1', 3, 0, 0, 0, 1, 1, '2024-03-28 16:46:18.713', '2024-04-01 09:09:56.511', NULL);
+INSERT INTO sys_menu VALUES (217, 213, '删除网关', '#', 'dash-square', '/0/207/213/217', 'F', '', 'iot:device:remove', '', 'btn btn-light-danger', 'handleDelete@0', 4, 0, 0, 0, 1, 1, '2024-03-28 16:46:19.055', '2024-04-01 09:09:56.511', NULL);
+INSERT INTO sys_menu VALUES (218, 213, '重新加载', '#', 'arrow-repeat', '/0/207/213/218', 'F', '', 'iot:device:refresh', '', 'btn btn-light-info', 'handleRefresh', 5, 0, 0, 0, 1, 1, '2024-03-28 16:46:19.055', '2024-04-01 09:09:56.511', NULL);
+
+INSERT INTO sys_api VALUES (222, 'IotAdmin/app/iot/apis.(*IotGroupApi).GetPage-fm', '获取分组列表', '/api/iot-group', 'GET', 'BUS', 0, 0, '2024-03-28 16:46:11.552', '2024-04-01 09:09:56.520', NULL);
+INSERT INTO sys_api VALUES (223, 'IotAdmin/app/iot/apis.(*IotGroupApi).Get-fm', '获取分组详情', '/api/iot-group/:id', 'GET', 'BUS', 0, 0, '2024-03-28 16:46:11.671', '2024-04-01 09:09:56.520', NULL);
+INSERT INTO sys_api VALUES (224, 'IotAdmin/app/iot/apis.(*IotGroupApi).Insert-fm', '添加分组', '/api/iot-group', 'POST', 'BUS', 0, 0, '2024-03-28 16:46:12.207', '2024-04-01 09:09:56.520', NULL);
+INSERT INTO sys_api VALUES (225, 'IotAdmin/app/iot/apis.(*IotGroupApi).Update-fm', '修改分组', '/api/iot-group/:id', 'PUT', 'BUS', 0, 0, '2024-03-28 16:46:12.497', '2024-04-01 09:09:56.520', NULL);
+INSERT INTO sys_api VALUES (226, 'IotAdmin/app/iot/apis.(*IotGroupApi).Delete-fm', '删除分组', '/api/iot-group', 'DELETE', 'BUS', 0, 0, '2024-03-28 16:46:12.805', '2024-04-01 09:09:56.520', NULL);
+INSERT INTO sys_api VALUES (227, 'IotAdmin/app/iot/apis.(*IotDeviceApi).GetPage-fm', '获取设备列表', '/api/iot-device', 'GET', 'BUS', 0, 0, '2024-03-28 16:46:17.477', '2024-04-01 09:09:56.520', NULL);
+INSERT INTO sys_api VALUES (228, 'IotAdmin/app/iot/apis.(*IotDeviceApi).Get-fm', '获取设备详情', '/api/iot-device/:id', 'GET', 'BUS', 0, 0, '2024-03-28 16:46:17.570', '2024-04-01 09:09:56.520', NULL);
+INSERT INTO sys_api VALUES (229, 'IotAdmin/app/iot/apis.(*IotDeviceApi).Insert-fm', '添加设备', '/api/iot-device', 'POST', 'BUS', 0, 0, '2024-03-28 16:46:18.204', '2024-04-01 09:09:56.520', NULL);
+INSERT INTO sys_api VALUES (230, 'IotAdmin/app/iot/apis.(*IotDeviceApi).Update-fm', '修改设备', '/api/iot-device/:id', 'PUT', 'BUS', 0, 0, '2024-03-28 16:46:18.606', '2024-04-01 09:09:56.520', NULL);
+INSERT INTO sys_api VALUES (231, 'IotAdmin/app/iot/apis.(*IotDeviceApi).Delete-fm', '删除设备', '/api/iot-device', 'DELETE', 'BUS', 0, 0, '2024-03-28 16:46:18.950', '2024-04-01 09:09:56.520', NULL);
+INSERT INTO sys_api VALUES (232, 'IotAdmin/app/iot/apis.(*IotDeviceApi).Refresh-fm', '重新加载设备', '/api/iot-device/refresh', 'POST', 'BUS', 0, 0, '2024-03-28 16:46:18.950', '2024-04-01 09:09:56.520', NULL);
+INSERT INTO sys_api VALUES (233, 'IotAdmin/app/iot/apis.(*IotDeviceApi).GetDeviceProtocols-fm', '获取表计协议列表', '/api/iot-device/device-protocol', 'GET', 'BUS', 0, 0, '2024-03-28 16:46:18.950', '2024-04-01 09:09:56.520', NULL);
+INSERT INTO sys_api VALUES (234, 'IotAdmin/app/iot/apis.(*IotDeviceApi).GetReportProtocols-fm', '获取上报协议列表', '/api/iot-device/report-protocol', 'GET', 'BUS', 0, 0, '2024-03-28 16:46:18.950', '2024-04-01 09:09:56.520', NULL);
+
+INSERT INTO sys_menu_api VALUES (208, 222);
+INSERT INTO sys_menu_api VALUES (209, 222);
+INSERT INTO sys_menu_api VALUES (208, 223);
+INSERT INTO sys_menu_api VALUES (209, 223);
+INSERT INTO sys_menu_api VALUES (210, 224);
+INSERT INTO sys_menu_api VALUES (211, 225);
+INSERT INTO sys_menu_api VALUES (212, 226);
+INSERT INTO sys_menu_api VALUES (213, 227);
+INSERT INTO sys_menu_api VALUES (214, 227);
+INSERT INTO sys_menu_api VALUES (213, 228);
+INSERT INTO sys_menu_api VALUES (214, 228);
+INSERT INTO sys_menu_api VALUES (215, 229);
+INSERT INTO sys_menu_api VALUES (216, 230);
+INSERT INTO sys_menu_api VALUES (217, 231);
+INSERT INTO sys_menu_api VALUES (218, 232);
+INSERT INTO sys_menu_api VALUES (213, 233);
+INSERT INTO sys_menu_api VALUES (214, 233);
+INSERT INTO sys_menu_api VALUES (213, 234);
+INSERT INTO sys_menu_api VALUES (214, 234);
+
 
 
 
@@ -377,6 +424,14 @@ INSERT INTO sys_dict_type VALUES (21, '设备模式', 'iot_device_mode', '2', ''
 INSERT INTO sys_dict_data VALUES (53, 1, '下发指令查询', '1', 'iot_device_mode', '', 'primary', '', '2', '', '新增操作', 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
 INSERT INTO sys_dict_data VALUES (54, 2, '表计主动上报', '2', 'iot_device_mode', '', 'success', '', '2', '', '修改操作', 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
 
+INSERT INTO sys_dict_type VALUES (20, '设备类型', 'iot_device_type', 2, '', 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
+INSERT INTO sys_dict_data VALUES (51, 1, '网关', '1', 'iot_device_type', '', 'primary', '', 2, '', '新增操作', 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
+INSERT INTO sys_dict_data VALUES (52, 2, '表计', '2', 'iot_device_type', '', 'success', '', 2, '', '修改操作', 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
+
+INSERT INTO sys_dict_type VALUES (21, '设备模式', 'iot_device_mode', 2, '', 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
+INSERT INTO sys_dict_data VALUES (53, 1, '下发指令查询', '1', 'iot_device_mode', '', 'primary', '', 2, '', '新增操作', 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
+INSERT INTO sys_dict_data VALUES (54, 2, '表计主动上报', '2', 'iot_device_mode', '', 'success', '', 2, '', '修改操作', 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
+
 
 
 INSERT INTO sys_job VALUES (1, '接口测试', 'SYSTEM', 1, '0/5 * * * * ', 'http://localhost:6071', '', 1, 1, 1, 0, 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
@@ -389,7 +444,7 @@ INSERT INTO sys_post VALUES (1, '默认岗位', 'CEO', 0, '2','默认岗位', 1,
 
 INSERT INTO sys_org VALUES (1, 0, '/0/1/', '物联网设备管理平台', 0, 'aituo', '13782218188', 'atuo@aituo.com', '2', 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
 INSERT INTO sys_org VALUES (2, 1, '/0/1/2/', '中科轼峰设备管理平台', 1, 'aituo', '13782218188', 'atuo@aituo.com', '2', 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
-INSERT INTO sys_org VALUES (3, 1, '/0/1/3/', '测试平台', 2, 'aituo', '13782218188', 'atuo@aituo.com', '2', 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
+INSERT INTO sys_org VALUES (3, 1, '/0/2/3/', '测试平台', 2, 'aituo', '13782218188', 'atuo@aituo.com', '2', 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
 INSERT INTO sys_org VALUES (4, 1, '/0/1/4/', '测试平台2', 3, 'aituo', '13782218188', 'atuo@aituo.com', '2', 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
 INSERT INTO sys_org VALUES (5, 1, '/0/1/5/', '测试平台3', 4, 'aituo', '13782218188', 'atuo@aituo.com', '1', 1, 1, '2024-03-14 00:00:00.000', '2024-03-14 00:00:00.000', NULL);
 

+ 10 - 0
SERVER/IotAdmin/core/sdk/pkg/security.go

@@ -61,6 +61,16 @@ func GenerateRandomKey4() string {
 	return generateRandString(4, number)
 }
 
+func GenerateRandomSymbol(length int) string {
+	return generateRandString(length, symbol)
+}
+func GenerateRandomLetter(length int) string {
+	return generateRandString(length, letter)
+}
+func GenerateRandomNumber(length int) string {
+	return generateRandString(length, number)
+}
+
 // SetPassword 根据明文密码和加盐值生成密码
 func SetPassword(password string, salt string) (verify string, err error) {
 	var rb []byte

+ 12 - 8
SERVER/IotAdmin/iot/db/device.go

@@ -17,6 +17,7 @@ import (
 
 // LoadDtuDeviceMap 加载DTU设备
 func LoadDtuDeviceMap() error {
+	iotMap.MapDtuDevice.Clean()
 	deviceArr := make([]models.IotDevice, 0)
 	for _, db := range dbMap {
 		gatewayArr := make([]models.IotDevice, 0)
@@ -35,7 +36,6 @@ func LoadDtuDeviceMap() error {
 }
 
 func loadDtuDeviceMap(db *gorm.DB, arr *[]models.IotDevice) error {
-	iotMap.MapDtuDevice.Clean()
 	if len(*arr) == 0 {
 		return nil
 	}
@@ -59,7 +59,7 @@ func addDtuDevice(db *gorm.DB, device models.IotDevice) error {
 	children := make([]models.IotDevice, 0)
 	db.Model(&models.IotDevice{}).Select("id,sn,dsn,protocol,address,bm_yz,other_config").Where("parent_id = ?", device.Id).Find(&children)
 	if len(children) == 0 {
-		return errors.New("children is nil")
+		return nil
 	}
 	cfg := device.ToDtuConfig(&children)
 	var dtu = &iotStruct.DtuDevice{
@@ -116,11 +116,15 @@ func DtuDeviceChange(message storage.Message) (err error) {
 		err = fmt.Errorf("json Unmarshal error,%s, %v", string(rb), err.Error())
 		return err
 	}
-	device := &models.IotDevice{}
-	err = db.Model(device).Where("id = ?", val.Id).Find(device).Error
-	if err != nil {
-		return
+	if val.Id == 0 {
+		err = LoadDtuDeviceMap()
+	} else {
+		device := &models.IotDevice{}
+		err = db.Model(device).Where("id = ?", val.Id).Find(device).Error
+		if err != nil {
+			return
+		}
+		err = addDtuDevice(db, *device)
 	}
-	err = addDtuDevice(db, *device)
-	return err
+	return
 }

+ 2 - 2
SERVER/IotAdmin/iot/service/downService/service.go

@@ -23,7 +23,6 @@ func NewDownStreamService() {
 	server := tcpserver.New(fmt.Sprintf(":%d", config.ApplicationConfig.TcpPort))
 	server.OnNewClient(func(conn *tcpserver.Client) {
 		logger.Infof("新设备连接:%s", conn.GetClientHost())
-
 	})
 	server.OnNewMessage(func(conn *tcpserver.Client, msg []byte) {
 		//logger.Debugf("[%s]收到新消息:%s", conn.GetClientHost(), string(msg))
@@ -78,6 +77,8 @@ func dealDtuRegisterHeartBeat(conn *tcpserver.Client, dtuMsg *iotStruct.DTUManag
 			iotMap.MapDtuClient.Add(dtuMsg.SN, clientState)
 		}
 		if dtuMsg.Cmd == iotStruct.CmdRegister {
+			// 设备上线
+			UpdateDtuStatus(dtuMsg.SN, constant.IotDeviceOnline)
 			logger.Infof("======【%s】====== Register  %s", dtuMsg.SN, conn.GetClientHost())
 		}
 		if dtuMsg.Cmd == iotStruct.CmdHeartBeat {
@@ -121,7 +122,6 @@ func runTran(msg <-chan *iotStruct.DtuRegisterChanMsg) {
 func updateOnlineConf(msg *iotStruct.DtuRegisterChanMsg) {
 	if dtu, ok := iotMap.MapDtuDevice.Get(msg.Sn); ok {
 		msg.Value.Config = dtu.Config
-		UpdateDtuStatus(msg.Sn, constant.IotDeviceOnline)
 		iotMap.MapDtuClient.Add(msg.Sn, msg.Value)
 		logger.Debugf("[%s]设备上线:%s ;配置:  %v", msg.Value.FD.GetClientHost(), msg.Sn, dtu.Config)
 	} else {

+ 1 - 0
SERVER/IotAdmin/template/v4/vue-view.go.template

@@ -291,6 +291,7 @@ const opts = reactive<any>({
     {{- end }}
 
 ] as any,
+    modalTitle: "{{.FunctionName}}",
     resetForm: () => {
         form.value = emptyFormData.value
     },

+ 1 - 1
UI/IOTADMIN.VUE/src/api/_sys.ts

@@ -57,7 +57,7 @@ class sysApi {
 			url: "/sys/role-menu-tree-select/0"
 		})
 	}
-	// 根据角色ID查询部门树结构
+	// 根据角色ID查询组织机构树结构
 	roleOrgTreeSelect = (roleId: string) => {
 		return Rs.get({
 			url: "/sys/role-org-tree-select/" + roleId,

+ 48 - 40
UI/IOTADMIN.VUE/src/api/iot/_device.ts

@@ -1,46 +1,54 @@
 import Rs from "@@/services/RequestService"
 
 class deviceApi {
-  // 查询Device列表
-  listDevice = (query: any) => {
-    return Rs.get({
-        url: '/iot-device',
-        params: query
-    })
-  }
-
-  // 查询Device详细
-  getDevice = (id: any) => {
-    return Rs.get({
-        url: '/iot-device/' + id,
-    })
-  }
-
-
-  // 新增Device
-  addDevice = (data: any) => {
-    return Rs.post({
-        url: '/iot-device',
-        data: data
-    })
-  }
-
-  // 修改Device
-  updateDevice = (data: any) => {
-    return Rs.put({
-        url: '/iot-device/'+data.id,
-        data: data
-    })
-  }
-
-  // 删除Device
-  delDevice = (ids: any) => {
-    return Rs.del({
-        url: '/iot-device',
-        data: { ids }
-    })
-  }
-
+	// 查询Device列表
+	listDevice = (query: any) => {
+		return Rs.get({
+			url: "/iot-device",
+			params: query
+		})
+	}
+
+	// 查询Device详细
+	getDevice = (id: any) => {
+		return Rs.get({
+			url: "/iot-device/" + id
+		})
+	}
+
+	// 新增Device
+	addDevice = (data: any) => {
+		return Rs.post({
+			url: "/iot-device",
+			data: data
+		})
+	}
+
+	// 修改Device
+	updateDevice = (data: any) => {
+		return Rs.put({
+			url: "/iot-device/" + data.id,
+			data: data
+		})
+	}
+
+	// 删除Device
+	delDevice = (ids: any) => {
+		return Rs.del({
+			url: "/iot-device",
+			data: { ids }
+		})
+	}
+	getDeviceProtocols = () => {
+		return Rs.get({
+			url: "/iot-device/device-protocols"
+		})
+	}
+	getReportProtocols = () => {
+		return Rs.get({
+			url: "/iot-device/report-protocols"
+		})
+	}
 }
 
 export default deviceApi

+ 7 - 7
UI/IOTADMIN.VUE/src/api/system/_org.ts

@@ -1,7 +1,7 @@
 import Rs from "@@/services/RequestService"
 
 class orgApi {
-	// 查询部门列表
+	// 查询组织机构列表
 	listOrg = (query?: any) => {
 		return Rs.get({
 			url: "/sys-org",
@@ -10,22 +10,22 @@ class orgApi {
 		})
 	}
 
-	// 查询部门详细
+	// 查询组织机构详细
 	getOrg = (orgId: string) => {
 		return Rs.get({
 			url: "/sys-org/" + orgId
 		})
 	}
 
-	// 新增部门
+	// 新增组织机构
 	addOrg = (data: any) => {
 		return Rs.post({
-			url: "/org",
+			url: "/sys-org",
 			data
 		})
 	}
 
-	// 修改部门
+	// 修改组织机构
 	updateOrg = (data: any) => {
 		return Rs.put({
 			url: "/sys-org/" + data.orgId,
@@ -33,10 +33,10 @@ class orgApi {
 		})
 	}
 
-	// 删除部门
+	// 删除组织机构
 	delOrg = (orgId: number | number[]) => {
 		return Rs.del({
-			url: "/org",
+			url: "/sys-org",
 			data: {
 				ids: orgId
 			}

+ 1 - 1
UI/IOTADMIN.VUE/src/components/tree/OrgTree.vue

@@ -57,7 +57,7 @@ watch(
 </script>
 <template>
 	<div :class="treeBoxClass" :style="treeBoxStyle">
-		<!-- <el-input v-model="searchWords" placeholder="请输入部门名称" clearable prefix-icon="Search" /> -->
+		<!-- <el-input v-model="searchWords" placeholder="请输入组织机构名称" clearable prefix-icon="Search" /> -->
 		<el-tree
 			class="pt-3"
 			ref="treeRef"

+ 1 - 1
UI/IOTADMIN.VUE/src/views/account/profile/index.vue

@@ -51,7 +51,7 @@ onMounted(init)
 							<dl>
 								<dt>
 									<i class="text-dark me-1 bi bi-briefcase-fill"></i>
-									所属部门
+									所属组织机构
 								</dt>
 								<dd>{{ user.org?.orgName }} / {{ user.postGroup }}</dd>
 							</dl>

+ 85 - 81
UI/IOTADMIN.VUE/src/views/iot/device/_gateway.vue

@@ -1,22 +1,26 @@
-<script setup lang="ts" name="Device">
+<script setup lang="ts" name="Gateway">
 import apis from "@a"
 import message from "@@/utils/message"
 import dayjs from "dayjs"
-const emits = defineEmits<{ (e: "change", v: number): void }>()
+// const props = withDefaults(
+// 	defineProps<{
+// 		queryMeter: (v: number) => void
+// 	}>(),
+// 	{}
+// )
+const emits = defineEmits<{
+	(e: "query-meter", v: number): void
+	(e: "create-meter", v: number): void
+}>()
 const groupIdOptions = ref<any[]>([])
-const protocolOptions = computed(() => {
-	return [
-		{ label: "请选择", value: "" },
-		{ label: "", value: "" }
-	]
-})
+
 const onlineStatusOptions = computed(() => {
 	return [
-		{ label: "在线", value: 1, class: "success" },
-		{ label: "离线", value: 2, class: "danger" }
+		{ label: "在线", value: 2, type: "success" },
+		{ label: "离线", value: 1, type: "danger" }
 	]
 })
-
+const isAdd = ref(false)
 const tableRef = ref()
 const modalRef = ref()
 const opts = reactive<any>({
@@ -42,7 +46,7 @@ const opts = reactive<any>({
 	searchFormItems: [
 		{
 			field: "groupId",
-			label: "分组ID",
+			label: "设备分组",
 			class: "w-100",
 			component: "VS",
 			data: () => groupIdOptions.value,
@@ -84,19 +88,25 @@ const opts = reactive<any>({
 		}
 	] as any,
 	permission: "iot:device",
-	handleFuns: {},
+	handleFuns: {
+		handleCreate
+	},
 	customBtns: [],
 	tableListFun: apis.iot.deviceApi.listDevice,
 	getEntityFun: apis.iot.deviceApi.getDevice,
 	deleteEntityFun: apis.iot.deviceApi.delDevice,
 	formItems: [
 		{
-			field: "parentId",
-			label: "父分组",
+			show: () => !isAdd.value,
+			field: "sn",
+			label: "设备编码",
 			class: "w-100",
 			component: "I",
-			type: "number",
-			required: false
+			required: true,
+			props: {
+				disabled: true
+			},
+			span: 24
 		},
 		{
 			field: "groupId",
@@ -114,49 +124,17 @@ const opts = reactive<any>({
 					label: "name",
 					value: "id"
 				}
-			}
-		},
-		{
-			field: "sn",
-			label: "设备编码",
-			class: "w-100",
-			component: "I",
-			required: true
+			},
+			span: 24
 		},
+
 		{
 			field: "name",
 			label: "设备名称",
 			class: "w-100",
 			component: "I",
-			required: true
-		},
-		{
-			field: "type",
-			label: "设备类型",
-			class: "w-100",
 			required: true,
-			component: "Dict",
-			props: {
-				type: "radio",
-				valueIsNumber: true,
-				clearable: true,
-				placeholder: "请选择设备类型",
-				dictType: "iot_device_type"
-			}
-		},
-		{
-			field: "mode",
-			label: "设备模式",
-			class: "w-100",
-			required: false,
-			component: "Dict",
-			props: {
-				type: "radio",
-				valueIsNumber: true,
-				clearable: true,
-				placeholder: "请选择设备模式",
-				dictType: "iot_device_mode"
-			}
+			span: 24
 		},
 		{
 			field: "cycle",
@@ -164,47 +142,30 @@ const opts = reactive<any>({
 			class: "w-100",
 			component: "I",
 			type: "number",
-			required: true
+			required: true,
+			span: 24
 		},
 		{
 			field: "description",
 			label: "设备描述",
 			class: "w-100",
 			component: "I",
-			required: false
-		},
-		{
-			field: "protocol",
-			label: "表计协议",
-			class: "w-100",
+			type: "textarea",
 			required: false,
-			component: "VS",
-			placeholder: "请选择表计协议",
-			data: () => protocolOptions.value,
-			props: {
-				type: "select",
-				clearable: true
-			}
-		},
-		{
-			field: "address",
-			label: "表计地址",
-			class: "w-100",
-			component: "I",
-			type: "number",
-			required: true
+			span: 24
 		}
 	] as any,
 	resetForm: () => {
 		form.value = emptyFormData.value
 	},
+	modalTitle: "网关",
 	emptyFormData: {
 		id: undefined,
-		parentId: undefined,
+		parentId: 0,
 		groupId: undefined,
 		sn: undefined,
 		name: undefined,
-		type: undefined,
+		type: 1,
 		mode: undefined,
 		cycle: undefined,
 		description: undefined,
@@ -215,8 +176,16 @@ const opts = reactive<any>({
 const { queryParams, emptyFormData } = toRefs(opts)
 const form = ref<any>(emptyFormData.value)
 
+/** 添加按钮操作 */
+function handleCreate() {
+	opts.resetForm()
+	isAdd.value = true
+	modalRef.value.changePrefixTitle("添加")
+	modalRef.value.show()
+}
 /** 修改按钮操作 */
 function handleUpdate(row: any) {
+	isAdd.value = false
 	tableRef.value.defaultHandleFuns.handleUpdate("", row)
 }
 /** 删除按钮操作 */
@@ -228,11 +197,13 @@ function submitForm() {
 	if (form.value.id != undefined) {
 		apis.iot.deviceApi.updateDevice(form.value).then(() => {
 			message.msgSuccess("修改成功")
+			queryParams.value.orgId = undefined
 			handleQuery()
 		})
 	} else {
 		apis.iot.deviceApi.addDevice(form.value).then(() => {
 			message.msgSuccess("新增成功")
+			queryParams.value.orgId = undefined
 			handleQuery()
 		})
 	}
@@ -241,6 +212,19 @@ function submitForm() {
 function handleQuery() {
 	addDateRange(queryParams.value, queryParams.value.dateRange)
 	tableRef.value?.search()
+	let count = 0
+	let timer: any = 0
+	function handle() {
+		const row = tableRef.value?.getData()[0]
+		if (row) {
+			clearTimeout(timer)
+			emits("query-meter", row.id)
+		} else if (count < 50) {
+			count++
+			timer = setTimeout(handle, 100)
+		}
+	}
+	handle()
 }
 /** 查询重置按钮 */
 function resetQuery() {
@@ -248,15 +232,24 @@ function resetQuery() {
 	addDateRange(queryParams.value, queryParams.value.dateRange)
 }
 
+function handleCreateMeter(row: any) {
+	emits("create-meter", row.id)
+}
 function init() {
 	apis.iot.groupApi.listGroup({ pageSize: 10000, pageIndex: 1 }).then((res) => {
 		groupIdOptions.value = res.data.rows
 	})
 }
 function onRowClick(row: any) {
-	emits("change", row.id)
+	emits("query-meter", row.id)
+}
+
+function query(orgId: number) {
+	queryParams.value.orgId = orgId
+	handleQuery()
 }
 onMounted(init)
+defineExpose({ query })
 </script>
 
 <template>
@@ -295,11 +288,15 @@ onMounted(init)
 				<VbTag valueIsNumber :value="row.onlineStatus" :data="onlineStatusOptions"></VbTag>
 			</template>
 			<template #timeOnline="{ row }">
-				<span>{{ row.timeOnline ? "" : dayjs(row.timeOnline).format("YYYY-MM-DD HH:mm:ss") }}</span>
+				<span :class="{ 'text-success': row.onlineStatus == 2 }">
+					{{ row.timeOnline.Valid ? dayjs(row.timeOnline.Time).format("YYYY-MM-DD HH:mm:ss") : "" }}
+				</span>
 			</template>
 			<template #timeOffline="{ row }">
-				<span>
-					{{ row.timeOffline ? "" : dayjs(row.timeOffline).format("YYYY-MM-DD HH:mm:ss") }}
+				<span :class="{ 'text-danger': row.onlineStatus == 1 }">
+					{{
+						row.timeOffline.Valid ? dayjs(row.timeOffline.Time).format("YYYY-MM-DD HH:mm:ss") : ""
+					}}
 				</span>
 			</template>
 			<template #createdAt="{ row }">
@@ -328,6 +325,13 @@ onMounted(init)
 						</template>
 					</el-button>
 				</vb-tooltip>
+				<vb-tooltip content="新增表计" placement="top">
+					<el-button link type="danger" @click="handleCreateMeter(row)">
+						<template #icon>
+							<VbIcon icon-name="plus-square" icon-type="duotone" class="fs-3"></VbIcon>
+						</template>
+					</el-button>
+				</vb-tooltip>
 			</template>
 		</VbDataTable>
 		<VbModal

+ 218 - 97
UI/IOTADMIN.VUE/src/views/iot/device/_meter.vue

@@ -1,31 +1,29 @@
-<script setup lang="ts" name="Device">
+<script setup lang="ts" name="Meter">
 import apis from "@a"
 import message from "@@/utils/message"
 import dayjs from "dayjs"
 
 const props = withDefaults(defineProps<{ id: number }>(), { id: 0 })
-
-const groupIdOptions = ref<any[]>([])
-const protocolOptions = computed(() => {
-	return [
-		{ label: "请选择", value: "" },
-		{ label: "", value: "" }
-	]
-})
-
+const { id: parentId } = toRefs(props)
+const protocolOptions = ref<any[]>([])
+const reportProtocolOptions = ref<any[]>([])
+const isAdd = ref(false)
 const tableRef = ref()
 const modalRef = ref()
 const opts = reactive<any>({
 	columns: [
 		{ field: "id", name: "ID", width: 100, visible: false, isSort: false, tooltip: true },
 		{ field: "sn", name: "设备编码", width: "auto", isSort: true, visible: true },
-		{ field: "name", name: "设备名称", width: "auto", isSort: true, visible: true },
-		{ field: "type", name: "设备类型", width: 100, isSort: true, visible: true },
-		{ field: "mode", name: "设备模式", width: 180, isSort: false, visible: true },
+		{ field: "name", name: "表计名称", width: "auto", isSort: true, visible: true },
+		// { field: "type", name: "设备类型", width: 100, isSort: true, visible: true },
+		{ field: "protocol", name: "表计协议", width: 200, isSort: true, visible: true },
+		{ field: "address", name: "表计串口地址", width: 130, isSort: false, visible: true },
+		// { field: "mode", name: "设备模式", width: 180, isSort: false, visible: true },
 		{ field: "createdAt", name: "创建时间", width: 185, isSort: true, visible: true },
 		{ field: "actions", name: `操作`, width: 150 }
 	],
 	queryParams: {
+		parentId: parentId.value,
 		sn: undefined,
 		name: undefined,
 		type: 2,
@@ -58,18 +56,6 @@ const opts = reactive<any>({
 				}
 			}
 		},
-		{
-			field: "type",
-			label: "设备类型",
-			class: "w-100",
-			component: "Dict",
-			props: {
-				type: "radio",
-				placeholder: "请选择设备类型",
-				dictType: "iot_device_type",
-				valueIsNumber: true
-			}
-		},
 		{
 			field: "dateRange",
 			label: "创建时间",
@@ -90,7 +76,7 @@ const opts = reactive<any>({
 			}
 		}
 	] as any,
-	permission: "iot:device",
+	permission: "",
 	handleFuns: {},
 	customBtns: [],
 	tableListFun: apis.iot.deviceApi.listDevice,
@@ -98,100 +84,55 @@ const opts = reactive<any>({
 	deleteEntityFun: apis.iot.deviceApi.delDevice,
 	formItems: [
 		{
-			field: "parentId",
-			label: "父分组",
-			class: "w-100",
-			component: "I",
-			type: "number",
-			required: false
-		},
-		{
-			field: "groupId",
-			label: "设备分组",
-			class: "w-100",
-			required: true,
-			component: "VS",
-			data: () => groupIdOptions.value,
-			props: {
-				type: "select",
-				valueIsNumber: true,
-				clearable: true,
-				placeholder: "请选择分组",
-				props: {
-					label: "name",
-					value: "id"
-				}
-			}
-		},
-		{
+			show: () => !isAdd.value,
 			field: "sn",
 			label: "设备编码",
 			class: "w-100",
 			component: "I",
-			required: true
-		},
-		{
-			field: "name",
-			label: "设备名称",
-			class: "w-100",
-			component: "I",
-			required: true
-		},
-		{
-			field: "type",
-			label: "设备类型",
-			class: "w-100",
 			required: true,
-			component: "Dict",
 			props: {
-				type: "radio",
-				valueIsNumber: true,
-				clearable: true,
-				placeholder: "请选择设备类型",
-				dictType: "iot_device_type"
-			}
+				disabled: true
+			},
+			span: 24
 		},
 		{
+			show: false,
 			field: "mode",
 			label: "设备模式",
 			class: "w-100",
 			required: false,
 			component: "Dict",
 			props: {
+				disabled: true,
 				type: "radio",
 				valueIsNumber: true,
 				clearable: true,
 				placeholder: "请选择设备模式",
 				dictType: "iot_device_mode"
-			}
-		},
-		{
-			field: "cycle",
-			label: "上报周期",
-			class: "w-100",
-			component: "I",
-			type: "number",
-			required: true
+			},
+			span: 24
 		},
 		{
-			field: "description",
-			label: "设备描述",
+			field: "name",
+			label: "设备名称",
 			class: "w-100",
 			component: "I",
-			required: false
+			required: true,
+			span: 24
 		},
 		{
 			field: "protocol",
 			label: "表计协议",
 			class: "w-100",
-			required: false,
+			required: true,
 			component: "VS",
 			placeholder: "请选择表计协议",
 			data: () => protocolOptions.value,
 			props: {
 				type: "select",
 				clearable: true
-			}
+			},
+			span: 12
 		},
 		{
 			field: "address",
@@ -199,31 +140,84 @@ const opts = reactive<any>({
 			class: "w-100",
 			component: "I",
 			type: "number",
-			required: true
+			required: true,
+			span: 12
+		},
+		{
+			field: "dsn",
+			label: "平台上报",
+			class: "w-100",
+			component: "slot",
+			span: 24
+		},
+		{
+			field: "bmYz",
+			label: "编码因子",
+			class: "w-100",
+			component: "I",
+			type: "textarea",
+			required: false
+		},
+		{
+			field: "description",
+			label: "设备描述",
+			class: "w-100",
+			component: "I",
+			type: "textarea",
+			required: false
 		}
 	] as any,
+	modalTitle: "表计",
 	resetForm: () => {
 		form.value = emptyFormData.value
 	},
 	emptyFormData: {
 		id: undefined,
-		parentId: undefined,
+		parentId: parentId.value,
 		groupId: undefined,
 		sn: undefined,
 		name: undefined,
-		type: undefined,
+		type: 2,
 		mode: undefined,
-		cycle: undefined,
-		description: undefined,
+		reportConfig: [
+			{
+				host: "",
+				protocol: "",
+				st: "",
+				mn: "",
+				user: "",
+				pwd: ""
+			}
+		],
 		protocol: undefined,
-		address: undefined
+		address: undefined,
+		bmYz: undefined,
+		description: undefined
 	}
 })
 const { queryParams, emptyFormData } = toRefs(opts)
-const form = ref<any>(emptyFormData.value)
+const form = ref<any>(Object.assign({}, emptyFormData.value))
+
+function handleCreate(parentId: number) {
+	isAdd.value = true
+	form.value.parentId = parentId
+	form.value.reportConfig = [
+		{
+			host: "",
+			protocol: "",
+			st: "",
+			mn: "",
+			user: "",
+			pwd: ""
+		}
+	]
+	modalRef.value.changePrefixTitle("添加")
+	modalRef.value.show()
+}
 
 /** 修改按钮操作 */
 function handleUpdate(row: any) {
+	isAdd.value = false
 	tableRef.value.defaultHandleFuns.handleUpdate("", row)
 }
 /** 删除按钮操作 */
@@ -255,20 +249,56 @@ function resetQuery() {
 	addDateRange(queryParams.value, queryParams.value.dateRange)
 }
 
-function init() {
-	apis.iot.groupApi.listGroup({ pageSize: 10000, pageIndex: 1 }).then((res) => {
-		groupIdOptions.value = res.data.rows
+function handelAddReportConfig() {
+	form.value.reportConfig.push({
+		host: "",
+		protocol: "",
+		st: "",
+		mn: "",
+		user: "",
+		pwd: ""
+	})
+}
+
+function handelRemoveReportConfig(index: number) {
+	message.confirm("是否确认删除第" + (index + 1) + "条上报配置?", "删除配置").then(() => {
+		form.value.reportConfig.splice(index, 1)
 	})
 }
 
+function init() {
+	apis.iot.deviceApi.getDeviceProtocols().then((res: any) => {
+		protocolOptions.value = res.data.map((v: any) => {
+			return {
+				label: v,
+				value: v
+			}
+		})
+	})
+	apis.iot.deviceApi.getReportProtocols().then((res: any) => {
+		reportProtocolOptions.value = res.data.map((v: any) => {
+			return {
+				label: v,
+				value: v
+			}
+		})
+	})
+}
+function createMeter(id: number) {
+	handleCreate(id)
+}
 onMounted(init)
 watch(
 	() => props.id,
 	(val: any) => {
+		parentId.value = val
 		queryParams.value.parentId = val
 		handleQuery()
 	}
 )
+defineExpose({
+	createMeter
+})
 </script>
 
 <template>
@@ -343,6 +373,97 @@ watch(
 			:form-items="opts.formItems as any"
 			:form-data="form"
 			@confirm="submitForm"
-			append-to-body></VbModal>
+			append-to-body>
+			<template #dsn_form="">
+				<div
+					class="w-100 px-5 mb-3"
+					v-for="(item, index) in form.reportConfig"
+					:key="index"
+					style="border: 2px solid var(--bs-primary); border-radius: 10px">
+					<div class="d-flex justify-content-between">
+						<span class="text-danger fw-bold">配置 {{ index + 1 }}</span>
+						<span>
+							<vb-tooltip
+								v-if="index === form.reportConfig.length - 1"
+								type="primary"
+								icon="ki-duotone ki-plus"
+								content="添加上报配置"
+								placement="top">
+								<el-button link type="primary" @click="handelAddReportConfig()">
+									<template #icon="">
+										<VbIcon icon-name="plus-square" icon-type="duotone" class="fs-3"></VbIcon>
+									</template>
+								</el-button>
+							</vb-tooltip>
+							<vb-tooltip
+								v-if="form.reportConfig.length > 1"
+								content="删除上报配置"
+								placement="top">
+								<el-button link type="primary" @click="handelRemoveReportConfig(index)">
+									<template #icon="">
+										<VbIcon icon-name="trash-square" icon-type="duotone" class="fs-3"></VbIcon>
+									</template>
+								</el-button>
+							</vb-tooltip>
+						</span>
+					</div>
+					<el-row :gutter="10">
+						<el-col :span="12">
+							<el-form-item
+								label="HOST"
+								:prop="`reportConfig.${index}.host`"
+								:rules="{ required: true, message: '请输入HOST(IP:端口)', trigger: 'blur' }">
+								<el-input
+									v-model="form.reportConfig[index].host"
+									@change="console.log('change', form)"
+									placeholder="请输入HOST(IP:端口)" />
+							</el-form-item>
+						</el-col>
+						<el-col :span="12">
+							<el-form-item
+								label="协议"
+								:prop="`reportConfig.${index}.protocol`"
+								:rules="{ required: true, message: '请选择上报协议', trigger: 'blur' }">
+								<el-select
+									v-model="form.reportConfig[index].protocol"
+									placeholder="请输入平台上报协议">
+									<el-option
+										v-for="(v, i) in reportProtocolOptions"
+										:label="v.label"
+										:value="v.value"
+										:key="i"></el-option>
+								</el-select>
+							</el-form-item>
+						</el-col>
+						<el-col :span="12">
+							<el-form-item
+								label="指令(ST)"
+								:prop="`reportConfig.${index}.st`"
+								:rules="{ required: true, message: '请输入平台指令', trigger: 'blur' }">
+								<el-input v-model="form.reportConfig[index].st" placeholder="请输入平台指令" />
+							</el-form-item>
+						</el-col>
+						<el-col :span="12">
+							<el-form-item
+								label="编码(MN)"
+								:prop="`reportConfig.${index}.mn`"
+								:rules="{ required: true, message: '请输入表计编码', trigger: 'blur' }">
+								<el-input v-model="form.reportConfig[index].mn" placeholder="请输入表计编码" />
+							</el-form-item>
+						</el-col>
+						<el-col :span="12">
+							<el-form-item label="用户" :prop="`reportConfig.${index}.user`">
+								<el-input v-model="form.reportConfig[index].user" placeholder="请输入平台用户" />
+							</el-form-item>
+						</el-col>
+						<el-col :span="12">
+							<el-form-item label="密码" :prop="`reportConfig.${index}.pwd`">
+								<el-input v-model="form.reportConfig[index].pwd" placeholder="请输入平台密码" />
+							</el-form-item>
+						</el-col>
+					</el-row>
+				</div>
+			</template>
+		</VbModal>
 	</div>
 </template>

+ 52 - 12
UI/IOTADMIN.VUE/src/views/iot/device/index.vue

@@ -1,22 +1,62 @@
 <script setup lang="ts" name="Device">
-import Gateway from "./_gateway"
-import Meter from "./_meter"
+import apis from "@a"
+import Gateway from "./_gateway.vue"
+import Meter from "./_meter.vue"
+import appStore from "@s"
+
+const orgTreeRef = ref()
+const gatewayRef = ref()
+const meterRef = ref()
+const orgOptions = ref<any[]>([])
+const orgId = ref(0)
 const id = ref(0)
-function onChange(data: number) {
-	id.value = data
+
+function handleQueryGateway() {
+	if (orgId.value) {
+		id.value = 0
+		gatewayRef.value?.query(orgId.value)
+	}
+}
+
+function handleQueryMeter(v: number) {
+	id.value = v
+}
+function handleCreateMeter(v: number) {
+	meterRef.value?.createMeter(v)
+}
+
+function init() {
+	apis.sysApi.orgTreeSelect(appStore.authStore.user.orgId).then((res) => {
+		orgOptions.value = res.data
+	})
 }
-function init() {}
 
 onMounted(init)
 </script>
 
 <template>
-	<div class="app-container d-flex flex-column" style="height: calc(100vh - 140px)">
-		<div class="w-100" style="height: 65%">
-			<Gateway @change="onChange" />
-		</div>
-		<div class="w-100" style="height: 35%">
-			<Meter :id="id"></Meter>
-		</div>
+	<div class="app-container d-flex flex-column">
+		<el-row :gutter="10">
+			<el-col v-if="orgOptions.length > 0 && orgOptions[0]?.children?.length" :span="4">
+				<OrgTree
+					ref="orgTreeRef"
+					v-model="orgId"
+					:data="orgOptions"
+					@node-click="handleQueryGateway"></OrgTree>
+			</el-col>
+			<el-col :span="orgOptions.length > 0 && orgOptions[0]?.children?.length ? 20 : 24">
+				<div class="w-100" style="height: calc(100vh - 140px)">
+					<div class="w-100" style="height: 65%">
+						<Gateway
+							ref="gatewayRef"
+							@create-meter="handleCreateMeter"
+							@query-meter="handleQueryMeter" />
+					</div>
+					<div class="w-100" style="height: 35%">
+						<Meter ref="meterRef" :id="id"></Meter>
+					</div>
+				</div>
+			</el-col>
+		</el-row>
 	</div>
 </template>

+ 23 - 1
UI/IOTADMIN.VUE/src/views/iot/group/index.vue

@@ -74,7 +74,9 @@ const opts = reactive<any>({
 		}
 	] as any,
 	permission: "iot:group",
-	handleFuns: {},
+	handleFuns: {
+		handleCreate
+	},
 	handleBtns: [
 		{
 			key: "handleUpdate",
@@ -121,6 +123,7 @@ const opts = reactive<any>({
 			type: "textarea"
 		}
 	] as any,
+	modalTitle: "分组",
 	resetForm: () => {
 		form.value = emptyFormData.value
 		getGroupTreeSelect()
@@ -135,6 +138,18 @@ const opts = reactive<any>({
 const { queryParams, emptyFormData } = toRefs(opts)
 const form = ref<any>(emptyFormData.value)
 
+/** 新增按钮操作 */
+function handleCreate(row?: any) {
+	opts.resetForm()
+	if (row != null && row.id) {
+		form.value.parentId = row.id
+	} else {
+		form.value.parentId = 0
+	}
+	modalRef.value.changePrefixTitle("添加")
+	modalRef.value.show()
+}
+
 /** 修改按钮操作 */
 function handleUpdate(row: any) {
 	tableRef.value.defaultHandleFuns.handleUpdate("", row)
@@ -215,6 +230,13 @@ onMounted(init)
 				<span>{{ dayjs(row.createdAt).format("YYYY-MM-DD HH:mm:ss") }}</span>
 			</template>
 			<template #actions="{ row }">
+				<vb-tooltip content="新增" placement="top">
+					<el-button link type="primary" @click="handleCreate(row)">
+						<template #icon>
+							<VbIcon icon-name="plus-square" icon-type="duotone" class="fs-3"></VbIcon>
+						</template>
+					</el-button>
+				</vb-tooltip>
 				<vb-tooltip content="修改" placement="top">
 					<el-button
 						link

+ 38 - 28
UI/IOTADMIN.VUE/src/views/system/org/index.vue

@@ -2,32 +2,35 @@
 import apis from "@a"
 import message from "@@/utils/message"
 import dayjs from "dayjs"
+import appStore from "@s"
 
 const { sys_normal_disable } = useDict("sys_normal_disable")
+const orgId = appStore.authStore.user.orgId
 const tableRef = ref()
 const modalRef = ref()
 const opts = reactive({
 	columns: [
-		{ field: "orgId", name: "部门编号", visible: false },
-		{ field: "orgName", name: "部门名称", visible: true },
+		{ field: "orgId", name: "组织机构编号", visible: false },
+		{ field: "orgName", name: "组织机构名称", visible: true },
 		{ field: "leader", name: "负责人", visible: true },
 		{ field: "phone", name: "联系电话", visible: true },
 		{ field: "email", name: "邮箱", visible: true },
-		{ field: "status", name: "部门状态", visible: true, width: 100 },
+		{ field: "status", name: "状态", visible: true, width: 100 },
 		{ field: "createdAt", name: "创建时间", visible: true, width: 185 },
 		{ field: "actions", name: `操作`, width: 150 }
 	],
 	queryParams: {
+		orgId: appStore.authStore.user.orgId,
 		orgName: undefined,
 		status: undefined
 	},
 	searchFormItems: [
 		{
 			field: "orgName",
-			label: "部门名称",
+			label: "组织名称",
 			class: "w-100",
 			required: false,
-			placeholder: "请输入部门名称",
+			placeholder: "请输入组织机构名称",
 			listeners: {
 				keyup: (e: KeyboardEvent) => {
 					if (e.code == "Enter") {
@@ -38,19 +41,23 @@ const opts = reactive({
 		},
 		{
 			field: "status",
-			label: "部门状态",
+			label: "组织状态",
 			class: "w-100",
 			required: false,
 			component: "Dict",
 			props: {
 				valueIsNumber: true,
-				placeholder: "请选择部门状态",
+				placeholder: "请选择组织机构状态",
 				dictType: "sys_normal_disable"
 			}
 		}
 	] as any,
 	permission: "system:org",
 	handleBtns: [
+		{
+			key: "handleCreate",
+			show: false
+		},
 		{
 			key: "handleUpdate",
 			show: false
@@ -60,22 +67,20 @@ const opts = reactive({
 			show: false
 		}
 	],
-	handleFuns: {
-		handleCreate
-	},
+	handleFuns: {},
 	customBtns: [],
 	tableListFun: apis.system.orgApi.listOrg,
 	getEntityFun: apis.system.orgApi.getOrg,
 	deleteEntityFun: apis.system.orgApi.delOrg,
 	exportName: "ORG",
-	modalTitle: "部门",
+	modalTitle: "组织机构",
 	resetForm: () => {
 		form.value = emptyFormData.value
-		getTreeSelect()
+		getOrgTreeSelect()
 	},
 	formRules: {
-		parentId: [{ required: true, message: "父部门不能为空", trigger: "blur" }],
-		orgName: [{ required: true, message: "部门名称不能为空", trigger: "blur" }],
+		parentId: [{ required: true, message: "父组织机构不能为空", trigger: "blur" }],
+		orgName: [{ required: true, message: "组织机构名称不能为空", trigger: "blur" }],
 		sort: [{ required: true, message: "显示排序不能为空", trigger: "blur" }],
 		email: [{ type: "email", message: "请输入正确的邮箱地址", trigger: ["blur", "change"] }],
 		phone: [
@@ -109,7 +114,7 @@ function resetQuery() {
 const orgOptions = ref<any>([])
 function reset() {
 	form.value = emptyFormData.value
-	getTreeSelect()
+	getOrgTreeSelect()
 }
 /** 新增按钮操作 */
 function handleCreate(row?: any) {
@@ -134,12 +139,12 @@ function handleUpdate(row: any) {
 		})
 	}
 }
-function getTreeSelect() {
+function getOrgTreeSelect() {
 	orgOptions.value = []
-	apis.system.orgApi.listOrg({ pageSize: 10000, pageIndex: 1 }).then((res) => {
-		const org: any = { orgId: 0, orgName: "主节点", children: [] }
-		org.children = res.data //handleTree(res.data, "orgId")
-		orgOptions.value.push(org)
+	apis.system.orgApi.listOrg({ orgId, pageSize: 10000, pageIndex: 1 }).then((res) => {
+		//const org: any = { orgId: 0, orgName: "主节点", children: [] }
+		//org.children = res.data //handleTree(res.data, "orgId")
+		orgOptions.value.push(...res.data)
 	})
 }
 /** 提交按钮 */
@@ -167,7 +172,7 @@ function handleDelete(rows: any[]) {
 	const ids = rows.map((v: any) => v.orgId)
 
 	message
-		.confirm('是否确认删除部门为"' + _orgNames + '"的数据项?')
+		.confirm('是否确认删除组织机构为"' + _orgNames + '"的数据项?')
 		.then(() => {
 			return apis.system.orgApi.delOrg(ids).then(() => {
 				handleQuery()
@@ -234,7 +239,11 @@ function getTableData(q: any) {
 					</el-button>
 				</vb-tooltip>
 				<vb-tooltip content="删除" placement="top">
-					<el-button link type="primary" @click="handleDelete([row])">
+					<el-button
+						v-if="row.parentId != 0 && row.orgId != orgId"
+						link
+						type="primary"
+						@click="handleDelete([row])">
 						<template #icon>
 							<VbIcon icon-name="trash-square" icon-type="duotone" class="fs-3"></VbIcon>
 						</template>
@@ -253,27 +262,28 @@ function getTableData(q: any) {
 			<template #form>
 				<el-row>
 					<el-col :span="24">
-						<el-form-item label="父部门" prop="parentId">
+						<el-form-item label="父组织机构" prop="parentId">
 							<el-tree-select
 								v-model="form.parentId"
 								:data="orgOptions"
 								:props="{ value: 'orgId', label: 'orgName', children: 'children' }"
 								class="w-100"
 								value-key="orgId"
+								disabled
 								:render-after-expand="false"
 								:default-expand-all="true"
-								placeholder="选择上级部门"
+								placeholder="选择上级组织机构"
 								check-strictly />
 						</el-form-item>
 					</el-col>
 					<el-col :span="12">
-						<el-form-item label="部门名称" prop="orgName">
-							<el-input v-model="form.orgName" placeholder="请输入部门名称" />
+						<el-form-item label="组织机构名" prop="orgName">
+							<el-input v-model="form.orgName" placeholder="请输入组织机构名称" />
 						</el-form-item>
 					</el-col>
 					<el-col :span="12">
 						<el-form-item label="显示顺序" prop="sort">
-							<el-input type="number" v-model="form.sort" placeholder="请输入显示顺序" />
+							<el-input type="number" v-model.number="form.sort" placeholder="请输入显示顺序" />
 						</el-form-item>
 					</el-col>
 					<el-col :span="12">
@@ -292,7 +302,7 @@ function getTableData(q: any) {
 						</el-form-item>
 					</el-col>
 					<el-col :span="12">
-						<el-form-item label="部门状态" prop="status">
+						<el-form-item label="组织机构状态" prop="status">
 							<el-radio-group v-model="form.status">
 								<el-radio
 									v-for="dict in sys_normal_disable"

+ 6 - 6
UI/IOTADMIN.VUE/src/views/system/role/index.vue

@@ -15,12 +15,12 @@ const dataScopeOptions = [
 		type: "primary"
 	},
 	{
-		label: "本部门数据",
+		label: "本组织机构数据",
 		value: "3",
 		type: "success"
 	},
 	{
-		label: "本部门及以下数据",
+		label: "本组织机构及以下数据",
 		value: "4",
 		type: "warning"
 	},
@@ -389,7 +389,7 @@ function getRoleMenuTreeSelect(roleId: string) {
 		return data
 	})
 }
-/** 根据角色ID查询部门树结构 */
+/** 根据角色ID查询组织机构树结构 */
 function getOrgTree(roleId: string) {
 	return apis.sysApi.roleOrgTreeSelect(roleId).then(({ data }) => {
 		orgOptions.value = data.orgs
@@ -435,12 +435,12 @@ function getMenuAllCheckedKeys() {
 	checkedKeys.unshift(...halfCheckedKeys)
 	return checkedKeys
 }
-/** 所有部门节点数据 */
+/** 所有组织机构节点数据 */
 function getOrgAllCheckedKeys() {
 	if (orgRef.value) {
-		// 目前被选中的部门节点
+		// 目前被选中的组织机构节点
 		const checkedKeys = orgRef.value.getCheckedKeys()
-		// 半选中的部门节点
+		// 半选中的组织机构节点
 		const halfCheckedKeys = orgRef.value.getHalfCheckedKeys()
 		checkedKeys.unshift(...halfCheckedKeys)
 		return checkedKeys

+ 4 - 4
UI/IOTADMIN.VUE/src/views/system/user/index.vue

@@ -21,7 +21,7 @@ const tableOpts = reactive({
 		{ field: "userId", name: `用户编号`, width: 85 },
 		{ field: "userName", name: `用户名称` },
 		{ field: "nickName", name: `用户昵称` },
-		{ field: "orgName", name: `部门` },
+		{ field: "orgName", name: `组织机构` },
 		{ field: "phone", name: `手机号码` },
 		{ field: "status", name: `状态` },
 		{ field: "createdAt", name: `创建时间` },
@@ -140,14 +140,14 @@ const modalOpts = reactive({
 		},
 		{
 			field: "orgId",
-			label: "归属部门",
+			label: "归属组织机构",
 			class: "w-100",
 			required: true,
 			data: () => orgOptions.value,
 			component: "vst",
 			props: {
 				//dataFun: loadOrg,
-				placeholder: "请选择归属部门",
+				placeholder: "请选择归属组织机构",
 				props: {
 					id: "id",
 					label: "label",
@@ -421,7 +421,7 @@ loadOrg()
 <template>
 	<div class="app-container">
 		<el-row :gutter="20">
-			<!--部门数据-->
+			<!--组织机构数据-->
 			<el-col :span="4" :xs="24">
 				<OrgTree v-model="queryParams.orgId" :data="orgOptions" @node-click="handleQuery"></OrgTree>
 			</el-col>