添加定时清理相关

This commit is contained in:
Sake 2026-01-17 16:19:36 +08:00
parent 8540f76fcf
commit 9cfb302777
30 changed files with 1655 additions and 243 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 647 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 90 KiB

View File

@ -30,7 +30,7 @@ func WireApp(bc *conf.Bootstrap, log *slog.Logger) (http.Handler, func(), error)
vqdTaskCore := api.NewVqdTaskCore(db) vqdTaskCore := api.NewVqdTaskCore(db)
hostCore := host.NewCore(bc) hostCore := host.NewCore(bc)
mediaCore := media.NewCore(hostCore) mediaCore := media.NewCore(hostCore)
vqdSdkCore := vqdsdk.NewCore(hostCore, vqdTaskCore) vqdSdkCore := vqdsdk.NewCore(hostCore, vqdTaskCore, bc)
vqdTaskAPI := api.NewVqdTaskAPI(vqdTaskCore, mediaCore,vqdSdkCore,hostCore, bc) vqdTaskAPI := api.NewVqdTaskAPI(vqdTaskCore, mediaCore,vqdSdkCore,hostCore, bc)
usecase := &api.Usecase{ usecase := &api.Usecase{

View File

@ -5,6 +5,7 @@ import (
"context" "context"
"easyvqd/internal/core/vqd" "easyvqd/internal/core/vqd"
"git.lnton.com/lnton/pkg/orm" "git.lnton.com/lnton/pkg/orm"
"time"
) )
var _ vqd.VqdAlarmStorer = VqdAlarm{} var _ vqd.VqdAlarmStorer = VqdAlarm{}
@ -48,6 +49,15 @@ func (d VqdAlarm) Del(ctx context.Context, model *vqd.VqdAlarm, opts ...orm.Quer
return orm.DeleteWithContext(ctx, d.db, model, opts...) return orm.DeleteWithContext(ctx, d.db, model, opts...)
} }
// DelAll implements vqd.VqdTaskTemplateStorer.
func (d VqdAlarm) DelAll(expireTime time.Time, batchSize int) (int, error) {
result := d.db.Where(`created_at < ?`, expireTime).Limit(batchSize).Delete(&vqd.VqdAlarm{})
if result.Error != nil {
return 0, result.Error
}
return int(result.RowsAffected), nil
}
// EditStatus implements vqd.VqdAlarmStorer. // EditStatus implements vqd.VqdAlarmStorer.
func (d VqdAlarm) EditStatus(status int, id int) error { func (d VqdAlarm) EditStatus(status int, id int) error {
if err := d.db.Model(&vqd.VqdAlarm{}).Where(`id = ?`, id).Update("task_status", status).Error; err != nil { if err := d.db.Model(&vqd.VqdAlarm{}).Where(`id = ?`, id).Update("task_status", status).Error; err != nil {

View File

@ -55,3 +55,6 @@ func (d VqdTaskTemplate) EditStatus(status vqd.EncodeStatus, id int) error {
} }
return nil return nil
} }
func (d VqdTaskTemplate) FirstOrCreate(b any) error {
return d.db.FirstOrCreate(b).Error
}

View File

@ -7,6 +7,7 @@ import (
"git.lnton.com/lnton/pkg/reason" "git.lnton.com/lnton/pkg/reason"
"github.com/jinzhu/copier" "github.com/jinzhu/copier"
"log/slog" "log/slog"
"time"
) )
// VqdAlarmStorer Instantiation interface // VqdAlarmStorer Instantiation interface
@ -17,6 +18,7 @@ type VqdAlarmStorer interface {
Add(context.Context, *VqdAlarm) error Add(context.Context, *VqdAlarm) error
Edit(context.Context, *VqdAlarm, func(*VqdAlarm), ...orm.QueryOption) error Edit(context.Context, *VqdAlarm, func(*VqdAlarm), ...orm.QueryOption) error
Del(context.Context, *VqdAlarm, ...orm.QueryOption) error Del(context.Context, *VqdAlarm, ...orm.QueryOption) error
DelAll(expireTime time.Time, batchSize int) (int, error)
} }
// FindVqdAlarmAll Paginated search // FindVqdAlarmAll Paginated search
@ -113,3 +115,8 @@ func (c Core) DelVqdAlarmAll(ctx context.Context, ids []int) (*VqdAlarm, error)
} }
return &out, nil return &out, nil
} }
// DelVqdTaskAlarmAll Delete object
func (c Core) DelVqdTaskAlarmAll(expireTime time.Time, batchSize int) (int, error) {
return c.store.VqdAlarm().DelAll(expireTime, batchSize)
}

View File

