From c27d094965eaa3007db3eab64455e9e2576a28ab Mon Sep 17 00:00:00 2001
From: Jerry Yan <792602257@qq.com>
Date: Sun, 15 Dec 2024 17:31:39 +0800
Subject: [PATCH] =?UTF-8?q?=E4=B9=B1=E4=B8=83=E5=85=AB=E7=B3=9F=E7=9A=84?=
 =?UTF-8?q?=E4=BF=AE=E6=94=B9=EF=BC=8C=E5=85=B6=E4=BB=96=E5=A4=96=E5=9B=B4?=
 =?UTF-8?q?=E6=B5=81=E7=A8=8B=E9=80=BB=E8=BE=91=E5=AE=8C=E5=96=84?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../com/ycwl/basic/config/SwaggerConfig.java  |  6 +-
 .../mobile/AppScenicController.java           |  2 +
 .../controller/task/TaskTaskController.java   |  6 ++
 .../com/ycwl/basic/mapper/FaceMapper.java     |  2 +-
 .../com/ycwl/basic/mapper/SourceMapper.java   |  4 +
 .../com/ycwl/basic/mapper/TaskMapper.java     |  4 +
 .../com/ycwl/basic/mapper/TemplateMapper.java |  1 +
 .../basic/model/pc/face/resp/FaceRespVO.java  |  2 +
 .../pc/faceSample/req/FaceSampleReqQuery.java |  5 +
 .../model/pc/task/entity/TaskEntity.java      |  1 +
 .../model/task/resp/SearchFaceRespVo.java     |  1 +
 .../service/impl/pc/FaceServiceImpl.java      | 71 +++++++------
 .../impl/task/TaskFaceServiceImpl.java        | 28 +++---
 .../impl/task/TaskTaskServiceImpl.java        | 99 ++++++++++++++++++-
 .../ycwl/basic/service/pc/TaskService.java    |  1 +
 .../basic/service/task/TaskFaceService.java   |  3 +
 .../ycwl/basic/service/task/TaskService.java  |  8 ++
 .../com/ycwl/basic/task/VideoPieceGetter.java | 18 +++-
 .../com/ycwl/basic/utils/JwtTokenUtil.java    |  4 +
 .../java/com/ycwl/basic/utils/OssUtil.java    |  6 ++
 src/main/resources/mapper/FaceMapper.xml      |  6 +-
 .../resources/mapper/FaceSampleMapper.xml     |  4 +-
 src/main/resources/mapper/SourceMapper.xml    | 19 +++-
 src/main/resources/mapper/TaskMapper.xml      | 23 ++++-
 src/main/resources/mapper/TemplateMapper.xml  |  7 +-
 25 files changed, 265 insertions(+), 66 deletions(-)

