diff --git a/src/main/java/com/ycwl/basic/constant/TaskConstant.java b/src/main/java/com/ycwl/basic/constant/TaskConstant.java
new file mode 100644
index 0000000..15ff9a0
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/constant/TaskConstant.java
@@ -0,0 +1,7 @@
+package com.ycwl.basic.constant;
+
+public class TaskConstant {
+    public static final String TASK_TEMPLATE_KEY_PFX="task:template:cache:";
+    public static final String TASK_ONLINE_WORKER_KEY_PFX="task:online_worker:";
+    public static final String TASK_WORKER_TASK_KEY_PFX="task:worker:task:";
+}
diff --git a/src/main/java/com/ycwl/basic/controller/task/TaskTaskController.java b/src/main/java/com/ycwl/basic/controller/task/TaskTaskController.java
new file mode 100644
index 0000000..3585405
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/controller/task/TaskTaskController.java
@@ -0,0 +1,60 @@
+package com.ycwl.basic.controller.task;
+
+import com.ycwl.basic.annotation.IgnoreToken;
+import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
+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.utils.ApiResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+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;
+import org.springframework.web.bind.annotation.RestController;
+
+@IgnoreToken
+@RestController
+@RequestMapping("/task/v1/")
+public class TaskTaskController {
+
+    @Autowired
+    private TaskService taskService;
+    @PostMapping("/sync")
+    public ApiResponse<TaskSyncRespVo> sync(@RequestBody TaskReqVo req) {
+        TaskSyncRespVo respVo = taskService.handleSyncTask(req);
+        if (respVo == null) {
+            return ApiResponse.fail("错误");
+        }
+        return ApiResponse.success(respVo);
+    }
+
+    @PostMapping("/template/{templateId}")
+    public ApiResponse<TemplateRespVO> getTemplateById(@PathVariable Long templateId, @RequestBody WorkerAuthReqVo req) {
+        return ApiResponse.success(taskService.workerGetTemplate(templateId, req));
+    }
+
+    @PostMapping("/{taskId}/uploadUrl")
+    public ApiResponse<String> getUploadUrl(@PathVariable Long taskId, @RequestBody WorkerAuthReqVo req) {
+        return ApiResponse.success(taskService.getUploadUrl(taskId, req));
+    }
+
+    @PostMapping("/{taskId}/success")
+    public ApiResponse taskSuccess(@PathVariable Long taskId, @RequestBody WorkerAuthReqVo req) {
+        taskService.taskSuccess(taskId, req);
+        return ApiResponse.success("OK");
+    }
+
+    @PostMapping("/{taskId}/fail")
+    public ApiResponse taskFail(@PathVariable Long taskId, @RequestBody WorkerAuthReqVo req) {
+        taskService.taskFail(taskId, req);
+        return ApiResponse.success("OK");
+    }
+
+    @PostMapping("/test/createRenderTask/{scenicId}/{templateId}/{faceId}")
+    public ApiResponse<String> createRenderTask(@PathVariable Long scenicId, @PathVariable Long templateId, @PathVariable Long faceId) {
+        taskService.createRenderTask(scenicId, templateId, faceId);
+        return ApiResponse.success("ok");
+    }
+}
diff --git a/src/main/java/com/ycwl/basic/mapper/pc/RenderWorkerMapper.java b/src/main/java/com/ycwl/basic/mapper/pc/RenderWorkerMapper.java
index 8a9b1af..a84c737 100644
--- a/src/main/java/com/ycwl/basic/mapper/pc/RenderWorkerMapper.java
+++ b/src/main/java/com/ycwl/basic/mapper/pc/RenderWorkerMapper.java
@@ -19,4 +19,6 @@ public interface RenderWorkerMapper {
     int deleteById(Long id);
     int update(RenderWorkerEntity renderWorker);
     int updateStatus(Long id);
+
+    RenderWorkerEntity findByAccessKey(String accessKey);
 }
