From 118af81ac6438d4093bed824634639f217c967b4 Mon Sep 17 00:00:00 2001
From: Jerry Yan <792602257@qq.com>
Date: Thu, 12 Dec 2024 14:38:15 +0800
Subject: [PATCH] =?UTF-8?q?GA/T=201400=E5=8D=8F=E8=AE=AE=E6=94=AF=E6=8C=81?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../controller/task/TaskTaskController.java   |   2 +
 .../basic/controller/viid/ViidController.java | 269 ++++++++++++++++++
 .../ycwl/basic/mapper/pc/DeviceMapper.java    |   6 +
 .../model/pc/device/entity/DeviceEntity.java  |  11 +
 .../model/pc/device/resp/DeviceRespVO.java    |   5 +
 .../model/viid/entity/DeviceIdObject.java     |  14 +
 .../model/viid/entity/FaceListObject.java     |  12 +
 .../basic/model/viid/entity/FaceObject.java   | 169 +++++++++++
 .../viid/entity/ResponseStatusObject.java     |  21 ++
 .../model/viid/entity/SubImageInfoObject.java |  28 ++
 .../basic/model/viid/entity/SubImageList.java |  13 +
 .../model/viid/entity/SystemTimeObject.java   |  18 ++
 .../basic/model/viid/req/FaceUploadReq.java   |  11 +
 .../basic/model/viid/req/KeepaliveReq.java    |  11 +
 .../basic/model/viid/req/RegisterReq.java     |  11 +
 .../basic/model/viid/req/UnRegisterReq.java   |  12 +
 .../basic/model/viid/resp/SystemTimeResp.java |  13 +
 .../basic/model/viid/resp/VIIDBaseResp.java   |  15 +
 .../impl/task/TaskFaceServiceImpl.java        |   7 +-
 .../com/ycwl/basic/utils/AliFaceUtil.java     |  21 ++
 .../java/com/ycwl/basic/utils/ImageUtils.java |  79 +++++
 .../java/com/ycwl/basic/utils/IpUtils.java    | 175 ++++++++++++
 src/main/resources/mapper/pc/DeviceMapper.xml |  23 +-
 .../resources/mapper/pc/FaceSampleMapper.xml  |  10 +-
 src/main/resources/mapper/pc/SourceMapper.xml |   8 +-
 25 files changed, 953 insertions(+), 11 deletions(-)
 create mode 100644 src/main/java/com/ycwl/basic/controller/viid/ViidController.java
 create mode 100644 src/main/java/com/ycwl/basic/model/viid/entity/DeviceIdObject.java
 create mode 100644 src/main/java/com/ycwl/basic/model/viid/entity/FaceListObject.java
 create mode 100644 src/main/java/com/ycwl/basic/model/viid/entity/FaceObject.java
 create mode 100644 src/main/java/com/ycwl/basic/model/viid/entity/ResponseStatusObject.java
 create mode 100644 src/main/java/com/ycwl/basic/model/viid/entity/SubImageInfoObject.java
 create mode 100644 src/main/java/com/ycwl/basic/model/viid/entity/SubImageList.java
 create mode 100644 src/main/java/com/ycwl/basic/model/viid/entity/SystemTimeObject.java
 create mode 100644 src/main/java/com/ycwl/basic/model/viid/req/FaceUploadReq.java
 create mode 100644 src/main/java/com/ycwl/basic/model/viid/req/KeepaliveReq.java
 create mode 100644 src/main/java/com/ycwl/basic/model/viid/req/RegisterReq.java
 create mode 100644 src/main/java/com/ycwl/basic/model/viid/req/UnRegisterReq.java
 create mode 100644 src/main/java/com/ycwl/basic/model/viid/resp/SystemTimeResp.java
 create mode 100644 src/main/java/com/ycwl/basic/model/viid/resp/VIIDBaseResp.java
 create mode 100644 src/main/java/com/ycwl/basic/utils/AliFaceUtil.java
 create mode 100644 src/main/java/com/ycwl/basic/utils/ImageUtils.java
 create mode 100644 src/main/java/com/ycwl/basic/utils/IpUtils.java

diff --git a/src/main/java/com/ycwl/basic/controller/task/TaskTaskController.java b/src/main/java/com/ycwl/basic/controller/task/TaskTaskController.java
index 3585405..335c5b9 100644
--- a/src/main/java/com/ycwl/basic/controller/task/TaskTaskController.java
+++ b/src/main/java/com/ycwl/basic/controller/task/TaskTaskController.java
@@ -7,6 +7,7 @@ import com.ycwl.basic.model.task.req.WorkerAuthReqVo;
 import com.ycwl.basic.model.task.resp.TaskSyncRespVo;
 import com.ycwl.basic.service.task.TaskService;
 import com.ycwl.basic.utils.ApiResponse;
+import io.swagger.annotations.Api;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -16,6 +17,7 @@ import org.springframework.web.bind.annotation.RestController;
 
 @IgnoreToken
 @RestController
