Browse Source

海康威视接口对接

huangyan 1 tháng trước cách đây
mục cha
commit
09a8203378

+ 8 - 2
config/local.yml

@@ -40,7 +40,7 @@ hikvision:
   AppKey: "29491854"
   Secret: "Vd1q7pNabJ2u4VlQVeoL"
   IsHttps: true
-  pageSize: 9999
+  pageSize: 999
   api:
     nodesByParams: "/artemis/api/irds/v2/region/nodesByParams" #根据查询条件查询区域列表信息,主要用于区域信息查询过滤。相对V1接口,支持级联场景的区域查询
     deviceResource: "/artemis/api/irds/v2/deviceResource/resources" #根据资源类型分页获取资源列表,主要用于资源信息的全量同步。
@@ -49,7 +49,8 @@ hikvision:
     controlling: "/artemis/api/video/v1/ptzs/controlling" #根据监控点编号进行云台操作接口
     visitorInfo: "/artemis/api/v1/visitorInfo/count" #获取今日访客信息包含:今日来访总人数(已签离人数,未签离人数),预约人数
     doorSearch: "/artemis/api/resource/v2/door/search" #查询门禁点列表v2
-    doorStates: "/artemis/api/acs/v1/door/states" #查询门禁设备状态接口
+    doorStates: "/artemis/api/nms/v1/online/acs_device/get" #查询门禁设备状态接口
+    acsdoorstates: "/artemis/api/acs/v1/door/states" #门禁点状态查询
     eventLogs: "/artemis/api/scpms/v2/eventLogs/searches" #入侵报警事件日志查询
     regionsRoot: "/artemis/api/resource/v1/regions/root" #获取区域树接口
     regionsSubRegions: "/artemis/api/resource/v2/regions/subRegions" #根据区域编号获取下一级区域列表v2
@@ -61,6 +62,11 @@ hikvision:
     appointmentRecords: "/artemis/api/visitor/v2/appointment/records" #查询访客预约记录v2
     visitorTypeList: "/artemis/api/v1/visitorData/visitorTypeList" #查询全部访客类型
     turnoverSearch: "/artemis/api/visitor/v1/event/turnover/search" #查询访客出入事件
+    cameraSearch: "/artemis/api/resource/v2/camera/search" #获取监控点资源
+    acsDeviceSearch: "/artemis/api/resource/v2/acsDevice/search" #查询门禁设备列表v2
+    manualCapture: "/artemis/api/video/v1/manualCapture" #抓拍监控图片
+    doorDoControl: "/artemis/api/acs/v1/door/doControl" #门禁点反控
+
 
 #会议系统
 conference:

+ 228 - 185
internal/handler/hikvision.go