diff --git a/src/main/java/com/ycwl/basic/mapper/pc/TaskMapper.java b/src/main/java/com/ycwl/basic/mapper/pc/TaskMapper.java
index 2ba13ed..bf8d260 100644
--- a/src/main/java/com/ycwl/basic/mapper/pc/TaskMapper.java
+++ b/src/main/java/com/ycwl/basic/mapper/pc/TaskMapper.java
@@ -4,6 +4,7 @@ import com.ycwl.basic.model.pc.task.entity.TaskEntity;
 import com.ycwl.basic.model.pc.task.req.TaskReqQuery;
 import com.ycwl.basic.model.pc.task.resp.TaskRespVO;
 import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
 
@@ -41,4 +42,9 @@ public interface TaskMapper {
      * @return
      */
     int countByMemberIdStauFinish(String userId);
+
+    List<TaskRespVO> selectNotRunning();
+
+    void assignToWorker(@Param("taskId") Long taskId, @Param("workerId") Long workerId);
+    void deassign(@Param("taskId") Long taskId);
 }
diff --git a/src/main/java/com/ycwl/basic/model/pc/faceSample/resp/FaceSampleRespVO.java b/src/main/java/com/ycwl/basic/model/pc/faceSample/resp/FaceSampleRespVO.java
index b3d7ea1..2d5c445 100644
--- a/src/main/java/com/ycwl/basic/model/pc/faceSample/resp/FaceSampleRespVO.java
+++ b/src/main/java/com/ycwl/basic/model/pc/faceSample/resp/FaceSampleRespVO.java
@@ -55,4 +55,5 @@ public class FaceSampleRespVO {
     private Date createAt;
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private Date updateAt;
+    private Long sourceId;
 }
diff --git a/src/main/java/com/ycwl/basic/model/pc/member/resp/MemberRespVO.java b/src/main/java/com/ycwl/basic/model/pc/member/resp/MemberRespVO.java
index 2966f8e..fd12f5e 100644
--- a/src/main/java/com/ycwl/basic/model/pc/member/resp/MemberRespVO.java
+++ b/src/main/java/com/ycwl/basic/model/pc/member/resp/MemberRespVO.java
@@ -70,4 +70,5 @@ public class MemberRespVO {
     private Date createDate;
     @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
     private Date updateAt;
+    private Integer orderCount;
 }