+@Api(tags = "渲染端对接接口")
 @RequestMapping("/task/v1/")
 public class TaskTaskController {
 
diff --git a/src/main/java/com/ycwl/basic/controller/viid/ViidController.java b/src/main/java/com/ycwl/basic/controller/viid/ViidController.java
new file mode 100644
index 0000000..80550bd
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/controller/viid/ViidController.java
@@ -0,0 +1,269 @@
+package com.ycwl.basic.controller.viid;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.ycwl.basic.annotation.IgnoreToken;
+import com.ycwl.basic.mapper.pc.DeviceMapper;
+import com.ycwl.basic.mapper.pc.FaceSampleMapper;
+import com.ycwl.basic.mapper.pc.SourceMapper;
+import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
+import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
+import com.ycwl.basic.model.pc.source.entity.SourceEntity;
+import com.ycwl.basic.model.viid.entity.DeviceIdObject;
+import com.ycwl.basic.model.viid.entity.FaceListObject;
+import com.ycwl.basic.model.viid.entity.FaceObject;
+import com.ycwl.basic.model.viid.entity.ResponseStatusObject;
+import com.ycwl.basic.model.viid.entity.SubImageInfoObject;
+import com.ycwl.basic.model.viid.entity.SubImageList;
+import com.ycwl.basic.model.viid.entity.SystemTimeObject;
+import com.ycwl.basic.model.viid.req.FaceUploadReq;
+import com.ycwl.basic.model.viid.req.KeepaliveReq;
+import com.ycwl.basic.model.viid.req.RegisterReq;
+import com.ycwl.basic.model.viid.req.UnRegisterReq;
+import com.ycwl.basic.model.viid.resp.SystemTimeResp;
+import com.ycwl.basic.model.viid.resp.VIIDBaseResp;
+import com.ycwl.basic.service.task.TaskFaceService;
+import com.ycwl.basic.utils.AliFaceUtil;
+import com.ycwl.basic.utils.ImageUtils;
+import com.ycwl.basic.utils.IpUtils;
+import com.ycwl.basic.utils.OssUtil;
+import com.ycwl.basic.utils.SnowFlakeUtil;
+import io.swagger.annotations.Api;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.List;
+import java.util.TimeZone;
+
+@IgnoreToken
+@RestController
+@Api(tags = "摄像头对接接口")
+@RequestMapping("/VIID")
+@Slf4j
+public class ViidController {
+    @Autowired
+    private DeviceMapper deviceMapper;
+    private static final String serverId = "00000000000000000001";
+    @Autowired
+    private SourceMapper sourceMapper;
+
+    // region 注册注销基础接口
+    /**
+     * 注册接口
+     *
+     * @param req     注册的信息
+     * @param request 请求
+     * @return 返回
+     */
+    @RequestMapping(value = "/System/Register", method = RequestMethod.POST)
+    public VIIDBaseResp register(@RequestBody RegisterReq req, HttpServletRequest request) {
+        DeviceIdObject deviceIdObject = req.getRegisterObject();
+        log.info("注册的设备信息:{}", deviceIdObject);
+        // 保存设备注册时间
+        DeviceEntity device = deviceMapper.getByDeviceNo(deviceIdObject.getDeviceId());
+        if (device == null) {
+            device = new DeviceEntity();
+            device.setName("未配置设备");
+            device.setNo(deviceIdObject.getDeviceId());
+            device.setOnline(1);
+        }
+        device.setKeepaliveAt(new Date());
+        device.setIpAddr(IpUtils.getIpAddr(request));
+        if (device.getId() != null) {
+            deviceMapper.updateEntity(device);
+        } else {
+            device.setId(SnowFlakeUtil.getLongId());
+            deviceMapper.addEntity(device);
+        }
+        SimpleDateFormat sdfTime = new SimpleDateFormat("yyyyMMddHHmmss");
+        return new VIIDBaseResp(
+                new ResponseStatusObject(serverId, "/VIID/System/Register", "0", "注册成功", sdfTime.format(new Date()))
+        );
+    }
+
+    /**
+     * 保活接口
+     *
+     * @param req     保活的设备信息
+     * @param request 请求
+     * @return 返回
+     */
+    @RequestMapping(value = "/System/Keepalive", method = RequestMethod.POST)
+    public VIIDBaseResp keepalive(@RequestBody KeepaliveReq req, HttpServletRequest request) {
+        DeviceIdObject keepaliveObject = req.getKeepaliveObject();
+        log.info("对方发送的心跳的信息:{}", keepaliveObject);
+
+        String deviceId = keepaliveObject.getDeviceId();
+        DeviceEntity device = deviceMapper.getByDeviceNo(deviceId);
+
+        // 判断设备状态
+        if (device == null) {
+            // 不存在设备就注册
+            device = new DeviceEntity();
+            device.setName("未配置设备");
+            device.setNo(deviceId);
+            device.setOnline(1);
+            device.setKeepaliveAt(new Date());
+            device.setIpAddr(IpUtils.getIpAddr(request));
+            device.setId(SnowFlakeUtil.getLongId());
+            deviceMapper.addEntity(device);
+        } else {
+            device.setOnline(1);
+            device.setKeepaliveAt(new Date());
+            deviceMapper.updateEntity(device);
+        }
+        log.info("已经解析过的心跳信息:{}", keepaliveObject);
+
+        SimpleDateFormat sdfTime = new SimpleDateFormat("yyyyMMddHHmmss");
+        return new VIIDBaseResp(
+                new ResponseStatusObject(deviceId, "/VIID/System/UnRegister", "0", "注销成功", sdfTime.format(new Date()))
+        );
+    }
+
+    /**
+     * 注销设备
+     *
+     * @param req     参数
+     * @return 返回
+     */
+    @RequestMapping(value = "/System/UnRegister", method = RequestMethod.POST)
+    public VIIDBaseResp unRegister(@RequestBody UnRegisterReq req) {
+        // 获取设备id
+        DeviceIdObject unRegisterObject = req.getUnRegisterObject();
+        String deviceId = unRegisterObject.getDeviceId();
+        log.info("获取的注销的请求参数:{}", unRegisterObject);
+
+        // 首先查询该设备是否存在
+        DeviceEntity device = deviceMapper.getByDeviceNo(deviceId);
+        // 判断
+        if (device != null) {
+            device.setOnline(0);
+            device.setKeepaliveAt(new Date());
+            int update = deviceMapper.updateEntity(device);
+        }
+        SimpleDateFormat sdfTime = new SimpleDateFormat("yyyyMMddHHmmss");
+        return new VIIDBaseResp(
+                new ResponseStatusObject(deviceId, "/VIID/System/UnRegister", "0", "注销成功", sdfTime.format(new Date()))
+        );
+    }
+
+    /**
+     * 校时接口
+     *
+     * @return 返回
+     */
+    @RequestMapping(value = "/System/Time", method = RequestMethod.GET)
+    public SystemTimeResp time() {
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
+        return new SystemTimeResp(
+                new SystemTimeObject(serverId, "2", sdf.format(new Date()), TimeZone.getTimeZone("Asia/Shanghai").toString())
+        );
+    }
+
+    // endregion
+
+    @Autowired
+    private FaceSampleMapper faceSampleMapper;
+
+    @Autowired
+    private TaskFaceService taskFaceService;
+    @Autowired
+    private OssUtil ossUtil;
+
+
+    /**
+     * 批量新增人脸
+     */
+    @RequestMapping(value = "/Faces", method = RequestMethod.POST)
+    public VIIDBaseResp faces(@RequestBody FaceUploadReq req) {
+        log.info("收到的人脸上报信息:{}",req);
+        FaceListObject faceListObject = req.getFaceListObject();
+        List<FaceObject> faceObject = faceListObject.getFaceObject();
+        String faceId = null;
+        // 遍历人脸列表
+        for (FaceObject face : faceObject) {
+            // 设置FaceId
+            faceId = face.getFaceID();
+            Long newFaceSampleId = SnowFlakeUtil.getLongId();
+            // 获取图片信息
+            SubImageList subImageList = face.getSubImageList();
+            // 判断人脸对象中的列表是否为空
+            String deviceID = face.getDeviceID();
+            DeviceEntity device = deviceMapper.getByDeviceNo(deviceID);
+            if (device == null) {
+                continue;
+            }
+            Long scenicId = device.getScenicId();
+            if (scenicId == null) {
+                continue;
+            }
+            if (ObjectUtil.isNotEmpty(subImageList) && CollUtil.isNotEmpty(subImageList.getSubImageInfoObject())) {
+                // 遍历每个图片对象
+                for (SubImageInfoObject subImage : subImageList.getSubImageInfoObject()) {
+                    // base64转换成MultipartFIle
+                    MultipartFile file = ImageUtils.base64ToMultipartFile(subImage.getData());
+                    String ext = subImage.getFileFormat();
+                    if (ext.equalsIgnoreCase("jpeg")) {
+                        ext = "jpg";
+                    }
+                    // Type=11 人脸
+                    if (subImage.getType().equals("11")) {
+                        // 上传oss
+                        FaceSampleEntity faceSample = new FaceSampleEntity();
+                        faceSample.setId(newFaceSampleId);
+                        faceSample.setScenicId(scenicId);
+                        faceSample.setDeviceId(device.getId());
+                        faceSample.setStatus(0);
+                        faceSample.setCreateAt(new Date());
+                        String url;
+                        try {
+                            url = ossUtil.uploadFile(file.getInputStream(), AliFaceUtil.generateEntityId(faceSample) + "." + ext);
+                        } catch (IOException e) {
+                            log.error("文件上传失败!", e);
+                            continue;
+                        }
+                        faceSample.setFaceUrl(url);
+                        faceSampleMapper.add(faceSample);
+                        log.info("人脸信息入库成功!");
+                        taskFaceService.addFaceSample(faceSample.getId());
+                    }
+                    // Type=14 场景图
+                    else if (subImage.getType().equals("14")) {
+                        SourceEntity source = new SourceEntity();
+                        source.setId(SnowFlakeUtil.getLongId());
+                        source.setDeviceId(device.getId());
+                        source.setScenicId(device.getScenicId());
+                        source.setFaceSampleId(newFaceSampleId);
+                        source.setType(2);
+                        // 上传oss
+                        String url;
+                        try {
+                            url = ossUtil.uploadFile(file.getInputStream(), "user-photo/", newFaceSampleId + "." + ext);
+                        } catch (IOException e) {
+                            log.error("文件上传失败!", e);
+                            continue;
+                        }
+                        source.setUrl(url);
+                        sourceMapper.add(source);
+                    }
+                }
+            }
+            log.info("设备ID:{}", deviceID);
+        }
+
+        SimpleDateFormat sdfTime = new SimpleDateFormat("yyyyMMddHHmmss");
+        return new VIIDBaseResp(
+                new ResponseStatusObject(faceId, "/VIID/Faces", "0", "OK", sdfTime.format(new Date()))
+        );
+    }
+
+}
diff --git a/src/main/java/com/ycwl/basic/mapper/pc/DeviceMapper.java b/src/main/java/com/ycwl/basic/mapper/pc/DeviceMapper.java
index b21bfcd..f73994d 100644
--- a/src/main/java/com/ycwl/basic/mapper/pc/DeviceMapper.java
+++ b/src/main/java/com/ycwl/basic/mapper/pc/DeviceMapper.java
@@ -33,4 +33,10 @@ public interface DeviceMapper {
     DeviceConfigEntity getConfigByDeviceId(Long deviceId);
     int addConfig(DeviceConfigEntity deviceConfigEntity);
     int updateConfig(DeviceConfigEntity deviceConfigEntity);
+
+    DeviceEntity getByDeviceNo(String deviceNo);
+
+    int updateEntity(DeviceEntity device);
+
+    int addEntity(DeviceEntity device);
 }
diff --git a/src/main/java/com/ycwl/basic/model/pc/device/entity/DeviceEntity.java b/src/main/java/com/ycwl/basic/model/pc/device/entity/DeviceEntity.java
index 873a1b6..054f256 100644
--- a/src/main/java/com/ycwl/basic/model/pc/device/entity/DeviceEntity.java
+++ b/src/main/java/com/ycwl/basic/model/pc/device/entity/DeviceEntity.java
@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import lombok.Data;
 
+import java.math.BigDecimal;
 import java.util.Date;
 
 /**
@@ -27,6 +28,14 @@ public class DeviceEntity {
      * 设备编号
      */
     private String no;
+    /**
+     * 经度
+     */
+    private BigDecimal longitude;
+    /***
+     * 纬度
+     */
+    private BigDecimal latitude;
     /**
      * 是否启用,0不启用,1启用
      */
@@ -35,6 +44,8 @@ public class DeviceEntity {
      * 是否在线,0不在线,1在线
      */
     private Integer online;
+    private String ipAddr;
+    private Date keepaliveAt;
     private Date createAt;
     private Date updateAt;
 }
diff --git a/src/main/java/com/ycwl/basic/model/pc/device/resp/DeviceRespVO.java b/src/main/java/com/ycwl/basic/model/pc/device/resp/DeviceRespVO.java
index bca82c8..b39c363 100644
--- a/src/main/java/com/ycwl/basic/model/pc/device/resp/DeviceRespVO.java
+++ b/src/main/java/com/ycwl/basic/model/pc/device/resp/DeviceRespVO.java
@@ -6,6 +6,7 @@ import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import java.math.BigDecimal;
 import java.util.Date;
 
 /**
@@ -22,6 +23,10 @@ public class DeviceRespVO {
     private String name;
     @ApiModelProperty("设备编号")
     private String no;
+    @ApiModelProperty("经度")
+    private BigDecimal longitude;
+    @ApiModelProperty("纬度")
+    private BigDecimal latitude;
     @ApiModelProperty("是否启用,0不启用,1启用")
     private Integer status;
     @ApiModelProperty("是否在线,0不在线,1在线")
diff --git a/src/main/java/com/ycwl/basic/model/viid/entity/DeviceIdObject.java b/src/main/java/com/ycwl/basic/model/viid/entity/DeviceIdObject.java
new file mode 100644
index 0000000..bf0bde1
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/viid/entity/DeviceIdObject.java
@@ -0,0 +1,14 @@
+package com.ycwl.basic.model.viid.entity;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class DeviceIdObject implements Serializable {
+
+    @JsonProperty("DeviceID")
+    private String deviceId;
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/ycwl/basic/model/viid/entity/FaceListObject.java b/src/main/java/com/ycwl/basic/model/viid/entity/FaceListObject.java
new file mode 100644
index 0000000..cab924a
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/viid/entity/FaceListObject.java
@@ -0,0 +1,12 @@
+package com.ycwl.basic.model.viid.entity;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class FaceListObject {
+    @JsonProperty("FaceObject")
+    private List<FaceObject> faceObject;
+}
diff --git a/src/main/java/com/ycwl/basic/model/viid/entity/FaceObject.java b/src/main/java/com/ycwl/basic/model/viid/entity/FaceObject.java
new file mode 100644
index 0000000..88b35ed
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/viid/entity/FaceObject.java
@@ -0,0 +1,169 @@
+package com.ycwl.basic.model.viid.entity;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class FaceObject {
+    @JsonProperty("FaceID")
+    private String FaceID;
+    @JsonProperty("InfoKind")
+    private Integer InfoKind;
+    @JsonProperty("SourceID")
+    private String SourceID;
+    @JsonProperty("DeviceID")
+    private String DeviceID;
+    @JsonProperty("LeftTopX")
+    private Integer LeftTopX;
+    @JsonProperty("LeftTopY")
+    private Integer LeftTopY;
+    @JsonProperty("RightBtmX")
+    private Integer RightBtmX;
+    @JsonProperty("RightBtmY")
+    private Integer RightBtmY;
+    @JsonProperty("IDNumber")
+    private String IDNumber;
+    @JsonProperty("Name")
+    private String Name;
+    @JsonProperty("UsedName")
+    private String UsedName;
+    @JsonProperty("Alias")
+    private String Alias;
+    @JsonProperty("AgeUpLimit")
+    private Integer AgeUpLimit;
+    @JsonProperty("AgeLowerLimit")
+    private Integer AgeLowerLimit;
+    @JsonProperty("EthicCode")
+    private String EthicCode;
+    @JsonProperty("NationalityCode")
+    private String NationalityCode;
+    @JsonProperty("NativeCityCode")
+    private String NativeCityCode;
+    @JsonProperty("ResidenceAdminDivision")
+    private String ResidenceAdminDivision;
+    @JsonProperty("ChineseAccentCode")
+    private String ChineseAccentCode;
+    @JsonProperty("JobCategory")
+    private String JobCategory;
+    @JsonProperty("AccompanyNumber")
+    private Integer AccompanyNumber;
+    @JsonProperty("SkinColor")
+    private String SkinColor;
+    @JsonProperty("FaceStyle")
+    private String FaceStyle;
+    @JsonProperty("FacialFeature")
+    private String FacialFeature;
+    @JsonProperty("PhysicalFeature")
+    private String PhysicalFeature;
+    @JsonProperty("IsDriver")
+    private Integer IsDriver;
+    @JsonProperty("IsForeigner")
+    private Integer IsForeigner;
+    @JsonProperty("ImmigrantTypeCode")
+    private String ImmigrantTypeCode;
+    @JsonProperty("IsSuspectedTerrorist")
+    private Integer IsSuspectedTerrorist;
+    @JsonProperty("SuspectedTerroristNumber")
+    private String SuspectedTerroristNumber;
+    @JsonProperty("IsCriminalInvolved")
+    private Integer IsCriminalInvolved;
+    @JsonProperty("CriminalInvolvedSpecilisationCode")
+    private String CriminalInvolvedSpecilisationCode;
+    @JsonProperty("BodySpeciallMark")
+    private String BodySpeciallMark;
+    @JsonProperty("CrimeMethod")
+    private String CrimeMethod;
+    @JsonProperty("CrimeCharacterCode")
+    private String CrimeCharacterCode;
+    @JsonProperty("EscapedCriminalNumber")
+    private String EscapedCriminalNumber;
+    @JsonProperty("IsDetainees")
+    private Integer IsDetainees;
+    @JsonProperty("DetentionHouseCode")
+    private String DetentionHouseCode;
+    @JsonProperty("DetaineesSpecialIdentity")
+    private String DetaineesSpecialIdentity;
+    @JsonProperty("MemberTypeCode")
+    private String MemberTypeCode;
+    @JsonProperty("IsVictim")
+    private String IsVictim;
+    @JsonProperty("VictimType")
+    private String VictimType;
+    @JsonProperty("CorpseConditionCode")
+    private String CorpseConditionCode;
+    @JsonProperty("IsSuspiciousPerson")
+    private String IsSuspiciousPerson;
+    @JsonProperty("Attitude")
+    private String Attitude;
+    @JsonProperty("Similaritydegree")
+    private String Similaritydegree;
+    @JsonProperty("EyebrowStyle")
+    private String EyebrowStyle;
+    @JsonProperty("NoseStyle")
+    private String NoseStyle;
+    @JsonProperty("MustacheStyle")
+    private String MustacheStyle;
+    @JsonProperty("LipStyle")
+    private String LipStyle;
+    @JsonProperty("WrinklePouch")
+    private String WrinklePouch;
+    @JsonProperty("AcneStain")
+    private String AcneStain;
+    @JsonProperty("FreckleBirthmark")
+    private String FreckleBirthmark;
+    @JsonProperty("ScarDimple")
+    private String ScarDimple;
+    @JsonProperty("TabID")
+    private String TabID;
+    @JsonProperty("OtherFeature")
+    private String OtherFeature;
+    @JsonProperty("Maritalstatus")
+    private String Maritalstatus;
+    @JsonProperty("FamilyAddress")
+    private String FamilyAddress;
+    @JsonProperty("CollectorOrg")
+    private String CollectorOrg;
+    @JsonProperty("CollectorID")
+    private String CollectorID;
+    @JsonProperty("DeviceSNNo")
+    private String DeviceSNNo;
+    @JsonProperty("APSId")
+    private String APSId;
+    @JsonProperty("LocationMarkTime")
+    private String LocationMarkTime;
+    @JsonProperty("FaceAppearTime")
+    private String FaceAppearTime;
+    @JsonProperty("FaceDisAppearTime")
+    private String FaceDisAppearTime;
+    @JsonProperty("ShotTime")
+    private String ShotTime;
+    @JsonProperty("IDType")
+    private String IDType;
+    @JsonProperty("GenderCode")
+    private String GenderCode;
+    @JsonProperty("HairStyle")
+    private String HairStyle;
+    @JsonProperty("HairColor")
+    private String HairColor;
+    @JsonProperty("RespiratorColor")
+    private String RespiratorColor;
+    @JsonProperty("CapStyle")
+    private String CapStyle;
+    @JsonProperty("CapColor")
+    private String CapColor;
+    @JsonProperty("GlassStyle")
+    private String GlassStyle;
+    @JsonProperty("GlassColor")
+    private String GlassColor;
+    @JsonProperty("PassportType")
+    private String PassportType;
+    @JsonProperty("DetaineesIdentity")
+    private String DetaineesIdentity;
+    @JsonProperty("InjuredDegree")
+    private String InjuredDegree;
+    @JsonProperty("EntryTime")
+    private String EntryTime;
+    @JsonProperty("SubImageList")
+    private SubImageList subImageList;
+
+}
\ No newline at end of file
diff --git a/src/main/java/com/ycwl/basic/model/viid/entity/ResponseStatusObject.java b/src/main/java/com/ycwl/basic/model/viid/entity/ResponseStatusObject.java
new file mode 100644
index 0000000..695ad50
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/viid/entity/ResponseStatusObject.java
@@ -0,0 +1,21 @@
+package com.ycwl.basic.model.viid.entity;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class ResponseStatusObject {
+
+    @JsonProperty("Id")
+    private String id;
+    @JsonProperty("RequestURL")
+    private String requestUrl;
+    @JsonProperty("StatusCode")
+    private String statusCode;
+    @JsonProperty("StatusString")
+    private String statusString;
+    @JsonProperty("LocalTime")
+    private String localTime;
+}
diff --git a/src/main/java/com/ycwl/basic/model/viid/entity/SubImageInfoObject.java b/src/main/java/com/ycwl/basic/model/viid/entity/SubImageInfoObject.java
new file mode 100644
index 0000000..71284d7
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/viid/entity/SubImageInfoObject.java
@@ -0,0 +1,28 @@
+package com.ycwl.basic.model.viid.entity;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+@Data
+public class SubImageInfoObject {
+    @JsonProperty("ImageID")
+    private String ImageID;
+    @JsonProperty("EventSort")
+    private Integer EventSort;
+    @JsonProperty("DeviceID")
+    private String DeviceID;
+    @JsonProperty("StoragePath")
+    private String StoragePath;
+    @JsonProperty("Type")
+    private String Type;
+    @JsonProperty("FileFormat")
+    private String FileFormat;
+    @JsonProperty("Width")
+    private String Width;
+    @JsonProperty("Height")
+    private String Height;
+    @JsonProperty("ShotTime")
+    private String ShotTime;
+    @JsonProperty("Data")
+    private String Data;
+}
diff --git a/src/main/java/com/ycwl/basic/model/viid/entity/SubImageList.java b/src/main/java/com/ycwl/basic/model/viid/entity/SubImageList.java
new file mode 100644
index 0000000..2723a04
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/viid/entity/SubImageList.java
@@ -0,0 +1,13 @@
+package com.ycwl.basic.model.viid.entity;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class SubImageList {
+
+    @JsonProperty("SubImageInfoObject")
+    private List<SubImageInfoObject> subImageInfoObject;
+}
diff --git a/src/main/java/com/ycwl/basic/model/viid/entity/SystemTimeObject.java b/src/main/java/com/ycwl/basic/model/viid/entity/SystemTimeObject.java
new file mode 100644
index 0000000..5630729
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/viid/entity/SystemTimeObject.java
@@ -0,0 +1,18 @@
+package com.ycwl.basic.model.viid.entity;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class SystemTimeObject {
+    @JsonProperty("VIIDServerID")
+    private String viidServerId;
+    @JsonProperty("TimeMode")
+    private String timeMode;
+    @JsonProperty("LocalTime")
+    private String localTime;
+    @JsonProperty("TimeZone")
+    private String timezone;
+}
diff --git a/src/main/java/com/ycwl/basic/model/viid/req/FaceUploadReq.java b/src/main/java/com/ycwl/basic/model/viid/req/FaceUploadReq.java
new file mode 100644
index 0000000..d801527
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/viid/req/FaceUploadReq.java
@@ -0,0 +1,11 @@
+package com.ycwl.basic.model.viid.req;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ycwl.basic.model.viid.entity.FaceListObject;
+import lombok.Data;
+
+@Data
+public class FaceUploadReq {
+    @JsonProperty("FaceListObject")
+    private FaceListObject faceListObject;
+}
diff --git a/src/main/java/com/ycwl/basic/model/viid/req/KeepaliveReq.java b/src/main/java/com/ycwl/basic/model/viid/req/KeepaliveReq.java
new file mode 100644
index 0000000..efb3204
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/viid/req/KeepaliveReq.java
@@ -0,0 +1,11 @@
+package com.ycwl.basic.model.viid.req;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ycwl.basic.model.viid.entity.DeviceIdObject;
+import lombok.Data;
+
+@Data
+public class KeepaliveReq {
+    @JsonProperty("KeepaliveObject")
+    private DeviceIdObject keepaliveObject;
+}
diff --git a/src/main/java/com/ycwl/basic/model/viid/req/RegisterReq.java b/src/main/java/com/ycwl/basic/model/viid/req/RegisterReq.java
new file mode 100644
index 0000000..98e6ca1
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/viid/req/RegisterReq.java
@@ -0,0 +1,11 @@
+package com.ycwl.basic.model.viid.req;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ycwl.basic.model.viid.entity.DeviceIdObject;
+import lombok.Data;
+
+@Data
+public class RegisterReq {
+    @JsonProperty("RegisterObject")
+    private DeviceIdObject registerObject;
+}
diff --git a/src/main/java/com/ycwl/basic/model/viid/req/UnRegisterReq.java b/src/main/java/com/ycwl/basic/model/viid/req/UnRegisterReq.java
new file mode 100644
index 0000000..89051e5
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/viid/req/UnRegisterReq.java
@@ -0,0 +1,12 @@
+package com.ycwl.basic.model.viid.req;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ycwl.basic.model.viid.entity.DeviceIdObject;
+import lombok.Data;
+
+@Data
+public class UnRegisterReq {
+
+    @JsonProperty("UnRegisterObject")
+    private DeviceIdObject unRegisterObject;
+}
diff --git a/src/main/java/com/ycwl/basic/model/viid/resp/SystemTimeResp.java b/src/main/java/com/ycwl/basic/model/viid/resp/SystemTimeResp.java
new file mode 100644
index 0000000..f07801e
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/viid/resp/SystemTimeResp.java
@@ -0,0 +1,13 @@
+package com.ycwl.basic.model.viid.resp;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ycwl.basic.model.viid.entity.SystemTimeObject;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class SystemTimeResp {
+    @JsonProperty("SystemTimeObject")
+    private SystemTimeObject systemTimeObject;
+}
diff --git a/src/main/java/com/ycwl/basic/model/viid/resp/VIIDBaseResp.java b/src/main/java/com/ycwl/basic/model/viid/resp/VIIDBaseResp.java
new file mode 100644
index 0000000..6fe80ae
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/viid/resp/VIIDBaseResp.java
@@ -0,0 +1,15 @@
+package com.ycwl.basic.model.viid.resp;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.ycwl.basic.model.viid.entity.ResponseStatusObject;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+@Data
+@AllArgsConstructor
+public class VIIDBaseResp {
+
+    @JsonProperty("ResponseStatusObject")
+    private ResponseStatusObject responseStatusObject;
+
+}
diff --git a/src/main/java/com/ycwl/basic/service/impl/task/TaskFaceServiceImpl.java b/src/main/java/com/ycwl/basic/service/impl/task/TaskFaceServiceImpl.java
index b38418b..371bc5f 100644
--- a/src/main/java/com/ycwl/basic/service/impl/task/TaskFaceServiceImpl.java
+++ b/src/main/java/com/ycwl/basic/service/impl/task/TaskFaceServiceImpl.java
@@ -25,6 +25,7 @@ import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
 import com.ycwl.basic.model.task.resp.AddFaceRespVo;
 import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
 import com.ycwl.basic.service.task.TaskFaceService;
+import com.ycwl.basic.utils.AliFaceUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -102,8 +103,7 @@ public class TaskFaceServiceImpl implements TaskFaceService {
         FaceSampleRespVO faceSampleRespVO = faceSampleMapper.getById(faceSampleId);
         AddFaceEntityRequest request = new AddFaceEntityRequest();
         request.setDbName(faceSampleRespVO.getScenicId().toString());
-        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
-        String entityId = faceSampleRespVO.getDeviceId().toString() + "_" + sdf.format(faceSampleRespVO.getCreateAt());
+        String entityId = AliFaceUtil.generateEntityId(faceSampleRespVO);
         request.setEntityId(entityId);
         IAcsClient client = getClient();
         try {
@@ -150,9 +150,8 @@ public class TaskFaceServiceImpl implements TaskFaceService {
         query.setStartTime(dayStart);
         query.setEndTime(dayEnd);
         IAcsClient client = getClient();
-        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
         faceSampleMapper.list(query).forEach(faceSampleEntity -> {
-            String entityId = faceSampleEntity.getDeviceId().toString() + "_" + sdf.format(faceSampleEntity.getCreateAt());
+            String entityId = AliFaceUtil.generateEntityId(faceSampleEntity);
             DeleteFaceEntityRequest request = new DeleteFaceEntityRequest();
             request.setDbName(scenicId.toString());
             request.setEntityId(entityId);
diff --git a/src/main/java/com/ycwl/basic/utils/AliFaceUtil.java b/src/main/java/com/ycwl/basic/utils/AliFaceUtil.java
new file mode 100644
index 0000000..658307f
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/utils/AliFaceUtil.java
@@ -0,0 +1,21 @@
+package com.ycwl.basic.utils;
+
+import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
+import com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO;
+
+import java.text.SimpleDateFormat;
+
+public class AliFaceUtil {
+    private static final String DATE_FORMAT="yyyyMMddHHmmssSSS";
+
+    public static String generateEntityId(FaceSampleEntity entity) {
+        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
+        String entityId = entity.getDeviceId().toString() + "_" + sdf.format(entity.getCreateAt());
+        return entityId;
+    }
+    public static String generateEntityId(FaceSampleRespVO entity) {
+        SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
+        String entityId = entity.getDeviceId().toString() + "_" + sdf.format(entity.getCreateAt());
+        return entityId;
+    }
+}
diff --git a/src/main/java/com/ycwl/basic/utils/ImageUtils.java b/src/main/java/com/ycwl/basic/utils/ImageUtils.java
new file mode 100644
index 0000000..1bca534
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/utils/ImageUtils.java
@@ -0,0 +1,79 @@
+package com.ycwl.basic.utils;
+
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Base64;
+
+public class ImageUtils {
+    public static MultipartFile base64ToMultipartFile(String base64) {
+        String[] baseStrs = base64.split(",");
+        byte[] b;
+        b = Base64.getDecoder().decode(baseStrs[0]);
+        for (int i = 0; i < b.length; ++i) {
+            if (b[i] < 0) {
+                b[i] += 256;
+            }
+        }
+        return new Base64DecodedMultipartFile(b, baseStrs[0]);
+    }
+    public static class Base64DecodedMultipartFile implements MultipartFile {
+
+        private final byte[] imgContent;
+        private final String header;
+
+        public Base64DecodedMultipartFile(byte[] imgContent, String header) {
+            this.imgContent = imgContent;
+            this.header = header.split(";")[0];
+        }
+
+        @Override
+        public String getName() {
+            // TODO - implementation depends on your requirements
+            return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1];
+        }
+
+        @Override
+        public String getOriginalFilename() {
+            // TODO - implementation depends on your requirements
+            return System.currentTimeMillis() + (int) Math.random() * 10000 + "." + header.split("/")[1];
+        }
+
+        @Override
+        public String getContentType() {
+            // TODO - implementation depends on your requirements
+            return header.split(":")[0];
+        }
+
+        @Override
+        public boolean isEmpty() {
+            return imgContent == null || imgContent.length == 0;
+        }
+
+        @Override
+        public long getSize() {
+            return imgContent.length;
+        }
+
+        @Override
+        public byte[] getBytes() {
+            return imgContent;
+        }
+
+        @Override
+        public InputStream getInputStream() {
+            return new ByteArrayInputStream(imgContent);
+        }
+
+        @Override
+        public void transferTo(File dest) throws IOException, IllegalStateException {
+            new FileOutputStream(dest).write(imgContent);
+        }
+
+    }
+
+}
diff --git a/src/main/java/com/ycwl/basic/utils/IpUtils.java b/src/main/java/com/ycwl/basic/utils/IpUtils.java
new file mode 100644
index 0000000..b4dc6a7
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/utils/IpUtils.java
@@ -0,0 +1,175 @@
+package com.ycwl.basic.utils;
+
+import org.apache.commons.lang3.StringUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * 获取IP方法
+ *
+ * @author tsingeye
+ */
+public class IpUtils {
+    /**
+     * 获取客户端IP
+     *
+     * @param request 请求对象
+     * @return IP地址
+     */
+    public static String getIpAddr(HttpServletRequest request) {
+        if (request == null) {
+            return "unknown";
+        }
+        String ip = request.getHeader("x-forwarded-for");
+        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("Proxy-Client-IP");
+        }
+        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("X-Forwarded-For");
+        }
+        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("X-Real-IP");
+        }
+
+        if (ip == null || ip.isEmpty() || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getRemoteAddr();
+        }
+
+        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : getMultistageReverseProxyIp(ip);
+    }
+
+    /**
+     * 将IPv4地址转换成字节
+     *
+     * @param text IPv4地址
+     * @return byte 字节
+     */
+    public static byte[] textToNumericFormatV4(String text) {
+        if (text.length() == 0) {
+            return null;
+        }
+
+        byte[] bytes = new byte[4];
+        String[] elements = text.split("\\." , -1);
+        try {
+            long l;
+            int i;
+            switch (elements.length) {
+                case 1:
+                    l = Long.parseLong(elements[0]);
+                    if ((l < 0L) || (l > 4294967295L)) {
+                        return null;
+                    }
+                    bytes[0] = (byte) (int) (l >> 24 & 0xFF);
+                    bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
+                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 2:
+                    l = Integer.parseInt(elements[0]);
+                    if ((l < 0L) || (l > 255L)) {
+                        return null;
+                    }
+                    bytes[0] = (byte) (int) (l & 0xFF);
+                    l = Integer.parseInt(elements[1]);
+                    if ((l < 0L) || (l > 16777215L)) {
+                        return null;
+                    }
+                    bytes[1] = (byte) (int) (l >> 16 & 0xFF);
+                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 3:
+                    for (i = 0; i < 2; ++i) {
+                        l = Integer.parseInt(elements[i]);
+                        if ((l < 0L) || (l > 255L)) {
+                            return null;
+                        }
+                        bytes[i] = (byte) (int) (l & 0xFF);
+                    }
+                    l = Integer.parseInt(elements[2]);
+                    if ((l < 0L) || (l > 65535L)) {
+                        return null;
+                    }
+                    bytes[2] = (byte) (int) (l >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 4:
+                    for (i = 0; i < 4; ++i) {
+                        l = Integer.parseInt(elements[i]);
+                        if ((l < 0L) || (l > 255L)) {
+                            return null;
+                        }
+                        bytes[i] = (byte) (int) (l & 0xFF);
+                    }
+                    break;
+                default:
+                    return null;
+            }
+        } catch (NumberFormatException e) {
+            return null;
+        }
+        return bytes;
+    }
+
+    /**
+     * 获取IP地址
+     *
+     * @return 本地IP地址
+     */
+    public static String getHostIp() {
+        try {
+            return InetAddress.getLocalHost().getHostAddress();
+        } catch (UnknownHostException e) {
+        }
+        return "127.0.0.1";
+    }
+
+    /**
+     * 获取主机名
+     *
+     * @return 本地主机名
+     */
+    public static String getHostName() {
+        try {
+            return InetAddress.getLocalHost().getHostName();
+        } catch (UnknownHostException e) {
+        }
+        return "未知";
+    }
+
+    /**
+     * 从多级反向代理中获得第一个非unknown IP地址
+     *
+     * @param ip 获得的IP地址
+     * @return 第一个非unknown IP地址
+     */
+    public static String getMultistageReverseProxyIp(String ip) {
+        // 多级反向代理检测
+        if (ip != null && ip.indexOf(",") > 0) {
+            final String[] ips = ip.trim().split(",");
+            for (String subIp : ips) {
+                if (false == isUnknown(subIp)) {
+                    ip = subIp;
+                    break;
+                }
+            }
+        }
+        return ip;
+    }
+
+    /**
+     * 检测给定字符串是否为未知,多用于检测HTTP请求相关
+     *
+     * @param checkString 被检测的字符串
+     * @return 是否未知
+     */
+    public static boolean isUnknown(String checkString) {
+        return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
+    }
+}
\ No newline at end of file
diff --git a/src/main/resources/mapper/pc/DeviceMapper.xml b/src/main/resources/mapper/pc/DeviceMapper.xml
index 15e7374..5685564 100644
--- a/src/main/resources/mapper/pc/DeviceMapper.xml
+++ b/src/main/resources/mapper/pc/DeviceMapper.xml
@@ -8,6 +8,10 @@
         insert into device_config(id, device_id, create_time)
         values (#{id}, #{deviceId}, now())
     </insert>
+    <insert id="addEntity">
+        insert into device(id, name, no, status, online, ip_addr, keepalive_at, create_at, update_at)
+        values (#{id}, #{name}, #{no}, 0, #{online}, #{ipAddr}, #{keepaliveAt}, now(), now())
+    </insert>
     <update id="update">
         update device set scenic_id = #{scenicId}, name = #{name}, no = #{no}, longitude = #{longitude}, latitude = #{latitude}, update_at = now() where id = #{id}
     </update>
@@ -34,11 +38,21 @@
             cut_post = #{cutPost}
         where id = #{id}
     </update>
+    <update id="updateEntity">
+        update device
+        set name = #{name},
+            no = #{no},
+            online = #{online},
+            ip_addr = #{ipAddr},
+            keepalive_at = #{keepaliveAt},
+            update_at = now()
+        where id = #{id}
+    </update>
     <delete id="deleteById">
         delete from device where id = #{id}
     </delete>
     <select id="list" resultType="com.ycwl.basic.model.pc.device.resp.DeviceRespVO">
-        select d.id, scenic_id, d.name, no, d.status, create_at, d.update_at, s.name scenic_name
+        select d.id, scenic_id, d.name, no, d.longitude, d.latitude, d.status, create_at, d.update_at, s.name scenic_name
         from device d
         left join scenic s on d.scenic_id = s.id
         <where>
@@ -63,7 +77,7 @@
         </where>
     </select>
     <select id="getById" resultType="com.ycwl.basic.model.pc.device.resp.DeviceRespVO">
-        select d.id, scenic_id, d.name, no, d.status, create_at, d.update_at, s.name scenic_name
+        select d.id, scenic_id, d.name, no, d.longitude, d.latitude, d.status, create_at, d.update_at, s.name scenic_name
         from device d
                  left join scenic s on d.scenic_id = s.id
         where d.id = #{id}
@@ -97,4 +111,9 @@
         from device
         where id = #{deviceId}
     </select>
+    <select id="getByDeviceNo" resultType="com.ycwl.basic.model.pc.device.entity.DeviceEntity">
+        select *
+        from device
+        where no = #{deviceNo}
+    </select>
 </mapper>
\ No newline at end of file
diff --git a/src/main/resources/mapper/pc/FaceSampleMapper.xml b/src/main/resources/mapper/pc/FaceSampleMapper.xml
index 0cba491..a70ba85 100644
--- a/src/main/resources/mapper/pc/FaceSampleMapper.xml
+++ b/src/main/resources/mapper/pc/FaceSampleMapper.xml
@@ -2,8 +2,8 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.ycwl.basic.mapper.pc.FaceSampleMapper">
     <insert id="add">
-        insert into face_sample(id, scenic_id, device_id, source_id, face_url, match_sample_ids, first_match_rate, match_result,`status`)
-        values (#{id}, #{scenicId}, #{deviceId}, #{sourceId}, #{faceUrl}, #{matchSampleIds}, #{firstMatchRate}, #{matchResult},#{status})
+        insert into face_sample(id, scenic_id, device_id, source_id, face_url, match_sample_ids, first_match_rate, match_result,`status`, create_at)
+        values (#{id}, #{scenicId}, #{deviceId}, #{sourceId}, #{faceUrl}, #{matchSampleIds}, #{firstMatchRate}, #{matchResult},#{status},#{createAt})
     </insert>
     <update id="update">
         update face_sample
@@ -32,6 +32,10 @@
             <if test="status!= null ">
                 `status` = #{status},
             </if>
+            <if test="score!= null ">
+                `score` = #{score},
+            </if>
+            update_at = now(),
         </set>
         where id = #{id}
     </update>
@@ -81,7 +85,7 @@
         </where>
     </select>
     <select id="getById" resultType="com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO">
-        select id, scenic_id, device_id, face_url, match_sample_ids, first_match_rate, source_id, match_result,`status`
+        select id, scenic_id, device_id, face_url, match_sample_ids, first_match_rate, source_id, match_result,`status`, create_at
         from face_sample
         where id = #{id}
     </select>
diff --git a/src/main/resources/mapper/pc/SourceMapper.xml b/src/main/resources/mapper/pc/SourceMapper.xml
index 7f3e714..b454508 100644
--- a/src/main/resources/mapper/pc/SourceMapper.xml
+++ b/src/main/resources/mapper/pc/SourceMapper.xml
@@ -2,7 +2,8 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.ycwl.basic.mapper.pc.SourceMapper">
     <insert id="add">
-        insert into source(id, scenic_id, device_id, member_id, url) values (#{id}, #{scenicId}, #{deviceId}, #{memberId}, #{url})
+        insert into source(id, scenic_id, device_id, member_id, url, video_url, `type`, face_sample_id)
+        values (#{id}, #{scenicId}, #{deviceId}, #{memberId}, #{url}, #{videoUrl}, #{type}, #{faceSampleId})
     </insert>
     <update id="update">
         update source
@@ -11,7 +12,10 @@
             <if test="deviceId!= null">device_id = #{deviceId}, </if>
             <if test="memberId!= null">member_id = #{memberId}, </if>
             <if test="url!= null">url = #{url}, </if>
+            <if test="videoUrl!= null">video_url = #{videoUrl}, </if>
             <if test="isBuy!=null">is_buy = #{isBuy}, </if>
+            <if test="type!=null">`type` = #{type}, </if>
+            <if test="faceSampleId!= null">face_sample_id = #{faceSampleId}, </if>
         </set>
             where id = #{id}
     </update>
@@ -20,7 +24,7 @@
     </delete>
 
     <select id="list" resultType="com.ycwl.basic.model.pc.source.resp.SourceRespVO">
-        select so.id, scenic_id, device_id, member_id, url, so.create_time, so.update_time,sc.`name` as scenicName
+        select so.id, scenic_id, device_id, member_id, url, so.create_time, so.update_time,sc.`name` as scenicName, so.video_url, so.`type`, so.face_sample_id
             from source so
             left join scenic sc on sc.id = so.scenic_id
         <where>