From 02548a3028681fe2dfa632dd88df1665d64c3597 Mon Sep 17 00:00:00 2001
From: Jerry Yan <792602257@qq.com>
Date: Mon, 13 Jan 2025 10:26:18 +0800
Subject: [PATCH] bug

---
 .../java/com/ycwl/basic/biz/OrderBiz.java     |  25 +-
 .../mobile/AppWxNotifyController.java         |  46 +++-
 .../basic/controller/pc/FaceController.java   |   5 -
 .../basic/controller/viid/ViidController.java |   4 +-
 .../basic/controller/wvp/WvpController.java   |   1 +
 .../com/ycwl/basic/mapper/SourceMapper.java   |   1 +
 .../ycwl/basic/mapper/SourceTaskMapper.java   |   7 +
 .../com/ycwl/basic/mapper/TemplateMapper.java |   1 +
 .../basic/model/pc/mp/ScenicMpNotifyVO.java   |   2 +
 .../pc/source/entity/SourceTaskEntity.java    |  22 ++
 .../repository/DeviceRepository.java          |   2 +-
 .../ycwl/basic/repository/FaceRepository.java |  32 ++-
 .../basic/repository/OrderRepository.java     |   5 +-
 .../basic/repository/ScenicRepository.java    |  22 ++
 .../basic/repository/TemplateRepository.java  |  16 +-
 .../service/impl/mobile/GoodsServiceImpl.java |  44 +--
 .../service/impl/mobile/WxPayServiceImpl.java |   6 +-
 .../service/impl/pc/DeviceServiceImpl.java    |   3 +-
 .../service/impl/pc/FaceServiceImpl.java      |  23 +-
 .../service/impl/pc/TemplateServiceImpl.java  |   1 +
 .../ycwl/basic/service/pc/FaceService.java    |   1 -
 .../ycwl/basic/service/task/TaskService.java  |   2 +-
 .../task/impl/TaskFaceServiceImpl.java        |  10 +-
 .../task/impl/TaskTaskServiceImpl.java        |  58 ++--
 .../service/wvp/impl/WvpServiceImpl.java      |   2 +-
 .../ycwl/basic/task/DynamicTaskGenerator.java |   4 -
 .../com/ycwl/basic/task/VideoPieceGetter.java | 258 ++++++++++--------
 src/main/resources/mapper/DeviceMapper.xml    |   1 +
 .../resources/mapper/FaceSampleMapper.xml     |   1 +
 .../resources/mapper/MpNotifyConfigMapper.xml |   2 +-
 src/main/resources/mapper/SourceMapper.xml    |   7 +
 src/main/resources/mapper/TaskMapper.xml      |   2 +-
 src/main/resources/mapper/TemplateMapper.xml  |   5 +
 33 files changed, 399 insertions(+), 222 deletions(-)
 create mode 100644 src/main/java/com/ycwl/basic/mapper/SourceTaskMapper.java
 create mode 100644 src/main/java/com/ycwl/basic/model/pc/source/entity/SourceTaskEntity.java
 rename src/main/java/com/ycwl/basic/{device => }/repository/DeviceRepository.java (98%)

diff --git a/src/main/java/com/ycwl/basic/biz/OrderBiz.java b/src/main/java/com/ycwl/basic/biz/OrderBiz.java
index ccd5a65..6f1164f 100644
--- a/src/main/java/com/ycwl/basic/biz/OrderBiz.java
+++ b/src/main/java/com/ycwl/basic/biz/OrderBiz.java
@@ -4,11 +4,13 @@ import com.ycwl.basic.mapper.FaceMapper;
 import com.ycwl.basic.mapper.VideoMapper;
 import com.ycwl.basic.model.mobile.order.IsBuyRespVO;
 import com.ycwl.basic.model.mobile.order.PriceObj;
+import com.ycwl.basic.model.pc.face.entity.FaceEntity;
 import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
 import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
 import com.ycwl.basic.model.pc.scenic.entity.ScenicEntity;
 import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
 import com.ycwl.basic.model.pc.video.resp.VideoRespVO;
+import com.ycwl.basic.repository.FaceRepository;
 import com.ycwl.basic.repository.OrderRepository;
 import com.ycwl.basic.repository.ScenicRepository;
 import com.ycwl.basic.repository.TemplateRepository;