@ -52,6 +52,18 @@ func (c Core) FindVqdTask(ctx context.Context, in *FindVqdTaskInput) ([]*VqdTask
} }
} }
// FindVqdTaskTemplateID Query a single object
func (c Core) FindVqdTaskTemplateID(ctx context.Context, id int) (*VqdTask, error) {
var out VqdTask
if err := c.store.VqdTask().Get(ctx, &out, orm.Where("task_template_id=?", id)); err != nil {
if orm.IsErrRecordNotFound(err) {
return nil, reason.ErrNotFound.Withf(`Get err[%s]`, err.Error())
}
return nil, reason.ErrDB.Withf(`Get err[%s]`, err.Error())
}
return &out, nil
}
// GetVqdTask Query a single object // GetVqdTask Query a single object
func (c Core) GetVqdTask(ctx context.Context, id int) (*VqdTask, error) { func (c Core) GetVqdTask(ctx context.Context, id int) (*VqdTask, error) {
var out VqdTask var out VqdTask
@ -63,6 +75,7 @@ func (c Core) GetVqdTask(ctx context.Context, id int) (*VqdTask, error) {
} }
return &out, nil return &out, nil
} }
func (c Core) GetNameVqdTask(ctx context.Context, name string) (*VqdTask, error) { func (c Core) GetNameVqdTask(ctx context.Context, name string) (*VqdTask, error) {
var out VqdTask var out VqdTask
if err := c.store.VqdTask().Get(ctx, &out, orm.Where("name=?", name)); err != nil { if err := c.store.VqdTask().Get(ctx, &out, orm.Where("name=?", name)); err != nil {

View File

@ -14,7 +14,7 @@ type EditVqdTaskInput struct {
Name string `json:"name"` // 名称 Name string `json:"name"` // 名称
ChannelID string `json:"channel_id"` // 关联通道 ChannelID string `json:"channel_id"` // 关联通道
ChannelName string `json:"channel_name"` // 通道名称 ChannelName string `json:"channel_name"` // 通道名称
TaskTemplateID string `json:"task_template_id"` // 关联模板 TaskTemplateID int `json:"task_template_id"` // 关联模板
TaskTemplateName string `json:"task_template_name"` // 模板名称 TaskTemplateName string `json:"task_template_name"` // 模板名称
Enable bool `form:"enable"` // 启用 Enable bool `form:"enable"` // 启用
Des string `json:"des"` // 描述 Des string `json:"des"` // 描述
@ -24,7 +24,7 @@ type AddVqdTaskInput struct {
Name string `json:"name"` // 名称 Name string `json:"name"` // 名称
ChannelID string `json:"channel_id"` // 关联通道 ChannelID string `json:"channel_id"` // 关联通道
ChannelName string `json:"channel_name"` // 通道名称 ChannelName string `json:"channel_name"` // 通道名称
TaskTemplateID string `json:"task_template_id"` // 关联模板 TaskTemplateID int `json:"task_template_id"` // 关联模板
TaskTemplateName string `json:"task_template_name"` // 模板名称 TaskTemplateName string `json:"task_template_name"` // 模板名称
Enable bool `form:"enable"` // 启用 Enable bool `form:"enable"` // 启用
Des string `json:"des"` // 描述 Des string `json:"des"` // 描述

View File

@ -17,6 +17,8 @@ type VqdTaskTemplateStorer interface {
Add(context.Context, *VqdTaskTemplate) error Add(context.Context, *VqdTaskTemplate) error
Edit(context.Context, *VqdTaskTemplate, func(*VqdTaskTemplate), ...orm.QueryOption) error Edit(context.Context, *VqdTaskTemplate, func(*VqdTaskTemplate), ...orm.QueryOption) error
Del(context.Context, *VqdTaskTemplate, ...orm.QueryOption) error Del(context.Context, *VqdTaskTemplate, ...orm.QueryOption) error
FirstOrCreate(b any) error
} }
// FindVqdTaskTemplateAll Paginated search // FindVqdTaskTemplateAll Paginated search
@ -33,16 +35,14 @@ func (c Core) FindVqdTaskTemplateAll() ([]*VqdTaskTemplate, int64, error) {
func (c Core) FindVqdTaskTemplate(ctx context.Context, in *FindVqdTaskTemplateInput) ([]*VqdTaskTemplate, int64, error) { func (c Core) FindVqdTaskTemplate(ctx context.Context, in *FindVqdTaskTemplateInput) ([]*VqdTaskTemplate, int64, error) {
items := make([]*VqdTaskTemplate, 0) items := make([]*VqdTaskTemplate, 0)
if in.Name != "" { if in.Name != "" {
query := orm.NewQuery(8). query := orm.NewQuery(8).Where("name like ? ", "%"+in.Name+"%")
Where("name like ? ", "%"+in.Name+"%").OrderBy("created_at DESC")
total, err := c.store.VqdTaskTemplate().Find(ctx, &items, in, query.Encode()...) total, err := c.store.VqdTaskTemplate().Find(ctx, &items, in, query.Encode()...)
if err != nil { if err != nil {
return nil, 0, reason.ErrDB.Withf(`Find err[%s]`, err.Error()) return nil, 0, reason.ErrDB.Withf(`Find err[%s]`, err.Error())
} }
return items, total, nil return items, total, nil
} else { } else {
query := orm.NewQuery(2).OrderBy("created_at DESC") total, err := c.store.VqdTaskTemplate().Find(ctx, &items, in)
total, err := c.store.VqdTaskTemplate().Find(ctx, &items, in, query.Encode()...)
if err != nil { if err != nil {
return nil, 0, reason.ErrDB.Withf(`Find err[%s]`, err.Error()) return nil, 0, reason.ErrDB.Withf(`Find err[%s]`, err.Error())
} }
@ -61,6 +61,16 @@ func (c Core) GetVqdTaskTemplate(ctx context.Context, id int) (*VqdTaskTemplate,
} }
return &out, nil return &out, nil
} }
func (c Core) GetIDVqdTaskTemplate(ctx context.Context, ID int64) (*VqdTaskTemplate, error) {
var out VqdTaskTemplate
if err := c.store.VqdTaskTemplate().Get(ctx, &out, orm.Where("id=?", ID)); err != nil {
if orm.IsErrRecordNotFound(err) {
return nil, reason.ErrNotFound.Withf(`Get err[%s]`, err.Error())
}
return nil, reason.ErrDB.Withf(`Get err[%s]`, err.Error())
}
return &out, nil
}
func (c Core) GetNameVqdTaskTemplate(ctx context.Context, name string) (*VqdTaskTemplate, error) { func (c Core) GetNameVqdTaskTemplate(ctx context.Context, name string) (*VqdTaskTemplate, error) {
var out VqdTaskTemplate var out VqdTaskTemplate
if err := c.store.VqdTaskTemplate().Get(ctx, &out, orm.Where("name=?", name)); err != nil { if err := c.store.VqdTaskTemplate().Get(ctx, &out, orm.Where("name=?", name)); err != nil {
@ -72,6 +82,11 @@ func (c Core) GetNameVqdTaskTemplate(ctx context.Context, name string) (*VqdTask
return &out, nil return &out, nil
} }
// FirstOrCreateTemplate Insert into database
func (c Core) FirstOrCreateTemplate(b any) error {
return c.store.VqdTaskTemplate().FirstOrCreate(b)
}
// AddVqdTaskTemplate Insert into database // AddVqdTaskTemplate Insert into database
func (c Core) AddVqdTaskTemplate(ctx context.Context, in *AddVqdTaskTemplateInput) (*VqdTaskTemplate, error) { func (c Core) AddVqdTaskTemplate(ctx context.Context, in *AddVqdTaskTemplateInput) (*VqdTaskTemplate, error) {
var out VqdTaskTemplate var out VqdTaskTemplate

View File

@ -11,39 +11,39 @@ type FindVqdTaskTemplateInput struct {
} }
type EditVqdTaskTemplateInput struct { type EditVqdTaskTemplateInput struct {
Name string `json:"name"` Name string `json:"name"`
Plans string `json:"plans"` Plans string `json:"plans"`
Enable bool `json:"enable"` Enable bool `json:"enable"`
//VqdConfig VqdConfig `json:"vqd_config"` // 诊断基础配置 VqdConfig VqdConfig `json:"vqd_config"` // 诊断基础配置
//VqdLgtDark VqdLgtDark `json:"vqd_lgt_dark"` // 亮度检测 VqdLgtDark VqdLgtDark `json:"vqd_lgt_dark"` // 亮度检测
//VqdBlue VqdBlue `json:"vqd_blue"` // 蓝屏检查 VqdBlue VqdBlue `json:"vqd_blue"` // 蓝屏检查
//VqdClarity VqdClarity `json:"vqd_clarity"` // 清晰度检查 VqdClarity VqdClarity `json:"vqd_clarity"` // 清晰度检查
//VqdShark VqdShark `json:"vqd_shark"` // 抖动检查 VqdShark VqdShark `json:"vqd_shark"` // 抖动检查
//VqdFreeze VqdFreeze `json:"vqd_freeze"` // 冻结检测 VqdFreeze VqdFreeze `json:"vqd_freeze"` // 冻结检测
//VqdColor VqdColor `json:"vqd_color"` // 偏色检测 VqdColor VqdColor `json:"vqd_color"` // 偏色检测
//VqdOcclusion VqdOcclusion `json:"vqd_occlusion"` // 遮挡检测 VqdOcclusion VqdOcclusion `json:"vqd_occlusion"` // 遮挡检测
//VqdNoise VqdNoise `json:"vqd_noise"` // 噪声检测 VqdNoise VqdNoise `json:"vqd_noise"` // 噪声检测
//VqdContrast VqdContrast `json:"vqd_contrast"` // 对比度检测 VqdContrast VqdContrast `json:"vqd_contrast"` // 对比度检测
//VqdMosaic VqdMosaic `json:"vqd_mosaic"` // 马赛克检测 VqdMosaic VqdMosaic `json:"vqd_mosaic"` // 马赛克检测
//VqdFlower VqdFlower `json:"vqd_flower"` // 花屏检测 VqdFlower VqdFlower `json:"vqd_flower"` // 花屏检测
Des string ` json:"des"` // 描述 Des string ` json:"des"` // 描述
} }
type AddVqdTaskTemplateInput struct { type AddVqdTaskTemplateInput struct {
Name string `json:"name"` Name string `json:"name"`
Plans string `json:"plans"` Plans string `json:"plans"`
Enable bool `json:"enable"` Enable bool `json:"enable"`
//VqdConfig VqdConfig `json:"vqd_config"` // 诊断基础配置 VqdConfig VqdConfig `json:"vqd_config"` // 诊断基础配置
//VqdLgtDark VqdLgtDark `json:"vqd_lgt_dark"` // 亮度检测 VqdLgtDark VqdLgtDark `json:"vqd_lgt_dark"` // 亮度检测
//VqdBlue VqdBlue `json:"vqd_blue"` // 蓝屏检查 VqdBlue VqdBlue `json:"vqd_blue"` // 蓝屏检查
//VqdClarity VqdClarity `json:"vqd_clarity"` // 清晰度检查 VqdClarity VqdClarity `json:"vqd_clarity"` // 清晰度检查
//VqdShark VqdShark `json:"vqd_shark"` // 抖动检查 VqdShark VqdShark `json:"vqd_shark"` // 抖动检查
//VqdFreeze VqdFreeze `json:"vqd_freeze"` // 冻结检测 VqdFreeze VqdFreeze `json:"vqd_freeze"` // 冻结检测
//VqdColor VqdColor `json:"vqd_color"` // 偏色检测 VqdColor VqdColor `json:"vqd_color"` // 偏色检测
//VqdOcclusion VqdOcclusion `json:"vqd_occlusion"` // 遮挡检测 VqdOcclusion VqdOcclusion `json:"vqd_occlusion"` // 遮挡检测
//VqdNoise VqdNoise `json:"vqd_noise"` // 噪声检测 VqdNoise VqdNoise `json:"vqd_noise"` // 噪声检测
//VqdContrast VqdContrast `json:"vqd_contrast"` // 对比度检测 VqdContrast VqdContrast `json:"vqd_contrast"` // 对比度检测
//VqdMosaic VqdMosaic `json:"vqd_mosaic"` // 马赛克检测 VqdMosaic VqdMosaic `json:"vqd_mosaic"` // 马赛克检测
//VqdFlower VqdFlower `json:"vqd_flower"` // 花屏检测 VqdFlower VqdFlower `json:"vqd_flower"` // 花屏检测
Des string ` json:"des"` // 描述 Des string ` json:"des"` // 描述
} }

View File

@ -0,0 +1,227 @@
package vqdsdk
import (
"fmt"
"io/fs"
"log/slog"
"os"
"path/filepath"
"time"
)
// 配置参数
const (
// 要清理的目标目录(请替换为你实际的目录路径)
cleanDir = "/snap"
// 定时任务执行间隔(每天执行一次)
interval = 24 * time.Hour
// 批量删除大小(避免单次删除过多锁表)
batchSize = 1000
// 日期目录的格式(如 20260117
dateDirLayout = "20060102"
// 定时任务首次执行时间每天凌晨1点
executeHour = 1
)
// scheduleCleanFile 定时执行清理任务
func (c Core) scheduleCleanTask() {
// 计算首次执行时间(今天/明天的凌晨1点
now := time.Now()
nextExec := time.Date(now.Year(), now.Month(), now.Day(), executeHour, 0, 0, 0, now.Location())
if nextExec.Before(now) {
nextExec = nextExec.Add(24 * time.Hour)
}
// 计算首次执行的等待时间
initialDelay := nextExec.Sub(now)
slog.Info(fmt.Sprintf("定时任务已启动,首次执行时间:%s等待 %v", nextExec.Format(time.RFC3339), initialDelay))
// 首次执行等待
time.Sleep(initialDelay)
// 执行首次清理
if err := c.cleanExpiredFiles(); err != nil {
slog.Error("首次清理任务执行失败 Files", "err", err)
}
time.Sleep(20 * time.Minute)
if err := c.cleanExpiredDbs(); err != nil {
slog.Error("首次清理任务执行失败 Dbs", "err", err)
}
// 循环执行定时任务
ticker := time.NewTicker(interval)
defer ticker.Stop()
for range ticker.C {
if err := c.cleanExpiredFiles(); err != nil {
slog.Error("定时清理任务执行失败 Files", "err", err)
}
time.Sleep(20 * time.Minute)
if err := c.cleanExpiredDbs(); err != nil {
slog.Error("定时清理任务执行失败 Dbs", "err", err)
}
}
}
// cleanExpiredDbs 清理超过expireDays天的数据
func (c Core) cleanExpiredDbs() error {
// 计算过期时间阈值
expireDays := time.Duration(c.Cfg.VqdConfig.SaveDay)
if expireDays < 1 {
expireDays = 1
}
expireTime := time.Now().Add(-expireDays * 24 * time.Hour)
slog.Info(fmt.Sprintf("开始清理中超过 %d 天的数据,过期时间阈值:%s", expireDays, expireTime.Format(time.RFC3339)))
totalDeleted := 0
for {
deletedCount, err := c.VqdTaskCore.DelVqdTaskAlarmAll(expireTime, batchSize)
if err != nil {
slog.Error("数据清理失败", "err", err)
return err
}
// 获取本次删除的行数
totalDeleted += deletedCount
// 无更多数据则退出循环
if deletedCount < batchSize {
break
}
// 批量删除间隔,降低数据库压力
time.Sleep(100 * time.Millisecond)
}
slog.Info("本次数据清理任务执行完成")
return nil
}
// deleteDirContents 删除目录下的所有文件(保留目录结构,仅删文件)
func deleteTaskDirContents(dir string, expireTime time.Time) error {
// 遍历目录
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
// 处理遍历过程中的错误(如权限问题)
if err != nil {
slog.Error("访问路径失败", "path", path, "err", err)
return nil
}
// 只处理目录(跳过文件)
if !d.IsDir() {
return nil
}
// 获取当前目录的名称(如 20260117
dirName := filepath.Base(path)
dirDate, err := time.Parse(dateDirLayout, dirName)
if err != nil {
slog.Error("解析目录日期失败", "path", path, "err", err)
return nil
}
// 判断日期目录是否早于阈值(即过期)
isExpired := dirDate.Before(expireTime)
// 非日期目录,继续遍历子目录
if dirDate.IsZero() {
return nil
}
// 日期目录未过期,跳过
if !isExpired {
slog.Error("目录日期未过期跳过", "path", path, "dirDate", dirDate.Format(dateDirLayout))
return nil
}
// 过期日期目录:先删除目录内所有文件
slog.Error("目录已过期开始清理其中文件", "path", path, "dirDate", dirDate.Format(dateDirLayout))
if err := deleteDirContents(path, expireTime); err != nil {
slog.Error("清理目录内容失败", "path", path, "err", err)
return nil
}
// 删除空的日期目录
if err := os.Remove(path); err != nil {
slog.Error("删除空目录失败(可能非空)", "path", path, "err", err)
} else {
slog.Info("成功删除过期目录", "path", path)
}
// 跳过已删除目录的子目录遍历(避免无效操作)
return fs.SkipDir
})
if err != nil {
slog.Error("遍历目录失败", "dir", dir, "err", err)
return fmt.Errorf("遍历目录 [%s] 失败:%w", dir, err)
}
return nil
}
func deleteDirContents(dir string, expireTime time.Time) error {
err := filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
if err != nil {
slog.Error("访问路径失败", "path", path, "err", err)
return nil // 跳过错误路径,继续处理
}
// 只删除文件,跳过目录
if !d.IsDir() {
// 获取文件信息(包含修改时间)
fileInfo, err := d.Info()
if err != nil {
slog.Error("获取文件失败", "path", path, "err", err)
return nil
}
// 判断文件是否过期
if fileInfo.ModTime().Before(expireTime) {
// 删除过期文件
if errs := os.Remove(path); errs != nil {
slog.Error("删除文件失败", "path", path, "err", err)
} else {
slog.Info("成功删除文件", "path", path)
}
}
}
return nil
})
if err != nil {
return fmt.Errorf("遍历目录 [%s] 失败:%w", dir, err)
}
return nil
}
// cleanExpiredFiles 清理指定目录下超过expireDays天未修改的文件
func (c Core) cleanExpiredFiles() error {
// 计算过期时间阈值
expireDays := time.Duration(c.Cfg.VqdConfig.SaveDay)
if expireDays < 1 {
expireDays = 1
}
expireTime := time.Now().Add(-expireDays * 24 * time.Hour)
slog.Info(fmt.Sprintf("开始清理目录 [%s] 中超过 %d 天的文件,过期时间阈值:%s", cleanDir, expireDays, expireTime.Format(time.RFC3339)))
dir, _ := os.Getwd()
rootDir := filepath.Join(dir, cleanDir)
dateDirs, err := os.ReadDir(rootDir)
if err != nil {
slog.Error("访问根目录路径失败", "path", rootDir, "err", err)
return nil
}
for _, d := range dateDirs {
// 只处理目录(跳过文件)
if !d.IsDir() {
return nil
}
path := filepath.Join(rootDir, d.Name())
if err := deleteTaskDirContents(path, expireTime); err != nil {
slog.Error("清理目录内容失败", "path", path, "err", err)
return nil
}
// 删除空的日期目录
if err := os.Remove(path); err != nil {
slog.Error("删除空目录失败(可能非空)", "path", path, "err", err)
} else {
slog.Info("成功删除过期目录", "path", path)
}
}
slog.Info("本次文件清理任务执行完成")
return nil
}

View File

@ -2,6 +2,7 @@ package vqdsdk
import ( import (
"context" "context"
"easyvqd/internal/conf"
"easyvqd/internal/core/host" "easyvqd/internal/core/host"
"easyvqd/internal/core/vqd" "easyvqd/internal/core/vqd"
"time" "time"
@ -10,14 +11,14 @@ import (
type Core struct { type Core struct {
HostCore *host.Core HostCore *host.Core
VqdTaskCore *vqd.Core VqdTaskCore *vqd.Core
//WorkflowCore *Workflow Cfg *conf.Bootstrap
} }
func NewCore(HostCore *host.Core, VqdTaskCore *vqd.Core) *Core { func NewCore(HostCore *host.Core, VqdTaskCore *vqd.Core, Cfg *conf.Bootstrap) *Core {
core := &Core{ core := &Core{
HostCore: HostCore, HostCore: HostCore,
VqdTaskCore: VqdTaskCore, VqdTaskCore: VqdTaskCore,
//WorkflowCore: OpenVqdTask(VqdTaskCore), Cfg: Cfg,
} }
time.AfterFunc(time.Duration(5)*time.Second, func() { time.AfterFunc(time.Duration(5)*time.Second, func() {
in := &vqd.AddVqdAlarmInput{ in := &vqd.AddVqdAlarmInput{
@ -31,10 +32,13 @@ func NewCore(HostCore *host.Core, VqdTaskCore *vqd.Core) *Core {
TaskName: "", TaskName: "",
FilePath: "", FilePath: "",
} }
core.VqdTaskCore.AddVqdAlarm(context.TODO(), in) for i := 0; i < 40; i++ {
core.VqdTaskCore.AddVqdAlarm(context.TODO(), in) core.VqdTaskCore.AddVqdAlarm(context.TODO(), in)
}
}) })
// 启用定时清理任务
core.scheduleCleanTask()
// 启用任务管理器 // 启用任务管理器
return core return core
} }

View File

@ -1,8 +1,10 @@
package api package api
import ( import (
"easyvqd/internal/core/vqd"
"easyvqd/internal/web/api/static" "easyvqd/internal/web/api/static"
"expvar" "expvar"
"git.lnton.com/lnton/pkg/orm"
statics "github.com/gin-contrib/static" statics "github.com/gin-contrib/static"
"log/slog" "log/slog"
"net/http" "net/http"
@ -24,6 +26,12 @@ import (
var startRuntime = time.Now() var startRuntime = time.Now()
// recordErr 记录错误
func recordErr(err error) {
if err != nil {
panic(err)
}
}
func setupRouter(r *gin.Engine, uc *Usecase) { func setupRouter(r *gin.Engine, uc *Usecase) {
r.Use( r.Use(
// 格式化输出到控制台,然后记录到日志 // 格式化输出到控制台,然后记录到日志
@ -55,7 +63,9 @@ func setupRouter(r *gin.Engine, uc *Usecase) {
registerConfig(r, ConfigAPI{uc: uc, cfg: uc.Conf}) registerConfig(r, ConfigAPI{uc: uc, cfg: uc.Conf})
RegisterHostAPI(r, uc) RegisterHostAPI(r, uc)
RegisterVqdTask(r, uc.VqdTaskAPI) RegisterVqdTask(r, uc.VqdTaskAPI)
if !orm.GetEnabledAutoMigrate() {
recordErr(InitTemplate(uc))
}
r.NoRoute(func(ctx *gin.Context) { r.NoRoute(func(ctx *gin.Context) {
p := ctx.Request.URL.Path p := ctx.Request.URL.Path
if strings.HasPrefix(p, "/web/") { if strings.HasPrefix(p, "/web/") {
@ -151,6 +161,105 @@ type KV struct {
Value int64 Value int64
} }
func InitTemplate(uc *Usecase) error {
cfg := uc.Conf
in := vqd.VqdTaskTemplate{
Enable: true,
IsDefault: true,
VqdConfig: vqd.VqdConfig{
Enable: true,
FrmNum: cfg.VqdConfig.FrmNum,
IsDeepLearn: cfg.VqdConfig.IsDeepLearn,
},
VqdLgtDark: vqd.VqdLgtDark{
Enable: true,
DarkThr: cfg.VqdLgtDark.DarkThr,
LgtThr: cfg.VqdLgtDark.LgtThr,
LgtDarkAbnNumRatio: cfg.VqdLgtDark.LgtDarkAbnNumRatio,
},
VqdBlue: vqd.VqdBlue{
Enable: true,
BlueThr: cfg.VqdBlue.BlueThr,
BlueAbnNumRatio: cfg.VqdBlue.BlueAbnNumRatio,
},
VqdClarity: vqd.VqdClarity{
Enable: true,
ClarityThr: cfg.VqdClarity.ClarityThr,
ClarityAbnNumRatio: cfg.VqdClarity.ClarityAbnNumRatio,
},
VqdShark: vqd.VqdShark{
Enable: true,
SharkThr: cfg.VqdShark.SharkThr,
SharkAbnNumRatio: cfg.VqdShark.SharkAbnNumRatio,
},
VqdFreeze: vqd.VqdFreeze{
Enable: true,
FreezeThr: cfg.VqdFreeze.FreezeThr,
FreezeAbnNumRatio: cfg.VqdFreeze.FreezeAbnNumRatio,
},
VqdColor: vqd.VqdColor{
Enable: true,
ColorThr: cfg.VqdColor.ColorThr,
ColorAbnNumRatio: cfg.VqdColor.ColorAbnNumRatio,
},
VqdOcclusion: vqd.VqdOcclusion{
Enable: true,
OcclusionThr: cfg.VqdOcclusion.OcclusionThr,
OcclusionAbnNumRatio: cfg.VqdOcclusion.OcclusionAbnNumRatio,
},
VqdNoise: vqd.VqdNoise{
Enable: true,
NoiseThr: cfg.VqdNoise.NoiseThr,
NoiseAbnNumRatio: cfg.VqdNoise.NoiseAbnNumRatio,
},
VqdContrast: vqd.VqdContrast{
Enable: true,
CtraLowThr: cfg.VqdContrast.CtraLowThr,
CtraHighThr: cfg.VqdContrast.CtraHighThr,
CtraAbnNumRatio: cfg.VqdContrast.CtraAbnNumRatio,
},
VqdMosaic: vqd.VqdMosaic{
Enable: true,
MosaicThr: cfg.VqdMosaic.MosaicThr,
MosaicAbnNumRatio: cfg.VqdMosaic.MosaicAbnNumRatio,
},
VqdFlower: vqd.VqdFlower{
Enable: true,
FlowerThr: cfg.VqdFlower.FlowerThr,
FlowerAbnNumRatio: cfg.VqdFlower.FlowerAbnNumRatio,
MosaicThr: cfg.VqdFlower.MosaicThr,
},
}
in.Name = "每天"
in.Model.ID = 1
in.Model.CreatedAt = orm.Time{Time: time.Now()}
in.Plans = "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111"
in.Des = "每天分析,启用全部分析模块。"
if err := uc.VqdTaskCore.FirstOrCreateTemplate(&in); err != nil {
slog.Error("FirstOrCreateTemplate", "err", err)
return err
}
in.Name = "工作日"
in.Model.ID = 2
in.Model.CreatedAt = orm.Time{Time: time.Now()}
in.Plans = "111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111000000000000000000000000000000000000000000000000"
in.Des = "工作日分析,启用全部分析模块。"
if err := uc.VqdTaskCore.FirstOrCreateTemplate(&in); err != nil {
slog.Error("FirstOrCreateTemplate", "err", err)
return err
}
in.Name = "双休日"
in.Model.ID = 3
in.Model.CreatedAt = orm.Time{Time: time.Now()}
in.Plans = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000111111111111111111111111111111111111111111111111"
in.Des = "休息日分析,启用全部分析模块。"
if err := uc.VqdTaskCore.FirstOrCreateTemplate(&in); err != nil {
slog.Error("FirstOrCreateTemplate", "err", err)
return err
}
return nil
}
func sortExpvarMap(data *expvar.Map, top int) []KV { func sortExpvarMap(data *expvar.Map, top int) []KV {
kvs := make([]KV, 0, 8) kvs := make([]KV, 0, 8)
data.Do(func(kv expvar.KeyValue) { data.Do(func(kv expvar.KeyValue) {

View File

@ -27,27 +27,60 @@ func registerConfig(g gin.IRouter, api ConfigAPI, handler ...gin.HandlerFunc) {
group.GET("/base", web.WarpH(api.getBase)) group.GET("/base", web.WarpH(api.getBase))
group.PUT("/base", web.WarpH(api.editBase)) group.PUT("/base", web.WarpH(api.editBase))
group.GET("/default", web.WarpH(api.getDefaultConfig))
} }
type getBaseOutput conf.VqdConfig type getBaseOutput struct {
type editBaseInput conf.VqdConfig SaveDay int32 `json:"save_day"`
}
type editBaseInput struct {
SaveDay int32 `json:"save_day"`
}
type getBaseConfigOutput struct {
FrmNum int32 `json:"frm_num"`
IsDeepLearn bool `json:"is_deep_learn"`
VqdLgtDark conf.VqdLgtDark `json:"vqd_lgt_dark"` // 亮度检测
VqdBlue conf.VqdBlue `json:"vqd_blue"` // 蓝屏检查
VqdClarity conf.VqdClarity `json:"vqd_clarity"` // 清晰度检查
VqdShark conf.VqdShark `json:"vqd_shark"` // 抖动检查
VqdFreeze conf.VqdFreeze `json:"vqd_freeze"` // 冻结检测
VqdColor conf.VqdColor `json:"vqd_color"` // 偏色检测
VqdOcclusion conf.VqdOcclusion `json:"vqd_occlusion"` // 遮挡检测
VqdNoise conf.VqdNoise `json:"vqd_noise"` // 噪声检测
VqdContrast conf.VqdContrast `json:"vqd_contrast"` // 对比度检测
VqdMosaic conf.VqdMosaic `json:"vqd_mosaic"` // 马赛克检测
VqdFlower conf.VqdFlower `json:"vqd_flower"` // 花屏检测
}
func (uc *ConfigAPI) editBase(c *gin.Context, in *editBaseInput) (any, error) { func (uc *ConfigAPI) editBase(c *gin.Context, in *editBaseInput) (any, error) {
uc.cfg.VqdConfig.FrmNum = in.FrmNum
uc.cfg.VqdConfig.SaveDay = in.SaveDay uc.cfg.VqdConfig.SaveDay = in.SaveDay
uc.cfg.VqdConfig.IsDeepLearn = in.IsDeepLearn
conf.WriteConfig(uc.cfg, uc.cfg.ConfigDirPath()) conf.WriteConfig(uc.cfg, uc.cfg.ConfigDirPath())
return in, nil return in, nil
} }
func (uc *ConfigAPI) getDefaultConfig(_ *gin.Context, _ *struct{}) (getBaseConfigOutput, error) {
return getBaseConfigOutput{
FrmNum: uc.cfg.VqdConfig.FrmNum,
IsDeepLearn: uc.cfg.VqdConfig.IsDeepLearn,
VqdLgtDark: uc.cfg.VqdLgtDark,
VqdBlue: uc.cfg.VqdBlue,
VqdClarity: uc.cfg.VqdClarity,
VqdShark: uc.cfg.VqdShark,
VqdFreeze: uc.cfg.VqdFreeze,
VqdColor: uc.cfg.VqdColor,
VqdOcclusion: uc.cfg.VqdOcclusion,
VqdNoise: uc.cfg.VqdNoise,
VqdContrast: uc.cfg.VqdContrast,
VqdMosaic: uc.cfg.VqdMosaic,
VqdFlower: uc.cfg.VqdFlower,
}, nil
}
func (uc *ConfigAPI) getBase(_ *gin.Context, _ *struct{}) (getBaseOutput, error) { func (uc *ConfigAPI) getBase(_ *gin.Context, _ *struct{}) (getBaseOutput, error) {
confMutex.Lock() confMutex.Lock()
defer confMutex.Unlock() defer confMutex.Unlock()
return getBaseOutput{ return getBaseOutput{
FrmNum: uc.cfg.VqdConfig.FrmNum, SaveDay: uc.cfg.VqdConfig.SaveDay,
IsDeepLearn: uc.cfg.VqdConfig.IsDeepLearn,
SaveDay: uc.cfg.VqdConfig.SaveDay,
}, nil }, nil
} }
func (uc *ConfigAPI) getToml(c *gin.Context) { func (uc *ConfigAPI) getToml(c *gin.Context) {

View File

@ -64,6 +64,10 @@ func (a VqdTaskAPI) findVqdTask(c *gin.Context, in *vqd.FindVqdTaskInput) (any,
row["channel_name"] = item.ChannelName row["channel_name"] = item.ChannelName
row["task_template_id"] = item.TaskTemplateID row["task_template_id"] = item.TaskTemplateID
row["task_template_name"] = item.TaskTemplateName row["task_template_name"] = item.TaskTemplateName
template, errs := a.core.GetIDVqdTaskTemplate(c.Request.Context(), item.TaskTemplateID)
if errs == nil && template != nil {
row["task_template_name"] = template.Name
}
row["created_at"] = item.CreatedAt row["created_at"] = item.CreatedAt
row["updated_at"] = item.UpdatedAt row["updated_at"] = item.UpdatedAt

View File

@ -20,6 +20,19 @@ func (a VqdTaskAPI) findVqdTaskTemplate(c *gin.Context, in *vqd.FindVqdTaskTempl
row["des"] = item.Des row["des"] = item.Des
row["plans"] = item.Plans row["plans"] = item.Plans
row["enable"] = item.Enable row["enable"] = item.Enable
row["is_default"] = item.IsDefault
row["vqd_config"] = item.VqdConfig
row["vqd_lgt_dark"] = item.VqdLgtDark
row["vqd_blue"] = item.VqdBlue
row["vqd_clarity"] = item.VqdClarity
row["vqd_shark"] = item.VqdShark
row["vqd_freeze"] = item.VqdFreeze
row["vqd_color"] = item.VqdColor
row["vqd_occlusion"] = item.VqdOcclusion
row["vqd_noise"] = item.VqdNoise
row["vqd_contrast"] = item.VqdContrast
row["vqd_mosaic"] = item.VqdMosaic
row["vqd_flower"] = item.VqdFlower
row["created_at"] = item.CreatedAt row["created_at"] = item.CreatedAt
row["updated_at"] = item.UpdatedAt row["updated_at"] = item.UpdatedAt
@ -38,6 +51,19 @@ func (a VqdTaskAPI) getVqdTaskTemplate(c *gin.Context, _ *struct{}) (any, error)
row["id"] = item.ID row["id"] = item.ID
row["name"] = item.Name row["name"] = item.Name
row["is_default"] = item.IsDefault
row["vqd_config"] = item.VqdConfig
row["vqd_lgt_dark"] = item.VqdLgtDark
row["vqd_blue"] = item.VqdBlue
row["vqd_clarity"] = item.VqdClarity
row["vqd_shark"] = item.VqdShark
row["vqd_freeze"] = item.VqdFreeze
row["vqd_color"] = item.VqdColor
row["vqd_occlusion"] = item.VqdOcclusion
row["vqd_noise"] = item.VqdNoise
row["vqd_contrast"] = item.VqdContrast
row["vqd_mosaic"] = item.VqdMosaic
row["vqd_flower"] = item.VqdFlower
row["des"] = item.Des row["des"] = item.Des
row["plans"] = item.Plans row["plans"] = item.Plans
row["enable"] = item.Enable row["enable"] = item.Enable
@ -71,7 +97,20 @@ func (a VqdTaskAPI) editVqdTaskTemplate(c *gin.Context, in *vqd.EditVqdTaskTempl
func (a VqdTaskAPI) delVqdTaskTemplate(c *gin.Context, _ *struct{}) (any, error) { func (a VqdTaskAPI) delVqdTaskTemplate(c *gin.Context, _ *struct{}) (any, error) {
ID, _ := strconv.Atoi(c.Param("id")) ID, _ := strconv.Atoi(c.Param("id"))
_, err := a.core.DelVqdTaskTemplate(c.Request.Context(), ID) info, err := a.core.GetVqdTaskTemplate(c.Request.Context(), ID)
if err != nil {
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`find vqd [%d] err [%s]`, ID, err.Error()))
}
if info.IsDefault {
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`默认模板不支持删除 [%s] `, info.Name))
}
templateInfo, err := a.core.FindVqdTaskTemplateID(c.Request.Context(), ID)
if err == nil {
if templateInfo != nil {
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`模板关联【%s】任务,需先清理【%s】任务后才能删除模板`, templateInfo.Name, templateInfo.Name))
}
}
_, err = a.core.DelVqdTaskTemplate(c.Request.Context(), ID)
if err != nil { if err != nil {
return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`del vqd [%d] err [%s]`, ID, err.Error())) return nil, reason.ErrServer.SetMsg(fmt.Sprintf(`del vqd [%d] err [%s]`, ID, err.Error()))
} }

View File

@ -1,5 +1,5 @@
import { GET, PUT } from "./http"; import { GET, PUT } from "./http";
import type { UpdateConfigBaseReq, VqdConfigBaseDetailRes } from "../types/config"; import type { UpdateConfigBaseReq, VqdConfigBaseDetailRes, VqdConfigDefaultDetailRes } from "../types/config";
/** /**
* *
@ -7,6 +7,12 @@ import type { UpdateConfigBaseReq, VqdConfigBaseDetailRes } from "../types/confi
export async function GetVqdConfigBase() { export async function GetVqdConfigBase() {
return await GET<VqdConfigBaseDetailRes>(`/configs/base`); return await GET<VqdConfigBaseDetailRes>(`/configs/base`);
} }
/**
*
*/
export async function GetVqdConfigDefault() {
return await GET<VqdConfigDefaultDetailRes>(`/configs/default`);
}
/** /**
* *

View File

@ -31,6 +31,8 @@ export async function GetVqdTaskTemplateById(id: string) {
*/ */
export async function UpdateVqdTaskTemplate(data: UpdateVqdTaskTemplateReq) { export async function UpdateVqdTaskTemplate(data: UpdateVqdTaskTemplateReq) {
const { id, ...payload } = data; const { id, ...payload } = data;
console.log(data);
return await PUT<VqdTaskTemplateBaseRes>(`/template/${id}`, payload); return await PUT<VqdTaskTemplateBaseRes>(`/template/${id}`, payload);
} }

View File

@ -1,10 +1,11 @@
import { forwardRef, useImperativeHandle, useState, useRef } from "react"; import { forwardRef, useImperativeHandle, useState, useRef } from "react";
import { Modal, Form, Input, Radio, Button, message, Space } from "antd"; import { Modal, Form, Input, Select, Button, message, Space } from "antd";
import { useMutation } from "@tanstack/react-query"; import { useMutation, useQuery } from "@tanstack/react-query";
import { CreateVqdTask, UpdateVqdTask } from "../api/vqdtask"; import { CreateVqdTask, UpdateVqdTask } from "../api/vqdtask";
import { GetVqdTaskTemplate } from "../api/vqdtasktemplate";
import type { CreateVqdTaskReq, VqdTaskItem } from "../types/vqdtask"; import type { CreateVqdTaskReq, VqdTaskItem } from "../types/vqdtask";
import { useGlobal } from "../Context"; import { useGlobal } from "../Context";
import ChannelModel, { IChannelModelFunc } from "./channel/Channel";
interface AddVqdTaskProps { interface AddVqdTaskProps {
title: string; title: string;
@ -19,12 +20,15 @@ const AddVqdTask = forwardRef<AddVqdTaskRef, AddVqdTaskProps>(
({ title, onSuccess }, ref) => { ({ title, onSuccess }, ref) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [editing, setEditing] = useState<boolean>(false); const [editing, setEditing] = useState<boolean>(false);
const [channelId, setChannelId] = useState<string>("");
const channelRef = useRef<IChannelModelFunc>(null);
const [form] = Form.useForm(); const [form] = Form.useForm();
const { ErrorHandle } = useGlobal(); const { ErrorHandle } = useGlobal();
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
open: (task?: VqdTaskItem) => { open: (task?: VqdTaskItem) => {
if (task) { if (task) {
setEditing(true); setEditing(true);
setChannelId(task.channel_id)
const formValues = { const formValues = {
name: task.name, name: task.name,
id: task.id, id: task.id,
@ -45,7 +49,29 @@ const AddVqdTask = forwardRef<AddVqdTaskRef, AddVqdTaskProps>(
setOpen(true); setOpen(true);
}, },
})); }));
const [pagination, setPagination] = useState({
page: 1,
size: 999,
name: ""
});
// 获取任务列表
const {
data: storageResponse,
isLoading,
refetch,
} = useQuery({
queryKey: ["storage", pagination],
queryFn: () =>
GetVqdTaskTemplate({ ...pagination })
.then((res) => res.data)
.catch((err) => {
ErrorHandle(err);
throw err;
}),
// refetchInterval: 4000,
retry: 1,
});
const { mutate: createMutate, isPending: creating } = useMutation({ const { mutate: createMutate, isPending: creating } = useMutation({
mutationFn: CreateVqdTask, mutationFn: CreateVqdTask,
onSuccess: () => { onSuccess: () => {
@ -69,6 +95,7 @@ const AddVqdTask = forwardRef<AddVqdTaskRef, AddVqdTaskProps>(
const handleClose = () => { const handleClose = () => {
setOpen(false); setOpen(false);
setEditing(false); setEditing(false);
setChannelId("");
form.resetFields(); form.resetFields();
}; };
@ -76,7 +103,7 @@ const AddVqdTask = forwardRef<AddVqdTaskRef, AddVqdTaskProps>(
<Modal <Modal
style={{ top: '-180px' }} // 距离顶部 80px可改为 10% 等百分比) style={{ top: '-180px' }} // 距离顶部 80px可改为 10% 等百分比)
title={title} title={title}
destroyOnHidden={true}
open={open} open={open}
onCancel={handleClose} onCancel={handleClose}
centered centered
@ -134,7 +161,34 @@ const AddVqdTask = forwardRef<AddVqdTaskRef, AddVqdTaskProps>(
> >
<Input placeholder="请输入名称" /> <Input placeholder="请输入名称" />
</Form.Item> </Form.Item>
<Form.Item
name="channel_id"
label="关联通道"
rules={[{ required: true, message: "请选择通道" }]}
>
<Space.Compact style={{ width: '100%' }}>
<Input defaultValue="请输入通道" disabled value={channelId} />
<Button type="primary" onClick={() => {
channelRef.current?.openModal(channelId)
}}></Button>
</Space.Compact>
</Form.Item>
<Form.Item name="task_template_id" label="选择模板" rules={[{ required: true, message: "请选择模板" }]}>
<Select
placeholder="请选择模板"
onChange={(res, item: any) => {
form.setFieldsValue({ task_template_name: item?.label });
}}
options={storageResponse?.items
.map((item) => ({
label: item.name,
value: item.id,
}))
.filter((item) => item.value !== 0)}
></Select>
</Form.Item>
<Form.Item <Form.Item
name="des" name="des"
label="描述" label="描述"
@ -146,7 +200,17 @@ const AddVqdTask = forwardRef<AddVqdTaskRef, AddVqdTaskProps>(
<Input /> <Input />
</Form.Item> </Form.Item>
)} )}
<Form.Item name="channel_name" hidden>
<Input />
</Form.Item>
<Form.Item name="task_template_name" hidden>
<Input />
</Form.Item>
</Form> </Form>
<ChannelModel ref={channelRef} onCallback={(id: any, name: any) => {
form.setFieldsValue({ channel_id: id, channel_name: name });
setChannelId(id)
}} />
</Modal> </Modal>
); );
} }

View File

@ -1,16 +1,77 @@
import { forwardRef, useImperativeHandle, useState, useRef } from "react"; import { forwardRef, useImperativeHandle, useState, useRef, createContext, useContext, useEffect } from "react";
import { Modal, Form, Input, Radio, Button, message, Space } from "antd"; import { Modal, Form, Input, InputNumber, Button, message, Row, Col, Card, Flex, Switch, Tabs, FormInstance } from "antd";
import { useMutation } from "@tanstack/react-query"; import { useMutation } from "@tanstack/react-query";
import { CreateVqdTaskTemplate, UpdateVqdTaskTemplate } from "../api/vqdtasktemplate"; import { GetVqdConfigDefault } from "../api/config";
import { CreateVqdTaskTemplate, UpdateVqdTaskTemplate, } from "../api/vqdtasktemplate";
import type { CreateVqdTaskTemplateReq, VqdTaskTemplateItem } from "../types/vqdtasktemplate"; import type { CreateVqdTaskTemplateReq, VqdTaskTemplateItem } from "../types/vqdtasktemplate";
import { useGlobal } from "../Context"; import { useGlobal } from "../Context";
import type { TabsProps } from 'antd';
const week = [
'星期一',
'星期二',
'星期三',
'星期四',
'星期五',
'星期六',
'星期日',
];
const hour = [
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
22, 23,
];
const gridStyle: React.CSSProperties = {
border: '0.1px solid #ccc',
textAlign: 'center',
lineHeight: '40px',
userSelect: 'none',
};
const titleStyle: React.CSSProperties = {
border: '0.1px solid #ccc',
width: '90px',
textAlign: 'center',
lineHeight: '40px',
userSelect: 'none',
};
type PlansSpan = {
start: string;
end: string;
};
export const emptyList = [
Array(24).fill(0),
Array(24).fill(0),
Array(24).fill(0),
Array(24).fill(0),
Array(24).fill(0),
Array(24).fill(0),
Array(24).fill(0),
];
interface AddVqdTaskTemplateProps { interface AddVqdTaskTemplateProps {
title: string; title: string;
onSuccess: () => void; onSuccess: () => void;
} }
interface IAddTemplateContext {
editing: boolean;
checkList: number[][];
form: FormInstance<CreateVqdTaskTemplateReq>;
setCheckList: React.Dispatch<React.SetStateAction<number[][]>>;
onDelPullDeviceData: (index: number) => void;
}
const layout = {
labelCol: { span: 10 },
wrapperCol: { span: 14 },
};
const AddTemplateContext = createContext<IAddTemplateContext | null>(null);
const useAddTemplate = () => {
const context = useContext(AddTemplateContext);
if (!context) {
throw new Error('useAddTemplate must be used within a AddTemplateProvider');
}
return context;
};
export interface AddVqdTaskTemplateRef { export interface AddVqdTaskTemplateRef {
open: (task?: VqdTaskTemplateItem) => void; open: (task?: VqdTaskTemplateItem) => void;
} }
@ -19,8 +80,81 @@ const AddVqdTaskTemplate = forwardRef<AddVqdTaskTemplateRef, AddVqdTaskTemplateP
({ title, onSuccess }, ref) => { ({ title, onSuccess }, ref) => {
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [editing, setEditing] = useState<boolean>(false); const [editing, setEditing] = useState<boolean>(false);
const [checkList, setCheckList] = useState<number[][]>([...emptyList.map((list) => [...list])]);
const [form] = Form.useForm(); const [form] = Form.useForm();
const { ErrorHandle } = useGlobal(); const { ErrorHandle } = useGlobal();
const arrayToString = (arr: number[][]): string => {
return arr.map((subArr) => subArr.join('')).join('');
}
const parsePlans = (value: string | undefined): number[][] => {
const result: number[][] = [];
if (!value) return result;
const binaryArray: number[] = value.split('').map(Number);
while (binaryArray.length) {
result.push(binaryArray.splice(0, 24));
}
return result;
};
const onChange = (key: string) => {
console.log(key);
};
const itemsTabs: TabsProps['items'] = [
{
key: '1',
forceRender: true,
label: '诊断参数',
children: <TemplateConfig />
},
{
key: '2',
forceRender: true,
label: '诊断时间',
children: <TemplatePlans />
},
];
const { mutate: getVqdConfigDefault } = useMutation({
mutationFn: GetVqdConfigDefault,
onSuccess: (res) => {
const formValues = {
vqd_config: {
enable: false,
frm_num: res.data.frm_num,
is_deep_learn: res.data.is_deep_learn,
},
enable: true,
plans: '',
des: '',
name: '',
vqd_lgt_dark: res.data.vqd_lgt_dark,
vqd_blue: res.data.vqd_blue,
vqd_clarity: res.data.vqd_clarity,
vqd_shark: res.data.vqd_shark,
vqd_freeze: res.data.vqd_freeze,
vqd_color: res.data.vqd_color,
vqd_occlusion: res.data.vqd_occlusion,
vqd_noise: res.data.vqd_noise,
vqd_contrast: res.data.vqd_contrast,
vqd_mosaic: res.data.vqd_mosaic,
vqd_flower: res.data.vqd_flower,
};
formValues.vqd_lgt_dark.enable = false
formValues.vqd_blue.enable = false
formValues.vqd_clarity.enable = false
formValues.vqd_shark.enable = false
formValues.vqd_freeze.enable = false
formValues.vqd_color.enable = false
formValues.vqd_occlusion.enable = false
formValues.vqd_noise.enable = false
formValues.vqd_contrast.enable = false
formValues.vqd_mosaic.enable = false
formValues.vqd_flower.enable = false
form.setFieldsValue(formValues);
},
onError: ErrorHandle,
});
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
open: (task?: VqdTaskTemplateItem) => { open: (task?: VqdTaskTemplateItem) => {
if (task) { if (task) {
@ -30,14 +164,29 @@ const AddVqdTaskTemplate = forwardRef<AddVqdTaskTemplateRef, AddVqdTaskTemplateP
id: task.id, id: task.id,
plans: task.plans, plans: task.plans,
enable: task.enable, enable: task.enable,
des: task.des,
vqd_config: task.vqd_config,
vqd_lgt_dark: task.vqd_lgt_dark,
vqd_blue: task.vqd_blue,
vqd_clarity: task.vqd_clarity,
vqd_shark: task.vqd_shark,
vqd_freeze: task.vqd_freeze,
vqd_color: task.vqd_color,
vqd_occlusion: task.vqd_occlusion,
vqd_noise: task.vqd_noise,
vqd_contrast: task.vqd_contrast,
vqd_mosaic: task.vqd_mosaic,
vqd_flower: task.vqd_flower,
}; };
setCheckList(parsePlans(task.plans))
form.setFieldsValue(formValues); form.setFieldsValue(formValues);
} else { } else {
getVqdConfigDefault()
setEditing(false); setEditing(false);
form.resetFields(); form.resetFields();
// form.setFieldsValue({ form.setFieldsValue({
// bid: "2",
// }); });
} }
setOpen(true); setOpen(true);
}, },
@ -68,77 +217,471 @@ const AddVqdTaskTemplate = forwardRef<AddVqdTaskTemplateRef, AddVqdTaskTemplateP
setEditing(false); setEditing(false);
form.resetFields(); form.resetFields();
}; };
const onDelPullDeviceData = (index: number) => {
}
return ( return (
<Modal <AddTemplateContext.Provider
style={{ top: '-180px' }} // 距离顶部 80px可改为 10% 等百分比) value={{
title={title} form,
checkList,
open={open} editing,
onCancel={handleClose} setCheckList,
centered onDelPullDeviceData
onOk={() => form.submit()} }}
confirmLoading={creating || updating}
> >
<Form <Modal
form={form} // style={{ top: '-180px' }} // 距离顶部 80px可改为 10% 等百分比)
layout="vertical" title={title}
onFinish={(values) => { width={"64%"}
if (creating || updating) return open={open}
console.log(values); onCancel={handleClose}
destroyOnHidden={true}
const { centered
name, onOk={() => form.submit()}
des, confirmLoading={creating || updating}
plans,
enable } = values as {
name: string;
des: string;
id?: number;
plans: string;
enable: boolean;
};
const payload: CreateVqdTaskTemplateReq = {
name,
des,
plans,
enable,
};
if (editing) {
const id = (values as any).id;
updateMutate({ id: String(id), ...payload });
} else {
createMutate(payload);
}
}}
> >
<Form
form={form}
<Form.Item {...layout}
name="name" onFinish={(values: CreateVqdTaskTemplateReq) => {
label="名称" if (creating || updating) return
rules={[{ required: true, message: "请输入名称" }]} const payload = values as CreateVqdTaskTemplateReq;
payload.plans = arrayToString(checkList)
console.log(payload);
if (editing) {
const id = (values as any).id;
updateMutate({ id: String(id), ...payload });
} else {
createMutate(payload);
}
}}
> >
<Input placeholder="请输入名称" /> <br />
</Form.Item> <Flex gap="large" >
<Form.Item <Form.Item
name="des" style={{ width: '30%' }}
label="描述" name="name"
> label="模板名称"
<Input placeholder="请输入描述" /> rules={[{ required: true, message: "请输入模板名称" }]}
</Form.Item> >
{editing && ( <Input placeholder="请输入名称" />
<Form.Item name="id" hidden> </Form.Item>
<Input />
</Form.Item> <Form.Item
)} style={{ width: '30%' }}
</Form> name="des"
</Modal> label="描述"
>
<Input placeholder="请输入描述" />
</Form.Item>
<Form.Item
style={{ width: '20%' }}
name="enable"
label="启用"
>
<Switch />
</Form.Item>
</Flex>
<Tabs defaultActiveKey="1" items={itemsTabs} onChange={onChange} />
{editing && (
<Form.Item name="id" hidden>
<Input />
</Form.Item>
)}
</Form>
</Modal>
</AddTemplateContext.Provider>
); );
} }
); );
export default AddVqdTaskTemplate; export default AddVqdTaskTemplate;
const TemplatePlans: React.FC = () => {
const {
checkList,
editing,
setCheckList,
form,
} = useAddTemplate();
// 开始滑动选择
const [config, setConfig] = useState<{
start: boolean;
}>({ start: false });
const selector = useRef<boolean>(true);
const [coping, setCoping] = useState<
{ index: number; value: number[] } | undefined
>();
const handler = (list: number[]) => {
let out: PlansSpan[] = [];
let start = false;
let timeParam: PlansSpan = { start: '', end: '' };
for (let i = 0; i < list.length; i++) {
const v = list[i];
let s = i.toString().padStart(2, '0');
if (i == 23 && v == 1) {
s = '24';
}
if (!start && v == 1) {
start = true;
timeParam = { start: `${i}:00`, end: '' };
}
if (start && (v == 0 || i == list.length - 1)) {
start = false;
timeParam.end = `${s}:00`;
out.push(timeParam);
}
}
return out;
};
return <>
<div style={{ border: '1px solid #999' }}>
<Row wrap={false}>
<div
style={{
...titleStyle,
}}
>
Week/Time
</div>
<Row wrap={false} style={{ width: '86.5%' }}>
{[...hour].map((v, idx) => {
return (
<Col key={v} span={1} style={gridStyle}>
{v}
</Col>
);
})}
</Row>
</Row>
{week.map((v, weekIdx) => {
return (
<Row
key={v}
onMouseDown={() => setConfig({ ...config, start: true })}
onMouseUp={() => setConfig({ ...config, start: false })}
wrap={false}
>
<div style={titleStyle}>{v}</div>
<Row key={v + '1'} wrap={false} style={{ width: '86.5%' }}>
{[...hour].map((v, hourIdx) => {
// 时间选择
return (
<Col
onMouseOver={() => {
if (!config.start) return;
setCheckList((v) => {
let list = [...v];
list[weekIdx][hourIdx] = selector.current ? 1 : 0;
return list;
});
}}
onMouseDown={() => {
selector.current = checkList[weekIdx][hourIdx] == 0;
setCheckList((v) => {
let list = [...v];
list[weekIdx][hourIdx] = selector.current ? 1 : 0;
return list;
});
}}
key={v}
span={1}
style={{
...gridStyle,
backgroundColor:
checkList[weekIdx][hourIdx] == 1
? '#658EE0'
: 'white',
}}
></Col>
);
})}
<div
style={{
margin: 'auto',
marginLeft: '2px',
}}
>
<Button
type={coping?.index == weekIdx ? 'primary' : 'default'}
size="small"
style={{ padding: '1px 5px', fontSize: '12px' }}
onClick={() => {
if (!coping) {
setCoping({
index: weekIdx,
value: checkList[weekIdx],
});
return;
}
setCheckList((v) => {
let list = [...v];
list[weekIdx] = [...coping.value];
return list;
});
setCoping(undefined);
}}
>
{!coping || coping?.index == weekIdx ? "复制" : "粘贴"}
</Button>
</div>
</Row>
</Row>
);
})}
</div>
<div style={{ height: '20px' }}></div>
<Card>
<div>
<span></span>
</div>
<div>
{week.map((v, weekIdx) => {
return (
// 周
<Row wrap={false} key={v}>
<div style={{ color: '#9A9A9A', paddingRight: '5px' }}>
<span>{v}</span> :
</div>
<Row wrap={false}>
{handler(checkList[weekIdx]).map((v, idx, arr) => {
// 已选时间段
return (
<Col key={`${v.start}~${v.end}_${idx}_${weekIdx}`}>
{`${v.start}~${v.end}` +
(idx < arr.length - 1 ? ',' : '')}
</Col>
);
})}
</Row>
</Row>
);
})}
</div>
</Card>
</>
}
const BoxInputNumber: React.FC<{
parent: string;
children: string;
defaultValue: number
labelName: string;
}> = ({ parent, children, defaultValue, labelName }) => {
return (
<Form.Item
className="mb-1"
name={[parent, children]}
label={labelName}
normalize={(value) => {
return value ? parseFloat(value) : defaultValue;
}}
>
<InputNumber
size="small"
defaultValue={defaultValue}
min={0}
max={1}
step={0.1}
stringMode
/>
</Form.Item>
);
};
const TemplateConfig: React.FC = () => {
const {
editing,
form,
} = useAddTemplate();
const handleValuesChange = (value: string) => {
if (value) {
// form.setFieldsValue({ });
}
};
return <>
<Flex gap="large" wrap justify="space-between">
<Flex vertical className="config-box">
<Flex justify="space-between" align="center" className="config-box-hade" >
<h4></h4>
<Form.Item
className="mb-0"
name={['vqd_config', 'enable']}
>
<Switch className="ml-1" size="small" />
</Form.Item>
</Flex>
<div className="config-box-item">
<Form.Item
className="mb-1"
name={['vqd_config', 'is_deep_learn']}
label="深度学习"
>
<Switch size="small" />
</Form.Item>
<Form.Item
className="mb-1"
name={['vqd_config', 'frm_num']}
label="连续分析帧数"
>
<InputNumber min={2} max={64} defaultValue={10} size="small" />
</Form.Item>
</div>
</Flex>
<Flex vertical className="config-box">
<Flex justify="space-between" align="center" className="config-box-hade">
<h4></h4>
<Form.Item className="mb-0" name={['vqd_blue', 'enable']} >
<Switch className="ml-1" size="small" />
</Form.Item>
</Flex>
<div className="config-box-item">
<BoxInputNumber parent="vqd_blue" children="blue_thr" defaultValue={0.6} labelName="判断阈值" />
<BoxInputNumber parent="vqd_blue" children="blue_abn_num_ratio" defaultValue={0.5} labelName="次数比例" />
</div>
</Flex>
<Flex vertical className="config-box">
<Flex justify="space-between" align="center" className="config-box-hade">
<h4></h4>
<Form.Item className="mb-0" name={['vqd_clarity', 'enable']} >
<Switch className="ml-1" size="small" />
</Form.Item>
</Flex>
<div className="config-box-item">
<BoxInputNumber parent="vqd_clarity" children="clarity_thr" defaultValue={0.4} labelName="判断阈值" />
<BoxInputNumber parent="vqd_clarity" children="clarity_abn_num_ratio" defaultValue={0.5} labelName="次数比例" />
</div>
</Flex>
<Flex vertical className="config-box">
<Flex justify="space-between" align="center" className="config-box-hade">
<h4></h4>
<Form.Item className="mb-0" name={['vqd_shark', 'enable']} >
<Switch className="ml-1" size="small" />
</Form.Item>
</Flex>
<div className="config-box-item">
<BoxInputNumber parent="vqd_shark" children="shark_thr" defaultValue={0.2} labelName="阈值参数" />
<BoxInputNumber parent="vqd_shark" children="shark_abn_num_ratio" defaultValue={0.2} labelName="次数比例" />
</div>
</Flex>
<Flex vertical className="config-box">
<Flex justify="space-between" align="center" className="config-box-hade">
<h4></h4>
<Form.Item className="mb-0" name={['vqd_freeze', 'enable']} >
<Switch className="ml-1" size="small" />
</Form.Item>
</Flex>
<div className="config-box-item">
<BoxInputNumber parent="vqd_freeze" children="freeze_thr" defaultValue={0.4} labelName="阈值参数" />
<BoxInputNumber parent="vqd_freeze" children="freeze_abn_num_ratio" defaultValue={0.9} labelName="次数比例" />
</div>
</Flex>
<Flex vertical className="config-box">
<Flex justify="space-between" align="center" className="config-box-hade">
<h4></h4>
<Form.Item className="mb-0" name={['vqd_color', 'enable']} >
<Switch className="ml-1" size="small" />
</Form.Item>
</Flex>
<div className="config-box-item">
<BoxInputNumber parent="vqd_color" children="color_thr" defaultValue={0.2} labelName="偏色判断值" />
<BoxInputNumber parent="vqd_color" children="color_abn_num_ratio" defaultValue={0.5} labelName="次数比例" />
</div>
</Flex>
<Flex vertical className="config-box">
<Flex justify="space-between" align="center" className="config-box-hade">
<h4></h4>
<Form.Item className="mb-0" name={['vqd_occlusion', 'enable']} >
<Switch className="ml-1" size="small" />
</Form.Item>
</Flex>
<div className="config-box-item">
<BoxInputNumber parent="vqd_occlusion" children="occlusion_thr" defaultValue={0.1} labelName="判断阈值" />
<BoxInputNumber parent="vqd_occlusion" children="occlusion_abn_num_ratio" defaultValue={0.5} labelName="次数比例" />
</div>
</Flex>
<Flex vertical className="config-box">
<Flex justify="space-between" align="center" className="config-box-hade">
<h4></h4>
<Form.Item className="mb-0" name={['vqd_mosaic', 'enable']} >
<Switch className="ml-1" size="small" />
</Form.Item>
</Flex>
<div className="config-box-item">
<BoxInputNumber parent="vqd_mosaic" children="mosaic_thr" defaultValue={0.1} labelName="阈值参数" />
<BoxInputNumber parent="vqd_mosaic" children="mosaic_abn_num_ratio" defaultValue={0.5} labelName="次数比例" />
</div>
</Flex>
<Flex vertical className="config-box">
<Flex justify="space-between" align="center" className="config-box-hade">
<h4></h4>
<Form.Item className="mb-0" name={['vqd_noise', 'enable']} >
<Switch className="ml-1" size="small" />
</Form.Item>
</Flex>
<div className="config-box-item">
<BoxInputNumber parent="vqd_noise" children="noise_thr" defaultValue={0.3} labelName="过暗阈值" />
<BoxInputNumber parent="vqd_noise" children="noise_abn_num_ratio" defaultValue={0.6} labelName="次数比例" />
</div>
</Flex>
<Flex vertical className="config-box">
<Flex justify="space-between" align="center" className="config-box-hade">
<h4></h4>
<Form.Item className="mb-0" name={['vqd_contrast', 'enable']} >
<Switch className="ml-1" size="small" />
</Form.Item>
</Flex>
<div className="config-box-item">
<BoxInputNumber parent="vqd_contrast" children="ctra_low_thr" defaultValue={0.2} labelName="低判断阈值" />
<BoxInputNumber parent="vqd_contrast" children="ctra_high_thr" defaultValue={0.8} labelName="高判断阈值" />
<BoxInputNumber parent="vqd_contrast" children="ctra_abn_num_ratio" defaultValue={0.5} labelName="次数比例" />
</div>
</Flex>
<Flex vertical className="config-box">
<Flex justify="space-between" align="center" className="config-box-hade">
<h4></h4>
<Form.Item className="mb-0" name={['vqd_lgt_dark', 'enable']} >
<Switch className="ml-1" size="small" />
</Form.Item>
</Flex>
<div className="config-box-item">
<BoxInputNumber parent="vqd_lgt_dark" children="dark_thr" defaultValue={0.4} labelName="过暗阈值" />
<BoxInputNumber parent="vqd_lgt_dark" children="lgt_thr" defaultValue={0.1} labelName="过亮阈值" />
<BoxInputNumber parent="vqd_lgt_dark" children="lgt_dark_abn_num_ratio" defaultValue={0.5} labelName="次数比例" />
</div>
</Flex>
<Flex vertical className="config-box">
<Flex justify="space-between" align="center" className="config-box-hade">
<h4></h4>
<Form.Item className="mb-0" name={['vqd_flower', 'enable']} >
<Switch className="ml-1" size="small" />
</Form.Item>
</Flex>
<div className="config-box-item">
<BoxInputNumber parent="vqd_flower" children="flower_thr" defaultValue={0.3} labelName="阈值参数" />
<BoxInputNumber parent="vqd_flower" children="flower_abn_num_ratio" defaultValue={0.6} labelName="过亮阈值" />
<BoxInputNumber parent="vqd_flower" children="mosaic_thr" defaultValue={0.3} labelName="马赛克阈值参数" />
</div>
</Flex>
</Flex>
</>
}

View File

@ -0,0 +1,34 @@
// import {
// FindAlarmSnapshot,
// } from '@/service/http/aiserver';
import { Image } from 'antd';
import React, { useState, useEffect } from 'react';
interface ISnapshot {
filePath: string;
}
const Snapshot: React.FC<ISnapshot> = ({
filePath,
}) => {
// const [base64, setBase64] = useState("");
// useEffect(() => {
// if (filePath != "") {
// FindAlarmSnapshot(filePath).then(data => {
// setBase64(data.data.data)
// })
// }
// }, [filePath]);
return (
<>
<Image
width="100%"
height="130px"
fallback={'./assets/img/noImg.png'}
src={filePath || './assets/img/noImg.png'}
/>
</>
);
};
export default Snapshot;

View File

@ -1,15 +1,16 @@
import { useRef, useState, useMemo } from "react"; import { useRef, useState, useMemo } from "react";
import { Table, Button, Space, Popconfirm, Flex, message, Tooltip } from "antd"; import { Table, Button, Space, Popconfirm, Flex, message, Tooltip, Select, Row, Col, Empty, Pagination, Tag } from "antd";
import { EditOutlined, DeleteOutlined, PlusOutlined } from "@ant-design/icons"; import { EditOutlined, DeleteOutlined, PlusOutlined } from "@ant-design/icons";
import { useQuery, useMutation } from "@tanstack/react-query"; import { useQuery, useMutation } from "@tanstack/react-query";
import { GetVqdAlarm, DeleteVqdAlarm, DeleteVqdAlarmAll } from "../api/vqdalarm"; import { GetVqdAlarm, DeleteVqdAlarm, DeleteVqdAlarmAll } from "../api/vqdalarm";
import type { VqdAlarmItem } from "../types/vqdalarm"; import type { VqdAlarmItem } from "../types/vqdalarm";
import type { ColumnsType } from "antd/es/table"; import type { ColumnsType } from "antd/es/table";
import ChannelModel, { IChannelModelFunc } from "./channel/Channel";
import { useGlobal } from "../Context"; import { useGlobal } from "../Context";
import { FormatFileSizeToString } from "../utils/rate"; import { FormatFileSizeToString } from "../utils/rate";
import { formatSecondsToHMS } from "../utils/time"; import { formatSecondsToHMS } from "../utils/time";
import Filter from "./Filter"; import Filter from "./Filter";
import AlarmSnap from './snap';
const variants = ['filled'] as const;
export default function VqdAlarmPage() { export default function VqdAlarmPage() {
const { ErrorHandle } = useGlobal(); const { ErrorHandle } = useGlobal();
const [pagination, setPagination] = useState({ const [pagination, setPagination] = useState({
@ -17,7 +18,8 @@ export default function VqdAlarmPage() {
size: 10, size: 10,
name: "" name: ""
}); });
const [arrList, setArrList] = useState<any>([{ name: "全部类型", id: 0 }]);
const [templateData, setTemplateData] = useState<VqdAlarmItem[]>([]);
// 获取任务列表 // 获取任务列表
const { const {
data: storageResponse, data: storageResponse,
@ -55,6 +57,13 @@ export default function VqdAlarmPage() {
}); });
// 处理分页变化 // 处理分页变化
const onAlarmPageChange = (page: number, pageSize?: number) => {
setPagination((prev) => ({
...prev,
page: page,
size: pageSize || prev.size,
}));
}
const handleTableChange = (page: number, pageSize?: number) => { const handleTableChange = (page: number, pageSize?: number) => {
setPagination((prev) => ({ setPagination((prev) => ({
...prev, ...prev,
@ -80,7 +89,7 @@ export default function VqdAlarmPage() {
setSelectedRowKeys([...newSelectedRowKeys]); setSelectedRowKeys([...newSelectedRowKeys]);
}, },
}; };
// 批量删除任务 // 批量删除任务
const { mutate: deleteMutationAll, isPending: delAllLoadings } = useMutation({ const { mutate: deleteMutationAll, isPending: delAllLoadings } = useMutation({
mutationFn: DeleteVqdAlarmAll, mutationFn: DeleteVqdAlarmAll,
onSuccess: () => { onSuccess: () => {
@ -129,7 +138,7 @@ export default function VqdAlarmPage() {
<Popconfirm <Popconfirm
title="确定要删除这个文件吗?" title="确定要删除这个告警吗?"
onConfirm={() => { onConfirm={() => {
if (record.id) { if (record.id) {
deleteMutation(record.id); deleteMutation(record.id);
@ -151,7 +160,7 @@ export default function VqdAlarmPage() {
return ( return (
<div> <div>
<Flex justify="space-between" align="center" className="mb-4"> {/* <Flex justify="space-between" align="center" className="mb-4">
<Space> <Space>
<Popconfirm <Popconfirm
@ -176,9 +185,9 @@ export default function VqdAlarmPage() {
setPagination({ ...pagination, name: value }); setPagination({ ...pagination, name: value });
}} }}
/> />
</Flex> </Flex> */}
{/* 表格 */} {/* 表格 */}
<Table {/* <Table
columns={columns} columns={columns}
rowSelection={rowSelection} rowSelection={rowSelection}
dataSource={storageResponse?.items} dataSource={storageResponse?.items}
@ -195,7 +204,109 @@ export default function VqdAlarmPage() {
onChange: handleTableChange, onChange: handleTableChange,
onShowSizeChange: handleTableChange, onShowSizeChange: handleTableChange,
}} }}
/> /> */}
<Flex justify="flex-end" className="mr-2" align="center">
{/* <Space className="pl-2">
<Popconfirm
title="确定要批量删除文件吗?"
onConfirm={() => {
deleteMutationAll({ ids: selectedRowKeys as number[] })
}}
okText="确定"
cancelText="取消"
>
<Button color="danger" variant="solid" loading={delAllLoadings} disabled={selectedRowKeys.length == 0} >
</Button>
</Popconfirm>
</Space> */}
{/* <DatePicker
defaultDate={moment().format('YYYY-MM-DD')}
moonData={moonReq}
onChangePanel={handleSelectMoon}
onSelectDate={handleSelectDate}
loading={moonLoading}
/> */}
<div className="w-[150px] ml-[20px]">
<Select
defaultValue={0}
className="w-[100%] mr-2"
placeholder="选择类型"
onChange={(v) => {
console.log("类型", v);
}
}
options={arrList.map((item: any) => {
return {
label: item.name,
value: item.id,
};
})}
optionRender={(option) => (
<Space>
<span>
{option.data.label}
</span>
</Space>
)}
/>
<Filter
searchLoading={isLoading}
onSearchChange={(value: string) => {
setPagination({ ...pagination, name: value });
}}
/>
</div>
</Flex>
<br />
<Row gutter={[16, 16]} className="pl-2 pr-2">
{storageResponse?.items.map((item) => {
return (
<Col xxl={6} xl={8} lg={12} md={12} sm={12} xs={24} key={item.id} >
<div className="overflow-hidden relative rounded-lg h-full w-full cursor-pointer shadow">
<AlarmSnap filePath={item.file_path} />
<div className="pl-3 pr-2 pb-1">
<Flex justify="space-between" align="center">
<Tag bordered={false} color="#87d068" className="m-0 mt-2">{item.alarm_name}</Tag>
<Space className="pr-2"> :{item.channel_name||"2222"}</Space>
</Flex>
<Flex justify="space-between" align="center">
<p className="m-0"> {item.created_at}</p>
<Tooltip title="删除">
<Popconfirm
title="删除告警"
description="确定要删除此告警吗?"
onConfirm={() => {
// delAlarmSnapshot([item.id])
}}
>
{/* loading={isDelLoading} */}
<Button type="text" danger icon={<DeleteOutlined />}></Button>
</Popconfirm>
</Tooltip>
</Flex>
</div>
</div>
</Col>
);
})}
{storageResponse?.items.length === 0 && (
<Col span={24}>
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
</Col>
)}
</Row>
<Flex justify="flex-end" className="mr-[20px] mt-6 mb-3" align="center">
<Pagination onChange={onAlarmPageChange} defaultCurrent={pagination.page} defaultPageSize={pagination.size} total={storageResponse?.total} />
</Flex>
</div> </div>
); );
} }

View File

@ -25,10 +25,7 @@ export default function VqdTaskPage() {
queryFn: () => queryFn: () =>
GetVqdConfigBase() GetVqdConfigBase()
.then((res) => { .then((res) => {
console.log(res.data);
const formValues = { const formValues = {
frm_num: res.data.frm_num,
is_deep_learn: res.data.is_deep_learn,
save_day: res.data.save_day, save_day: res.data.save_day,
}; };
form.setFieldsValue(formValues); form.setFieldsValue(formValues);
@ -51,17 +48,11 @@ export default function VqdTaskPage() {
const { const {
save_day, save_day,
frm_num,
is_deep_learn
} = values as { } = values as {
save_day: number; save_day: number;
frm_num: number;
is_deep_learn: boolean;
}; };
const payload: UpdateConfigBaseReq = { const payload: UpdateConfigBaseReq = {
save_day, save_day,
frm_num,
is_deep_learn,
}; };
const id = (values as any).id; const id = (values as any).id;
@ -71,12 +62,12 @@ export default function VqdTaskPage() {
<Form.Item name="save_day" label="数据保存天数" rules={[{ required: true, message: "请输入数据保存天数" }]}> <Form.Item name="save_day" label="数据保存天数" rules={[{ required: true, message: "请输入数据保存天数" }]}>
<InputNumber min={1} defaultValue={3} /> <InputNumber min={1} defaultValue={3} />
</Form.Item> </Form.Item>
<Form.Item name="frm_num" label="连续分析帧数(2-64), 默认为10, 最大为 64" rules={[{ required: true, message: "请输入连续分析帧数" }]}> {/* <Form.Item name="frm_num" label="(2-64), 10, 64" rules={[{ required: true, message: "" }]}>
<InputNumber max={64} min={2} defaultValue={10} /> <InputNumber max={64} min={2} defaultValue={10} />
</Form.Item> </Form.Item>
<Form.Item label="是否使用深度学习版本" name="is_deep_learn"> <Form.Item label="是否使用深度学习版本" name="is_deep_learn">
<Switch /> <Switch />
</Form.Item> </Form.Item> */}
<Button type="primary" onClick={handleSave}> <Button type="primary" onClick={handleSave}>
</Button> </Button>

View File

@ -6,7 +6,6 @@ import { GetVqdTask, DeleteVqdTask } from "../api/vqdtask";
import type { VqdTaskItem } from "../types/vqdtask"; import type { VqdTaskItem } from "../types/vqdtask";
import type { ColumnsType } from "antd/es/table"; import type { ColumnsType } from "antd/es/table";
import AddVqdTask, { AddVqdTaskRef } from "./AddVqdTask"; import AddVqdTask, { AddVqdTaskRef } from "./AddVqdTask";
import ChannelModel, { IChannelModelFunc } from "./channel/Channel";
import { useGlobal } from "../Context"; import { useGlobal } from "../Context";
import { FormatFileSizeToString } from "../utils/rate"; import { FormatFileSizeToString } from "../utils/rate";
import { formatSecondsToHMS } from "../utils/time"; import { formatSecondsToHMS } from "../utils/time";
@ -100,8 +99,18 @@ export default function VqdTaskPage() {
align: "center", align: "center",
}, },
{ {
title: "文件名称", title: "关联通道",
dataIndex: "file_name", dataIndex: "channel_name",
align: "center",
render: (text, record) => (
<Space>
{text}
</Space>
),
},
{
title: "模板",
dataIndex: "task_template_name",
align: "center", align: "center",
render: (text, record) => ( render: (text, record) => (
<Space> <Space>
@ -132,7 +141,7 @@ export default function VqdTaskPage() {
<Button icon={<EditOutlined />} onClick={() => handleEdit(record)} /> <Button icon={<EditOutlined />} onClick={() => handleEdit(record)} />
</Tooltip> </Tooltip>
<Popconfirm <Popconfirm
title="确定要删除这个文件吗?" title="确定要删除这个任务吗?"
onConfirm={() => { onConfirm={() => {
if (record.id) { if (record.id) {
deleteMutation(record.id); deleteMutation(record.id);

View File

@ -1,9 +1,9 @@
import { useRef, useState, useMemo } from "react"; import { useRef, useState, useMemo } from "react";
import { Table, Button, Space, Popconfirm, Flex, message, Tooltip } from "antd"; import { Table, Button, Space, Popconfirm, Flex, message, Tooltip, Switch, Tag } from "antd";
import { EditOutlined, DeleteOutlined, PlusOutlined } from "@ant-design/icons"; import { EditOutlined, DeleteOutlined, PlusOutlined } from "@ant-design/icons";
import { useQuery, useMutation } from "@tanstack/react-query"; import { useQuery, useMutation } from "@tanstack/react-query";
import { GetVqdTaskTemplate, DeleteVqdTaskTemplate } from "../api/vqdtasktemplate"; import { GetVqdTaskTemplate, DeleteVqdTaskTemplate, UpdateVqdTaskTemplate } from "../api/vqdtasktemplate";
import type { VqdTaskTemplateItem } from "../types/vqdtasktemplate"; import type { VqdTaskTemplateItem, CreateVqdTaskTemplateReq } from "../types/vqdtasktemplate";
import type { ColumnsType } from "antd/es/table"; import type { ColumnsType } from "antd/es/table";
import AddVqdTaskTemplate, { AddVqdTaskTemplateRef } from "./AddVqdTaskTemplate"; import AddVqdTaskTemplate, { AddVqdTaskTemplateRef } from "./AddVqdTaskTemplate";
import { useGlobal } from "../Context"; import { useGlobal } from "../Context";
@ -64,6 +64,11 @@ export default function VqdTaskTemplatePage() {
const handleEdit = (disk: VqdTaskTemplateItem) => { const handleEdit = (disk: VqdTaskTemplateItem) => {
dialogRef.current?.open(disk); dialogRef.current?.open(disk);
}; };
const saveTemplate = (disk: VqdTaskTemplateItem, t: boolean) => {
const payload = disk as CreateVqdTaskTemplateReq;
payload.enable = t
updateMutate({ id: String(disk.id), ...payload })
};
// 处理分页变化 // 处理分页变化
const handleTableChange = (page: number, pageSize?: number) => { const handleTableChange = (page: number, pageSize?: number) => {
@ -91,6 +96,14 @@ export default function VqdTaskTemplatePage() {
setSelectedRowKeys([...newSelectedRowKeys]); setSelectedRowKeys([...newSelectedRowKeys]);
}, },
}; };
const { mutate: updateMutate } = useMutation({
mutationFn: UpdateVqdTaskTemplate,
onSuccess: () => {
message.success("更新成功");
refetch()
},
onError: ErrorHandle,
});
// 表格列定义 // 表格列定义
const columns: ColumnsType<VqdTaskTemplateItem> = [ const columns: ColumnsType<VqdTaskTemplateItem> = [
{ {
@ -99,26 +112,54 @@ export default function VqdTaskTemplatePage() {
align: "center", align: "center",
}, },
{ {
title: "文件名称", title: "启用",
dataIndex: "file_name", dataIndex: "enable",
align: "center", align: "center",
render: (text, record) => ( render: (text, record) => (
<Space> <Space>
{text} <Switch value={text} defaultChecked onChange={(t) => {
saveTemplate(record, t)
}} />
</Space> </Space>
), ),
}, },
{
title: "诊断模块",
align: "center",
width: 550,
dataIndex: "vqd_lgt_dark",
render: (text, record) => (
<Flex gap="small" align="center" wrap>
{record?.vqd_lgt_dark?.enable && <Tag bordered={false} color="green" ></Tag>}
{record?.vqd_blue?.enable && <Tag bordered={false} color="green" ></Tag>}
{record?.vqd_clarity?.enable && <Tag bordered={false} color="green" ></Tag>}
{record?.vqd_shark?.enable && <Tag bordered={false} color="green" ></Tag>}
{record?.vqd_freeze?.enable && <Tag bordered={false} color="green" ></Tag>}
{record?.vqd_color?.enable && <Tag bordered={false} color="green" ></Tag>}
{record?.vqd_occlusion?.enable && <Tag bordered={false} color="green" ></Tag>}
{record?.vqd_noise?.enable && <Tag bordered={false} color="green" ></Tag>}
{record?.vqd_contrast?.enable && <Tag bordered={false} color="green" ></Tag>}
{record?.vqd_mosaic?.enable && <Tag bordered={false} color="green" ></Tag>}
{record?.vqd_flower?.enable && <Tag bordered={false} color="green" ></Tag>}
</Flex>
),
},
{ {
title: "描述", title: "描述",
dataIndex: "des", dataIndex: "des",
align: "center", align: "center",
}, },
{ // {
title: "创建日期", // title: "日期",
dataIndex: "created_at", // dataIndex: "created_at",
align: "center", // align: "center",
render: (text: string) => (text ? new Date(text).toLocaleString() : "-"), // render: (text: string, record) => (
}, // <>
// <div>创建:{(text ? new Date(text).toLocaleString() : "-")}</div>
// 更新:{(record?.updated_at ? new Date(record?.updated_at).toLocaleString() : "-")}
// </>
// ),
// },
{ {
title: "操作", title: "操作",
align: "center", align: "center",
@ -126,12 +167,12 @@ export default function VqdTaskTemplatePage() {
fixed: "right", fixed: "right",
render: (_, record) => ( render: (_, record) => (
<Space> <Space>
<Tooltip placement="top" title="编辑" color="#fff"> <Tooltip placement="top" title="编辑" color="#fff">
<Button icon={<EditOutlined />} onClick={() => handleEdit(record)} /> <Button icon={<EditOutlined />} onClick={() => handleEdit(record)} />
</Tooltip> </Tooltip>
<Popconfirm {!record.is_default&&<Popconfirm
title="确定要删除这个文件吗?" title="确定要删除这个模板吗?"
onConfirm={() => { onConfirm={() => {
if (record.id) { if (record.id) {
deleteMutation(record.id); deleteMutation(record.id);
@ -145,7 +186,8 @@ export default function VqdTaskTemplatePage() {
danger danger
icon={<DeleteOutlined />} icon={<DeleteOutlined />}
/> />
</Popconfirm> </Popconfirm>}
</Space> </Space>
), ),
}, },
@ -203,7 +245,7 @@ export default function VqdTaskTemplatePage() {
{/* 编辑模态框 */} {/* 编辑模态框 */}
<AddVqdTaskTemplate <AddVqdTaskTemplate
ref={dialogRef} ref={dialogRef}
title="编辑" title="添加/编辑模板"
onSuccess={() => refetch()} onSuccess={() => refetch()}
/> />
</div> </div>

View File

@ -1,5 +1,4 @@
import { Space, ConfigProvider, Modal, Tag, Tooltip, Button } from "antd"; import { Alert, ConfigProvider, Modal, Tag, message } from "antd";
import { DeliveredProcedureOutlined } from "@ant-design/icons";
import Table, { ColumnsType } from "antd/es/table"; import Table, { ColumnsType } from "antd/es/table";
import React, { import React, {
forwardRef, forwardRef,
@ -13,30 +12,28 @@ import { ChannelItem, ChannelReq } from "../../types/device";
import Filter from "./Filter"; import Filter from "./Filter";
import { GetChannels } from "../../api/devices"; import { GetChannels } from "../../api/devices";
import { useGlobal } from "../../Context"; import { useGlobal } from "../../Context";
import type { AddTaskItem } from "../../types/audiotask";
export interface IChannelModelFunc { export interface IChannelModelFunc {
openModal: (id: number, name: string) => void; openModal: (id: string) => void;
} }
interface IChannelModel { interface IChannelModel {
ref: any; ref: any;
onCallback: (data: AddTaskItem[]) => void; onCallback: (id: any, name:any) => void;
} }
const ChannelModel: React.FC<IChannelModel> = forwardRef(({ onCallback }, ref) => { const ChannelModel: React.FC<IChannelModel> = forwardRef(({onCallback},ref) => {
useImperativeHandle(ref, () => ({ useImperativeHandle(ref, () => ({
openModal: (id: number, name: string) => { openModal: (id: string) => {
setOpen(true); setOpen(true);
// if (id != 0) { if (id != "") {
// setSelectedRowKeys([id]) setSelectedRowKeys([id])
// } }
audioName.current = name
pid.current = id; pid.current = id;
}, },
})); }));
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const pid = useRef<number>(0); const pid = useRef<string>(undefined);
const audioName = useRef<string>('');
const { ErrorHandle } = useGlobal(); const { ErrorHandle } = useGlobal();
const columns: ColumnsType<ChannelItem> = [ const columns: ColumnsType<ChannelItem> = [
@ -77,25 +74,6 @@ const ChannelModel: React.FC<IChannelModel> = forwardRef(({ onCallback }, ref) =
dataIndex: "protocol", dataIndex: "protocol",
render: (text: string) => text || "-", render: (text: string) => text || "-",
}, },
{
title: "操作",
align: "center",
width: 120,
fixed: "right",
render: (_, record) => (
<Space>
<Tooltip placement="top" title="下发广播任务" color="#fff">
<Button icon={<DeliveredProcedureOutlined />} onClick={() => {
onCallback([{
audio_id: pid.current,
channel_id: record.id,
channel_name: record.name,
}])
}} />
</Tooltip>
</Space>
),
},
]; ];
// 获取通道列表 // 获取通道列表
@ -104,10 +82,9 @@ const ChannelModel: React.FC<IChannelModel> = forwardRef(({ onCallback }, ref) =
size: 10, // 通道一般 < 10 个,客户端不做分页,一次性全查 size: 10, // 通道一般 < 10 个,客户端不做分页,一次性全查
device_id: "", device_id: "",
pid: "ROOT", pid: "ROOT",
status: true, status: "",
name: "", name: "",
bid: "", bid: "",
protocol: "GB28181"
}); });
const { data, isLoading } = useQuery({ const { data, isLoading } = useQuery({
@ -122,7 +99,7 @@ const ChannelModel: React.FC<IChannelModel> = forwardRef(({ onCallback }, ref) =
enabled: open, enabled: open,
}); });
const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]); const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([]);
const [selectedRowsAll, setSelectedRows] = useState<ChannelItem[]>([]); const [selectedRows, setSelectedRows] = useState<ChannelItem[]>([]);
const rowSelection = { const rowSelection = {
selectedRowKeys, selectedRowKeys,
getCheckboxProps: (record: ChannelItem) => ({ getCheckboxProps: (record: ChannelItem) => ({
@ -132,34 +109,18 @@ const ChannelModel: React.FC<IChannelModel> = forwardRef(({ onCallback }, ref) =
newSelectedRowKeys: React.Key[], newSelectedRowKeys: React.Key[],
selectedRows: ChannelItem[] selectedRows: ChannelItem[]
) => { ) => {
setSelectedRowKeys(newSelectedRowKeys); if (newSelectedRowKeys.length > 0) {
setSelectedRows(selectedRows) setSelectedRowKeys([newSelectedRowKeys[newSelectedRowKeys.length - 1]]);
// if (newSelectedRowKeys.length > 0) { setSelectedRows([selectedRows[selectedRows.length - 1]]);
// setSelectedRowKeys([newSelectedRowKeys[newSelectedRowKeys.length - 1]]); }
// }
}, },
}; };
const onAll = () => {
let dataItem: AddTaskItem[] = []
selectedRowsAll.forEach(record => {
let list: AddTaskItem = {
audio_id: pid.current,
channel_id: record.id,
channel_name: record.name,
}
dataItem.push(list)
});
onCallback(dataItem)
setOpen(false);
setSelectedRows([])
setSelectedRowKeys([])
}
const onCancel = () => { const onCancel = () => {
setOpen(false); setOpen(false);
// if (selectedRowKeys.length>0) { if (selectedRowKeys.length>0) {
// onCallback(selectedRowKeys[0], pid.current) onCallback(selectedRows[0].id, selectedRows[0].name||selectedRows[0].id)
// } }
setSelectedRows([])
setSelectedRowKeys([]) setSelectedRowKeys([])
}; };
@ -184,17 +145,11 @@ const ChannelModel: React.FC<IChannelModel> = forwardRef(({ onCallback }, ref) =
> >
<Modal <Modal
open={open} open={open}
title={`选择通道广播【${audioName.current}】音频`} title="绑定通道"
style={{ top: "5%" }} style={{ top: "5%" }}
width={"1000px"} width={"1000px"}
footer={ onCancel={onCancel}
<> onOk={onCancel}
<Button onClick={() => onCancel()} > </Button>
<Button disabled={selectedRowKeys.length == 0} type="primary" onClick={() => onAll()} className="mr-6"></Button>
</>
}
onCancel={onCancel}
// onOk={onCancel}
> >
<div> <div>
<div className="mb-2 flex justify-end"> <div className="mb-2 flex justify-end">
@ -204,7 +159,7 @@ const ChannelModel: React.FC<IChannelModel> = forwardRef(({ onCallback }, ref) =
onSearchChange={(value: string) => { onSearchChange={(value: string) => {
setPagination({ ...pagination, name: value, bid: value }); setPagination({ ...pagination, name: value, bid: value });
}} }}
onSelectChange={(value: any) => { onSelectChange={(value: string) => {
setPagination({ ...pagination, status: value }); setPagination({ ...pagination, status: value });
}} }}
/> />

View File

@ -145,6 +145,14 @@
margin-right: 0.75rem; margin-right: 0.75rem;
} }
.m-0 {
margin: 0;
}
.mb-0 {
margin-bottom: 0;
}
.mb-1 { .mb-1 {
margin-bottom: 0.25rem; margin-bottom: 0.25rem;
} }
@ -169,10 +177,26 @@
margin-right: 0px; margin-right: 0px;
} }
.mr-2 {
margin-right: 0.5rem;
}
.mr-4 {
margin-right: 1rem;
}
.mt-2 {
margin-top: 0.5rem;
}
.mt-4 { .mt-4 {
margin-top: 1rem; margin-top: 1rem;
} }
.mt-6 {
margin-top: 1.5rem;
}
.block { .block {
display: block; display: block;
} }
@ -438,6 +462,10 @@
padding-bottom: 2rem; padding-bottom: 2rem;
} }
.pb-1 {
padding-bottom: 0.25rem;
}
.pb-2 { .pb-2 {
padding-bottom: 0.5rem; padding-bottom: 0.5rem;
} }
@ -446,6 +474,18 @@
padding-bottom: 0.75rem; padding-bottom: 0.75rem;
} }
.pl-2 {
padding-left: 0.5rem;
}
.pl-3 {
padding-left: 0.75rem;
}
.pr-2 {
padding-right: 0.5rem;
}
.pr-4 { .pr-4 {
padding-right: 1rem; padding-right: 1rem;
} }
@ -506,6 +546,12 @@
color: rgb(17 24 39 / var(--tw-text-opacity, 1)); color: rgb(17 24 39 / var(--tw-text-opacity, 1));
} }
.shadow {
--tw-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
--tw-shadow-colored: 0 1px 3px 0 var(--tw-shadow-color), 0 1px 2px -1px var(--tw-shadow-color);
box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow)
}
.filter { .filter {
filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow); filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
} }
@ -553,3 +599,22 @@ body {
grid-template-columns: repeat(3, minmax(0, 1fr)); grid-template-columns: repeat(3, minmax(0, 1fr));
} }
} }
.config-box {
width: 260px;
border: 1px solid rgb(222,222,222,0.8);
border-radius: 0.5rem;
}
.config-box-hade {
padding: 0.2rem 0.6rem;
border-radius: 0.5rem 0.5rem 0 0;
background-color: rgb(222,222,222,0.8);
}
.config-box-hade h4 {
margin: 0;
}
.config-box-item {
padding: 0.3rem;
}

View File

@ -1,4 +1,16 @@
import type {
VqdLgtDark,
VqdBlue,
VqdClarity,
VqdShark,
VqdFreeze,
VqdColor,
VqdOcclusion,
VqdNoise,
VqdContrast,
VqdMosaic,
VqdFlower,
} from "./vqdtasktemplate"
/** /**
* *
*/ */
@ -8,12 +20,24 @@ export type VqdConfigBaseRes = {
export type UpdateConfigBaseReq = { export type UpdateConfigBaseReq = {
save_day: number; save_day: number;
frm_num: number;
is_deep_learn: boolean;
}; };
export type VqdConfigBaseDetailRes = { export type VqdConfigBaseDetailRes = {
save_day: number; save_day: number;
}
export type VqdConfigDefaultDetailRes = {
frm_num: number; frm_num: number;
is_deep_learn: boolean; is_deep_learn: boolean;
} vqd_lgt_dark: VqdLgtDark;
vqd_blue: VqdBlue;
vqd_clarity: VqdClarity;
vqd_shark: VqdShark;
vqd_freeze: VqdFreeze;
vqd_color: VqdColor;
vqd_occlusion: VqdOcclusion;
vqd_noise: VqdNoise;
vqd_contrast: VqdContrast;
vqd_mosaic: VqdMosaic;
vqd_flower: VqdFlower;
}

View File

@ -189,7 +189,7 @@ type ChannelReq = {
/** /**
* true:线; false:线; * true:线; false:线;
*/ */
status?: boolean; status?: string;
}; };
export type ChannelRes = { export type ChannelRes = {

View File

@ -26,6 +26,19 @@ export type VqdTaskTemplateItem = {
name: string; name: string;
plans: string; plans: string;
enable: boolean; enable: boolean;
is_default: boolean;
vqd_config: VqdConfig;
vqd_lgt_dark: VqdLgtDark;
vqd_blue: VqdBlue;
vqd_clarity: VqdClarity;
vqd_shark: VqdShark;
vqd_freeze: VqdFreeze;
vqd_color: VqdColor;
vqd_occlusion: VqdOcclusion;
vqd_noise: VqdNoise;
vqd_contrast: VqdContrast;
vqd_mosaic: VqdMosaic;
vqd_flower: VqdFlower;
created_at?: string; created_at?: string;
updated_at?: string; updated_at?: string;
des: string; des: string;
@ -49,6 +62,70 @@ export type VqdTaskTemplateReq = {
size: number; size: number;
} }
export type VqdConfig = {
enable: boolean;
frm_num: number;
is_deep_learn: boolean;
}
export type VqdLgtDark = {
enable: boolean;
dark_thr: number;
lgt_thr: number;
lgt_dark_abn_num_ratio: number;
}
export type VqdBlue = {
enable: boolean;
blue_thr: number;
blue_abn_num_ratio: number;
}
export type VqdClarity = {
enable: boolean;
clarity_thr: number;
clarity_abn_num_ratio: number;
}
export type VqdShark = {
enable: boolean;
shark_thr: number;
shark_abn_num_ratio: number;
}
export type VqdFreeze = {
enable: boolean;
freeze_thr: number;
freeze_abn_num_ratio: number;
}
export type VqdColor = {
enable: boolean;
color_thr: number;
color_abn_num_ratio: number;
}
export type VqdOcclusion = {
enable: boolean;
occlusion_thr: number;
occlusion_abn_num_ratio: number;
}
export type VqdNoise = {
enable: boolean;
noise_thr: number;
noise_abn_num_ratio: number;
}
export type VqdContrast = {
enable: boolean;
ctra_low_thr: number;
ctra_high_thr: number;
ctra_abn_num_ratio: number;
}
export type VqdMosaic = {
enable: boolean;
mosaic_thr: number;
mosaic_abn_num_ratio: number;
}
export type VqdFlower = {
enable: boolean;
flower_thr: number;
flower_abn_num_ratio: number;
mosaic_thr: number;
}
export type CreateVqdTaskTemplateReq = { export type CreateVqdTaskTemplateReq = {
/** /**
* *
@ -62,6 +139,18 @@ export type CreateVqdTaskTemplateReq = {
* *
*/ */
enable: boolean; enable: boolean;
vqd_config: VqdConfig;
vqd_lgt_dark: VqdLgtDark;
vqd_blue: VqdBlue;
vqd_clarity: VqdClarity;
vqd_shark: VqdShark;
vqd_freeze: VqdFreeze;
vqd_color: VqdColor;
vqd_occlusion: VqdOcclusion;
vqd_noise: VqdNoise;
vqd_contrast: VqdContrast;
vqd_mosaic: VqdMosaic;
vqd_flower: VqdFlower;
/** /**
* *
*/ */
@ -86,6 +175,19 @@ export type VqdTaskTemplateDetailRes = {
name: string; name: string;
plans: string; plans: string;
enable: boolean; enable: boolean;
is_default: boolean;
vqd_config: VqdConfig;
vqd_lgt_dark: VqdLgtDark;
vqd_blue: VqdBlue;
vqd_clarity: VqdClarity;
vqd_shark: VqdShark;
vqd_freeze: VqdFreeze;
vqd_color: VqdColor;
vqd_occlusion: VqdOcclusion;
vqd_noise: VqdNoise;
vqd_contrast: VqdContrast;
vqd_mosaic: VqdMosaic;
vqd_flower: VqdFlower;
created_at?: string; created_at?: string;
updated_at?: string; updated_at?: string;
des: string; des: string;