diff --git a/src/main/java/com/ycwl/basic/model/pc/order/req/OrderReqQuery.java b/src/main/java/com/ycwl/basic/model/pc/order/req/OrderReqQuery.java
index a73b200..55940f4 100644
--- a/src/main/java/com/ycwl/basic/model/pc/order/req/OrderReqQuery.java
+++ b/src/main/java/com/ycwl/basic/model/pc/order/req/OrderReqQuery.java
@@ -17,6 +17,7 @@ import java.util.Date;
 @Data
 @ApiModel(value = "订单查询对象")
 public class OrderReqQuery extends BaseQueryParameterReq {
+    private Long id;
     private Long memberId;
     @ApiModelProperty("用户昵称")
     private String memberNickname;
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 0465039..64b9eeb 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
@@ -24,6 +24,10 @@ public class TaskEntity {
      * 用户ID,可以不和用户关联
      */
     private Long memberId;
+    /**
+     * 人脸ID,face.id
+     */
+    private Long faceId;
     /**
      * 模板ID
      */
diff --git a/src/main/java/com/ycwl/basic/model/task/req/ClientStatusReqVo.java b/src/main/java/com/ycwl/basic/model/task/req/ClientStatusReqVo.java
new file mode 100644
index 0000000..dfd0019
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/task/req/ClientStatusReqVo.java
@@ -0,0 +1,18 @@
+package com.ycwl.basic.model.task.req;
+
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+@Data
+public class ClientStatusReqVo {
+    private String platform;
+    private String runtime_version;
+    private String version;
+    private Integer cpu_count;
+    private BigDecimal cpu_usage;
+    private BigDecimal memory_total;
+    private BigDecimal memory_available;
+    private List<String> support_feature;
+}
diff --git a/src/main/java/com/ycwl/basic/model/task/req/TaskReqVo.java b/src/main/java/com/ycwl/basic/model/task/req/TaskReqVo.java
new file mode 100644
index 0000000..961c9fa
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/task/req/TaskReqVo.java
@@ -0,0 +1,10 @@
+package com.ycwl.basic.model.task.req;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class TaskReqVo extends WorkerAuthReqVo {
+    private ClientStatusReqVo clientStatus;
+}
diff --git a/src/main/java/com/ycwl/basic/model/task/req/WorkerAuthReqVo.java b/src/main/java/com/ycwl/basic/model/task/req/WorkerAuthReqVo.java
new file mode 100644
index 0000000..7ec1675
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/task/req/WorkerAuthReqVo.java
@@ -0,0 +1,9 @@
+package com.ycwl.basic.model.task.req;
+
+import lombok.Data;
+
+@Data
+public class WorkerAuthReqVo {
+    private String accessKey;
+
+}
diff --git a/src/main/java/com/ycwl/basic/model/task/resp/TaskItemRespVo.java b/src/main/java/com/ycwl/basic/model/task/resp/TaskItemRespVo.java
new file mode 100644
index 0000000..a2ae271
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/task/resp/TaskItemRespVo.java
@@ -0,0 +1,7 @@
+package com.ycwl.basic.model.task.resp;
+
+import lombok.Data;
+
+@Data
+public class TaskItemRespVo {
+}
diff --git a/src/main/java/com/ycwl/basic/model/task/resp/TaskSyncRespVo.java b/src/main/java/com/ycwl/basic/model/task/resp/TaskSyncRespVo.java
new file mode 100644
index 0000000..6aac186
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/model/task/resp/TaskSyncRespVo.java
@@ -0,0 +1,14 @@
+package com.ycwl.basic.model.task.resp;
+
+import com.ycwl.basic.model.pc.task.resp.TaskRespVO;
+import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
+import lombok.Data;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Data
+public class TaskSyncRespVo {
+    private List<TaskRespVO> tasks = new ArrayList<>();
+    private List<TemplateRespVO> templates = new ArrayList<>();
+}
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
new file mode 100644
index 0000000..4265a19
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/service/impl/task/TaskTaskServiceImpl.java
@@ -0,0 +1,216 @@
+package com.ycwl.basic.service.impl.task;
+
+import com.alibaba.fastjson.JSON;
+import com.ycwl.basic.constant.TaskConstant;
+import com.ycwl.basic.mapper.pc.FaceMapper;
+import com.ycwl.basic.mapper.pc.FaceSampleMapper;
+import com.ycwl.basic.mapper.pc.RenderWorkerMapper;
+import com.ycwl.basic.mapper.pc.SourceMapper;
+import com.ycwl.basic.mapper.pc.TaskMapper;
+import com.ycwl.basic.mapper.pc.TemplateMapper;
+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.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.req.TemplateReqQuery;
+import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
+import com.ycwl.basic.model.task.req.ClientStatusReqVo;
+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.utils.OssUtil;
+import com.ycwl.basic.utils.SnowFlakeUtil;
+import lombok.NonNull;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.stream.Collectors;
+
+@Service
+public class TaskTaskServiceImpl implements TaskService {
+    @Autowired
+    private TemplateMapper templateMapper;
+    @Autowired
+    private RenderWorkerMapper renderWorkerMapper;
+    @Autowired
+    private TaskMapper taskMapper;
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate;
+    @Autowired
+    private FaceMapper faceMapper;
+    @Autowired
+    private FaceSampleMapper faceSampleMapper;
+    @Autowired
+    private SourceMapper sourceMapper;
+    @Autowired
+    private OssUtil ossUtil;
+
+    private RenderWorkerEntity getWorker(@NonNull WorkerAuthReqVo req) {
+        String accessKey = req.getAccessKey();
+        if (accessKey == null) {
+            return null;
+        }
+        RenderWorkerEntity worker = renderWorkerMapper.findByAccessKey(accessKey);
+        return worker;
+    }
+
+    @Override
+    public TaskSyncRespVo handleSyncTask(@NonNull TaskReqVo req) {
+        RenderWorkerEntity worker = getWorker(req);
+        if (worker == null) {
+            return null;
+        }
+        worker.setOnline(1);
+        worker.setName(null);
+        worker.setStatus(null);
+        // get status
+        ClientStatusReqVo clientStatus = req.getClientStatus();
+        if (clientStatus != null) {
+            // 临时这么用下
+            worker.setCpuCount(clientStatus.getCpu_count());
+            worker.setCpuUsage(clientStatus.getCpu_usage());
+            // 上报的是字节,存储的是兆
+            worker.setMemoryAvailable(clientStatus.getMemory_available().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));
+            worker.setMemoryTotal(clientStatus.getMemory_total().divide(BigDecimal.valueOf(1024 * 1024), RoundingMode.CEILING));
+
+            worker.setPlatform(clientStatus.getPlatform());
+            worker.setRuntimeVersion(clientStatus.getRuntime_version());
+            worker.setSupportFeature(String.join(",", clientStatus.getSupport_feature()));
+            worker.setVersion(clientStatus.getVersion());
+
+            worker.setUpdateAt(new Date());
+            redisTemplate.opsForValue().set(TaskConstant.TASK_ONLINE_WORKER_KEY_PFX + worker.getId(), JSON.toJSONString(clientStatus), 60, TimeUnit.SECONDS);
+        }
+        renderWorkerMapper.update(worker);
+        TaskSyncRespVo resp = new TaskSyncRespVo();
+        // Template
+        String cacheJson = redisTemplate.opsForValue().get(TaskConstant.TASK_TEMPLATE_KEY_PFX + worker.getId());
+        if (cacheJson == null) {
+            List<TemplateRespVO> templateList = templateMapper.list(new TemplateReqQuery());
+            for (TemplateRespVO template : templateList) {
+                template.setChildren(templateMapper.getByPid(template.getId()));
+            }
+            resp.setTemplates(templateList);
+            redisTemplate.opsForValue().set(TaskConstant.TASK_TEMPLATE_KEY_PFX + worker.getId(), JSON.toJSONString(templateList), 60, TimeUnit.SECONDS);
+        } else {
+            resp.setTemplates(JSON.parseArray(cacheJson, TemplateRespVO.class));
+        }
+        List<TaskRespVO> taskList = taskMapper.selectNotRunning();
+        resp.setTasks(taskList);
+        taskList.forEach(task -> {
+            taskMapper.assignToWorker(task.getId(), worker.getId());
+        });
+        // return Task
+        return resp;
+    }
+
+    @Override
+    public void createRenderTask(Long scenicId, Long templateId, Long faceId) {
+        // 有人脸,找视频
+        if (faceId == null) {
+            return;
+        }
+        FaceRespVO faceRespVO = faceMapper.getById(faceId);
+        if (faceRespVO == null) {
+            return;
+        }
+        Map<String, List<SourceRespVO>> sourcesMap = Arrays.stream(faceRespVO.getMatchSampleIds().split(","))
+                .map(Long::valueOf)
+                .map(sampleId -> {
+                    return faceSampleMapper.getById(sampleId);
+                })
+                .filter(Objects::nonNull)
+                .map(FaceSampleRespVO::getSourceId)
+                .map(sourceId -> sourceMapper.getById(sourceId))
+                .collect(Collectors.groupingBy(item -> item.getDeviceId().toString()));
+        TaskEntity taskEntity = new TaskEntity();
+        taskEntity.setId(SnowFlakeUtil.getLongId());
+        taskEntity.setFaceId(faceId);
+        taskEntity.setMemberId(faceRespVO.getMemberId());
+        taskEntity.setTemplateId(templateId);
+        taskEntity.setScenicId(scenicId);
+        taskEntity.setTaskParams(JSON.toJSONString(sourcesMap));
+        taskEntity.setStatus(0);
+        taskMapper.add(taskEntity);
+    }
+
+    @Override
+    public TemplateRespVO workerGetTemplate(@NonNull Long templateId, @NonNull WorkerAuthReqVo req) {
+        if (templateId == null) {
+            return null;
+        }
+        RenderWorkerEntity worker = getWorker(req);
+        if (worker == null) {
+            return null;
+        }
+        TemplateRespVO respVO = templateMapper.getById(templateId);
+        respVO.setChildren(templateMapper.getByPid(templateId));
+        return respVO;
+    }
+
+    @Override
+    public void taskSuccess(@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.setStatus(1);
+        taskUpdate.setWorkerId(worker.getId());
+        taskMapper.update(taskUpdate);
+    }
+
+    @Override
+    public void taskFail(Long taskId, 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.setStatus(2);
+        taskUpdate.setWorkerId(worker.getId());
+        taskMapper.update(taskUpdate);
+        taskMapper.deassign(taskId);
+    }
+
+    @Override
+    public String getUploadUrl(Long taskId, WorkerAuthReqVo req) {
+        TaskRespVO task = taskMapper.getById(taskId);
+        if (task == null) {
+            return null;
+        }
+        String filename = task.getId() + "_" + task.getScenicId() + ".mp4";
+        if (StringUtils.isBlank(task.getVideoUrl())) {
+            // 生成
+            String url = ossUtil.generateUrlOfFile("user-video/", filename);
+            TaskEntity updateTask = new TaskEntity();
+            updateTask.setId(taskId);
+            updateTask.setVideoUrl(url);
+            taskMapper.update(updateTask);
+        }
+        return ossUtil.generateSignedUrlForUpload("user-video/", filename);
+    }
+}
diff --git a/src/main/java/com/ycwl/basic/service/task/TaskService.java b/src/main/java/com/ycwl/basic/service/task/TaskService.java
new file mode 100644
index 0000000..85366ed
--- /dev/null
+++ b/src/main/java/com/ycwl/basic/service/task/TaskService.java
@@ -0,0 +1,19 @@
+package com.ycwl.basic.service.task;
+
+import com.ycwl.basic.model.pc.template.resp.TemplateRespVO;
+import com.ycwl.basic.model.task.req.TaskReqVo;
+import com.ycwl.basic.model.task.req.WorkerAuthReqVo;
+import com.ycwl.basic.model.task.resp.TaskSyncRespVo;
+
+public interface TaskService {
+    TaskSyncRespVo handleSyncTask(TaskReqVo req);
+    void createRenderTask(Long scenicId, Long templateId, Long faceId);
+
+    TemplateRespVO workerGetTemplate(Long templateId, WorkerAuthReqVo req);
+
+    void taskSuccess(Long taskId, WorkerAuthReqVo req);
+
+    void taskFail(Long taskId, WorkerAuthReqVo req);
+
+    String getUploadUrl(Long taskId, WorkerAuthReqVo req);
+}
diff --git a/src/main/java/com/ycwl/basic/utils/OssUtil.java b/src/main/java/com/ycwl/basic/utils/OssUtil.java
index df6e763..042be00 100644
--- a/src/main/java/com/ycwl/basic/utils/OssUtil.java
+++ b/src/main/java/com/ycwl/basic/utils/OssUtil.java
@@ -1,6 +1,8 @@
 package com.ycwl.basic.utils;
 
+import cn.hutool.core.date.DateUtil;
 import com.aliyun.oss.ClientException;
+import com.aliyun.oss.HttpMethod;
 import com.aliyun.oss.OSS;
 import com.aliyun.oss.OSSClientBuilder;
 import com.aliyun.oss.OSSException;
@@ -12,6 +14,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Component;
 
 import java.io.InputStream;
+import java.util.Date;
 
 @Slf4j
 @Component
@@ -27,7 +30,15 @@ public class OssUtil {
      * @return
      */
     public String uploadFile(InputStream inputStream, String filename) {
-        String uploadFileName = ossConfig.getObjectName() + filename;
+        return uploadFile(inputStream, ossConfig.getObjectName(), filename);
+    }
+
+    public String uploadAssetFile(InputStream inputStream, String filename) {
+        return uploadFile(inputStream, "assets/", filename);
+    }
+
+    public String uploadFile(InputStream inputStream, String path, String filename) {
+        String uploadFileName = path + filename;
         OSS ossClient = new OSSClientBuilder().build(ossConfig.getEndPoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());
         try {
             PutObjectRequest putObjectRequest = new PutObjectRequest(ossConfig.getBucketName(), uploadFileName, inputStream);
@@ -57,6 +68,24 @@ public class OssUtil {
         return BizCodeEnum.UPLOAD_FAILED.getMessage();
     }
 
+    public String generateSignedUrlForDownload(String path, String filename) {
+        String downloadFile = path + filename;
+        return generateSignedUrl(downloadFile, HttpMethod.GET);
+    }
+
+    public String generateSignedUrlForUpload(String path, String filename) {
+        String uploadFileName = path + filename;
+        return generateSignedUrl(uploadFileName, HttpMethod.PUT);
+    }
+
+    public String generateSignedUrl(String objectName, HttpMethod method) {
+        OSS ossClient = new OSSClientBuilder().build(ossConfig.getEndPoint(), ossConfig.getAccessKeyId(), ossConfig.getAccessKeySecret());
+        return ossClient.generatePresignedUrl(ossConfig.getBucketName(), objectName, DateUtil.offsetHour(new Date(), 1), method).toString();
+    }
+    public String generateUrlOfFile(String path, String filename) {
+        String objectName = path + filename;
+        return ossConfig.getUrl() + objectName;
+    }
 
     public boolean deleteFile(String filename) {
         // 填写文件完整路径。文件完整路径中不能包含Bucket名称。
diff --git a/src/main/resources/mapper/pc/FaceSampleMapper.xml b/src/main/resources/mapper/pc/FaceSampleMapper.xml
index 7315c6a..649539c 100644
--- a/src/main/resources/mapper/pc/FaceSampleMapper.xml
+++ b/src/main/resources/mapper/pc/FaceSampleMapper.xml
@@ -2,15 +2,21 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.ycwl.basic.mapper.pc.FaceSampleMapper">
     <insert id="add">
-        insert into face_sample(id, device_id, face_url, match_sample_ids, first_match_rate, match_result,`status`)
-        values (#{id}, #{deviceId}, #{faceUrl}, #{matchSampleIds}, #{firstMatchRate}, #{matchResult},#{status})
+        insert into face_sample(id, scenic_id, device_id, source_id, face_url, match_sample_ids, first_match_rate, match_result,`status`)
+        values (#{id}, #{scenicId}, #{deviceId}, #{sourceId}, #{faceUrl}, #{matchSampleIds}, #{firstMatchRate}, #{matchResult},#{status})
     </insert>
     <update id="update">
         update face_sample
         <set>
+            <if test="scenicId!= null ">
+                scenic_id = #{scenicId},
+            </if>
             <if test="deviceId!= null ">
                 device_id = #{deviceId},
             </if>
+            <if test="sourceId!= null ">
+                source_id = #{sourceId},
+            </if>
             <if test="faceUrl!= null and faceUrl!= ''">
                 face_url = #{faceUrl},
             </if>
@@ -42,15 +48,18 @@
         </if>
     </delete>
     <select id="list" resultType="com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO">
-        select id, scenic_id, device_id, face_url, match_sample_ids, first_match_rate, match_result,`status`
+        select id, scenic_id, device_id, face_url, source_id, match_sample_ids, first_match_rate, match_result,`status`
         from face_sample
         <where>
             <if test="scenicId!= null and scenicId!= ''">
-                and device_id = #{deviceId}
+                and scenic_id = #{scenicId}
             </if>
             <if test="deviceId!= null and deviceId!= ''">
                 and device_id = #{deviceId}
             </if>
+            <if test="source_id!= null and source_id!= ''">
+                and source_id = #{source_id}
+            </if>
             <if test="matchSampleIds!= null and matchSampleIds!= ''">
                 and match_sample_ids like concat('%', #{matchSampleIds}, '%')
             </if>
@@ -72,7 +81,7 @@
         </where>
     </select>
     <select id="getById" resultType="com.ycwl.basic.model.pc.faceSample.resp.FaceSampleRespVO">
-        select id, scenic_id, device_id, face_url, match_sample_ids, first_match_rate, match_result,`status`
+        select id, scenic_id, device_id, face_url, match_sample_ids, first_match_rate, source_id, match_result,`status`
         from face_sample
         where id = #{id}
     </select>
diff --git a/src/main/resources/mapper/pc/MemberMapper.xml b/src/main/resources/mapper/pc/MemberMapper.xml
index 4108d7f..6d75ccd 100644
--- a/src/main/resources/mapper/pc/MemberMapper.xml
+++ b/src/main/resources/mapper/pc/MemberMapper.xml
@@ -3,13 +3,13 @@
 <mapper namespace="com.ycwl.basic.mapper.pc.MemberMapper">
     <insert id="add">
         insert into member(id, openid, nickname, real_name, promo_code, broker_id, agreement, phone, country, province, city)
-        values (#{id}, #{openid}, #{nickname}, #{realName}, #{promoCode}, #{brokerId}, #{agreement}, #{phone}, #{country}, #{province}, #{city})
+        values (#{id}, #{openId}, #{nickname}, #{realName}, #{promoCode}, #{brokerId}, #{agreement}, #{phone}, #{country}, #{province}, #{city})
     </insert>
     <update id="update">
         update member
         <set>
-            <if test="openid!= null and openid!= ''">
-                openid = #{openid},
+            <if test="openId!= null and openId!= ''">
+                openid = #{openId},
             </if>
             <if test="nickname!= null and nickname!= ''">
                 nickname = #{nickname},
@@ -45,11 +45,13 @@
         delete from member where id = #{id}
     </delete>
     <select id="list" resultType="com.ycwl.basic.model.pc.member.resp.MemberRespVO">
-        select id, openid, nickname, real_name, promo_code, broker_id, agreement, phone, country, province, city
+        select id, openid, nickname, real_name, promo_code, broker_id, agreement, phone, country, province, city,
+               (select count(1) from `order` where `order`.member_id = member.id) as order_count,
+               create_date
 from member
         <where>
-            <if test="openid!= null and openid!= ''">
-                and openid like concat('%',#{openid},'%')
+            <if test="openId!= null and openId!= ''">
+                and openid like concat('%',#{openId},'%')
             </if>
             <if test="nickname!= null and nickname!= ''">
                 and nickname like concat('%',#{nickname},'%')
diff --git a/src/main/resources/mapper/pc/RenderWorkerMapper.xml b/src/main/resources/mapper/pc/RenderWorkerMapper.xml
index c5bc9ea..8bbab5b 100644
--- a/src/main/resources/mapper/pc/RenderWorkerMapper.xml
+++ b/src/main/resources/mapper/pc/RenderWorkerMapper.xml
@@ -121,4 +121,9 @@
         from render_worker
         where id = #{id}
     </select>
+    <select id="findByAccessKey" resultType="com.ycwl.basic.model.pc.renderWorker.entity.RenderWorkerEntity">
+        select id, `name`, scenic_only, test_only, `online`, `status`, create_at, update_at
+        from render_worker
+        where access_key = #{accessKey} and status = 1
+    </select>
 </mapper>
\ No newline at end of file
diff --git a/src/main/resources/mapper/pc/TaskMapper.xml b/src/main/resources/mapper/pc/TaskMapper.xml
index e3714d4..e9284a7 100644
--- a/src/main/resources/mapper/pc/TaskMapper.xml
+++ b/src/main/resources/mapper/pc/TaskMapper.xml
@@ -24,6 +24,16 @@
         set status = #{status}
         where id = #{id}
     </update>
+    <update id="assignToWorker">
+        update task
+        set worker_id = #{workerId}
+        where id = #{taskId}
+    </update>
+    <update id="deassign">
+        update task
+        set worker_id = null
+        where id = #{taskId}
+    </update>
     <delete id="deleteById">
         delete from task where id = #{id}
     </delete>
@@ -55,4 +65,9 @@ from task
         where member_id = #{userId}
           and status = 1
     </select>
+    <select id="selectNotRunning" 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
+        from task
+        where status = 0 and worker_id is null
+    </select>
 </mapper>
\ No newline at end of file
diff --git a/src/main/resources/mapper/pc/TemplateMapper.xml b/src/main/resources/mapper/pc/TemplateMapper.xml
index 67927fb..f9143d2 100644
--- a/src/main/resources/mapper/pc/TemplateMapper.xml
+++ b/src/main/resources/mapper/pc/TemplateMapper.xml
@@ -45,7 +45,7 @@
         delete from template where scenic_id = #{id}
     </delete>
     <select id="list" resultType="com.ycwl.basic.model.pc.template.resp.TemplateRespVO">
-        select t.id, t.scenic_id, s.name as scenic_name, t.`name`, pid, is_placeholder, source_url, luts, overlays, audios, frame_rate, speed, cover_url, t.status, t.create_time, t.update_time
+        select t.id, t.scenic_id, s.name as scenic_name, t.`name`, cover_url, t.status, t.create_time, t.update_time
         from template t left join scenic s on s.id = t.scenic_id
         <where>
             pid = 0