@@ -27,9 +29,9 @@ public class OrderBiz {
     @Autowired
     private TemplateRepository templateRepository;
     @Autowired
-    private FaceMapper faceMapper;
-    @Autowired
     private OrderRepository orderRepository;
+    @Autowired
+    private FaceRepository faceRepository;
 
     public PriceObj queryPrice(Long scenicId, int goodsType, Long goodsId) {
         PriceObj priceObj = new PriceObj();
@@ -56,16 +58,21 @@ public class OrderBiz {
                     return priceObj;
                 }
                 priceObj.setPrice(template.getPrice());
-                priceObj.setSlashPrice(template.getSlashPrice());
+                BigDecimal slashPrice = template.getSlashPrice();
+                if (slashPrice == null) {
+                    priceObj.setSlashPrice(priceObj.getPrice());
+                } else {
+                    priceObj.setSlashPrice(slashPrice);
+                }
                 priceObj.setScenicId(video.getScenicId());
                 break;
             case 1: // source
                 // goodsId 实际上是人脸ID
-                FaceRespVO _faceRespVO = faceMapper.getById(goodsId);
-                if (_faceRespVO == null || _faceRespVO.getScenicId() == null) {
+                FaceEntity _face = faceRepository.getFace(goodsId);
+                if (_face == null || _face.getScenicId() == null) {
                     return null;
                 }
-                ScenicEntity _scenic = scenicRepository.getScenic(_faceRespVO.getScenicId());
+                ScenicEntity _scenic = scenicRepository.getScenic(_face.getScenicId());
                 if (_scenic == null) {
                     return null;
                 }
@@ -74,11 +81,11 @@ public class OrderBiz {
                 break;
             case 2: // source
                 // goodsId 实际上是人脸ID
-                FaceRespVO __faceRespVO = faceMapper.getById(goodsId);
-                if (__faceRespVO == null || __faceRespVO.getScenicId() == null) {
+                FaceEntity __face = faceRepository.getFace(goodsId);
+                if (__face == null || __face.getScenicId() == null) {
                     return null;
                 }
-                ScenicEntity __scenic = scenicRepository.getScenic(__faceRespVO.getScenicId());
+                ScenicEntity __scenic = scenicRepository.getScenic(__face.getScenicId());
                 if (__scenic == null) {
                     return null;
                 }
diff --git a/src/main/java/com/ycwl/basic/controller/mobile/AppWxNotifyController.java b/src/main/java/com/ycwl/basic/controller/mobile/AppWxNotifyController.java
index ed9ac77..2d54b1f 100644
--- a/src/main/java/com/ycwl/basic/controller/mobile/AppWxNotifyController.java
+++ b/src/main/java/com/ycwl/basic/controller/mobile/AppWxNotifyController.java
@@ -4,12 +4,15 @@ package com.ycwl.basic.controller.mobile;
 import com.alibaba.fastjson.JSONObject;
 import com.ycwl.basic.annotation.IgnoreToken;
 import com.ycwl.basic.model.wx.WechatMessageSubscribeForm;
+import com.ycwl.basic.repository.ScenicRepository;
 import com.ycwl.basic.service.mobile.WxNotifyService;
 import com.ycwl.basic.utils.ApiResponse;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -30,20 +33,43 @@ import java.util.List;
 public class AppWxNotifyController {
     @Autowired
     private WxNotifyService wxNotifyService;
+    @Autowired
+    private ScenicRepository scenicRepository;
+//
+//    @ApiOperation(value = "通知", notes = "通知")
+//    @PostMapping("/pushMessage")
+//    @IgnoreToken
+//    public ApiResponse<?> pushMessage(@RequestBody WechatMessageSubscribeForm req) {
+//        JSONObject resJson = wxNotifyService.pushMessage(req);
+//        return ApiResponse.success(resJson);
+//    }
 
-    @ApiOperation(value = "通知", notes = "通知")
-    @PostMapping("/pushMessage")
-    @IgnoreToken
-    public ApiResponse<?> pushMessage(@RequestBody WechatMessageSubscribeForm req) {
-        JSONObject resJson = wxNotifyService.pushMessage(req);
-        return ApiResponse.success(resJson);
-    }
-
-    @GetMapping("/getIds")
+    @GetMapping({"/getIds", "/"})
     @IgnoreToken
     public ApiResponse<List<String>> getIds() {
         return ApiResponse.success(new ArrayList<String>() {{
-            add("5b8vTm7kvwYubqDxb3dxBqFIhc3Swt5l7QHSK5r-ZRI");
+            add("5b8vTm7kvwYubqDxb3dxBs0BqxMsgVgGw573aahTEd8");
+            add("vPIzbkA0x4mMj-vdbWx6_45e8juWXzs3FGYnDsIPv3A");
+            add("HB1vp-0BXc2WyYeoYN3a3GuZV9HtPLXUTT7blCBq9eY");
+        }});
+    }
+
+    @GetMapping("/{scenicId}")
+    @IgnoreToken
+    public ApiResponse<List<String>> getIds(@PathVariable("scenicId") Long scenicId) {
+        return ApiResponse.success(new ArrayList<String>() {{
+            String videoGeneratedTemplateId = scenicRepository.getVideoGeneratedTemplateId(scenicId);
+            if (StringUtils.isNotBlank(videoGeneratedTemplateId)) {
+                add(videoGeneratedTemplateId);
+            }
+            String videoDownloadTemplateId = scenicRepository.getVideoDownloadTemplateId(scenicId);
+            if (StringUtils.isNotBlank(videoDownloadTemplateId)) {
+                add(videoDownloadTemplateId);
+            }
+            String videoPreExpireTemplateId = scenicRepository.getVideoPreExpireTemplateId(scenicId);
+            if (StringUtils.isNotBlank(videoPreExpireTemplateId)) {
+                add(videoPreExpireTemplateId);
+            }
         }});
     }
 
diff --git a/src/main/java/com/ycwl/basic/controller/pc/FaceController.java b/src/main/java/com/ycwl/basic/controller/pc/FaceController.java
index fb150ef..5bc5025 100644
--- a/src/main/java/com/ycwl/basic/controller/pc/FaceController.java
+++ b/src/main/java/com/ycwl/basic/controller/pc/FaceController.java
@@ -54,11 +54,6 @@ public class FaceController {
     public ApiResponse<Integer> deleteByIds(@RequestBody List<Long> ids) {
         return faceService.deleteByIds(ids);
     }
-    @ApiOperation("修改用户人脸信息")
-    @PostMapping("/update")
-    public ApiResponse<Integer> update(@RequestBody FaceEntity face) {
-        return faceService.update(face);
-    }
 
 
 }
diff --git a/src/main/java/com/ycwl/basic/controller/viid/ViidController.java b/src/main/java/com/ycwl/basic/controller/viid/ViidController.java
index c10ee6b..d746442 100644
--- a/src/main/java/com/ycwl/basic/controller/viid/ViidController.java
+++ b/src/main/java/com/ycwl/basic/controller/viid/ViidController.java
@@ -129,7 +129,7 @@ public class ViidController {
 //        log.info("已经解析过的心跳信息:{}", keepaliveObject);
 
         return new VIIDBaseResp(
-                new ResponseStatusObject(deviceId, "/VIID/System/UnRegister", "0", "注销成功", sdfTime.format(new Date()))
+                new ResponseStatusObject(deviceId, "/VIID/System/Keepalive", "0", "保活", sdfTime.format(new Date()))
         );
     }
 
@@ -186,8 +186,8 @@ public class ViidController {
      * 批量新增人脸
      */
     @RequestMapping(value = "/Faces", method = RequestMethod.POST)
+    @IgnoreLogReq
     public VIIDBaseResp faces(@RequestBody FaceUploadReq req) {
-        log.info("收到的人脸上报信息:{}",req);
         FaceListObject faceListObject = req.getFaceListObject();
         List<FaceObject> faceObject = faceListObject.getFaceObject();
         String faceId = null;
diff --git a/src/main/java/com/ycwl/basic/controller/wvp/WvpController.java b/src/main/java/com/ycwl/basic/controller/wvp/WvpController.java
index 02851c4..5a15a45 100644
--- a/src/main/java/com/ycwl/basic/controller/wvp/WvpController.java
+++ b/src/main/java/com/ycwl/basic/controller/wvp/WvpController.java
@@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.RestController;
 @Api(tags = "WVP对接接口")
 @RequestMapping("/wvp/v1/")
 public class WvpController {
+
     @IgnoreLogReq
     @PostMapping("/sync")
     public ApiResponse sync() {
diff --git a/src/main/java/com/ycwl/basic/mapper/SourceMapper.java b/src/main/java/com/ycwl/basic/mapper/SourceMapper.java
index 153aefe..fbb9cb5 100644
--- a/src/main/java/com/ycwl/basic/mapper/SourceMapper.java
+++ b/src/main/java/com/ycwl/basic/mapper/SourceMapper.java
@@ -61,6 +61,7 @@ public interface SourceMapper {
 
     int hasRelationTo(Long memberId, Long sourceId, int type);
 
+    List<SourceEntity> listVideoByScenicFaceRelation(Long scenicId, Long faceId);
     List<SourceEntity> listVideoByFaceRelation(Long faceId);
 
 }
diff --git a/src/main/java/com/ycwl/basic/mapper/SourceTaskMapper.java b/src/main/java/com/ycwl/basic/mapper/SourceTaskMapper.java
new file mode 100644
index 0000000..6538328
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/mapper/SourceTaskMapper.java
@@ -0,0 +1,7 @@
+package com.ycwl.basic.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ycwl.basic.model.pc.source.entity.SourceTaskEntity;
+
+public interface SourceTaskMapper extends BaseMapper<SourceTaskEntity> {
+}
diff --git a/src/main/java/com/ycwl/basic/mapper/TemplateMapper.java b/src/main/java/com/ycwl/basic/mapper/TemplateMapper.java
index cdd397e..0d60fcd 100644
--- a/src/main/java/com/ycwl/basic/mapper/TemplateMapper.java
+++ b/src/main/java/com/ycwl/basic/mapper/TemplateMapper.java
@@ -19,6 +19,7 @@ import java.util.List;
 public interface TemplateMapper {
     List<TemplateRespVO> list(TemplateReqQuery templateReqQuery);
     TemplateRespVO getById(Long id);
+    TemplateEntity get(Long id);
     int add(TemplateEntity task);
     int deleteById(Long id);
     int update(TemplateEntity task);
diff --git a/src/main/java/com/ycwl/basic/model/pc/mp/ScenicMpNotifyVO.java b/src/main/java/com/ycwl/basic/model/pc/mp/ScenicMpNotifyVO.java
index d1af411..527c005 100644
--- a/src/main/java/com/ycwl/basic/model/pc/mp/ScenicMpNotifyVO.java
+++ b/src/main/java/com/ycwl/basic/model/pc/mp/ScenicMpNotifyVO.java
@@ -10,4 +10,6 @@ public class ScenicMpNotifyVO {
     private String appSecret;
     private String appState;
     private String videoGeneratedTemplateId;
+    private String videoDownloadTemplateId;
+    private String videoPreExpireTemplateId;
 }
diff --git a/src/main/java/com/ycwl/basic/model/pc/source/entity/SourceTaskEntity.java b/src/main/java/com/ycwl/basic/model/pc/source/entity/SourceTaskEntity.java
new file mode 100644
index 0000000..fa0fb1e
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/pc/source/entity/SourceTaskEntity.java
@@ -0,0 +1,22 @@
+package com.ycwl.basic.model.pc.source.entity;
+
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+@TableName("source_task")
+public class SourceTaskEntity {
+    private Integer id;
+    private Long scenicId;
+    private Long deviceId;
+    private Long faceSampleId;
+    private Integer status;
+    private String url;
+    private Date createTime;
+    private Date startTime;
+    private Date endTime;
+    private Long waitTaskId;
+    private String nextFsIds;
+}
diff --git a/src/main/java/com/ycwl/basic/device/repository/DeviceRepository.java b/src/main/java/com/ycwl/basic/repository/DeviceRepository.java
similarity index 98%
rename from src/main/java/com/ycwl/basic/device/repository/DeviceRepository.java
rename to src/main/java/com/ycwl/basic/repository/DeviceRepository.java
index e643dfb..e8e8c51 100644
--- a/src/main/java/com/ycwl/basic/device/repository/DeviceRepository.java
+++ b/src/main/java/com/ycwl/basic/repository/DeviceRepository.java
@@ -1,4 +1,4 @@
-package com.ycwl.basic.device.repository;
+package com.ycwl.basic.repository;
 
 import com.alibaba.fastjson.JSONObject;
 import com.ycwl.basic.mapper.DeviceMapper;
diff --git a/src/main/java/com/ycwl/basic/repository/FaceRepository.java b/src/main/java/com/ycwl/basic/repository/FaceRepository.java
index c49ec75..46d9432 100644
--- a/src/main/java/com/ycwl/basic/repository/FaceRepository.java
+++ b/src/main/java/com/ycwl/basic/repository/FaceRepository.java
@@ -1,10 +1,10 @@
 package com.ycwl.basic.repository;
 
+import com.alibaba.fastjson.JSONObject;
 import com.ycwl.basic.mapper.FaceMapper;
 import com.ycwl.basic.mapper.FaceSampleMapper;
 import com.ycwl.basic.model.pc.face.entity.FaceEntity;
 import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
-import com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
@@ -24,14 +24,40 @@ public class FaceRepository {
     @Autowired
     private FaceSampleMapper faceSampleMapper;
 
+    public static final String FACE_CACHE_KEY = "face:%s";
+    public static final String FACE_SAMPLE_CACHE_KEY = "face:%s:sample";
+
+    public FaceEntity getFace(Long id) {
+        if (redisTemplate.hasKey(String.format(FACE_CACHE_KEY, id))) {
+            return JSONObject.parseObject(redisTemplate.opsForValue().get(String.format(FACE_CACHE_KEY, id)), FaceEntity.class);
+        }
+        FaceEntity face = faceMapper.get(id);
+        if (face != null) {
+            redisTemplate.opsForValue().set(String.format(FACE_CACHE_KEY, id), JSONObject.toJSONString(face));
+        }
+        return face;
+    }
+
     public List<FaceSampleEntity> getFaceSampleList(Long faceId) {
-        FaceEntity face = faceMapper.get(faceId);
+        if (redisTemplate.hasKey(String.format(FACE_SAMPLE_CACHE_KEY, faceId))) {
+            return JSONObject.parseArray(redisTemplate.opsForValue().get(String.format(FACE_SAMPLE_CACHE_KEY, faceId)), FaceSampleEntity.class);
+        }
+        FaceEntity face = getFace(faceId);
         if (face == null) {
             return Collections.emptyList();
         }
         if (StringUtils.isBlank(face.getMatchSampleIds())) {
             return Collections.emptyList();
         }
-        return faceSampleMapper.listByIds(Arrays.stream(face.getMatchSampleIds().split(",")).map(Long::valueOf).collect(Collectors.toList()));
+        List<FaceSampleEntity> list = faceSampleMapper.listByIds(Arrays.stream(face.getMatchSampleIds().split(",")).map(Long::valueOf).collect(Collectors.toList()));
+        if (!list.isEmpty()) {
+            redisTemplate.opsForValue().set(String.format(FACE_SAMPLE_CACHE_KEY, faceId), JSONObject.toJSONString(list));
+        }
+        return list;
+    }
+
+    public void clearFaceCache(Long faceId) {
+        redisTemplate.delete(String.format(FACE_CACHE_KEY, faceId));
+        redisTemplate.delete(String.format(FACE_SAMPLE_CACHE_KEY, faceId));
     }
 }
diff --git a/src/main/java/com/ycwl/basic/repository/OrderRepository.java b/src/main/java/com/ycwl/basic/repository/OrderRepository.java
index 3690d69..eec9e1d 100644
--- a/src/main/java/com/ycwl/basic/repository/OrderRepository.java
+++ b/src/main/java/com/ycwl/basic/repository/OrderRepository.java
@@ -6,6 +6,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Component;
 
+import java.util.concurrent.TimeUnit;
+
 @Component
 public class OrderRepository {
     @Autowired
@@ -17,10 +19,11 @@ public class OrderRepository {
 
     public boolean checkUserBuyItem(Long userId, int goodsType, Long goodsId) {
         if (redisTemplate.hasKey(String.format(ORDER_ITEM_CACHE_KEY, userId, goodsType, goodsId))) {
-            return true;
+            return "1".equals(redisTemplate.opsForValue().get(String.format(ORDER_ITEM_CACHE_KEY, userId, goodsType, goodsId)));
         }
         OrderEntity orderEntity = orderMapper.getUserBuyItem(userId, goodsType, goodsId);
         if (orderEntity == null) {
+            redisTemplate.opsForValue().set(String.format(ORDER_ITEM_CACHE_KEY, userId, goodsType, goodsId), "0", 60, TimeUnit.SECONDS);
             return false;
         }
         redisTemplate.opsForValue().set(String.format(ORDER_ITEM_CACHE_KEY, userId, goodsType, goodsId), "1");
diff --git a/src/main/java/com/ycwl/basic/repository/ScenicRepository.java b/src/main/java/com/ycwl/basic/repository/ScenicRepository.java
index 65bb704..d1a2da9 100644
--- a/src/main/java/com/ycwl/basic/repository/ScenicRepository.java
+++ b/src/main/java/com/ycwl/basic/repository/ScenicRepository.java
@@ -81,6 +81,12 @@ public class ScenicRepository {
                 case 0:
                     mpNotifyConfig.setVideoGeneratedTemplateId(item.getTemplateId());
                     break;
+                case 1:
+                    mpNotifyConfig.setVideoDownloadTemplateId(item.getTemplateId());
+                    break;
+                case 2:
+                    mpNotifyConfig.setVideoPreExpireTemplateId(item.getTemplateId());
+                    break;
             }
         });
         redisTemplate.opsForValue().set(String.format(SCENIC_MP_NOTIFY_CACHE_KEY, scenicId), JSONObject.toJSONString(mpNotifyConfig));
@@ -95,6 +101,22 @@ public class ScenicRepository {
         return null;
     }
 
+    public String getVideoDownloadTemplateId(Long scenicId) {
+        ScenicMpNotifyVO scenicMpNotifyConfig = getScenicMpNotifyConfig(scenicId);
+        if (scenicMpNotifyConfig != null) {
+            return scenicMpNotifyConfig.getVideoDownloadTemplateId();
+        }
+        return null;
+    }
+
+    public String getVideoPreExpireTemplateId(Long scenicId) {
+        ScenicMpNotifyVO scenicMpNotifyConfig = getScenicMpNotifyConfig(scenicId);
+        if (scenicMpNotifyConfig != null) {
+            return scenicMpNotifyConfig.getVideoPreExpireTemplateId();
+        }
+        return null;
+    }
+
     public void clearCache(Long scenicId) {
         redisTemplate.delete(String.format(SCENIC_CACHE_KEY, scenicId));
         redisTemplate.delete(String.format(SCENIC_CONFIG_CACHE_KEY, scenicId));
diff --git a/src/main/java/com/ycwl/basic/repository/TemplateRepository.java b/src/main/java/com/ycwl/basic/repository/TemplateRepository.java
index 22ebd51..8da63f8 100644
--- a/src/main/java/com/ycwl/basic/repository/TemplateRepository.java
+++ b/src/main/java/com/ycwl/basic/repository/TemplateRepository.java
@@ -17,10 +17,6 @@ import java.util.stream.Collectors;
 
 @Service // 临时这么用
 public class TemplateRepository {
-    @Autowired
-    private FaceMapper faceMapper;
-    @Autowired
-    private FaceSampleMapper faceSampleMapper;
     @Autowired
     private TemplateMapper templateMapper;
     @Autowired
@@ -39,6 +35,15 @@ public class TemplateRepository {
                 .collect(Collectors.toList());
     }
 
+    public int getTemplateMinimalPlaceholderCount(Long templateId) {
+        TemplateConfigEntity config = getTemplateConfig(templateId);
+        if (config == null || config.getMinimalPlaceholderFill() == null) {
+            return 1;
+        } else {
+            return config.getMinimalPlaceholderFill();
+        }
+    }
+
     public List<TemplateRespVO> getTemplateListByScenicId(Long scenicId) {
         List<Long> idList;
         if (redisTemplate.hasKey(String.format(TEMPLATE_ID_BY_SCENIC_ID_CACHE_KEY, scenicId))) {
@@ -69,6 +74,9 @@ public class TemplateRepository {
     }
 
     public TemplateConfigEntity getTemplateConfig(Long templateId) {
+        if (templateId == null) {
+            return new TemplateConfigEntity();
+        }
         if (redisTemplate.hasKey(String.format(TEMPLATE_CONFIG_CACHE_KEY, templateId))) {
             return JSONObject.parseObject(redisTemplate.opsForValue().get(String.format(TEMPLATE_CONFIG_CACHE_KEY, templateId)), TemplateConfigEntity.class);
         }
diff --git a/src/main/java/com/ycwl/basic/service/impl/mobile/GoodsServiceImpl.java b/src/main/java/com/ycwl/basic/service/impl/mobile/GoodsServiceImpl.java
index 76ecf56..28d1af4 100644
--- a/src/main/java/com/ycwl/basic/service/impl/mobile/GoodsServiceImpl.java
+++ b/src/main/java/com/ycwl/basic/service/impl/mobile/GoodsServiceImpl.java
@@ -13,6 +13,7 @@ import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
 import com.ycwl.basic.model.pc.source.req.SourceReqQuery;
 import com.ycwl.basic.model.pc.source.resp.SourceRespVO;
 import com.ycwl.basic.model.pc.task.entity.TaskEntity;
+import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
 import com.ycwl.basic.model.pc.video.entity.MemberVideoEntity;
 import com.ycwl.basic.model.pc.video.req.VideoReqQuery;
 import com.ycwl.basic.model.pc.video.resp.VideoRespVO;
@@ -258,14 +259,19 @@ public class GoodsServiceImpl implements GoodsService {
             return ApiResponse.success(response);
         }
         response.setScenicId(taskList.get(0).getScenicId());
-        response.setMaxCount(templateRepository.getTemplateListByScenicId(response.getScenicId()).size());
-        List<MemberVideoEntity> notFinishedTasks = taskList.stream().filter(task -> {
-            TaskEntity taskById = videoTaskRepository.getTaskById(task.getTaskId());
-            if (taskById == null) {
-                return true;
-            }
-            return taskById.getStatus() != 1;
-        }).collect(Collectors.toList());
+        List<TemplateRespVO> templateList = templateRepository.getTemplateListByScenicId(response.getScenicId());
+        List<Long> templateIds = templateList.stream().map(TemplateRespVO::getId).collect(Collectors.toList());
+        response.setMaxCount(templateList.size());
+        List<MemberVideoEntity> notFinishedTasks = taskList.stream()
+                .filter(task -> templateIds.contains(task.getTemplateId()))
+                .filter(task -> {
+                    TaskEntity taskById = videoTaskRepository.getTaskById(task.getTaskId());
+                    if (taskById == null) {
+                        return true;
+                    }
+                    return taskById.getStatus() != 1;
+                })
+                .collect(Collectors.toList());
         if (!notFinishedTasks.isEmpty()) {
             response.setCount(taskList.size() - notFinishedTasks.size());
             response.setTemplateId(notFinishedTasks.get(0).getTemplateId());
@@ -300,13 +306,14 @@ public class GoodsServiceImpl implements GoodsService {
         }
         response.setScenicId(taskList.get(0).getScenicId());
         response.setMaxCount(templateRepository.getTemplateListByScenicId(response.getScenicId()).size());
-        List<MemberVideoEntity> notFinishedTasks = taskList.stream().filter(task -> {
-            TaskEntity taskById = videoTaskRepository.getTaskById(task.getTaskId());
-            if (taskById == null) {
-                return true;
-            }
-            return taskById.getStatus() != 1;
-        }).collect(Collectors.toList());
+        List<MemberVideoEntity> notFinishedTasks = taskList.stream()
+                .filter(task -> {
+                    TaskEntity taskById = videoTaskRepository.getTaskById(task.getTaskId());
+                    if (taskById == null) {
+                        return true;
+                    }
+                    return taskById.getStatus() != 1;
+                }).collect(Collectors.toList());
         if (!notFinishedTasks.isEmpty()) {
             response.setCount(taskList.size() - notFinishedTasks.size());
             response.setTemplateId(notFinishedTasks.get(0).getTemplateId());
@@ -319,7 +326,12 @@ public class GoodsServiceImpl implements GoodsService {
         response.setTemplateId(lastVideo.getTemplateId());
         response.setVideoId(lastVideo.getVideoId());
         response.setCount(taskList.size());
-        response.setStatus(1);
+        if (null == lastVideo.getVideoId()) {
+            response.setStatus(2);
+        } else {
+            response.setStatus(1);
+            response.setVideoId(lastVideo.getVideoId());
+        }
         return ApiResponse.success(response);
     }
 
diff --git a/src/main/java/com/ycwl/basic/service/impl/mobile/WxPayServiceImpl.java b/src/main/java/com/ycwl/basic/service/impl/mobile/WxPayServiceImpl.java
index 4ced799..5e40611 100644
--- a/src/main/java/com/ycwl/basic/service/impl/mobile/WxPayServiceImpl.java
+++ b/src/main/java/com/ycwl/basic/service/impl/mobile/WxPayServiceImpl.java
@@ -130,9 +130,9 @@ public class WxPayServiceImpl implements WxPayService {
             Payer payer = new Payer();
             payer.setOpenid(req.getOpenId());
             request.setPayer(payer);
-            SettleInfo settleInfo = new SettleInfo();
-            settleInfo.setProfitSharing(true);
-            request.setSettleInfo(settleInfo);
+//            SettleInfo settleInfo = new SettleInfo();
+//            settleInfo.setProfitSharing(true);
+//            request.setSettleInfo(settleInfo);
 
             // 调用下单方法,得到应答
             PrepayResponse response = service.prepay(request);
diff --git a/src/main/java/com/ycwl/basic/service/impl/pc/DeviceServiceImpl.java b/src/main/java/com/ycwl/basic/service/impl/pc/DeviceServiceImpl.java
index e3a8776..b9a32be 100644
--- a/src/main/java/com/ycwl/basic/service/impl/pc/DeviceServiceImpl.java
+++ b/src/main/java/com/ycwl/basic/service/impl/pc/DeviceServiceImpl.java
@@ -2,7 +2,7 @@ package com.ycwl.basic.service.impl.pc;
 
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
-import com.ycwl.basic.device.repository.DeviceRepository;
+import com.ycwl.basic.repository.DeviceRepository;
 import com.ycwl.basic.mapper.DeviceMapper;
 import com.ycwl.basic.model.pc.device.entity.DeviceConfigEntity;
 import com.ycwl.basic.model.pc.device.req.DeviceAddOrUpdateReq;
@@ -89,5 +89,6 @@ public class DeviceServiceImpl implements DeviceService {
     public void saveConfig(Long configId, DeviceConfigEntity config) {
         config.setId(configId);
         deviceMapper.updateConfig(config);
+        deviceRepository.clearDeviceCache(config.getDeviceId());
     }
 }
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 638dfdc..f156703 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
@@ -19,6 +19,7 @@ import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
 import com.ycwl.basic.model.pc.source.entity.MemberSourceEntity;
 import com.ycwl.basic.model.pc.source.entity.SourceEntity;
 import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
+import com.ycwl.basic.repository.FaceRepository;
 import com.ycwl.basic.service.pc.FaceService;
 import com.ycwl.basic.service.task.TaskFaceService;
 import com.ycwl.basic.service.task.TaskService;
@@ -66,6 +67,8 @@ public class FaceServiceImpl implements FaceService {
     private FaceSampleMapper faceSampleMapper;
     @Autowired
     private OrderBiz orderBiz;
+    @Autowired
+    private FaceRepository faceRepository;
 
     @Override
     public ApiResponse<PageInfo<FaceRespVO>> pageQuery(FaceReqQuery faceReqQuery) {
@@ -113,15 +116,6 @@ public class FaceServiceImpl implements FaceService {
         return ApiResponse.success(i);
     }
 
-    @Override
-    public ApiResponse<Integer> update(FaceEntity face) {
-        int i = faceMapper.update(face);
-        if (i == 0) {
-            return ApiResponse.fail("修改失败");
-        }
-        return ApiResponse.success(i);
-    }
-
     @Override
 //    @Transactional(rollbackFor = Exception.class)
     public ApiResponse faceUpload(MultipartFile file, Long scenicId) {
@@ -191,6 +185,7 @@ public class FaceServiceImpl implements FaceService {
         } else {
             //2、更新人脸
             faceMapper.update(faceEntity);
+            faceRepository.clearFaceCache(faceEntity.getId());
         }
         if (sampleListIds == null) {
             return ApiResponse.fail("请先游玩后再来获取视频吧");
@@ -215,11 +210,6 @@ public class FaceServiceImpl implements FaceService {
             return memberSourceEntity;
         }).collect(Collectors.toList());
         sourceMapper.addRelations(memberSourceEntityList);
-        VideoPieceGetter.Task task = new VideoPieceGetter.Task();
-        task.faceId = faceEntity.getId();
-        task.faceSampleIds = sampleListIds;
-        task.memberId = userId;
-        VideoPieceGetter.addTask(task);
         taskTaskService.autoCreateTaskByFaceId(faceEntity.getId());
         StatisticsRecordAddReq statisticsRecordAddReq = new StatisticsRecordAddReq();
         statisticsRecordAddReq.setMemberId(userId);
@@ -230,6 +220,11 @@ public class FaceServiceImpl implements FaceService {
         FaceRecognizeResp resp = new FaceRecognizeResp();
         resp.setUrl(faceUrl);
         resp.setFaceId(faceEntity.getId());
+        VideoPieceGetter.Task task = new VideoPieceGetter.Task();
+        task.faceId = faceEntity.getId();
+        task.faceSampleIds = sampleListIds;
+        task.memberId = userId;
+        VideoPieceGetter.addTask(task);
         return ApiResponse.success(resp);
     }
 
diff --git a/src/main/java/com/ycwl/basic/service/impl/pc/TemplateServiceImpl.java b/src/main/java/com/ycwl/basic/service/impl/pc/TemplateServiceImpl.java
index f42d88b..3cbc3a3 100644
--- a/src/main/java/com/ycwl/basic/service/impl/pc/TemplateServiceImpl.java
+++ b/src/main/java/com/ycwl/basic/service/impl/pc/TemplateServiceImpl.java
@@ -102,6 +102,7 @@ public class TemplateServiceImpl implements TemplateService {
     @Override
     public ApiResponse<Boolean> updateStatus(Long id) {
         int i = templateMapper.updateStatus(id);
+        templateRepository.clearTemplateCache(id);
         if (i > 0) {
             return ApiResponse.success(true);
         }else {
diff --git a/src/main/java/com/ycwl/basic/service/pc/FaceService.java b/src/main/java/com/ycwl/basic/service/pc/FaceService.java
index 6907660..b6700a4 100644
--- a/src/main/java/com/ycwl/basic/service/pc/FaceService.java
+++ b/src/main/java/com/ycwl/basic/service/pc/FaceService.java
@@ -20,7 +20,6 @@ public interface FaceService {
     ApiResponse<Integer> add(FaceEntity face);
     ApiResponse<Integer> deleteById(Long id);
     ApiResponse<Integer> deleteByIds(List<Long> ids);
-    ApiResponse<Integer> update(FaceEntity face);
 
     ApiResponse faceUpload(MultipartFile file, Long scrnicId);
 }
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 7abee20..9f8fa5b 100644
--- a/src/main/java/com/ycwl/basic/service/task/TaskService.java
+++ b/src/main/java/com/ycwl/basic/service/task/TaskService.java
@@ -10,7 +10,7 @@ import java.util.Date;
 
 public interface TaskService {
     TaskSyncRespVo handleSyncTask(TaskReqVo req);
-    void createRenderTask(Long scenicId, Long templateId, Long faceId);
+    boolean createRenderTask(Long scenicId, Long templateId, Long faceId);
 
     TemplateRespVO workerGetTemplate(Long templateId, WorkerAuthReqVo req);
 
diff --git a/src/main/java/com/ycwl/basic/service/task/impl/TaskFaceServiceImpl.java b/src/main/java/com/ycwl/basic/service/task/impl/TaskFaceServiceImpl.java
index 2af4f5f..0fe09c2 100644
--- a/src/main/java/com/ycwl/basic/service/task/impl/TaskFaceServiceImpl.java
+++ b/src/main/java/com/ycwl/basic/service/task/impl/TaskFaceServiceImpl.java
@@ -32,6 +32,7 @@ import com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO;
 import com.ycwl.basic.model.pc.scenic.entity.ScenicConfigEntity;
 import com.ycwl.basic.model.task.resp.AddFaceSampleRespVo;
 import com.ycwl.basic.model.task.resp.SearchFaceRespVo;
+import com.ycwl.basic.repository.FaceRepository;
 import com.ycwl.basic.service.task.TaskFaceService;
 import com.ycwl.basic.storage.StorageFactory;
 import com.ycwl.basic.storage.adapters.IStorageAdapter;
@@ -71,6 +72,8 @@ public class TaskFaceServiceImpl implements TaskFaceService {
     private RedisTemplate<String, String> redisTemplate;
     @Autowired
     private FaceDetectLogMapper logMapper;
+    @Autowired
+    private FaceRepository faceRepository;
 
     private IAcsClient getClient() {
         DefaultProfile profile = DefaultProfile.getProfile(
@@ -91,6 +94,7 @@ public class TaskFaceServiceImpl implements TaskFaceService {
             faceEntity.setScore(respVo.getScore());
             faceEntity.setMatchSampleIds(StringUtils.join(respVo.getSampleListIds(), ","));
             faceMapper.update(faceEntity);
+            faceRepository.clearFaceCache(faceId);
         }
         return respVo;
     }
@@ -162,7 +166,9 @@ public class TaskFaceServiceImpl implements TaskFaceService {
         AddFaceSampleRespVo respVo = addFaceSample(faceSampleRespVO.getScenicId().toString(), entityId, faceSampleRespVO.getFaceUrl(), faceSampleId.toString());
         FaceSampleEntity faceSampleEntity = new FaceSampleEntity();
         faceSampleEntity.setId(faceSampleId);
-        faceSampleEntity.setScore(respVo.getScore());
+        if (respVo != null) {
+            faceSampleEntity.setScore(respVo.getScore());
+        }
         faceSampleEntity.setUpdateAt(new Date());
         faceSampleMapper.update(faceSampleEntity);
         addFaceSampleUrlCache(faceSampleId, faceSampleRespVO.getFaceUrl());
@@ -178,6 +184,7 @@ public class TaskFaceServiceImpl implements TaskFaceService {
         try {
             client.getAcsResponse(request);
         } catch (ClientException e) {
+            log.error("addFaceEntity", e);
             return null;
         }
         AddFaceRequest addFaceRequest = new AddFaceRequest();
@@ -191,6 +198,7 @@ public class TaskFaceServiceImpl implements TaskFaceService {
             respVo.setScore(acsResponse.getData().getQualitieScore());
             return respVo;
         } catch (ClientException e) {
+            log.error("addFaceEntity", e);
             return null;
         }
     }
diff --git a/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java b/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java
index bd9d18d..11db85b 100644
--- a/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java
+++ b/src/main/java/com/ycwl/basic/service/task/impl/TaskTaskServiceImpl.java
@@ -16,9 +16,9 @@ import com.ycwl.basic.mapper.TaskMapper;
 import com.ycwl.basic.mapper.TemplateMapper;
 import com.ycwl.basic.mapper.VideoMapper;
 import com.ycwl.basic.model.mobile.order.PriceObj;
+import com.ycwl.basic.model.pc.face.entity.FaceEntity;
 import com.ycwl.basic.model.pc.face.resp.FaceRespVO;
 import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
-import com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO;
 import com.ycwl.basic.model.pc.member.resp.MemberRespVO;
 import com.ycwl.basic.model.pc.mp.MpConfigEntity;
 import com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity;
@@ -42,6 +42,7 @@ import com.ycwl.basic.notify.NotifyFactory;
 import com.ycwl.basic.notify.adapters.INotifyAdapter;
 import com.ycwl.basic.notify.entity.NotifyContent;
 import com.ycwl.basic.notify.enums.NotifyType;
+import com.ycwl.basic.repository.FaceRepository;
 import com.ycwl.basic.repository.ScenicRepository;
 import com.ycwl.basic.repository.VideoTaskRepository;
 import com.ycwl.basic.service.task.TaskService;
@@ -100,6 +101,8 @@ public class TaskTaskServiceImpl implements TaskService {
     private ScenicRepository scenicRepository;
     @Autowired
     private TemplateBiz templateBiz;
+    @Autowired
+    private FaceRepository faceRepository;
 
     private RenderWorkerEntity getWorker(@NonNull WorkerAuthReqVo req) {
         String accessKey = req.getAccessKey();
@@ -151,32 +154,18 @@ public class TaskTaskServiceImpl implements TaskService {
     }
 
     @Override
-    public void createRenderTask(Long scenicId, Long templateId, Long faceId) {
-        // 有人脸,找视频
-        if (faceId == null) {
-            return;
-        }
+    public boolean createRenderTask(Long scenicId, Long templateId, Long faceId) {
         boolean canGenerate = templateBiz.determineTemplateCanGenerate(templateId, faceId);
         if (!canGenerate) {
-            return;
+            return false;
         }
-        TemplateConfigEntity config = templateRepository.getTemplateConfig(templateId);
-        FaceRespVO faceRespVO = faceMapper.getById(faceId);
-        if (faceRespVO == null) {
-            return;
+        FaceEntity face = faceRepository.getFace(faceId);
+        if (face == null) {
+            return false;
         }
-        Map<String, List<SourceRespVO>> sourcesMap = Arrays.stream(faceRespVO.getMatchSampleIds().split(","))
-                .map(Long::valueOf)
-                .map(sampleId -> faceSampleMapper.getById(sampleId))
-                .filter(Objects::nonNull)
-                .map(FaceSampleRespVO::getSourceId)
-                .map(sourceId -> sourceMapper.getById(sourceId))
+        List<SourceEntity> sourceEntityList = sourceMapper.listVideoByScenicFaceRelation(scenicId, faceId);
+        Map<String, List<SourceEntity>> sourcesMap = sourceEntityList.stream()
                 .collect(Collectors.groupingBy(item -> item.getDeviceId().toString()));
-        if (config != null) {
-            if (config.getMinimalPlaceholderFill() > sourcesMap.size()) {
-                throw new RuntimeException("请先游玩后在来生成吧~");
-            }
-        }
         TaskEntity taskEntity = new TaskEntity();
         taskEntity.setId(SnowFlakeUtil.getLongId());
         taskEntity.setFaceId(faceId);
@@ -185,6 +174,7 @@ public class TaskTaskServiceImpl implements TaskService {
         taskEntity.setTaskParams(JSON.toJSONString(sourcesMap));
         taskEntity.setStatus(0);
         taskMapper.add(taskEntity);
+        return true;
     }
 
     @Override
@@ -250,8 +240,11 @@ public class TaskTaskServiceImpl implements TaskService {
     @Override
     public void createTaskByFaceIdAndTempalteId(Long faceId, Long templateId, int automatic) {
         FaceRespVO faceRespVO = faceMapper.getById(faceId);
+        if (faceRespVO == null) {
+            return;
+        }
         ScenicConfigEntity scenicConfig = scenicRepository.getScenicConfig(faceRespVO.getScenicId());
-        List<FaceSampleEntity> faceSampleList = faceSampleMapper.listByIds(Arrays.stream(faceRespVO.getMatchSampleIds().split(",")).map(Long::valueOf).collect(Collectors.toList()));
+        List<FaceSampleEntity> faceSampleList = faceRepository.getFaceSampleList(faceId);
         if (faceSampleList.isEmpty()) {
             return;
         }
@@ -296,13 +289,16 @@ public class TaskTaskServiceImpl implements TaskService {
         VideoPieceGetter.Task task = new VideoPieceGetter.Task();
         task.faceId = faceId;
         task.faceSampleIds = faceSampleIds;
+        task.templateId = templateId;
         task.memberId = faceRespVO.getMemberId();
         task.callback = () -> {
+            log.info("task callback");
             boolean canGenerate = templateBiz.determineTemplateCanGenerate(templateId, faceId);
             if (!canGenerate) {
+                log.info("task callback: 不能生成");
                 return;
             }
-            List<SourceEntity> videoSourceList = sourceMapper.listVideoByFaceRelation(faceId);
+            List<SourceEntity> videoSourceList = sourceMapper.listVideoByScenicFaceRelation(faceRespVO.getScenicId(), faceId);
             Map<String, List<SourceEntity>> sourcesMap = videoSourceList.stream()
                     .peek(item -> item.setUrl(item.getVideoUrl()))
                     .collect(Collectors.groupingBy(item -> item.getDeviceId().toString()));
@@ -329,7 +325,7 @@ public class TaskTaskServiceImpl implements TaskService {
                 taskEntity.setTaskParams(JSON.toJSONString(sourcesMap));
                 taskMapper.add(taskEntity);
                 memberVideoEntity.setTaskId(taskEntity.getId());
-            } else{
+            } else {
                 memberVideoEntity.setTaskId(list.get(0).getId());
                 VideoEntity video = videoMapper.findByTaskId(list.get(0).getId());
                 if (video != null) {
@@ -483,32 +479,24 @@ public class TaskTaskServiceImpl implements TaskService {
                 return;
             }
             ScenicEntity scenic = scenicRepository.getScenic(item.getScenicId());
-            String title = "您在【" + scenic.getName() + "】的影像";
+            String title = "您在【" + scenic.getName() + "】的专属影像";
             String page = "pages/videoSynthesis/buy?scenicId=" + item.getScenicId() + "&faceId=" + item.getFaceId() + "&id=" + item.getVideoId();
             /**
-             * 景点 {{thing5.DATA}}
              * 视频名称 {{thing1.DATA}}
-             * 游玩时间 {{time2.DATA}}
              * 生成时间 {{time4.DATA}}
              * 备注 {{thing3.DATA}}
              */
             Map<String, Object> params = new HashMap<>();
             Map<String, Object> dataParam = new HashMap<>();
-            Map<String, String> scenicMap = new HashMap<>();
-            scenicMap.put("value", scenic.getName());
-            dataParam.put("thing5", scenicMap);
             Map<String, String> videoMap = new HashMap<>();
             TemplateRespVO template = templateRepository.getTemplate(item.getTemplateId());
             videoMap.put("value", template.getName());
             dataParam.put("thing1", videoMap);
-            Map<String, String> timeMap = new HashMap<>();
-            timeMap.put("value", DateUtil.format(getTaskShotDate(taskId), "yyyy-MM-dd"));
-            dataParam.put("time2", timeMap);
             Map<String, String> timeMap2 = new HashMap<>();
             timeMap2.put("value", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm"));
             dataParam.put("time4", timeMap2);
             Map<String, String> remarkMap = new HashMap<>();
-            remarkMap.put("value", "您的游玩Vlog已经等候多时,快来看看吧");
+            remarkMap.put("value", "请及时查看视频,48小时后系统删除");
             dataParam.put("thing3", remarkMap);
             params.put("data", dataParam);
             params.put("page", page);
diff --git a/src/main/java/com/ycwl/basic/service/wvp/impl/WvpServiceImpl.java b/src/main/java/com/ycwl/basic/service/wvp/impl/WvpServiceImpl.java
index c2eaca2..80ec34a 100644
--- a/src/main/java/com/ycwl/basic/service/wvp/impl/WvpServiceImpl.java
+++ b/src/main/java/com/ycwl/basic/service/wvp/impl/WvpServiceImpl.java
@@ -1,6 +1,6 @@
 package com.ycwl.basic.service.wvp.impl;
 
-import com.ycwl.basic.device.repository.DeviceRepository;
+import com.ycwl.basic.repository.DeviceRepository;
 import com.ycwl.basic.repository.ScenicRepository;
 import com.ycwl.basic.service.wvp.WvpService;
 import org.springframework.beans.factory.annotation.Autowired;
diff --git a/src/main/java/com/ycwl/basic/task/DynamicTaskGenerator.java b/src/main/java/com/ycwl/basic/task/DynamicTaskGenerator.java
index daf0c8e..ce4dcbb 100644
--- a/src/main/java/com/ycwl/basic/task/DynamicTaskGenerator.java
+++ b/src/main/java/com/ycwl/basic/task/DynamicTaskGenerator.java
@@ -42,12 +42,8 @@ public class DynamicTaskGenerator {
     @Autowired
     private TaskFaceService faceService;
     @Autowired
-    private FaceSampleMapper faceSampleMapper;
-    @Autowired
     private TaskService taskService;
     @Autowired
-    private DeviceMapper deviceMapper;
-    @Autowired
     private TemplateBiz templateBiz;
 
     @Scheduled(cron = "0 0 * * * ?")
diff --git a/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java b/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java
index 8388b72..3fe997a 100644
--- a/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java
+++ b/src/main/java/com/ycwl/basic/task/VideoPieceGetter.java
@@ -4,7 +4,8 @@ import com.ycwl.basic.biz.OrderBiz;
 import com.ycwl.basic.device.DeviceFactory;
 import com.ycwl.basic.device.entity.common.FileObject;
 import com.ycwl.basic.device.operator.IDeviceStorageOperator;
-import com.ycwl.basic.device.repository.DeviceRepository;
+import com.ycwl.basic.model.pc.faceSample.entity.FaceSampleEntity;
+import com.ycwl.basic.repository.DeviceRepository;
 import com.ycwl.basic.mapper.DeviceMapper;
 import com.ycwl.basic.mapper.FaceSampleMapper;
 import com.ycwl.basic.mapper.SourceMapper;
@@ -14,6 +15,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.MemberSourceEntity;
 import com.ycwl.basic.model.pc.source.entity.SourceEntity;
+import com.ycwl.basic.repository.TemplateRepository;
 import com.ycwl.basic.storage.StorageFactory;
 import com.ycwl.basic.storage.adapters.IStorageAdapter;
 import com.ycwl.basic.utils.SnowFlakeUtil;
@@ -31,10 +33,13 @@ import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Comparator;
 import java.util.Date;
 import java.util.List;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.stream.Collectors;
 import java.util.stream.IntStream;
 
@@ -45,21 +50,21 @@ public class VideoPieceGetter {
     @Autowired
     private FaceSampleMapper faceSampleMapper;
     @Autowired
-    private DeviceMapper deviceMapper;
-    @Autowired
     private DeviceRepository deviceRepository;
     @Autowired
     private SourceMapper sourceMapper;
     @Autowired
     private OrderBiz orderBiz;
+    @Autowired
+    private TemplateRepository templateRepository;
 
     @Data
     public static class Task {
-        public String type = "normal";
         public List<Long> faceSampleIds;
         public Callback callback;
         public Long memberId;
         public Long faceId;
+        public Long templateId;
 
         public static interface Callback {
             void onInvoke();
@@ -86,112 +91,149 @@ public class VideoPieceGetter {
             return;
         }
         log.info("poll task: {}", task);
-        if (task.getType().equalsIgnoreCase("normal")) {
-            task.getFaceSampleIds().parallelStream().forEach(faceSampleId -> {
-                FaceSampleRespVO faceSample = faceSampleMapper.getById(faceSampleId);
-                DeviceEntity device = deviceRepository.getDevice(faceSample.getDeviceId());
-                DeviceConfigEntity config = deviceRepository.getDeviceConfig(faceSample.getDeviceId());
-
-                SourceEntity source = sourceMapper.querySameVideo(faceSample.getId(), device.getId());
-                IsBuyRespVO isBuy = orderBiz.isBuy(task.getMemberId(), faceSample.getScenicId(), 1, faceSample.getId());
-                if (source != null) {
-                    // 有原视频
-                    int count = sourceMapper.hasRelationTo(task.getMemberId(), source.getId(), 1);
-                    if (count > 0) {
-                        return;
-                    }
-                    MemberSourceEntity videoSource = new MemberSourceEntity();
-                    videoSource.setId(SnowFlakeUtil.getLongId());
-                    videoSource.setScenicId(faceSample.getScenicId());
-                    videoSource.setFaceId(task.getFaceId());
-                    videoSource.setMemberId(task.getMemberId());
-                    videoSource.setType(1);
-                    if (isBuy.isBuy()) { // 如果用户买过
-                        videoSource.setIsBuy(1);
-                    } else if (isBuy.isFree()) { // 全免费逻辑
-                        videoSource.setIsBuy(1);
-                    } else {
-                        videoSource.setIsBuy(0);
-                    }
-                    videoSource.setSourceId(source.getId());
-                    sourceMapper.addRelation(videoSource);
-                    return;
-                }
-                BigDecimal cutPre = BigDecimal.valueOf(5L);
-                BigDecimal cutPost = BigDecimal.valueOf(4L);
-                if (config == null) {
-                    return;
-                }
-                // 有配置
-                if (config.getCutPre() != null) {
-                    cutPre = config.getCutPre();
-                }
-                if (config.getCutPost() != null) {
-                    cutPost = config.getCutPost();
-                }
-                IDeviceStorageOperator pieceGetter = DeviceFactory.getDeviceStorageOperator(device, config);
-                if (pieceGetter == null) {
-                    return;
-                }
-                BigDecimal duration = cutPre.add(cutPost);
-                List<FileObject> listByDtRange = pieceGetter.getFileListByDtRange(
-                        new Date(faceSample.getCreateAt().getTime() - cutPre.multiply(BigDecimal.valueOf(1000)).longValue()),
-                        new Date(faceSample.getCreateAt().getTime() + cutPost.multiply(BigDecimal.valueOf(1000)).longValue())
-                );
-                if (listByDtRange.isEmpty()) {
-                    log.warn("没有可用的文件");
-                    return;
-                }
-                log.info("查询到可用的文件: {}", listByDtRange);
-                long offset = faceSample.getCreateAt().getTime() - cutPre.multiply(BigDecimal.valueOf(1000)).longValue() - listByDtRange.get(0).getCreateTime().getTime();
-                FfmpegTask ffmpegTask = new FfmpegTask();
-                ffmpegTask.setFileList(listByDtRange);
-                ffmpegTask.setDuration(duration);
-                ffmpegTask.setOffsetStart(BigDecimal.valueOf(offset, 3));
-                File outFile = new File(faceSample.getDeviceId().toString() + "_" + faceSample.getId() + ".mp4");
-                ffmpegTask.setOutputFile(outFile.getAbsolutePath());
-                boolean result = startFfmpegTask(ffmpegTask);
-                if (!result) {
-                    log.warn("视频裁切失败");
-                    return;
-                }
-                log.info("视频裁切成功");
-                IStorageAdapter adapter = StorageFactory.use("assets");
-                String url = adapter.uploadFile(outFile, "video-source", outFile.getName());
-                // 上传成功后删除文件
-                outFile.delete();
-                SourceEntity imgSource = sourceMapper.findBySampleId(faceSample.getId());
-                SourceEntity sourceEntity = new SourceEntity();
-                sourceEntity.setId(SnowFlakeUtil.getLongId());
-                sourceEntity.setCreateTime(faceSample.getCreateAt());
-                MemberSourceEntity videoSource = new MemberSourceEntity();
-                videoSource.setMemberId(task.getMemberId());
-                videoSource.setType(1);
-                videoSource.setFaceId(task.getFaceId());
-                videoSource.setScenicId(faceSample.getScenicId());
-                videoSource.setSourceId(sourceEntity.getId());
-                if (imgSource != null) {
-                    sourceEntity.setUrl(imgSource.getUrl());
-                    sourceEntity.setPosJson(imgSource.getPosJson());
-                }
-                sourceEntity.setVideoUrl(url);
-                sourceEntity.setFaceSampleId(faceSample.getId());
-                sourceEntity.setScenicId(faceSample.getScenicId());
-                sourceEntity.setDeviceId(faceSample.getDeviceId());
-                sourceEntity.setType(1);
-                if (isBuy.isBuy()) { // 如果用户买过
-                    videoSource.setIsBuy(1);
-                } else if (isBuy.isFree()) { // 全免费逻辑
-                    videoSource.setIsBuy(1);
-                } else {
-                    videoSource.setIsBuy(0);
-                }
-                sourceMapper.add(sourceEntity);
-                sourceMapper.addRelation(videoSource);
-            });
+        List<String> templatePlaceholder;
+        if (null != task.getTemplateId()) {
+            templatePlaceholder = templateRepository.getTemplatePlaceholder(task.getTemplateId());
+        } else {
+            templatePlaceholder = null;
         }
+        AtomicBoolean invoke = new AtomicBoolean(false);
+        List<String> currentPlaceholder = new ArrayList<>();
+        List<FaceSampleEntity> list = faceSampleMapper.listByIds(task.getFaceSampleIds());
+        Collection<List<FaceSampleEntity>> collection = list.stream()
+                .filter(faceSample -> {
+                    if (templatePlaceholder != null) {
+                        return templatePlaceholder.contains(faceSample.getDeviceId().toString());
+                    }
+                    return true;
+                })
+                .collect(Collectors.groupingBy(FaceSampleEntity::getDeviceId))
+                .values();
+        collection
+                .stream()
+                .parallel()
+                .forEach(faceSampleList -> {
+                    faceSampleList.forEach(faceSample -> {
+                        DeviceEntity device = deviceRepository.getDevice(faceSample.getDeviceId());
+                        DeviceConfigEntity config = deviceRepository.getDeviceConfig(faceSample.getDeviceId());
+
+                        SourceEntity source = sourceMapper.querySameVideo(faceSample.getId(), device.getId());
+                        IsBuyRespVO isBuy = orderBiz.isBuy(task.getMemberId(), faceSample.getScenicId(), 1, faceSample.getId());
+                        if (source == null) {
+                            BigDecimal cutPre = BigDecimal.valueOf(5L);
+                            BigDecimal cutPost = BigDecimal.valueOf(4L);
+                            if (config == null) {
+                                return;
+                            }
+                            // 有配置
+                            if (config.getCutPre() != null) {
+                                cutPre = config.getCutPre();
+                            }
+                            if (config.getCutPost() != null) {
+                                cutPost = config.getCutPost();
+                            }
+                            IDeviceStorageOperator pieceGetter = DeviceFactory.getDeviceStorageOperator(device, config);
+                            if (pieceGetter == null) {
+                                return;
+                            }
+                            BigDecimal duration = cutPre.add(cutPost);
+                            List<FileObject> listByDtRange = pieceGetter.getFileListByDtRange(
+                                    new Date(faceSample.getCreateAt().getTime() - cutPre.multiply(BigDecimal.valueOf(1000)).longValue()),
+                                    new Date(faceSample.getCreateAt().getTime() + cutPost.multiply(BigDecimal.valueOf(1000)).longValue())
+                            );
+                            if (listByDtRange.isEmpty()) {
+                                log.warn("没有可用的文件");
+                                return;
+                            }
+                            log.info("查询到可用的文件: {}", listByDtRange);
+                            long offset = faceSample.getCreateAt().getTime() - cutPre.multiply(BigDecimal.valueOf(1000)).longValue() - listByDtRange.get(0).getCreateTime().getTime();
+                            FfmpegTask ffmpegTask = new FfmpegTask();
+                            ffmpegTask.setFileList(listByDtRange);
+                            ffmpegTask.setDuration(duration);
+                            ffmpegTask.setOffsetStart(BigDecimal.valueOf(offset, 3));
+                            File outFile = new File(faceSample.getDeviceId().toString() + "_" + faceSample.getId() + ".mp4");
+                            ffmpegTask.setOutputFile(outFile.getAbsolutePath());
+                            boolean result = startFfmpegTask(ffmpegTask);
+                            if (!result) {
+                                log.warn("视频裁切失败");
+                                return;
+                            }
+                            log.info("视频裁切成功");
+                            IStorageAdapter adapter = StorageFactory.use("assets");
+                            String url = adapter.uploadFile(outFile, "video-source", outFile.getName());
+                            // 上传成功后删除文件
+                            outFile.delete();
+                            SourceEntity imgSource = sourceMapper.findBySampleId(faceSample.getId());
+                            SourceEntity sourceEntity = new SourceEntity();
+                            sourceEntity.setId(SnowFlakeUtil.getLongId());
+                            sourceEntity.setCreateTime(faceSample.getCreateAt());
+                            MemberSourceEntity videoSource = new MemberSourceEntity();
+                            videoSource.setMemberId(task.getMemberId());
+                            videoSource.setType(1);
+                            videoSource.setFaceId(task.getFaceId());
+                            videoSource.setScenicId(faceSample.getScenicId());
+                            videoSource.setSourceId(sourceEntity.getId());
+                            if (imgSource != null) {
+                                sourceEntity.setUrl(imgSource.getUrl());
+                                sourceEntity.setPosJson(imgSource.getPosJson());
+                            }
+                            sourceEntity.setVideoUrl(url);
+                            sourceEntity.setFaceSampleId(faceSample.getId());
+                            sourceEntity.setScenicId(faceSample.getScenicId());
+                            sourceEntity.setDeviceId(faceSample.getDeviceId());
+                            sourceEntity.setType(1);
+                            if (isBuy.isBuy()) { // 如果用户买过
+                                videoSource.setIsBuy(1);
+                            } else if (isBuy.isFree()) { // 全免费逻辑
+                                videoSource.setIsBuy(1);
+                            } else {
+                                videoSource.setIsBuy(0);
+                            }
+                            sourceMapper.add(sourceEntity);
+                            sourceMapper.addRelation(videoSource);
+                        } else {
+                            // 有原视频
+                            int count = sourceMapper.hasRelationTo(task.getMemberId(), source.getId(), 1);
+                            if (count <= 0) {
+                                // 没有关联
+                                MemberSourceEntity videoSource = new MemberSourceEntity();
+                                videoSource.setId(SnowFlakeUtil.getLongId());
+                                videoSource.setScenicId(faceSample.getScenicId());
+                                videoSource.setFaceId(task.getFaceId());
+                                videoSource.setMemberId(task.getMemberId());
+                                videoSource.setType(1);
+                                if (isBuy.isBuy()) { // 如果用户买过
+                                    videoSource.setIsBuy(1);
+                                } else if (isBuy.isFree()) { // 全免费逻辑
+                                    videoSource.setIsBuy(1);
+                                } else {
+                                    videoSource.setIsBuy(0);
+                                }
+                                videoSource.setSourceId(source.getId());
+                                sourceMapper.addRelation(videoSource);
+                            }
+                        }
+                        if (templatePlaceholder != null) {
+                            if (templatePlaceholder.contains(faceSample.getDeviceId().toString())) {
+                                if (!currentPlaceholder.contains(faceSample.getDeviceId().toString())) {
+                                    currentPlaceholder.add(faceSample.getDeviceId().toString());
+                                }
+                            }
+                            log.info("当前进度:{}/{}", currentPlaceholder.size(), collection.size());
+                            if (currentPlaceholder.size() >= collection.size()) {
+                                if (!invoke.get()) {
+                                    invoke.set(true);
+                                    task.getCallback().onInvoke();
+                                }
+                            }
+                        }
+                    });
+                });
         if (null != task.getCallback()) {
-            task.getCallback().onInvoke();
+            if (!invoke.get()) {
+                invoke.set(true);
+                task.getCallback().onInvoke();
+            }
         }
     }
 
diff --git a/src/main/resources/mapper/DeviceMapper.xml b/src/main/resources/mapper/DeviceMapper.xml
index 4b2ffb8..8fa38e2 100644
--- a/src/main/resources/mapper/DeviceMapper.xml
+++ b/src/main/resources/mapper/DeviceMapper.xml
@@ -96,6 +96,7 @@
         select *
         from device_config
         where device_id = #{deviceId}
+        limit 1
     </select>
     <select id="getByDeviceId" resultType="com.ycwl.basic.model.pc.device.entity.DeviceEntity">
         select *
diff --git a/src/main/resources/mapper/FaceSampleMapper.xml b/src/main/resources/mapper/FaceSampleMapper.xml
index 42632da..b1dfc5d 100644
--- a/src/main/resources/mapper/FaceSampleMapper.xml
+++ b/src/main/resources/mapper/FaceSampleMapper.xml
@@ -94,5 +94,6 @@
             #{id}
         </foreach>
         )
+        order by create_at desc
     </select>
 </mapper>
diff --git a/src/main/resources/mapper/MpNotifyConfigMapper.xml b/src/main/resources/mapper/MpNotifyConfigMapper.xml
index 33df7ba..02dff60 100644
--- a/src/main/resources/mapper/MpNotifyConfigMapper.xml
+++ b/src/main/resources/mapper/MpNotifyConfigMapper.xml
@@ -4,6 +4,6 @@
     <select id="listByMpId" resultType="com.ycwl.basic.model.pc.mp.MpNotifyConfigEntity">
         select *
         from mp_notify_config
-        where mp_id = #{mpId}
+        where mp_id = #{mpId} and status = 1
     </select>
 </mapper>
\ No newline at end of file
diff --git a/src/main/resources/mapper/SourceMapper.xml b/src/main/resources/mapper/SourceMapper.xml
index 6b8bd4a..20c6de0 100644
--- a/src/main/resources/mapper/SourceMapper.xml
+++ b/src/main/resources/mapper/SourceMapper.xml
@@ -163,4 +163,11 @@
         where ms.face_id = #{faceId} and ms.type = 1
         order by create_time desc
     </select>
+    <select id="listVideoByScenicFaceRelation" resultType="com.ycwl.basic.model.pc.source.entity.SourceEntity">
+        select s.*
+        from member_source ms
+            left join source s on ms.source_id = s.id
+        where ms.face_id = #{faceId} and ms.type = 1 and ms.scenic_id = #{scenicId}
+        order by create_time desc
+    </select>
 </mapper>
diff --git a/src/main/resources/mapper/TaskMapper.xml b/src/main/resources/mapper/TaskMapper.xml
index 3b61e2c..409ebe1 100644
--- a/src/main/resources/mapper/TaskMapper.xml
+++ b/src/main/resources/mapper/TaskMapper.xml
@@ -55,7 +55,7 @@
     </delete>
     <select id="list" resultType="com.ycwl.basic.model.pc.task.resp.TaskRespVO">
         select id, worker_id, face_id, member_id, template_id, scenic_id, task_params, video_url, `status`, result, create_time, update_time, start_time, end_time
-from task
+        from task
         <where>
             <if test="workerId!= null">and worker_id = #{workerId} </if>
             <if test="memberId!= null">and member_id = #{memberId} </if>
diff --git a/src/main/resources/mapper/TemplateMapper.xml b/src/main/resources/mapper/TemplateMapper.xml
index 1c3ab5b..f6ced4e 100644
--- a/src/main/resources/mapper/TemplateMapper.xml
+++ b/src/main/resources/mapper/TemplateMapper.xml
@@ -110,4 +110,9 @@
         from template t
         where t.scenic_id = #{scenicId} and t.pid = 0 and t.status = 1
     </select>
+    <select id="get" resultType="com.ycwl.basic.model.pc.template.entity.TemplateEntity">
+        select *
+        from template
+        where id = #{id}
+    </select>
 </mapper>