922 lines
28 KiB
Go
922 lines
28 KiB
Go
|
// ==========================================================================
|
|||
|
// GFast自动生成controller操作代码。
|
|||
|
// 生成日期:2024-03-01 12:49:32
|
|||
|
// 生成路径: internal/app/system/controller/ys7devices.go
|
|||
|
// 生成人:gfast
|
|||
|
// desc:荧石摄像头
|
|||
|
// company:云南奇讯科技有限公司
|
|||
|
// ==========================================================================
|
|||
|
|
|||
|
package controller
|
|||
|
|
|||
|
import (
|
|||
|
"context"
|
|||
|
"encoding/json"
|
|||
|
"errors"
|
|||
|
"fmt"
|
|||
|
"github.com/gogf/gf/v2/database/gdb"
|
|||
|
"github.com/gogf/gf/v2/frame/g"
|
|||
|
"github.com/gogf/gf/v2/net/ghttp"
|
|||
|
"github.com/gogf/gf/v2/os/gctx"
|
|||
|
"github.com/gogf/gf/v2/util/gconv"
|
|||
|
"github.com/tiger1103/gfast/v3/api/v1/common/coryCommon"
|
|||
|
"github.com/tiger1103/gfast/v3/api/v1/common/shp"
|
|||
|
"github.com/tiger1103/gfast/v3/api/v1/system"
|
|||
|
"github.com/tiger1103/gfast/v3/internal/app/system/consts"
|
|||
|
"github.com/tiger1103/gfast/v3/internal/app/system/dao"
|
|||
|
logic "github.com/tiger1103/gfast/v3/internal/app/system/logic/busViolationLevel"
|
|||
|
"github.com/tiger1103/gfast/v3/internal/app/system/model"
|
|||
|
"github.com/tiger1103/gfast/v3/internal/app/system/model/do"
|
|||
|
"github.com/tiger1103/gfast/v3/internal/app/system/service"
|
|||
|
"github.com/tiger1103/gfast/v3/library/liberr"
|
|||
|
"github.com/tiger1103/gfast/v3/third/arithmetic/SpartaApi"
|
|||
|
"github.com/tiger1103/gfast/v3/third/ys7"
|
|||
|
"log"
|
|||
|
"os"
|
|||
|
"path/filepath"
|
|||
|
"strconv"
|
|||
|
"strings"
|
|||
|
"sync"
|
|||
|
"time"
|
|||
|
)
|
|||
|
|
|||
|
type ys7DevicesController struct {
|
|||
|
BaseController
|
|||
|
}
|
|||
|
|
|||
|
var Ys7Devices = new(ys7DevicesController)
|
|||
|
|
|||
|
// List 列表
|
|||
|
func (c *ys7DevicesController) List(ctx context.Context, req *system.Ys7DevicesSearchReq) (res *system.Ys7DevicesSearchRes, err error) {
|
|||
|
res, err = service.Ys7Devices().List(ctx, req)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// Get 获取荧石摄像头
|
|||
|
func (c *ys7DevicesController) Get(ctx context.Context, req *system.Ys7DevicesGetReq) (res *system.Ys7DevicesGetRes, err error) {
|
|||
|
res = new(system.Ys7DevicesGetRes)
|
|||
|
res.Ys7DevicesInfoRes, err = service.Ys7Devices().GetById(ctx, req.Id)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// Add 添加荧石摄像头
|
|||
|
func (c *ys7DevicesController) Add(ctx context.Context, req *system.Ys7DevicesAddReq) (res *system.Ys7DevicesAddRes, err error) {
|
|||
|
err = service.Ys7Devices().Add(ctx, req)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// Edit 修改荧石摄像头
|
|||
|
func (c *ys7DevicesController) Edit(ctx context.Context, req *system.Ys7DevicesEditReq) (res *system.Ys7DevicesEditRes, err error) {
|
|||
|
err = service.Ys7Devices().Edit(ctx, req)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// Delete 删除荧石摄像头
|
|||
|
func (c *ys7DevicesController) Delete(ctx context.Context, req *system.Ys7DevicesDeleteReq) (res *system.Ys7DevicesDeleteRes, err error) {
|
|||
|
err = service.Ys7Devices().Delete(ctx, req.Ids)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// BindProject摄像头绑定项目
|
|||
|
func (c *ys7DevicesController) BindProject(ctx context.Context, req *system.Ys7DevicesBindProjectReq) (*system.Ys7DevicesBindProjectRes, error) {
|
|||
|
// 遍历 DeviceSerial 更新项目ID
|
|||
|
for _, deviceSerial := range req.List.DeviceSerial {
|
|||
|
_, err := dao.Ys7Devices.Ctx(ctx).Where("DeviceSerial", deviceSerial).
|
|||
|
Update(g.Map{
|
|||
|
"ProjectId": req.List.ProjectId,
|
|||
|
})
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return &system.Ys7DevicesBindProjectRes{}, nil
|
|||
|
}
|
|||
|
|
|||
|
func (s *ys7DevicesController) EditPosition(ctx context.Context, req *system.Ys7DevicesEditPositionReq) (*system.Ys7DevicesEditPositionRes, error) {
|
|||
|
err := g.Try(ctx, func(ctx context.Context) {
|
|||
|
dt := shp.Detail{}
|
|||
|
if err := json.Unmarshal([]byte(req.Position), &dt); err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
dt.Position.Lng, dt.Position.Lat = coryCommon.GCJ02toWGS84(dt.Position.Lng, dt.Position.Lat)
|
|||
|
data, err := json.Marshal(dt)
|
|||
|
if err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
_, err = dao.Ys7Devices.Ctx(ctx).WherePri(req.Id).Update(g.Map{
|
|||
|
"Detail": string(data),
|
|||
|
})
|
|||
|
liberr.ErrIsNil(ctx, err, "修改失败")
|
|||
|
})
|
|||
|
|
|||
|
return &system.Ys7DevicesEditPositionRes{}, err
|
|||
|
}
|
|||
|
|
|||
|
// 根据项目ID获取摄像头列表
|
|||
|
func (s *ys7DevicesController) GetListByProjectId(ctx context.Context, req *system.Ys7DevicesGetByProjectIdReq) (listRes *system.Ys7DevicesGetByProjectIdRes, err error) {
|
|||
|
listRes = new(system.Ys7DevicesGetByProjectIdRes)
|
|||
|
|
|||
|
m := dao.Ys7Devices.Ctx(ctx).WithAll().Where(dao.Ys7Devices.Columns().ProjectId, req.ProjectId)
|
|||
|
|
|||
|
listRes.Total, err = m.Count()
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
if req.PageNum == 0 {
|
|||
|
req.PageNum = 1
|
|||
|
}
|
|||
|
listRes.CurrentPage = req.PageNum
|
|||
|
if req.PageSize == 0 {
|
|||
|
req.PageSize = consts.PageSize
|
|||
|
}
|
|||
|
order := "sort desc,id desc"
|
|||
|
|
|||
|
var res []*model.Ys7DevicesInfoRes
|
|||
|
err = m.Page(req.PageNum, req.PageSize).Order(order).Scan(&res)
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
listRes.List = make([]*model.Ys7DevicesList2Res, len(res))
|
|||
|
for k, v := range res {
|
|||
|
listRes.List[k] = &model.Ys7DevicesList2Res{
|
|||
|
Id: v.Id,
|
|||
|
DeviceSerial: v.DeviceSerial,
|
|||
|
DeviceName: v.DeviceName,
|
|||
|
ProjectId: v.ProjectId,
|
|||
|
Token: ys7.Ys72Instance.GetAccessToken(),
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// 获取视频播放地址
|
|||
|
func (s *ys7DevicesController) GetVideoUrl(ctx context.Context, req *system.Ys7DevicesGetVideoUrlReq) (res *system.Ys7DevicesGetVideoUrlRes, err error) {
|
|||
|
Device, err := ys7.Ys72Instance.GetDevice(req.DeviecesSerial)
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
liveUrl, err := Device.GetLiveAddress()
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
return &system.Ys7DevicesGetVideoUrlRes{
|
|||
|
VideoUrl: liveUrl,
|
|||
|
}, nil
|
|||
|
}
|
|||
|
|
|||
|
// 获取AccessToken
|
|||
|
func (s *ys7DevicesController) GetAccessToken(ctx context.Context, req *system.Ys7DevicesGetAccessTokenReq) (res *system.Ys7DevicesGetAccessTokenRes, err error) {
|
|||
|
return &system.Ys7DevicesGetAccessTokenRes{
|
|||
|
Token: ys7.GetAccessToken(),
|
|||
|
}, nil
|
|||
|
}
|
|||
|
|
|||
|
// GIS 前端调用修改摄像头信息
|
|||
|
func (s *ys7DevicesController) EditGis(ctx context.Context, req *system.Ys7DevicesEditGisReq) (res *system.Ys7DevicesEditGisRes, err error) {
|
|||
|
err = g.Try(ctx, func(ctx context.Context) {
|
|||
|
_, err := dao.Ys7Devices.Ctx(ctx).WherePri(req.Id).Update(do.Ys7Devices{
|
|||
|
DeviceSerial: req.DeviceSerial,
|
|||
|
DeviceName: req.DeviceName,
|
|||
|
Detail: req.Detail,
|
|||
|
})
|
|||
|
liberr.ErrIsNil(ctx, err, "修改失败")
|
|||
|
})
|
|||
|
return &system.Ys7DevicesEditGisRes{}, err
|
|||
|
}
|
|||
|
|
|||
|
// 开启视频加密
|
|||
|
func (s *ys7DevicesController) OpenEncrypt(ctx context.Context, req *system.Ys7DevicesOpenEncryptReq) (res *system.Ys7DevicesOpenEncryptRes, err error) {
|
|||
|
Device, err := ys7.Ys72Instance.GetDevice(req.DeviceSerial)
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
r := ghttp.RequestFromCtx(ctx)
|
|||
|
r.Response.ClearBuffer()
|
|||
|
|
|||
|
err = Device.OpenEncrypt()
|
|||
|
if err != nil {
|
|||
|
r.Response.WriteJson(fmt.Sprintf(`{"code":1,"message":"开启加密失败:%s"}`, err.Error()))
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
r.Response.WriteJson(`{"code":0,"message":"开启加密成功"}`)
|
|||
|
return &system.Ys7DevicesOpenEncryptRes{}, nil
|
|||
|
}
|
|||
|
|
|||
|
// 关闭视频加密
|
|||
|
func (s *ys7DevicesController) CloseEncrypt(ctx context.Context, req *system.Ys7DevicesCloseEncryptReq) (res *system.Ys7DevicesCloseEncryptRes, err error) {
|
|||
|
Device, err := ys7.Ys72Instance.GetDevice(req.DeviceSerial)
|
|||
|
if err != nil {
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
r := ghttp.RequestFromCtx(ctx)
|
|||
|
r.Response.ClearBuffer()
|
|||
|
|
|||
|
err = Device.CloseEncrypt()
|
|||
|
if err != nil {
|
|||
|
r.Response.WriteJson(fmt.Sprintf(`{"code":1,"message":"%s"}`, err.Error()))
|
|||
|
return nil, err
|
|||
|
}
|
|||
|
|
|||
|
r.Response.WriteJson(`{"code":0,"message":"关闭加密成功"}`)
|
|||
|
return &system.Ys7DevicesCloseEncryptRes{}, nil
|
|||
|
}
|
|||
|
|
|||
|
// 小程序获取设备列表
|
|||
|
func (s *ys7DevicesController) GetListByProjectIdForMini(ctx context.Context, req *system.Ys7DevicesGetListReq) (listRes *system.Ys7DevicesGetListRes, err error) {
|
|||
|
listRes = new(system.Ys7DevicesGetListRes)
|
|||
|
|
|||
|
m := dao.Ys7Devices.Ctx(ctx).WithAll()
|
|||
|
|
|||
|
if req.Id != "" {
|
|||
|
m = m.Where(dao.Ys7Devices.Columns().Id+" = ?", req.Id)
|
|||
|
}
|
|||
|
if len(req.DateRange) != 0 {
|
|||
|
m = m.Where(dao.Ys7Devices.Columns().CreatedAt+" >=? AND "+dao.Ys7Devices.Columns().CreatedAt+" <=?", req.DateRange[0], req.DateRange[1])
|
|||
|
}
|
|||
|
if req.DeviceSerial != "" {
|
|||
|
m = m.Where(dao.Ys7Devices.Columns().DeviceSerial+" = ?", req.DeviceSerial)
|
|||
|
}
|
|||
|
if req.DeviceName != "" {
|
|||
|
m = m.Where(dao.Ys7Devices.Columns().DeviceName+" like ?", "%"+req.DeviceName+"%")
|
|||
|
}
|
|||
|
if req.DeviceType != "" {
|
|||
|
m = m.Where(dao.Ys7Devices.Columns().DeviceType+" = ?", req.DeviceType)
|
|||
|
}
|
|||
|
if req.Status != "" {
|
|||
|
m = m.Where(dao.Ys7Devices.Columns().Status+" = ?", gconv.Int(req.Status))
|
|||
|
}
|
|||
|
if req.Defence != "" {
|
|||
|
m = m.Where(dao.Ys7Devices.Columns().Defence+" = ?", gconv.Int64(req.Defence))
|
|||
|
}
|
|||
|
if req.DeviceVersion != "" {
|
|||
|
m = m.Where(dao.Ys7Devices.Columns().DeviceVersion+" = ?", req.DeviceVersion)
|
|||
|
}
|
|||
|
if req.ProjectId != "" {
|
|||
|
m = m.Where(dao.Ys7Devices.Columns().ProjectId+" = ?", req.ProjectId)
|
|||
|
}
|
|||
|
|
|||
|
listRes.Total, err = m.Count()
|
|||
|
liberr.ErrIsNil(ctx, err, "获取总数失败")
|
|||
|
if req.PageNum == 0 {
|
|||
|
req.PageNum = 1
|
|||
|
}
|
|||
|
|
|||
|
listRes.CurrentPage = req.PageNum
|
|||
|
if req.PageSize == 0 {
|
|||
|
req.PageSize = consts.PageSize
|
|||
|
}
|
|||
|
|
|||
|
order := "id desc"
|
|||
|
if req.OrderBy != "" {
|
|||
|
order = req.OrderBy
|
|||
|
}
|
|||
|
|
|||
|
var res []*model.Ys7DevicesInfoRes
|
|||
|
err = m.Fields(system.Ys7DevicesSearchRes{}).Page(req.PageNum, req.PageSize).Order(order).Scan(&res)
|
|||
|
liberr.ErrIsNil(ctx, err, "获取数据失败")
|
|||
|
|
|||
|
listRes.List = make([]*model.Ys7DevicesList3Res, len(res))
|
|||
|
for k, v := range res {
|
|||
|
// redis 中获取封面图
|
|||
|
value, err := g.Redis().Get(ctx, "ys7:capture:"+v.DeviceSerial)
|
|||
|
cover := value.String()
|
|||
|
if err != nil {
|
|||
|
cover = ""
|
|||
|
}
|
|||
|
|
|||
|
listRes.List[k] = &model.Ys7DevicesList3Res{
|
|||
|
Id: v.Id,
|
|||
|
CreatedAt: v.CreatedAt,
|
|||
|
DeviceSerial: v.DeviceSerial,
|
|||
|
DeviceName: v.DeviceName,
|
|||
|
DeviceType: v.DeviceType,
|
|||
|
Status: v.Status,
|
|||
|
Defence: v.Defence,
|
|||
|
DeviceVersion: v.DeviceVersion,
|
|||
|
ProjectId: v.ProjectId,
|
|||
|
Detail: v.Detail,
|
|||
|
Token: ys7.Ys72Instance.GetAccessToken(),
|
|||
|
Cover: cover,
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// ManualSnapshotInterfaceFunc 手动摄像头抓拍
|
|||
|
func (s *ys7DevicesController) ManualSnapshotInterfaceFunc(ctx context.Context, req *system.ManualSnapshotInterfaceReq) (res *system.ManualSnapshotInterfaceRes, err error) {
|
|||
|
err = ManualSnapshotFunc(ctx, req.DeviceSerial)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// PtzStartFunc 开启云台控制
|
|||
|
func (s *ys7DevicesController) PtzStartFunc(ctx context.Context, req *system.PtzStartReq) (res *system.PtzStartRes, err error) {
|
|||
|
flag := true
|
|||
|
err = StartOrEndFunc(ctx, req.DeviceSerial, req.Direction, flag)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// PtzEndFunc 关闭云台控制
|
|||
|
func (s *ys7DevicesController) PtzEndFunc(ctx context.Context, req *system.PtzEndReq) (res *system.PtzEndRes, err error) {
|
|||
|
flag := false
|
|||
|
err = StartOrEndFunc(ctx, req.DeviceSerial, req.Direction, flag)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
func StartOrEndFunc(ctx context.Context, deviceSerial string, direction int, isStart bool) (err error) {
|
|||
|
err = g.Try(ctx, func(ctx context.Context) {
|
|||
|
//1、得到设备
|
|||
|
device, err := ys7.GetDevice(deviceSerial)
|
|||
|
if err != nil {
|
|||
|
liberr.ErrIsNil(ctx, err, "获取信息失败")
|
|||
|
}
|
|||
|
//2、判断设备是否在线
|
|||
|
if device.Online() {
|
|||
|
var start *ys7.Public
|
|||
|
if isStart { //true 为开启
|
|||
|
start, err = device.PTZStart(direction)
|
|||
|
} else { //flase 为停止
|
|||
|
start, err = device.PTZEnd(direction)
|
|||
|
}
|
|||
|
liberr.ErrIsNil(ctx, err)
|
|||
|
if start.Code != ys7.Ok {
|
|||
|
err = errors.New(start.Msg)
|
|||
|
liberr.ErrIsNil(ctx, err)
|
|||
|
}
|
|||
|
} else {
|
|||
|
err = errors.New("设备不在线")
|
|||
|
liberr.ErrIsNil(ctx, err)
|
|||
|
}
|
|||
|
})
|
|||
|
return err
|
|||
|
}
|
|||
|
|
|||
|
// ManualSnapshotFunc 摄像头手动快照
|
|||
|
func ManualSnapshotFunc(ctx context.Context, serial string) error {
|
|||
|
var str []string
|
|||
|
err := g.Try(ctx, func(ctx context.Context) {
|
|||
|
str = append(str, serial)
|
|||
|
entity, err := SelectBySerial(ctx, str)
|
|||
|
liberr.ErrIsNil(ctx, err, "获取信息失败")
|
|||
|
for _, res := range entity {
|
|||
|
ProjectId, _ := strconv.ParseInt(res.ProjectId, 10, 64)
|
|||
|
tableID := int64(res.Id)
|
|||
|
_, err = StatrDevice(ctx, res.DeviceSerial, ProjectId, tableID, "1", res.DeviceName)
|
|||
|
liberr.ErrIsNil(ctx, err)
|
|||
|
}
|
|||
|
})
|
|||
|
return err
|
|||
|
}
|
|||
|
|
|||
|
// PeriodicSnapshotFunc 摄像头定时快照
|
|||
|
func PeriodicSnapshotFunc(ctx context.Context) {
|
|||
|
err := g.Try(ctx, func(ctx context.Context) {
|
|||
|
//1、获取到摄像头列表
|
|||
|
_map := ys7.GetDeviceMap()
|
|||
|
//2、遍历获取在线的-设备串号
|
|||
|
var str []string
|
|||
|
for _, entity := range _map {
|
|||
|
if entity.Online() {
|
|||
|
str = append(str, entity.DeviceSerial)
|
|||
|
}
|
|||
|
}
|
|||
|
//3、定时抓拍
|
|||
|
if len(str) > 0 {
|
|||
|
entity, err := SelectBySerial(ctx, str)
|
|||
|
liberr.ErrIsNil(ctx, err, "获取信息失败")
|
|||
|
for _, res := range entity {
|
|||
|
ProjectId, _ := strconv.ParseInt(res.ProjectId, 10, 64)
|
|||
|
tableID := int64(res.Id)
|
|||
|
_, err = StatrDevice(ctx, res.DeviceSerial, ProjectId, tableID, "2", res.DeviceName)
|
|||
|
}
|
|||
|
}
|
|||
|
})
|
|||
|
fmt.Println("摄像头定时快照:", err)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
func SelectBySerial(ctx context.Context, serial []string) (entity []*model.Ys7DevicesInfoRes, err error) {
|
|||
|
dao.Ys7Devices.Ctx(ctx).Where("DeviceSerial in (?)", serial).Scan(&entity)
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
func StatrDevice(ctx context.Context, serial string, projectId int64, table int64, typeStr string, sxtName string) (device ys7.Ys7Device, err error) {
|
|||
|
device, err = ys7.GetDevice(serial)
|
|||
|
if err != nil {
|
|||
|
liberr.ErrIsNil(ctx, err)
|
|||
|
return
|
|||
|
}
|
|||
|
if typeStr == "1" { //手动拍照
|
|||
|
//err = TakAPictureFunc(ctx, device, projectId, table, sxtName)
|
|||
|
err = CaptureAndEnqueue(ctx, cameraQueue, device, projectId, table, sxtName)
|
|||
|
} else {
|
|||
|
go func() {
|
|||
|
goFunc(ctx, device, projectId, table, sxtName)
|
|||
|
}()
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
func goFunc(ctx context.Context, device ys7.Ys7Device, projectId int64, table int64, sxtName string) (err error) {
|
|||
|
err = g.Try(ctx, func(ctx context.Context) {
|
|||
|
//1、查询预置位
|
|||
|
var devicePresetEntity []*model.DevicePresetInfoRes
|
|||
|
_ = dao.DevicePreset.Ctx(ctx).Where("deviceSerial", device.DeviceSerial).Scan(&devicePresetEntity)
|
|||
|
//2、将在线的摄像头预置位进行遍历,每个预置点停留20秒
|
|||
|
for _, one := range devicePresetEntity {
|
|||
|
res, err := device.MovePreset(one.Index)
|
|||
|
if err != nil {
|
|||
|
g.Log("camera").Error(ctx, res.Msg)
|
|||
|
continue
|
|||
|
}
|
|||
|
if res.Code != "200" {
|
|||
|
g.Log("camera").Error(ctx, res.Msg)
|
|||
|
continue
|
|||
|
}
|
|||
|
//停留20秒
|
|||
|
time.Sleep(time.Second * 20)
|
|||
|
//err = TakAPictureFunc(ctx, device, projectId, table, sxtName)
|
|||
|
// 在每个摄像头抓图回调中调用:
|
|||
|
err = CaptureAndEnqueue(ctx, cameraQueue, device, projectId, table, sxtName)
|
|||
|
if err != nil {
|
|||
|
g.Log("camera").Error(ctx, res.Msg)
|
|||
|
continue
|
|||
|
}
|
|||
|
}
|
|||
|
return
|
|||
|
})
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
//func TakAPictureFunc(ctx context.Context, device ys7.Ys7Device, projectId int64, table int64, sxtName string) (err error) {
|
|||
|
// err = g.Try(ctx, func(ctx context.Context) {
|
|||
|
// //3、预置位停留的时候进行抓图
|
|||
|
// capture, err := device.Capture()
|
|||
|
// if err != nil {
|
|||
|
// var str = "定时快照错误:" + err.Error()
|
|||
|
// err = errors.New(str)
|
|||
|
// return
|
|||
|
// }
|
|||
|
// if capture.Code != "200" {
|
|||
|
// var str = "抓图操作失败,错误码为:" + capture.Code + ",错误描述:" + capture.Msg
|
|||
|
// err = errors.New(str)
|
|||
|
// return
|
|||
|
// }
|
|||
|
// //4、把图片存储到本地(临时地址)、把临时地址图片给到AI进行识别
|
|||
|
// lsPath, err := DownloadTheImagToLocalViaUrl(ctx, capture.Data.PicUrl, coryCommon.Temporary+"/")
|
|||
|
// if err != nil {
|
|||
|
// g.Log("camera").Error(ctx, err)
|
|||
|
// return
|
|||
|
// } else {
|
|||
|
// rpath := coryCommon.ResourcePublicToFunc(lsPath, 1)
|
|||
|
// lsPath = coryCommon.GlobalPath + rpath
|
|||
|
//
|
|||
|
// //5、需要记录摄像头的工作(拍摄的所有图片),让用户知道摄像头在正常工作
|
|||
|
// addReq := system.Ys7DevicesImgAddReq{
|
|||
|
// FatherId: uint64(table),
|
|||
|
// Name: sxtName,
|
|||
|
// Path: rpath,
|
|||
|
// }
|
|||
|
// if err = service.Ys7DevicesImg().Add(ctx, &addReq); err != nil {
|
|||
|
// g.Log("camera").Error(ctx, "记录摄像头工作记录失败")
|
|||
|
// }
|
|||
|
// }
|
|||
|
// //6、抓图完毕将URL给到AI那边进行算法操作
|
|||
|
// result, flag, err := RequestToSendFunc(ctx, lsPath, SpartaApi.YJCAMERA)
|
|||
|
// if err != nil {
|
|||
|
// return
|
|||
|
// }
|
|||
|
// if flag {
|
|||
|
// num, path, mp, err := BlockDiagramFunc(ctx, result, flag, lsPath)
|
|||
|
// if err != nil {
|
|||
|
// return
|
|||
|
// }
|
|||
|
// //5、通过算法且满足要求就进行数据存储
|
|||
|
// AddCameraImg(ctx, projectId, num, table, path, mp, sxtName)
|
|||
|
// }
|
|||
|
// return
|
|||
|
// })
|
|||
|
// return err
|
|||
|
//}
|
|||
|
|
|||
|
// AddCameraImg 项目id,违规次数,表的主键ID,算法图片
|
|||
|
func AddCameraImg(ctx context.Context, projectId int64, num int, table int64, imgPath string, mp map[string]string, sxtName string, result *SpartaApi.RecognizeRes) (err error) {
|
|||
|
err = g.DB().Transaction(ctx, func(ctx context.Context, tx gdb.TX) error {
|
|||
|
err = g.Try(ctx, func(ctx context.Context) {
|
|||
|
mpkStr := ""
|
|||
|
mpvStr := ""
|
|||
|
for key, value := range mp {
|
|||
|
mpkStr = mpkStr + key + ","
|
|||
|
mpvStr = mpvStr + value + "、"
|
|||
|
}
|
|||
|
mpkStr = strings.TrimRight(mpkStr, ",")
|
|||
|
mpvStr = strings.TrimRight(mpvStr, "、")
|
|||
|
//5、生成数据存储到数据表中(识别记录)
|
|||
|
path := coryCommon.ResourcePublicToFunc(imgPath, 1)
|
|||
|
addReq := system.BusTourAddReq{
|
|||
|
ProjectId: projectId,
|
|||
|
TourCategory: "2",
|
|||
|
TourType: mpkStr,
|
|||
|
Picture: path,
|
|||
|
Describe: mpvStr,
|
|||
|
Num: num,
|
|||
|
TableName: dao.Ys7Devices.Table(),
|
|||
|
TableId: table,
|
|||
|
SxtName: sxtName,
|
|||
|
}
|
|||
|
err2 := service.BusTour().Add(ctx, &addReq)
|
|||
|
if err2 == nil {
|
|||
|
//1、本地创建一个text来记录日志
|
|||
|
// 定义文件路径
|
|||
|
filePath := coryCommon.GetCWD() + "/coryLogs/logs/ai_log.txt"
|
|||
|
// 打开文件,如果文件不存在则创建
|
|||
|
file, err := os.OpenFile(filePath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
|||
|
if err != nil {
|
|||
|
log.Fatal(err)
|
|||
|
}
|
|||
|
defer file.Close()
|
|||
|
// 写入日志信息
|
|||
|
marshal, _ := json.Marshal(result)
|
|||
|
_, err = file.WriteString(fmt.Sprintf("项目ID:%d,违规次数:%d,表的主键ID:%d,算法图片:%s,识别结果:%s,----------%s\n", projectId, num, table, imgPath, mpvStr, string(marshal)))
|
|||
|
if err != nil {
|
|||
|
log.Fatal(err)
|
|||
|
}
|
|||
|
}
|
|||
|
//6、生成数据存储到违规记录里面
|
|||
|
var bvl *model.BusViolationLevelInfoRes
|
|||
|
llike := dao.BusViolationLevel.Ctx(ctx).As("a").Safe()
|
|||
|
for _, zd := range strings.Split(mpkStr, ",") {
|
|||
|
llike = llike.WhereOr("a.tour_type like ?", "%"+zd+"%")
|
|||
|
}
|
|||
|
err := llike.LeftJoin("sys_dict_data", "c", "c.dict_type = 'risx' and c.dict_value = a.risx").Fields("a.id,a.grade,c.dict_label").Scan(&bvl)
|
|||
|
liberr.ErrIsNil(ctx, err)
|
|||
|
if bvl == nil {
|
|||
|
err = errors.New("请设置违章等级!")
|
|||
|
g.Log().Error(ctx, "请设置违章等级!")
|
|||
|
return
|
|||
|
}
|
|||
|
recordAddReq := do.BusViolationRecord{
|
|||
|
ProjectId: projectId,
|
|||
|
LevelId: bvl.Id,
|
|||
|
Level: bvl.Grade + ":" + bvl.DictLabel,
|
|||
|
TourType: mpkStr,
|
|||
|
DataSource: "camera",
|
|||
|
SxtName: sxtName,
|
|||
|
//Picture: path,
|
|||
|
//WxOrPc: "1",
|
|||
|
}
|
|||
|
info, err := dao.BusViolationRecord.Ctx(ctx).Insert(recordAddReq)
|
|||
|
liberr.ErrIsNil(ctx, err)
|
|||
|
id, _ := info.LastInsertId()
|
|||
|
if path != "" { //给BusViolationRecord插入附件信息
|
|||
|
pathSplit := strings.Split(path, "/")
|
|||
|
fileInfo := strings.Split(pathSplit[len(pathSplit)-1], ".")
|
|||
|
_, err = g.DB().Model("bus_violation_record_path").Ctx(ctx).Insert(
|
|||
|
g.Map{
|
|||
|
"ticket_id": id,
|
|||
|
"type": 1,
|
|||
|
"name": fileInfo[0],
|
|||
|
"path": path,
|
|||
|
"file_type": fileInfo[1]})
|
|||
|
liberr.ErrIsNil(ctx, err)
|
|||
|
}
|
|||
|
//7、通过违章记录拿到等级关联的岗位信息,再根据岗位拿到具体需要通知的人(需要存储通知的人),然后给他们发通知信息
|
|||
|
err, posts := logic.SelectLevelByPostInfo(ctx, bvl.Id)
|
|||
|
liberr.ErrIsNil(ctx, err)
|
|||
|
var violationRecordCorrelationEntity []*model.ViolationRecordCorrelation
|
|||
|
var postId []int
|
|||
|
for _, post := range posts {
|
|||
|
userIDs, _ := dao.SysUserPost.Ctx(ctx).Where("post_id", post.PostId).Fields(dao.SysUserPost.Columns().UserId).Distinct().Array()
|
|||
|
for _, d := range userIDs {
|
|||
|
violationRecordCorrelationEntity = append(violationRecordCorrelationEntity, &model.ViolationRecordCorrelation{
|
|||
|
RecordId: id,
|
|||
|
UserId: d.Int64(),
|
|||
|
PostId: int64(post.PostId),
|
|||
|
})
|
|||
|
postId = append(postId, int(post.PostId))
|
|||
|
}
|
|||
|
}
|
|||
|
_, err = g.DB().Model("bus_violation_record_correlation").Ctx(ctx).Insert(violationRecordCorrelationEntity)
|
|||
|
liberr.ErrIsNil(ctx, err, "存储通知的人失败")
|
|||
|
var userId uint64 = 1
|
|||
|
err = PublicPublish(ctx, &system.NotificationsPublishReq{
|
|||
|
NotificationText: "【您有一份重要的违章需要处理!】工单号为:" + strconv.FormatInt(id, 10),
|
|||
|
Positions: postId,
|
|||
|
ProjectId: int(projectId),
|
|||
|
}, userId)
|
|||
|
liberr.ErrIsNil(ctx, err)
|
|||
|
})
|
|||
|
return err
|
|||
|
})
|
|||
|
return err
|
|||
|
}
|
|||
|
|
|||
|
// DownloadTheImagToLocalViaUrl 通过url下载图片到本地
|
|||
|
func DownloadTheImagToLocalViaUrl(ctx context.Context, picUrl string, lj string) (imgPath string, err error) {
|
|||
|
get, err := g.Client().Get(gctx.New(), picUrl)
|
|||
|
if err != nil {
|
|||
|
return "", err
|
|||
|
}
|
|||
|
st := strings.Split(picUrl, ".")
|
|||
|
sp := strings.Split(st[len(st)-1], "?")
|
|||
|
imgPath = coryCommon.GetCWD() + "/" + coryCommon.Ynr(lj) + coryCommon.FileName("sxt_") + "." + sp[0]
|
|||
|
imgPath = filepath.ToSlash(imgPath)
|
|||
|
err = os.WriteFile(imgPath, get.ReadAll(), 0666)
|
|||
|
if err != nil {
|
|||
|
err = errors.New("存储图片失败")
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
func RequestToSendFunc(ctx context.Context, lsPath, recType string) (result *SpartaApi.RecognizeRes, flag bool, err error) {
|
|||
|
req := SpartaApi.RecognizeReq{
|
|||
|
CapUrl: lsPath,
|
|||
|
RecType: recType,
|
|||
|
Async: "False",
|
|||
|
CallBackUrl: "",
|
|||
|
AreaHigh: "",
|
|||
|
}
|
|||
|
result, flag, err = SpartaApi.CommonAlgorithmTwoFunc(ctx, &req)
|
|||
|
if err != nil {
|
|||
|
return
|
|||
|
} else {
|
|||
|
ewflag := false
|
|||
|
//把精度不高的数据剔除
|
|||
|
if result.HasTarget == 1 {
|
|||
|
for i := 0; i < len(result.Targets); i++ {
|
|||
|
if result.Targets[i].Score < SpartaApi.Sensitivity {
|
|||
|
result.Targets = append(result.Targets[:i], result.Targets[i+1:]...)
|
|||
|
i--
|
|||
|
} else {
|
|||
|
ewflag = true
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if ewflag == false {
|
|||
|
flag = false
|
|||
|
result.HasTarget = 0
|
|||
|
}
|
|||
|
}
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
// @Title BlockDiagramFunc 2024/8/7 17:12:00
|
|||
|
// @Description 函数的详细描述
|
|||
|
// @Auth Cory
|
|||
|
// @param 输入参数名 ---> "参数解释"
|
|||
|
// @Return error ---> "错误信息"
|
|||
|
func BlockDiagramFunc(ctx context.Context, result *SpartaApi.RecognizeRes, flag bool, lsPath string) (num int, imgPath string, mp map[string]string, err error) {
|
|||
|
imgPath, err = DownloadTheImagToLocalViaUrl(ctx, lsPath, coryCommon.Helmet)
|
|||
|
if err != nil {
|
|||
|
return
|
|||
|
}
|
|||
|
/**
|
|||
|
框出图片中有错误的地方
|
|||
|
*/
|
|||
|
num = 0
|
|||
|
mp = make(map[string]string)
|
|||
|
entity := coryCommon.TestDrawRectTextEntity{
|
|||
|
ImPath: imgPath,
|
|||
|
}
|
|||
|
var zuobiao []*coryCommon.CoordinatesListEntity
|
|||
|
for _, data := range result.Targets {
|
|||
|
if data.Score >= SpartaApi.Sensitivity {
|
|||
|
tp := data.Type
|
|||
|
mp[tp] = SpartaApi.GetDescription(tp)
|
|||
|
flag = true
|
|||
|
num = num + 1
|
|||
|
zuobiao = append(zuobiao, &coryCommon.CoordinatesListEntity{
|
|||
|
X: data.LeftTopPoint[0],
|
|||
|
Y: data.LeftTopPoint[1],
|
|||
|
W: data.Size[0],
|
|||
|
H: data.Size[1],
|
|||
|
})
|
|||
|
}
|
|||
|
}
|
|||
|
entity.Coordinates = zuobiao
|
|||
|
coryCommon.TestDrawRectTextFunc(&entity)
|
|||
|
//coryCommon.Test_draw_rect_text(imgPath, data.LeftTopPoint[0], data.LeftTopPoint[1], data.Size[0], data.Size[1])
|
|||
|
return
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
================================================
|
|||
|
固定协程池(Worker Pool)并发处理,外加无限队列
|
|||
|
================================================
|
|||
|
*/
|
|||
|
|
|||
|
var cameraQueue *TaskQueue
|
|||
|
|
|||
|
func init() {
|
|||
|
fmt.Println("初始化摄像头算法队列*8")
|
|||
|
once.Do(func() {
|
|||
|
cameraQueue = InitCameraQueueSystem(gctx.New())
|
|||
|
})
|
|||
|
}
|
|||
|
|
|||
|
type TaskQueue struct {
|
|||
|
lock sync.Mutex
|
|||
|
cond *sync.Cond
|
|||
|
tasks []CameraImageTask
|
|||
|
}
|
|||
|
|
|||
|
func NewTaskQueue() *TaskQueue {
|
|||
|
q := &TaskQueue{}
|
|||
|
q.cond = sync.NewCond(&q.lock)
|
|||
|
return q
|
|||
|
}
|
|||
|
|
|||
|
func (q *TaskQueue) Enqueue(task CameraImageTask) {
|
|||
|
q.lock.Lock()
|
|||
|
q.tasks = append(q.tasks, task)
|
|||
|
q.cond.Signal() // 通知一个等待的 worker
|
|||
|
q.lock.Unlock()
|
|||
|
}
|
|||
|
|
|||
|
func (q *TaskQueue) Dequeue() CameraImageTask {
|
|||
|
q.lock.Lock()
|
|||
|
for len(q.tasks) == 0 {
|
|||
|
q.cond.Wait() // 等待入队
|
|||
|
}
|
|||
|
task := q.tasks[0]
|
|||
|
q.tasks = q.tasks[1:]
|
|||
|
q.lock.Unlock()
|
|||
|
return task
|
|||
|
}
|
|||
|
|
|||
|
type CameraImageTask struct {
|
|||
|
ProjectId int64
|
|||
|
Table int64
|
|||
|
SxtName string
|
|||
|
LsPath string
|
|||
|
}
|
|||
|
|
|||
|
// StartWorkerPool 启动协程池消费任务
|
|||
|
func StartWorkerPool(ctx context.Context, queue *TaskQueue, workerNum int) {
|
|||
|
for i := 0; i < workerNum; i++ {
|
|||
|
go func(workerId int) {
|
|||
|
for {
|
|||
|
task := queue.Dequeue() // 阻塞直到有任务
|
|||
|
err := ProcessCameraImageTask(ctx, task)
|
|||
|
if err != nil {
|
|||
|
g.Log("camera").Errorf(ctx, "Worker %d 执行任务失败: %v", workerId, err)
|
|||
|
}
|
|||
|
}
|
|||
|
}(i)
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// CaptureAndEnqueue 抓图后入队
|
|||
|
func CaptureAndEnqueue(ctx context.Context, queue *TaskQueue, device ys7.Ys7Device, projectId, table int64, sxtName string) error {
|
|||
|
capture, err := device.Capture()
|
|||
|
if err != nil {
|
|||
|
return fmt.Errorf("定时快照错误:%w", err)
|
|||
|
}
|
|||
|
if capture.Code != "200" {
|
|||
|
return fmt.Errorf("抓图操作失败,错误码为:%s, 错误描述:%s", capture.Code, capture.Msg)
|
|||
|
}
|
|||
|
|
|||
|
lsPath, err := DownloadTheImagToLocalViaUrl(ctx, capture.Data.PicUrl, coryCommon.Temporary+"/")
|
|||
|
if err != nil {
|
|||
|
return fmt.Errorf("图片下载失败:%w", err)
|
|||
|
}
|
|||
|
|
|||
|
rpath := coryCommon.ResourcePublicToFunc(lsPath, 1)
|
|||
|
fullPath := coryCommon.GlobalPath + rpath
|
|||
|
|
|||
|
addReq := system.Ys7DevicesImgAddReq{
|
|||
|
FatherId: uint64(table),
|
|||
|
Name: sxtName,
|
|||
|
Path: rpath,
|
|||
|
}
|
|||
|
if err = service.Ys7DevicesImg().Add(ctx, &addReq); err != nil {
|
|||
|
g.Log("camera").Error(ctx, "记录摄像头工作记录失败:", err)
|
|||
|
}
|
|||
|
|
|||
|
// 入队
|
|||
|
queue.Enqueue(CameraImageTask{
|
|||
|
ProjectId: projectId,
|
|||
|
Table: table,
|
|||
|
SxtName: sxtName,
|
|||
|
LsPath: fullPath,
|
|||
|
})
|
|||
|
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// ProcessCameraImageTask 处理任务逻辑
|
|||
|
func ProcessCameraImageTask(ctx context.Context, task CameraImageTask) error {
|
|||
|
fmt.Println("已进入队列算法---------》", task.SxtName)
|
|||
|
result, flag, err := RequestToSendFunc(ctx, task.LsPath, SpartaApi.YJCAMERA)
|
|||
|
fmt.Println("==>", result)
|
|||
|
if err != nil {
|
|||
|
return fmt.Errorf("AI识别失败:%w", err)
|
|||
|
}
|
|||
|
if flag {
|
|||
|
num, path, mp, err := BlockDiagramFunc(ctx, result, flag, task.LsPath)
|
|||
|
if err != nil {
|
|||
|
return fmt.Errorf("图像分析失败:%w", err)
|
|||
|
}
|
|||
|
AddCameraImg(ctx, task.ProjectId, num, task.Table, path, mp, task.SxtName, result)
|
|||
|
}
|
|||
|
return nil
|
|||
|
}
|
|||
|
|
|||
|
// 启动
|
|||
|
func InitCameraQueueSystem(ctx context.Context) *TaskQueue {
|
|||
|
queue := NewTaskQueue()
|
|||
|
StartWorkerPool(ctx, queue, 1)
|
|||
|
return queue // 🔁 返回 queue 供调用者使用
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
//
|
|||
|
//func init() {
|
|||
|
// fmt.Println("初始化队列形式处理算法(同时10个协程来跑数据)")
|
|||
|
// ctx := gctx.New()
|
|||
|
// StartCameraImageWorkerPool(ctx, 10) // 启动10个工作协程
|
|||
|
//}
|
|||
|
//
|
|||
|
//type CameraImageTask struct {
|
|||
|
// ProjectId int64
|
|||
|
// Table int64
|
|||
|
// SxtName string
|
|||
|
// LsPath string
|
|||
|
//}
|
|||
|
//
|
|||
|
//var cameraImageQueue = make(chan CameraImageTask, 100) // 队列容量视实际情况设置
|
|||
|
//
|
|||
|
//func TakAPictureFunc(ctx context.Context, device ys7.Ys7Device, projectId, table int64, sxtName string) error {
|
|||
|
// capture, err := device.Capture()
|
|||
|
// if err != nil {
|
|||
|
// return fmt.Errorf("定时快照错误:%w", err)
|
|||
|
// }
|
|||
|
// if capture.Code != "200" {
|
|||
|
// return fmt.Errorf("抓图操作失败,错误码为:%s, 错误描述:%s", capture.Code, capture.Msg)
|
|||
|
// }
|
|||
|
//
|
|||
|
// lsPath, err := DownloadTheImagToLocalViaUrl(ctx, capture.Data.PicUrl, coryCommon.Temporary+"/")
|
|||
|
// if err != nil {
|
|||
|
// return fmt.Errorf("图片下载失败:%w", err)
|
|||
|
// }
|
|||
|
//
|
|||
|
// rpath := coryCommon.ResourcePublicToFunc(lsPath, 1)
|
|||
|
// fullPath := coryCommon.GlobalPath + rpath
|
|||
|
//
|
|||
|
// addReq := system.Ys7DevicesImgAddReq{
|
|||
|
// FatherId: uint64(table),
|
|||
|
// Name: sxtName,
|
|||
|
// Path: rpath,
|
|||
|
// }
|
|||
|
// if err = service.Ys7DevicesImg().Add(ctx, &addReq); err != nil {
|
|||
|
// g.Log("camera").Error(ctx, "记录摄像头工作记录失败:", err)
|
|||
|
// }
|
|||
|
//
|
|||
|
// // 入队任务
|
|||
|
// cameraImageQueue <- CameraImageTask{
|
|||
|
// ProjectId: projectId,
|
|||
|
// Table: table,
|
|||
|
// SxtName: sxtName,
|
|||
|
// LsPath: fullPath,
|
|||
|
// }
|
|||
|
// return nil
|
|||
|
//}
|
|||
|
//
|
|||
|
//func StartCameraImageWorkerPool(ctx context.Context, workerNum int) {
|
|||
|
// for i := 0; i < workerNum; i++ {
|
|||
|
// go func(workerId int) {
|
|||
|
// for task := range cameraImageQueue {
|
|||
|
// err := ProcessCameraImageTask(ctx, task)
|
|||
|
// if err != nil {
|
|||
|
// g.Log("camera").Errorf(ctx, "Worker %d 处理任务出错: %v", workerId, err)
|
|||
|
// }
|
|||
|
// }
|
|||
|
// }(i)
|
|||
|
// }
|
|||
|
//}
|
|||
|
//
|
|||
|
//func ProcessCameraImageTask(ctx context.Context, task CameraImageTask) error {
|
|||
|
// result, flag, err := RequestToSendFunc(ctx, task.LsPath, SpartaApi.YJCAMERA)
|
|||
|
// if err != nil {
|
|||
|
// return fmt.Errorf("AI 请求失败:%w", err)
|
|||
|
// }
|
|||
|
// if flag {
|
|||
|
// num, path, mp, err := BlockDiagramFunc(ctx, result, flag, task.LsPath)
|
|||
|
// if err != nil {
|
|||
|
// return fmt.Errorf("图像处理失败:%w", err)
|
|||
|
// }
|
|||
|
// AddCameraImg(ctx, task.ProjectId, num, task.Table, path, mp, task.SxtName)
|
|||
|
// }
|
|||
|
// return nil
|
|||
|
//}
|