@@ -7,6 +7,7 @@ import (
 	"city_chips/pkg/helper/uuid"
 	"encoding/json"
 	"fmt"
+	"github.com/tidwall/gjson"
 	"math/rand"
 	"net/http"
 	"strconv"
@@ -14,7 +15,6 @@ import (
 
 	"github.com/gin-gonic/gin"
 	"github.com/spf13/viper"
-	"go.uber.org/zap"
 )
 
 type HikvisionHandler struct {
@@ -340,46 +340,44 @@ func (h *HikvisionHandler) GetAccess(ctx *gin.Context) {
 //		   "streamform": "ps"
 //		}
 func (h *HikvisionHandler) GetHikvisionMonitoring(ctx *gin.Context) {
-	m := make(map[string]string)
+	m := make(map[string]any)
 	cameraIndexCode := ctx.Query("cameraIndexCode")
+	control := ctx.Query("control")
 	m["cameraIndexCode"] = cameraIndexCode
 	m["protocol"] = "ws"
 	if len(cameraIndexCode) <= 0 || cameraIndexCode == "" {
 		resp.HandleError(ctx, 1203, "设备编码不能为空", nil)
 		return
 	}
+	hikvision, err := h.hikvisionService.Hikvision(h.conf.GetString("hikvision.api.previewURLs"), m, 15)
+	if err != nil {
+		h.logger.Error("获取获取监控点资源失败")
+		resp.HandleError(ctx, 1201, "获取获取监控点资源失败", err)
+		return
+	}
+	if hikvision.Code != "0" {
+		atoi, _ := strconv.Atoi(hikvision.Code)
+		resp.HandleError(ctx, atoi, hikvision.Msg, nil)
+		return
+	}
+	marshalString, err := json.Marshal(hikvision)
+	if err != nil {
+		resp.HandleError(ctx, 1202, "json序列化失败", nil)
+		return
+	}
+	var backquote bool
+	if control == "" {
+		backquote = true
+	} else {
+		backquote = false
+	}
+	url := gjson.Get(string(marshalString), "data.url")
 	ctx.HTML(http.StatusOK, "h5player.html", gin.H{
 		"title":           "测试",
-		"wsurl":           "ws://127.0.0.1/" + cameraIndexCode,
+		"wsurl":           url,
 		"cameraIndexCode": cameraIndexCode,
+		"control":         backquote,
 	})
-	//fmt.Println("cameraIndexCode", h.conf.GetString("hikvision.api.previewURLs"))
-	//hikvision, err := h.hikvisionService.Hikvision(h.conf.GetString("hikvision.api.previewURLs"), m, 15)
-	////返回结果{
-	////    "code": "0",
-	////    "msg": "success",
-	////    "data": {
-	////        "url": "rtsp://10.2.145.66:655/EUrl/CLJ52BW"
-	////    }
-	////}
-	//if err != nil {
-	//	h.logger.Error("获取获取监控点资源失败")
-	//	resp.HandleError(ctx, 1201, "获取获取监控点资源失败", err)
-	//	return
-	//}
-	//if hikvision.Code != "0" {
-	//	atoi, _ := strconv.Atoi(hikvision.Code)
-	//	resp.HandleError(ctx, atoi, hikvision.Msg, nil)
-	//	return
-	//}
-	//marshalString, err := json.Marshal(hikvision)
-	//if err != nil {
-	//	resp.HandleError(ctx, 1202, "json序列化失败", nil)
-	//	return
-	//}
-	//url := gjson.Get(string(marshalString), "data.url")
-	//
-	//resp.HandleSuccess(ctx, url)
 }
 
 // 视频监控云台控制{
@@ -393,7 +391,7 @@ func (h *HikvisionHandler) GetHikvisionMonitoring(ctx *gin.Context) {
 //}
 
 func (h *HikvisionHandler) Gimbalcontrol(ctx *gin.Context) {
-	m := make(map[string]string)
+	m := make(map[string]any)
 	cameraIndexCode := ctx.Query("cameraIndexCode")
 	command := ctx.Query("command")
 	action := ctx.Query("action")
@@ -427,7 +425,7 @@ func (h *HikvisionHandler) Gimbalcontrol(ctx *gin.Context) {
 
 // VisitorInfoCount 获取今日访客信息包含:今日来访总人数(已签离人数,未签离人数),预约人数
 func (h *HikvisionHandler) VisitorInfoCount(c *gin.Context) {
-	m := make(map[string]string)
+	m := make(map[string]any)
 	parkId := c.Query("parkId")
 	m["parkId"] = parkId
 	hikvision, err := h.hikvisionService.Hikvision(h.conf.GetString("hikvision.api.visitorInfo"), m, 15)
@@ -446,6 +444,58 @@ func (h *HikvisionHandler) VisitorInfoCount(c *gin.Context) {
 
 // GetDoorSearch 查询门禁点列表v2
 func (h *HikvisionHandler) GetDoorSearch(ctx *gin.Context) {
+	var Acs model.DoorSearch
+	var AcsDevice model.AcsDoorStates
+
+	name := ctx.Query("name")
+	pageNo := ctx.Query("pageNo")
+	pageSize := ctx.Query("pageSize")
+
+	err, result := h.hikvisionService.GetDoorSearch(pageNo, pageSize, name)
+	if err != nil {
+		h.logger.Error("获取门禁设备列表失败")
+		resp.HandleError(ctx, 1201, "获取门禁设备列表失败", err)
+		return
+	}
+
+	marshal, err := json.Marshal(result)
+	if err != nil {
+		h.logger.Error("json序列化失败")
+		resp.HandleError(ctx, 1202, "json序列化失败", nil)
+		return
+	}
+	err = json.Unmarshal(marshal, &Acs)
+	if err != nil {
+		h.logger.Error("json反序列化失败")
+		resp.HandleError(ctx, 1203, "json反序列化失败", nil)
+		return
+	}
+	for i, _ := range Acs.Data.List {
+		err, h2 := h.hikvisionService.GetAcsDoorStates([]string{Acs.Data.List[i].IndexCode})
+		if err != nil {
+			h.logger.Error("获取门禁设备在线状态失败")
+			resp.HandleError(ctx, 1201, "获取门禁设备在线状态失败", err)
+			return
+		}
+		bytes, err := json.Marshal(h2)
+		if err != nil {
+			h.logger.Error("json序列化失败")
+			resp.HandleError(ctx, 1202, "json序列化失败", nil)
+			return
+		}
+		err = json.Unmarshal(bytes, &AcsDevice)
+		if err != nil {
+			h.logger.Error("json反序列化失败")
+			resp.HandleError(ctx, 1203, "json反序列化失败", nil)
+			return
+		}
+		Acs.Data.List[i].State = AcsDevice.Data.AuthDoorList[0].DoorState
+	}
+	resp.HandleSuccess(ctx, Acs.Data)
+}
+
+// GetDoorStates 获取门禁设备在线状态
+func (h *HikvisionHandler) GetDoorStates(ctx *gin.Context) {
 	// 设置响应头
 	ctx.Header("Content-Type", "text/event-stream")
 	ctx.Header("Cache-Control", "no-cache")
@@ -455,11 +505,10 @@ func (h *HikvisionHandler) GetDoorSearch(ctx *gin.Context) {
 	notify := ctx.Writer.CloseNotify()
 
 	var response model.Response
-	//var doorlist []model.DoorList
-	//var doorResp model.DoorResp
-	m := make(map[string]string)
-	m["pageNo"] = "1"
-	m["pageSize"] = "1000"
+	var AcsDevice model.AcsDevice
+	indexCodes := ctx.Query("indexCodes")
+	pageNo := ctx.Query("pageNo")
+	pageSize := ctx.Query("pageSize")
 
 	for conn {
 		select {
@@ -468,100 +517,40 @@ func (h *HikvisionHandler) GetDoorSearch(ctx *gin.Context) {
 			fmt.Println("断开连接")
 			return
 		default:
-			doorSearch, err := h.hikvisionService.Hikvision(h.conf.GetString("hikvision.api.doorSearch"), m, 15)
+			err, h2 := h.hikvisionService.GetDoorStates(pageNo, pageSize, []string{indexCodes})
 			if err != nil {
-				h.logger.Error("获取门禁点列表失败")
+				h.logger.Error("获取门禁设备在线状态失败")
 				response.Code = 1203
-				response.Msg = "获取门禁点列表失败"
+				response.Msg = "获取门禁设备在线状态失败"
 				response.Data = nil
 				res, _ := json.Marshal(&response)
 				fmt.Fprintf(ctx.Writer, "data: %s\n\n", string(res))
 				ctx.Writer.Flush()
+				conn = false
 				return
 			}
-			if doorSearch.Code != "0" {
+			bytes, err := json.Marshal(h2)
+			if err != nil {
+				h.logger.Error("json序列化失败")
 				response.Code = 1203
-				response.Msg = "获取门禁点列表失败"
+				response.Msg = "json序列化失败"
+				response.Data = nil
+				res, _ := json.Marshal(&response)
+				fmt.Fprintf(ctx.Writer, "data: %s\n\n", string(res))
+			}
+			err = json.Unmarshal(bytes, &AcsDevice)
+			if err != nil {
+				h.logger.Error("json反序列化失败")
+				response.Code = 1203
+				response.Msg = "json反序列化失败"
 				response.Data = nil
 				res, _ := json.Marshal(&response)
 				fmt.Fprintf(ctx.Writer, "data: %s\n\n", string(res))
-				ctx.Writer.Flush()
 				conn = false
-				return
 			}
-			// 获取门禁状态
-			//doorIndexCodes := []string{""}
-			//for _, v := range doorResp.Data.List {
-			//	doorIndexCodes = append(doorIndexCodes, v.IndexCode)
-			//}
-			//data := map[string]string{
-			//	"doorIndexCodes": strings.Join(doorIndexCodes, ","),
-			//}
-			//doorStates, err := h.hikvisionService.Hikvision(h.conf.GetString("hikvision.api.doorStates"), data, 15)
-			//if err != nil {
-			//	h.logger.Error("获取门禁状态失败")
-			//	response.Code = 1203
-			//	response.Msg = "获取门禁状态失败"
-			//	response.Data = nil
-			//	res, _ := json.Marshal(&response)
-			//	fmt.Fprintf(ctx.Writer, "data: %s\n\n", string(res))
-			//	ctx.Writer.Flush()
-			//	conn = false
-			//	return
-			//}
-			//if doorStates.Code != "0" {
-			//	response.Code = 1203
-			//	response.Msg = "获取门禁状态失败"
-			//	response.Data = nil
-			//	res, _ := json.Marshal(&response)
-			//	fmt.Fprintf(ctx.Writer, "data: %s\n\n", string(res))
-			//	ctx.Writer.Flush()
-			//	conn = false
-			//	return
-			//}
-			//
-			//for i := 0; i < 3; i++ {
-			//	genUUID := uuid.GenUUID()
-			//	name := fmt.Sprintf("资源:%v", i+1)
-			//
-			//	list := model.DoorList{
-			//		IndexCode:       genUUID,
-			//		ResourceType:    "door",
-			//		Name:            name,
-			//		DoorNo:          genUUID,
-			//		ChannelNo:       genUUID,
-			//		ParentIndexCode: genUUID,
-			//		ControlOneId:    genUUID,
-			//		ControlTwoId:    genUUID,
-			//		ReaderInId:      genUUID,
-			//		ReaderOutId:     genUUID,
-			//		DoorSerial:      i + 1,
-			//		TreatyType:      genUUID,
-			//		RegionIndexCode: genUUID,
-			//		RegionPath:      genUUID,
-			//		CreateTime:      time.Now().Format("2006-01-02 15:04:05"),
-			//		UpdateTime:      time.Now().Format("2006-01-02 15:04:05"),
-			//		Description:     genUUID,
-			//		ChannelType:     genUUID,
-			//		RegionName:      genUUID,
-			//		RegionPathName:  genUUID,
-			//		InstallLocation: genUUID,
-			//	}
-			//	doorlist = append(doorlist, list)
-			//}
-			//doorResp := model.DoorResp{
-			//	Code: "0",
-			//	Msg:  "SUCCESS",
-			//	Data: struct {
-			//		Total    int              `json:"total"`
-			//		PageNo   int              `json:"pageNo"`
-			//		PageSize int              `json:"pageSize"`
-			//		List     []model.DoorList `json:"list"`
-			//	}{Total: 3, PageNo: 1, PageSize: 1, List: doorlist},
-			//}
 			response.Code = 200
 			response.Msg = "获取门禁点列表成功"
-			response.Data = doorSearch.Data
+			response.Data = AcsDevice.Data
 			res, _ := json.Marshal(&response)
 			fmt.Fprintf(ctx.Writer, "data: %s\n\n", string(res))
 			ctx.Writer.Flush()
@@ -572,13 +561,6 @@ func (h *HikvisionHandler) GetDoorSearch(ctx *gin.Context) {
 
 // DoControl 控制门禁
 func (h *HikvisionHandler) DoControl(ctx *gin.Context) {
-	// 设置响应头
-	ctx.Header("Content-Type", "text/event-stream")
-	ctx.Header("Cache-Control", "no-cache")
-	ctx.Header("Connection", "keep-alive")
-	// 监听客户端断开连接
-	conn := true
-	notify := ctx.Writer.CloseNotify()
 	doorIndexCodes := ctx.Query("doorIndexCodes")
 	controlType := ctx.Query("controlType")
 	if len(doorIndexCodes) <= 0 || len(controlType) <= 0 {
@@ -590,76 +572,43 @@ func (h *HikvisionHandler) DoControl(ctx *gin.Context) {
 	m["doorIndexCodes"] = doorIndexCodes
 	m["controlType"] = controlType
 	var response model.Response
-	for conn {
-		select {
-		case <-notify:
-			conn = false
-			fmt.Println("断开连接")
-			return
-		default:
-			//hikvision, err := h.hikvisionService.Hikvision(h.conf.GetString("hikvision.api.control"), m, 15)
-			//if err != nil {
-			//	h.logger.Error("控制门禁失败")
-			//	response.Code = 1203
-			//	response.Msg = "控制门禁失败"
-			//	response.Data = nil
-			//	res, _ := json.Marshal(&response)
-			//	fmt.Fprintf(ctx.Writer, "data: %s\n\n", string(res))
-			//	ctx.Writer.Flush()
-			//	conn = false
-			//	return
-			//}
-			//if hikvision.Code != "0" {
-			//	response.Code = 1203
-			//	response.Msg = "控制门禁失败"
-			//	response.Data = nil
-			//	res, _ := json.Marshal(&response)
-			//	fmt.Fprintf(ctx.Writer, "data: %s\n\n", string(res))
-			//	ctx.Writer.Flush()
-			//	conn = false
-			//	return
-			//}
-			genUUID := uuid.GenUUID()
-			doControl := model.DoControl{
-				Code: "0",
-				Msg:  "SUCCESS",
-				Data: []model.DoControlData{{
-					DoorIndexCode:     genUUID,
-					ControlResultCode: 0,
-					ControlResultDesc: "success",
-				}},
-			}
-			response.Code = 200
-			response.Msg = "控制门禁成功"
-			response.Data = doControl.Data
-			res, _ := json.Marshal(&response)
-			fmt.Fprintf(ctx.Writer, "data: %s\n\n", string(res))
-			ctx.Writer.Flush()
-			time.Sleep(10 * time.Second)
-		}
-	}
+
+	genUUID := uuid.GenUUID()
+	doControl := model.DoControl{
+		Code: "0",
+		Msg:  "SUCCESS",
+		Data: []model.DoControlData{{
+			DoorIndexCode:     genUUID,
+			ControlResultCode: 0,
+			ControlResultDesc: "success",
+		}},
+	}
+	response.Code = 200
+	response.Msg = "控制门禁成功"
+	response.Data = doControl.Data
+	res, _ := json.Marshal(&response)
+	fmt.Fprintf(ctx.Writer, "data: %s\n\n", string(res))
+	ctx.Writer.Flush()
+	time.Sleep(10 * time.Second)
 }
 
 // RealTimeInspection 入侵报警事件日志查询
 func (h *HikvisionHandler) RealTimeInspection(ctx *gin.Context) {
-	m := make(map[string]string)
-	m["startTime"] = ctx.Query("startTime") //开始时间
-	m["endTime"] = ctx.Query("endTime")     //结束时间
-	m["pageNo"] = ctx.Query("pageNo")
-	m["pageSize"] = h.conf.GetString("hikvision.pageSize")
+	pageNo := ctx.Query("pageNo")
+	pageSize := ctx.Query("pageSize")
+	srcType := ctx.Query("srcType")
+	startTime := ctx.Query("startTime")
+	endTime := ctx.Query("endTime")
+	srcName := ctx.Query("srcName")
+	eventType := ctx.Query("eventType")
+	eventTypeInt, _ := strconv.Atoi(eventType)
 	var eventLogs model.EventLogs
-	hikvision, err := h.hikvisionService.Hikvision(h.conf.GetString("hikvision.api.eventLogs"), m, 15)
+	err, result := h.hikvisionService.GetEventLogs(pageNo, pageSize, srcType, startTime, endTime, srcName, eventTypeInt)
 	if err != nil {
-		h.logger.Error("入侵报警事件日志查询失败", zap.Error(err))
-		resp.HandleError(ctx, 1203, "入侵报警事件日志查询失败", err)
-		return
-	}
-	if hikvision.Code != "0" {
-		h.logger.Error("入侵报警事件日志查询失败")
-		resp.HandleError(ctx, 1203, "入侵报警事件日志查询失败", hikvision.Code)
+		resp.HandleError(ctx, 1203, "获取入侵报警事件日志查询失败", err)
 		return
 	}
-	marshal, err := json.Marshal(hikvision)
+	marshal, err := json.Marshal(result)
 	if err != nil {
 		h.logger.Error("json序列化失败")
 		resp.HandleError(ctx, 1203, "json序列化失败", err)
@@ -673,6 +622,100 @@ func (h *HikvisionHandler) RealTimeInspection(ctx *gin.Context) {
 	}
 	for i, _ := range eventLogs.Data.List {
 		eventLogs.Data.List[i].SrcType = model.ResourceType[eventLogs.Data.List[i].SrcType]
+		//eventLogs.Data.List[i].EventType = model.IntrusionAlarmEventType[eventLogs.Data.List[i].EventType]
+	}
+	resp.HandleSuccess(ctx, eventLogs.Data)
+}
+
+// GetCameraSearch 获取摄像头查询
+func (h *HikvisionHandler) GetCameraSearch(ctx *gin.Context) {
+	pageNo := ctx.Query("pageNo")
+	pageSize := ctx.Query("pageSize")
+	name := ctx.Query("name")
+	err, search := h.hikvisionService.GetcameraSearch(pageNo, pageSize, name)
+	if err != nil {
+		resp.HandleError(ctx, 1203, "获取摄像头查询失败", err)
+		return
+	}
+	var cameraSearch model.CameraSearch
+	marshal, err := json.Marshal(search)
+	if err != nil {
+		h.logger.Error("json序列化失败")
+		resp.HandleError(ctx, 1203, "json序列化失败", err)
+		return
+	}
+	err = json.Unmarshal(marshal, &cameraSearch)
+	if err != nil {
+		h.logger.Error("json反序列化失败")
+		resp.HandleError(ctx, 1203, "json反序列化失败", err)
+		return
+	}
+	for i, _ := range cameraSearch.Data.List {
+		err, result := h.hikvisionService.GetManualCapture(cameraSearch.Data.List[i].IndexCode)
+		if err != nil {
+			cameraSearch.Data.List[i].Url = ""
+		} else {
+			var manualCapture model.ManualCapture
+			marshal, err := json.Marshal(result)
+			if err != nil {
+				h.logger.Error("json序列化失败")
+				resp.HandleError(ctx, 1203, "json序列化失败", err)
+				return
+			}
+			err = json.Unmarshal(marshal, &manualCapture)
+			if err != nil {
+				h.logger.Error("json反序列化失败")
+				resp.HandleError(ctx, 1203, "json反序列化失败", err)
+				return
+			}
+			cameraSearch.Data.List[i].Url = manualCapture.Data.PicUrl
+		}
+	}
+	resp.HandleSuccess(ctx, cameraSearch.Data)
+}
+
+// GetCameraList 获取监控点资源
+func (h *HikvisionHandler) GetCameraList(ctx *gin.Context) {
+	pageNo := ctx.Query("pageNo")
+	pageSize := ctx.Query("pageSize")
+	err, search := h.hikvisionService.GetCamerasList(pageNo, pageSize)
+	if err != nil {
+		resp.HandleError(ctx, 1203, "获取监控点资源失败", err)
+		return
+	}
+	resp.HandleSuccess(ctx, search.Data)
+}
+
+// GetAcsDeviceSearch 获取门禁设备查询
+func (h *HikvisionHandler) GetAcsDeviceSearch(ctx *gin.Context) {
+	pageNo := ctx.Query("pageNo")
+	pageSize := ctx.Query("pageSize")
+	name := ctx.Query("name")
+	err, search := h.hikvisionService.GetAcsDeviceSearch(pageNo, pageSize, name)
+	if err != nil {
+		resp.HandleError(ctx, 1203, "获取门禁设备列表失败", err)
+		return
+	}
+	resp.HandleSuccess(ctx, search.Data)
+}
+
+// GetDoorDoControl 控制门禁点
+func (h *HikvisionHandler) GetDoorDoControl(ctx *gin.Context) {
+	doorIndexCodes := ctx.QueryArray("doorIndexCodes")
+	controlType := ctx.Query("controlType")
+	atoi, err2 := strconv.Atoi(controlType)
+	if err2 != nil {
+		resp.HandleError(ctx, 1203, "参数错误", err2)
+		return
+	}
+	if len(doorIndexCodes) <= 0 || len(doorIndexCodes) > 10 {
+		resp.HandleError(ctx, 1203, "参数错误", nil)
+		return
+	}
+	err, search := h.hikvisionService.GetDoorDoControl(doorIndexCodes, atoi)
+	if err != nil {
+		resp.HandleError(ctx, 1203, "控制门禁失败", err.Error())
+		return
 	}
-	resp.HandleSuccess(ctx, hikvision.Data)
+	resp.HandleSuccess(ctx, search.Data)
 }

+ 146 - 36
internal/handler/intelligentbuildingcontrol.go

@@ -3,12 +3,14 @@ package handler
 import (
 	"city_chips/internal/model"
 	"city_chips/internal/service"
+	"city_chips/pkg/helper/obix"
 	"city_chips/pkg/helper/resp"
+	"encoding/json"
 	"fmt"
 	"go.uber.org/zap"
-	"io"
 	"math/rand"
-	"net/http"
+	"regexp"
+	"sync"
 	"time"
 
 	"github.com/spf13/viper"
@@ -67,7 +69,6 @@ func (h *IntelligentBuildingControlHandler) GetIntelligentBuildingControl(ctx *g
 	resp.HandleSuccess(ctx, m)
 }
 
-// GetPoint 获取点位数据
 func (h *IntelligentBuildingControlHandler) GetPoint(ctx *gin.Context) {
 	pointName := ctx.PostForm("pointName")
 	deviceType := ctx.PostForm("deviceType")
@@ -76,6 +77,7 @@ func (h *IntelligentBuildingControlHandler) GetPoint(ctx *gin.Context) {
 	section := ctx.PostForm("section")
 	device_name := ctx.PostForm("deviceName")
 	conds := make(map[string]any)
+	var pointType []model.PointType
 	if pointName != "" {
 		conds["point_name"] = pointName
 	}
@@ -94,55 +96,157 @@ func (h *IntelligentBuildingControlHandler) GetPoint(ctx *gin.Context) {
 	if device_name != "" {
 		conds["device_name"] = device_name
 	}
+
 	baseUrl := h.conf.GetString("obix.baseUrl")
 	points, err := h.intelligentBuildingControlService.GetPoint(conds)
 	if err != nil {
 		resp.HandleError(ctx, 1201, "查询点位失败", nil)
 		return
 	}
-	type result struct {
-		Body string
-		Err  error
-	}
-	resultChan := make(chan result, len(*points))
-	ctxReq := ctx.Request.Context()
-	//设置最大并发数
-	sem := make(chan struct{}, 10)
+
+	var wg sync.WaitGroup
+	var mutex sync.Mutex // 保护切片并发写入
+	m := make(map[string]string)
+	sem := make(chan struct{}, 10) // 最大并发数为10
+
 	for _, v := range *points {
 		url := baseUrl + v.FullPath
+		wg.Add(1)
 		sem <- struct{}{}
-		go func(url string) {
-			defer func() { <-sem }()
-			req, err := http.NewRequestWithContext(ctxReq, "GET", url, nil)
-			get, err := http.DefaultClient.Do(req)
+		go func(url string, pointName string) {
+			defer func() {
+				<-sem
+				wg.Done()
+			}()
+
+			request, err := obix.SendSecureRequest(url, h.conf.GetString("obix.username"), h.conf.GetString("obix.password"))
 			if err != nil {
-				resultChan <- result{Err: err}
+				h.logger.Error("发送请求失败", zap.Error(err))
 				return
 			}
-			defer get.Body.Close()
-			body, err := io.ReadAll(get.Body)
+
+			re := regexp.MustCompile(`val="([^"]+)"`)
+			matches := re.FindStringSubmatch(request)
+
+			mutex.Lock()
+			defer mutex.Unlock()
+
+			if len(matches) > 1 {
+				s := model.PointName[pointName]
+				m[s] = matches[1]
+				pointType = append(pointType, model.PointType{Type: m})
+			} else {
+				h.logger.Warn("未找到 val 值", zap.String("url", url))
+			}
+		}(url, v.PointName)
+	}
+
+	// 等待所有协程完成
+	wg.Wait()
+
+	// 统一返回结果
+	resp.HandleSuccess(ctx, pointType)
+}
+func (h *IntelligentBuildingControlHandler) GetGetPointSSE(ctx *gin.Context) {
+	// 设置响应头
+	ctx.Header("Content-Type", "text/event-stream")
+	ctx.Header("Cache-Control", "no-cache")
+	ctx.Header("Connection", "keep-alive")
+	// 监听客户端断开连接
+	conn := true
+	notify := ctx.Writer.CloseNotify()
+	type Response struct {
+		RequestId string `protobuf:"bytes,1,opt,name=requestId,proto3" json:"requestId,omitempty"`
+		Code      int32  `protobuf:"varint,2,opt,name=code,proto3" json:"code,omitempty"`
+		Msg       string `protobuf:"bytes,3,opt,name=msg,proto3" json:"msg,omitempty"`
+		Data      any    `json:"data"`
+	}
+	pointName := ctx.Query("pointName")
+	deviceType := ctx.Query("deviceType")
+	building := ctx.Query("building")
+	floor := ctx.Query("floor")
+	section := ctx.Query("section")
+	device_name := ctx.Query("deviceName")
+	conds := make(map[string]any)
+	if pointName != "" {
+		conds["point_name"] = pointName
+	}
+	if deviceType != "" {
+		conds["device_type"] = deviceType
+	}
+	if building != "" {
+		conds["building"] = building
+	}
+	if floor != "" {
+		conds["floor"] = floor
+	}
+	if section != "" {
+		conds["section"] = section
+	}
+	if device_name != "" {
+		conds["device_name"] = device_name
+	}
+
+	baseUrl := h.conf.GetString("obix.baseUrl")
+
+	var response Response
+	for conn {
+		select {
+		case <-notify:
+			conn = false
+			fmt.Println("断开连接")
+			return
+		default:
+			m := make(map[string]any)
+			points, err := h.intelligentBuildingControlService.GetPoint(conds)
 			if err != nil {
-				resultChan <- result{Err: err}
-				return
+				resp.HandleError(ctx, 1201, "查询点位失败", nil)
+				conn = false
 			}
-			fmt.Println(string(body))
-			resultChan <- result{Body: string(body)}
-		}(url)
-	}
-	// 等待所有 goroutine 完成
-	go func() {
-		// 等待所有结果
-		for i := 0; i < cap(resultChan); i++ {
-			r := <-resultChan
-			if r.Err != nil {
-				h.logger.Error("获取设备数据失败", zap.Error(r.Err))
-				continue
+			for _, v := range *points {
+				url := baseUrl + v.FullPath
+				request, err := obix.SendSecureRequest(url, h.conf.GetString("obix.username"), h.conf.GetString("obix.password"))
+				if err != nil {
+					h.logger.Error("发送请求失败", zap.Error(err))
+					conn = false
+					return
+				}
+				re := regexp.MustCompile(`val="([^"]+)"`)
+				matches := re.FindStringSubmatch(request)
+				if len(matches) > 1 {
+					s := model.PointName[v.PointName]
+					if s != "" {
+						value := matches[1]
+						switch val := obix.DetectType(value).(type) {
+						case int:
+							m[s] = val
+						case float64:
+							m[s] = fmt.Sprintf("%.2f", val) // 保留两位小数输出
+						case bool:
+							if val {
+								m[s] = "是"
+							} else {
+								m[s] = "否"
+							}
+						default:
+							m[s] = value // 原样输出字符串
+						}
+					}
+				} else {
+					h.logger.Warn("未找到 val 值", zap.String("url", url))
+					conn = false
+				}
 			}
-			//可以处理各个设备响应的数据并且处理
-			fmt.Println(r.Body)
+			response.Code = 200
+			response.RequestId = ctx.ClientIP()
+			response.Msg = "success"
+			response.Data = m
+			res, _ := json.Marshal(&response)
+			fmt.Fprintf(ctx.Writer, "data: %s\n\n", string(res))
+			ctx.Writer.Flush()
+			time.Sleep(10 * time.Second)
 		}
-	}()
-	resp.HandleSuccess(ctx, points)
+	}
 }
 
 // GetPointType 获取点位类型
@@ -161,6 +265,12 @@ func (h *IntelligentBuildingControlHandler) GetPointType(ctx *gin.Context) {
 	//	resp.HandleError(ctx, 1201, "绑定XML失败", nil)
 	//	return
 	//}
+	request, err2 := obix.SendSecureRequest("https://10.1.201.253/obix/config/Drivers/BacnetNetwork/DDC_9B_1F_1a/points/PAU/PAU_9B_1F_1/PAUAlr1", h.conf.GetString("obix.username"), h.conf.GetString("obix.password"))
+	if err2 != nil {
+		resp.HandleError(ctx, 1201, "发送请求失败", nil)
+		return
+	}
+	fmt.Println(request, "===========")
 	fmt.Println(tempS1)
 	points, err := h.intelligentBuildingControlService.GetPointType()
 	if err != nil {

+ 218 - 0
internal/model/hikvision.go

@@ -474,6 +474,214 @@ type TurnoverSearch struct {
 	} `json:"data"`
 }
 
+type CamerasList struct {
+	Code string `json:"code"`
+	Msg  string `json:"msg"`
+	Data struct {
+		Total    int `json:"total"`
+		PageNo   int `json:"pageNo"`
+		PageSize int `json:"pageSize"`
+		List     []struct {
+			Altitude                  string `json:"altitude"`
+			CameraIndexCode           string `json:"cameraIndexCode"`
+			CameraName                string `json:"cameraName"`
+			CameraType                int    `json:"cameraType"`
+			CameraTypeName            string `json:"cameraTypeName"`
+			CapabilitySet             string `json:"capabilitySet"`
+			CapabilitySetName         string `json:"capabilitySetName"`
+			IntelligentSet            string `json:"intelligentSet"`
+			IntelligentSetName        string `json:"intelligentSetName"`
+			ChannelNo                 string `json:"channelNo"`
+			ChannelType               string `json:"channelType"`
+			ChannelTypeName           string `json:"channelTypeName"`
+			CreateTime                string `json:"createTime"`
+			EncodeDevIndexCode        string `json:"encodeDevIndexCode"`
+			EncodeDevResourceType     string `json:"encodeDevResourceType"`
+			EncodeDevResourceTypeName string `json:"encodeDevResourceTypeName"`
+			GbIndexCode               string `json:"gbIndexCode"`
+			InstallLocation           string `json:"installLocation"`
+			KeyBoardCode              string `json:"keyBoardCode"`
+			Latitude                  string `json:"latitude"`
+			Longitude                 string `json:"longitude"`
+			Pixel                     int    `json:"pixel"`
+			Ptz                       int    `json:"ptz"`
+			PtzController             int    `json:"ptzController"`
+			PtzControllerName         string `json:"ptzControllerName"`
+			PtzName                   string `json:"ptzName"`
+			RecordLocation            string `json:"recordLocation"`
+			RecordLocationName        string `json:"recordLocationName"`
+			RegionIndexCode           string `json:"regionIndexCode"`
+			Status                    int    `json:"status"`
+			StatusName                string `json:"statusName"`
+			TransType                 int    `json:"transType"`
+			TransTypeName             string `json:"transTypeName"`
+			TreatyType                string `json:"treatyType"`
+			TreatyTypeName            string `json:"treatyTypeName"`
+			Viewshed                  string `json:"viewshed"`
+			UpdateTime                string `json:"updateTime"`
+		} `json:"list"`
+	} `json:"data"`
+}
+type CameraSearch struct {
+	Code string `json:"code"`
+	Msg  string `json:"msg"`
+	Data struct {
+		Total    int `json:"total"`
+		PageNo   int `json:"pageNo"`
+		PageSize int `json:"pageSize"`
+		List     []struct {
+			IndexCode         string `json:"indexCode"`
+			AddressDesc       string `json:"addressDesc"`
+			ResourceType      string `json:"resourceType"`
+			InstallLocation   string `json:"installLocation"`
+			Latitude          string `json:"latitude"`
+			Longitude         string `json:"longitude"`
+			ExternalIndexCode string `json:"externalIndexCode"`
+			Name              string `json:"name"`
+			ChanNum           int    `json:"chanNum"`
+			CascadeCode       string `json:"cascadeCode"`
+			ParentIndexCode   string `json:"parentIndexCode"`
+			Elevation         string `json:"elevation"`
+			CameraType        int    `json:"cameraType"`
+			Capability        string `json:"capability"`
+			RecordLocation    string `json:"recordLocation"`
+			ChannelType       string `json:"channelType"`
+			RegionIndexCode   string `json:"regionIndexCode"`
+			RegionPath        string `json:"regionPath"`
+			TransType         int    `json:"transType"`
+			TreatyType        string `json:"treatyType"`
+			CreateTime        string `json:"createTime"`
+			UpdateTime        string `json:"updateTime"`
+			DisOrder          int    `json:"disOrder"`
+			ResourceIndexCode string `json:"resourceIndexCode"`
+			DecodeTag         string `json:"decodeTag"`
+			CameraRelateTalk  string `json:"cameraRelateTalk"`
+			RegionName        string `json:"regionName"`
+			RegionPathName    string `json:"regionPathName"`
+			Url               string `json:"url"`
+		} `json:"list"`
+	} `json:"data"`
+}
+type ManualCapture struct {
+	Code string `json:"code"`
+	Msg  string `json:"msg"`
+	Data struct {
+		PicUrl string `json:"picUrl"`
+	} `json:"data"`
+}
+type AcsDeviceSearch struct {
+	Code string `json:"code"`
+	Msg  string `json:"msg"`
+	Data struct {
+		Total    int `json:"total"`
+		PageNo   int `json:"pageNo"`
+		PageSize int `json:"pageSize"`
+		List     []struct {
+			IndexCode                  string `json:"indexCode"`
+			ResourceType               string `json:"resourceType"`
+			Name                       string `json:"name"`
+			ParentIndexCode            string `json:"parentIndexCode"`
+			DevTypeCode                string `json:"devTypeCode"`
+			DevTypeDesc                string `json:"devTypeDesc"`
+			DeviceCode                 string `json:"deviceCode"`
+			Manufacturer               string `json:"manufacturer"`
+			RegionIndexCode            string `json:"regionIndexCode"`
+			RegionPath                 string `json:"regionPath"`
+			TreatyType                 string `json:"treatyType"`
+			CardCapacity               int    `json:"cardCapacity"`
+			FingerCapacity             int    `json:"fingerCapacity"`
+			VeinCapacity               int    `json:"veinCapacity"`
+			FaceCapacity               int    `json:"faceCapacity"`
+			DoorCapacity               int    `json:"doorCapacity"`
+			DeployId                   string `json:"deployId"`
+			NetZoneId                  string `json:"netZoneId"`
+			CreateTime                 string `json:"createTime"`
+			UpdateTime                 string `json:"updateTime"`
+			Description                string `json:"description"`
+			AcsReaderVerifyModeAbility string `json:"acsReaderVerifyModeAbility"`
+			RegionName                 string `json:"regionName"`
+			RegionPathName             string `json:"regionPathName"`
+			Ip                         string `json:"ip"`
+			Port                       string `json:"port"`
+			Capability                 string `json:"capability"`
+			DevSerialNum               string `json:"devSerialNum"`
+			DataVersion                string `json:"dataVersion"`
+			State                      int    `json:"state"`
+		} `json:"list"`
+	} `json:"data"`
+}
+
+type AcsDevice struct {
+	Code string `json:"code"`
+	Msg  string `json:"msg"`
+	Data struct {
+		PageNo    int `json:"pageNo"`
+		PageSize  int `json:"pageSize"`
+		TotalPage int `json:"totalPage"`
+		Total     int `json:"total"`
+		List      []struct {
+			DeviceType      string    `json:"deviceType"`
+			DeviceIndexCode string    `json:"deviceIndexCode"`
+			RegionIndexCode string    `json:"regionIndexCode"`
+			CollectTime     time.Time `json:"collectTime"`
+			RegionName      string    `json:"regionName"`
+			IndexCode       string    `json:"indexCode"`
+			Cn              string    `json:"cn"`
+			TreatyType      string    `json:"treatyType"`
+			Manufacturer    string    `json:"manufacturer"`
+			Ip              string    `json:"ip"`
+			Port            int       `json:"port"`
+			Online          int       `json:"online"`
+		} `json:"list"`
+	} `json:"data"`
+}
+
+// AcsDoorStates 门禁点状态
+type AcsDoorStates struct {
+	Code string `json:"code"`
+	Msg  string `json:"msg"`
+	Data struct {
+		AuthDoorList []struct {
+			DoorIndexCode string `json:"doorIndexCode"`
+			DoorState     int    `json:"doorState"`
+		} `json:"authDoorList"`
+		NoAuthDoorIndexCodeList []string `json:"noAuthDoorIndexCodeList"`
+	} `json:"data"`
+}
+type DoorSearch struct {
+	Code string `json:"code"`
+	Msg  string `json:"msg"`
+	Data struct {
+		Total    int `json:"total"`
+		PageNo   int `json:"pageNo"`
+		PageSize int `json:"pageSize"`
+		List     []struct {
+			IndexCode       string `json:"indexCode"`
+			ResourceType    string `json:"resourceType"`
+			Name            string `json:"name"`
+			DoorNo          string `json:"doorNo"`
+			ChannelNo       string `json:"channelNo"`
+			ParentIndexCode string `json:"parentIndexCode"`
+			ControlOneId    string `json:"controlOneId"`
+			ControlTwoId    string `json:"controlTwoId"`
+			ReaderInId      string `json:"readerInId"`
+			ReaderOutId     string `json:"readerOutId"`
+			DoorSerial      int    `json:"doorSerial"`
+			TreatyType      string `json:"treatyType"`
+			RegionIndexCode string `json:"regionIndexCode"`
+			RegionPath      string `json:"regionPath"`
+			CreateTime      string `json:"createTime"`
+			UpdateTime      string `json:"updateTime"`
+			Description     string `json:"description"`
+			ChannelType     string `json:"channelType"`
+			RegionName      string `json:"regionName"`
+			RegionPathName  string `json:"regionPathName"`
+			InstallLocation string `json:"installLocation"`
+			State           int    `json:"state"`
+		} `json:"list"`
+	} `json:"data"`
+}
+
 var ResourceType = map[string]string{
 	"region":                "区域",
 	"acsDevice":             "门禁控制器",
@@ -517,6 +725,16 @@ var ResourceType = map[string]string{
 	"alarmLamp":             "警灯",
 	"siren":                 "警号",
 }
+var IntrusionAlarmEventType = map[int]string{
+	327937: "布防",
+	327938: "撤防",
+	327941: "消警",
+	327939: "防区",
+	327940: "旁路恢复",
+	327681: "报警",
+	327946: "防区布防",
+	327947: "防区撤防",
+}
 
 func (m *Hikvision) TableName() string {
 	return "hikvision"

+ 47 - 1
internal/model/intelligentbuildingcontrol.go

@@ -1,6 +1,9 @@
 package model
 
-import "gorm.io/gorm"
+import (
+	"encoding/xml"
+	"gorm.io/gorm"
+)
 
 type IntelligentBuildingControl struct {
 	gorm.Model
@@ -30,6 +33,49 @@ var DeviceType = map[string]string{
 	"EAF": "送排风机",
 }
 
+type PointType struct {
+	Type map[string]string `json:"type"`
+}
+
+// PointName 设备名称对应表
+var PointName = map[string]string{
+	"TempS1":   "送风温度",   //
+	"HumS1":    "送风湿度",   //
+	"TempH1":   "回风温度",   //
+	"TempX1":   "新风温度",   //
+	"CO2":      "回风二氧化碳", //
+	"AHUSts1":  "运行状态",   //
+	"AHUAlr1":  "故障报警",   //
+	"AHUAorm1": "自动状态",   //
+	"FJDPS1":   "风机压差",   //
+	"FDKG1":    "防冻开关",   //
+	"Sorw1":    "冬夏季模式",  //
+	"XFLev1":   "新风阀反馈",  //
+	"HFLev1":   "回风阀反馈",  //
+	"SFLev1":   "水阀反馈",
+	"GlwDPS1":  "过滤网压差", //
+}
+
+// RealPoint TempS1 点位表
+type RealPoint struct {
+	XMLName xml.Name `xml:"real"`
+	Val     string   `xml:"val,attr"`     // "28.355751037597656"
+	Status  string   `xml:"status,attr"`  // "down"
+	Display string   `xml:"display,attr"` // "28.36 °C {down}"
+	Href    string   `xml:"href,attr"`
+	Unit    string   `xml:"unit,attr"` // "obix:units/celsius"
+}
+
+// PointType 设备类型表
+type BooleanPoint struct {
+	XMLName xml.Name `xml:"bool"`
+	Val     string   `xml:"val,attr"`
+	Status  string   `xml:"status,attr"`
+	Display string   `xml:"display,attr"`
+	Href    string   `xml:"href,attr"`
+	Is      string   `xml:"is,attr"`
+}
+
 // NumericPoint TempS1
 type NumericPoint struct {
 	Val      float64       `xml:"val,attr"`

+ 6 - 0
internal/server/http.go

@@ -55,6 +55,11 @@ func NewServerHTTP(
 		Hikvision.GET("/doControl", hikvision.DoControl)
 		Hikvision.GET("/eventLogs", hikvision.RealTimeInspection)
 		Hikvision.GET("/getPatrolPoint", hikvision.GetPatrolPoint)
+		Hikvision.GET("/getCameraSearch", hikvision.GetCameraSearch)
+		Hikvision.GET("/getCameraList", hikvision.GetCameraList)
+		Hikvision.GET("/getAcsDeviceSearch", hikvision.GetAcsDeviceSearch)
+		Hikvision.GET("/getDoorStates", hikvision.GetDoorStates)
+		Hikvision.GET("/getDoorDoControl", hikvision.GetDoorDoControl)
 	}
 	//会议系统
 	Conference := r.Group("/Conference")
@@ -114,6 +119,7 @@ func NewServerHTTP(
 	{
 		inte.GET("/count", intell.GetIntelligentBuildingControl)
 		inte.POST("/point", intell.GetPoint)
+		inte.GET("/pointSSE", intell.GetGetPointSSE)
 		inte.GET("/pointType", intell.GetPointType)
 		inte.GET("/deviceType", intell.GetDeviceType)
 	}

+ 231 - 13
internal/service/hikvision.go

@@ -3,16 +3,17 @@ package service
 import (
 	"city_chips/internal/model"
 	"city_chips/internal/repository"
+	"city_chips/pkg/helper/hikvisionOpenAPIGo"
 	"encoding/json"
 	"errors"
 	"strings"
 
 	"github.com/spf13/viper"
-	"github.com/zxbit2011/hikvisionOpenAPIGo"
+	//"github.com/zxbit2011/hikvisionOpenAPIGo"
 )
 
 type HikvisionService interface {
-	Hikvision(url string, body map[string]string, timeout int) (hikvisionOpenAPIGo.Result, error)
+	Hikvision(url string, body map[string]any, timeout int) (hikvisionOpenAPIGo.Result, error)
 	DeviceResource(Device string) (error, model.DeviceResource)
 	GetRegionsRoot() (error, model.RegionsRoot)
 	GetRegionsSubRegions(pageNo, pageSize string) (error, model.RegionsSubRegions)
@@ -25,6 +26,14 @@ type HikvisionService interface {
 	GetAppointmentRecords(receptionistId, visitorName, phoneNo, pageNo, pageSize string) (error, model.VisitorTypeInfo)
 	GetVisitorTypeList() (error, model.VisitorTypeList)
 	GetTurnoverSearch(pageNo, pageSize string) (error, model.TurnoverSearch)
+	GetcameraSearch(pageNo, pageSize, name string) (error, hikvisionOpenAPIGo.Result)
+	GetDoorSearch(pageNo, pageSize, name string) (error, hikvisionOpenAPIGo.Result)
+	GetDoorStates(pageNo, pageSize string, indexCodes []string) (error, hikvisionOpenAPIGo.Result)
+	GetAcsDeviceSearch(pageNo, pageSize, name string) (error, hikvisionOpenAPIGo.Result)
+	GetManualCapture(cameraIndexCode string) (error, hikvisionOpenAPIGo.Result)
+	GetAcsDoorStates(indexCodes []string) (error, hikvisionOpenAPIGo.Result)
+	GetDoorDoControl(doorIndexCodes []string, controlType int) (error, hikvisionOpenAPIGo.Result)
+	GetEventLogs(pageNo, pageSize, srcType, startTime, endTime, srcName string, eventType int) (error, hikvisionOpenAPIGo.Result)
 }
 
 func NewHikvisionService(service *Service, hikvisionRepository repository.HikvisionRepository, conf *viper.Viper) HikvisionService {
@@ -42,7 +51,7 @@ type hikvisionService struct {
 }
 
 // Hikvision 海康威视对接
-func (s *hikvisionService) Hikvision(url string, body map[string]string, timeout int) (hikvisionOpenAPIGo.Result, error) {
+func (s *hikvisionService) Hikvision(url string, body map[string]any, timeout int) (hikvisionOpenAPIGo.Result, error) {
 	config := hikvisionOpenAPIGo.HKConfig{
 		Ip:      s.conf.GetString("hikvision.Ip"),
 		Port:    s.conf.GetInt("hikvision.Port"),
@@ -57,7 +66,7 @@ func (s *hikvisionService) Hikvision(url string, body map[string]string, timeout
 // DeviceResource 根据设备类型获取设备资源
 func (s *hikvisionService) DeviceResource(Device string) (error, model.DeviceResource) {
 	var deviceResource model.DeviceResource
-	m := make(map[string]string)
+	m := make(map[string]any)
 	m["pageNo"] = "1"
 	m["pageSize"] = s.conf.GetString("hikvision.pageSize")
 	m["resourceType"] = Device
@@ -103,7 +112,7 @@ func (s *hikvisionService) GetRegionsRoot() (error, model.RegionsRoot) {
 // GetRegionsSubRegions 获取子目录资源信息
 func (s *hikvisionService) GetRegionsSubRegions(pageNo, pageSize string) (error, model.RegionsSubRegions) {
 	var regionsSubRegions model.RegionsSubRegions
-	m := make(map[string]string)
+	m := make(map[string]any)
 	if pageNo != "" {
 		m["pageNo"] = pageNo
 	} else {
@@ -140,7 +149,7 @@ func (s *hikvisionService) GetRegionsSubRegions(pageNo, pageSize string) (error,
 func (s *hikvisionService) GetVqdByIndexCodes(pageNo, pageSize string, indexCodes []string) (error, model.VqdList) {
 	var vqdlist model.VqdList
 	// 获取门禁状态
-	m := make(map[string]string)
+	m := make(map[string]any)
 	if pageNo != "" {
 		m["pageNo"] = pageNo
 	} else {
@@ -180,7 +189,7 @@ func (s *hikvisionService) GetVqdByIndexCodes(pageNo, pageSize string, indexCode
 func (s *hikvisionService) GetCameraOnline(regionId, includeSubNode, status, pageNo, pageSize string, indexCodes []string) (error, model.CameraOnline) {
 	var cameraOnline model.CameraOnline
 	// 获取门禁状态
-	m := make(map[string]string)
+	m := make(map[string]any)
 	if pageNo != "" {
 		m["pageNo"] = pageNo
 	} else {
@@ -232,7 +241,7 @@ func (s *hikvisionService) GetCameraOnline(regionId, includeSubNode, status, pag
 func (s *hikvisionService) GetRecordList(beginTime, endTime, pageNo, pageSize string, indexCodes []string) (error, model.RecordList) {
 	var recordList model.RecordList
 	// 获取门禁状态
-	m := make(map[string]string)
+	m := make(map[string]any)
 	if pageNo != "" {
 		m["pageNo"] = pageNo
 	} else {
@@ -271,7 +280,7 @@ func (s *hikvisionService) GetRecordList(beginTime, endTime, pageNo, pageSize st
 func (s *hikvisionService) GetCamerasList(pageNo, pageSize string) (error, model.Cameras) {
 	var cameras model.Cameras
 	// 获取门禁状态
-	m := make(map[string]string)
+	m := make(map[string]any)
 	if pageNo != "" {
 		m["pageNo"] = pageNo
 	} else {
@@ -307,7 +316,7 @@ func (s *hikvisionService) GetCamerasList(pageNo, pageSize string) (error, model
 func (s *hikvisionService) GetVisitingRecords(receptionistId, receptionistName, visitorName, pageNo, pageSize string) (error, model.VisitingRecords) {
 	var visitingRecords model.VisitingRecords
 	// 获取门禁状态
-	m := make(map[string]string)
+	m := make(map[string]any)
 	if pageNo != "" {
 		m["pageNo"] = pageNo
 	} else {
@@ -349,7 +358,7 @@ func (s *hikvisionService) GetVisitingRecords(receptionistId, receptionistName,
 func (s *hikvisionService) GetVisitorTypeInfo(pageNo, pageSize string) (error, model.VisitorTypeInfo) {
 	var visitorTypeInfo model.VisitorTypeInfo
 	// 获取门禁状态
-	m := make(map[string]string)
+	m := make(map[string]any)
 	if pageNo != "" {
 		m["pageNo"] = pageNo
 	} else {
@@ -385,7 +394,7 @@ func (s *hikvisionService) GetVisitorTypeInfo(pageNo, pageSize string) (error, m
 func (s *hikvisionService) GetAppointmentRecords(receptionistId, visitorName, phoneNo, pageNo, pageSize string) (error, model.VisitorTypeInfo) {
 	var visitorTypeInfo model.VisitorTypeInfo
 	// 获取门禁状态
-	m := make(map[string]string)
+	m := make(map[string]any)
 	if pageNo != "" {
 		m["pageNo"] = pageNo
 	} else {
@@ -448,7 +457,7 @@ func (s *hikvisionService) GetVisitorTypeList() (error, model.VisitorTypeList) {
 // GetTurnoverSearch 查询访客出入事件
 func (s *hikvisionService) GetTurnoverSearch(pageNo, pageSize string) (error, model.TurnoverSearch) {
 	var turnoverSearch model.TurnoverSearch
-	m := make(map[string]string)
+	m := make(map[string]any)
 	if pageNo != "" {
 		m["pageNo"] = pageNo
 	} else {
@@ -477,3 +486,212 @@ func (s *hikvisionService) GetTurnoverSearch(pageNo, pageSize string) (error, mo
 	}
 	return nil, turnoverSearch
 }
+
+// GetCameraSearch 获取摄像头列表
+func (s *hikvisionService) GetcameraSearch(pageNo, pageSize, name string) (error, hikvisionOpenAPIGo.Result) {
+	//var cameraSearch model.CameraSearch
+	m := make(map[string]any)
+	if pageNo != "" {
+		m["pageNo"] = pageNo
+	} else {
+		m["pageNo"] = "1"
+	}
+	if pageSize != "" {
+		m["pageSize"] = pageSize
+	} else {
+		m["pageSize"] = s.conf.GetString("hikvision.pageSize")
+	}
+	if name != "" {
+		m["name"] = name
+	}
+	// 获取门禁状态
+	hikvision, err := s.Hikvision(s.conf.GetString("hikvision.api.cameraSearch"), m, 15)
+	if err != nil {
+		return errors.New("获取摄像头列表失败"), hikvisionOpenAPIGo.Result{}
+	}
+	if hikvision.Code != "0" {
+		return errors.New("获取摄像头列表失败"), hikvisionOpenAPIGo.Result{}
+	}
+	return nil, hikvision
+}
+
+// GetDoorSearch 获取门禁列表
+func (s *hikvisionService) GetDoorSearch(pageNo, pageSize, name string) (error, hikvisionOpenAPIGo.Result) {
+	//var cameraSearch model.CameraSearch
+	m := make(map[string]any)
+	if pageNo != "" {
+		m["pageNo"] = pageNo
+	} else {
+		m["pageNo"] = "1"
+	}
+	if pageSize != "" {
+		m["pageSize"] = pageSize
+	} else {
+		m["pageSize"] = s.conf.GetString("hikvision.pageSize")
+	}
+	if name != "" {
+		m["name"] = name
+	}
+	// 获取门禁状态
+	hikvision, err := s.Hikvision(s.conf.GetString("hikvision.api.doorSearch"), m, 15)
+	if err != nil {
+		return errors.New("获取门禁点列表失败"), hikvisionOpenAPIGo.Result{}
+	}
+	if hikvision.Code != "0" {
+		return errors.New("获取门禁点列表失败"), hikvisionOpenAPIGo.Result{}
+	}
+	return nil, hikvision
+}
+
+// GetDoorStates  获取门禁设备状态
+func (s *hikvisionService) GetDoorStates(pageNo, pageSize string, indexCodes []string) (error, hikvisionOpenAPIGo.Result) {
+	//var cameraSearch model.CameraSearch
+	m := make(map[string]any)
+	if pageNo != "" {
+		m["pageNo"] = pageNo
+	} else {
+		m["pageNo"] = "1"
+	}
+	if pageSize != "" {
+		m["pageSize"] = pageSize
+	} else {
+		m["pageSize"] = "10"
+	}
+	if len(indexCodes) != 0 {
+		m["indexCodes"] = indexCodes
+	}
+	// 获取门禁状态
+	hikvision, err := s.Hikvision(s.conf.GetString("hikvision.api.doorStates"), m, 15)
+	if err != nil {
+		return errors.New("获取门禁点状态失败"), hikvisionOpenAPIGo.Result{}
+	}
+	if hikvision.Code != "0" {
+		return errors.New("获取门禁点状态失败"), hikvisionOpenAPIGo.Result{}
+	}
+	return nil, hikvision
+}
+
+// GetAcsDoorStates 查询门禁点状态
+func (s *hikvisionService) GetAcsDoorStates(indexCodes []string) (error, hikvisionOpenAPIGo.Result) {
+	//var cameraSearch model.CameraSearch
+	m := make(map[string]any)
+	if len(indexCodes) != 0 {
+		m["doorIndexCodes"] = indexCodes
+	}
+	// 获取门禁状态
+	hikvision, err := s.Hikvision(s.conf.GetString("hikvision.api.acsdoorstates"), m, 15)
+	if err != nil {
+		return errors.New("获取门禁点状态失败"), hikvisionOpenAPIGo.Result{}
+	}
+	if hikvision.Code != "0" {
+		return errors.New("获取门禁点状态失败"), hikvisionOpenAPIGo.Result{}
+	}
+	return nil, hikvision
+}
+
+// GetAcsDeviceSearch 获取门禁设备列表
+func (s *hikvisionService) GetAcsDeviceSearch(pageNo, pageSize, name string) (error, hikvisionOpenAPIGo.Result) {
+	//var cameraSearch model.CameraSearch
+	m := make(map[string]any)
+	if pageNo != "" {
+		m["pageNo"] = pageNo
+	} else {
+		m["pageNo"] = "1"
+	}
+	if pageSize != "" {
+		m["pageSize"] = pageSize
+	} else {
+		m["pageSize"] = s.conf.GetString("hikvision.pageSize")
+	}
+	if name != "" {
+		m["name"] = name
+	}
+	// 获取门禁状态
+	hikvision, err := s.Hikvision(s.conf.GetString("hikvision.api.acsDeviceSearch"), m, 15)
+	if err != nil {
+		return errors.New("获取门禁设备列表失败"), hikvisionOpenAPIGo.Result{}
+	}
+	if hikvision.Code != "0" {
+		return errors.New("获取门禁设备列表失败"), hikvisionOpenAPIGo.Result{}
+	}
+	return nil, hikvision
+}
+
+// GetManualCapture 手动抓图
+func (s *hikvisionService) GetManualCapture(cameraIndexCode string) (error, hikvisionOpenAPIGo.Result) {
+	//var cameraSearch model.CameraSearch
+	m := make(map[string]any)
+	if cameraIndexCode != "" {
+		m["cameraIndexCode"] = cameraIndexCode
+	}
+	// 获取门禁状态
+	hikvision, err := s.Hikvision(s.conf.GetString("hikvision.api.manualCapture"), m, 15)
+	if err != nil {
+		return errors.New("手动抓图失败"), hikvisionOpenAPIGo.Result{}
+	}
+	if hikvision.Code != "0" {
+		return errors.New("手动抓图失败"), hikvisionOpenAPIGo.Result{}
+	}
+	return nil, hikvision
+}
+
+// GetDoorDoControl  门禁点控制
+func (s *hikvisionService) GetDoorDoControl(doorIndexCodes []string, controlType int) (error, hikvisionOpenAPIGo.Result) {
+	//var cameraSearch model.CameraSearch
+	m := make(map[string]any)
+	if len(doorIndexCodes) != 0 {
+		m["doorIndexCodes"] = doorIndexCodes
+	} else {
+		return errors.New("请选择门禁点"), hikvisionOpenAPIGo.Result{}
+	}
+	m["controlType"] = controlType
+	// 获取门禁状态
+	hikvision, err := s.Hikvision(s.conf.GetString("hikvision.api.doorDoControl"), m, 15)
+	if err != nil {
+		return errors.New("门禁点控制失败"), hikvisionOpenAPIGo.Result{}
+	}
+	if hikvision.Code != "0" {
+		return errors.New("门禁点控制失败"), hikvisionOpenAPIGo.Result{}
+	}
+	return nil, hikvision
+}
+
+// GetEventLogs 入侵报警事件日志查询v2
+func (s *hikvisionService) GetEventLogs(pageNo, pageSize, srcType, startTime, endTime, srcName string, eventType int) (error, hikvisionOpenAPIGo.Result) {
+	//var cameraSearch model.CameraSearch
+	m := make(map[string]any)
+	if pageNo != "" {
+		m["pageNo"] = pageNo
+	} else {
+		m["pageNo"] = "1"
+	}
+	if pageSize != "" {
+		m["pageSize"] = pageSize
+	} else {
+		m["pageSize"] = s.conf.GetString("hikvision.pageSize")
+	}
+	if srcType != "" {
+		m["srcType"] = srcType
+	}
+	if startTime != "" {
+		m["startTime"] = startTime
+	}
+	if endTime != "" {
+		m["endTime"] = endTime
+	}
+	if srcName != "" {
+		m["srcName"] = srcName
+	}
+	if eventType != 0 {
+		m["eventType"] = eventType
+	}
+	// 获取门禁状态
+	hikvision, err := s.Hikvision(s.conf.GetString("hikvision.api.eventLogs"), m, 15)
+	if err != nil {
+		return errors.New("入侵报警事件日志查询失败"), hikvisionOpenAPIGo.Result{}
+	}
+	if hikvision.Code != "0" {
+		return errors.New("入侵报警事件日志查询失败"), hikvisionOpenAPIGo.Result{}
+	}
+	return nil, hikvision
+}

+ 0 - 0
pkg/helper/hikvision/HttpUtil.h → pkg/helper/hikvisionOpenAPIGo/HttpUtil.h


+ 1 - 1
pkg/helper/hikvision/hikvision.go → pkg/helper/hikvisionOpenAPIGo/hikvision.go

@@ -1,4 +1,4 @@
-package hikvision
+package hikvisionOpenAPIGo
 
 //
 ///*

+ 1 - 1
pkg/helper/hikvision/hikvisionCameras.go → pkg/helper/hikvisionOpenAPIGo/hikvisionCameras.go

@@ -1,4 +1,4 @@
-package hikvision
+package hikvisionOpenAPIGo
 
 import (
 	"github.com/zxbit2011/hikvisionOpenAPIGo"

+ 320 - 0
pkg/helper/hikvisionOpenAPIGo/hikvisionOpenAPIGo.go

@@ -0,0 +1,320 @@
+package hikvisionOpenAPIGo
+
+import (
+	"bytes"
+	"crypto/hmac"
+	"crypto/md5"
+	"crypto/sha256"
+	"crypto/tls"
+	"encoding/base64"
+	"encoding/hex"
+	"encoding/json"
+	"fmt"
+	"github.com/gofrs/uuid"
+	"io/ioutil"
+	"net/http"
+	"net/url"
+	"sort"
+	"strconv"
+	"strings"
+	"time"
+)
+
+// HKConfig 海康OpenAPI配置参数
+type HKConfig struct {
+	Ip      string //平台ip
+	Port    int    //平台端口
+	AppKey  string //平台APPKey
+	Secret  string //平台APPSecret
+	IsHttps bool   //是否使用HTTPS协议
+}
+
+// 返回结果
+type Result struct {
+	Code string      `json:"code"`
+	Msg  string      `json:"msg"`
+	Data interface{} `json:"data"`
+}
+
+// 返回值data
+type Data struct {
+	Total    int                      `json:"total"`
+	PageSize int                      `json:"pageSize"`
+	PageNo   int                      `json:"pageNo"`
+	List     []map[string]interface{} `json:"list"`
+}
+
+// @title		HTTP Post请求
+// @url			HTTP接口Url		string				 HTTP接口Url,不带协议和端口
+// @body		请求参数			map[string]any     支持数组、结构体等
+// @return		请求结果			Result
+func (hk HKConfig) HttpPost(url string, body map[string]any, timeout int) (result Result, err error) {
+	var header = make(map[string]string)
+	bodyJson, err := json.Marshal(body)
+	if err != nil {
+		return result, err
+	}
+	err = hk.initRequest(header, url, string(bodyJson), true)
+	if err != nil {
+		return Result{}, err
+	}
+
+	var sb strings.Builder
+	if hk.IsHttps {
+		sb.WriteString("https://")
+	} else {
+		sb.WriteString("http://")
+	}
+	sb.WriteString(fmt.Sprintf("%s:%d%s", hk.Ip, hk.Port, url))
+
+	client := &http.Client{
+		Timeout: time.Duration(timeout) * time.Second,
+		CheckRedirect: func(req *http.Request, via []*http.Request) error {
+			return http.ErrUseLastResponse
+		},
+	}
+	if hk.IsHttps {
+		tr := &http.Transport{
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+		}
+		client.Transport = tr
+	}
+
+	req, err := http.NewRequest("POST", sb.String(), bytes.NewReader(bodyJson))
+	if err != nil {
+		return result, err
+	}
+
+	req.Header.Set("Accept", header["Accept"])
+	req.Header.Set("Content-Type", header["Content-Type"])
+	for k, v := range header {
+		if strings.HasPrefix(k, "x-ca-") {
+			req.Header.Set(k, v)
+		}
+	}
+
+	resp, err := client.Do(req)
+	if err != nil {
+		return result, err
+	}
+	defer resp.Body.Close()
+
+	if resp.StatusCode == http.StatusOK {
+		resBody, _ := ioutil.ReadAll(resp.Body)
+		err = json.Unmarshal(resBody, &result)
+		return result, err
+	} else if resp.StatusCode == http.StatusFound || resp.StatusCode == http.StatusMovedPermanently {
+		reqUrl := resp.Header.Get("Location")
+		err = fmt.Errorf("HttpPost Response StatusCode:%d,Location:%s", resp.StatusCode, reqUrl)
+	} else {
+		err = fmt.Errorf("HttpPost Response StatusCode:%d", resp.StatusCode)
+	}
+	return result, err
+}
+
+// @title		HTTP Get请求
+// @url			HTTP接口Url		string			 HTTP接口Url,不带协议和端口
+// @params		请求参数		map[string]any    支持数组、结构体等
+// @timeout		超时时间		int			    单位秒
+// @return		请求结果		Result
+func (hk HKConfig) HttpGet(url string, params map[string]any, timeout int) (result Result, err error) {
+	var header = make(map[string]string)
+
+	// 构造查询参数
+	queryParams := buildQueryParams(params)
+	u := fmt.Sprintf("%s:%d%s?%s", hk.Ip, hk.Port, url, queryParams)
+
+	var sb strings.Builder
+	if hk.IsHttps {
+		sb.WriteString("https://")
+	} else {
+		sb.WriteString("http://")
+	}
+	sb.WriteString(u)
+
+	client := &http.Client{
+		Timeout: time.Duration(timeout) * time.Second,
+		CheckRedirect: func(req *http.Request, via []*http.Request) error {
+			return http.ErrUseLastResponse
+		},
+	}
+	if hk.IsHttps {
+		tr := &http.Transport{
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+		}
+		client.Transport = tr
+	}
+
+	req, err := http.NewRequest("GET", sb.String(), nil)
+	if err != nil {
+		return result, err
+	}
+
+	// 初始化签名头
+	err = hk.initRequest(header, url, "", false)
+	if err != nil {
+		return result, err
+	}
+
+	req.Header.Set("Accept", header["Accept"])
+	req.Header.Set("Content-Type", header["Content-Type"])
+	for k, v := range header {
+		if strings.HasPrefix(k, "x-ca-") {
+			req.Header.Set(k, v)
+		}
+	}
+
+	resp, err := client.Do(req)
+	if err != nil {
+		return result, err
+	}
+	defer resp.Body.Close()
+
+	if resp.StatusCode == http.StatusOK {
+		resBody, _ := ioutil.ReadAll(resp.Body)
+		err = json.Unmarshal(resBody, &result)
+		return result, err
+	} else if resp.StatusCode == http.StatusFound || resp.StatusCode == http.StatusMovedPermanently {
+		reqUrl := resp.Header.Get("Location")
+		err = fmt.Errorf("HttpGet Response StatusCode:%d,Location:%s", resp.StatusCode, reqUrl)
+	} else {
+		err = fmt.Errorf("HttpGet Response StatusCode:%d", resp.StatusCode)
+	}
+	return result, err
+}
+
+// initRequest 初始化请求头
+func (hk HKConfig) initRequest(header map[string]string, url, body string, isPost bool) error {
+	header["Accept"] = "application/json"
+	header["Content-Type"] = "application/json"
+	if isPost {
+		var err error
+		header["content-md5"], err = computeContentMd5(body)
+		if err != nil {
+			return err
+		}
+	}
+	header["x-ca-timestamp"] = strconv.FormatInt(time.Now().UnixMilli(), 10)
+	uid, err := uuid.NewV4()
+	if err != nil {
+		return err
+	}
+	header["x-ca-nonce"] = uid.String()
+	header["x-ca-key"] = hk.AppKey
+
+	var strToSign string
+	if isPost {
+		strToSign = buildSignString(header, url, "POST")
+	} else {
+		strToSign = buildSignString(header, url, "GET")
+	}
+	signedStr, err := computeForHMACSHA256(strToSign, hk.Secret)
+	if err != nil {
+		return err
+	}
+	header["x-ca-signature"] = signedStr
+	return nil
+}
+
+// computeContentMd5 计算content-md5
+func computeContentMd5(body string) (string, error) {
+	h := md5.New()
+	_, err := h.Write([]byte(body))
+	if err != nil {
+		return "", err
+	}
+	md5Str := hex.EncodeToString(h.Sum(nil))
+	return base64.StdEncoding.EncodeToString([]byte(md5Str)), nil
+}
+
+// computeForHMACSHA256 计算HMACSHA265
+func computeForHMACSHA256(str, secret string) (string, error) {
+	mac := hmac.New(sha256.New, []byte(secret))
+	_, err := mac.Write([]byte(str))
+	if err != nil {
+		return "", err
+	}
+	return base64.StdEncoding.EncodeToString(mac.Sum(nil)), nil
+}
+
+// buildSignString 计算签名字符串
+func buildSignString(header map[string]string, url, method string) string {
+	var sb []string
+	sb = append(sb, strings.ToUpper(method))
+	sb = append(sb, "\n")
+
+	if header != nil {
+		if _, ok := header["Accept"]; ok {
+			sb = append(sb, header["Accept"])
+			sb = append(sb, "\n")
+		}
+		if _, ok := header["Content-MD5"]; ok {
+			sb = append(sb, header["Content-MD5"])
+			sb = append(sb, "\n")
+		}
+		if _, ok := header["Content-Type"]; ok {
+			sb = append(sb, header["Content-Type"])
+			sb = append(sb, "\n")
+		}
+	}
+	sb = append(sb, buildSignHeader(header))
+	sb = append(sb, url)
+	return strings.Join(sb, "")
+}
+
+// buildSignHeader 计算签名头
+func buildSignHeader(header map[string]string) string {
+	var sslice []string
+	for key := range header {
+		if strings.Contains(key, "x-ca-") {
+			sslice = append(sslice, key)
+		}
+	}
+	sort.Strings(sslice)
+
+	var sbSignHeader []string
+	var sb []string
+	for _, k := range sslice {
+		sb = append(sb, k+":")
+		if header[k] != "" {
+			sb = append(sb, header[k])
+		}
+		sb = append(sb, "\n")
+		sbSignHeader = append(sbSignHeader, k)
+	}
+
+	header["x-ca-signature-headers"] = strings.Join(sbSignHeader, ",")
+	return strings.Join(sb, "")
+}
+
+// buildQueryParams 构建查询参数字符串,支持数组、基本类型
+func buildQueryParams(params map[string]any) string {
+	values := make(url.Values)
+
+	for key, value := range params {
+		switch v := value.(type) {
+		case string:
+			values.Add(key, v)
+		case int:
+			values.Add(key, strconv.Itoa(v))
+		case bool:
+			values.Add(key, strconv.FormatBool(v))
+		case []string:
+			for _, item := range v {
+				values.Add(key+"[]", item)
+			}
+		case []int:
+			for _, item := range v {
+				values.Add(key+"[]", strconv.Itoa(item))
+			}
+		case []interface{}:
+			for _, item := range v {
+				values.Add(key+"[]", fmt.Sprintf("%v", item))
+			}
+		default:
+			values.Add(key, fmt.Sprintf("%v", v))
+		}
+	}
+
+	return values.Encode()
+}

+ 81 - 0
pkg/helper/obix/obix.go

@@ -0,0 +1,81 @@
+package obix
+
+import (
+	"city_chips/internal/model"
+	"crypto/tls"
+	"encoding/base64"
+	"encoding/xml"
+	"fmt"
+	"io"
+	"net/http"
+	"net/url"
+	"strconv"
+)
+
+// SendSecureRequest 发送 GET 请求到指定 URL,使用用户名和密码构造认证 Header
+func SendSecureRequest(fullURL, username, password string) (string, error) {
+	// 创建不验证证书的 HTTP Client
+	client := &http.Client{
+		Transport: &http.Transport{
+			TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
+		},
+	}
+
+	// 创建请求
+	req, err := http.NewRequest("GET", fullURL, nil)
+	if err != nil {
+		return "", fmt.Errorf("failed to create request: %w", err)
+	}
+
+	// 构造 Authorization 头(Basic Auth)
+	auth := username + ":" + password
+	req.Header.Add("Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(auth)))
+
+	// 构造 Cookie 中的 niagara_origin_uri 参数(包含认证信息)
+	encodedUser := url.QueryEscape(username)
+	encodedPass := url.QueryEscape(password)
+
+	originURI := req.URL.Path + "?Username=" + encodedUser + "&Password=" + encodedPass
+	req.Header.Add("Cookie", "JSESSIONID=6ee85d04496e56251021fff41d3a690a53bb09f3524d5828e5.node0; niagara_origin_uri="+originURI)
+
+	// 发送请求
+	res, err := client.Do(req)
+	if err != nil {
+		return "", fmt.Errorf("request failed: %w", err)
+	}
+	defer res.Body.Close()
+
+	// 读取响应体
+	body, err := io.ReadAll(res.Body)
+	if err != nil {
+		return "", fmt.Errorf("failed to read response body: %w", err)
+	}
+	return string(body), nil
+}
+func ParseTemperatureFromXML(xmlData []byte) (*model.RealPoint, error) {
+	var realPoint model.RealPoint
+	err := xml.Unmarshal(xmlData, &realPoint)
+	if err != nil {
+		return nil, fmt.Errorf("failed to unmarshal XML: %w", err)
+	}
+	return &realPoint, nil
+}
+func DetectType(s string) interface{} {
+	// 1. 尝试转为整数
+	if i, err := strconv.Atoi(s); err == nil {
+		return i
+	}
+
+	// 2. 尝试转为浮点数
+	if f, err := strconv.ParseFloat(s, 64); err == nil {
+		return f
+	}
+
+	// 3. 尝试转为布尔值
+	if b, err := strconv.ParseBool(s); err == nil {
+		return b
+	}
+
+	// 4. 如果都不是,则返回原字符串
+	return s
+}

+ 21 - 47
templates/h5player.html

@@ -57,10 +57,10 @@
 				position: fixed;
 				z-index: 2025;
 				bottom: 4%;
-				right: 4%;
+				left: 4%;
 				/* width:20%; */
-				width: 200px;
-				height: 200px;
+				width: 140px;
+				height: 140px;
 				margin: 0 auto;
 				border-radius: 50%;
 			}
@@ -83,7 +83,7 @@
 				position: absolute;
 				width: 60%;
 				height: 60%;
-				background: #000000;
+				background: #FFFFFF;
 				z-index: 2;
 			}
 
@@ -105,6 +105,7 @@
 			.control-top {
 				top: 0;
 				left: 50%;
+				background-color: #FFFFFF;
 				transform: translateX(-50%) rotate(-45deg);
 				border-radius: 4px 100% 4px 4px;
 			}
@@ -124,6 +125,7 @@
 			.control-bottom {
 				left: 50%;
 				bottom: 0;
+				background-color: #FFFFFF;
 				transform: translateX(-50%) rotate(45deg);
 				border-radius: 4px 4px 100% 4px;
 			}
@@ -143,6 +145,7 @@
 			.control-left {
 				top: 50%;
 				left: 0;
+				background-color: #FFFFFF;
 				transform: translateY(-50%) rotate(45deg);
 				border-radius: 4px 4px 4px 100%;
 			}
@@ -162,6 +165,7 @@
 			.control-right {
 				top: 50%;
 				right: 0;
+				background: #FFFFFF;
 				transform: translateY(-50%) rotate(45deg);
 				border-radius: 4px 100% 4px 4px;
 			}
@@ -186,7 +190,7 @@
 				transform: translate(-50%, -50%);
 				width: 51.2%;
 				height: 51.2%;
-				background: #000000;
+				background: #FFFFFF;
 				border-radius: 50%;
 			}
 
@@ -221,46 +225,9 @@
 		</style>
 	</head>
 	<body>
-		<div id="app">
+		<div id="app" >
 			<div id="player"></div>
-			<a-locale-provider :locale="zh_CN">
-				<a-row>
-					<!-- <a-col :span="24" :md="24">
-						<a-affix :offset-top="8">
-							<div id="player"></div>
-						</a-affix>
-						<a-form-item>
-							分屏
-							<a-radio-group v-model="splitNum" @change="arrangeWindow">
-								<a-radio-button :value="1">1x1</a-radio-button>
-								<a-radio-button :value="2">2x2</a-radio-button>
-								<a-radio-button :value="3" v-show="!isMoveDevice">3x3</a-radio-button>
-								<a-radio-button :value="4" v-show="!isMoveDevice">4x4</a-radio-button>
-							</a-radio-group>
-							<a-button @click="wholeFullScreen">整体全屏</a-button>
-							<a-button @click="singleFullScreen">单窗口全屏</a-button>
-						</a-form-item>
-					</a-col> -->
-					<a-col :span="24" :md="12">
-						<div class="actions">
-							<a-form :label-col="labelCol" :wrapper-col="wrapperCol" v-show="tabActive !== 'log'">
-								<a-form-item label="预览URL">
-									<a-input v-model="urls.realplay"></a-input>
-								</a-form-item>
-								<a-form-item label="对讲URL">
-									<a-input v-model="urls.talk"></a-input>
-								</a-form-item>
-								<a-form-item label="预览&对讲">
-									<a-button id="btn-realplay" @click="realplay">开始预览</a-button>
-									<a-button id="btn-realplay-stop" @click="stopPlay">停止预览</a-button>
-									<a-button id="btn-stopall" @click="stopAllPlay">停止全部窗口</a-button>
-								</a-form-item>
-							</a-form>
-						</div>
-					</a-col>
-				</a-row>
-			</a-locale-provider>
-			<div class="control-wrapper">
+			<div class="control-wrapper" id="turntable">
 				<div class="control-btn control-top" @click="goTop"></div>
 				<div class="control-btn control-left" @click="goLeft"></div>
 				<div class="control-btn control-bottom" @click="goBottom"></div>
@@ -298,8 +265,14 @@
 			const IS_MOVE_DEVICE = document.body.clientWidth < 992 // 是否移动设备
 			const MSE_IS_SUPPORT = !!window.MediaSource // 是否支持mse
 
-			if (IS_MOVE_DEVICE) {
-				const vc = new VConsole()
+			// if (IS_MOVE_DEVICE) {
+			// 	const vc = new VConsole()
+			// }
+			let control = {{.control}}
+			if (control === true){
+				document.getElementById('turntable').style.display = 'block'
+			}else {
+				document.getElementById('turntable').style.display = 'none'
 			}
 
 			// function streamcb(data) {
@@ -448,7 +421,7 @@
 							szBasePath: "./", // 必填,与h5player.min.js的引用路径一致
 							iMaxSplit: 1,
 							iCurrentSplit: IS_MOVE_DEVICE ? 1 : 2,
-							openDebug: true,
+							// openDebug: false,
 							mseWorkerEnable: false, //是否开启多线程解码,分辨率大于1080P建议开启,否则可能卡顿
 							bSupporDoubleClickFull: true, //是否支持双击全屏,true-双击是全屏;false-双击无响应
 							oStyle: {
@@ -593,6 +566,7 @@
 					this.$el.style.setProperty('display', 'block')
 					this.init()
 					this.createPlayer()
+					this.realplay()
 				}
 			})
 		</script>