camera.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. package devices
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "github.com/gin-gonic/gin"
  6. "go.uber.org/zap"
  7. "io"
  8. "os"
  9. "path/filepath"
  10. "server/dao"
  11. "server/global"
  12. "server/model/common/response"
  13. "server/model/devices"
  14. "server/utils/cache"
  15. "strconv"
  16. "strings"
  17. "time"
  18. )
  19. type CameraApi struct {
  20. }
  21. // DeviceEndianHeartbeat 摄像头心跳
  22. func (ca *CameraApi) DeviceEndianHeartbeat(c *gin.Context) {
  23. var info devices.CameraEndianHeartbeatRequest
  24. if err := c.ShouldBindJSON(&info); err != nil {
  25. global.GVA_LOG.Error("DeviceEndianHeartbeat === ", zap.Error(err))
  26. response.FailWithMessage("参数错误", c)
  27. return
  28. }
  29. cache.UpdateDeviceState(info.SerialNum, 1)
  30. resp := devices.CameraEndianHeartbeatResponse{
  31. ReturnCode: 0,
  32. PushEventPic: true,
  33. }
  34. response.OkWithData(resp, c)
  35. }
  36. func (ca *CameraApi) DeviceEndianEvent(c *gin.Context) {
  37. // 步骤1:解析 multipart/form-data 表单(包含EventInfo和图片文件)
  38. var form devices.CameraEventForm
  39. if err := c.ShouldBind(&form); err != nil {
  40. global.GVA_LOG.Error("表单解析失败", zap.Error(err))
  41. response.FailWithMessage("表单格式错误:"+err.Error(), c)
  42. return
  43. }
  44. // 步骤2:处理EventInfo.json文件(原有逻辑)
  45. file, err := form.EventInfo.Open()
  46. if err != nil {
  47. global.GVA_LOG.Error("打开EventInfo文件失败", zap.Error(err))
  48. response.FailWithMessage("读取事件文件失败:"+err.Error(), c)
  49. return
  50. }
  51. defer file.Close()
  52. fileContent, err := io.ReadAll(file)
  53. if err != nil {
  54. global.GVA_LOG.Error("读取EventInfo文件内容失败", zap.Error(err))
  55. response.FailWithMessage("解析事件文件失败:"+err.Error(), c)
  56. return
  57. }
  58. var eventReq devices.CameraEndianEventRequest
  59. if err := json.Unmarshal(fileContent, &eventReq); err != nil {
  60. global.GVA_LOG.Error("JSON解析失败", zap.Error(err), zap.String("content", string(fileContent)))
  61. response.FailWithMessage("事件数据格式错误:"+err.Error(), c)
  62. return
  63. }
  64. //if eventReq.EventType != "Alarm" {
  65. // global.GVA_LOG.Info("事件处理完成", zap.Any("event", eventReq))
  66. // response.OkWithData(devices.CameraEndianEventResponse{
  67. // ReturnCode: 0,
  68. // }, c)
  69. // return
  70. //}
  71. // 步骤3:新增逻辑 - 处理图片文件(form.Files)
  72. var savedFiles string // 记录成功保存的图片路径
  73. if form.File != nil {
  74. // 遍历所有上传的图片
  75. // 3.1 打开图片文件
  76. imgFile, err := form.File.Open()
  77. if err != nil {
  78. global.GVA_LOG.Warn("打开图片文件失败", zap.String("filename", form.File.Filename), zap.Error(err))
  79. return // 跳过当前文件,处理下一个
  80. }
  81. defer imgFile.Close()
  82. // 3.2 读取图片内容
  83. imgBytes, err := io.ReadAll(imgFile)
  84. if err != nil {
  85. global.GVA_LOG.Warn("读取图片内容失败", zap.String("filename", form.File.Filename), zap.Error(err))
  86. return
  87. }
  88. // 3.3 简单校验图片类型(可选,根据需求调整)
  89. if !isImageFile(form.File.Filename) {
  90. global.GVA_LOG.Warn("非图片文件,跳过处理", zap.String("filename", form.File.Filename))
  91. return
  92. }
  93. // 3.4 保存图片到本地(实际项目可改为上传OSS/云存储)
  94. savePath, err := saveImageToLocal(eventReq.SerialNum, form.File.Filename, imgBytes)
  95. if err != nil {
  96. global.GVA_LOG.Warn("保存图片失败", zap.String("filename", form.File.Filename), zap.Error(err))
  97. }
  98. savedFiles = savePath
  99. }
  100. // 步骤4:返回响应(包含事件信息和图片处理结果)
  101. resp := devices.CameraEndianEventResponse{
  102. ReturnCode: 0,
  103. }
  104. global.GVA_LOG.Info("事件处理完成", zap.Any("event", eventReq), zap.String("saved_files", savedFiles))
  105. response.OkWithData(resp, c)
  106. }
  107. // 辅助函数:判断是否为图片文件(通过文件名后缀)
  108. func isImageFile(filename string) bool {
  109. ext := strings.ToLower(filepath.Ext(filename))
  110. switch ext {
  111. case ".jpg", ".jpeg", ".png", ".bmp", ".gif":
  112. return true
  113. default:
  114. return false
  115. }
  116. }
  117. // 辅助函数:保存图片到本地目录
  118. func saveImageToLocal(serialNum, filename string, data []byte) (string, error) {
  119. // 构建保存路径:./uploads/{设备序列号}/{日期}/filename
  120. dateDir := time.Now().Format("20060102")
  121. saveDir := filepath.Join("./uploads", serialNum, dateDir)
  122. if err := os.MkdirAll(saveDir, 0755); err != nil {
  123. return "", fmt.Errorf("创建保存目录失败:%w", err)
  124. }
  125. // 生成唯一文件名(避免重名)
  126. uniqueName := fmt.Sprintf("%s_%s", time.Now().Format("150405"), filename)
  127. savePath := filepath.Join(saveDir, uniqueName)
  128. // 写入文件
  129. if err := os.WriteFile(savePath, data, 0644); err != nil {
  130. return "", fmt.Errorf("写入文件失败:%w", err)
  131. }
  132. return savePath, nil
  133. }
  134. //---------------------------------------------------------------------------------------------------------------------
  135. func (ca *CameraApi) QueryAllCameras(c *gin.Context) {
  136. cameras, err := cameraService.QueryAllCameras()
  137. if err != nil {
  138. global.GVA_LOG.Error("查询失败", zap.Error(err))
  139. response.FailWithMessage("查询失败", c)
  140. return
  141. }
  142. response.OkWithData(cameras, c)
  143. }
  144. func (ca *CameraApi) QueryCameraList(c *gin.Context) {
  145. var info devices.SearchCamera
  146. if err := c.ShouldBind(&info); err != nil {
  147. global.GVA_LOG.Error("参数错误", zap.Error(err))
  148. response.FailWithMessage("参数错误", c)
  149. return
  150. }
  151. list, total, err := cameraService.QueryCameraList(info)
  152. if err != nil {
  153. global.GVA_LOG.Error("查询失败", zap.Error(err))
  154. response.FailWithMessage("查询失败", c)
  155. return
  156. }
  157. response.OkWithDetailed(response.PageResult{
  158. List: list,
  159. Total: total,
  160. Page: info.Page,
  161. PageSize: info.PageSize,
  162. }, "获取成功", c)
  163. }
  164. func (ca *CameraApi) CreateCamera(c *gin.Context) {
  165. var camera dao.Camera
  166. if err := c.ShouldBind(&camera); err != nil {
  167. global.GVA_LOG.Error("参数错误", zap.Error(err))
  168. response.FailWithMessage("参数错误", c)
  169. return
  170. }
  171. if err := cameraService.CreateCamera(camera); err != nil {
  172. global.GVA_LOG.Error("新增失败", zap.Error(err))
  173. response.FailWithMessage("新增失败", c)
  174. return
  175. }
  176. response.OkWithMessage("新增成功", c)
  177. }
  178. func (ca *CameraApi) UpdateCamera(c *gin.Context) {
  179. var camera dao.Camera
  180. if err := c.ShouldBind(&camera); err != nil {
  181. global.GVA_LOG.Error("参数错误", zap.Error(err))
  182. response.FailWithMessage("参数错误", c)
  183. return
  184. }
  185. if err := cameraService.UpdateCamera(camera); err != nil {
  186. global.GVA_LOG.Error("更新失败", zap.Error(err))
  187. response.FailWithMessage("更新失败", c)
  188. return
  189. }
  190. response.OkWithMessage("更新成功", c)
  191. }
  192. func (ca *CameraApi) DeleteCamera(c *gin.Context) {
  193. id, err := strconv.Atoi(c.Query("id"))
  194. if err != nil {
  195. response.FailWithMessage("参数错误", c)
  196. return
  197. }
  198. if err := cameraService.DeleteCamera(id); err != nil {
  199. global.GVA_LOG.Error("删除失败", zap.Error(err))
  200. response.FailWithMessage("删除失败", c)
  201. return
  202. }
  203. response.OkWithMessage("删除成功", c)
  204. }