Files
observer/server/biz/dao/false_target_report.go
T
2026-09-10 09:41:13 +08:00

145 lines
5.5 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package dao
import (
"context"
"github.com/gogf/gf/v2/database/gdb"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/os/gtime"
"observer-server/biz/consts"
"observer-server/biz/model/entity"
"observer-server/common"
)
// FalseTargetReport 假目标上报表 DAO(技术设计.md「假目标上报」)。
type falseTargetReportDao struct{}
var FalseTargetReport = &falseTargetReportDao{}
func init() {
ctx := context.Background()
_, err := g.DB().Exec(ctx, `CREATE TABLE IF NOT EXISTS false_target_report (
id INTEGER PRIMARY KEY AUTOINCREMENT,
phone_num TEXT NOT NULL,
file TEXT NOT NULL,
labels_json TEXT NOT NULL DEFAULT '',
species TEXT NOT NULL DEFAULT '',
status TEXT NOT NULL DEFAULT 'pending', -- pending/approved(拒绝即删记录,无 rejected 存量)
image_hash INTEGER NOT NULL DEFAULT 0, -- 整帧 dHash 64 位(上报查重;0=未算/存量回填前)
suspect_real INTEGER NOT NULL DEFAULT 0, -- RF-DETR 高分检出疑似真目标预判标记(0/1)
created_at TEXT NOT NULL,
reviewed_at TEXT
)`)
if err != nil {
panic(err)
}
// 存量库迁移:查重/预判两列(2026-09-09;新库建表已含列,幂等跳过)
common.EnsureColumn(ctx, consts.TableFalseTargetReport, "image_hash", "image_hash INTEGER NOT NULL DEFAULT 0")
common.EnsureColumn(ctx, consts.TableFalseTargetReport, "suspect_real", "suspect_real INTEGER NOT NULL DEFAULT 0")
}
// Insert 插入上报记录并返回自增 id
func (d *falseTargetReportDao) Insert(ctx context.Context, m *entity.FalseTargetReport) (int64, error) {
res, err := g.DB().Model(consts.TableFalseTargetReport).Ctx(ctx).Data(g.Map{
"phone_num": m.PhoneNum,
"file": m.File,
"labels_json": m.LabelsJson,
"species": m.Species,
"status": m.Status,
"image_hash": m.ImageHash,
"created_at": m.CreatedAt,
}).Insert()
if err != nil {
return 0, err
}
return res.LastInsertId()
}
// CountTodayByPhone 某用户当日(自然日)上报条数(日限额判定)
func (d *falseTargetReportDao) CountTodayByPhone(ctx context.Context, phone string, dayStart *gtime.Time) (int, error) {
return g.DB().Model(consts.TableFalseTargetReport).Ctx(ctx).
Where("phone_num", phone).
WhereGTE("created_at", dayStart).
Count()
}
// PageByFilter 管理端分页(phoneNum 精确过滤、status 过滤,按上报时间倒序)
func (d *falseTargetReportDao) PageByFilter(ctx context.Context, phone, status string, page, size int) ([]*entity.FalseTargetReport, int64, error) {
base := func() *gdb.Model {
m := g.DB().Model(consts.TableFalseTargetReport).Ctx(ctx)
if phone != "" {
m = m.Where("phone_num", phone)
}
if status != "" {
m = m.Where("status", status)
}
return m
}
total, err := base().Count()
if err != nil {
return nil, 0, err
}
var list []*entity.FalseTargetReport
err = base().OrderDesc("id").Limit((page-1)*size, size).Scan(&list)
return list, int64(total), err
}
// GetByIds 按 id 批量取(审核前校验)
func (d *falseTargetReportDao) GetByIds(ctx context.Context, ids []int64) ([]*entity.FalseTargetReport, error) {
var list []*entity.FalseTargetReport
err := g.DB().Model(consts.TableFalseTargetReport).Ctx(ctx).WhereIn("id", ids).Scan(&list)
return list, err
}
// SetStatus 审核通过落状态(仅 pending 可迁转,重复审核由调用方先查后写保证幂等)
func (d *falseTargetReportDao) SetStatus(ctx context.Context, id int64, status string, reviewedAt *gtime.Time) error {
_, err := g.DB().Model(consts.TableFalseTargetReport).Ctx(ctx).Where("id", id).
Data(g.Map{"status": status, "reviewed_at": reviewedAt}).Update()
return err
}
// DeleteByIds 删除记录(拒绝即删:记录与文件同删,不留 rejected 存量)
func (d *falseTargetReportDao) DeleteByIds(ctx context.Context, ids []int64) error {
_, err := g.DB().Model(consts.TableFalseTargetReport).Ctx(ctx).WhereIn("id", ids).Delete()
return err
}
// ListHashes 全表非零 dHash(上报查重比对集;0=未算/回填前不参与比对)。
// 条件必须是 != 0 而非 > 0dHash 最高位为 1 时 int64 存为负数(SQLite INTEGER 有符号),
// 用 > 0 会把约一半的 hash 排除在比对集外,查重静默失效(2026-09-10 实测)
func (d *falseTargetReportDao) ListHashes(ctx context.Context) ([]int64, error) {
all, err := g.DB().Model(consts.TableFalseTargetReport).Ctx(ctx).
Fields("image_hash").Where("image_hash != 0").Array("image_hash")
if err != nil {
return nil, err
}
out := make([]int64, 0, len(all))
for _, v := range all {
out = append(out, v.Int64())
}
return out, nil
}
// ListHashMissing 存量回填待办:image_hash=0 的记录
func (d *falseTargetReportDao) ListHashMissing(ctx context.Context) ([]*entity.FalseTargetReport, error) {
var list []*entity.FalseTargetReport
err := g.DB().Model(consts.TableFalseTargetReport).Ctx(ctx).
Where("image_hash", 0).OrderAsc("id").Scan(&list)
return list, err
}
// UpdateHash 回填整帧 dHash
func (d *falseTargetReportDao) UpdateHash(ctx context.Context, id int64, hash int64) error {
_, err := g.DB().Model(consts.TableFalseTargetReport).Ctx(ctx).Where("id", id).
Data("image_hash", hash).Update()
return err
}
// SetSuspectReal 预判命中置疑似真目标标记(幂等,只置 1 不清 0)
func (d *falseTargetReportDao) SetSuspectReal(ctx context.Context, id int64) error {
_, err := g.DB().Model(consts.TableFalseTargetReport).Ctx(ctx).Where("id", id).
Data("suspect_real", 1).Update()
return err
}