package controllers
|
|
import (
|
"basic.com/valib/bhomeclient.git"
|
"basic.com/valib/bhomedbapi.git"
|
"basic.com/valib/logger.git"
|
"encoding/json"
|
"fmt"
|
"io"
|
"net/http"
|
"os"
|
"path/filepath"
|
"strconv"
|
"strings"
|
"time"
|
"vamicro/config"
|
"vamicro/search-service/esutil"
|
"vamicro/search-service/models"
|
)
|
|
type EsSearchController struct{}
|
|
// @Security ApiKeyAuth
|
// @Summary 检索
|
// @Description 信息检索和比对检索
|
// @Accept json
|
// @Produce json
|
// @Tags es
|
// @Param obj body models.EsSearch true "底库数据"
|
// @Success 200 {string} json "{"code":200, msg:"目录结构数据", success:true}"
|
// @Failure 500 {string} json "{"code":500, msg:"返回错误信息", success:false}"
|
// @Router /data/api-v/es/esSearch [POST]
|
func (sc *EsSearchController) PostEsSearch(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply {
|
var arg models.EsSearch
|
err := c.BindJSON(&arg)
|
if err != nil || arg.Page <= 0 && arg.Size <= 0 {
|
return &bhomeclient.Reply{Success: false, Msg: "参数有误"}
|
}
|
data := findEsData(&arg)
|
|
return &bhomeclient.Reply{Success: true, Data: data}
|
}
|
|
func (sc *EsSearchController) PostEsDelete(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply {
|
type DeleteReq struct {
|
Id string `json:"id"` //数据id
|
User string `json:"user"`
|
Password string `json:"password"`
|
}
|
|
var reqBody DeleteReq
|
if e := c.BindJSON(&reqBody); e != nil {
|
return &bhomeclient.Reply{Success: false, Msg: "参数有误:" + e.Error()}
|
}
|
|
uApi := bhomedbapi.UserApi{}
|
ok, _ := uApi.Login(reqBody.User, reqBody.Password)
|
if !ok {
|
return &bhomeclient.Reply{Success: false, Msg: "密码不正确"}
|
}
|
|
var sApi bhomedbapi.SysSetApi
|
flag, localConf := sApi.GetServerInfo()
|
if !flag || localConf.AlarmIp == "" || localConf.AlarmPort == 0 {
|
logger.Debug("localConf err")
|
return &bhomeclient.Reply{Success: false, Msg: "es未配置"}
|
}
|
index := config.EsInfo.EsIndex.AiOcean.IndexName
|
url := "http://" + localConf.AlarmIp + ":" + strconv.Itoa(int(localConf.AlarmPort)) +
|
"/" + index + "/_delete_by_query?refresh=true"
|
var reqJson = `
|
{
|
"query": {
|
"bool": {
|
"filter": [
|
{
|
"term": {
|
"id": "` + reqBody.Id + `"
|
}
|
}
|
]
|
}
|
}
|
}
|
`
|
buf, re := esutil.EsReq("POST", url, []byte(reqJson))
|
if re != nil {
|
return &bhomeclient.Reply{Success: false, Msg: re.Error()}
|
}
|
var info interface{}
|
json.Unmarshal(buf, &info)
|
out, ok := info.(map[string]interface{})
|
if !ok {
|
return &bhomeclient.Reply{Success: false, Msg: "删除失败"}
|
}
|
middle, ok := out["deleted"].(float64)
|
batches, ok1 := out["batches"].(float64)
|
if !ok || !ok1 {
|
return &bhomeclient.Reply{Success: false, Msg: "first updated change error"}
|
}
|
if batches == 0 {
|
return &bhomeclient.Reply{Success: false, Msg: "目标数据不存在"}
|
}
|
logger.Debug("删除es数据ret:", string(buf), " middle:", middle, " batches:", batches, " reqBody:", reqBody)
|
|
time.Sleep(1 * time.Second)
|
|
return &bhomeclient.Reply{Success: true, Msg: "删除成功"}
|
}
|
|
type GetVideoUrlReq struct {
|
Id string `json:"id"`
|
}
|
|
func (sc *EsSearchController) GetVideoUrl(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply {
|
var arg GetVideoUrlReq
|
err := c.BindJSON(&arg)
|
if err != nil || arg.Id == "" {
|
return &bhomeclient.Reply{Success: false, Msg: "参数有误"}
|
}
|
|
var sApi bhomedbapi.SysSetApi
|
flag, localConf := sApi.GetServerInfo()
|
if !flag || localConf.AlarmIp == "" || localConf.AlarmPort == 0 {
|
logger.Debug("localConf err")
|
return &bhomeclient.Reply{Success: false, Msg: "localConf err"}
|
}
|
|
url := "http://" + localConf.AlarmIp + ":" + strconv.Itoa(int(localConf.AlarmPort)) +
|
"/" + config.EsInfo.EsIndex.AiOcean.IndexName + "/_search"
|
|
var prama = `
|
{
|
"query": {
|
"bool": {
|
"filter": [
|
{
|
"term": {
|
"id": "` + arg.Id + `"
|
}
|
}
|
]
|
}
|
},
|
"_source": [
|
"videoUrl"
|
]
|
}
|
`
|
|
buf, err := esutil.EsReq("POST", url, []byte(prama))
|
if err != nil {
|
return &bhomeclient.Reply{Success: false, Msg: "es request err"}
|
}
|
|
sources, err := esutil.Sourcelist(buf)
|
if err != nil {
|
return &bhomeclient.Reply{Success: false, Msg: "es soucelist err"}
|
}
|
|
var videoUrl string
|
if len(sources) > 0 {
|
videoUrl = sources[0]["videoUrl"].(string)
|
}
|
|
return &bhomeclient.Reply{Success: true, Data: videoUrl}
|
}
|
|
// 获取监控等级
|
func getAlarmLevel(alarmlevel []int32) []string {
|
d := bhomedbapi.DicApi{}
|
res, data := d.FindByType("ALARMLEVEL")
|
if data == nil {
|
logger.Debug("data is nil")
|
}
|
logger.Debug(res)
|
// logger.Debug(data)
|
alarmLevel := make(map[int32]string)
|
tmp := data.(map[string]interface{})
|
for _, value := range tmp["ALARMLEVEL"].([]interface{}) {
|
// logger.Debug(value.(map[string]interface{})["value"]," ",value.(map[string]interface{})["name"])
|
val := value.(map[string]interface{})["value"].(string)
|
name := value.(map[string]interface{})["name"].(string)
|
vl, err := strconv.Atoi(val)
|
if err != nil {
|
logger.Debug(err)
|
}
|
alarmLevel[int32(vl)] = name
|
}
|
alarmLevelRes := make([]string, len(alarmlevel))
|
for i, v := range alarmlevel {
|
if v < 0 {
|
alarmLevelRes[i] = "撤防"
|
} else {
|
alarmLevelRes[i] = alarmLevel[v]
|
}
|
}
|
return alarmLevelRes
|
}
|
|
func findEsData(searchBody *models.EsSearch) map[string]interface{} {
|
webPage := searchBody.Page
|
|
webSize := searchBody.Size
|
from := strconv.Itoa((webPage - 1) * webSize)
|
//esFrom := strconv.Itoa(from)
|
//esSize := strconv.Itoa(webSize)
|
size := strconv.Itoa(webSize)
|
//请求索引
|
index := config.EsInfo.EsIndex.AiOcean.IndexName
|
queryStr := ""
|
queryBody := searchBody.InputValue
|
//检索框
|
if queryBody != "" {
|
queryStr = "\"must\":[{\"multi_match\":{\"query\":\"" + queryBody + "\",\"fields\":[\"cameraAddr^1.5\",\"taskName^1.5\",\"sdkName^1.5\",\"showLabels^3.0\",\"baseInfo.tableName^1.5\",\"baseInfo.targetName^1.5\",\"baseInfo.labels^1.5\",\"alarmRules.alarmLevel^1.5\",\"linkTag^1.5\",\"linkTagInfo.cameraAddr\",\"linkTagInfo.taskName^1.5\",\"linkTagInfo.sdkName^1.5\",\"linkTagInfo.showLabels^1.5\",\"linkTagInfo.baseInfo.tableName^1.5\",\"linkTagInfo.baseInfo.targetName^1.5\",\"linkTagInfo.baseInfo.labels^1.5\",\"linkTagInfo.alarmRules.alarmLevel^1.5\"]," +
|
"\"type\":\"cross_fields\",\"operator\":\"OR\",\"slop\":0,\"prefix_length\":0,\"max_expansions\":50,\"zero_terms_query\":\"NONE\",\"auto_generate_synonyms_phrase_query\":true,\"fuzzy_transpositions\":true,\"boost\":1}}],"
|
}
|
|
searchTime := searchBody.SearchTime
|
if searchTime == nil || len(searchTime) < 2 {
|
info := make(map[string]interface{}, 0)
|
info["err"] = "请输入时间范围"
|
return info
|
}
|
|
gteDate := searchTime[0]
|
lteDate := searchTime[1]
|
|
//判断数据ID
|
idStr := ""
|
linkTagInfoIdStr := ""
|
//personId := searchBody.Id
|
id := []string{}
|
if id != nil && len(id) > 0 {
|
esId := strings.Replace(strings.Trim(fmt.Sprint(id), "[]"), " ", "\",\"", -1)
|
idStr = "{\"terms\":{\"id\":[\"" + esId + "\"]}},"
|
linkTagInfoIdStr = "{\"terms\":{\"linkTagInfo.id\":[\"" + esId + "\"]}},"
|
}
|
|
//判断任务ID
|
taskIdStr := ""
|
linkTagInfoTaskIdStr := ""
|
taskId := searchBody.Tasks
|
if taskId != nil && len(taskId) > 0 {
|
esTaskId := strings.Replace(strings.Trim(fmt.Sprint(taskId), "[]"), " ", "\",\"", -1)
|
taskIdStr = "{\"terms\":{\"taskId\":[\"" + esTaskId + "\"]}},"
|
linkTagInfoTaskIdStr = "{\"terms\":{\"linkTagInfo.taskId\":[\"" + esTaskId + "\"]}},"
|
}
|
//判断数据来源
|
dataSourceStr := ""
|
dataSource := searchBody.DataSource
|
if dataSource != "" {
|
dataSourceStr = "{\"term\":{\"dataSource\":\"" + dataSource + "\"}},"
|
}
|
//判断摄像机ID
|
cameraIdStr := ""
|
linkTagInfoCameraIdStr := ""
|
cameraId := searchBody.TreeNodes
|
if cameraId != nil && len(cameraId) > 0 {
|
esCameraId := strings.Replace(strings.Trim(fmt.Sprint(cameraId), "[]"), " ", "\",\"", -1)
|
cameraIdStr = "{\"terms\":{\"cameraId\":[\"" + esCameraId + "\"]}},"
|
linkTagInfoCameraIdStr = "{\"terms\":{\"linkTagInfo.cameraId\":[\"" + esCameraId + "\"]}},"
|
}
|
|
//判断库表ID
|
tableId := searchBody.Tabs
|
esTableId := ""
|
esTableIdStr := ""
|
linkTagInfoEsTableIdStr := ""
|
if tableId != nil && len(tableId) > 0 {
|
esTableId = strings.Replace(strings.Trim(fmt.Sprint(tableId), "[]"), " ", "\",\"", -1)
|
esTableIdStr = "{\"terms\":{\"baseInfo.tableId\":[\"" + esTableId + "\"]}},"
|
linkTagInfoEsTableIdStr = "{\"terms\":{\"linkTagInfo.baseInfo.tableId\":[\"" + esTableId + "\"]}},"
|
}
|
//判断收藏状态
|
isCollectStr := ""
|
linkTagInfoIsCollectStr := ""
|
isCollect := searchBody.Collection
|
if isCollect != "" {
|
if isCollect == "1" {
|
isCollectStr = "{\"term\":{\"isCollect\":true}},"
|
linkTagInfoIsCollectStr = "{\"term\":{\"linkTagInfo.isCollect\":true}},"
|
} else if isCollect == "0" {
|
isCollectStr = "{\"term\":{\"isCollect\":false}},"
|
linkTagInfoIsCollectStr = "{\"term\":{\"linkTagInfo.isCollect\":false}},"
|
}
|
}
|
//判断布防等级id
|
alarmLevelId := searchBody.AlarmLevel
|
alarmLevelStr := ""
|
linkTagInfoAlarmLevelStr := ""
|
if len(alarmLevelId) > 0 {
|
alarmLevelTypes := strings.Replace(strings.Trim(fmt.Sprint(getAlarmLevel(alarmLevelId)), "[]"), " ", "\",\"", -1)
|
alarmLevelStr = "{\"terms\":{\"alarmRules.alarmLevel.raw\":[\"" + alarmLevelTypes + "\"]}},"
|
linkTagInfoAlarmLevelStr = "{\"terms\":{\"linkTagInfo.alarmRules.alarmLevel.raw\":[\"" + alarmLevelTypes + "\"]}},"
|
}
|
|
//使用es底层机制处理分页
|
//请求头
|
serverId := config.Server.AnalyServerId
|
var sApi bhomedbapi.SysSetApi
|
flag, localConf := sApi.GetServerInfo()
|
if !flag || localConf.AlarmIp == "" || localConf.AlarmPort == 0 {
|
logger.Debug("localConf err")
|
return nil
|
}
|
url := "http://" + localConf.AlarmIp + ":" + strconv.Itoa(int(localConf.AlarmPort)) +
|
"/" + index + "/_search?search_type=dfs_query_then_fetch"
|
|
analyServerFilterStr := ""
|
if !searchBody.IsAll {
|
analyServerFilterStr = "{\"term\":{\"analyServerId\":\"" + serverId + "\"}},"
|
}
|
linkTagInfoAnalyServerFilterStr := "{\"term\":{\"linkTagInfo.analyServerId\":\"" + serverId + "\"}},"
|
|
//请求体
|
prama := "{\"from\":\"" + from + "\"," +
|
"\"size\":\"" + size + "\"," +
|
"\"query\":{\"bool\":{" + queryStr +
|
"\"should\":[" +
|
"{\"bool\":{\"filter\":[" +
|
dataSourceStr +
|
cameraIdStr +
|
alarmLevelStr +
|
idStr +
|
taskIdStr +
|
isCollectStr +
|
esTableIdStr +
|
analyServerFilterStr +
|
"{\"range\":{\"picDate\":{\"from\":\"" + gteDate + "\",\"to\":\"" + lteDate + "\",\"include_lower\":true,\"include_upper\":true,\"boost\":1}}}" +
|
"]}}," +
|
"{\"bool\":{\"filter\":[" +
|
linkTagInfoCameraIdStr +
|
linkTagInfoAlarmLevelStr +
|
linkTagInfoIdStr +
|
linkTagInfoTaskIdStr +
|
linkTagInfoIsCollectStr +
|
linkTagInfoEsTableIdStr +
|
linkTagInfoAnalyServerFilterStr +
|
"{\"range\":{\"linkTagInfo.picDate\":{\"from\":\"" + gteDate + "\",\"to\":\"" + lteDate + "\",\"include_lower\":true,\"include_upper\":true,\"boost\":1}}}" +
|
"]}}" +
|
"],\"minimum_should_match\":1}}," +
|
"\"sort\":[{\"_score\":{\"order\":\"desc\"}},{\"updateTime\":{\"order\":\"desc\"}}]," +
|
"\"_source\":{\"includes\":[],\"excludes\":[\"*.feature\"]}" +
|
"}"
|
logger.Debug("url: ", url)
|
logger.Debug("findEsData.param:", prama)
|
//数据解析
|
tokenRes := esutil.GetEsDataReq(url, prama, true)
|
tmpAllDate := esutil.ResponseData(tokenRes)
|
return tmpAllDate
|
}
|
|
// 报警记录关注和取消关注接口
|
func (sc *EsSearchController) Collect(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply {
|
type CollectReq struct {
|
Id string `json:"id"` //数据id
|
IsCollect bool `json:"isCollect"` //关注或者取消关注
|
}
|
var reqBody CollectReq
|
if e := c.BindJSON(&reqBody); e != nil {
|
return &bhomeclient.Reply{Msg: "参数有误:" + e.Error()}
|
}
|
|
var sApi bhomedbapi.SysSetApi
|
flag, localConf := sApi.GetServerInfo()
|
if !flag || localConf.AlarmIp == "" || localConf.AlarmPort == 0 {
|
logger.Debug("localConf err")
|
return &bhomeclient.Reply{Msg: "es未配置"}
|
}
|
index := config.EsInfo.EsIndex.AiOcean.IndexName
|
url := "http://" + localConf.AlarmIp + ":" + strconv.Itoa(int(localConf.AlarmPort)) +
|
"/" + index + "/_update_by_query?refresh=true"
|
sourceStr := "ctx._source.isCollect=" + strconv.FormatBool(reqBody.IsCollect) + ""
|
var reqJson = `
|
{
|
"script": {
|
"source": "` + sourceStr + `"
|
},
|
"query": {
|
"term": {
|
"id": "` + reqBody.Id + `"
|
}
|
}
|
}
|
`
|
buf, re := esutil.EsReq("POST", url, []byte(reqJson))
|
if re != nil {
|
return &bhomeclient.Reply{Msg: re.Error()}
|
}
|
var info interface{}
|
json.Unmarshal(buf, &info)
|
out, ok := info.(map[string]interface{})
|
if !ok {
|
return &bhomeclient.Reply{Msg: "更新失败"}
|
}
|
middle, ok := out["updated"].(float64)
|
batches, ok1 := out["batches"].(float64)
|
if !ok || !ok1 {
|
return &bhomeclient.Reply{Msg: "first updated change error"}
|
}
|
if batches == 0 {
|
return &bhomeclient.Reply{Msg: "目标数据不存在"}
|
}
|
logger.Debug("修改es是否关注 ret:", string(buf), " middle:", middle, " batches:", batches, " reqBody:", reqBody)
|
return &bhomeclient.Reply{Success: true, Msg: "更新成功"}
|
}
|
|
// UpdateStatusReq 请求体结构
|
type UpdateMisreportReq struct {
|
Id string `json:"id"` // 数据id
|
PicSrcUrl []string `json:"picSrcUrl"` // 照片URL列表
|
TaskName string `json:"taskName"` // 保存照片的文件名列表
|
}
|
|
// @Security ApiKeyAuth
|
// @Summary 修改ES数据中的status字段
|
// @Description 修改ES数据中的status字段
|
// @Accept json
|
// @Produce json
|
// @Tags es
|
// @Param obj body models.SignMisreport true "更新请求"
|
// @Success 200 {string} json "{"code":200, msg:"更新成功", success:true}"
|
// @Failure 500 {string} json "{"code":500, msg:"返回错误信息", success:false}"
|
// @Router /data/api-v/es/esUpdateStatus [POST]
|
func (sc *EsSearchController) SignMisreport(h *bhomeclient.WrapperHandler, c *bhomeclient.Request) *bhomeclient.Reply {
|
|
var reqBody UpdateMisreportReq
|
if e := c.BindJSON(&reqBody); e != nil {
|
return &bhomeclient.Reply{Msg: "参数有误:" + e.Error()}
|
}
|
|
var sApi bhomedbapi.SysSetApi
|
flag, localConf := sApi.GetServerInfo()
|
if !flag || localConf.AlarmIp == "" || localConf.AlarmPort == 0 {
|
logger.Error("localConf err")
|
return &bhomeclient.Reply{Msg: "es未配置"}
|
}
|
index := config.EsInfo.EsIndex.AiOcean.IndexName
|
// 保存照片到服务器文件夹
|
saveDir := "/data/misreport_images" //config.Server.MisreportImagesPath
|
// 拼接保存路径
|
savePath := filepath.Join(saveDir, reqBody.TaskName, "未标注")
|
//logger.Error(savePath)
|
if err := os.MkdirAll(savePath, os.ModePerm); err != nil {
|
logger.Error(err.Error())
|
return &bhomeclient.Reply{Msg: "创建保存目录失败: " + err.Error()}
|
}
|
// 下载并保存每个照片
|
for _, photoUrl := range reqBody.PicSrcUrl {
|
if photoUrl == "" {
|
continue
|
}
|
photoUrl = ensureHTTPPrefix(photoUrl)
|
photoResp, err := http.Get(photoUrl)
|
if err != nil {
|
logger.Error("下载照片失败")
|
return &bhomeclient.Reply{Msg: "下载照片失败: " + err.Error()}
|
}
|
defer photoResp.Body.Close()
|
saveFilePath := filepath.Join(savePath, reqBody.Id+".jpg")
|
saveFile, err := os.Create(saveFilePath)
|
if err != nil {
|
logger.Error("创建保存文件失败:", saveFilePath)
|
return &bhomeclient.Reply{Msg: "创建保存文件失败: " + err.Error()}
|
}
|
defer saveFile.Close()
|
|
if _, err := io.Copy(saveFile, photoResp.Body); err != nil {
|
logger.Error("保存照片失败:", saveFilePath)
|
return &bhomeclient.Reply{Msg: "保存照片失败: " + err.Error()}
|
}
|
}
|
|
url := "http://" + localConf.AlarmIp + ":" + strconv.Itoa(int(localConf.AlarmPort)) +
|
"/" + index + "/_update_by_query"
|
|
// 构造更新请求的 JSON
|
var reqJson = `
|
{
|
"script": {
|
"source": "ctx._source.misreport = params.misreport",
|
"lang": "painless",
|
"params": {
|
"misreport": true
|
}
|
},
|
"query": {
|
"bool": {
|
"filter": [
|
{
|
"term": {
|
"id": "` + reqBody.Id + `"
|
}
|
}
|
]
|
}
|
}
|
}`
|
// 发送请求到 ES
|
buf, re := esutil.EsReq("POST", url, []byte(reqJson))
|
if re != nil {
|
logger.Error(re.Error())
|
return &bhomeclient.Reply{Msg: re.Error()}
|
}
|
|
// 解析返回结果
|
var info interface{}
|
json.Unmarshal(buf, &info)
|
out, ok := info.(map[string]interface{})
|
if !ok {
|
logger.Error("更新失败")
|
return &bhomeclient.Reply{Msg: "更新失败"}
|
}
|
// 检查是否成功更新
|
updated, ok := out["updated"].(float64)
|
if !ok || updated == 0 {
|
return &bhomeclient.Reply{Msg: "目标数据不存在或未更新"}
|
}
|
|
logger.Debug("更新es数据ret:", string(buf), " misreport:", updated, " reqBody:", reqBody)
|
return &bhomeclient.Reply{Success: true, Msg: "更新成功"}
|
}
|
|
// 确保 URL 以 http:// 或 https:// 开头
|
func ensureHTTPPrefix(url string) string {
|
if !strings.HasPrefix(url, "http://") && !strings.HasPrefix(url, "https://") {
|
url = "http://" + url
|
}
|
return url
|
}
|