diff --git a/src/main/java/com/ycwl/basic/config/SwaggerConfig.java b/src/main/java/com/ycwl/basic/config/SwaggerConfig.java
index 8abeba1..9d59e2e 100644
--- a/src/main/java/com/ycwl/basic/config/SwaggerConfig.java
+++ b/src/main/java/com/ycwl/basic/config/SwaggerConfig.java
@@ -38,7 +38,7 @@ public class SwaggerConfig {
                 // 选择展示哪些接口
                 .select()
                 //只有com.zcy.e.firstaid包内的才去展示
-                .apis(RequestHandlerSelectors.basePackage("com.ycwl"))
+                .apis(RequestHandlerSelectors.basePackage("com.ycwl.basic.controller.mobile"))
                 .paths(PathSelectors.any())
                 .build()
                 .globalOperationParameters(getGlobalRequestParameters());
@@ -50,8 +50,8 @@ public class SwaggerConfig {
     public ApiInfo apiInfo() {
 
         return new ApiInfoBuilder()
-                .title("city-investment-smart-park")
-                .description("城投智慧园区")
+                .title("liuyin-re")
+                .description("流影重构")
                 .contact(new Contact("ycwl", "www.xxx.com", "xxxxxxxxx.com"))
                 .version("1.0")
                 .build();
diff --git a/src/main/java/com/ycwl/basic/controller/mobile/AppScenicController.java b/src/main/java/com/ycwl/basic/controller/mobile/AppScenicController.java
index e757d20..77de1e8 100644
--- a/src/main/java/com/ycwl/basic/controller/mobile/AppScenicController.java
+++ b/src/main/java/com/ycwl/basic/controller/mobile/AppScenicController.java
@@ -1,6 +1,7 @@
 package com.ycwl.basic.controller.mobile;
 
 import com.github.pagehelper.PageInfo;
+import com.ycwl.basic.annotation.IgnoreToken;
 import com.ycwl.basic.model.mobile.goods.GoodsPageVO;
 import com.ycwl.basic.model.mobile.goods.GoodsReqQuery;
 import com.ycwl.basic.model.mobile.scenic.ScenicAppVO;
@@ -36,6 +37,7 @@ public class AppScenicController {
         return appScenicService.pageQuery(scenicReqQuery);
     }
     @ApiOperation("根据id查询景区详情")
+    @IgnoreToken
     @GetMapping("getDetails/{id}")
     public ApiResponse<ScenicRespVO> getDetails(@PathVariable Long id){
         return appScenicService.getDetails(id);
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 335c5b9..a39308f 100644
--- a/src/main/java/com/ycwl/basic/controller/task/TaskTaskController.java
+++ b/src/main/java/com/ycwl/basic/controller/task/TaskTaskController.java
@@ -42,6 +42,12 @@ public class TaskTaskController {
         return ApiResponse.success(taskService.getUploadUrl(taskId, req));
     }
 
+    @PostMapping("/{taskId}/start")
+    public ApiResponse taskStart(@PathVariable Long taskId, @RequestBody WorkerAuthReqVo req) {
+        taskService.taskStart(taskId, req);
+        return ApiResponse.success("OK");
+    }
+
     @PostMapping("/{taskId}/success")
     public ApiResponse taskSuccess(@PathVariable Long taskId, @RequestBody WorkerAuthReqVo req) {
         taskService.taskSuccess(taskId, req);
diff --git a/src/main/java/com/ycwl/basic/mapper/FaceMapper.java b/src/main/java/com/ycwl/basic/mapper/FaceMapper.java
index 191993b..6a4a77f 100644
--- a/src/main/java/com/ycwl/basic/mapper/FaceMapper.java
+++ b/src/main/java/com/ycwl/basic/mapper/FaceMapper.java
@@ -23,7 +23,7 @@ public interface FaceMapper {
     int deleteByIds(@Param("list") List<Long> ids);
     int update(FaceEntity face);
 
-    FaceRespVO getByMemberId(Long userId);
+    FaceRespVO getByMemberId(@Param("userId") Long userId, @Param("scenicId") Long scenicId);
 
     int finishedJourney(Long faceId);
 }
diff --git a/src/main/java/com/ycwl/basic/mapper/SourceMapper.java b/src/main/java/com/ycwl/basic/mapper/SourceMapper.java
index 64b3758..fffa472 100644
--- a/src/main/java/com/ycwl/basic/mapper/SourceMapper.java
+++ b/src/main/java/com/ycwl/basic/mapper/SourceMapper.java
@@ -18,6 +18,8 @@ public interface SourceMapper {
 
     SourceRespVO getById(Long id);
 
+    List<SourceEntity> listBySampleIds(List<Long> sourceIds);
+
     int add(SourceEntity source);
 
     int deleteById(Long id);
@@ -37,4 +39,6 @@ public interface SourceMapper {
      * @return
      */
     int countByMemberId(String userId);
+
+    List<SourceEntity> listVideoBySampleIds(List<Long> sampleId);
 }
diff --git a/src/main/java/com/ycwl/basic/mapper/TaskMapper.java b/src/main/java/com/ycwl/basic/mapper/TaskMapper.java
index cc7a407..3413c62 100644
--- a/src/main/java/com/ycwl/basic/mapper/TaskMapper.java
+++ b/src/main/java/com/ycwl/basic/mapper/TaskMapper.java
@@ -50,4 +50,8 @@ public interface TaskMapper {
     void deassign(@Param("taskId") Long taskId);
 
     int countTask(TaskReqQuery taskReqQuery);
+
+    int setStart(TaskEntity taskUpdate);
+    int setSuccess(TaskEntity taskUpdate);
+    int setFail(TaskEntity taskUpdate);
 }
diff --git a/src/main/java/com/ycwl/basic/mapper/TemplateMapper.java b/src/main/java/com/ycwl/basic/mapper/TemplateMapper.java
index e702993..5245606 100644
--- a/src/main/java/com/ycwl/basic/mapper/TemplateMapper.java
+++ b/src/main/java/com/ycwl/basic/mapper/TemplateMapper.java
@@ -32,4 +32,5 @@ public interface TemplateMapper {
     int updateConfigById(TemplateConfigEntity templateConfigEntity);
     int deleteConfigByTemplateId(Long templateId);
     int deleteConfigById(Long id);
+    List<TemplateEntity> listByScenicId(Long scenicId);
 }
diff --git a/src/main/java/com/ycwl/basic/model/pc/face/resp/FaceRespVO.java b/src/main/java/com/ycwl/basic/model/pc/face/resp/FaceRespVO.java
index 0bed9c6..ac7904e 100644
--- a/src/main/java/com/ycwl/basic/model/pc/face/resp/FaceRespVO.java
+++ b/src/main/java/com/ycwl/basic/model/pc/face/resp/FaceRespVO.java
@@ -16,6 +16,8 @@ import java.util.Date;
 @ApiModel("人脸查询响应参数")
 public class FaceRespVO {
     private Long id;
+    @ApiModelProperty("景区ID")
+    private Long scenicId;
     @ApiModelProperty("会员id")
     private Long memberId;
     @ApiModelProperty("用户上传的人脸照片")
diff --git a/src/main/java/com/ycwl/basic/model/pc/faceSample/req/FaceSampleReqQuery.java b/src/main/java/com/ycwl/basic/model/pc/faceSample/req/FaceSampleReqQuery.java
index 0dd67c9..bed59ce 100644
--- a/src/main/java/com/ycwl/basic/model/pc/faceSample/req/FaceSampleReqQuery.java
+++ b/src/main/java/com/ycwl/basic/model/pc/faceSample/req/FaceSampleReqQuery.java
@@ -26,6 +26,11 @@ public class FaceSampleReqQuery extends BaseQueryParameterReq {
      */
     @ApiModelProperty("来源设备")
     private Long deviceId;
+    /**
+     * 来源ID
+     */
+    @ApiModelProperty("来源ID")
+    private Long sourceId;
     /**
      * 人脸照片
      */
diff --git a/src/main/java/com/ycwl/basic/model/pc/task/entity/TaskEntity.java b/src/main/java/com/ycwl/basic/model/pc/task/entity/TaskEntity.java
index 64b9eeb..9f9d829 100644
--- a/src/main/java/com/ycwl/basic/model/pc/task/entity/TaskEntity.java
+++ b/src/main/java/com/ycwl/basic/model/pc/task/entity/TaskEntity.java
@@ -54,4 +54,5 @@ public class TaskEntity {
     private String result;
     private Date createTime;
     private Date updateTime;
+    private Integer automatic;
 }
diff --git a/src/main/java/com/ycwl/basic/model/task/resp/SearchFaceRespVo.java b/src/main/java/com/ycwl/basic/model/task/resp/SearchFaceRespVo.java
index 99dc3cf..074e80f 100644
--- a/src/main/java/com/ycwl/basic/model/task/resp/SearchFaceRespVo.java
+++ b/src/main/java/com/ycwl/basic/model/task/resp/SearchFaceRespVo.java
@@ -8,4 +8,5 @@ import java.util.List;
 public class SearchFaceRespVo {
     private float score;
     private List<Long> sampleListIds;
+    private String searchResultJson;
 }
diff --git a/src/main/java/com/ycwl/basic/service/impl/pc/FaceServiceImpl.java b/src/main/java/com/ycwl/basic/service/impl/pc/FaceServiceImpl.java
index 2341cc5..afd5af0 100644
--- a/src/main/java/com/ycwl/basic/service/impl/pc/FaceServiceImpl.java
+++ b/src/main/java/com/ycwl/basic/service/impl/pc/FaceServiceImpl.java
@@ -15,6 +15,7 @@ import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
 import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
 import com.ycwl.basic.service.pc.FaceService;
 import com.ycwl.basic.service.task.TaskFaceService;
+import com.ycwl.basic.service.task.TaskService;
 import com.ycwl.basic.utils.*;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -26,6 +27,8 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.util.Date;
 import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
 
 /**
  * @Author:longbinbin
@@ -45,6 +48,8 @@ public class FaceServiceImpl implements FaceService {
 
     @Value("${face.score}")
     private float faceScore;
+    @Autowired
+    private TaskService taskTaskService;
 
     @Override
     public ApiResponse<PageInfo<FaceRespVO>> pageQuery(FaceReqQuery faceReqQuery) {
@@ -110,53 +115,55 @@ public class FaceServiceImpl implements FaceService {
         log.info("当前登录用户信息:{}",worker);
 
         //1、上传人脸照片
-        String facaeUrl = uploadFileALiOss(file, userId);
+        String faceUrl = uploadFileALiOss(file, userId);
+        SearchFaceRespVo searchFaceRespVo = faceService.searchFace(scenicId, faceUrl);
+        float score = searchFaceRespVo.getScore();
+        if (score<faceScore) {
+            //校验失败,删除,提示重新上传
+            ossUtil.deleteFileByUrl(faceUrl);
+
+            throw new BaseException("人脸照片校验失败,请重新上传");
+        }
         // 2、查看人脸是否已上传
-        FaceRespVO faceRespVO=faceMapper.getByMemberId(userId);
+        FaceRespVO faceRespVO=faceMapper.getByMemberId(userId, scenicId);
 
         FaceEntity faceEntity = new FaceEntity();
+        faceEntity.setScore(searchFaceRespVo.getScore());
+        faceEntity.setMatchResult(searchFaceRespVo.getSearchResultJson());
+        faceEntity.setMatchSampleIds(searchFaceRespVo.getSampleListIds().stream().map(String::valueOf).collect(Collectors.joining(",")));
+        faceEntity.setCreateAt(new Date());
+        faceEntity.setScenicId(scenicId);
+        faceEntity.setMemberId(userId);
+        faceEntity.setFaceUrl(faceUrl);
         if (faceRespVO==null) {
             //新增人脸
             faceEntity.setId(SnowFlakeUtil.getLongId());
-            faceEntity.setMemberId(userId);
-            faceEntity.setFaceUrl(facaeUrl);
-//            faceEntity.setScore();
-//            faceEntity.setMatchSampleIds();
-//            faceEntity.setFirstMatchRate();
-//            faceEntity.setMatchResult();
-            //TODO 人脸数据存库
             faceMapper.add(faceEntity);
+            taskTaskService.autoCreateTaskByFaceId(faceEntity.getId());
         }else {
             //2、更新人脸
-            faceRespVO.setFaceUrl(facaeUrl);
-            BeanUtil.copyProperties(faceRespVO,faceEntity);
+            faceEntity.setId(faceRespVO.getId());
             faceMapper.update(faceEntity);
+            if (!Objects.equals(
+                    faceRespVO.getMatchSampleIds(),
+                    searchFaceRespVo.getSampleListIds().stream().map(String::valueOf).collect(Collectors.joining(","))
+            )) {
+                taskTaskService.autoCreateTaskByFaceId(faceEntity.getId());
+            }
         }
-        SearchFaceRespVo faceRespVo = faceService.searchFace(scenicId, faceEntity.getId());
-        float score = faceRespVo.getScore();
-        if (score<faceScore) {
-            //校验失败,删除,提示重新上传
-            ossUtil.deleteFile(facaeUrl);
-
-            throw new BaseException("人脸照片校验失败,请重新上传");
-        }else {
-            StatisticsRecordAddReq statisticsRecordAddReq = new StatisticsRecordAddReq();
-            statisticsRecordAddReq.setMemberId(userId);
-            statisticsRecordAddReq.setType(StatisticEnum.UPLOAD_FACE.code);
-            statisticsRecordAddReq.setScenicId(scenicId);
-            statisticsRecordAddReq.setMorphId(faceEntity.getId());
-            statisticsMapper.addStatisticsRecord(statisticsRecordAddReq);
-            //校验成功,保存用户人脸信息,将访问人脸照片访问地址响应给前端
-            return ApiResponse.success(facaeUrl);
-        }
-
-
-
+        StatisticsRecordAddReq statisticsRecordAddReq = new StatisticsRecordAddReq();
+        statisticsRecordAddReq.setMemberId(userId);
+        statisticsRecordAddReq.setType(StatisticEnum.UPLOAD_FACE.code);
+        statisticsRecordAddReq.setScenicId(scenicId);
+        statisticsRecordAddReq.setMorphId(faceEntity.getId());
+        statisticsMapper.addStatisticsRecord(statisticsRecordAddReq);
+        return ApiResponse.success(faceUrl);
     }
 
     @Override
     public ApiResponse<FaceRespVO> getFaceByMemberId(Long memberId) {
-        return ApiResponse.success(faceMapper.getByMemberId(memberId));
+        // TODO: 修改
+        return ApiResponse.success(faceMapper.getByMemberId(memberId, 3928516560393736192L));
     }
 
     /**
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 70d94a8..6435d72 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
@@ -11,7 +11,6 @@ import com.aliyuncs.facebody.model.v20191230.SearchFaceRequest;
 import com.aliyuncs.facebody.model.v20191230.SearchFaceResponse;
 import com.ycwl.basic.config.FaceDetectConfig;
 import com.ycwl.basic.exception.BaseException;
-import com.ycwl.basic.mapper.DeviceMapper;
 import com.ycwl.basic.mapper.FaceMapper;
 import com.ycwl.basic.mapper.FaceSampleMapper;
 import com.ycwl.basic.mapper.ScenicMapper;
@@ -46,9 +45,6 @@ public class TaskFaceServiceImpl implements TaskFaceService {
     private FaceSampleMapper faceSampleMapper;
     @Autowired
     private ScenicMapper scenicMapper;
-    private static final String DATE_FORMAT="yyyyMMddHHmmssSSS";
-    @Autowired
-    private DeviceMapper deviceMapper;
     @Autowired
     private FaceDetectConfig faceDetectConfig;
 
@@ -61,10 +57,24 @@ public class TaskFaceServiceImpl implements TaskFaceService {
     @Override
     public SearchFaceRespVo searchFace(Long scenicId, Long faceId) {
         FaceRespVO faceRespVO = faceMapper.getById(faceId);
+        SearchFaceRespVo respVo = searchFace(scenicId, faceRespVO.getFaceUrl());
+        if (respVo != null) {
+            FaceEntity faceEntity = new FaceEntity();
+            faceEntity.setId(faceId);
+            faceEntity.setMatchResult(respVo.getSearchResultJson());
+            faceEntity.setScore(respVo.getScore());
+            faceEntity.setMatchSampleIds(StringUtils.join(respVo.getSampleListIds(), ","));
+            faceMapper.update(faceEntity);
+        }
+        return respVo;
+    }
+
+    @Override
+    public SearchFaceRespVo searchFace(Long scenicId, String faceUrl) {
         IAcsClient client = getClient();
         SearchFaceRequest request = new SearchFaceRequest();
         request.setDbName(scenicId.toString());
-        request.setImageUrl(faceRespVO.getFaceUrl());
+        request.setImageUrl(faceUrl);
         request.setLimit(100);
         request.setQualityScoreThreshold(80F);
         try {
@@ -74,18 +84,13 @@ public class TaskFaceServiceImpl implements TaskFaceService {
                 return null;
             }
             SearchFaceRespVo respVo = new SearchFaceRespVo();
-            FaceEntity faceEntity = new FaceEntity();
-            faceEntity.setId(faceId);
-            faceEntity.setMatchResult(JSON.toJSONString(matchList));
-            faceEntity.setScore(matchList.get(0).getQualitieScore());
             List<SearchFaceResponse.Data.MatchListItem.FaceItemsItem> faceItems = matchList.get(0).getFaceItems().stream()
                     .filter(faceItemsItem -> faceItemsItem.getConfidence() > 50).collect(Collectors.toList());
             List<Long> faceSampleIds = faceItems.stream()
                     .map(SearchFaceResponse.Data.MatchListItem.FaceItemsItem::getExtraData)
                     .map(Long::parseLong)
                     .collect(Collectors.toList());
-            faceEntity.setMatchSampleIds(StringUtils.join(faceSampleIds, ","));
-            faceMapper.update(faceEntity);
+            respVo.setSearchResultJson(JSON.toJSONString(matchList.get(0)));
             respVo.setSampleListIds(faceSampleIds);
             respVo.setScore(matchList.get(0).getQualitieScore());
             return respVo;
@@ -93,7 +98,6 @@ public class TaskFaceServiceImpl implements TaskFaceService {
             log.error("人脸搜索失败:{}", e.getMessage());
             throw new BaseException(e.getMessage());
         }
-//        return null;
     }
 
     @Override
diff --git a/src/main/java/com/ycwl/basic/service/impl/task/TaskTaskServiceImpl.java b/src/main/java/com/ycwl/basic/service/impl/task/TaskTaskServiceImpl.java
index 4a9129d..a7fda93 100644
--- a/src/main/java/com/ycwl/basic/service/impl/task/TaskTaskServiceImpl.java
+++ b/src/main/java/com/ycwl/basic/service/impl/task/TaskTaskServiceImpl.java
@@ -2,6 +2,11 @@ package com.ycwl.basic.service.impl.task;
 
 import com.alibaba.fastjson.JSON;
 import com.ycwl.basic.constant.TaskConstant;
+import com.ycwl.basic.device.DeviceFactory;
+import com.ycwl.basic.device.operator.IDeviceStorageOperator;
+import com.ycwl.basic.mapper.DeviceMapper;
+import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
+import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
 import com.ycwl.basic.mapper.FaceMapper;
 import com.ycwl.basic.mapper.FaceSampleMapper;
 import com.ycwl.basic.mapper.RenderWorkerMapper;
@@ -12,9 +17,11 @@ import com.ycwl.basic.mapper.VideoMapper;
 import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
 import com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO;
 import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity;
+import com.ycwl.basic.model.pc.source.entity.SourceEntity;
 import com.ycwl.basic.model.pc.source.resp.SourceRespVO;
 import com.ycwl.basic.model.pc.task.entity.TaskEntity;
 import com.ycwl.basic.model.pc.task.resp.TaskRespVO;
+import com.ycwl.basic.model.pc.template.entity.TemplateEntity;
 import com.ycwl.basic.model.pc.template.req.TemplateReqQuery;
 import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
 import com.ycwl.basic.model.pc.video.entity.VideoEntity;
@@ -23,6 +30,7 @@ import com.ycwl.basic.model.task.req.TaskReqVo;
 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.task.VideoPieceGetter;
 import com.ycwl.basic.utils.OssUtil;
 import com.ycwl.basic.utils.SnowFlakeUtil;
 import lombok.NonNull;
@@ -38,6 +46,7 @@ import java.util.Date;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
+import java.util.Optional;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
@@ -163,6 +172,92 @@ public class TaskTaskServiceImpl implements TaskService {
         return respVO;
     }
 
+    @Override
+    public void taskStart(@NonNull Long taskId, @NonNull WorkerAuthReqVo req) {
+        TaskRespVO task = taskMapper.getById(taskId);
+        if (task == null) {
+            return;
+        }
+        RenderWorkerEntity worker = getWorker(req);
+        if (worker == null) {
+            return;
+        }
+        TaskEntity taskUpdate = new TaskEntity();
+        taskUpdate.setId(taskId);
+        taskUpdate.setWorkerId(worker.getId());
+        taskMapper.setStart(taskUpdate);
+    }
+
+    @Override
+    public void autoCreateTaskByFaceId(Long id) {
+        FaceRespVO faceRespVO = faceMapper.getById(id);
+        List<FaceSampleRespVO> faceSampleList = faceSampleMapper.listByIds(Arrays.stream(faceRespVO.getMatchSampleIds().split(",")).map(Long::valueOf).collect(Collectors.toList()));
+        if (faceSampleList.isEmpty()) {
+            return;
+        }
+        List<TemplateEntity> templateList = templateMapper.listByScenicId(faceRespVO.getScenicId());
+        if (templateList == null || templateList.isEmpty()) {
+            return;
+        }
+        autoCreateTaskByFaceIdAndTempalteId(id, templateList.get(0).getId(), 1);
+    }
+    @Override
+    public void autoCreateTaskByFaceIdAndTempalteId(Long faceId, Long templateId) {
+        autoCreateTaskByFaceIdAndTempalteId(faceId, templateId, 0);
+    }
+
+    @Override
+    public void autoCreateTaskByFaceIdAndTempalteId(Long faceId, Long templateId, int automatic) {
+        FaceRespVO faceRespVO = faceMapper.getById(faceId);
+        List<FaceSampleRespVO> faceSampleList = faceSampleMapper.listByIds(Arrays.stream(faceRespVO.getMatchSampleIds().split(",")).map(Long::valueOf).collect(Collectors.toList()));
+        if (faceSampleList.isEmpty()) {
+            return;
+        }
+        List<SourceEntity> sourceList = sourceMapper.listBySampleIds(faceSampleList.stream().map(FaceSampleRespVO::getId).collect(Collectors.toList()));
+        if (sourceList.isEmpty()) {
+            return;
+        }
+        Thread taskThread = new Thread(() -> {
+            List<SourceEntity> vSourceList = sourceMapper.listVideoBySampleIds(faceSampleList.stream().map(FaceSampleRespVO::getId).collect(Collectors.toList()));
+            List<VideoPieceGetter.Task> tasks = faceSampleList.stream().map(sample -> {
+                Optional<SourceEntity> optional = vSourceList.stream().filter(video -> video.getFaceSampleId().equals(sample.getId())).findFirst();
+                if (optional.isPresent()) {
+                    return null;
+                }
+                VideoPieceGetter.Task task = new VideoPieceGetter.Task();
+                task.setFaceSampleId(sample.getId());
+                task.setDeviceId(sample.getDeviceId());
+                task.setCreateTime(sample.getCreateAt());
+                return task;
+            }).filter(Objects::nonNull).collect(Collectors.toList());
+            VideoPieceGetter.Task task = new VideoPieceGetter.Task();
+            task.setType("callback");
+            task.setCallback(() -> {
+                List<SourceEntity> videoSourceList = sourceMapper.listVideoBySampleIds(faceSampleList.stream().map(FaceSampleRespVO::getId).collect(Collectors.toList()));
+                Map<String, List<SourceEntity>> sourcesMap = videoSourceList.stream()
+                        .peek(item -> item.setUrl(item.getVideoUrl()))
+                        .collect(Collectors.groupingBy(item -> item.getDeviceId().toString()));
+                TaskEntity taskEntity = new TaskEntity();
+                taskEntity.setId(SnowFlakeUtil.getLongId());
+                taskEntity.setScenicId(faceRespVO.getScenicId());
+                taskEntity.setFaceId(faceId);
+                taskEntity.setMemberId(faceRespVO.getMemberId());
+                taskEntity.setTemplateId(templateId);
+                taskEntity.setTaskParams(JSON.toJSONString(sourcesMap));
+                taskEntity.setStatus(0);
+                taskEntity.setAutomatic(automatic);
+                taskMapper.add(taskEntity);
+            });
+            if (!tasks.isEmpty()) {
+                tasks.forEach(VideoPieceGetter::addTask);
+                VideoPieceGetter.addTask(task);
+            } else {
+                task.getCallback().onInvoke();
+            }
+        });
+        taskThread.start();
+    }
+
     @Override
     public void taskSuccess(@NonNull Long taskId, @NonNull WorkerAuthReqVo req) {
         TaskRespVO task = taskMapper.getById(taskId);
@@ -177,7 +272,7 @@ public class TaskTaskServiceImpl implements TaskService {
         taskUpdate.setId(taskId);
         taskUpdate.setStatus(1);
         taskUpdate.setWorkerId(worker.getId());
-        taskMapper.update(taskUpdate);
+        taskMapper.setSuccess(taskUpdate);
         VideoEntity video = videoMapper.findByTaskId(taskId);
         if (video != null) {
             video.setVideoUrl(task.getVideoUrl());
@@ -210,7 +305,7 @@ public class TaskTaskServiceImpl implements TaskService {
         taskUpdate.setId(taskId);
         taskUpdate.setStatus(2);
         taskUpdate.setWorkerId(worker.getId());
-        taskMapper.update(taskUpdate);
+        taskMapper.setFail(taskUpdate);
         taskMapper.deassign(taskId);
     }
 
diff --git a/src/main/java/com/ycwl/basic/service/pc/TaskService.java b/src/main/java/com/ycwl/basic/service/pc/TaskService.java
index d514c06..5326632 100644
--- a/src/main/java/com/ycwl/basic/service/pc/TaskService.java
+++ b/src/main/java/com/ycwl/basic/service/pc/TaskService.java
@@ -20,4 +20,5 @@ public interface TaskService {
     ApiResponse<Boolean> deleteById(Long id);
     ApiResponse<Boolean> update(TaskEntity task);
     ApiResponse<Boolean> updateStatus(Long id,Integer status);
+
 }
diff --git a/src/main/java/com/ycwl/basic/service/task/TaskFaceService.java b/src/main/java/com/ycwl/basic/service/task/TaskFaceService.java
index 76a2eaf..0a1d8e7 100644
--- a/src/main/java/com/ycwl/basic/service/task/TaskFaceService.java
+++ b/src/main/java/com/ycwl/basic/service/task/TaskFaceService.java
@@ -1,5 +1,6 @@
 package com.ycwl.basic.service.task;
 
+import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
 import com.ycwl.basic.model.task.resp.AddFaceRespVo;
 import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
 
@@ -7,6 +8,8 @@ public interface TaskFaceService {
 
     SearchFaceRespVo searchFace(Long scenicId, Long faceId);
 
+    SearchFaceRespVo searchFace(Long scenicId, String faceUrl);
+
     AddFaceRespVo addFaceSample(Long faceSampleId);
 
     void batchDeleteFace(Long scenicId);
diff --git a/src/main/java/com/ycwl/basic/service/task/TaskService.java b/src/main/java/com/ycwl/basic/service/task/TaskService.java
index 85366ed..da07160 100644
--- a/src/main/java/com/ycwl/basic/service/task/TaskService.java
+++ b/src/main/java/com/ycwl/basic/service/task/TaskService.java
@@ -11,9 +11,17 @@ public interface TaskService {
 
     TemplateRespVO workerGetTemplate(Long templateId, WorkerAuthReqVo req);
 
+    void autoCreateTaskByFaceIdAndTempalteId(Long faceId, Long templateId);
+
+    void autoCreateTaskByFaceIdAndTempalteId(Long faceId, Long templateId, int automatic);
+
     void taskSuccess(Long taskId, WorkerAuthReqVo req);
 
     void taskFail(Long taskId, WorkerAuthReqVo req);
 
     String getUploadUrl(Long taskId, WorkerAuthReqVo req);
+
+    void taskStart(Long taskId, WorkerAuthReqVo req);
+
+    void autoCreateTaskByFaceId(Long id);
 }
diff --git a/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java b/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java
index df6d6fc..bf47771 100644
--- a/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java
+++ b/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java
@@ -11,6 +11,7 @@ import com.ycwl.basic.model.pc.device.entity.DeviceEntity;
 import com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO;
 import com.ycwl.basic.model.pc.source.entity.SourceEntity;
 import com.ycwl.basic.utils.OssUtil;
+import com.ycwl.basic.utils.SnowFlakeUtil;
 import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -49,9 +50,15 @@ public class VideoPieceGetter {
 
     @Data
     public static class Task {
+        public String type = "normal";
         public Long deviceId;
         public Long faceSampleId;
         public Date createTime;
+        public Callback callback;
+
+        public static interface Callback {
+            void onInvoke();
+        }
     }
     @Data
     public static class FfmpegTask {
@@ -67,13 +74,17 @@ public class VideoPieceGetter {
         queue.add(task);
     }
 
-    @Scheduled(fixedDelay = 5000L)
+    @Scheduled(fixedDelay = 1000L)
     public void doTask() {
         Task task = queue.poll();
         if (task == null) {
             return;
         }
         log.info("poll task: {}", task);
+        if (!task.getType().equalsIgnoreCase("normal")) {
+            task.getCallback().onInvoke();
+            return;
+        }
         FaceSampleRespVO faceSample = faceSampleMapper.getById(task.getFaceSampleId());
         DeviceEntity device = deviceMapper.getByDeviceId(task.getDeviceId());
         DeviceConfigEntity config = deviceMapper.getConfigByDeviceId(task.getDeviceId());
@@ -98,10 +109,6 @@ public class VideoPieceGetter {
                 new Date(task.getCreateTime().getTime() - cutPre.multiply(BigDecimal.valueOf(1000)).longValue()),
                 new Date(task.getCreateTime().getTime() + cutPost.multiply(BigDecimal.valueOf(1000)).longValue())
         );
-        if (listByDtRange.isEmpty()) {
-            queue.add(task);
-            return;
-        }
         long offset = task.getCreateTime().getTime() - listByDtRange.get(0).getCreateTime().getTime();
         FfmpegTask ffmpegTask = new FfmpegTask();
         ffmpegTask.setFileList(listByDtRange);
@@ -119,6 +126,7 @@ public class VideoPieceGetter {
             InputStream inputStream = new FileInputStream(outFile);
             String url = ossUtil.uploadFile(inputStream, "user-video-source", outFile.getName());
             SourceEntity sourceEntity = new SourceEntity();
+            sourceEntity.setId(SnowFlakeUtil.getLongId());
             sourceEntity.setVideoUrl(url);
             sourceEntity.setFaceSampleId(faceSample.getId());
             sourceEntity.setScenicId(faceSample.getScenicId());
diff --git a/src/main/java/com/ycwl/basic/utils/JwtTokenUtil.java b/src/main/java/com/ycwl/basic/utils/JwtTokenUtil.java
index 9a7fba2..63eb087 100644
--- a/src/main/java/com/ycwl/basic/utils/JwtTokenUtil.java
+++ b/src/main/java/com/ycwl/basic/utils/JwtTokenUtil.java
@@ -44,6 +44,10 @@ public class JwtTokenUtil {
      */
     public String generateToken(JwtInfo jwtInfo) throws Exception {
         // 过期时间,默认 15 天
+        return generateToken(jwtInfo, expire);
+    }
+
+    public static String generateToken(JwtInfo jwtInfo, int expire) throws Exception {
         LocalDateTime expireTime = LocalDateTime.now().plusDays(expire);
         byte[] bytes = RsaKeyUtil.toBytes(PRI_KEY);
         String token = JwtAnalysisUtil.generateToken(jwtInfo, bytes, expireTime);
diff --git a/src/main/java/com/ycwl/basic/utils/OssUtil.java b/src/main/java/com/ycwl/basic/utils/OssUtil.java
index 042be00..d6f9d20 100644
--- a/src/main/java/com/ycwl/basic/utils/OssUtil.java
+++ b/src/main/java/com/ycwl/basic/utils/OssUtil.java
@@ -14,6 +14,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import java.io.InputStream;
+import java.net.URI;
 import java.util.Date;
 
 @Slf4j
@@ -117,4 +118,9 @@ public class OssUtil {
         return false;
     }
 
+    public void deleteFileByUrl(String faceUrl) {
+        URI uri = URI.create(faceUrl);
+        String objectName = uri.getPath();
+        deleteFile(objectName);
+    }
 }
diff --git a/src/main/resources/mapper/FaceMapper.xml b/src/main/resources/mapper/FaceMapper.xml
index 3395255..df84e54 100644
--- a/src/main/resources/mapper/FaceMapper.xml
+++ b/src/main/resources/mapper/FaceMapper.xml
@@ -77,13 +77,13 @@
         where id = #{id}
     </select>
     <select id="getByMemberId" resultType="com.ycwl.basic.model.pc.face.resp.FaceRespVO">
-        select id, member_id, face_url,score, match_sample_ids, first_match_rate, match_result, create_at, update_at
+        select id, scenic_id, member_id, face_url,score, match_sample_ids, first_match_rate, match_result, create_at, update_at
         from face
-        where member_id = #{memberId}
+        where member_id = #{userId} and scenic_id = #{scenicId}
     </select>
     <select id="listByScenicIdAndNotFinished" resultType="com.ycwl.basic.model.pc.face.resp.FaceRespVO">
         select id, scenic_id, member_id, face_url,score, match_sample_ids, first_match_rate, match_result, create_at, update_at
         from face
         where scenic_id = #{scenicId} and finished_journey != 1
     </select>
-</mapper>
\ No newline at end of file
+</mapper>
diff --git a/src/main/resources/mapper/FaceSampleMapper.xml b/src/main/resources/mapper/FaceSampleMapper.xml
index 86e74d5..78e53d4 100644
--- a/src/main/resources/mapper/FaceSampleMapper.xml
+++ b/src/main/resources/mapper/FaceSampleMapper.xml
@@ -90,7 +90,7 @@
         where id = #{id}
     </select>
     <select id="listByIds" 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 in (
         <foreach collection="list" item="id" separator=",">
@@ -98,4 +98,4 @@
         </foreach>
         )
     </select>
-</mapper>
\ No newline at end of file
+</mapper>
diff --git a/src/main/resources/mapper/SourceMapper.xml b/src/main/resources/mapper/SourceMapper.xml
index c13eaed..e3c414e 100644
--- a/src/main/resources/mapper/SourceMapper.xml
+++ b/src/main/resources/mapper/SourceMapper.xml
@@ -63,4 +63,21 @@
     <select id="countByMemberId" resultType="java.lang.Integer">
         select count(1) from source where  member_id = #{userId}
     </select>
-</mapper>
\ No newline at end of file
+    <select id="listBySampleIds" resultType="com.ycwl.basic.model.pc.source.entity.SourceEntity">
+        select *
+        from source
+        where face_sample_id in
+        <foreach collection="list" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+    </select>
+    <select id="listVideoBySampleIds" resultType="com.ycwl.basic.model.pc.source.entity.SourceEntity">
+        select *
+        from source
+        where face_sample_id in
+        <foreach collection="list" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+        and type = 1
+    </select>
+</mapper>
diff --git a/src/main/resources/mapper/TaskMapper.xml b/src/main/resources/mapper/TaskMapper.xml
index 4b36379..9b3005f 100644
--- a/src/main/resources/mapper/TaskMapper.xml
+++ b/src/main/resources/mapper/TaskMapper.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.TaskMapper">
     <insert id="add">
-        insert into task(id, worker_id, member_id, template_id, scenic_id, task_params, video_url, `status`, result)
-        values (#{id}, #{workerId}, #{memberId}, #{templateId}, #{scenicId}, #{taskParams}, #{videoUrl}, #{status}, #{result})
+        insert into task(id, worker_id, member_id, face_id, template_id, scenic_id, task_params, video_url, `status`, result, automatic)
+        values (#{id}, #{workerId}, #{memberId}, #{faceId}, #{templateId}, #{scenicId}, #{taskParams}, #{videoUrl}, #{status}, #{result}, #{automatic})
     </insert>
     <update id="update">
         update task
@@ -35,11 +35,26 @@
         set worker_id = null
         where id = #{taskId}
     </update>
+    <update id="setStart">
+        update task
+        set start_time = now(), worker_id = #{workerId}
+        where id = #{id}
+    </update>
+    <update id="setSuccess">
+        update task
+        set end_time = now(), status = 1, result = #{result}
+        where id = #{id}
+    </update>
+    <update id="setFail">
+        update task
+        set end_time = now(), status = 3, result = #{result}
+        where id = #{id}
+    </update>
     <delete id="deleteById">
         delete from task where id = #{id}
     </delete>
     <select id="list" resultType="com.ycwl.basic.model.pc.task.resp.TaskRespVO">
-        select id, worker_id, member_id, template_id, scenic_id, task_params, video_url, `status`, result, create_time, update_time
+        select id, worker_id, member_id, template_id, scenic_id, task_params, video_url, `status`, result, create_time, update_time, start_time, end_time
 from task
         <where>
             <if test="workerId!= null">and worker_id = #{workerId} </if>
@@ -83,4 +98,4 @@ from task
             <if test="endTime!= null">and create_time &lt;= #{endTime} </if>
         </where>
     </select>
-</mapper>
\ No newline at end of file
+</mapper>
diff --git a/src/main/resources/mapper/TemplateMapper.xml b/src/main/resources/mapper/TemplateMapper.xml
index b0e5a22..184dd0a 100644
--- a/src/main/resources/mapper/TemplateMapper.xml
+++ b/src/main/resources/mapper/TemplateMapper.xml
@@ -91,4 +91,9 @@
     <select id="getConfig" resultType="com.ycwl.basic.model.pc.template.entity.TemplateConfigEntity">
         select * from template_config where template_id = #{templateId}
     </select>
-</mapper>
\ No newline at end of file
+    <select id="listByScenicId" resultType="com.ycwl.basic.model.pc.template.entity.TemplateEntity">
+        select *
+        from template
+        where scenic_id = #{scenicId} and pid = 0
+    </select>
+</mapper>