qixiaoning
2025-07-18 24f44f6ecefb5e83295bab670533529c6bc81810
本地调试
3个文件已添加
5个文件已修改
517 ■■■■■ 已修改文件
api-gateway/main.go 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
camera-common/models/task.go 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
camera-service/controllers/camera.go 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
camera-service/main.go 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
config/pro.yaml 183 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sync-service/models/cameraPolygon.go 89 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sync-service/models/cameraRuleGroup.go 91 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
sync-service/models/cameraRuleGroupArg.go 108 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
api-gateway/main.go
@@ -1,14 +1,16 @@
package main
import (
    "basic.com/valib/logc.git"
    "basic.com/valib/logger.git"
    "basic.com/valib/version.git"
    "context"
    "flag"
    "basic.com/valib/logc.git"
    "basic.com/valib/logger.git"
    vaversion "basic.com/valib/version.git"
    "github.com/gin-gonic/gin"
//    "net/http"
//    _ "net/http/pprof"
    //    "net/http"
    //    _ "net/http/pprof"
    "os"
    "os/signal"
    "syscall"
@@ -23,17 +25,18 @@
var (
    procName = service.ProcName
    env = flag.String("e", "pro", "")
    env      = flag.String("e", "pro", "")
)
//func init() {
// func init() {
func sinit() {
    flag.Parse()
    //控制台打印版本
    vaversion.Usage()
    config.Init(*env)
    // 日志初始化
    var logFile = config.LogConf.Path + "vamicro-"+procName+".log"
    var logFile = config.LogConf.Path + "vamicro-" + procName + ".log"
    logger.InitLogger(logFile, config.LogConf.Level, config.LogConf.MaxSize, config.LogConf.MaxBackups, config.LogConf.MaxAge)
    logger.Info("log init success !")
}
@@ -44,7 +47,7 @@
    //    logger.Info(http.ListenAndServe("0.0.0.0:6077", nil))
    //}()
    sinit()
    sinit()
    models.Init()
    defer models.CloseDB()
camera-common/models/task.go
New file
@@ -0,0 +1 @@
package models
camera-service/controllers/camera.go
@@ -321,7 +321,7 @@
    if sv.ChangeRunType(ccrVo) {
        cIds := strings.Join(ccrVo.CameraIds, ",")
        cc.addDbChangeMsg(h.Bk, protomsg.TableChanged_T_Camera, cIds, protomsg.DbAction_Update, "")
        _, _ = service2.DoBusReq("/data/api-v/saas/syncCamera", config.Server.AnalyServerId, aiot.RequestMethod_Post, aiot.RequestContentType_ApplicationJson, map[string]interface{}{})
         _, _ = service2.DoBusReq("/data/api-v/saas/syncCamera", config.Server.AnalyServerId, aiot.RequestMethod_Post, aiot.RequestContentType_ApplicationJson, map[string]interface{}{})
        return &bhomeclient.Reply{Success: true, Msg: "更新成功"}
    } else {
        return &bhomeclient.Reply{Success: false, Msg: "更新失败"}
@@ -1000,3 +1000,11 @@
    _, _ = service2.DoBusReq("/data/api-v/saas/syncCamera", config.Server.AnalyServerId, aiot.RequestMethod_Post, aiot.RequestContentType_ApplicationJson, map[string]interface{}{})
    return &bhomeclient.Reply{Success: true, Msg: "保存成功"}
}
/**
 *  根据视频id获取任务
 */
func (cc CameraController) GetTaskById(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply {
    tasks := "hello,world"
    return &bhomeclient.Reply{Success: true, Msg: "获取成功", Data: tasks}
}
camera-service/main.go
@@ -1,10 +1,6 @@
package main
import (
    "basic.com/valib/bhomeclient.git"
    "basic.com/valib/bhomedbapi.git"
    "basic.com/valib/logger.git"
    "basic.com/valib/version.git"
    "context"
    "flag"
    "os"
@@ -15,6 +11,11 @@
    "vamicro/camera-service/models"
    "vamicro/camera-service/service"
    "vamicro/config"
    "basic.com/valib/bhomeclient.git"
    "basic.com/valib/bhomedbapi.git"
    "basic.com/valib/logger.git"
    vaversion "basic.com/valib/version.git"
)
var (
@@ -75,7 +76,7 @@
    ms.Free()
}
//处理订阅消息
// 处理订阅消息
func dealSubMsg(ctx context.Context, ms *bhomeclient.MicroNode) {
    for {
@@ -125,6 +126,9 @@
    funcMap[urlPrefix+"/camera/getSyncSensorData"] = cc.GetSyncSensorData
    funcMap[urlPrefix+"/camera/saveNotExistOrUpdate"] = cc.SaveNotExistOrUpdate
    //摄像机关联督查任务
    funcMap[urlPrefix+"/camera/getTasks"] = cc.GetTaskById
    var pubTopics []string
    for key, _ := range funcMap {
        pubTopics = append(pubTopics, key)
config/pro.yaml
@@ -1,42 +1,32 @@
server:
    serverName: "SmartAI"
    runmode: debug
    jwtSecret: BASIC
    jwtExpire: 24
    url: http://127.0.0.1:8080
    analyServerId: DSPAD010120211015235820
    networkAdapter: eth0
#循环覆盖---------------------------------------------------------------------------------------------#
    #es服务IP  仅在公司测试环境使用,线上勿配置
    esServerIp: 192.168.8.118
    #es服务端口  仅在公司测试环境使用,线上勿配置
    esServerPort: 9200
#---------------------------------------------------------------------------------------------循环覆盖#
    #并行线程进制
    coreBaseUnit: 100
    #超时时间
    timeOut: 2
    analyServerId: DSVAD202505139F8038
    networkAdapter: enp6s0
    #脚本目录
    scriptPath: /opt/vasystem/script
    #设备编号
    deviceNum: 001
    #设备型号
    deviceModel: Bsk-JS1000N
    deviceModel: BSK-JS1000X
    #设备型号
    deviceType: DS0104322264020416
    deviceType: DS0301322264020416
    deviceDesc: 分析/存储设备1
    #设备序列号
    deviceSerialNum: 01
    #主控版本
    masterVersion: V1.0.0
    masterVersion: V1.0.0.0
    #web版本
    webVersion: 2.0
    webVersion: 2.0
    #通道个数
    channelCount: 0
    #硬盘个数
    diskCount: 2
    #Exec root command
    sudoPassword: basic2021
    sudoPassword: 123
    rtspUnique: false
    sysThresholds:
    - value: 60
      color: '#13ce66'
@@ -49,34 +39,78 @@
    licensePath: /opt/vasystem/licence.inc
    lKey: flzxsqc,ysyhljt.
    lPublicKeyPath: /opt/vasystem/public.pem
    headpics: ["none"]
    langs:
    - name: "简体中文"
      lang: "zh_CN.UTF-8"
      language: "zh_CN:zh"
    - name: "英语"
      lang: "en_US.UTF-8"
      language: "en_US:en"
    - name: "繁体中文(香港)"
      lang: "zh_HK.UTF-8"
      language: "zh_HK:zh"
    voices:
    - id: 1
      name: 1.mp3
      path: /files/voices/1.mp3
    - id: 2
      path: /home/basic/files/1.mp3
    - id: 2
      name: 2.mp3
      path: /files/voices/2.mp3
      path: /home/basic/files/2.mp3
    - id: 3
      name: 3.mp3
      path: /files/voices/3.mp3
      path: /home/basic/files/3.mp3
    - id: 4
      name: 4.mp3
      path: /files/voices/4.mp3
      path: /home/basic/files/4.mp3
    - id: 5
      name: 5.mp3
      path: /files/voices/5.mp3
    - id: lineup
      name: 请有序排队,不要拥挤
      path: /files/voices/lineup.mp3
    - id: warningArea
      name: 警戒区域,尽快离开
      path: /files/voices/warningArea.wav
      path: /home/basic/files/5.mp3
database:
    driver: sqlite
    name: sqlite3
    filepath: /opt/vasystem/config/testdb.db
cluster:
    pwdpre: bjbasic123
    #serf snapshot文件的完整路径,serfSnapShot是个文件
    serfsnapshotpath: /opt/vasystem/serfSnapShot
    # 集群内部端口
    port: 7081
    # 集群心跳间隔
    heartBeat: 15
    # saas服务上报地址
    saasReportUrl: 192.168.20.117:7081
facedetect:
    ip: 127.0.0.1
    port: 4009
dbpersoncompare:
    ip: 127.0.0.1
    port: 4010
espersoncompare:
    port: 4011
    ips:
    - 127.0.0.1
weedfs:
    port: 6333
es:
    port: 9200
    shards: 1,2
    index:
      aiOcean:
        index: ai_ocean
        type: analysisModel
    thresholdTime: 10
    thresholdStayTime: 0
    storePath:
      - /data3/elasticsearch
#循环覆盖---------------------------------------------------------------------------------------------#
storage:
    mountPoint: ["data"]
    #同analyServerId
    id: DSVAD20230919AC63EC
    #文件服务挂载点
    mountPoint: ["/data/disk1/"]
    #文件服务存储路径
    volumePath: ["/data/disk2/seaweedfs/data/volume"]
    volumePath: ["/data/disk1/seaweedfs/data/volume"]
    #清理阈值
    threshold: 85
    #文件服务端口--用做指定服务端口任务控制
@@ -93,85 +127,42 @@
        indexName: basicfs
        indexType: clearItem
#---------------------------------------------------------------------------------------------循环覆盖#
fileDb:
  driver: sqlite
  name: sqlite3
  filepath: /opt/vasystem/config/file-service.db
file-service:
  savePath: /opt/vasystem/files
shop:
  url: apps.smartai.com:7004
database:
fileDb:
    driver: sqlite
    name: sqlite3
    filepath: /opt/vasystem/config/testdb.db
cluster:
    pwdpre: bjbasic123
    #serf snapshot文件的完整路径,serfSnapShot是个文件
    serfsnapshotpath: /opt/vasystem/serfSnapShot
    # 内部集群配置
    # 集群内部端口
    port: 7081
    # 集群心跳间隔
    heartBeat: 15
    # saas服务上报地址
    saasReportUrl: 192.168.20.117:7081
    name: sqlite
    filepath: /opt/vasystem/config/file-service.db
file-service:
    savePath: /opt/vasystem/files
shop:
    url: 127.0.0.1:7004
saas:
  url: 192.168.20.117:7080
facedetect:
    ip: 127.0.0.1
    port: 4009
dbpersoncompare:
    ip: 127.0.0.1
    port: 4010
espersoncompare:
    port: 4011
    ips:
    - 127.0.0.1
redis:
    host: 127.0.0.1
    port: 6379
    password: password
    db: 1
es:
    shards: 1,2
    index:
        # 人脸抓拍记录
        videopersons:
            index: videopersons
            type: perVideoPicture
        # 行为抓拍记录*
        personaction:
            index: personaction
            type: perVideoAction
        aiocean:
            index: ai_ocean
            type: analysisModel
    thresholdTime: 10
    thresholdStayTime: 0
    url: 192.168.20.117:7080
ruletrack:
    timeout_seconds: 30
    target_box: 1
    jitter_buffer: 300
#so配置
sopath:
    ip: 192.168.1.182
    port: 8008
ruletrack:
    timeout_seconds: 86400
    movepos: 1
#通用配置
LogBasePath: /opt/vasystem/valog/
LogLevel: 5
LogLevel: 5
log:
    path: /opt/vasystem/valog/
    level: -1
    maxSize: 128
    maxBackups: 30
    maxAge: 15
#推流
MaxStreamsNum: 16
#推流
LibFfmpegPath: /opt/vasystem/libs/libcffmpeg-capture.so
VideoPublishWidth: 960
VideoPublishHeight: 640
VideoPublishPort: 10101
SenderFreq: 1000
#so配置
trace:
    useBlockList: 1
sync-service/models/cameraPolygon.go
@@ -1,26 +1,25 @@
package models
import (
    "basic.com/pubsub/protomsg.git"
    "basic.com/valib/logger.git"
    "encoding/json"
    "regexp"
    "basic.com/valib/logger.git"
)
type CameraPolygon struct {
    Id            string `gorm:"primary_key;column:id" json:"id"`
    CameraId      string `gorm:"column:camera_id" json:"camera_id"`      //摄像机id
    Name          string `gorm:"column:name" json:"name"`           //形状名称
    Polygon       string `gorm:"column:polygon" json:"polygon"`        //形状结构定义
    DirectionLine string `gorm:"column:direction_line" json:"direction_line"` //方向线
    Type           string `gorm:"column:type" json:"type"`             //类型,["line","rect","polygon"]
    CameraId      string `gorm:"column:camera_id" json:"camera_id"`                   //摄像机id
    Name          string `gorm:"column:name" json:"name"`                             //形状名称
    Polygon       string `gorm:"column:polygon" json:"polygon"`                       //形状结构定义
    DirectionLine string `gorm:"column:direction_line" json:"direction_line"`         //方向线
    Type          string `gorm:"column:type" json:"type"`                             //类型,["line","rect","polygon"]
    DefenceState  int    `gorm:"column:defence_state;default:0" json:"defence_state"` //布撤防状态
}
const (
    TYPE_LINE = "line" //线
    TYPE_RECT = "rect" //矩形
    TYPE_POLYGON = "polygon" //面
    TYPE_LINE              = "line"    //线
    TYPE_RECT              = "rect"    //矩形
    TYPE_POLYGON           = "polygon" //面
    CAMERAPOLYGON_AREA_ALL = "全部区域"
)
@@ -35,44 +34,44 @@
}
func (cp *CameraPolygon) FindAll() (polygons []CameraPolygon) {
    if err := db.Table("camera_polygon").Scan(&polygons).Error;err !=nil {
    if err := db.Table("camera_polygon").Scan(&polygons).Error; err != nil {
        return nil
    }
    return polygons
}
func (cp *CameraPolygon) FindAllMap() map[string]CameraPolygon {
    m := make(map[string]CameraPolygon,0)
    m := make(map[string]CameraPolygon, 0)
    polygons := cp.FindAll()
    if polygons !=nil {
        for _,p :=range polygons {
    if polygons != nil {
        for _, p := range polygons {
            m[p.Id] = p
        }
    }
    return m
}
func (cp *CameraPolygon) SelectById(id string) (model CameraPolygon,flag bool) {
    exist := db.Table("camera_polygon").First(&model,"id=?",id).RecordNotFound()
    return model,!exist
func (cp *CameraPolygon) SelectById(id string) (model CameraPolygon, flag bool) {
    exist := db.Table("camera_polygon").First(&model, "id=?", id).RecordNotFound()
    return model, !exist
}
func (cp *CameraPolygon) FindAllByCameraId(cameraId string) (polygons []CameraPolygon, err error) {
    if err := db.Table("camera_polygon").Where("camera_id = ?", cameraId).Scan(&polygons).Error;err !=nil {
    if err := db.Table("camera_polygon").Where("camera_id = ?", cameraId).Scan(&polygons).Error; err != nil {
        return nil, err
    }
    return polygons,nil
    return polygons, nil
}
//FindByCameraId 根据摄像机id查找在规则中使用的多边形
// FindByCameraId 根据摄像机id查找在规则中使用的多边形
func (cp *CameraPolygon) FindRulePolygonsByCameraId(cameraId string) (polygons []CameraPolygon, err error) {
    if err := db.Table("camera_polygon").Where("camera_id = ? and type !=?", cameraId, TYPE_LINE).Scan(&polygons).Error;err !=nil {
    if err := db.Table("camera_polygon").Where("camera_id = ? and type !=?", cameraId, TYPE_LINE).Scan(&polygons).Error; err != nil {
        return nil, err
    }
    return polygons,nil
    return polygons, nil
}
//保存摄像机区域
// 保存摄像机区域
func (cp *CameraPolygon) Insert() (result bool, err error) {
    if err = db.Table("camera_polygon").Save(&cp).Error; err != nil {
        return false, err
@@ -80,63 +79,63 @@
    return true, nil
}
//更新摄像机区域
func (cp *CameraPolygon) Update() (bool,error) {
    result := db.Exec("update camera_polygon set camera_id=?,name=?,polygon=?,direction_line=?,type=?,defence_state=? where id=?",cp.CameraId,cp.Name,cp.Polygon,cp.DirectionLine,cp.Type,cp.DefenceState,cp.Id)
// 更新摄像机区域
func (cp *CameraPolygon) Update() (bool, error) {
    result := db.Exec("update camera_polygon set camera_id=?,name=?,polygon=?,direction_line=?,type=?,defence_state=? where id=?", cp.CameraId, cp.Name, cp.Polygon, cp.DirectionLine, cp.Type, cp.DefenceState, cp.Id)
    if result.Error != nil {
        return false, result.Error
    }
    return result.RowsAffected > 0, nil
}
//判断摄像机有没有重名的区域
// 判断摄像机有没有重名的区域
func (cp CameraPolygon) Exist(cameraId string, name string) (model CameraPolygon, exist bool) {
    exist = db.Table("camera_polygon").First(&model, "camera_id=? and name=?", cameraId, name).RecordNotFound()
    return model, !exist
}
//UnInstall 删除摄像机区域
func (cp *CameraPolygon) Delete(id string,name string) bool {
    if err := db.Table("camera_polygon").Where("id=?",id).Delete(&CameraPolygon{}).Error; err != nil {
// UnInstall 删除摄像机区域
func (cp *CameraPolygon) Delete(id string, name string) bool {
    if err := db.Table("camera_polygon").Where("id=?", id).Delete(&CameraPolygon{}).Error; err != nil {
        return false
    }
    var crg CameraRuleGroup
    groups := crg.FindGroupByPolygonId(id)
    if groups != nil {
        for _,g :=range groups {
        for _, g := range groups {
            //将groupText中的已删除的多边形名称替换为NULL
            reg := regexp.MustCompile(`(`+name+`于)`)
            reg := regexp.MustCompile(`(` + name + `于)`)
            newGText := reg.ReplaceAllString(g.GroupText, `<span style="color:RGB(255,0,0);">NULL</span>于`)
            crg.UpdateText(g.Id, newGText)
        }
    }
    err := db.Exec("update camera_task_args set polygon_id='' where polygon_id=?",id).Error
    if err !=nil {
        logger.Debug("rm polygon_id in camera_task_args err:",err)
    err := db.Exec("update camera_task_args set polygon_id='' where polygon_id=?", id).Error
    if err != nil {
        logger.Debug("rm polygon_id in camera_task_args err:", err)
    }
    return true
}
func (cp *CameraPolygon) UpdateDefenceStateByPolygonId(polygonId string,state int) bool {
    result := db.Exec("update camera_polygon set defence_state=? where id=?",state,polygonId)
    if result.Error!=nil{
func (cp *CameraPolygon) UpdateDefenceStateByPolygonId(polygonId string, state int) bool {
    result := db.Exec("update camera_polygon set defence_state=? where id=?", state, polygonId)
    if result.Error != nil {
        return false
    }
    if result.RowsAffected>0{
    if result.RowsAffected > 0 {
        return true
    } else {
        return false
    }
}
func (cp *CameraPolygon) UpdateDefenceStateByCameraId(cameraId string,state int) bool {
    result := db.Exec("update camera_polygon set defence_state=? where camera_id=?",state,cameraId)
    if result.Error!=nil{
func (cp *CameraPolygon) UpdateDefenceStateByCameraId(cameraId string, state int) bool {
    result := db.Exec("update camera_polygon set defence_state=? where camera_id=?", state, cameraId)
    if result.Error != nil {
        return false
    }
    if result.RowsAffected>0{
    if result.RowsAffected > 0 {
        return true
    } else {
        return false
    }
}
}
sync-service/models/cameraRuleGroup.go
New file
@@ -0,0 +1,91 @@
package models
type CameraRuleGroup struct {
    Id         string `gorm:"primary_key;column:id" json:"id"`
    GroupText  string `gorm:"column:group_text" json:"group_text"`
    AlarmLevel int    `gorm:"column:alarm_level;default:1" json:"alarm_level"`
    SetType    string `gorm:"column:set_type" json:"set_type"`
    TemplateId   string `gorm:"column:template_id" json:"template_id"`     //场景模板id
    TemplateRule string `gorm:"column:template_rule" json:"template_rule"` //场景模板的配置
    TimeRuleId   string `gorm:"column:time_rule_id" json:"time_rule_id"`   //时间段
    SceneName    string `gorm:"column:scene_name" json:"scene_name"`       //场景名称,从模板来,修改即自定义
    Desc         string `gorm:"column:desc" json:"desc"`                   //场景描述
    Enable       bool   `gorm:"column:enable;default:1" json:"enable"`     //开关,默认开启
    VoiceId string `gorm:"column:voiceId" json:"voiceId"` //事件声音
}
const (
    Type_SetType_Batch = "batchTask"
    Type_SetType_Link  = "linkTask"
    RecordNotFound     = "record not found"
)
func (CameraRuleGroup) TableName() string {
    return "camera_rule_group"
}
func (crg *CameraRuleGroup) SelectById(id string) (rows int64, err error) {
    result := db.Table(crg.TableName()).Where("id = ?", id).First(&crg)
    if result.Error != nil && result.Error.Error() != RecordNotFound {
        return 0, result.Error
    }
    return result.RowsAffected, nil
}
func (crg *CameraRuleGroup) FindAll() (list []CameraRuleGroup) {
    if err := db.Table(crg.TableName()).Scan(&list).Error; err != nil {
        return nil
    }
    return list
}
func (crg *CameraRuleGroup) Insert() (bool, error) {
    if err := db.Table(crg.TableName()).Create(&crg).Error; err != nil {
        return false, err
    }
    return true, nil
}
func (crg *CameraRuleGroup) FindByCameraId(cameraId string, setType string) (arr []CameraRuleGroup, err error) {
    sql := "select * from " + crg.TableName() + " where id in (select distinct group_id from " + CameraRuleGroupArg{}.TableName() + " where camera_id='" + cameraId + "')"
    if setType != "" {
        sql += " and set_type='batchTask'"
    }
    if err := db.Raw(sql).Scan(&arr).Error; err != nil {
        return nil, err
    }
    return arr, nil
}
func (crg *CameraRuleGroup) FindGroupByPolygonId(polygonId string) (list []CameraRuleGroup) {
    var rga CameraRuleGroupArg
    err := db.Raw("select * from "+crg.TableName()+" where id in (select distinct group_id from "+rga.TableName()+" where polygon_id=?)", polygonId).Find(&list).Error
    if err != nil {
        return nil
    }
    return list
}
func (crg *CameraRuleGroup) UpdateText(id string, text string) bool {
    execResult := db.Exec("update "+crg.TableName()+" set group_text=? where id=?", text, id)
    if execResult.Error != nil {
        return false
    }
    return execResult.RowsAffected > 0
}
func (crg *CameraRuleGroup) UpdateAlarmLevel(groupId string, alarmLevel int) bool {
    execResult := db.Exec("update "+crg.TableName()+" set alarm_level=? where id=?", alarmLevel, groupId)
    if execResult.Error != nil {
        return false
    }
    return execResult.RowsAffected > 0
}
func (crg *CameraRuleGroup) FindByTimeRuleId(timeRuleId string) (list []CameraRuleGroup, e error) {
    if err := db.Table(crg.TableName()).Where("time_rule_id=?", timeRuleId).Scan(&list).Error; err != nil {
        return nil, err
    }
    return list, nil
}
sync-service/models/cameraRuleGroupArg.go
New file
@@ -0,0 +1,108 @@
package models
type CameraRuleBase struct {
    CameraId             string             `gorm:"column:camera_id" json:"camera_id"`           //摄像机id
    SdkId                string             `gorm:"column:sdk_id" json:"sdk_id"`                    //算法id
    PolygonId            string             `gorm:"column:polygon_id" json:"polygon_id"`         //多边形id
    SdkSet                 string             `gorm:"column:sdk_set" json:"sdk_set"`                    //算法id
    RuleWithPre          string             `gorm:"column:rule_with_pre" json:"rule_with_pre"`   //与上一条记录的逻辑运算规则(&&,||)
    IsSaveAnyhow         bool             `gorm:"column:is_save_anyhow;default:0;" json:"is_save_anyhow"` //rule_with_pre是触发时,是否无论被触发的条件满不满足,都保留数据
    GroupId              string             `gorm:"column:group_id" json:"group_id"`             //分组id
    Sort                 int                `gorm:"column:sort" json:"sort"`                   //排序
}
type CameraRuleGroupArg struct {
    Id                   string             `gorm:"column:id;primary_key;type:varchar(50);unique;not null;" json:"id"`
    CameraRuleBase
}
func (CameraRuleGroupArg) TableName() string {
    return "camera_rule_group_arg"
}
func (rga *CameraRuleGroupArg) InsertByGroup() bool {
    tx := db.Table(rga.TableName()).Begin()
    if tx.Error != nil {
        return false
    }
    if err := tx.Create(&rga).Error; err != nil {
        tx.Rollback()
        return false
    }
    if tx.Commit().Error == nil {
        return true
    }
    return false
}
func (rga *CameraRuleGroupArg) FindAll() (args []CameraRuleGroupArg) {
    if err := db.Table(rga.TableName()).Scan(&args).Error; err != nil {
        return nil
    }
    return args
}
type DbGroupId struct {
    GroupId string `json:"group_id"`
}
func (rga *CameraRuleGroupArg) FindGroupIdByCameraId(cameraId string) (groupIds []DbGroupId, err error) {
    if err := db.Raw("select distinct group_id from "+rga.TableName()+" where camera_id=?", cameraId).Scan(&groupIds).Error; err != nil {
        return nil, err
    }
    return groupIds, nil
}
//DeleteByGroup 根据group_id删除规则组设置
func (rga CameraRuleGroupArg) DeleteByGroup(groupId string) bool {
    var crg CameraRuleGroup
    var err error
    tx := db.Begin()
    defer func() {
        if err != nil && tx != nil {
            tx.Rollback()
        }
    }()
    if err = tx.Table(rga.TableName()).Where("group_id=?", groupId).Delete(CameraRuleGroupArg{}).Error; err != nil {
        return false
    }
    if err = tx.Table(crg.TableName()).Where("group_id=?", groupId).Delete(crg).Error; err != nil {
        return false
    }
    if err = tx.Commit().Error; err != nil {
        return false
    } else {
        return true
    }
}
func (rga CameraRuleGroupArg) FindByGroupId(groupId string) (rags []CameraRuleGroupArg) {
    if err := db.Table(rga.TableName()).Where("group_id=?", groupId).Find(&rags).Error; err != nil {
        return nil
    }
    return rags
}
//判断多边形是否在规则设置中正在使用
func (rga CameraRuleGroupArg) IsPolygonInUse(polygonId string) bool {
    var rules []CameraRuleGroupArg
    if err := db.Table(rga.TableName()).Where("polygon_id=?", polygonId).Find(&rules).Error; err != nil {
        return true
    }
    if len(rules) == 0 {
        return false
    }
    return true
}
func (rga CameraRuleGroupArg) ExistRunningTask(cameraId string) bool {
    var arr []CameraRuleGroupArg
    if err = db.Raw("select a.* from "+CameraRuleGroupArg{}.TableName()+" a join "+CameraRuleGroup{}.TableName()+" g on a.group_id=g.id where a.camera_id=? and g.enable=1",cameraId).Scan(&arr).Error;err !=nil{
        return false
    }
    return len(arr) >0
}