浏览代码

Merge branch 'release' into project-jmga-test

# Conflicts:
#	src/main/java/com/fdkankan/scene/service/impl/SceneEditInfoServiceImpl.java
#	src/main/java/com/fdkankan/scene/service/impl/ScenePlusServiceImpl.java
#	src/main/java/com/fdkankan/scene/service/impl/SceneProServiceImpl.java
#	src/main/java/com/fdkankan/scene/service/impl/SceneServiceImpl.java
dsx 2 年之前
父节点
当前提交
dede33137c
共有 85 个文件被更改,包括 4157 次插入486 次删除
  1. 6 0
      pom.xml
  2. 22 0
      src/main/java/com/fdkankan/scene/bean/BodySegmentStatusBean.java
  3. 11 0
      src/main/java/com/fdkankan/scene/bean/SceneBean.java
  4. 17 8
      src/main/java/com/fdkankan/scene/bean/SceneJsonBean.java
  5. 51 0
      src/main/java/com/fdkankan/scene/config/ScheduledConfig.java
  6. 0 45
      src/main/java/com/fdkankan/scene/config/Test.java
  7. 21 0
      src/main/java/com/fdkankan/scene/controller/SceneAsynOperLogController.java
  8. 21 0
      src/main/java/com/fdkankan/scene/controller/SceneCleanOrigController.java
  9. 21 0
      src/main/java/com/fdkankan/scene/controller/SceneColdStorageLogController.java
  10. 29 6
      src/main/java/com/fdkankan/scene/controller/SceneController.java
  11. 81 39
      src/main/java/com/fdkankan/scene/controller/SceneEditController.java
  12. 150 0
      src/main/java/com/fdkankan/scene/controller/SceneMarkShapeController.java
  13. 4 4
      src/main/java/com/fdkankan/scene/controller/TestController.java
  14. 105 0
      src/main/java/com/fdkankan/scene/entity/SceneAsynOperLog.java
  15. 69 0
      src/main/java/com/fdkankan/scene/entity/SceneCleanOrig.java
  16. 72 0
      src/main/java/com/fdkankan/scene/entity/SceneColdStorage.java
  17. 75 0
      src/main/java/com/fdkankan/scene/entity/SceneColdStorageLog.java
  18. 50 0
      src/main/java/com/fdkankan/scene/entity/SceneEditControls.java
  19. 12 0
      src/main/java/com/fdkankan/scene/entity/SceneEditInfoExt.java
  20. 74 0
      src/main/java/com/fdkankan/scene/entity/SceneMarkShape.java
  21. 6 0
      src/main/java/com/fdkankan/scene/entity/ScenePlus.java
  22. 6 0
      src/main/java/com/fdkankan/scene/entity/ScenePlusExt.java
  23. 3 3
      src/main/java/com/fdkankan/scene/generate/AutoGenerate.java
  24. 33 0
      src/main/java/com/fdkankan/scene/httpclient/MyClient.java
  25. 26 5
      src/main/java/com/fdkankan/scene/listener/RabbitMqListener.java
  26. 18 0
      src/main/java/com/fdkankan/scene/mapper/ISceneAsynOperLogMapper.java
  27. 18 0
      src/main/java/com/fdkankan/scene/mapper/ISceneCleanOrigMapper.java
  28. 18 0
      src/main/java/com/fdkankan/scene/mapper/ISceneColdStorageLogMapper.java
  29. 18 0
      src/main/java/com/fdkankan/scene/mapper/ISceneColdStorageMapper.java
  30. 13 0
      src/main/java/com/fdkankan/scene/mapper/IScenePlusMapper.java
  31. 15 0
      src/main/java/com/fdkankan/scene/mapper/ISceneProMapper.java
  32. 16 0
      src/main/java/com/fdkankan/scene/mapper/MarkShapeMapper.java
  33. 190 0
      src/main/java/com/fdkankan/scene/schedule/ScheduleJob.java
  34. 5 0
      src/main/java/com/fdkankan/scene/service/ICameraService.java
  35. 24 0
      src/main/java/com/fdkankan/scene/service/ISceneAsynOperLogService.java
  36. 32 0
      src/main/java/com/fdkankan/scene/service/ISceneCleanOrigService.java
  37. 16 0
      src/main/java/com/fdkankan/scene/service/ISceneColdStorageLogService.java
  38. 18 0
      src/main/java/com/fdkankan/scene/service/ISceneColdStorageService.java
  39. 13 0
      src/main/java/com/fdkankan/scene/service/ISceneEditInfoExtService.java
  40. 5 8
      src/main/java/com/fdkankan/scene/service/ISceneEditInfoService.java
  41. 2 0
      src/main/java/com/fdkankan/scene/service/ISceneEditService.java
  42. 30 0
      src/main/java/com/fdkankan/scene/service/ISceneMarkShapeService.java
  43. 11 0
      src/main/java/com/fdkankan/scene/service/IScenePlusService.java
  44. 11 0
      src/main/java/com/fdkankan/scene/service/ISceneProService.java
  45. 16 0
      src/main/java/com/fdkankan/scene/service/ISceneService.java
  46. 11 0
      src/main/java/com/fdkankan/scene/service/impl/CameraServiceImpl.java
  47. 118 0
      src/main/java/com/fdkankan/scene/service/impl/SceneAsynOperLogServiceImpl.java
  48. 298 0
      src/main/java/com/fdkankan/scene/service/impl/SceneCleanOrigServiceImpl.java
  49. 33 0
      src/main/java/com/fdkankan/scene/service/impl/SceneColdStorageLogServiceImpl.java
  50. 36 0
      src/main/java/com/fdkankan/scene/service/impl/SceneColdStorageServiceImpl.java
  51. 380 4
      src/main/java/com/fdkankan/scene/service/impl/SceneEditInfoExtServiceImpl.java
  52. 338 141
      src/main/java/com/fdkankan/scene/service/impl/SceneEditInfoServiceImpl.java
  53. 24 3
      src/main/java/com/fdkankan/scene/service/impl/SceneEditServiceImpl.java
  54. 181 0
      src/main/java/com/fdkankan/scene/service/impl/SceneMarkShapeServiceImpl.java
  55. 36 5
      src/main/java/com/fdkankan/scene/service/impl/ScenePlusServiceImpl.java
  56. 282 136
      src/main/java/com/fdkankan/scene/service/impl/SceneProServiceImpl.java
  57. 169 0
      src/main/java/com/fdkankan/scene/service/impl/SceneServiceImpl.java
  58. 12 0
      src/main/java/com/fdkankan/scene/service/impl/SurveillanceServiceImpl.java
  59. 121 0
      src/main/java/com/fdkankan/scene/util/ConverxyUtil.java
  60. 98 0
      src/main/java/com/fdkankan/scene/util/OssBodySegmentUtil.java
  61. 97 0
      src/main/java/com/fdkankan/scene/util/test.java
  62. 29 0
      src/main/java/com/fdkankan/scene/vo/BaseJsonArrayParamVO.java
  63. 23 0
      src/main/java/com/fdkankan/scene/vo/DeleteSidListParamVO.java
  64. 1 4
      src/main/java/com/fdkankan/scene/vo/DeleteLinkSceneStylesParamVO.java
  65. 20 0
      src/main/java/com/fdkankan/scene/vo/SaveFiltersParamVO.java
  66. 35 0
      src/main/java/com/fdkankan/scene/vo/SceneAsynOperLogParamVO.java
  67. 44 0
      src/main/java/com/fdkankan/scene/vo/SceneEditControlsParamVO.java
  68. 40 0
      src/main/java/com/fdkankan/scene/vo/SceneEditControlsVO.java
  69. 6 0
      src/main/java/com/fdkankan/scene/vo/SceneEditInfoParamVO.java
  70. 21 0
      src/main/java/com/fdkankan/scene/vo/SceneInfoVO.java
  71. 39 0
      src/main/java/com/fdkankan/scene/vo/SceneMarkShapeDetectParamVO.java
  72. 36 0
      src/main/java/com/fdkankan/scene/vo/SceneMarkShapeParamVO.java
  73. 46 0
      src/main/java/com/fdkankan/scene/vo/SceneMarkShapeReDetectParamVO.java
  74. 2 0
      src/main/java/com/fdkankan/scene/vo/UploadPanoramaVO.java
  75. 13 50
      src/main/resources/bootstrap-prod-eur.yml
  76. 4 0
      src/main/resources/bootstrap-prod.yml
  77. 4 0
      src/main/resources/bootstrap-test-eur.yml
  78. 5 0
      src/main/resources/bootstrap-test.yml
  79. 5 0
      src/main/resources/mapper/scene/SceneAsynOperLogMapper.xml
  80. 5 0
      src/main/resources/mapper/scene/SceneCleanOrigMapper.xml
  81. 5 0
      src/main/resources/mapper/scene/SceneColdStorageLogMapper.xml
  82. 5 0
      src/main/resources/mapper/scene/SceneColdStorageMapper.xml
  83. 42 1
      src/main/resources/mapper/scene/ScenePlusMapper.xml
  84. 39 1
      src/main/resources/mapper/scene/SceneProMapper.xml
  85. 0 23
      src/test/java/com/fdkankan/scene/SceneApplicationTests.java

+ 6 - 0
pom.xml

@@ -146,6 +146,12 @@
             <version>6.8.1</version>
         </dependency>
 
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>imageseg20191230</artifactId>
+            <version>1.0.5</version>
+        </dependency>
+
     </dependencies>
 
     <dependencyManagement>

+ 22 - 0
src/main/java/com/fdkankan/scene/bean/BodySegmentStatusBean.java

@@ -0,0 +1,22 @@
+package com.fdkankan.scene.bean;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class BodySegmentStatusBean {
+
+    private String uuid;
+
+    private Integer status;
+
+    private String imageUrl;
+
+
+
+}

+ 11 - 0
src/main/java/com/fdkankan/scene/bean/SceneBean.java

@@ -0,0 +1,11 @@
+package com.fdkankan.scene.bean;
+
+import lombok.Data;
+
+@Data
+public class SceneBean {
+
+    private String num;
+
+    private String dataSource;
+}

+ 17 - 8
src/main/java/com/fdkankan/scene/bean/SceneJsonBean.java

@@ -3,14 +3,13 @@ package com.fdkankan.scene.bean;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.fdkankan.scene.vo.SceneEditControlsVO;
+import java.util.Date;
+import java.util.List;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
-import java.util.Date;
-import java.util.List;
-
 /**
  * <p>
  * scene.json实体类
@@ -92,11 +91,6 @@ public class SceneJsonBean {
      */
     private Integer linkVersion;
 
-//    /**
-//     * 户型图文件路径集合
-//     */
-//    private String[] floorPlanPaths;
-
     /**
      * 是否上传了户型图(0-否,1-是)
      */
@@ -123,6 +117,11 @@ public class SceneJsonBean {
     private String sceneKind;
 
     /**
+     * 算法模型类型(dam,3dtiles)
+     */
+    private String modelKind;
+
+    /**
      * 空间视频数据
      */
     private String boxVideos;
@@ -209,5 +208,15 @@ public class SceneJsonBean {
      */
     private Integer surveillances;
 
+    /**
+     * 分享信息
+     */
+    private JSONObject sns;
+
+    /**
+     * 是否有指示牌(0-否,1-是)
+     */
+    private Integer billboards;
+
 
 }

+ 51 - 0
src/main/java/com/fdkankan/scene/config/ScheduledConfig.java

@@ -0,0 +1,51 @@
+package com.fdkankan.scene.config;
+
+import org.springframework.boot.autoconfigure.batch.BatchProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.scheduling.annotation.SchedulingConfigurer;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+import org.springframework.scheduling.config.ScheduledTaskRegistrar;
+import org.springframework.util.CollectionUtils;
+
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.concurrent.Executors;
+
+@Configuration
+public class ScheduledConfig implements SchedulingConfigurer {
+
+    /**
+     * 此配置实现:
+     * 1、同一个定时任务等待上一次执行完毕后再执行
+     * 2、不同定时任务同时执行
+     * @param taskRegistrar
+     */
+    @Override
+    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
+        Method[] methods = BatchProperties.Job.class.getMethods();
+        int defaultPoolSize = 3;
+        int corePoolSize = 0;
+
+        if (!CollectionUtils.isEmpty(Arrays.asList(methods))) {
+
+            for (Method method : methods) {
+
+                Scheduled annotation = method.getAnnotation(Scheduled.class);
+
+                if (annotation != null) {
+
+                    corePoolSize++;
+                }
+            }
+            if (defaultPoolSize > corePoolSize) {
+
+                corePoolSize = defaultPoolSize;
+            }
+
+            taskRegistrar.setScheduler(Executors.newScheduledThreadPool(corePoolSize));
+        }
+    }
+}

+ 0 - 45
src/main/java/com/fdkankan/scene/config/Test.java

@@ -1,45 +0,0 @@
-package com.fdkankan.scene.config;
-
-/**
- * <p>
- *  这是一个测试类
- * </p>
- *
- * @author dengsixing
- * @date 2022/1/12
- **/
-public class Test {
-
-    /**
-     * 这是一个类属性
-     */
-    private static final String TEST = "test";
-
-
-    /**
-     * <p>
-     *   这是一个测试方法
-     * </p>
-     * @author dengsixing
-     * @date 2022/1/12
-     * @param id 主键id
-     * @param name  姓名
-     * @return java.lang.String
-     **/
-    public String test(long id, String name){
-        return id + "-" + name;
-    }
-
-    public static void main(String[] args) {
-
-        //方法体内的单行注释
-        String test =  Test.TEST;
-
-        /*
-          方法体内多行注释
-         */
-        String test1 = new Test().test(1, "zhangsan");
-        System.out.println(test1);
-
-    }
-}

+ 21 - 0
src/main/java/com/fdkankan/scene/controller/SceneAsynOperLogController.java

@@ -0,0 +1,21 @@
+package com.fdkankan.scene.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ *  前端控制器
+ * </p>
+ *
+ * @author 
+ * @since 2022-12-07
+ */
+@RestController
+@RequestMapping("/scene/sceneAsynOperLog")
+public class SceneAsynOperLogController {
+
+}
+

+ 21 - 0
src/main/java/com/fdkankan/scene/controller/SceneCleanOrigController.java

@@ -0,0 +1,21 @@
+package com.fdkankan.scene.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * 删除oss原始资源记录 前端控制器
+ * </p>
+ *
+ * @author 
+ * @since 2023-03-29
+ */
+@RestController
+@RequestMapping("/scene/sceneCleanOrig")
+public class SceneCleanOrigController {
+
+}
+

+ 21 - 0
src/main/java/com/fdkankan/scene/controller/SceneColdStorageLogController.java

@@ -0,0 +1,21 @@
+package com.fdkankan.scene.controller;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * 场景冷归档日志表 前端控制器
+ * </p>
+ *
+ * @author 
+ * @since 2023-07-12
+ */
+@RestController
+@RequestMapping("/scene/sceneColdStorageLog")
+public class SceneColdStorageLogController {
+
+}
+

+ 29 - 6
src/main/java/com/fdkankan/scene/controller/SceneController.java

@@ -2,6 +2,8 @@ package com.fdkankan.scene.controller;
 
 
 import com.fdkankan.common.constant.SceneInfoReqType;
+import com.fdkankan.scene.annotation.CheckPermit;
+import com.fdkankan.scene.service.ISceneService;
 import com.fdkankan.web.response.ResultData;
 import com.fdkankan.scene.service.ISceneEditInfoService;
 import com.fdkankan.scene.service.IScenePlusService;
@@ -12,11 +14,8 @@ import com.fdkankan.scene.vo.SceneInfoVO;
 import com.fdkankan.web.controller.BaseController;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.GetMapping;
-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;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 
 /**
  * <p>
@@ -34,6 +33,8 @@ public class SceneController extends BaseController {
     private ISceneEditInfoService sceneEditInfoService;
     @Autowired
     private IScenePlusService scenePlusService;
+    @Autowired
+    private ISceneService sceneService;
 
     /**
      * <p>
@@ -70,7 +71,6 @@ public class SceneController extends BaseController {
      * </p>
      * @author dengsixing
      * @date 2022/8/1
-     * @param param
      * @return com.fdkankan.web.response.ResultData
      **/
     @GetMapping(value = "/downLoadZSData")
@@ -78,5 +78,28 @@ public class SceneController extends BaseController {
         return scenePlusService.downLoadZSData(sceneNum);
     }
 
+    /**
+     * 上传人体抠图原图
+     * @param num
+     * @param file
+     * @return
+     * @throws Exception
+     */
+    @PostMapping(value = "/uploadBodySegment")
+    public ResultData uploadBodySegment(@RequestParam("file") MultipartFile file,
+                                        @RequestParam(value = "rotate", required = false) Integer rotate) throws Exception {
+        return sceneService.uploadBodySegment(file, rotate);
+    }
+
+    /**
+     * 获取人体抠图提取状态
+     * @return ResultData
+     * @throws Exception
+     */
+    @PostMapping(value = "/getBodySegmentStatus")
+    public ResultData getBodySegmentStatus(@RequestParam(value = "serialNum") String uuid) throws Exception {
+        return sceneService.getBodySegmentStatus(uuid);
+    }
+
 }
 

+ 81 - 39
src/main/java/com/fdkankan/scene/controller/SceneEditController.java

@@ -3,44 +3,9 @@ package com.fdkankan.scene.controller;
 import com.fdkankan.common.constant.ErrorCode;
 import com.fdkankan.common.constant.SceneInfoReqType;
 import com.fdkankan.common.exception.BusinessException;
-import com.fdkankan.model.utils.CreateHouseJsonUtil;
 import com.fdkankan.scene.annotation.CheckPermit;
-import com.fdkankan.scene.service.IBoxModelService;
-import com.fdkankan.scene.service.IDownloadTourVideoService;
-import com.fdkankan.scene.service.ISceneEditInfoService;
-import com.fdkankan.scene.service.ISceneEditService;
-import com.fdkankan.scene.service.IScenePlusService;
-import com.fdkankan.scene.service.ISceneProService;
-import com.fdkankan.scene.service.ISceneUploadService;
-import com.fdkankan.scene.service.ISurveillanceService;
-import com.fdkankan.scene.vo.BallScreenVideoParamVO;
-import com.fdkankan.scene.vo.BaseDataParamVO;
-import com.fdkankan.scene.vo.BaseFileParamVO;
-import com.fdkankan.scene.vo.BaseJsonDataParamVO;
-import com.fdkankan.scene.vo.BaseSceneParamVO;
-import com.fdkankan.scene.vo.BaseSidParamVO;
-import com.fdkankan.scene.vo.DeleteFileParamVO;
-import com.fdkankan.scene.vo.DeleteHotIconParamVO;
-import com.fdkankan.scene.vo.DeleteHotParamVO;
-import com.fdkankan.scene.vo.DeleteLinkPanParamVO;
-import com.fdkankan.scene.vo.DeleteLinkSceneStylesParamVO;
-import com.fdkankan.scene.vo.DeleteMosaicParamVO;
-import com.fdkankan.scene.vo.DeleteSidParamVO;
-import com.fdkankan.scene.vo.DownloadVO;
-import com.fdkankan.scene.vo.FileNameAndDataParamVO;
-import com.fdkankan.scene.vo.FileParamVO;
-import com.fdkankan.scene.vo.LocalesParamVO;
-import com.fdkankan.scene.vo.RenameCadParamVO;
-import com.fdkankan.scene.vo.SaveLinkPanParamVO;
-import com.fdkankan.scene.vo.SaveTagsParamVO;
-import com.fdkankan.scene.vo.SaveTagsVisibleParamVO;
-import com.fdkankan.scene.vo.SceneAuthVO;
-import com.fdkankan.scene.vo.SceneEditInfoParamVO;
-import com.fdkankan.scene.vo.SceneEditInfoVO;
-import com.fdkankan.scene.vo.SceneInfoParamVO;
-import com.fdkankan.scene.vo.SceneInfoVO;
-import com.fdkankan.scene.vo.SurveillanceParamVO;
-import com.fdkankan.scene.vo.UploadContentParamVO;
+import com.fdkankan.scene.service.*;
+import com.fdkankan.scene.vo.*;
 import com.fdkankan.web.controller.BaseController;
 import com.fdkankan.web.response.ResultData;
 import java.io.IOException;
@@ -84,6 +49,10 @@ public class SceneEditController extends BaseController {
     private IBoxModelService boxModelService;
     @Autowired
     private IScenePlusService scenePlusService;
+    @Autowired
+    private ISceneAsynOperLogService sceneAsynOperLogService;
+    @Autowired
+    private ISceneEditInfoExtService sceneEditInfoExtService;
 
     /**
      * <p>
@@ -313,7 +282,7 @@ public class SceneEditController extends BaseController {
      **/
     @CheckPermit
     @PostMapping(value = "/styles/delete")
-    public ResultData deleteStyles(@RequestBody @Validated DeleteLinkSceneStylesParamVO param) throws Exception {
+    public ResultData deleteStyles(@RequestBody @Validated DeleteStylesParamVO param) throws Exception {
         return sceneEditInfoService.deleteStyles(param);
     }
 
@@ -755,7 +724,7 @@ public class SceneEditController extends BaseController {
      */
     @CheckPermit
     @PostMapping(value = "/filter/save")
-    public ResultData saveFilter(@RequestBody @Validated BaseDataParamVO param) throws Exception{
+    public ResultData saveFilter(@RequestBody @Validated SaveFiltersParamVO param) throws Exception{
         return sceneEditInfoService.saveFilter(param);
     }
 
@@ -857,5 +826,78 @@ public class SceneEditController extends BaseController {
         return scenePlusService.uploadShareLogo(num, file);
     }
 
+    /**
+     * <p>
+     删除空间模型
+     * </p>
+     * @author dengsixing
+     * @date 2022/10/19
+     * @param param
+     * @return com.fdkankan.common.response.ResultData
+     **/
+    @CheckPermit
+    @PostMapping("/getAsynOperLog")
+    public ResultData getAsynOperLog(@RequestBody @Validated SceneAsynOperLogParamVO param){
+        return sceneAsynOperLogService.getAsynOperLog(param);
+    }
+
+    /**
+     * 获取编辑器版本信息
+     * @return
+     */
+    @GetMapping("/getServiceUpTip")
+    public ResultData getServiceUpTip(){
+        return sceneEditService.getServiceUpTip();
+    }
+
+    /**
+     * 保存或者修改指示牌
+     * @param param
+     * @return
+     * @throws Exception
+     */
+    @CheckPermit
+    @PostMapping("/billboards/save")
+    public ResultData saveBillboards(@RequestBody @Validated BaseJsonArrayParamVO param) throws Exception {
+        return sceneEditInfoExtService.saveBillboards(param);
+    }
+
+    /**
+     * 删除指示牌
+     * @param param
+     * @return
+     * @throws Exception
+     */
+    @CheckPermit
+    @PostMapping("/billboards/delete")
+    public ResultData deleteBillboards(@RequestBody @Validated DeleteSidListParamVO param) throws Exception {
+        return sceneEditInfoExtService.deleteBillboards(param);
+    }
+
+    /**
+     * 获取指示牌列表
+     * @param param
+     * @return
+     * @throws Exception
+     */
+    @CheckPermit
+    @PostMapping("/billboards/list")
+    public ResultData deleteBillboards(@RequestBody @Validated BaseSceneParamVO param) throws Exception {
+        return ResultData.ok(sceneEditInfoExtService.listBillboards(param));
+    }
+
+    /**
+     * 获取指示牌列表
+     * @param param
+     * @return
+     * @throws Exception
+     */
+    @CheckPermit
+    @PostMapping("/billboards/styles/delete")
+    public ResultData deleteBillboards(@RequestBody @Validated DeleteStylesParamVO param) throws Exception {
+        return ResultData.ok(sceneEditInfoExtService.deleteBillboardsStyles(param));
+    }
+
+
 
 }

+ 150 - 0
src/main/java/com/fdkankan/scene/controller/SceneMarkShapeController.java

@@ -0,0 +1,150 @@
+package com.fdkankan.scene.controller;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
+import com.fdkankan.model.constants.UploadFilePath;
+import com.fdkankan.rabbitmq.util.RabbitMqProducer;
+import com.fdkankan.scene.entity.SceneMarkShape;
+import com.fdkankan.scene.entity.ScenePlus;
+import com.fdkankan.scene.entity.ScenePlusExt;
+import com.fdkankan.scene.service.ISceneMarkShapeService;
+import com.fdkankan.scene.service.IScenePlusExtService;
+import com.fdkankan.scene.service.IScenePlusService;
+import com.fdkankan.scene.vo.SceneMarkShapeDetectParamVO;
+import com.fdkankan.scene.vo.SceneMarkShapeParamVO;
+import com.fdkankan.scene.vo.SceneMarkShapeReDetectParamVO;
+import com.fdkankan.web.controller.BaseController;
+import com.fdkankan.web.response.ResultData;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 初始化接口
+ *
+ * @author fdkk
+ */
+@RestController
+@RequestMapping("/service/scene/sceneMarkShape")
+@Slf4j
+public class SceneMarkShapeController extends BaseController
+{
+    @Value("${queue.scene.yolov5-detect-queue}")
+    private String yolov5DetectQueue;
+    @Autowired
+    private ISceneMarkShapeService sceneMarkShapeService;
+    @Resource
+    private FYunFileServiceInterface fYunFileService;
+    @Autowired
+    private IScenePlusService scenePlusService;
+    @Autowired
+    private IScenePlusExtService scenePlusExtService;
+    @Value("${fyun.host}")
+    private String ossUrlPrefix;
+    @Autowired
+    private RabbitMqProducer rabbitMqProducer;
+    @Value("${main.url}")
+    private String mainUrl;
+
+
+    /**
+     * 获取场景全景图路径连接
+     */
+    @PostMapping("/getPanorama")
+    public ResultData getPanorama(@RequestBody @Validated  SceneMarkShapeParamVO param) {
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+        if(ObjectUtil.isNotNull(scenePlus)) {
+            ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
+            if (ObjectUtil.isNotNull(scenePlus)) {
+                String publicUserPath = String.format(UploadFilePath.scene_result_data_path, param.getNum());
+                List<String> panoramaList = fYunFileService.listRemoteFiles(scenePlusExt.getYunFileBucket(), publicUserPath + "caches/images/");
+                List<String> panoramaListUrl = panoramaList.stream().filter(f -> FileUtil.extName(f).equals("jpg")).map(s -> ossUrlPrefix + s).collect(Collectors.toList());
+                return ResultData.ok(panoramaListUrl);
+            }
+        }
+        return ResultData.ok("场景数据不存在");
+    }
+    /**
+     * 根据场景码和图片名称获取数据
+     */
+    @PostMapping("/getInfo")
+    public ResultData getInfo(@RequestBody @Validated  SceneMarkShapeParamVO param) {
+        SceneMarkShape res=  sceneMarkShapeService.findByNumAndImagePath(param.getNum(),param.getImagePath());
+        return ResultData.ok(res);
+    }
+    /**
+     * 将需要推理的场景推入到队列
+     */
+    @PostMapping("/detectScene")
+    public ResultData detect(@RequestBody @Validated SceneMarkShapeDetectParamVO param) {
+        param.setWebSite(mainUrl);
+        rabbitMqProducer.sendByWorkQueue(yolov5DetectQueue, param);
+        return ResultData.ok();
+    }
+    /**
+     * 将需要训练的场景推入到队列
+     */
+    @PostMapping("/trainScene")
+    public ResultData trainScene(@RequestBody @Validated SceneMarkShapeReDetectParamVO param) {
+        sceneMarkShapeService.trainScene(param);
+        return ResultData.ok();
+    }
+    /**
+     * 将需要重新推理的场景推入到队列
+     */
+    @PostMapping("/editReDetectStatus")
+    public ResultData editReDetectStatus(@RequestBody @Validated SceneMarkShapeParamVO param) {
+        sceneMarkShapeService.editTrainStatus(param);
+        return ResultData.ok();
+    }
+    /**
+     * 保存或者修改
+     */
+    @PostMapping("/saveOrEdit")
+    public ResultData save(@RequestParam(value = "num") String num,@RequestParam("file") MultipartFile file) throws IOException {
+        sceneMarkShapeService.saveFileToDB(file,num);
+        return ResultData.ok();
+    }
+    /**
+     * 保存或者修改JSON
+     */
+    @PostMapping("/saveOrEditJson")
+    public ResultData saveOrEditJson(@RequestBody SceneMarkShape param) {
+        SceneMarkShape shape = sceneMarkShapeService.findByNumAndImagePath(param.getNum(), param.getImagePath());
+        if (ObjectUtil.isNotNull(shape)){
+            param.setId(shape.getId());
+            param.setUpdateTime(new Date());
+            return ResultData.ok(sceneMarkShapeService.updateById(param));
+        }else {
+            param.setCreateTime(new Date());
+            return ResultData.ok(sceneMarkShapeService.save(param));
+        }
+    }
+    /**
+     * 保存或者修改JSON
+     */
+    @PostMapping("/editLabel")
+    public ResultData editLabel(@RequestParam(value = "num") String num,@RequestParam(value = "imgPath") String imgPath,@RequestParam("file") MultipartFile file) throws IOException {
+        log.info("进入editLabel---num{},imgPath{}",num,imgPath);
+        return sceneMarkShapeService.editLabelByFile(num, imgPath, file);
+    }
+    /**
+     * 保存或者修改JSON
+     */
+    @PostMapping("/testquery")
+    public ResultData testquery()   {
+        Map<String, List<SceneMarkShape>> res=new HashMap<>();
+        res.put("findByReTrainStatus",sceneMarkShapeService.findByReTrainStatus(1));
+        res.put("findByToTrainStatus",sceneMarkShapeService.findByToTrainStatus(0));
+        return ResultData.ok(res);
+    }
+}

+ 4 - 4
src/main/java/com/fdkankan/scene/controller/TestController.java

@@ -1,5 +1,6 @@
 package com.fdkankan.scene.controller;
 
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
 import com.fdkankan.rabbitmq.util.RabbitMqProducer;
 import com.fdkankan.web.response.ResultData;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -21,13 +22,12 @@ public class TestController {
 
     @Autowired
     private RabbitMqProducer rabbitMqProducer;
+    @Autowired
+    private FYunFileServiceInterface fYunFileService;
 
     @GetMapping("/test")
     public ResultData test(){
-        for (int i = 0; i < 100; i++){
-            rabbitMqProducer.sendByWorkQueue("test_dsx", "{\"name\":123}");
-        }
-        return ResultData.ok();
+        return ResultData.ok(fYunFileService.fileExist("scene_result_data/KK-t-JCaoqtvy7AO/caches/images"));
     }
 
 }

+ 105 - 0
src/main/java/com/fdkankan/scene/entity/SceneAsynOperLog.java

@@ -0,0 +1,105 @@
+package com.fdkankan.scene.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.util.Date;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author 
+ * @since 2022-12-07
+ */
+@Getter
+@Setter
+@TableName("t_scene_asyn_oper_log")
+public class SceneAsynOperLog implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 场景码
+     */
+    @TableField("num")
+    private String num;
+
+    /**
+     * 操作类型(upload-上传,download-下载)
+     */
+    @TableField("oper_type")
+    private String operType;
+
+    /**
+     * 模块名称
+     */
+    @TableField("module")
+    private String module;
+
+    /**
+     * 功能
+     */
+    @TableField("func")
+    private String func;
+
+    /**
+     * 版本号
+     */
+    @TableField("version")
+    private Integer version;
+
+    /**
+     * 状态(0-处理中,1-处理完成,2-处理失败)
+     */
+    @TableField("state")
+    private Integer state;
+
+    /**
+     * 下载链接
+     */
+    @TableField("url")
+    private String url;
+
+    /**
+     * 是否需要弹窗(0-否,1-是)
+     */
+    @TableField("pop")
+    private Integer pop;
+
+    /**
+     * 扩展信息
+     */
+    @TableField("ext_data")
+    private String extData;
+
+    /**
+     * 创建时间
+     */
+    @TableField("create_time")
+    private Date createTime;
+
+    /**
+     * 修改时间
+     */
+    @TableField("update_time")
+    private Date updateTime;
+
+    /**
+     * 状态(A-有效,I-无效)
+     */
+    @TableField("rec_status")
+    @TableLogic(value = "A", delval = "I")
+    private String recStatus;
+
+
+}

+ 69 - 0
src/main/java/com/fdkankan/scene/entity/SceneCleanOrig.java

@@ -0,0 +1,69 @@
+package com.fdkankan.scene.entity;
+
+import com.baomidou.mybatisplus.annotation.*;
+
+import java.io.Serializable;
+import java.util.Date;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 删除oss原始资源记录
+ * </p>
+ *
+ * @author 
+ * @since 2023-03-29
+ */
+@Getter
+@Setter
+@TableName("t_scene_clean_orig")
+public class SceneCleanOrig implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @TableField("num")
+    private String num;
+
+    /**
+     * type
+     */
+    @TableField("type")
+    private Integer type;
+
+    /**
+     * 0-处理中,1-成功,-1失败
+     */
+    @TableField("state")
+    private Integer state;
+
+    /**
+     * 失败原因
+     */
+    @TableField("reason")
+    private String reason;
+
+    /**
+     * 创建时间
+     */
+    @TableField("create_time")
+    private Date createTime;
+
+    /**
+     * 修改时间
+     */
+    @TableField("update_time")
+    private Date updateTime;
+
+    /**
+     * 记录的状态,A: 生效,I: 禁用
+     */
+    @TableField("rec_status")
+    @TableLogic(value = "A", delval = "I")
+    private String recStatus;
+
+
+}

+ 72 - 0
src/main/java/com/fdkankan/scene/entity/SceneColdStorage.java

@@ -0,0 +1,72 @@
+package com.fdkankan.scene.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.util.Date;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 场景封存状态表
+ * </p>
+ *
+ * @author 
+ * @since 2023-07-25
+ */
+@Getter
+@Setter
+@TableName("t_scene_cold_storage")
+public class SceneColdStorage implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 场景码
+     */
+    @TableField("num")
+    private String num;
+
+    /**
+     * 1-封存,2-未封存
+     */
+    @TableField("state")
+    private Integer state;
+
+    /**
+     * 创建时间
+     */
+    @TableField("create_time")
+    private Date createTime;
+
+    /**
+     * 修改时间
+     */
+    @TableField("update_time")
+    private Date updateTime;
+
+    @TableField("rec_status")
+    @TableLogic(value = "A", delval = "I")
+    private String recStatus;
+
+    /**
+     * 冷存储bucket
+     */
+    @TableField("cold_bucket")
+    private String coldBucket;
+
+    /**
+     * 正常使用bucket
+     */
+    @TableField("bucket")
+    private String bucket;
+
+
+}

+ 75 - 0
src/main/java/com/fdkankan/scene/entity/SceneColdStorageLog.java

@@ -0,0 +1,75 @@
+package com.fdkankan.scene.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.util.Date;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 场景冷归档日志表
+ * </p>
+ *
+ * @author 
+ * @since 2023-07-12
+ */
+@Getter
+@Setter
+@TableName("t_scene_cold_storage_log")
+public class SceneColdStorageLog implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 场景码
+     */
+    @TableField("num")
+    private String num;
+
+    /**
+     * 封存地址
+     */
+    @TableField("path")
+    private String path;
+
+    /**
+     * 操作类型(1-封存,2-解封存)
+     */
+    @TableField("type")
+    private Integer type;
+
+    @TableField("state")
+    private Integer state;
+
+    @TableField("reason")
+    private String reason;
+
+    /**
+     * 创建时间
+     */
+    @TableField("create_time")
+    private Date createTime;
+
+    /**
+     * 修改时间
+     */
+    @TableField("update_time")
+    private Date updateTime;
+
+    /**
+     * A-有效,I-无效
+     */
+    @TableField("rec_status")
+    @TableLogic(value = "A", delval = "I")
+    private String recStatus;
+
+
+}

+ 50 - 0
src/main/java/com/fdkankan/scene/entity/SceneEditControls.java

@@ -88,6 +88,56 @@ public class SceneEditControls implements Serializable {
     @TableField("show_rule")
     private Integer showRule;
 
+
+    /**
+     * 是否展示标尺(0-不需要,1-需要)
+     */
+    @TableField("show_scale")
+    private Integer showScale;
+
+    /**
+     * 是否展示分享场景(0-不需要,1-需要)
+     */
+    @TableField("show_share")
+    private Integer showShare;
+
+    /**
+     * 是否展示分享热点(0-不需要,1-需要)
+     */
+    @TableField("show_tagshare")
+    private Integer showTagshare;
+
+    /**
+     * 是否展示合照开关(0-不需要,1-需要)
+     */
+    @TableField("show_capture")
+    private Integer showCapture;
+
+    /**
+     * 是否显示多媒体标签标题(0-否,1-是)
+     */
+    @TableField("show_tag_title")
+    private Integer showTagTitle;
+
+    /**
+     * 是否显示指示牌标签标题(0-否,1-是)
+     */
+    @TableField("show_billboard_title")
+    private Integer showBillboardTitle;
+
+    /**
+     * 是否显示视频监控标签标题(0-否,1-是)
+     */
+    @TableField("show_camera_title")
+    private Integer showCameraTitle;
+
+    /**
+     * 是否显示场景关联标签标题(0-否,1-是)
+     */
+    @TableField("show_link_title")
+    private Integer showLinkTitle;
+
+
     /**
      * 创建时间
      */

+ 12 - 0
src/main/java/com/fdkankan/scene/entity/SceneEditInfoExt.java

@@ -91,6 +91,18 @@ public class SceneEditInfoExt {
     private String shareLogoImg;
 
     /**
+     * 是否有指示牌(0-否,1-是)
+     */
+    @TableField("billboards")
+    private Integer billboards;
+
+    /**
+     * 分享配置信息
+     */
+    @TableField("sns_info")
+    private String snsInfo;
+
+    /**
      * 创建时间
      */
     @TableField("create_time")

+ 74 - 0
src/main/java/com/fdkankan/scene/entity/SceneMarkShape.java

@@ -0,0 +1,74 @@
+package com.fdkankan.scene.entity;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * <p>
+ * 场景标记多边形识别数据
+ * </p>
+ *
+ * @author Xiewj
+ * @date 2023/3/30
+ */
+@Data
+@TableName(value = "t_scene_mark_shape",autoResultMap = true)
+@Accessors(chain = true)
+public class SceneMarkShape implements Serializable {
+
+      /**
+       * 主键
+       */
+      @TableId(value = "id", type = IdType.AUTO)
+      private Long id;
+
+      @TableField("version")
+      private String version;
+      @TableField(typeHandler = FastjsonTypeHandler.class, value = "flag")
+      private JSONObject flag;
+
+      @TableField(typeHandler = FastjsonTypeHandler.class, value = "shapes")
+      private List<JSONObject> shapes;
+
+      @TableField("image_path")
+      private String imagePath;
+      @TableField("image_height")
+      private Integer imageHeight;
+      @TableField("image_width")
+      private Integer imageWidth;
+      @TableField("num")
+      private String num;
+      /**
+       * 0不需要 1需要
+       */
+      @TableField("re_train")
+      private Integer reTrain;
+      /**
+       * 0需要训练 1已经训练过
+       */
+      @TableField("to_train")
+      private Integer toTrain;
+
+      @TableField("create_time")
+      private Date createTime;
+
+      @TableField("update_time")
+      private Date updateTime;
+
+      /**
+       * 记录的状态,A: 生效,I: 禁用
+       */
+      @TableField("rec_status")
+      @TableLogic(value = "A", delval = "I")
+      private String recStatus;
+
+}

+ 6 - 0
src/main/java/com/fdkankan/scene/entity/ScenePlus.java

@@ -95,6 +95,12 @@ public class ScenePlus implements Serializable {
     private Integer recommend;
 
     /**
+     * 是否有housetype文件(0-否,1-是)
+     */
+    @TableField("house_type")
+    private Integer houseType;
+
+    /**
      * 创建时间
      */
     @TableField("create_time")

+ 6 - 0
src/main/java/com/fdkankan/scene/entity/ScenePlusExt.java

@@ -125,6 +125,12 @@ public class ScenePlusExt implements Serializable {
     private String sceneKind;
 
     /**
+     * 算法模型类型(dam,3dtiles)
+     */
+    @TableField("model_kind")
+    private String modelKind;
+
+    /**
      * 算法计算完成时间
      */
     @TableField("algorithm_time")

+ 3 - 3
src/main/java/com/fdkankan/scene/generate/AutoGenerate.java

@@ -18,7 +18,7 @@ public class AutoGenerate {
         String path =System.getProperty("user.dir");
 
         generate(path,"scene", getTables(new String[]{
-                "t_scene_clean"
+                "t_scene_cold_storage"
         }));
 
 //        generate(path,"goods", getTables(new String[]{
@@ -46,8 +46,8 @@ public class AutoGenerate {
 
 
     public static void  generate(String path,String moduleName,  List<String> tables){
-        FastAutoGenerator.create("jdbc:mysql://rm-wz90w10465iiwwv098o.mysql.rds.aliyuncs.com/4dkankan_v4",
-            "root","D2719bd0cae1a005")
+        FastAutoGenerator.create("jdbc:mysql://120.24.144.164:3306/4dkankan_v4",
+            "root","4Dage@4Dage#@168")
                 .globalConfig(builder -> {
                     builder.author("")               //作者
                             .outputDir(path+"\\src\\main\\java")    //输出路径(写到java目录)

+ 33 - 0
src/main/java/com/fdkankan/scene/httpclient/MyClient.java

@@ -0,0 +1,33 @@
+package com.fdkankan.scene.httpclient;
+
+
+import com.dtflys.forest.annotation.Get;
+import com.dtflys.forest.annotation.Var;
+import com.dtflys.forest.callback.OnProgress;
+import com.dtflys.forest.extensions.DownloadFile;
+import com.fdkankan.web.response.ResultData;
+
+import java.io.File;
+
+public interface MyClient {
+
+    /**
+     * 在方法上加上@DownloadFile注解
+     * dir属性表示文件下载到哪个目录
+     * filename属性表示文件下载成功后以什么名字保存,如果不填,这默认从URL中取得文件名
+     * OnProgress参数为监听上传进度的回调函数
+     */
+    @Get(url = "{url}")
+    @DownloadFile(dir = "{dir}", filename = "{filename}")
+    File downloadFile(@Var("url") String url, @Var("dir") String dir, @Var("filename")String filename);
+
+    /**
+     * 在方法上加上@DownloadFile注解
+     * dir属性表示文件下载到哪个目录
+     * filename属性表示文件下载成功后以什么名字保存,如果不填,这默认从URL中取得文件名
+     * OnProgress参数为监听上传进度的回调函数
+     */
+    @Get(url = "${url}?${params}")
+    ResultData get(@Var("url") String url, @Var("params") String params);
+
+}

+ 26 - 5
src/main/java/com/fdkankan/scene/listener/RabbitMqListener.java

@@ -1,8 +1,10 @@
 package com.fdkankan.scene.listener;
 
 import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
 import com.fdkankan.scene.entity.DownloadTourVideo;
 import com.fdkankan.scene.service.IDownloadTourVideoService;
+import com.fdkankan.scene.service.ISceneService;
 import com.rabbitmq.client.Channel;
 import java.nio.charset.StandardCharsets;
 import lombok.extern.slf4j.Slf4j;
@@ -28,11 +30,13 @@ public class RabbitMqListener {
     @Value("${queue.scene.transfer-tour-video}")
     private String downloadTourVideoQueue;
 
+    @Value("${queue.bodySegment:body-segment}")
+    private String bodySegmentQueueName;
+
     @Autowired
     private IDownloadTourVideoService downloadTourVideoService;
-
-
-
+    @Autowired
+    private ISceneService sceneService;
 
     /**
      * 开启了手动确认模式,如果没有手动确认,消费者不会重试,当服务重启时会再次消费,因为rabbitmq认为你还没有处理完你的业务
@@ -59,6 +63,25 @@ public class RabbitMqListener {
      * concurrency = "3"    设置消费线程数,每个线程每次只拉取一条消息消费
      */
     @RabbitListener(
+            queuesToDeclare = @Queue("${queue.bodySegment}"),
+            concurrency = "${maxThread.bodySegment}"
+    )
+    public void bodySegment(Channel channel, Message message) throws Exception {
+        String messageId = message.getMessageProperties().getMessageId();
+        String msg = new String(message.getBody(), StandardCharsets.UTF_8);
+        log.info("开始消费消息,id:{},queue:{},content:{}", messageId, bodySegmentQueueName, msg);
+        JSONObject jsonObject = JSON.parseObject(msg);
+        sceneService.bodySegmentHandler(jsonObject.getString("imgUrl"), jsonObject.getString("uuid"));
+        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
+        log.info("结束消费消息,id:{}", messageId);
+    }
+
+    /**
+     * 开启了手动确认模式,如果没有手动确认,消费者不会重试,当服务重启时会再次消费,因为rabbitmq认为你还没有处理完你的业务
+     * queuesToDeclare = @Queue("${queue.modeling.modeling-test}"),  如果队列不不存在会自动创建队列
+     * concurrency = "3"    设置消费线程数,每个线程每次只拉取一条消息消费
+     */
+    @RabbitListener(
         queuesToDeclare = @Queue("test_dsx")
     )
     public void test(Channel channel, Message message) throws Exception {
@@ -72,6 +95,4 @@ public class RabbitMqListener {
     }
 
 
-
-
 }

+ 18 - 0
src/main/java/com/fdkankan/scene/mapper/ISceneAsynOperLogMapper.java

@@ -0,0 +1,18 @@
+package com.fdkankan.scene.mapper;
+
+import com.fdkankan.scene.entity.SceneAsynOperLog;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ *  Mapper 接口
+ * </p>
+ *
+ * @author 
+ * @since 2022-12-07
+ */
+@Mapper
+public interface ISceneAsynOperLogMapper extends BaseMapper<SceneAsynOperLog> {
+
+}

+ 18 - 0
src/main/java/com/fdkankan/scene/mapper/ISceneCleanOrigMapper.java

@@ -0,0 +1,18 @@
+package com.fdkankan.scene.mapper;
+
+import com.fdkankan.scene.entity.SceneCleanOrig;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 删除oss原始资源记录 Mapper 接口
+ * </p>
+ *
+ * @author 
+ * @since 2023-03-29
+ */
+@Mapper
+public interface ISceneCleanOrigMapper extends BaseMapper<SceneCleanOrig> {
+
+}

+ 18 - 0
src/main/java/com/fdkankan/scene/mapper/ISceneColdStorageLogMapper.java

@@ -0,0 +1,18 @@
+package com.fdkankan.scene.mapper;
+
+import com.fdkankan.scene.entity.SceneColdStorageLog;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 场景冷归档日志表 Mapper 接口
+ * </p>
+ *
+ * @author 
+ * @since 2023-07-12
+ */
+@Mapper
+public interface ISceneColdStorageLogMapper extends BaseMapper<SceneColdStorageLog> {
+
+}

+ 18 - 0
src/main/java/com/fdkankan/scene/mapper/ISceneColdStorageMapper.java

@@ -0,0 +1,18 @@
+package com.fdkankan.scene.mapper;
+
+import com.fdkankan.scene.entity.SceneColdStorage;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 场景封存状态表 Mapper 接口
+ * </p>
+ *
+ * @author 
+ * @since 2023-07-25
+ */
+@Mapper
+public interface ISceneColdStorageMapper extends BaseMapper<SceneColdStorage> {
+
+}

+ 13 - 0
src/main/java/com/fdkankan/scene/mapper/IScenePlusMapper.java

@@ -1,9 +1,14 @@
 package com.fdkankan.scene.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fdkankan.scene.bean.SceneBean;
 import com.fdkankan.scene.entity.ScenePlus;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
 /**
  * <p>
  * 场景主表 Mapper 接口
@@ -15,4 +20,12 @@ import org.apache.ibatis.annotations.Mapper;
 @Mapper
 public interface IScenePlusMapper extends BaseMapper<ScenePlus> {
 
+    List<SceneBean> selectCleanOrigScene(Date time);
+
+    List<SceneBean> selectCleanOrigSceneDeleted(Date time);
+
+    List<SceneBean> listCleanOss4TestCamera(Set<Long> cameraIds, Date time);
+
+    List<SceneBean> selectColdStorageScene(Date time);
+
 }

+ 15 - 0
src/main/java/com/fdkankan/scene/mapper/ISceneProMapper.java

@@ -1,9 +1,14 @@
 package com.fdkankan.scene.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fdkankan.scene.bean.SceneBean;
 import com.fdkankan.scene.entity.ScenePro;
 import org.apache.ibatis.annotations.Mapper;
 
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
+
 /**
  * <p>
  * pro场景表 Mapper 接口
@@ -15,4 +20,14 @@ import org.apache.ibatis.annotations.Mapper;
 @Mapper
 public interface ISceneProMapper extends BaseMapper<ScenePro> {
 
+    List<SceneBean> selectCleanOrigScene(Date time);
+
+    List<SceneBean> listCleanOss4DeletedScene(Date time);
+
+    List<SceneBean> listCleanOss4TestCamera(Set<Long> cameraIds, Date time);
+
+    List<SceneBean> selectColdStorageScene(Date time);
+
+
+
 }

+ 16 - 0
src/main/java/com/fdkankan/scene/mapper/MarkShapeMapper.java

@@ -0,0 +1,16 @@
+package com.fdkankan.scene.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fdkankan.scene.entity.SceneMarkShape;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Xiewj
+ * @date 2021/11/22
+ */
+@Mapper
+@Component("MarkShapeMapper")
+public interface MarkShapeMapper extends BaseMapper<SceneMarkShape> {
+}
+

+ 190 - 0
src/main/java/com/fdkankan/scene/schedule/ScheduleJob.java

@@ -0,0 +1,190 @@
+package com.fdkankan.scene.schedule;
+
+import com.fdkankan.redis.constant.RedisLockKey;
+import com.fdkankan.redis.util.RedisLockUtil;
+import com.fdkankan.scene.service.ISceneAsynOperLogService;
+import com.fdkankan.scene.service.ISceneCleanOrigService;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+
+@RefreshScope
+@Log4j2
+@Component
+public class ScheduleJob {
+
+    @Value("${environment:#{null}}")
+    private String environment;
+
+    @Autowired
+    private ISceneAsynOperLogService sceneAsynOperLogService;
+    @Autowired
+    private ISceneCleanOrigService sceneCleanOrigService;
+    @Autowired
+    private RedisLockUtil redisLockUtil;
+
+    /**
+     * 每天凌晨一点执行
+     */
+    @Scheduled(cron="0 0 1 * * ?")
+    public void cleanDownloadPanorama() {
+        log.info("定时清除全景图压缩包开始");
+        sceneAsynOperLogService.cleanDownloadPanorama();
+        log.info("定时清除全景图压缩包完毕");
+    }
+
+//    /**
+//     * 删除场景原始资源
+//     * 每天凌晨执行
+//     */
+//    @Scheduled(cron="0 0 1 * * ?")
+//    public void cleanOssHomeV3() {
+//        log.info("删除v3场景原始资源开始");
+//        String lockKey = RedisLockKey.LOCK_CLEAN_SCENE_ORIG_V3;
+//        try {
+//            boolean lock = redisLockUtil.lock(lockKey, 24*60*60);
+//            if(!lock){
+//                return;
+//            }
+//            sceneCleanOrigService.cleanOrigV3();
+//        }finally {
+//            redisLockUtil.unlockLua(lockKey);
+//        }
+//        log.info("删除v3场景原始资源结束");
+//    }
+//
+//    /**
+//     * 删除场景原始资源
+//     * 每天凌晨执行
+//     */
+//    @Scheduled(cron="0 0 1 * * ?")
+//    public void cleanOssHomeV4() {
+//        log.info("删除v4场景原始资源开始");
+//        String lockKey = RedisLockKey.LOCK_CLEAN_SCENE_ORIG_V4;
+//        try {
+//            boolean lock = redisLockUtil.lock(lockKey, 24*60*60);
+//            if(!lock){
+//                return;
+//            }
+//            sceneCleanOrigService.cleanOrigV4();
+//        }finally {
+//            redisLockUtil.unlockLua(lockKey);
+//        }
+//        log.info("删除v4场景原始资源结束");
+//    }
+
+    /**
+     * 删除已删除场景原始资源及caches
+     * 每天凌晨执行
+     */
+    @Scheduled(cron="0 0 1 * * ?")
+    public void cleanOss4DeletedSceneV3() {
+        log.info("删除已删除V3场景原始资源开始");
+        String lockKey = RedisLockKey.LOCK_CLEAN_SCENE_DELETED_ORIG_V3;
+        try {
+            boolean lock = redisLockUtil.lock(lockKey, 24*60*60);
+            if(!lock){
+                return;
+            }
+            sceneCleanOrigService.cleanOss4DeletedSceneV3();
+        }finally {
+            redisLockUtil.unlockLua(lockKey);
+        }
+        log.info("删除已删除V3场景原始资源结束");
+    }
+
+
+    /**
+     * 删除已删除场景原始资源及caches
+     * 每天凌晨执行
+     */
+    @Scheduled(cron="0 0 1 * * ?")
+    public void cleanOss4DeletedSceneV4() {
+        log.info("删除已删除V4场景原始资源开始");
+        String lockKey = RedisLockKey.LOCK_CLEAN_SCENE_DELETED_ORIG_V4;
+        try {
+            boolean lock = redisLockUtil.lock(lockKey, 24*60*60);
+            if(!lock){
+                return;
+            }
+            sceneCleanOrigService.cleanOss4DeletedSceneV4();
+        }finally {
+            redisLockUtil.unlockLua(lockKey);
+        }
+        log.info("删除已删除V4场景原始资源结束");
+    }
+
+//    /**
+//     * 删除测试相机场景原始资源及caches
+//     * 每天凌晨执行
+//     */
+//    @Scheduled(cron="0 0 1 * * ?")
+//    public void cleanOss4TestCameraV3() {
+//        if(StrUtil.isEmpty(environment) || !environment.equals("dev")){
+//            return;
+//        }
+//        log.info("删除已删除V4场景原始资源开始");
+//        sceneCleanOrigService.cleanOss4TestCameraV3();
+//        log.info("删除已删除V4场景原始资源结束");
+//    }
+//
+//
+//    /**
+//     * 删除测试相机场景原始资源及caches
+//     * 每天凌晨执行
+//     */
+//    @Scheduled(cron="0 0 1 * * ?")
+//    public void cleanOss4TestCameraV4() {
+//        if(StrUtil.isEmpty(environment) || !environment.equals("dev")){
+//            return;
+//        }
+//        log.info("删除已删除V4场景原始资源开始");
+//        sceneCleanOrigService.cleanOss4TestCameraV4();
+//        log.info("删除已删除V4场景原始资源结束");
+//    }
+
+    /**
+     * 删除场景原始资源
+     * 每天凌晨执行
+     */
+    @Scheduled(cron="0 0 1 * * ?")
+    public void coldStorageHomeV3() {
+        log.info("冻结v3场景原始资源开始");
+        String lockKey = RedisLockKey.LOCK_CLEAN_SCENE_ORIG_V3;
+        try {
+            boolean lock = redisLockUtil.lock(lockKey, 24*60*60);
+            if(!lock){
+                return;
+            }
+            sceneCleanOrigService.coldStorageHomeV3();
+        }finally {
+            redisLockUtil.unlockLua(lockKey);
+        }
+        log.info("冻结v3场景原始资源结束");
+    }
+
+    /**
+     * 删除场景原始资源
+     * 每天凌晨执行
+     */
+    @Scheduled(cron="0 0 1 * * ?")
+    public void coldStorageHomeV4() {
+        log.info("冻结v4场景原始资源开始");
+        String lockKey = RedisLockKey.LOCK_CLEAN_SCENE_ORIG_V4;
+        try {
+            boolean lock = redisLockUtil.lock(lockKey, 24*60*60);
+            if(!lock){
+                return;
+            }
+            sceneCleanOrigService.coldStorageHomeV4();
+        }finally {
+            redisLockUtil.unlockLua(lockKey);
+        }
+        log.info("冻结v4场景原始资源结束");
+    }
+}

+ 5 - 0
src/main/java/com/fdkankan/scene/service/ICameraService.java

@@ -3,6 +3,8 @@ package com.fdkankan.scene.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.fdkankan.scene.entity.Camera;
 
+import java.util.List;
+
 /**
  * <p>
  * 相机主表 服务类
@@ -15,4 +17,7 @@ public interface ICameraService extends IService<Camera> {
 
     Camera findByChildName(String childName);
 
+    List<Camera> listBySnCodes(List<String> snCodes);
+
+
 }

+ 24 - 0
src/main/java/com/fdkankan/scene/service/ISceneAsynOperLogService.java

@@ -0,0 +1,24 @@
+package com.fdkankan.scene.service;
+
+import com.fdkankan.scene.entity.SceneAsynOperLog;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.scene.vo.SceneAsynOperLogParamVO;
+import com.fdkankan.web.response.ResultData;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestBody;
+
+/**
+ * <p>
+ *  服务类
+ * </p>
+ *
+ * @author 
+ * @since 2022-12-07
+ */
+public interface ISceneAsynOperLogService extends IService<SceneAsynOperLog> {
+
+    ResultData getAsynOperLog(SceneAsynOperLogParamVO param);
+
+    void cleanDownloadPanorama();
+
+}

+ 32 - 0
src/main/java/com/fdkankan/scene/service/ISceneCleanOrigService.java

@@ -0,0 +1,32 @@
+package com.fdkankan.scene.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.scene.entity.SceneCleanOrig;
+
+/**
+ * <p>
+ * 删除oss原始资源记录 服务类
+ * </p>
+ *
+ * @author 
+ * @since 2023-03-29
+ */
+public interface ISceneCleanOrigService extends IService<SceneCleanOrig> {
+
+    void cleanOrigV3();
+
+    void cleanOrigV4();
+
+    void cleanOss4DeletedSceneV3();
+
+    void cleanOss4DeletedSceneV4();
+
+    void cleanOss4TestCameraV3();
+
+    void cleanOss4TestCameraV4();
+
+    void coldStorageHomeV3();
+
+    void coldStorageHomeV4();
+
+}

+ 16 - 0
src/main/java/com/fdkankan/scene/service/ISceneColdStorageLogService.java

@@ -0,0 +1,16 @@
+package com.fdkankan.scene.service;
+
+import com.fdkankan.scene.entity.SceneColdStorageLog;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 场景冷归档日志表 服务类
+ * </p>
+ *
+ * @author 
+ * @since 2023-07-12
+ */
+public interface ISceneColdStorageLogService extends IService<SceneColdStorageLog> {
+    void saveLog(String num, String path, Integer type, Integer state, String reason);
+}

+ 18 - 0
src/main/java/com/fdkankan/scene/service/ISceneColdStorageService.java

@@ -0,0 +1,18 @@
+package com.fdkankan.scene.service;
+
+import com.fdkankan.scene.entity.SceneColdStorage;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 场景封存状态表 服务类
+ * </p>
+ *
+ * @author 
+ * @since 2023-07-25
+ */
+public interface ISceneColdStorageService extends IService<SceneColdStorage> {
+
+    void save(String num, Integer state, String coldBucket, String standarBucket);
+
+}

+ 13 - 0
src/main/java/com/fdkankan/scene/service/ISceneEditInfoExtService.java

@@ -1,7 +1,12 @@
 package com.fdkankan.scene.service;
 
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.fdkankan.scene.entity.SceneEditInfoExt;
+import com.fdkankan.scene.vo.*;
+import com.fdkankan.web.response.ResultData;
+
+import java.util.List;
 
 /**
  * <p>
@@ -19,4 +24,12 @@ public interface ISceneEditInfoExtService extends IService<SceneEditInfoExt> {
 
     void updateToursByNum(String num, Integer tours);
 
+    ResultData saveBillboards(BaseJsonArrayParamVO param) throws Exception;
+
+    ResultData deleteBillboards(DeleteSidListParamVO param) throws Exception;
+
+    JSONObject listBillboards(BaseSceneParamVO param) throws Exception;
+
+    ResultData deleteBillboardsStyles(DeleteStylesParamVO param) throws Exception;
+
 }

+ 5 - 8
src/main/java/com/fdkankan/scene/service/ISceneEditInfoService.java

@@ -2,16 +2,15 @@ package com.fdkankan.scene.service;
 
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.fdkankan.scene.annotation.CheckPermit;
 import com.fdkankan.scene.vo.BaseSceneParamVO;
-import com.fdkankan.scene.vo.SurveillanceParamVO;
+import com.fdkankan.scene.vo.SaveFiltersParamVO;
 import com.fdkankan.web.response.ResultData;
 import com.fdkankan.scene.entity.SceneEditInfo;
 import com.fdkankan.scene.vo.BallScreenVideoParamVO;
 import com.fdkankan.scene.vo.BaseDataParamVO;
 import com.fdkankan.scene.vo.BaseFileParamVO;
 import com.fdkankan.scene.vo.DeleteLinkPanParamVO;
-import com.fdkankan.scene.vo.DeleteLinkSceneStylesParamVO;
+import com.fdkankan.scene.vo.DeleteStylesParamVO;
 import com.fdkankan.scene.vo.DeleteMosaicParamVO;
 import com.fdkankan.scene.vo.DeleteSidParamVO;
 import com.fdkankan.scene.vo.DownloadVO;
@@ -26,9 +25,7 @@ import com.fdkankan.scene.vo.SceneInfoParamVO;
 import com.fdkankan.scene.vo.SceneInfoVO;
 import java.io.IOException;
 import java.util.List;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
+
 import org.springframework.web.multipart.MultipartFile;
 
 /**
@@ -99,7 +96,7 @@ public interface ISceneEditInfoService extends IService<SceneEditInfo> {
 
     ResultData deleteLinkPan(DeleteLinkPanParamVO param) throws Exception;
 
-    ResultData deleteStyles(DeleteLinkSceneStylesParamVO param) throws Exception;
+    ResultData deleteStyles(DeleteStylesParamVO param) throws Exception;
 
     ResultData deleteMosaics(DeleteMosaicParamVO param) throws Exception;
 
@@ -109,7 +106,7 @@ public interface ISceneEditInfoService extends IService<SceneEditInfo> {
 
     ResultData deleteWaterMark(BaseFileParamVO param) throws Exception;
 
-    ResultData saveFilter(BaseDataParamVO param) throws Exception;
+    ResultData saveFilter(SaveFiltersParamVO param) throws Exception;
 
     ResultData listFilter(BaseSceneParamVO param) throws Exception;
 

+ 2 - 0
src/main/java/com/fdkankan/scene/service/ISceneEditService.java

@@ -26,4 +26,6 @@ public interface ISceneEditService {
 
     ResultData deleteTour(BaseSceneParamVO param) throws Exception;
 
+    ResultData getServiceUpTip();
+
 }

+ 30 - 0
src/main/java/com/fdkankan/scene/service/ISceneMarkShapeService.java

@@ -0,0 +1,30 @@
+package com.fdkankan.scene.service;
+
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.scene.entity.SceneMarkShape;
+import com.fdkankan.scene.vo.SceneMarkShapeParamVO;
+import com.fdkankan.scene.vo.SceneMarkShapeReDetectParamVO;
+import com.fdkankan.web.response.ResultData;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Created by Xiewj on 2021/11/23 0026 10:14
+ */
+public interface ISceneMarkShapeService extends IService<SceneMarkShape> {
+    void saveFileToDB(MultipartFile inPath, String num) throws IOException;
+
+    SceneMarkShape findByNumAndImagePath(String num, String imagePath);
+
+    ResultData editLabelByFile(String num, String imgPath, MultipartFile file) throws IOException;
+
+    void trainScene(SceneMarkShapeReDetectParamVO param);
+
+    List<SceneMarkShape> findByReTrainStatus(Integer reTrain);
+    List<SceneMarkShape> findByToTrainStatus(Integer toTrain);
+
+    void editTrainStatus(SceneMarkShapeParamVO param);
+}

+ 11 - 0
src/main/java/com/fdkankan/scene/service/IScenePlusService.java

@@ -1,9 +1,12 @@
 package com.fdkankan.scene.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.scene.bean.SceneBean;
 import com.fdkankan.web.response.ResultData;
 import com.fdkankan.scene.vo.BaseSceneParamVO;
 import java.util.List;
+import java.util.Set;
+
 import com.fdkankan.scene.entity.ScenePlus;
 import com.fdkankan.scene.vo.SceneCheckKeyParamVO;
 import org.springframework.web.multipart.MultipartFile;
@@ -34,4 +37,12 @@ public interface IScenePlusService extends IService<ScenePlus> {
 
     ResultData uploadShareLogo(String num, MultipartFile file) throws Exception;
 
+    List<SceneBean> listCleanOrigScene(int cleanOrigMonth);
+
+    List<SceneBean> listCleanOss4DeletedScene(int cleanOrigMonth);
+
+    List<SceneBean> listCleanOss4TestCamera(Set<Long> cameraIds, int cleanOrigMonth);
+
+    List<SceneBean> listColdStorageScene(int month);
+
 }

+ 11 - 0
src/main/java/com/fdkankan/scene/service/ISceneProService.java

@@ -1,6 +1,7 @@
 package com.fdkankan.scene.service;
 
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.scene.bean.SceneBean;
 import com.fdkankan.web.response.ResultData;
 import com.fdkankan.scene.entity.ScenePro;
 import com.fdkankan.scene.vo.BaseDataParamVO;
@@ -14,6 +15,8 @@ import com.fdkankan.scene.vo.SceneEditParamVO;
 import com.fdkankan.scene.vo.SceneParamVO;
 import com.fdkankan.scene.vo.SceneVO;
 import java.util.List;
+import java.util.Set;
+
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.multipart.MultipartFile;
 
@@ -49,4 +52,12 @@ public interface ISceneProService extends IService<ScenePro> {
 
     ScenePro getByNum(String num);
 
+    List<SceneBean> listCleanOrigScene(int cleanOrigMonth);
+
+    List<SceneBean> listCleanOss4DeletedScene(int month);
+
+    List<SceneBean> listCleanOss4TestCamera(Set<Long> cameraIds, int month);
+
+    List<SceneBean> listColdStorageScene(int month);
+
 }

+ 16 - 0
src/main/java/com/fdkankan/scene/service/ISceneService.java

@@ -0,0 +1,16 @@
+package com.fdkankan.scene.service;
+
+import com.fdkankan.scene.bean.BodySegmentStatusBean;
+import com.fdkankan.web.response.ResultData;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
+
+public interface ISceneService {
+
+    ResultData uploadBodySegment(MultipartFile file,Integer rotate) throws Exception;
+
+    void bodySegmentHandler(String imgUrl, String uuid);
+
+    ResultData getBodySegmentStatus(String uuid);
+
+}

+ 11 - 0
src/main/java/com/fdkankan/scene/service/impl/CameraServiceImpl.java

@@ -1,5 +1,6 @@
 package com.fdkankan.scene.service.impl;
 
+import cn.hutool.core.collection.CollUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fdkankan.scene.entity.Camera;
@@ -7,6 +8,8 @@ import com.fdkankan.scene.mapper.ICameraMapper;
 import com.fdkankan.scene.service.ICameraService;
 import org.springframework.stereotype.Service;
 
+import java.util.List;
+
 /**
  * <p>
  * 相机主表 服务实现类
@@ -22,4 +25,12 @@ public class CameraServiceImpl extends ServiceImpl<ICameraMapper, Camera> implem
     public Camera findByChildName(String childName) {
         return this.getOne(new LambdaQueryWrapper<Camera>().eq(Camera::getChildName, childName));
     }
+
+    @Override
+    public List<Camera> listBySnCodes(List<String> snCodes) {
+        if(CollUtil.isEmpty(snCodes)){
+            return null;
+        }
+        return this.list(new LambdaQueryWrapper<Camera>().in(Camera::getSnCode, snCodes));
+    }
 }

+ 118 - 0
src/main/java/com/fdkankan/scene/service/impl/SceneAsynOperLogServiceImpl.java

@@ -0,0 +1,118 @@
+package com.fdkankan.scene.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.fdkankan.common.constant.CommonOperStatus;
+import com.fdkankan.common.constant.CommonStatus;
+import com.fdkankan.common.constant.SceneAsynFuncType;
+import com.fdkankan.common.constant.SceneAsynModuleType;
+import com.fdkankan.common.constant.SceneAsynOperType;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
+import com.fdkankan.scene.entity.SceneAsynOperLog;
+import com.fdkankan.scene.mapper.ISceneAsynOperLogMapper;
+import com.fdkankan.scene.service.ISceneAsynOperLogService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.scene.vo.SceneAsynOperLogParamVO;
+import com.fdkankan.web.response.ResultData;
+import java.io.IOException;
+import java.util.Calendar;
+import java.util.List;
+import java.util.stream.Collectors;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ *  服务实现类
+ * </p>
+ *
+ * @author 
+ * @since 2022-12-07
+ */
+@Slf4j
+@Service
+public class SceneAsynOperLogServiceImpl extends ServiceImpl<ISceneAsynOperLogMapper, SceneAsynOperLog> implements ISceneAsynOperLogService {
+
+    @Autowired
+    private FYunFileServiceInterface fYunFileService;
+
+
+    @Override
+    public ResultData getAsynOperLog(SceneAsynOperLogParamVO param) {
+
+        LambdaQueryWrapper<SceneAsynOperLog> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(SceneAsynOperLog::getNum, param.getNum());
+        if(StrUtil.isNotEmpty(param.getOperType())){
+            queryWrapper.eq(SceneAsynOperLog::getOperType, param.getOperType());
+        }
+        if(StrUtil.isNotEmpty(param.getModule())){
+            queryWrapper.eq(SceneAsynOperLog::getModule, param.getModule());
+        }
+        if(StrUtil.isNotEmpty(param.getFunc())){
+            queryWrapper.eq(SceneAsynOperLog::getFunc, param.getFunc());
+        }
+
+        //需要弹窗的异步操作列表
+        List<SceneAsynOperLog> list = this.list(queryWrapper);
+
+        //如果列表中有需要弹窗并且处理完毕的,需要把这些数据改为不需要弹窗了,因为前端请求到之后就会弹出提示,下次不需要弹窗了
+        if(CollUtil.isNotEmpty(list)){
+            List<Long> idList = list.stream().filter(log -> {
+                if(!log.getState().equals(CommonOperStatus.WAITING.code())){
+                    return true;
+                }
+                return false;
+            }).map(log->log.getId()).collect(Collectors.toList());
+            if(CollUtil.isNotEmpty(idList)){
+                this.update(new LambdaUpdateWrapper<SceneAsynOperLog>()
+                    .set(SceneAsynOperLog::getPop, CommonStatus.NO.code())
+                    .in(SceneAsynOperLog::getId, idList));
+            }
+        }
+
+        return ResultData.ok(list);
+    }
+
+    @Override
+    public void cleanDownloadPanorama() {
+
+        List<SceneAsynOperLog> downloadList = this.list(
+            new LambdaQueryWrapper<SceneAsynOperLog>()
+                .eq(SceneAsynOperLog::getOperType, SceneAsynOperType.DOWNLOAD.code())
+                .eq(SceneAsynOperLog::getModule, SceneAsynModuleType.UPLOAD_DOWNLOAD.code())
+                .eq(SceneAsynOperLog::getFunc, SceneAsynFuncType.PANORAMIC_IMAGE.code()));
+        if(CollUtil.isEmpty(downloadList)){
+            return;
+        }
+        DateTime preMonth = DateUtil.offsetMonth(Calendar.getInstance().getTime(), -1);
+        List<SceneAsynOperLog> deleteList = downloadList.parallelStream().filter(log -> {
+            if (log.getCreateTime().before(preMonth)) {
+                return Boolean.TRUE;
+            }
+            return false;
+        }).collect(Collectors.toList());
+        if(CollUtil.isEmpty(deleteList)){
+            return;
+        }
+
+        //删除数据库记录
+        List<Long> deleteIdList = deleteList.parallelStream().map(item -> item.getId()).collect(Collectors.toList());
+        this.removeByIds(deleteIdList);
+
+        deleteList.parallelStream().forEach(item -> {
+            if(StrUtil.isNotEmpty(item.getUrl())){
+                try {
+                    fYunFileService.deleteFile(item.getUrl());
+                } catch (IOException e) {
+                    log.warn("删除oss全景图下载压缩包失败,key:{}", item.getUrl());
+                }
+            }
+        });
+
+    }
+}

+ 298 - 0
src/main/java/com/fdkankan/scene/service/impl/SceneCleanOrigServiceImpl.java

@@ -0,0 +1,298 @@
+package com.fdkankan.scene.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.exceptions.ExceptionUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.fdkankan.common.constant.CommonStatus;
+import com.fdkankan.common.constant.CommonSuccessStatus;
+import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.common.constant.OperationType;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
+import com.fdkankan.model.constants.ConstantFilePath;
+import com.fdkankan.model.constants.UploadFilePath;
+import com.fdkankan.model.utils.SceneUtil;
+import com.fdkankan.redis.constant.RedisKey;
+import com.fdkankan.redis.util.RedisUtil;
+import com.fdkankan.scene.bean.SceneBean;
+import com.fdkankan.scene.entity.Camera;
+import com.fdkankan.scene.entity.SceneCleanOrig;
+import com.fdkankan.scene.mapper.ISceneCleanOrigMapper;
+import com.fdkankan.scene.mapper.IScenePlusExtMapper;
+import com.fdkankan.scene.service.*;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.stereotype.Service;
+import sun.font.TextRecord;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 删除oss原始资源记录 服务实现类
+ * </p>
+ *
+ * @author 
+ * @since 2023-03-29
+ */
+@RefreshScope
+@Slf4j
+@Service
+public class SceneCleanOrigServiceImpl extends ServiceImpl<ISceneCleanOrigMapper, SceneCleanOrig> implements ISceneCleanOrigService {
+
+    @Value("${scene.cleanOrig.month}")
+    private Integer cleanOrigMonth;
+    @Value("${scene.coldStorage.month}")
+    private Integer coldStorageMonth;
+    @Value("${scene.cleanDeleted.month}")
+    private Integer cleanDeletedMonth;
+    @Value("#{'${scene.cleanTestCamera.snCode:}'.split(',')}")
+    private List<String> testSnCodeList;
+    @Value("${scene.cleanTestCamera.month}")
+    private Integer cleanTestCameraMonth;
+    @Value("${fyun.bucket}")
+    private String bucket;
+    @Value("${fyun.coldBucket}")
+    private String coldBucket;
+    @Autowired
+    private ICameraService cameraService;
+    @Autowired
+    private ISceneColdStorageService sceneColdStorageService;
+
+
+    @Autowired
+    private ISceneProService sceneProService;
+    @Autowired
+    private IScenePlusService scenePlusService;
+    @Autowired
+    private IScenePlusExtService scenePlusExtService;
+    @Autowired
+    private FYunFileServiceInterface fYunFileService;
+    @Autowired
+    private RedisUtil redisUtil;
+    @Autowired
+    private ISceneColdStorageLogService sceneColdStorageLogService;
+
+    @Override
+    public void cleanOrigV4() {
+        //查询所有计算时间超过限定时间的场景,计算成功、未被删除、最后一次计算后未被删除过的
+        List<SceneBean> sceneBeans = scenePlusService.listCleanOrigScene(cleanOrigMonth);
+        this.cleanOrig(sceneBeans);
+    }
+
+    @Override
+    public void cleanOrigV3() {
+        //查询所有计算时间超过限定时间的场景,计算成功、未被删除
+        List<SceneBean> sceneBeans = sceneProService.listCleanOrigScene(cleanOrigMonth);
+        this.cleanOrig(sceneBeans);
+
+    }
+
+    private void cleanOrig(List<SceneBean> sceneBeans){
+        if(CollUtil.isEmpty(sceneBeans)){
+            return;
+        }
+        sceneBeans.parallelStream().forEach(scene->{
+            boolean lock = this.lock(scene.getDataSource());
+            try {
+                if(lock) {
+                    this.cleanOrigHandler(scene);
+                    this.saveLog(scene.getNum(), 1, CommonSuccessStatus.SUCCESS.code(), null);
+                }
+            }catch (Exception e){
+                log.error("删除原始资源失败,num : " + scene.getNum(), e);
+                this.saveLog(scene.getNum(), 1, CommonSuccessStatus.FAIL.code(), ExceptionUtil.stacktraceToString(e, 3000));
+            }finally {
+                this.releaseLock(scene.getDataSource());
+            }
+        });
+    }
+
+    private void cleanOrigHandler(SceneBean scene){
+        String dataSource = scene.getDataSource();
+        if(StrUtil.isNotEmpty(dataSource)){
+            String homePath = dataSource.replace(ConstantFilePath.BUILD_MODEL_PATH, ConstantFilePath.OSS_PREFIX);
+            //由于国内测试和生产用的bucket是同一个,这里需要做一个安全校验,保证不会删错
+            String fileContent = fYunFileService.getFileContent(homePath.concat("/").concat("data.fdage"));
+            if(StrUtil.isNotBlank(fileContent)){
+                JSONObject jsonObject = JSON.parseObject(fileContent);
+                String snCode = jsonObject.getJSONObject("cam").getString("uuid");
+                String uuidTime = jsonObject.getString("uuidtime");
+                if(StrUtil.isEmpty(snCode)
+                        || StrUtil.isEmpty(uuidTime)
+                        || !homePath.contains(snCode)
+                        || !homePath.contains(uuidTime)){
+                    throw new RuntimeException("dataSource与data.fdage文件不匹配");
+                }else{
+                    fYunFileService.deleteFolder(homePath);
+                }
+            }
+        }
+    }
+
+
+
+
+    private void saveLog(String num, int type, int status, String reason){
+        //清除旧的日志
+        this.remove(new LambdaQueryWrapper<SceneCleanOrig>().eq(SceneCleanOrig::getNum, num));
+        SceneCleanOrig sceneCleanOrig = new SceneCleanOrig();
+        sceneCleanOrig.setNum(num);
+        sceneCleanOrig.setType(type);
+        sceneCleanOrig.setState(status);
+        sceneCleanOrig.setReason(reason);
+        this.saveOrUpdate(sceneCleanOrig);
+    }
+
+    private boolean lock(String dataSource){
+        Map<String, String> property = SceneUtil.getPropertyFromDataSource(dataSource);
+        String homePath = property.get("homePath");
+        String uuid = property.get("uuid");
+
+        String uploadLock = redisUtil.get(String.format(RedisKey.SCENE_OSS_HOME_DIR_UPLOAD, uuid));
+        //场景正在上传,不删除
+        if(StrUtil.isNotEmpty(uploadLock)){
+            return false;
+        }
+        redisUtil.set(String.format(RedisKey.SCENE_OSS_HOME_DIR_DELETE, uuid), homePath, 8*60*60);
+        return true;
+    }
+
+    private void releaseLock(String dataSource){
+        Map<String, String> property = SceneUtil.getPropertyFromDataSource(dataSource);
+        String uuid = property.get("uuid");
+        redisUtil.del(String.format(RedisKey.SCENE_OSS_HOME_DIR_DELETE, uuid));
+    }
+
+
+    @Override
+    public void cleanOss4DeletedSceneV3() {
+        List<SceneBean> sceneBeans = sceneProService.listCleanOss4DeletedScene(cleanDeletedMonth);
+        this.cleanOrig4Delete(sceneBeans, false, 2);
+    }
+
+    @Override
+    public void cleanOss4DeletedSceneV4() {
+        //查询所有计算时间超过限定时间的场景,计算成功、未被删除、最后一次计算后未被删除过的
+        List<SceneBean> sceneBeans = scenePlusService.listCleanOss4DeletedScene(cleanDeletedMonth);
+        this.cleanOrig4Delete(sceneBeans, true, 2);
+    }
+
+    /**
+     * 删除已删除场景的原始资源及caches目录(v3场景不需要删除caches目录)
+     * @param sceneBeans
+     * @param deleteCaches 是否需要删除caches目录
+     */
+    private void cleanOrig4Delete(List<SceneBean> sceneBeans, boolean deleteCaches, Integer type){
+        if(CollUtil.isEmpty(sceneBeans)){
+            return;
+        }
+        sceneBeans.parallelStream().forEach(scene->{
+            try {
+                //删除caches文件
+                if(deleteCaches){
+                    this.deleteResultCaches(scene.getNum());
+                }
+                //删除原始资源
+                this.cleanOrigHandler(scene);
+
+                this.saveLog(scene.getNum(), type, CommonSuccessStatus.SUCCESS.code(), null);
+            }catch (Exception e){
+                log.error("删除已删除场景资源失败,num : " + scene.getNum(), e);
+                this.saveLog(scene.getNum(), type, CommonSuccessStatus.FAIL.code(), ExceptionUtil.stacktraceToString(e, 3000));
+            }
+        });
+    }
+
+    private void deleteResultCaches(String num){
+        String cachesPath = String.format(UploadFilePath.scene_result_data_path, num).concat("caches");
+        if(CollUtil.isEmpty(fYunFileService.listRemoteFiles(cachesPath))){
+            return;
+        }
+        fYunFileService.deleteFolder(cachesPath);
+    }
+
+    @Override
+    public void cleanOss4TestCameraV3() {
+        List<Camera> cameras = cameraService.listBySnCodes(testSnCodeList);
+        if(CollUtil.isEmpty(cameras)){
+            return;
+        }
+        Set<Long> cameraIds = cameras.stream().map(Camera::getId).collect(Collectors.toSet());
+        List<SceneBean> sceneBeans = sceneProService.listCleanOss4TestCamera(cameraIds, cleanTestCameraMonth);
+        this.cleanOrig4Delete(sceneBeans, false, 3);
+    }
+
+    @Override
+    public void cleanOss4TestCameraV4() {
+        List<Camera> cameras = cameraService.listBySnCodes(testSnCodeList);
+        if(CollUtil.isEmpty(cameras)){
+            return;
+        }
+        Set<Long> cameraIds = cameras.stream().map(Camera::getId).collect(Collectors.toSet());
+        List<SceneBean> sceneBeans = scenePlusService.listCleanOss4TestCamera(cameraIds, cleanTestCameraMonth);
+        this.cleanOrig4Delete(sceneBeans, true, 3);
+    }
+
+    @Override
+    public void coldStorageHomeV3() {
+        //查询所有计算时间超过限定时间的场景,计算成功、未被删除
+        List<SceneBean> sceneBeans = sceneProService.listColdStorageScene(coldStorageMonth);
+        this.coldStorage(sceneBeans);
+    }
+
+    @Override
+    public void coldStorageHomeV4() {
+        //查询所有计算时间超过限定时间的场景,计算成功、未被删除
+        List<SceneBean> sceneBeans = scenePlusService.listColdStorageScene(coldStorageMonth);
+        this.coldStorage(sceneBeans);
+    }
+
+    private void coldStorage(List<SceneBean> sceneBeans){
+        if(CollUtil.isEmpty(sceneBeans)){
+            return;
+        }
+        sceneBeans.parallelStream().forEach(scene->{
+            boolean lock = this.lock(scene.getDataSource());
+            try {
+                if(lock) {
+                    this.coldStorageHandler(scene);
+                    sceneColdStorageLogService.saveLog(scene.getNum(), scene.getDataSource(), 1, 1, null);
+                    sceneColdStorageService.save(scene.getNum(), 1, coldBucket, bucket);
+                }
+            }catch (Exception e){
+                log.error("冷归档失败,num:{}" + scene.getNum(), e);
+                sceneColdStorageLogService.saveLog(scene.getNum(), scene.getDataSource(),1, CommonSuccessStatus.FAIL.code(), ExceptionUtil.stacktraceToString(e, 3000));
+            }finally {
+                this.releaseLock(scene.getDataSource());
+            }
+        });
+    }
+
+    private void coldStorageHandler(SceneBean scene){
+        String dataSource = scene.getDataSource();
+        if(StrUtil.isEmpty(dataSource) || dataSource.length() < 10) {
+            return;
+        }
+        String homePath = dataSource.replace(ConstantFilePath.BUILD_MODEL_PATH, ConstantFilePath.OSS_PREFIX);
+
+        //将文件复制到冷归档bucket
+        fYunFileService.copyFileBetweenBucket(bucket, homePath, coldBucket, homePath);
+
+        List<String> origList = fYunFileService.listRemoteFiles(bucket, homePath);
+        List<String> coldList = fYunFileService.listRemoteFiles(coldBucket, homePath);
+        if(origList.size() != coldList.size()){
+            throw new RuntimeException("复制文件到冷归档bucket失败");
+        }
+
+        //删除标准bucket文件
+        fYunFileService.deleteFolder(homePath);
+    }
+}

+ 33 - 0
src/main/java/com/fdkankan/scene/service/impl/SceneColdStorageLogServiceImpl.java

@@ -0,0 +1,33 @@
+package com.fdkankan.scene.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.scene.entity.SceneColdStorageLog;
+import com.fdkankan.scene.mapper.ISceneColdStorageLogMapper;
+import com.fdkankan.scene.service.ISceneColdStorageLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 场景冷归档日志表 服务实现类
+ * </p>
+ *
+ * @author 
+ * @since 2023-07-12
+ */
+@Service
+public class SceneColdStorageLogServiceImpl extends ServiceImpl<ISceneColdStorageLogMapper, SceneColdStorageLog> implements ISceneColdStorageLogService {
+
+    public void saveLog(String num, String path, Integer type, Integer state, String reason){
+        //清除旧的日志
+        this.remove(new LambdaQueryWrapper<SceneColdStorageLog>().eq(SceneColdStorageLog::getNum, num));
+        SceneColdStorageLog sceneColdStorageLog = new SceneColdStorageLog();
+        sceneColdStorageLog.setNum(num);
+        sceneColdStorageLog.setPath(path);
+        sceneColdStorageLog.setType(type);
+        sceneColdStorageLog.setState(state);
+        sceneColdStorageLog.setReason(reason);
+        this.saveOrUpdate(sceneColdStorageLog);
+    }
+
+}

+ 36 - 0
src/main/java/com/fdkankan/scene/service/impl/SceneColdStorageServiceImpl.java

@@ -0,0 +1,36 @@
+package com.fdkankan.scene.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.fdkankan.scene.entity.SceneColdStorage;
+import com.fdkankan.scene.mapper.ISceneColdStorageMapper;
+import com.fdkankan.scene.service.ISceneColdStorageService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+import java.util.Objects;
+
+/**
+ * <p>
+ * 场景封存状态表 服务实现类
+ * </p>
+ *
+ * @author 
+ * @since 2023-07-25
+ */
+@Service
+public class SceneColdStorageServiceImpl extends ServiceImpl<ISceneColdStorageMapper, SceneColdStorage> implements ISceneColdStorageService {
+
+    @Override
+    public void save(String num, Integer state, String coldBucket, String standarBucket) {
+
+        SceneColdStorage sceneColdStorage = this.getOne(new LambdaQueryWrapper<SceneColdStorage>().eq(SceneColdStorage::getNum, num));
+        if(Objects.isNull(sceneColdStorage)){
+            sceneColdStorage = new SceneColdStorage();
+        }
+        sceneColdStorage.setNum(num);
+        sceneColdStorage.setState(state);
+        sceneColdStorage.setColdBucket(coldBucket);
+        sceneColdStorage.setBucket(standarBucket);
+        this.saveOrUpdate(sceneColdStorage);
+    }
+}

+ 380 - 4
src/main/java/com/fdkankan/scene/service/impl/SceneEditInfoExtServiceImpl.java

@@ -1,20 +1,42 @@
 package com.fdkankan.scene.service.impl;
 
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.common.constant.CommonStatus;
 import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.common.constant.FileBizType;
 import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.common.util.FileUtils;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
+import com.fdkankan.model.constants.ConstantFilePath;
+import com.fdkankan.model.constants.UploadFilePath;
+import com.fdkankan.redis.constant.RedisKey;
+import com.fdkankan.redis.constant.RedisLockKey;
+import com.fdkankan.redis.util.RedisLockUtil;
+import com.fdkankan.redis.util.RedisUtil;
+import com.fdkankan.scene.bean.TagBean;
 import com.fdkankan.scene.entity.SceneEditInfo;
 import com.fdkankan.scene.entity.SceneEditInfoExt;
 import com.fdkankan.scene.entity.ScenePlus;
+import com.fdkankan.scene.entity.ScenePlusExt;
 import com.fdkankan.scene.mapper.ISceneEditInfoExtMapper;
-import com.fdkankan.scene.service.ISceneEditInfoExtService;
-import com.fdkankan.scene.service.ISceneEditInfoService;
-import com.fdkankan.scene.service.IScenePlusService;
-import java.util.Objects;
+import com.fdkankan.scene.service.*;
+import com.fdkankan.scene.vo.*;
+import com.fdkankan.web.response.ResultData;
+import org.aspectj.apache.bcel.generic.RET;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
 /**
  * <p>
  *  服务实现类
@@ -29,7 +51,17 @@ public class SceneEditInfoExtServiceImpl extends ServiceImpl<ISceneEditInfoExtMa
     @Autowired
     private IScenePlusService scenePlusService;
     @Autowired
+    private IScenePlusExtService scenePlusExtService;
+    @Autowired
     private ISceneEditInfoService sceneEditInfoService;
+    @Autowired
+    private RedisUtil redisUtil;
+    @Autowired
+    private RedisLockUtil redisLockUtil;
+    @Autowired
+    private FYunFileServiceInterface fYunFileService;
+    @Autowired
+    private ISceneUploadService sceneUploadService;
 
     @Override
     public SceneEditInfoExt getByScenePlusId(long scenePlusId) {
@@ -53,4 +85,348 @@ public class SceneEditInfoExtServiceImpl extends ServiceImpl<ISceneEditInfoExtMa
         sceneEditInfoExt.setTours(tours);
         this.updateById(sceneEditInfoExt);
     }
+
+    @Override
+    public ResultData saveBillboards(BaseJsonArrayParamVO param) throws Exception {
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+
+        this.addOrUpdateBillboards(param.getNum(), param.getData());
+
+        this.addOrUpdateBillboardsStyles(param.getNum(), param.getStyles());
+
+        //保存数据库
+        SceneEditInfoExt sceneEditInfoExt = this.getByScenePlusId(scenePlus.getId());
+        this.updateBillboards(param.getNum(), sceneEditInfoExt);
+//        this.updateById(sceneEditInfoExt);
+
+        sceneEditInfoService.upgradeVersionById(sceneEditInfoExt.getEditInfoId());
+
+        return ResultData.ok();
+    }
+
+    private void addOrUpdateBillboardsStyles(String num, List<JSONObject> styles) throws Exception{
+
+        this.syncBillboardsStylesFromFileToRedis(num);
+
+        if(CollUtil.isEmpty(styles)){
+            return;
+        }
+
+        long time = Calendar.getInstance().getTimeInMillis();
+        Map<String, String> styleMap = new HashMap<>();
+        AtomicInteger index = new AtomicInteger();
+        styles.stream().forEach(style->{
+            String id = style.getString("sid");
+            style.put("createTime", time + index.getAndIncrement());
+            styleMap.put(id, style.toJSONString());
+        });
+
+        String key = String.format(RedisKey.SCENE_BILLBOARDS_STYLES, num);
+        redisUtil.hmset(key, styleMap);
+
+        //写入本地文件,作为备份
+        this.writeBillboardStylesJson(num);
+    }
+
+    private void syncBillboardsStylesFromFileToRedis(String num) throws Exception{
+
+        String key = String.format(RedisKey.SCENE_BILLBOARDS_STYLES, num);
+        boolean exist = redisUtil.hasKey(key);
+        if(exist){
+            return;
+        }
+        String lockKey = String.format(RedisLockKey.LOCK_BILLBOARDS_STYLES_SYNC, num);
+        String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
+        boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE);
+        if(!lock){
+            throw new BusinessException(ErrorCode.SYSTEM_BUSY);
+        }
+        try{
+            exist = redisUtil.hasKey(key);
+            if(exist){
+                return;
+            }
+            String stylesPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num);
+            String stylesData = FileUtils.readUtf8String(stylesPath + "billboards-styles.json");
+            if(StrUtil.isEmpty(stylesData)){
+                return;
+            }
+            JSONArray stylesArr = JSON.parseArray(stylesData);
+            if(CollUtil.isEmpty(stylesArr)){
+                return;
+            }
+            Map<String, String> styleMap = new HashMap<>();
+            for (Object style : stylesArr) {
+                JSONObject styleObj = (JSONObject)style;
+                String id = styleObj.getString("sid");
+                styleMap.put(id, styleObj.toJSONString());
+            }
+            redisUtil.hmset(key, styleMap);
+        }finally {
+            redisLockUtil.unlockLua(lockKey, lockVal);
+        }
+
+    }
+
+    @Override
+    public ResultData deleteBillboards(DeleteSidListParamVO param) throws Exception {
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+        ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
+        String bucket = scenePlusExt.getYunFileBucket();
+
+        List<String> deleteSidList = param.getSidList();
+
+        this.syncBillboardsFromFileToRedis(param.getNum());
+
+        //处理删除状态数据
+        this.deleteBillboards(param.getNum(), deleteSidList, bucket);
+
+        //写入本地文件,作为备份
+        this.writeBillboardJson(param.getNum());
+
+        //保存数据库
+        SceneEditInfoExt sceneEditInfoExt = this.getByScenePlusId(scenePlus.getId());
+        this.updateBillboards(param.getNum(), sceneEditInfoExt);
+        sceneEditInfoService.upgradeVersionById(sceneEditInfoExt.getEditInfoId());
+
+        return ResultData.ok();
+    }
+
+    @Override
+    public JSONObject listBillboards(BaseSceneParamVO param) throws Exception {
+
+        JSONObject result = new JSONObject();
+        List<JSONObject> tags = new ArrayList<>();
+        List<JSONObject> styles = new ArrayList<>();
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+        SceneEditInfoExt sceneEditInfoExt = this.getByScenePlusId(scenePlus.getId());
+
+        this.syncBillboardsFromFileToRedis(param.getNum());
+
+        //获取指示牌数据
+        String key = String.format(RedisKey.SCENE_BILLBOARDS, param.getNum());
+        List<String> list = redisUtil.hgetValues(key);
+        if(CollUtil.isNotEmpty(list)){
+            List<TagBean> sortList = list.stream().map(str -> {
+                JSONObject jsonObject = JSON.parseObject(str);
+                TagBean tagBean = new TagBean();
+                tagBean.setCreateTime(jsonObject.getLong("createTime"));
+                jsonObject.remove("createTime");
+                tagBean.setTag(jsonObject);
+                return tagBean;
+            }).collect(Collectors.toList());
+            sortList.sort(Comparator.comparingLong(TagBean::getCreateTime).reversed());
+            tags = sortList.stream().map(item -> item.getTag()).collect(Collectors.toList());
+        }
+        result.put("tags", tags);
+
+        //获取图标数据
+        this.syncBillboardsStylesFromFileToRedis(param.getNum());
+        key = String.format(RedisKey.SCENE_BILLBOARDS_STYLES, param.getNum());
+        List<String> sytlelist = redisUtil.hgetValues(key);
+        if(CollUtil.isNotEmpty(sytlelist)){
+            List<TagBean> stileSortList = sytlelist.stream().map(str -> {
+                JSONObject jsonObject = JSON.parseObject(str);
+                TagBean tagBean = new TagBean();
+                tagBean.setCreateTime(jsonObject.getLong("createTime"));
+                jsonObject.remove("createTime");
+                tagBean.setTag(jsonObject);
+                return tagBean;
+            }).collect(Collectors.toList());
+            stileSortList.sort(Comparator.comparingLong(TagBean::getCreateTime).reversed());
+            styles = stileSortList.stream().map(item -> item.getTag()).collect(Collectors.toList());
+        }
+        result.put("styles", styles);
+
+        return result;
+    }
+
+    private void deleteBillboards(String num, List<String> deleteSidList, String bucket) throws Exception {
+        if(CollUtil.isEmpty(deleteSidList)){
+            return;
+        }
+
+        //从redis中加载热点数据
+        String key = String.format(RedisKey.SCENE_BILLBOARDS, num);
+        List<String> deletDataList = redisUtil.hMultiGet(key, deleteSidList);
+        if(CollUtil.isEmpty(deletDataList))
+            return;
+        //从redis中移除热点数据
+        redisUtil.hdel(key, deleteSidList.toArray());
+    }
+
+    private void addOrUpdateBillboards(String num, List<JSONObject> data) throws Exception{
+        Map<String, String> addOrUpdateMap = new HashMap<>();
+        int i = 0;
+        for (JSONObject jsonObject : data) {
+            jsonObject.put("createTime", Calendar.getInstance().getTimeInMillis() + i++);
+            addOrUpdateMap.put(jsonObject.getString("sid"), JSON.toJSONString(jsonObject));
+        }
+
+        this.syncBillboardsFromFileToRedis(num);
+
+        //处理新增和修改数据
+        this.addOrUpdateBillboardsHandler(num, addOrUpdateMap);
+    }
+
+    /**
+     * <p>
+     保证指示牌数据安全性,当redis宕机导致热点数据丢失时,可以从文件中读取,恢复到redis
+     * </p>
+     * @author dengsixing
+     * @date 2022/3/3
+     **/
+    private void syncBillboardsFromFileToRedis(String num) throws Exception{
+
+        String key = String.format(RedisKey.SCENE_BILLBOARDS, num);
+        boolean exist = redisUtil.hasKey(key);
+        if(exist){
+            return;
+        }
+        String lockKey = String.format(RedisLockKey.LOCK_BILLBOARDS_SYNC, num);
+        String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
+        boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE);
+        if(!lock){
+            throw new BusinessException(ErrorCode.SYSTEM_BUSY);
+        }
+        try{
+            exist = redisUtil.hasKey(key);
+            if(exist){
+                return;
+            }
+            String billboardsFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "billboards.json";
+            String billboardsData = FileUtils.readUtf8String(billboardsFilePath);
+            if(StrUtil.isEmpty(billboardsData)){
+                return;
+            }
+            JSONArray tagsArr = JSON.parseArray(billboardsData);
+            if(CollUtil.isEmpty(tagsArr)){
+                return;
+            }
+            Map<String, String> map = new HashMap<>();
+            for (Object o : tagsArr) {
+                JSONObject jo = (JSONObject)o;
+                map.put(jo.getString("sid"), jo.toJSONString());
+            }
+            redisUtil.hmset(key, map);
+        }finally {
+            redisLockUtil.unlockLua(lockKey, lockVal);
+        }
+    }
+
+    private void addOrUpdateBillboardsHandler(String num, Map<String, String> addOrUpdateMap){
+        if(CollUtil.isEmpty(addOrUpdateMap))
+            return;
+
+        //批量写入缓存
+        String key = String.format(RedisKey.SCENE_BILLBOARDS, num);
+        redisUtil.hmset(key, addOrUpdateMap);
+
+        //写入本地文件,作为备份
+        this.writeBillboardJson(num);
+    }
+
+    /**
+     * <p>
+     热点数据保存
+
+     * </p>
+     * @author dengsixing
+     * @date 2022/3/3
+     *
+     **/
+    private void writeBillboardJson(String num){
+        String lockKey = String.format(RedisLockKey.LOCK_BILLBOARDS_SYNC, num);
+        String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
+        boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE);
+        if(!lock){
+            return;
+        }
+        try{
+            String dataKey = String.format(RedisKey.SCENE_BILLBOARDS, num);
+            String hotJsonPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "billboards.json";
+            if(!redisUtil.hasKey(dataKey)){
+                FileUtil.del(hotJsonPath);
+                return;
+            }
+            Map<String, String> billboardMap = redisUtil.hmget(dataKey);
+            List<JSONObject>  billboardList = billboardMap.entrySet().stream().map(entry->JSON.parseObject(entry.getValue())).collect(Collectors.toList());
+            FileUtil.writeUtf8String(JSON.toJSONString(billboardList), hotJsonPath);
+        }finally {
+            redisLockUtil.unlockLua(lockKey, lockVal);
+        }
+    }
+
+    private void writeBillboardStylesJson(String num){
+        String lockKey = String.format(RedisLockKey.LOCK_BILLBOARDS_STYLES_SYNC, num);
+        String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
+        boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE);
+        if(!lock){
+            return;
+        }
+        try{
+            String dataKey = String.format(RedisKey.SCENE_BILLBOARDS_STYLES, num);
+            String stylesPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "billboards-styles.json";
+            if(!redisUtil.hasKey(dataKey)){
+                FileUtil.del(stylesPath);
+                return;
+            }
+            Map<String, String> billboardStylesMap = redisUtil.hmget(dataKey);
+            List<JSONObject>  billboardStyleList = billboardStylesMap.entrySet().stream().map(entry->JSON.parseObject(entry.getValue())).collect(Collectors.toList());
+            FileUtil.writeUtf8String(JSON.toJSONString(billboardStyleList), stylesPath);
+        }finally {
+            redisLockUtil.unlockLua(lockKey, lockVal);
+        }
+    }
+
+    private void updateBillboards(String num, SceneEditInfoExt sceneEditInfoExt){
+        //查询缓存是否包含热点数据
+        String key = String.format(RedisKey.SCENE_BILLBOARDS, num);
+        Map<String, String> billboardsMap = redisUtil.hmget(key);
+        boolean hashBillboards= false;
+        for (Map.Entry<String, String> tagMap : billboardsMap.entrySet()) {
+            if(StrUtil.isEmpty(tagMap.getValue())){
+                continue;
+            }
+            hashBillboards = true;
+            break;
+        }
+
+        //更改热点状态
+        sceneEditInfoExt.setBillboards(hashBillboards ? CommonStatus.YES.code().intValue() : CommonStatus.NO.code().intValue());
+        this.updateById(sceneEditInfoExt);
+    }
+
+    @Override
+    public ResultData deleteBillboardsStyles(DeleteStylesParamVO param) throws Exception {
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+        if (scenePlus == null)
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
+
+        List<String> sidList = param.getSidList();
+
+        this.syncBillboardsStylesFromFileToRedis(param.getNum());
+
+        String key = String.format(RedisKey.SCENE_BILLBOARDS_STYLES, param.getNum());
+        List<String> deleteList = redisUtil.hMultiGet(key, sidList);
+        redisUtil.hdel(key, sidList.toArray());
+
+        //写入本地文件,作为备份
+        this.writeBillboardStylesJson(param.getNum());
+
+        //删除oss文件
+        List<String> deleteFileList = deleteList.stream().map(str -> {
+            JSONObject parse = JSON.parseObject(str);
+            return parse.getString("url");
+        }).collect(Collectors.toList());
+        sceneUploadService.delete(
+                DeleteFileParamVO.builder()
+                        .num(param.getNum())
+                        .fileNames(deleteFileList)
+                        .bizType(FileBizType.BILLBOARD_ICON.code()).build());
+
+        return ResultData.ok();
+    }
+
+
 }

+ 338 - 141
src/main/java/com/fdkankan/scene/service/impl/SceneEditInfoServiceImpl.java

@@ -1,4 +1,8 @@
 package com.fdkankan.scene.service.impl;
+import cn.hutool.core.util.CharsetUtil;
+import com.fdkankan.common.constant.*;
+import com.fdkankan.common.util.FileSizeUtil;
+import com.fdkankan.scene.vo.SaveFiltersParamVO;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
@@ -12,17 +16,9 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.fdkankan.common.constant.CommonStatus;
-import com.fdkankan.common.constant.ErrorCode;
-import com.fdkankan.common.constant.FileBizType;
-import com.fdkankan.common.constant.OperationType;
-import com.fdkankan.common.constant.SceneFrom;
-import com.fdkankan.common.constant.SceneInfoReqType;
-import com.fdkankan.common.constant.ServerCode;
 import com.fdkankan.common.exception.BusinessException;
 import com.fdkankan.common.util.FileMd5Util;
 import com.fdkankan.common.util.FileUtils;
-import com.fdkankan.fyun.constant.FYunTypeEnum;
 import com.fdkankan.fyun.face.FYunFileServiceInterface;
 import com.fdkankan.model.constants.ConstantFilePath;
 import com.fdkankan.model.constants.UploadFilePath;
@@ -44,6 +40,7 @@ import com.fdkankan.scene.bean.VertexBean;
 import com.fdkankan.scene.bean.WallBean;
 import com.fdkankan.scene.entity.CameraDetail;
 import com.fdkankan.scene.entity.Company;
+import com.fdkankan.scene.entity.SceneAsynOperLog;
 import com.fdkankan.scene.entity.SceneDataDownload;
 import com.fdkankan.scene.entity.SceneEditControls;
 import com.fdkankan.scene.entity.SceneEditInfo;
@@ -53,6 +50,7 @@ import com.fdkankan.scene.entity.ScenePlusExt;
 import com.fdkankan.scene.mapper.ISceneEditInfoMapper;
 import com.fdkankan.scene.service.ICameraDetailService;
 import com.fdkankan.scene.service.ICompanyService;
+import com.fdkankan.scene.service.ISceneAsynOperLogService;
 import com.fdkankan.scene.service.ISceneDataDownloadService;
 import com.fdkankan.scene.service.ISceneEditControlsService;
 import com.fdkankan.scene.service.ISceneEditInfoExtService;
@@ -68,7 +66,7 @@ import com.fdkankan.scene.vo.BaseFileParamVO;
 import com.fdkankan.scene.vo.BaseSceneParamVO;
 import com.fdkankan.scene.vo.DeleteFileParamVO;
 import com.fdkankan.scene.vo.DeleteLinkPanParamVO;
-import com.fdkankan.scene.vo.DeleteLinkSceneStylesParamVO;
+import com.fdkankan.scene.vo.DeleteStylesParamVO;
 import com.fdkankan.scene.vo.DeleteMosaicParamVO;
 import com.fdkankan.scene.vo.DeleteSidParamVO;
 import com.fdkankan.scene.vo.DownloadVO;
@@ -103,6 +101,7 @@ import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
 import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 import javax.annotation.Resource;
@@ -162,6 +161,8 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
     private ICompanyService companyService;
     @Autowired
     private ISurveillanceService surveillanceService;
+    @Autowired
+    private ISceneAsynOperLogService sceneAsynOperLogService;
 
     @Transactional
     @Override
@@ -189,6 +190,11 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
             sceneEditInfo.setVersion(sceneEditInfoDb.getVersion() + 1);
             this.updateById(sceneEditInfo);
         }
+        SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByEditInfoId(sceneEditInfo.getId());
+        if(Objects.nonNull(param.getSns())){
+            sceneEditInfoExt.setSnsInfo(JSON.toJSONString(param.getSns()));
+        }
+        sceneEditInfoExtService.updateById(sceneEditInfoExt);
 
         if(Objects.nonNull(param.getControls())){
             SceneEditControls sceneEditControls = BeanUtil.copyProperties(param.getControls(), SceneEditControls.class);
@@ -272,6 +278,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         sceneJson.setSceneResolution(scenePlusExt.getSceneResolution());
         sceneJson.setSceneFrom(scenePlusExt.getSceneFrom());
         sceneJson.setSceneKind(scenePlusExt.getSceneKind());
+        sceneJson.setModelKind(scenePlusExt.getModelKind());
         if(StrUtil.isNotEmpty(scenePlusExt.getVideos())){
             sceneJson.setVideos(scenePlusExt.getVideos());
         }
@@ -279,8 +286,11 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         //发布马赛克列表
         sceneJson.setMosaicList(this.getMosaicList(num));
 
+        //发布分享配置
+        sceneJson.setSns(JSON.parseObject(sceneEditInfoExt.getSnsInfo()));
+
         //处理热点数据,生成hot.json
-        this.publicHotData(num, sceneEditInfo, bucket);
+        this.publicHotData(num, bucket);
 
         //发布场景关联相关数据
         this.publicLinkSceneData(num, bucket);
@@ -291,6 +301,9 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         //发布摄像头数据
         this.publicSurveillance(num, sceneEditInfoExt.getSurveillances(), bucket);
 
+        //发布指示牌数据
+        this.publicBillboardData(num, bucket);
+
         //本地写sceneJson文件
         String localSceneJsonPath = String.format(ConstantFilePath.SCENE_DATA_PATH_V4, num) + "scene.json";
         FileUtils.writeFile(localSceneJsonPath, JSON.toJSONString(sceneJson));
@@ -298,19 +311,22 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         String sceneJsonPath = String.format(UploadFilePath.DATA_VIEW_PATH+"scene.json", num);
         fYunFileService.uploadFile(bucket, JSON.toJSONBytes(sceneJson), sceneJsonPath);
 
-        //sceneJson放入缓存
-        String key = String.format(RedisKey.SCENE_JSON, num);
-        redisUtil.set(key, JSON.toJSONString(sceneJson));
-
         //删除发布数据中的user目录
         String publicUserPath = String.format(UploadFilePath.USER_VIEW_PATH, num);
-        fYunFileService.deleteFile(bucket, publicUserPath);
+        List<String> userViewFileList = fYunFileService.listRemoteFiles(bucket, publicUserPath);
+        if(CollUtil.isNotEmpty(userViewFileList)){
+            fYunFileService.deleteFolder(bucket, publicUserPath);
+        }
 
         //复制编辑目录到发布目录
         String editPath = String.format(UploadFilePath.USER_EDIT_PATH, param.getNum());
         String viewPath = String.format(UploadFilePath.USER_VIEW_PATH, param.getNum());
         fYunFileService.copyFileBetweenBucket(bucket, editPath, bucket, viewPath);
 
+        //sceneJson放入缓存
+        String key = String.format(RedisKey.SCENE_JSON, num);
+        redisUtil.set(key, JSON.toJSONString(sceneJson));
+
         //入库
         if(sceneEditInfo.getId() == null){
             this.save(sceneEditInfo);
@@ -323,11 +339,18 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
 
         scenePlus.setTitle(sceneEditInfo.getTitle());
         scenePlus.setDescription(sceneEditInfo.getDescription());
+        scenePlus.setHouseType(this.existsHouseType(bucket, num));
         scenePlusService.updateById(scenePlus);
 
         return ResultData.ok();
     }
 
+    private int existsHouseType(String bucket, String num){
+        String houseTypePath = String.format(UploadFilePath.USER_VIEW_PATH, num) + "houseType.json";
+        boolean exist = fYunFileService.fileExist(bucket, houseTypePath);
+        return exist ? CommonStatus.YES.code().intValue() : CommonStatus.NO.code().intValue();
+    }
+
     private void publicSurveillance(String num, Integer surveillances, String bucket) throws IOException {
         String surveillanceJsonPath = String.format(UploadFilePath.USER_EDIT_PATH, num) + "surveillance.json";
         if(surveillances == CommonStatus.NO.code().intValue()){
@@ -358,6 +381,11 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         String userEditPath = String.format(UploadFilePath.USER_EDIT_PATH, num);
         String imgViewPath = String.format(UploadFilePath.IMG_VIEW_PATH, num);
 
+        //清除发布目录中的场景关联图片
+        if(fYunFileService.fileExist(bucket,imgViewPath + "panorama")){
+            fYunFileService.deleteFolder(bucket,imgViewPath + "panorama");
+        }
+
         //生成links.json并上传到发布目录
         String linkPanKey = String.format(RedisKey.SCENE_LINKPAN_DATA, num);
         Map<String, String> linkPanMap = redisUtil.hmget(linkPanKey);
@@ -372,12 +400,11 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         fYunFileService.uploadFile(bucket, linkPanArr.toString().getBytes(), linkScenePath);
 
         //拷贝编辑目录到发布目录
-        fYunFileService.deleteFile(bucket,imgViewPath + "panorama");
         fYunFileService.copyFileBetweenBucket(bucket, imgEditPath + "panorama", bucket, imgViewPath + "panorama");
 
     }
 
-    private void publicHotData(String sceneNum, SceneEditInfo sceneEditInfo, String bucket) throws IOException {
+    private void publicHotData(String sceneNum, String bucket) throws IOException {
         String hotDataKey = String.format(RedisKey.SCENE_HOT_DATA, sceneNum);
         Map<String, String> hotMap = redisUtil.hmget(hotDataKey);
 
@@ -400,8 +427,20 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
 
         String hotJsonPath = String.format(UploadFilePath.USER_EDIT_PATH, sceneNum) + "hot.json";
         fYunFileService.uploadFile(bucket, tags.toString().getBytes(), hotJsonPath);
-        this.saveTagsToSceneEditInfo(sceneNum, sceneEditInfo);
+//        this.saveTagsToSceneEditInfo(sceneNum, sceneEditInfo);
+
+    }
 
+    private void publicBillboardData(String sceneNum, String bucket) throws IOException {
+        String Key = String.format(RedisKey.SCENE_BILLBOARDS, sceneNum);
+        String userEditPath = String.format(UploadFilePath.USER_EDIT_PATH, sceneNum) + "billboards.json";
+        List<String> list = redisUtil.hgetValues(Key);
+        if(CollUtil.isEmpty(list)){
+            fYunFileService.deleteFile(bucket, userEditPath);
+            return;
+        }
+        List<JSONObject> collect = list.stream().map(str -> JSON.parseObject(str)).collect(Collectors.toList());
+        fYunFileService.uploadFile(bucket, JSON.toJSONString(collect).getBytes(), userEditPath);
     }
 
     @Override
@@ -453,15 +492,18 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         }
         sceneInfoVO.setControls(BeanUtil.copyProperties(sceneEditControls, SceneEditControlsVO.class));
         sceneInfoVO.setNum(num);
-        sceneInfoVO.setCreateTime(scenePlus.getCreateTime());
+        sceneInfoVO.setCreateTime(scenePlusExt.getAlgorithmTime());
 
         sceneInfoVO.setSceneResolution(scenePlusExt.getSceneResolution());
         sceneInfoVO.setSceneFrom(scenePlusExt.getSceneFrom());
         sceneInfoVO.setSceneKind(scenePlusExt.getSceneKind());
+        sceneInfoVO.setModelKind(scenePlusExt.getModelKind());
         sceneInfoVO.setVideos(scenePlusExt.getVideos());
-        if(CommonStatus.YES.code().equals(sceneEditInfoExt.getMosaic())){
+        if(CommonStatus.YES.code().intValue() == sceneEditInfoExt.getMosaic()){
             sceneInfoVO.setMosaicList(this.getMosaicList(num));
         }
+        sceneInfoVO.setSpace(FileSizeUtil.convert(scenePlusExt.getSpace(), FileSizeUnitType.MB.code()));
+        sceneInfoVO.setSns(JSON.parseObject(sceneEditInfoExt.getSnsInfo()));
 
         this.SortBoxVideos(sceneInfoVO);
 
@@ -470,6 +512,12 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         return sceneInfoVO;
     }
 
+    public static void main(String[] args) {
+        String test = "";
+        JSONObject jsonObject = JSON.parseObject(test);
+        System.out.println(jsonObject);
+    }
+
     private void SortBoxVideos(SceneInfoVO sceneInfoVO){
         String boxVideos = sceneInfoVO.getBoxVideos();
         if(StrUtil.isEmpty(boxVideos)){
@@ -548,33 +596,29 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         String sceneJson = redisUtil.get(key);
         SceneInfoVO sceneInfoVO = null;
         //先查询redis
-        if(StrUtil.isNotEmpty(sceneJson)) {
-            sceneInfoVO = JSON.parseObject(sceneJson, SceneInfoVO.class);
-            sceneInfoVO.setScenePassword(null);
-            if(Objects.isNull(sceneInfoVO.getFloorPlanAngle())){
-                sceneInfoVO.setFloorPlanAngle(0f);
-            }
-            if(Objects.isNull(sceneInfoVO.getFloorPlanCompass())){
-                sceneInfoVO.setFloorPlanCompass(0f);
-            }
-            return sceneInfoVO;
+        if(StrUtil.isEmpty(sceneJson)) {
+            String objectName = String.format(ConstantFilePath.SCENE_VIEW_DATA_DATA_SCENEJSON, num);
+            sceneJson = fYunFileService.getFileContent(scenePlusExt.getYunFileBucket(), objectName);
+            redisUtil.set(key, sceneJson);
         }
-
-        //如果redis没找到,从scene.json中获取
-        String objectName = String.format(ConstantFilePath.SCENE_VIEW_DATA_DATA_SCENEJSON, num);
-        String objectContent = fYunFileService.getFileContent(scenePlusExt.getYunFileBucket(), objectName);
-        log.info("获取scene.json内容,path:{}, content:{}", objectName, objectContent);
-        if(StrUtil.isEmpty(objectContent))
-            return null;
-        sceneInfoVO = JSON.parseObject(objectContent, SceneInfoVO.class);
+        sceneInfoVO = JSON.parseObject(sceneJson, SceneInfoVO.class);
+        sceneInfoVO.setScenePassword(null);
         if(Objects.isNull(sceneInfoVO.getFloorPlanAngle())){
             sceneInfoVO.setFloorPlanAngle(0f);
         }
         if(Objects.isNull(sceneInfoVO.getFloorPlanCompass())){
             sceneInfoVO.setFloorPlanCompass(0f);
         }
-        redisUtil.set(key, JSON.toJSONString(sceneInfoVO));
-        sceneInfoVO.setScenePassword(null);
+        SceneEditControlsVO controls = sceneInfoVO.getControls();
+        if(Objects.isNull(controls.getShowShare())){
+            controls.setShowShare(CommonStatus.YES.code().intValue());
+        }
+        if(Objects.isNull(controls.getShowCapture())){
+            controls.setShowCapture(CommonStatus.YES.code().intValue());
+        }
+        if(Objects.isNull(controls.getShowBillboardTitle())){
+            controls.setShowBillboardTitle(CommonStatus.YES.code().intValue());
+        }
 
         return sceneInfoVO;
     }
@@ -605,7 +649,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         //处理户型图数据
         //上传floorplan_user.json文件
         FileUtils.writeFile(localDataPath + "floorplan_user.json", floorJsonData);
-        fYunFileService.uploadFile(bucket, localDataPath + "floorplan_user.json", editUserPath + "floorplan_user.json");
+        fYunFileService.uploadFile(bucket, localDataPath + "floorplan_user.json", editUserPath + "floorplan.json");
 
         //写入数据库
         Byte floorPlanUser = null;
@@ -663,18 +707,22 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         String bucket = scenePlusExt.getYunFileBucket();
         String path = scenePlusExt.getDataSource();
 
-        //户型图上传
-        String  userEditPath = UploadFilePath.USER_EDIT_PATH + "floor-cad-%s.%s";
-        String floorCadPath = path + "/results/floorplan_cad";
-        List<String> floorCadList = FileUtils.getFileList(floorCadPath);
-        if(CollUtil.isNotEmpty(floorCadList)){
-            floorCadList.stream().forEach(str->{
-                String substring = str.substring(str.lastIndexOf(File.separator) + 1);
-                String[] arr = substring.split("floor");
-                String[] arr2 = arr[1].split("\\.");
-                fYunFileService.uploadFile(bucket, str, String.format(userEditPath, num, arr2[0], arr2[1]));
-            });
-        }
+        //户型图上传 恢复默认并发布同时点击刷新查看页面,平面图会变形,所以这里先注释掉 bug-36281 2023-05-04
+//        String ossResultPath = String.format(UploadFilePath.scene_result_data_path, num);
+//        String floorplanCadPath = ossResultPath + "floorplan_cad/";
+//        fYunFileService.copyFileBetweenBucket(bucket, floorplanCadPath, bucket, String.format(UploadFilePath.USER_EDIT_PATH, num));
+
+//        String  userEditPath = UploadFilePath.USER_EDIT_PATH + "floor-cad-%s.%s";
+//        String floorCadPath = path + "/results/floorplan_cad";
+//        List<String> floorCadList = FileUtils.getFileList(floorCadPath);
+//        if(CollUtil.isNotEmpty(floorCadList)){
+//            floorCadList.stream().forEach(str->{
+//                String substring = str.substring(str.lastIndexOf(File.separator) + 1);
+//                String[] arr = substring.split("floor");
+//                String[] arr2 = arr[1].split("\\.");
+//                fYunFileService.uploadFile(bucket, str, String.format(userEditPath, num, arr2[0], arr2[1]));
+//            });
+//        }
 
         //根据floorplan_cad.json生成houseType.json
         this.uploadHouseTypeJson(num, bucket);
@@ -715,6 +763,10 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         result.put("version", "2.1");
 
         String floorplanCadPath = String.format(UploadFilePath.DATA_VIEW_PATH, num) + "floorplan_cad.json";
+        if(!fYunFileService.fileExist(bucket, floorplanCadPath)){
+            log.warn("生成houseType.json失败,原因:floorplan_cad.json文件不存在,num:{}", num);
+            return;
+        }
         String floorcadStr = fYunFileService.getFileContent(bucket, floorplanCadPath);
 
         JSONObject floorcadObj = JSON.parseObject(floorcadStr);
@@ -824,16 +876,16 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
         String bucket = scenePlusExt.getYunFileBucket();
 
-        String key = String.format(UploadFilePath.DATA_VIEW_PATH, param.getNum()) + "floorplan_cad.json";
-        String floorplanCadJson = fYunFileService.getFileContent(bucket, key);
-        if(StrUtil.isEmpty(floorplanCadJson)){
+        String key = String.format(UploadFilePath.USER_EDIT_PATH, param.getNum()) + "floorplan.json";
+        String floorplanJson = fYunFileService.getFileContent(bucket, key);
+        if(StrUtil.isEmpty(floorplanJson)){
             return ResultData.ok();
         }
         Map<Integer, String> renameMap = new HashMap<>();
         param.getFloors().stream().forEach(floor->{
             renameMap.put(floor.getSubgroup(), floor.getName());
         });
-        JSONObject jsonObject = JSON.parseObject(floorplanCadJson);
+        JSONObject jsonObject = JSON.parseObject(floorplanJson);
         if(Objects.isNull(jsonObject)){
             return ResultData.ok();
         }
@@ -897,9 +949,11 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         String sceneJson = redisUtil.get(key);
         if(StrUtil.isNotEmpty(sceneJson)){
             SceneJsonBean sceneJsonBean = JSON.parseObject(sceneJson, SceneJsonBean.class);
-            sceneJsonBean.setVersion(version);
+            if(Objects.nonNull(version)){
+                sceneJsonBean.setVersion(version);
+            }
             if(Objects.nonNull(imgVersion)){
-                sceneJsonBean.setImgVersion(imgVersion + 1);
+                sceneJsonBean.setImgVersion(imgVersion);
             }
             redisUtil.set(key, JSON.toJSONString(sceneJsonBean));
         }
@@ -909,9 +963,11 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         sceneJson= fYunFileService.getFileContent(bucket, sceneJsonPath);
         if(StrUtil.isNotEmpty(sceneJson)){
             SceneJsonBean sceneJsonBean = JSON.parseObject(sceneJson, SceneJsonBean.class);
-            sceneJsonBean.setVersion(version);
+            if(Objects.nonNull(version)){
+                sceneJsonBean.setVersion(version);
+            }
             if(Objects.nonNull(imgVersion)){
-                sceneJsonBean.setImgVersion(imgVersion + 1);
+                sceneJsonBean.setImgVersion(imgVersion);
             }
             fYunFileService.uploadFile(bucket, JSON.toJSONString(sceneJsonBean).getBytes(StandardCharsets.UTF_8), sceneJsonPath);
         }
@@ -929,6 +985,19 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         if(scenePlus == null){
             throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
         }
+
+        //查询是否存在等待中的异步操作记录,如果存在,抛出业务异常,终止操作
+        this.checkSceneAsynOper(num, null, SceneAsynModuleType.UPLOAD_DOWNLOAD.code() , SceneAsynFuncType.PANORAMIC_IMAGE.code());
+
+        //清除全景图异步操作记录,防止再次下载的时候请求到旧的压缩包
+        sceneAsynOperLogService.remove(
+            new LambdaQueryWrapper<SceneAsynOperLog>()
+            .eq(SceneAsynOperLog::getNum, num)
+            .eq(SceneAsynOperLog::getModule, SceneAsynModuleType.UPLOAD_DOWNLOAD.code())
+            .eq(SceneAsynOperLog::getFunc, SceneAsynFuncType.PANORAMIC_IMAGE.code())
+        );
+
+
         ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
         String bucket = scenePlusExt.getYunFileBucket();
 
@@ -943,7 +1012,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         String zipTargetFilePath = targetImagesPath + file.getOriginalFilename();
 
         //判断全景图缓存是否存在,如果不存在,从计算目录中拷贝到缓存目录
-        this.cachePanorama(path, num);
+//        this.cachePanorama(path, num);
 
         //先删除本地文件
         FileUtils.deleteDirectory(targetImagesPath);
@@ -954,9 +1023,14 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         file.transferTo(targetFile);
 
         //如果是压缩包上传,需要解压缩
+        int async = CommonStatus.NO.code();
         if(file.getOriginalFilename().endsWith(".zip")){
+
+            //标记为异步处理
+            async = CommonStatus.YES.code();
+
             //解压zip包
-            ZipUtil.unzip(zipTargetFilePath,targetImagesPath);
+            ZipUtil.unzip(zipTargetFilePath,targetImagesPath, CharsetUtil.CHARSET_GBK);
             //删除压缩包
             FileUtils.delFile(zipTargetFilePath);
         }
@@ -990,11 +1064,13 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         }
 
         //比对图片列表,不存在的要返回名称集合
-        String visionPath = path + "/results/vision.txt";
+        String ossVisionPath = String.format(UploadFilePath.IMG_VIEW_PATH, num) + "vision.txt";
+        String visionPath = String.format(ConstantFilePath.SCENE_DATA_PATH_V4, num) + "vision.txt";
+        fYunFileService.downloadFile(ossVisionPath, visionPath);
         List<String> panoramaImageList = SceneUtil.getPanoramaImageList(visionPath);
         List<String> notExistFileList = uploadFileList.stream().filter(filePath -> {
             filePath = filePath.substring(filePath.lastIndexOf(File.separator) + 1);
-            if(panoramaImageList.contains(filePath)){
+            if(CollUtil.isEmpty(panoramaImageList) || panoramaImageList.contains(filePath)){
                 return false;
             }
             return true;
@@ -1015,7 +1091,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
                     return filePath.substring(filePath.lastIndexOf(File.separator) + 1);
                 }).collect(Collectors.toList());
             }
-            return ResultData.ok(new UploadPanoramaVO(0, notExistFileList));
+            return ResultData.ok(new UploadPanoramaVO(0,0, notExistFileList));
         }
 
         //上传
@@ -1026,8 +1102,9 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         CreateObjUtil.convertVisionmodeldataToTxt(target + File.separator + "extras" + File.separator + "vision.modeldata",
             target + File.separator + "extras" + File.separator + "vision.txt");
 
-        FileUtils.copyFile(path + File.separator + "data.json", target + File.separator+"data.json", true);
-        FileUtils.copyFile(path + File.separator + "project.json", target + File.separator+"project.json", true);
+        String ossResultPath = String.format(UploadFilePath.scene_result_data_path, num);
+        fYunFileService.downloadFile(bucket, ossResultPath + "data.json", target + File.separator+"data.json");
+        fYunFileService.downloadFile(bucket, ossResultPath + "project.json", target + File.separator+"project.json");
 
         //data.json增加extras为执行重建算法
         String data = FileUtils.readFile(target + File.separator+"data.json");
@@ -1061,11 +1138,74 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         if(new File(target + File.separator + "results").exists()){
             FileUtils.delAllFile(target + File.separator + "results");
         }
-        if(FYunTypeEnum.AWS.code().equals(fyunType)){
-            //亚马逊保持旧方式,超链接capture
-            CreateObjUtil.createSoftConnection(path + File.separator + "capture", target + File.separator + "capture");
-        }
+
         fYunFileService.downloadFile(ConstantFilePath.OSS_PREFIX + path.replace(ConstantFilePath.BUILD_MODEL_PATH, "") + "/data.fdage", target + File.separator + "capture/data.fdage");
+
+        //如果部分成功,则需要返回成功数量和失败列表
+        if(CollUtil.isNotEmpty(notExistFileList)){
+            notExistFileList = notExistFileList.stream().map(filePath -> {
+                return filePath.substring(filePath.lastIndexOf(File.separator) + 1);
+            }).collect(Collectors.toList());
+        }
+
+        UploadPanoramaVO uploadPanoramaVO = new UploadPanoramaVO();
+        uploadPanoramaVO.setAsyn(async);
+        if(async == CommonStatus.YES.code().intValue()){
+            List<String> finalUploadFileList = uploadFileList;
+            List<String> finalNotExistFileList = notExistFileList;
+            CompletableFuture.runAsync(() -> {
+                SceneAsynOperLog sceneAsynOperLog = new SceneAsynOperLog();
+                sceneAsynOperLog.setNum(num);
+                sceneAsynOperLog.setOperType(SceneAsynOperType.UPLOAD.code());
+                sceneAsynOperLog.setModule(SceneAsynModuleType.UPLOAD_DOWNLOAD.code());
+                sceneAsynOperLog.setFunc(SceneAsynFuncType.PANORAMIC_IMAGE.code());
+                if(CollUtil.isNotEmpty(finalNotExistFileList)){
+                    Map<String, Object> extData = new HashMap<>();
+                    extData.put("successCnt", finalUploadFileList.size());
+                    extData.put("failList", finalNotExistFileList);
+                    sceneAsynOperLog.setExtData(JSON.toJSONString(extData));
+                }
+                sceneAsynOperLogService.save(sceneAsynOperLog);
+                try {
+                    this.uploadPanoramaHandler(num,bucket,target,imgViewPath, finalUploadFileList,targetImagesPath);
+                    sceneAsynOperLog.setState(CommonOperStatus.SUCCESS.code());
+                } catch (Exception e) {
+                    log.error("上传全景图报错,num:" + num, e);
+                    sceneAsynOperLog.setState(CommonOperStatus.FAILD.code());
+                }
+                sceneAsynOperLogService.updateById(sceneAsynOperLog);
+            });
+        }else{
+            this.uploadPanoramaHandler(num,bucket,target,imgViewPath,uploadFileList,targetImagesPath);
+            if(CollUtil.isNotEmpty(notExistFileList)){
+                uploadPanoramaVO.setSuccessCnt(uploadFileList.size());
+                uploadPanoramaVO.setFailList(notExistFileList);
+            }
+        }
+        return ResultData.ok(uploadPanoramaVO);
+    }
+
+    private void checkSceneAsynOper(String num, String operType, String module, String function){
+        LambdaQueryWrapper<SceneAsynOperLog> queryWrapper =
+            new LambdaQueryWrapper<SceneAsynOperLog>()
+                .eq(SceneAsynOperLog::getNum,num)
+                .eq(SceneAsynOperLog::getState, CommonOperStatus.WAITING.code());
+        if(StrUtil.isNotEmpty(operType)){
+            queryWrapper.eq(SceneAsynOperLog::getOperType, operType);
+        }
+        if(StrUtil.isNotEmpty(module)){
+            queryWrapper.eq(SceneAsynOperLog::getModule, module);
+        }
+        if(StrUtil.isNotEmpty(function)){
+            queryWrapper.eq(SceneAsynOperLog::getFunc, function);
+        }
+        List<SceneAsynOperLog> waittingLogList = sceneAsynOperLogService.list(queryWrapper);
+        if(CollUtil.isNotEmpty(waittingLogList)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5066);
+        }
+    }
+
+    public void uploadPanoramaHandler(String num, String bucket, String target, String imgViewPath, List<String> uploadFileList, String targetImagesPath) throws Exception {
         CreateObjUtil.build3dModel(target , "1");
 
         String uploadJsonPath= target + File.separator + "results" +File.separator+"upload.json";
@@ -1084,6 +1224,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         if(array == null){
             throw new BusinessException(ErrorCode.FAILURE_CODE_7013);
         }
+        Map<String, String> map = new HashMap<>();
         JSONObject fileJson = null;
         String fileName = "";
         for(int i = 0, len = array.size(); i < len; i++) {
@@ -1123,31 +1264,23 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
                 continue;
             }
         }
-        if(map.size()>0) {
-            fYunFileService.uploadMulFiles(bucket, map);
-        }
 
-        //拷贝修改后的全景图到缓存目录
-        String cachedImagesPath = String.format(ConstantFilePath.SCENE_CACHE_IMAGES, num);
+        //用户上传的全景图上传到ossresult目录
+        String ossCachesImagesPath = String.format(UploadFilePath.scene_result_data_path, num) + "caches/images/";
         uploadFileList.stream().forEach(srcPath->{
-            cn.hutool.core.io.FileUtil.copy(srcPath, srcPath.replace(targetImagesPath, cachedImagesPath), true);
+            map.put(srcPath, srcPath.replace(targetImagesPath, ossCachesImagesPath));
         });
 
+        if(map.size()>0) {
+            fYunFileService.uploadMulFiles(bucket, map);
+        }
+
         //更新数据库版本号
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
         SceneEditInfo sceneEditInfo = this.getByScenePlusId(scenePlus.getId());
         this.upgradeVersionAndImgVersionById(sceneEditInfo.getId());
         //更新scenejson缓存和oss文件版本号
         this.upgradeSceneJsonVersion(num, sceneEditInfo.getVersion() + 1, sceneEditInfo.getImgVersion() + 1, bucket);
-
-        //如果部分成功,则需要返回成功数量和失败列表
-        if(CollUtil.isNotEmpty(notExistFileList)){
-            notExistFileList = notExistFileList.stream().map(filePath -> {
-                return filePath.substring(filePath.lastIndexOf(File.separator) + 1);
-            }).collect(Collectors.toList());
-            return ResultData.ok(new UploadPanoramaVO(uploadFileList.size(), notExistFileList));
-        }
-
-        return ResultData.ok();
     }
 
 
@@ -1162,6 +1295,10 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         if(Objects.isNull(scenePlus)){
             throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
         }
+
+        //查询是否存在等待中的异步操作记录,如果存在,抛出业务异常,终止操作
+        this.checkSceneAsynOper(num,null, SceneAsynModuleType.UPLOAD_DOWNLOAD.code() , SceneAsynFuncType.PANORAMIC_IMAGE.code());
+
         ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
         String bucket = scenePlusExt.getYunFileBucket();
         String path = scenePlusExt.getDataSource();
@@ -1174,47 +1311,96 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         String cacheImageFormat = "downloads/scene/%s/caches/images/";
 
         //判断全景图缓存是否存在,如果不存在,从计算目录中拷贝到缓存目录
-        this.cachePanorama(scenePlusExt.getDataSource(), num);
+//        this.cachePanorama(scenePlusExt.getDataSource(), num);
+
+        //根据vision.txt获取到有效的全景图名称
+        String ossVisionPath = String.format(UploadFilePath.IMG_VIEW_PATH, num) + "vision.txt";
+        String visionPath = String.format(ConstantFilePath.SCENE_DATA_PATH_V4, num) + "vision.txt";
+        fYunFileService.downloadFile(ossVisionPath, visionPath);
+        List<String> panoramaImageList = SceneUtil.getPanoramaImageList(visionPath);
+        if(CollUtil.isEmpty(panoramaImageList)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5063);
+        }
+
+        Map<String, Object> map = new HashMap<>();
 
-        String url = null;
-        String downloadName = null;
+        //标记是否是异步操作,默认是同步操作
         //如果入参文件名不为空,则是单个文件下载,不需要打包
+        String ossResultPath = String.format(UploadFilePath.scene_result_data_path, num) + "caches/images/";
         if(StrUtil.isNotEmpty(fileName)){
             //如果是单张图片,直接提供oss url
-            String localFilePath = localImagesPath + fileName;
-            String ossFilePath = imgCachePath + fileName;
-            if(!cn.hutool.core.io.FileUtil.exist(localFilePath)){
+//            if(!fYunFileService.fileExist(bucket, ossResultPath + fileName)){
+//                throw new BusinessException(ErrorCode.FAILURE_CODE_5063);
+//            }
+            if(!panoramaImageList.contains(fileName)){
                 throw new BusinessException(ErrorCode.FAILURE_CODE_5063);
             }
-            fYunFileService.uploadFile(bucket, localFilePath, ossFilePath);
-            url = ossUrlPrefix + ossFilePath;
-            downloadName = fileName;
+            String url = ossUrlPrefix + ossResultPath + fileName;
+            String downloadName = fileName;
+            map.put("asyn", CommonStatus.NO.code());
+            map.put("fileUrl", url + "?t=" + System.currentTimeMillis());
+            map.put("fileName", downloadName);
+            return ResultData.ok(map);
         }else{
-            if(!cn.hutool.core.io.FileUtil.exist(localImagesPath)
-                || cn.hutool.core.io.FileUtil.isDirEmpty(new File(localImagesPath))){
-                throw new BusinessException(ErrorCode.FAILURE_CODE_5063);
-            }
+            //清除旧的下载记录
+            sceneAsynOperLogService.remove(
+                new LambdaQueryWrapper<SceneAsynOperLog>()
+                    .eq(SceneAsynOperLog::getNum, num)
+                    .eq(SceneAsynOperLog::getOperType, SceneAsynOperType.DOWNLOAD.code())
+                    .eq(SceneAsynOperLog::getModule, SceneAsynModuleType.UPLOAD_DOWNLOAD.code())
+                    .eq(SceneAsynOperLog::getFunc, SceneAsynFuncType.PANORAMIC_IMAGE.code()));
+
+            //开始异步执行下载全景图压缩包操作
+            CompletableFuture.runAsync(() -> {
+                SceneEditInfo sceneEditInfo = this.getByScenePlusId(scenePlus.getId());
+                SceneAsynOperLog sceneAsynOperLog = new SceneAsynOperLog();
+                sceneAsynOperLog.setNum(num);
+                sceneAsynOperLog.setOperType(SceneAsynOperType.DOWNLOAD.code());
+                sceneAsynOperLog.setModule(SceneAsynModuleType.UPLOAD_DOWNLOAD.code());
+                sceneAsynOperLog.setFunc(SceneAsynFuncType.PANORAMIC_IMAGE.code());
+                sceneAsynOperLog.setVersion(sceneEditInfo.getImgVersion());
+                sceneAsynOperLogService.save(sceneAsynOperLog);
+                try {
+
+                    //下载到本地目录
+                    FileUtil.del(localImagesPath);
+                    fYunFileService.downloadFileByCommand(bucket, localImagesPath, ossResultPath);
+                    //移除非必须文件
+                    List<String> fileNames = FileUtil.listFileNames(localImagesPath);
+                    fileNames.stream().forEach(name->{
+                        if(!panoramaImageList.contains(name)){
+                            FileUtil.del(localImagesPath + name);
+                        }
+                    });
+
+                    String downloadName = num + "_images.zip";
+                    long start = Calendar.getInstance().getTimeInMillis();
+                    //打包
+                    String zipPath = cachePath + downloadName;
+                    ZipUtil.zip(localImagesPath, zipPath);
+                    long end1 = Calendar.getInstance().getTimeInMillis();
+                    log.info("打包耗时:" + (end1 - start));
+                    //上传压缩包
+                    fYunFileService.uploadFileByCommand(bucket, zipPath, String.format(cacheFormat, num) + downloadName);
+                    String url = String.format(cacheFormat, num) + downloadName;
+                    long end2 = Calendar.getInstance().getTimeInMillis();
+                    log.info("上传耗时:" + (end2 - end1));
+                    //删除本地压缩包
+                    FileUtils.deleteFile(zipPath);
+                    //删除本地目录
+                    FileUtils.deleteDirectory(localImagesPath);
+                    sceneAsynOperLog.setState(CommonOperStatus.SUCCESS.code());
+                    sceneAsynOperLog.setUrl(url);
+                }catch (Exception e){
+                    sceneAsynOperLog.setState(CommonOperStatus.FAILD.code());
+                    log.error("下载全景图压缩包失败,num:" + num, e);
+                }
+                sceneAsynOperLogService.saveOrUpdate(sceneAsynOperLog);
+            });
 
-            downloadName = num + "_images.zip";
-            long start = Calendar.getInstance().getTimeInMillis();
-            //打包
-            String zipPath = cachePath + downloadName;
-            ZipUtil.zip(localImagesPath, zipPath);
-            long end1 = Calendar.getInstance().getTimeInMillis();
-            log.info("打包耗时:" + (end1 - start));
-            //上传压缩包
-            fYunFileService.uploadFileByCommand(bucket, zipPath, String.format(cacheFormat, num) + downloadName);
-            url = ossUrlPrefix + String.format(cacheFormat, num) + downloadName;
-            long end2 = Calendar.getInstance().getTimeInMillis();
-            log.info("上传耗时:" + (end2 - end1));
-            //删除本地压缩包
-//            FileUtils.deleteFile(zipPath);
+            map.put("asyn", CommonStatus.YES.code());
+            return ResultData.ok(map);
         }
-
-        Map<String, Object> map = new HashMap<>();
-        map.put("fileUrl", url + "?t=" + System.currentTimeMillis());
-        map.put("fileName", downloadName);
-        return ResultData.ok(map);
     }
 
     private void cachePanorama(String dataSource, String num){
@@ -1425,8 +1611,8 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
             fYunFileService.uploadFile(bucket, target + File.separator + "extras/video/" + videoName.replace("mp4", "flv"),videosViewPath + videoName.replace("mp4", "flv"));
 
             //覆盖原始视频资源
-            FileUtils.copyFile(target + File.separator + "extras/video/" + videoName,
-                path + File.separator + "caches/videos/" + videoName, true);
+//            FileUtils.copyFile(target + File.separator + "extras/video/" + videoName,
+//                path + File.separator + "caches/videos/" + videoName, true);
 
         }
         FileUtils.deleteDirectory(target + File.separator + "extras/video/");
@@ -1498,15 +1684,20 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
             if(new File(target + File.separator + "results").exists()){
                 FileUtils.delAllFile(target + File.separator + "results");
             }
+
             //创建文件夹,并link文件夹
             new File(target + File.separator + "caches").mkdirs();
-            CreateObjUtil.createSoftConnection(path + File.separator + "capture", target + File.separator + "capture");
+            fYunFileService.downloadFileByCommand(target + File.separator + "capture", SceneUtil.getHomePath(path));
+//            CreateObjUtil.createSoftConnection(path + File.separator + "capture", target + File.separator + "capture");
             if(new File(path + File.separator + "caches" + File.separator + "images").exists()){
                 CreateObjUtil.createSoftConnection(path + File.separator + "caches" + File.separator + "images", target + File.separator + "caches" + File.separator + "images");
             }
 
-            FileUtils.copyFile(path + File.separator + "data.json", target + File.separator+"data.json", true);
-            FileUtils.copyFile(path + File.separator + "project.json", target + File.separator+"project.json", true);
+            String ossResultPath = String.format(UploadFilePath.scene_result_data_path, num);
+            fYunFileService.downloadFile(bucket, ossResultPath + "data.json", target + File.separator+"data.json");
+            fYunFileService.downloadFile(bucket, ossResultPath + "project.json", target + File.separator+"project.json");
+//            FileUtils.copyFile(path + File.separator + "data.json", target + File.separator+"data.json", true);
+//            FileUtils.copyFile(path + File.separator + "project.json", target + File.separator+"project.json", true);
 
             //data.json增加extras为执行重建算法
             String project = FileUtils.readFile(target + File.separator+"project.json");
@@ -1779,7 +1970,6 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
         String bucket = scenePlusExt.getYunFileBucket();
 
-        String localDataPath = String.format(ConstantFilePath.DATABUFFER_FORMAT, num);
         String localImagesPath = String.format(ConstantFilePath.IMAGESBUFFER_FORMAT, num);
         String path = scenePlusExt.getDataSource();
         String target = localImagesPath + "panorama/" + sid;
@@ -1794,8 +1984,9 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         file.transferTo(targetFile);
 
         //调用算法切全景图
-        FileUtils.copyFile(path + File.separator + "data.json", target + File.separator+"data.json", true);
-        FileUtils.copyFile(path + File.separator + "project.json", target + File.separator+"project.json", true);
+        String ossResultPath = String.format(UploadFilePath.scene_result_data_path, num);
+        fYunFileService.downloadFile(bucket, ossResultPath + "data.json", target + File.separator+"data.json");
+        fYunFileService.downloadFile(bucket, ossResultPath + "project.json", target + File.separator+"project.json");
         JSONObject visionJson = new JSONObject();
         JSONArray visionArray = new JSONArray();
         visionJson.put("uuid", sid);
@@ -1804,9 +1995,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         visionArray.add(visionJson);
         JSONObject vision = new JSONObject();
         vision.put("sweepLocations", visionArray);
-        cn.hutool.core.io.FileUtil.writeString(vision.toString(),
-            target + "/extras" + File.separator + "vision.txt",
-            StandardCharsets.UTF_8);
+        cn.hutool.core.io.FileUtil.writeString(vision.toString(), target + "/extras" + File.separator + "vision.txt", StandardCharsets.UTF_8);
 
         //data.json增加extras为执行重建算法
         String type = "4k";
@@ -1834,8 +2023,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
             }
             dataJson.put("skybox_type", skyboxType);
 
-            cn.hutool.core.io.FileUtil.writeString(dataJson.toString(),
-                target + File.separator+"data.json", StandardCharsets.UTF_8);
+            cn.hutool.core.io.FileUtil.writeString(dataJson.toString(), target + File.separator+"data.json", StandardCharsets.UTF_8);
         }
 
         //创建文件夹软连接并且复制data.json和project.json
@@ -1850,10 +2038,6 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
             cn.hutool.core.io.FileUtil.del(resultPath);
         }
         //下载data.fdage
-        if(FYunTypeEnum.AWS.code().equals(this.fyunType)){
-            //亚马逊保持旧方式,超链接capture
-            CreateObjUtil.createSoftConnection(path + File.separator + "capture", capturePath);
-        }
         fYunFileService.downloadFile(ConstantFilePath.OSS_PREFIX + path.replace(ConstantFilePath.BUILD_MODEL_PATH, "") + "/data.fdage", capturePath + "/data.fdage");
         CreateObjUtil.build3dModel(target , "1");
 
@@ -1917,7 +2101,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
     }
 
     @Override
-    public ResultData deleteStyles(DeleteLinkSceneStylesParamVO param) throws Exception {
+    public ResultData deleteStyles(DeleteStylesParamVO param) throws Exception {
         ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
         if (scenePlus == null)
             throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
@@ -1983,14 +2167,19 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         List<String> deletDataList = redisUtil.hMultiGet(key, deleteSidList);
         if(CollUtil.isEmpty(deletDataList))
             return;
+        List<String> thumbNameList = deleteSidList.stream().map(sid -> {
+            String linkPan = redisUtil.hget(key, sid);
+            JSONObject linkPanObj = JSON.parseObject(linkPan);
+            return FileUtil.getPrefix(linkPanObj.getString("thumb"));
+        }).collect(Collectors.toList());
 
         //从redis中移除热点数据
         redisUtil.hdel(key, deleteSidList.toArray());
 
         //删除oss文件
         String imgEditPath = String.format(UploadFilePath.IMG_EDIT_PATH, num);
-        deleteSidList.stream().forEach(sid->{
-            fYunFileService.deleteFolder(bucket, imgEditPath + "panorama_edit/" + sid);
+        thumbNameList.stream().forEach(thumbName->{
+            fYunFileService.deleteFolder(bucket, imgEditPath + "panorama/" + thumbName);
         });
 
     }
@@ -2600,7 +2789,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
     }
 
     @Override
-    public ResultData saveFilter(BaseDataParamVO param) throws Exception {
+    public ResultData saveFilter(SaveFiltersParamVO param) throws Exception {
 
         ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
         if(Objects.isNull(scenePlus)){
@@ -2621,11 +2810,19 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         //写本地文件,作为备份
         this.writeFilter(param.getNum());
 
+        //如果页面选择恢复默认,filters字段值为否
+        if(Objects.nonNull(param.getReset()) && param.getReset() == CommonStatus.YES.code().intValue()){
+            filters = CommonStatus.NO.code();
+        }
+
         //更新数据库
         SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId());
         sceneEditInfoExt.setFilters(filters);
         sceneEditInfoExtService.updateById(sceneEditInfoExt);
 
+        //更新版本号
+        this.upgradeVersionById(sceneEditInfoExt.getEditInfoId());
+
         return ResultData.ok();
 
     }

+ 24 - 3
src/main/java/com/fdkankan/scene/service/impl/SceneEditServiceImpl.java

@@ -11,6 +11,7 @@ import com.fdkankan.common.constant.CommonStatus;
 import com.fdkankan.common.constant.ErrorCode;
 import com.fdkankan.model.constants.UploadFilePath;
 import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.scene.httpclient.MyClient;
 import com.fdkankan.web.response.ResultData;
 import com.fdkankan.common.util.DateExtUtil;
 import com.fdkankan.fyun.face.FYunFileServiceInterface;
@@ -67,6 +68,12 @@ import org.springframework.util.ObjectUtils;
 @RefreshScope
 public class SceneEditServiceImpl implements ISceneEditService {
 
+    @Value("${4dkk.manageService.basePath}")
+    private String manageServiceUrl;
+
+    @Value("${4dkk.manageService.api.getServiceUpTip}")
+    private String getServiceUpTipApi;
+
     @Autowired
     ISceneProService sceneProService;
     @Autowired
@@ -97,6 +104,9 @@ public class SceneEditServiceImpl implements ISceneEditService {
     @Value("${scene.expired.month:#{null}}")
     private Integer expiredMonth;
 
+    @Autowired
+    private MyClient myClient;
+
     @Override
     public SceneAuthVO getAuth(String num, SSOUser ssoUser){
 
@@ -121,9 +131,9 @@ public class SceneEditServiceImpl implements ISceneEditService {
         sceneAuthVO.setInclude(new ArrayList<>());
         sceneAuthVO.setCompany(null);
 
-        //判断本地资源是否已本删除,如果已删除,前端根据字段值为true提示用户不能使用某些功能,需要重算
-        Date algorithmTime = scenePlusExt.getAlgorithmTime() == null ? scenePlus.getCreateTime() : scenePlusExt.getAlgorithmTime();
-        if (!ObjectUtils.isEmpty(expiredMonth) && com.fdkankan.common.util.DateUtil.delay(algorithmTime, expiredMonth, Calendar.MONTH).before(new Date())) {
+        //判断data.json是否存在,如果存在,则证明计算在未被定时任务删除前上传过oss
+        boolean exist = fYunFileService.fileExist(String.format(UploadFilePath.scene_result_data_path, num).concat("data.json"));
+        if(!exist){
             sceneAuthVO.setSourceExpired(true);
         }
 
@@ -309,4 +319,15 @@ public class SceneEditServiceImpl implements ISceneEditService {
         return ResultData.ok();
     }
 
+    @Override
+    public ResultData getServiceUpTip() {
+        try {
+            String url = this.manageServiceUrl.concat(this.getServiceUpTipApi);
+            String params = "type=" + 0;
+            ResultData resultData = myClient.get(url, params);
+            return ResultData.ok(resultData.getData());
+        }catch (Exception e){
+            return ResultData.ok();
+        }
+    }
 }

+ 181 - 0
src/main/java/com/fdkankan/scene/service/impl/SceneMarkShapeServiceImpl.java

@@ -0,0 +1,181 @@
+package com.fdkankan.scene.service.impl;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.lang.UUID;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.model.constants.ConstantFilePath;
+import com.fdkankan.rabbitmq.util.RabbitMqProducer;
+import com.fdkankan.scene.entity.SceneMarkShape;
+import com.fdkankan.scene.mapper.MarkShapeMapper;
+import com.fdkankan.scene.service.ISceneMarkShapeService;
+import com.fdkankan.scene.util.ConverxyUtil;
+import com.fdkankan.scene.vo.SceneMarkShapeParamVO;
+import com.fdkankan.scene.vo.SceneMarkShapeReDetectParamVO;
+import com.fdkankan.web.response.ResultData;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * Created by Xiewj on 2021/11/23 0026 10:14
+ */
+@Slf4j
+@Service
+public class SceneMarkShapeServiceImpl extends ServiceImpl<MarkShapeMapper, SceneMarkShape> implements ISceneMarkShapeService {
+    @Autowired
+    private RabbitMqProducer rabbitMqProducer;
+    @Value("${queue.scene.yolov5-train-queue}")
+    private String yolov5TrainQueue;
+    @Value("${main.url}")
+    private String mainUrl;
+
+    @Override
+    public void editTrainStatus(SceneMarkShapeParamVO param) {
+        SceneMarkShape byNumAndImagePath = findByNumAndImagePath(param.getNum(), param.getImagePath());
+        if (ObjectUtil.isNotNull(byNumAndImagePath)){
+            byNumAndImagePath.setReTrain(0);
+            byNumAndImagePath.setToTrain(1);
+            updateById(byNumAndImagePath);
+        }
+    }
+
+    @Override
+    public List<SceneMarkShape> findByReTrainStatus(Integer reTrain){
+        LambdaQueryWrapper<SceneMarkShape> wrapper = Wrappers.lambdaQuery();
+        wrapper.eq(SceneMarkShape::getReTrain,reTrain);
+        return list(wrapper);
+    }
+
+    @Override
+    public List<SceneMarkShape> findByToTrainStatus(Integer toTrain) {
+        QueryWrapper queryWrapper = new QueryWrapper();
+        queryWrapper.select("DISTINCT num")
+                .eq("to_train",toTrain) ;
+        return getBaseMapper().selectList(queryWrapper);
+    }
+
+    @Override
+    public void trainScene(SceneMarkShapeReDetectParamVO param) {
+        //查询需要重新训练的图片
+        List<SceneMarkShape> reDetectStatuList = findByReTrainStatus(1);
+        for (SceneMarkShape shape : reDetectStatuList) {
+            SceneMarkShapeReDetectParamVO paramVO=new SceneMarkShapeReDetectParamVO();
+            paramVO.setWebSite(mainUrl);
+            if (StrUtil.isNotEmpty(param.getSaveDir())){
+                paramVO.setSaveDir(param.getSaveDir());
+            }
+            paramVO.setNum(shape.getNum());
+            paramVO.setImagePath(shape.getImagePath());
+            paramVO.setDetectType(1);
+            rabbitMqProducer.sendByWorkQueue(yolov5TrainQueue,paramVO);
+        }
+        //查询需要进入训练的场景
+        List<SceneMarkShape> byToDetectStatus = findByToTrainStatus(0);
+        for (SceneMarkShape shape : byToDetectStatus) {
+            SceneMarkShapeReDetectParamVO paramVO=new SceneMarkShapeReDetectParamVO();
+            paramVO.setWebSite(mainUrl);
+            if (StrUtil.isNotEmpty(param.getSaveDir())){
+                paramVO.setSaveDir(param.getSaveDir());
+            }
+            paramVO.setNum(shape.getNum());
+            paramVO.setDetectType(2);
+            rabbitMqProducer.sendByWorkQueue(yolov5TrainQueue,paramVO);
+        }
+    }
+
+    @Override
+    public ResultData editLabelByFile(String num, String imgPath, MultipartFile file) throws IOException {
+
+        SceneMarkShape shape = findByNumAndImagePath(num, imgPath);
+        if (ObjectUtil.isNotNull(shape)){
+            String uuid = UUID.randomUUID().toString();
+            String fileName = file.getOriginalFilename();
+            String extName = FileUtil.extName(fileName);
+            String tempFileName = uuid + "." + extName;
+            String srcPath = ConstantFilePath.SCENE_V4_PATH + num + "/markShapes/" + tempFileName;
+            File tempFile = new File(srcPath);
+            if(!tempFile.getParentFile().exists()){
+                tempFile.getParentFile().mkdirs();
+            }
+            file.transferTo(tempFile);
+
+            List<String> s = FileUtil.readUtf8Lines(tempFile);
+            List<JSONObject> shapeJsons=new ArrayList<>();
+            //转换labelimg标注处理的结果
+            log.info("转换labelimg标注处理的结果开始");
+            for (String s1 : s) {
+                int[] ints = ConverxyUtil.centerWh2xyxy(s1, 4096,2048);
+                String[] s2 = s1.split(" ");
+                JSONObject shapeJson=new JSONObject();
+                shapeJson.put("bbox",ints);
+                shapeJson.put("color",ConverxyUtil.getColor(s2[0]));
+                shapeJson.put("label",s1);
+                shapeJson.put("category",ConverxyUtil.getLabelVal(s2[0]));
+                shapeJson.put("score",0);
+                shapeJsons.add(shapeJson);
+            }
+            log.info("转换labelimg标注处理的结果结束,{}",shapeJsons);
+            shape.setShapes(shapeJsons);
+            shape.setReTrain(1);
+            shape.setUpdateTime(new Date());
+            updateById(shape);
+            return ResultData.ok(shape);
+        }else {
+            return ResultData.error(ErrorCode.NOT_RECORD);
+        }
+    }
+
+    @Override
+    public SceneMarkShape findByNumAndImagePath(String num, String imagePath) {
+        LambdaQueryWrapper<SceneMarkShape> wrapper = Wrappers.lambdaQuery();
+        wrapper.eq(SceneMarkShape::getNum,num);
+        wrapper.eq(SceneMarkShape::getImagePath,imagePath);
+        return getOne(wrapper);
+    }
+
+    @Override
+    public void saveFileToDB(MultipartFile file, String num) throws IOException {
+        String uuid = UUID.randomUUID().toString();
+        String fileName = file.getOriginalFilename();
+        String extName = cn.hutool.core.io.FileUtil.extName(fileName);
+        String tempFileName = uuid + "." + extName;
+        String srcPath = ConstantFilePath.SCENE_V4_PATH + num + "/markShapes/" + tempFileName;
+        File tempFile = new File(srcPath);
+        if(!tempFile.getParentFile().exists()){
+            tempFile.getParentFile().mkdirs();
+        }
+        file.transferTo(tempFile);
+        String s = FileUtil.readUtf8String(tempFile);
+        JSONObject jsonObject = JSONObject.parseObject(s);
+        tempFile.delete();
+        SceneMarkShape sceneMarkShape= JSON.toJavaObject(jsonObject,SceneMarkShape.class);
+        sceneMarkShape.setNum(num);
+        SceneMarkShape shape = findByNumAndImagePath(sceneMarkShape.getNum(), sceneMarkShape.getImagePath());
+        if (ObjectUtil.isNotNull(shape)){
+            log.info("shape-替换id修改---{}",sceneMarkShape);
+            sceneMarkShape.setId(shape.getId());
+            updateById(sceneMarkShape);
+        }else {
+            log.info("新增-替换id修改---{}",sceneMarkShape);
+            log.info("MarkShapeMapper---{}",sceneMarkShape);
+            save(sceneMarkShape);
+        }
+    }
+}

+ 36 - 5
src/main/java/com/fdkankan/scene/service/impl/ScenePlusServiceImpl.java

@@ -1,6 +1,8 @@
 package com.fdkankan.scene.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.date.DateField;
+import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.extra.qrcode.QrCodeUtil;
@@ -15,6 +17,7 @@ import com.fdkankan.common.exception.BusinessException;
 import com.fdkankan.fyun.face.FYunFileServiceInterface;
 import com.fdkankan.model.constants.ConstantFilePath;
 import com.fdkankan.model.constants.UploadFilePath;
+import com.fdkankan.scene.bean.SceneBean;
 import com.fdkankan.scene.entity.SceneEditInfoExt;
 import com.fdkankan.scene.entity.ScenePro;
 import com.fdkankan.scene.service.ISceneEditInfoExtService;
@@ -37,9 +40,8 @@ import com.fdkankan.scene.vo.BaseSceneParamVO;
 import com.fdkankan.scene.vo.SceneCheckKeyParamVO;
 import com.fdkankan.scene.vo.SceneDataDownloadVO;
 import java.io.File;
-import java.util.List;
-import java.util.Objects;
-import java.util.UUID;
+import java.util.*;
+
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -222,8 +224,8 @@ public class ScenePlusServiceImpl extends ServiceImpl<IScenePlusMapper, ScenePlu
         String outPathEn = ConstantFilePath.BASE_PATH + File.separator + "sceneQRcode/"+num+"_en.png";
 
         String webSize = "/" + sceneProNewUrl + num;
-        QrCodeUtil.generate(webSize, QrConfig.create().setImg(logoPath), FileUtil.file(outPathZh));
-        QrCodeUtil.generate(webSize + "&lang=en", QrConfig.create().setImg(logoPath), FileUtil.file(outPathEn));
+        QrCodeUtil.generate(webSize, QrConfig.create().setImg(logoPath).setWidth(1024).setHeight(1024), FileUtil.file(outPathZh));
+        QrCodeUtil.generate(webSize + "&lang=en", QrConfig.create().setImg(logoPath).setWidth(1024).setHeight(1024), FileUtil.file(outPathEn));
         //上传logo图片
         String ossLogoPath = String.format(UploadFilePath.DOWNLOADS_QRCODE, num) + "shareLogo" + extName;
         fYunFileService.uploadFile(scenePlusExt.getYunFileBucket(), logoPath, ossLogoPath);
@@ -242,4 +244,33 @@ public class ScenePlusServiceImpl extends ServiceImpl<IScenePlusMapper, ScenePlu
 
         return ResultData.ok();
     }
+
+    @Override
+    public List<SceneBean> listCleanOrigScene(int cleanOrigMonth) {
+        Date time = Calendar.getInstance().getTime();
+        time = DateUtil.beginOfDay(DateUtil.offset(time, DateField.MONTH, -cleanOrigMonth));
+        return this.baseMapper.selectCleanOrigScene(time);
+    }
+
+    @Override
+    public List<SceneBean> listCleanOss4DeletedScene(int month) {
+        Date time = Calendar.getInstance().getTime();
+        time = DateUtil.beginOfDay(DateUtil.offset(time, DateField.MONTH, -month));
+        return this.baseMapper.selectCleanOrigSceneDeleted(time);
+    }
+
+    @Override
+    public List<SceneBean> listCleanOss4TestCamera(Set<Long> cameraIds, int month) {
+        Date time = Calendar.getInstance().getTime();
+        time = DateUtil.beginOfDay(DateUtil.offset(time, DateField.MONTH, -month));
+        return this.baseMapper.listCleanOss4TestCamera(cameraIds, time);
+
+    }
+
+    @Override
+    public List<SceneBean> listColdStorageScene(int cleanOrigMonth) {
+        Date time = Calendar.getInstance().getTime();
+        time = DateUtil.beginOfDay(DateUtil.offset(time, DateField.MONTH, -cleanOrigMonth));
+        return this.baseMapper.selectColdStorageScene(time);
+    }
 }

+ 282 - 136
src/main/java/com/fdkankan/scene/service/impl/SceneProServiceImpl.java

@@ -1,7 +1,10 @@
 package com.fdkankan.scene.service.impl;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DateField;
+import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.RuntimeUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.ZipUtil;
 import com.alibaba.fastjson.JSON;
@@ -10,14 +13,12 @@ import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.fdkankan.common.constant.CommonStatus;
+import com.fdkankan.common.constant.*;
 import com.fdkankan.model.constants.ConstantFileName;
 import com.fdkankan.model.constants.ConstantFilePath;
-import com.fdkankan.common.constant.ErrorCode;
-import com.fdkankan.common.constant.FileBizType;
-import com.fdkankan.common.constant.ServerCode;
 import com.fdkankan.model.constants.UploadFilePath;
 import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.scene.bean.SceneBean;
 import com.fdkankan.web.response.ResultData;
 import com.fdkankan.model.utils.ComputerUtil;
 import com.fdkankan.model.utils.ConvertUtils;
@@ -56,15 +57,9 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import java.io.File;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
 import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Set;
 import java.util.stream.Collectors;
 import lombok.extern.slf4j.Slf4j;
 import org.redisson.Redisson;
@@ -199,11 +194,15 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
         if (scenePlus == null)
             throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
         ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
+        String bucket = scenePlusExt.getYunFileBucket();
 
         List<String> deleteSidList = param.getSidList();
 
         //处理删除状态数据
-        this.deleteHotData(param.getNum(), deleteSidList, scenePlusExt.getYunFileBucket());
+        this.deleteHotData(param.getNum(), deleteSidList, bucket);
+
+        //删除导览中的热点数据
+        this.deleteHotDataFromTourJson(param.getNum(), param.getSidList(), bucket);
 
         //写入本地文件,作为备份
         this.writeHotJson(param.getNum());
@@ -216,6 +215,31 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
         return ResultData.ok();
     }
 
+    private void deleteHotDataFromTourJson(String num, List<String> sidList, String bucket){
+        String key = String.format(UploadFilePath.USER_EDIT_PATH, num) + "tour.json";
+        String tourJson = fYunFileService.getFileContent(bucket, key);
+        if(StrUtil.isEmpty(tourJson)){
+            return;
+        }
+        JSONArray jsonArray = JSON.parseArray(tourJson);
+        if(CollUtil.isEmpty(jsonArray)){
+            return;
+        }
+        jsonArray.stream().forEach(tour->{
+            JSONObject obj = (JSONObject) tour;
+            JSONArray itemArra = obj.getJSONArray("list");
+            itemArra.stream().forEach(item->{
+                JSONObject itemObj = (JSONObject) item;
+                String tagId = itemObj.getString("tagId");
+                if(tagId != null && sidList.contains(tagId)){
+                    itemObj.remove("tagId");
+                }
+            });
+        });
+        fYunFileService.uploadFile(bucket, jsonArray.toJSONString().getBytes(StandardCharsets.UTF_8), key);
+
+    }
+
     @Override
     public ResultData deleteIcons(DeleteHotIconParamVO param) throws Exception {
 
@@ -628,14 +652,11 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
             editInfo.setScenePlusId(scenePlus.getId());
             sceneEditInfoService.save(editInfo);
         }else{
-            sceneEditInfoService.upgradeVersionById(editInfo.getId());
+            sceneEditInfoService.upgradeVersionAndImgVersionById(editInfo.getId());
             //更新scenejson缓存和oss文件版本号
-            sceneEditInfoService.upgradeSceneJsonVersion(param.getNum(), editInfo.getVersion() + 1, null, bucket);
+            sceneEditInfoService.upgradeSceneJsonVersion(param.getNum(), editInfo.getVersion() + 1, editInfo.getImgVersion() + 1, bucket);
         }
 
-        //更新scene.json版本号
-//        sceneEditInfoService.upgradeVersionToSceneJson(param.getNum());
-
         return ResultData.ok();
     }
 
@@ -662,29 +683,12 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
         ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
         String bucket = scenePlusExt.getYunFileBucket();
 
-        //文件上传的位置可以自定义
-        String path = scenePlusExt.getDataSource() + "_obj2txt";
-        String zipPath = path + "/zip/";
-        String filePath =  path + "/extras/";
-        String resultPath = path + "/results/";
-
-        //压缩文件处理:解压缩,解压缩后复制等操作
-        this.objAndImgFileHandler(resultPath, filePath, zipPath, file);
-
-        //创建data.json
-        this.writeDataJson(path);
-
-        //调用算法,不同的类型调用不同的算法
-        if("V2".equals(scenePlusExt.getBuildType())){
-            CreateObjUtil.objToTxt(path , "1");
-        }
-        if("V3".equals(scenePlusExt.getBuildType())){
-            CreateObjUtil.build3dModel(path , "1");
+        if(ModelKind.THREE_D_TILE.code().equals(scenePlusExt.getModelKind())){
+            this.buildModel43dtiles(num, bucket, scenePlusExt.getDataSource(), file);
+        }else{
+            this.buildModel4Dam(num, bucket, scenePlusExt.getDataSource(), scenePlusExt.getBuildType(), file);
         }
 
-        //算法计算完后,生成压缩文件,上传到oss
-        this.uploadFileofterRebuildPanoram(path, num, bucket);
-
         //更新版本信息
         SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
         if(Objects.isNull(sceneEditInfo)){
@@ -704,12 +708,144 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
                     .set(SceneEditInfo::getIsUploadObj, CommonStatus.YES.code())
                     .eq(SceneEditInfo::getId, sceneEditInfo.getId()));
 
-            sceneEditInfoService.upgradeSceneJsonVersion(num, sceneEditInfo.getVersion() + 1, sceneEditInfo.getImgVersion() + 1, bucket);        }
+            sceneEditInfoService.upgradeSceneJsonVersion(num, sceneEditInfo.getVersion() + 1, sceneEditInfo.getImgVersion() + 1, bucket);
+        }
 
         return ResultData.ok();
     }
 
-    private void uploadFileofterRebuildPanoram(String path, String sceneNum, String bucket) throws Exception {
+    /**
+     * 老算法(dam)上传模型逻辑
+     * @param num
+     * @param bucket
+     * @param dataSource
+     * @param buildType
+     * @throws Exception
+     */
+    private void buildModel4Dam(String num, String bucket, String dataSource, String buildType, MultipartFile file) throws Exception {
+        //文件上传的位置可以自定义
+        String path = dataSource + "_obj2txt";
+        String zipPath = path + "/zip/";
+        String filePath =  path + "/extras/";
+        String resultPath = path + "/results/";
+
+        //压缩文件处理:解压缩,解压缩后复制等操作
+        this.objAndImgFileHandler(resultPath, filePath, zipPath, file);
+
+        //创建data.json
+        this.writeDataJson(path);
+
+        //调用算法,不同的类型调用不同的算法
+        if("V2".equals(buildType)){
+            CreateObjUtil.objToTxt(path , "1");
+        }
+        if("V3".equals(buildType)){
+            CreateObjUtil.build3dModel(path , "1");
+        }
+
+        //算法计算完后,生成压缩文件,上传到oss
+        this.uploadFileofterRebuildPanoram(path, filePath, num, bucket);
+    }
+
+    /**
+     * 新算法(3dtiles)上传模型逻辑
+     * @param num
+     * @param bucket
+     * @param dataSource
+     * @throws Exception
+     */
+    private void buildModel43dtiles(String num, String bucket, String dataSource, MultipartFile file) throws Exception {
+        //文件上传的位置可以自定义
+        String path = dataSource + "_obj2Tiles" + File.separator;
+        String meshPath = path  + "mesh";
+        String zipPath = path + "zip" + File.separator;
+        String zipFilePath = zipPath + file.getOriginalFilename();
+
+
+        //压缩文件处理:解压缩,解压缩后复制等操作
+        FileUtil.del(path);
+        FileUtil.mkdir(zipPath);
+        File zipFile = new File(zipFilePath);
+        file.transferTo(zipFile);
+        ZipUtil.unzip(zipFilePath, meshPath);
+
+        //检测文件
+        String floorsJsonPath = meshPath + File.separator + "floors.json";
+        if(!FileUtil.exist(floorsJsonPath)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5068);
+        }
+        String floorsJsonStr = FileUtil.readUtf8String(floorsJsonPath);
+        JSONObject floorsJsonObj = JSON.parseObject(floorsJsonStr);
+        JSONArray floorArr = floorsJsonObj.getJSONArray("floors");
+        if(CollUtil.isEmpty(floorArr)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5069);
+        }
+        Set<String> floorNameSet = new HashSet<>();
+        floorArr.stream().forEach(item->{
+            JSONObject itemObj = (JSONObject) item;
+            //楼层目录是否存在
+            String name = itemObj.getString("name");
+            if(StrUtil.isEmpty(name) || !FileUtil.exist(meshPath + File.separator + name)){
+                throw new BusinessException(ErrorCode.FAILURE_CODE_5070);
+            }
+            //检测obj文件是否存在
+            String objPath = itemObj.getString("objPath");
+            if(StrUtil.isEmpty(objPath) || !FileUtil.exist(path + objPath)){
+                throw new BusinessException(ErrorCode.FAILURE_CODE_5070);
+            }
+            if(floorNameSet.contains(name)){
+                throw new BusinessException(ErrorCode.FAILURE_CODE_5069);
+            }
+            floorNameSet.add(name);
+        });
+
+        //读取oss上的floors.jsoon用于校验用户上传的模型楼层数是否一一对应
+        String ossFloorsJson = fYunFileService.getFileContent(bucket, String.format(UploadFilePath.DATA_VIEW_PATH, num) + "mesh/floors.json");
+        JSONObject orginFloorsJsonObj = JSON.parseObject(ossFloorsJson);
+        JSONArray orginFloorArr = orginFloorsJsonObj.getJSONArray("floors");
+        Set<String> orginFloorNameSet = orginFloorArr.stream().map(item -> {
+            JSONObject itemObj = (JSONObject) item;
+            return itemObj.getString("name");
+        }).collect(Collectors.toSet());
+        if(floorNameSet.size() != orginFloorNameSet.size()){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5070);
+        }
+        orginFloorNameSet.stream().forEach(orginName->{
+            if(!floorNameSet.contains(orginName)){
+                throw new BusinessException(ErrorCode.FAILURE_CODE_5070);
+            }
+        });
+
+
+        //调用算法
+        String command = "bash /home/ubuntu/bin/Obj2Tiles.sh " + path;
+        log.info("上传3dtiles模型开始, num:{}, targetPath:{}", num, path);
+//        RuntimeUtil.exec(command);
+        CreateObjUtil.callshell(command);
+        log.info("上传3dtiles模型结束, num:{}, targetPath:{}", num, path);
+
+        //检测计算结果
+        String tilesPath = path + "3dtiles";
+        String tilesetJsonPath = tilesPath + File.separator + "tileset.json";
+        boolean success = ComputerUtil.checkComputeCompleted(tilesetJsonPath, maxCheckTimes, waitTime);
+        if(!success){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_7013);
+        }
+
+        //删除logs
+        FileUtil.del(tilesPath + File.separator + "logs");
+
+        //算法计算完后,生成压缩文件,上传到oss
+        //上传3dtiles
+        fYunFileService.deleteFolder(bucket, String.format(UploadFilePath.IMG_VIEW_PATH, num) + "3dtiles");
+        fYunFileService.uploadFileByCommand(bucket, tilesPath, String.format(UploadFilePath.IMG_VIEW_PATH, num) + "3dtiles");
+        //上传mesh
+        fYunFileService.deleteFolder(bucket, String.format(UploadFilePath.DATA_VIEW_PATH, num) + "mesh");
+        fYunFileService.uploadFileByCommand(bucket, meshPath, String.format(UploadFilePath.DATA_VIEW_PATH, num) + "mesh");
+
+    }
+
+    private void uploadFileofterRebuildPanoram(String path, String filePath, String sceneNum, String bucket) throws Exception {
         //因为共享目录有延迟,这里循环检测算法是否计算完毕3次,每次隔五秒
         String uploadJsonPath = path + File.separator + "results" +File.separator+"upload.json";
         boolean exist = ComputerUtil.checkComputeCompleted(uploadJsonPath, maxCheckTimes, waitTime);
@@ -744,12 +880,24 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
             }
         }
 
-        CreateObjUtil.convertTxtToDam( path + File.separator + "results" +File.separator+"modeldata.txt", path + File.separator + "results" +File.separator+ ConstantFileName.modelUUID+"_50k.dam");
-        CreateObjUtil.convertDamToLzma(path + File.separator + "results");
-        CreateObjUtil.convertTxtToDam( path + File.separator + "results" +File.separator+"modeldata.txt", path + File.separator + "results" + File.separator+ConstantFileName.modelUUID+"_50k.dam");
-        map.put(path + File.separator + "results" +File.separator+ConstantFileName.modelUUID+"_50k.dam.lzma", imgViewPath +ConstantFileName.modelUUID+"_50k.dam.lzma");
+        String damPath = path + File.separator + "results" +File.separator+ ConstantFileName.modelUUID+"_50k.dam";
+        CreateObjUtil.convertTxtToDam( path + File.separator + "results" +File.separator+"modeldata.txt", damPath);
+        boolean existDam = ComputerUtil.checkComputeCompleted(damPath, 5, 2);
+        if(!existDam){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_7013);
+        }
+//        CreateObjUtil.convertDamToLzma(path + File.separator + "results");
+//        CreateObjUtil.convertTxtToDam( path + File.separator + "results" +File.separator+"modeldata.txt", path + File.separator + "results" + File.separator+ConstantFileName.modelUUID+"_50k.dam");
+//        map.put(path + File.separator + "results" +File.separator+ConstantFileName.modelUUID+"_50k.dam.lzma", imgViewPath +ConstantFileName.modelUUID+"_50k.dam.lzma");
         map.put(path + File.separator + "results" +File.separator+ConstantFileName.modelUUID+"_50k.dam", imgViewPath+ConstantFileName.modelUUID+"_50k.dam");
 
+        String ossMeshPath = String.format(UploadFilePath.DATA_VIEW_PATH, sceneNum) + "mesh";
+        //删除oss中的mesh
+        fYunFileService.deleteFolder(bucket, ossMeshPath);
+        //上传obj相关文件
+        List<String> fileNames = FileUtil.listFileNames(filePath);
+        fileNames.stream().forEach(name->map.put(filePath + name, ossMeshPath + File.separator + name));
+
         fYunFileService.uploadMulFiles(bucket, map);
     }
 
@@ -874,105 +1022,79 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
 
         SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
 
+        if(ModelKind.THREE_D_TILE.code().equals(scenePlusExt.getModelKind())){
+            return this.downloadModel43dtiles(num, bucket, scenePlusExt, sceneEditInfo);
+        }
+
+        return this.downloadModel4Dam(num, bucket);
+    }
+
+    @Override
+    public ScenePro getByNum(String num) {
+        return this.getOne(new LambdaQueryWrapper<ScenePro>().eq(ScenePro::getNum, num));
+    }
+
+    private ResultData downloadModel43dtiles(String num, String bucket, ScenePlusExt scenePlusExt, SceneEditInfo sceneEditInfo){
+
+        //下载mesh到本地
+        String meshOssPath = String.format(UploadFilePath.DATA_VIEW_PATH, num) + "mesh/";
+        String meshLocalPath = String.format(ConstantFilePath.SCENE_DATA_PATH_V4, num) + "mesh";
+        String zipName = num + "_mesh.zip";
+        String zipFilePath = String.format(ConstantFilePath.SCENE_DATA_PATH_V4, num) + zipName;
+        //下载
+        fYunFileService.downloadFileByCommand(bucket, meshLocalPath, meshOssPath);
+        //打包
+        ZipUtil.zip(meshLocalPath,zipFilePath);
+        //上传压缩包
+        fYunFileService.uploadFile(bucket, zipFilePath, "downloads/extras/" + zipName);
+        //删除本地文件
+        FileUtil.del(meshLocalPath);
+        FileUtil.del(zipFilePath);
+        String url = ossUrlPrefix + "downloads/extras/" + zipName + "?t=" + Calendar.getInstance().getTimeInMillis();
+        return ResultData.ok(url);
+    }
+
+    public static void main(String[] args) {
+
+        Date time = Calendar.getInstance().getTime();
+        time = DateUtil.beginOfDay(DateUtil.offset(time, DateField.MONTH, -12));
+        System.out.println(time);
+
+    }
+
+
+    private ResultData downloadModel4Dam(String num, String bucket){
         String localImagePath = String.format(ConstantFilePath.IMAGESBUFFER_FORMAT, num);
         if(!new File(localImagePath).exists()){
             new File(localImagePath).mkdirs();
         }
 
-
-        String newData =  scenePlusExt.getDataSource() + "_obj2txt/extras";
-        String newResultData = scenePlusExt.getDataSource() + "_obj2txt/results/upload.json";
         String zipName = num + "_extras.zip";
         String zipPath = localImagePath + zipName;
-        //如果用户上传过模型,就打包上传到oss,直接返回
-        if(CommonStatus.YES.code().equals(sceneEditInfo.getIsUploadObj())
-            && new File(newData).exists()
-            && new File(newResultData).exists()){
-            //打包
-            ZipUtil.zip(newData, zipPath);
-            //上传压缩包
-            fYunFileService.uploadFile(bucket, zipPath, "downloads/extras/" + zipName);
-            String url = ossUrlPrefix + "downloads/extras/" + zipName + "?t=" + Calendar.getInstance().getTimeInMillis();
-            return ResultData.ok(url);
-        }
-
 
-        String buildType = scenePlusExt.getBuildType();
-        if("V3".equals(buildType)){
-            String dataViewPath = String.format(UploadFilePath.DATA_VIEW_PATH, num);
-            //V3版本去oss下载2048模型
-            String meshPath =  String.format(ConstantFilePath.DATABUFFER_FORMAT, num) + "mesh";
-            FileUtils.deleteDirectory(meshPath);
-            fYunFileService.downloadFileByCommand(bucket, meshPath, dataViewPath + "mesh");
-            log.info("meshPath="+meshPath);
-            if(!new File(meshPath).exists()){
-                throw new BusinessException(ErrorCode.FAILURE_CODE_7006);
-            }
-            log.info(new File(meshPath).listFiles().toString());
-            if(new File(meshPath).listFiles().length > 0){
-                for(File file : new File(meshPath).listFiles()){
-                    if(file.isDirectory()){
-                        for (File item : file.listFiles()) {
-                            if(item.getName().endsWith(".obj") && !"output.house.obj".equals(item.getName()) &&
-                                !"mesh.obj".equals(item.getName())){
-                                item.delete();
-                            }
-                            if(item.getName().endsWith(".mtl") && !"output.house.mtl".equals(item.getName()) &&
-                                !"mesh.mtl".equals(item.getName())){
-                                item.delete();
-                            }
-                        }
-                        continue;
-                    }
-                    if(file.getName().endsWith(".obj") && !"output.house.obj".equals(file.getName()) &&
-                            !"mesh.obj".equals(file.getName())){
-                        file.delete();
+        String dataViewPath = String.format(UploadFilePath.DATA_VIEW_PATH, num);
+        //V3版本去oss下载2048模型
+        String meshPath =  String.format(ConstantFilePath.DATABUFFER_FORMAT, num) + "mesh";
+        FileUtils.deleteDirectory(meshPath);
+        fYunFileService.downloadFileByCommand(bucket, meshPath, dataViewPath + "mesh");
+        log.info("meshPath="+meshPath);
+        if(!new File(meshPath).exists() || new File(meshPath).listFiles().length < 1){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_7006);
+        }
+        for(File file : new File(meshPath).listFiles()){
+            if(file.isDirectory()){
+                for (File item : file.listFiles()) {
+                    if(item.getName().endsWith(".obj") && !"output.house.obj".equals(item.getName()) &&
+                            !"mesh.obj".equals(item.getName())){
+                        item.delete();
                     }
-                    if(file.getName().endsWith(".mtl") && !"output.house.mtl".equals(file.getName()) &&
-                            !"mesh.mtl".equals(file.getName())){
-                        file.delete();
+                    if(item.getName().endsWith(".mtl") && !"output.house.mtl".equals(item.getName()) &&
+                            !"mesh.mtl".equals(item.getName())){
+                        item.delete();
                     }
                 }
-                //打包
-                ZipUtil.zip(meshPath, zipPath);
-                //上传压缩包
-                fYunFileService.uploadFile(bucket, zipPath, "downloads/extras/" + zipName);
-                String url = ossUrlPrefix + "downloads/extras/" + zipName + "?t=" + Calendar.getInstance().getTimeInMillis();
-                FileUtil.del(zipPath);
-                return ResultData.ok(url);
-            }
-        }
-
-        //V2版本在本地获取模型资源
-        //修改过的资源
-        String editData =  scenePlusExt.getDataSource() + "_edit/caches/tex";
-        String results = scenePlusExt.getDataSource() + "_edit/results";
-        if (new File(editData).exists() && new File(results).exists()){
-            for(File file : new File(editData).listFiles()){
-                if(file.getName().endsWith(".obj") && !"output.house.obj".equals(file.getName()) &&
-                        !"mesh.obj".equals(file.getName())){
-                    file.delete();
-                }
-                if(file.getName().endsWith(".mtl") && !"output.house.mtl".equals(file.getName()) &&
-                        !"mesh.mtl".equals(file.getName())){
-                    file.delete();
-                }
+                continue;
             }
-
-            ZipUtil.zip(editData, zipPath);
-            //上传压缩包
-            fYunFileService.uploadFile(bucket, zipPath, "downloads/extras/" + zipName);
-            String url = ossUrlPrefix + "downloads/extras/" + zipName + "?t=" + Calendar.getInstance().getTimeInMillis();
-            return ResultData.ok(url);
-        }
-
-        //没上传过返回源资源
-        String dataPath = scenePlusExt.getDataSource() + "/caches/tex";
-        File dataFile = new File(dataPath);
-        if(!dataFile.exists()){
-            throw new BusinessException(ErrorCode.FAILURE_CODE_3018);
-        }
-        for(File file : dataFile.listFiles()){
             if(file.getName().endsWith(".obj") && !"output.house.obj".equals(file.getName()) &&
                     !"mesh.obj".equals(file.getName())){
                 file.delete();
@@ -982,16 +1104,40 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
                 file.delete();
             }
         }
-
-        ZipUtil.zip(dataPath, zipPath);
+        //打包
+        ZipUtil.zip(meshPath, zipPath);
         //上传压缩包
         fYunFileService.uploadFile(bucket, zipPath, "downloads/extras/" + zipName);
         String url = ossUrlPrefix + "downloads/extras/" + zipName + "?t=" + Calendar.getInstance().getTimeInMillis();
+        FileUtil.del(zipPath);
         return ResultData.ok(url);
     }
 
     @Override
-    public ScenePro getByNum(String num) {
-        return this.getOne(new LambdaQueryWrapper<ScenePro>().eq(ScenePro::getNum, num));
+    public List<SceneBean> listCleanOrigScene(int cleanOrigMonth) {
+        Date time = Calendar.getInstance().getTime();
+        time = DateUtil.beginOfDay(DateUtil.offset(time, DateField.MONTH, -cleanOrigMonth));
+        return this.baseMapper.selectCleanOrigScene(time);
+    }
+
+    @Override
+    public List<SceneBean> listCleanOss4DeletedScene(int month) {
+        Date time = Calendar.getInstance().getTime();
+        time = DateUtil.beginOfDay(DateUtil.offset(time, DateField.MONTH, -month));
+        return this.baseMapper.listCleanOss4DeletedScene(time);
+    }
+
+    @Override
+    public List<SceneBean> listCleanOss4TestCamera(Set<Long> cameraIds, int month) {
+        Date time = Calendar.getInstance().getTime();
+        time = DateUtil.beginOfDay(DateUtil.offset(time, DateField.MONTH, -month));
+        return this.baseMapper.listCleanOss4TestCamera(cameraIds, time);
+    }
+
+    @Override
+    public List<SceneBean> listColdStorageScene(int cleanOrigMonth) {
+        Date time = Calendar.getInstance().getTime();
+        time = DateUtil.beginOfDay(DateUtil.offset(time, DateField.MONTH, -cleanOrigMonth));
+        return this.baseMapper.selectColdStorageScene(time);
     }
 }

+ 169 - 0
src/main/java/com/fdkankan/scene/service/impl/SceneServiceImpl.java

@@ -0,0 +1,169 @@
+package com.fdkankan.scene.service.impl;
+
+import cn.hutool.core.img.ImgUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.lang.UUID;
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.fdkankan.common.constant.CommonOperStatus;
+import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.common.util.DateExtUtil;
+import com.fdkankan.common.util.FileUtils;
+import com.fdkankan.fyun.config.FYunFileConfig;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
+import com.fdkankan.model.constants.ConstantFilePath;
+import com.fdkankan.rabbitmq.util.RabbitMqProducer;
+import com.fdkankan.redis.constant.RedisKey;
+import com.fdkankan.redis.util.RedisUtil;
+import com.fdkankan.scene.bean.BodySegmentStatusBean;
+import com.fdkankan.scene.service.ISceneService;
+import com.fdkankan.scene.util.OssBodySegmentUtil;
+import com.fdkankan.web.response.ResultData;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+import sun.rmi.runtime.Log;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.util.Calendar;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+@Slf4j
+@Service("sceneService")
+public class SceneServiceImpl implements ISceneService {
+
+    @Value("${queue.bodySegment:body-segment}")
+    private String queueName;
+    @Value("${oss.bodySegment.bucket:4dkankan-huadong}")
+    private String bodySegmentBucket;
+    @Value("${oss.bodySegment.point:oss-cn-shanghai.aliyuncs.com}")
+    private String bodySegmentHost;
+
+    @Autowired
+    private OssBodySegmentUtil ossBodySegmentUtil;
+    @Autowired
+    private RedisUtil redisUtil;
+    @Autowired
+    private RabbitMqProducer rabbitMqProducer;
+    @Autowired
+    private FYunFileServiceInterface fYunFileService;
+    @Autowired
+    public FYunFileConfig fYunFileConfig;
+
+    @Override
+    public ResultData uploadBodySegment(MultipartFile file, Integer rotate) throws Exception {
+
+        if(!FileUtils.checkFileSizeIsLimit(file.getSize(), 10, "M")){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_4003, "10M");
+        }
+
+        String uuid = UUID.randomUUID().toString();
+
+        String fileName = file.getOriginalFilename();
+        String extName = fileName.substring(fileName.lastIndexOf("."));
+        File tempFile = File.createTempFile(uuid, extName);
+        file.transferTo(tempFile);
+
+        //判断是否需要旋转
+        if(Objects.nonNull(rotate) && rotate != 0){
+            Image rotateImg = ImgUtil.rotate(ImageIO.read(tempFile), rotate);
+            File tempRotateFile = File.createTempFile(uuid + "-rotate", extName);
+            ImgUtil.write(rotateImg, tempRotateFile);
+            tempFile = tempRotateFile;
+        }
+
+        //校验像素
+        BufferedImage bufferedImage = ImgUtil.read(tempFile.getPath());
+        Float scale = 1F;
+        Float widthScale = 1F;
+        Float heightScale = 1F;
+        int width = bufferedImage.getWidth();
+        int height = bufferedImage.getHeight();
+        if(width > 2000){
+            widthScale = new BigDecimal(2000).divide(new BigDecimal(width),5, BigDecimal.ROUND_DOWN).floatValue();
+        }
+        if(height > 2000){
+            heightScale = new BigDecimal(2000).divide(new BigDecimal(height),5, BigDecimal.ROUND_DOWN).floatValue();
+        }
+        scale = widthScale > heightScale ? heightScale : widthScale;
+        ImgUtil.scale(new File(tempFile.getPath()), new File(tempFile.getPath()), scale);
+
+        String orgImgOssPath = "body_segment/original/" + tempFile.getName();
+        ossBodySegmentUtil.uploadOss(tempFile.getPath(), orgImgOssPath);
+//        fYunFileService.uploadFile(bodySegmentBucket, tempFile.getPath(), orgImgOssPath);
+
+        BodySegmentStatusBean bodySegmentStatusBean = BodySegmentStatusBean.builder().uuid(uuid).status(CommonOperStatus.WAITING.code()).build();
+        redisUtil.set(String.format(RedisKey.SCENE_BODY_SEGMENT, uuid), JSON.toJSONString(bodySegmentStatusBean), RedisKey.CAMERA_EXPIRE_7_TIME);
+
+        Map<String, String> map = new HashMap<>();
+        map.put("uuid", uuid);
+        map.put("imgUrl", "https://" +  bodySegmentBucket + "." + bodySegmentHost + "/" + orgImgOssPath);
+        rabbitMqProducer.sendByWorkQueue(queueName, map);
+
+        return ResultData.ok(uuid);
+    }
+
+    public static void main(String[] args) throws IOException {
+        Image rotateImg = ImgUtil.rotate(ImageIO.read(FileUtil.file("C:\\Users\\dsx\\Desktop\\IMG_6633.HEIC.JPG")), 90);
+        ImgUtil.write(rotateImg, FileUtil.file("C:\\Users\\dsx\\Desktop\\IMG_6633.HEIC_2.JPG"));
+    }
+
+    @Override
+    public void bodySegmentHandler(String imgUrl, String uuid) {
+        String progress = redisUtil.hget(RedisKey.SCENE_BODY_SEGMENT, uuid);
+        BodySegmentStatusBean bodySegmentStatusBean = null;
+        try {
+            if(StrUtil.isEmpty(progress)){
+                bodySegmentStatusBean = JSON.parseObject(progress, BodySegmentStatusBean.class);
+            }
+            if(Objects.isNull(bodySegmentStatusBean)){
+                bodySegmentStatusBean = new BodySegmentStatusBean();
+                bodySegmentStatusBean.setUuid(uuid);
+            }
+            String dir = ConstantFilePath.BASE_PATH + "/bodySegment/" +
+                    DateExtUtil.format(Calendar.getInstance().getTime(), DateExtUtil.dateStyle6);
+            String fileName = uuid + ".png";
+            String imgPath = dir + "/" + fileName;
+            ossBodySegmentUtil.extracted(imgUrl, dir, fileName);
+            if(!FileUtil.exist(imgPath)){
+                throw new Exception("提取图片失败");
+            }
+            String targetOssImgPath = "body_segment/segment/" + uuid + ".png";
+            fYunFileService.uploadFile(imgPath, targetOssImgPath);
+            bodySegmentStatusBean.setStatus(CommonOperStatus.SUCCESS.code());
+            bodySegmentStatusBean.setImageUrl(fYunFileConfig.getHost() + targetOssImgPath);
+            redisUtil.set(String.format(RedisKey.SCENE_BODY_SEGMENT, uuid), JSON.toJSONString(bodySegmentStatusBean), RedisKey.CAMERA_EXPIRE_7_TIME);
+        } catch (Exception e) {
+            bodySegmentStatusBean.setStatus(CommonOperStatus.FAILD.code());
+            redisUtil.set(String.format(RedisKey.SCENE_BODY_SEGMENT, uuid), JSON.toJSONString(bodySegmentStatusBean), RedisKey.CAMERA_EXPIRE_7_TIME);
+        }finally {
+            try {
+                //免费版qps不能大于2,故休眠一秒
+                Thread.sleep(1000L);
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Override
+    public ResultData getBodySegmentStatus(String uuid) {
+
+        String progress = redisUtil.get(String.format(RedisKey.SCENE_BODY_SEGMENT, uuid));
+        if(StrUtil.isEmpty(progress)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5038);
+        }
+        BodySegmentStatusBean bodySegmentStatusBean = JSON.parseObject(progress, BodySegmentStatusBean.class);
+        return ResultData.ok(bodySegmentStatusBean);
+    }
+}

+ 12 - 0
src/main/java/com/fdkankan/scene/service/impl/SurveillanceServiceImpl.java

@@ -7,11 +7,13 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fdkankan.common.constant.CommonStatus;
 import com.fdkankan.common.constant.ErrorCode;
 import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.scene.entity.SceneEditInfo;
 import com.fdkankan.scene.entity.SceneEditInfoExt;
 import com.fdkankan.scene.entity.ScenePlus;
 import com.fdkankan.scene.entity.Surveillance;
 import com.fdkankan.scene.mapper.ISurveillanceMapper;
 import com.fdkankan.scene.service.ISceneEditInfoExtService;
+import com.fdkankan.scene.service.ISceneEditInfoService;
 import com.fdkankan.scene.service.IScenePlusService;
 import com.fdkankan.scene.service.ISurveillanceService;
 import com.fdkankan.scene.vo.BaseSidParamVO;
@@ -39,6 +41,8 @@ public class SurveillanceServiceImpl extends ServiceImpl<ISurveillanceMapper, Su
     private IScenePlusService scenePlusService;
     @Autowired
     private ISceneEditInfoExtService sceneEditInfoExtService;
+    @Autowired
+    private ISceneEditInfoService sceneEditInfoService;
 
     @Override
     public ResultData saveSurveillance(SurveillanceParamVO param) {
@@ -47,6 +51,7 @@ public class SurveillanceServiceImpl extends ServiceImpl<ISurveillanceMapper, Su
         if(Objects.isNull(scenePlus)){
             throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
         }
+        SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
         SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId());
 
         Surveillance surveillance = this.getBySid(param.getNum(), param.getSid());
@@ -64,6 +69,9 @@ public class SurveillanceServiceImpl extends ServiceImpl<ISurveillanceMapper, Su
         sceneEditInfoExt.setSurveillances(CommonStatus.YES.code().intValue());
         sceneEditInfoExtService.updateById(sceneEditInfoExt);
 
+        sceneEditInfoService.upgradeVersionById(sceneEditInfo.getId());
+
+
         return ResultData.ok();
     }
 
@@ -73,6 +81,7 @@ public class SurveillanceServiceImpl extends ServiceImpl<ISurveillanceMapper, Su
         if(Objects.isNull(scenePlus)){
             throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
         }
+        SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
         SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId());
 
         this.remove(new LambdaQueryWrapper<Surveillance>().eq(Surveillance::getSid, param.getSid()));
@@ -82,6 +91,9 @@ public class SurveillanceServiceImpl extends ServiceImpl<ISurveillanceMapper, Su
             sceneEditInfoExt.setSurveillances(CommonStatus.NO.code().intValue());
         }
         sceneEditInfoExtService.updateById(sceneEditInfoExt);
+
+        sceneEditInfoService.upgradeVersionById(sceneEditInfo.getId());
+
         return ResultData.ok();
     }
 

+ 121 - 0
src/main/java/com/fdkankan/scene/util/ConverxyUtil.java

@@ -0,0 +1,121 @@
+package com.fdkankan.scene.util;
+
+import cn.hutool.core.io.FileUtil;
+import com.alibaba.fastjson.JSONObject;
+
+import java.io.File;
+import java.math.BigDecimal;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Xiewj
+ * @date 2023/4/11
+ */
+public class ConverxyUtil {
+   static Map<String,String> label=new HashMap<>();
+   static Map<String,int[]> color=new HashMap<>();
+
+   static void init() {
+      label.put("0","cabinet");
+      label.put("1","air");
+      label.put("2","battery");
+
+      color.put("0",new int[]{56,56,255});
+      color.put("1",new int[]{151,157,255});
+      color.put("2",new int[]{31,112,255});
+   }
+   public static String getLabelVal(String key) {
+      if (label.size()==0){
+         init();
+      }
+      //标签类型初始化
+     return label.get(key);
+   }
+   public static int[] getColor(String key) {
+      if (color.size()==0){
+         init();
+      }
+      //标签类型初始化
+      return color.get(key);
+   }
+      // 将中心宽高格式转换为左上角点和右下角点格式
+   /**
+    * 将xywh格式的目标框转换为xyxy格式
+    * @param xywh xywh格式的目标框,格式为"x,y,w,h"
+    * @return xyxy格式的目标框,格式为"x1,y1,x2,y2"
+    */
+   public static int[] centerWh2xyxy(String xywh,int w1,int h1){
+      String[] values = xywh.split(" ");
+      if (values.length<4){
+         return null;
+      }
+      float x = Float.parseFloat(values[1]);
+      float y = Float.parseFloat(values[2]);
+      float w = Float.parseFloat(values[3]);
+      float h = Float.parseFloat(values[4]);
+      int[] xyxy = new int[4];
+      xyxy[0] = (int) ((x - w / 2) * w1); // x1
+      xyxy[1] = (int) ((y - h / 2)* h1); // y1
+      xyxy[2] = (int) ((x + w / 2)* w1); // x2
+      xyxy[3] = (int) ((y+ h / 2)* h1); // y2
+      return xyxy;
+   }
+
+   // 将左上角点和右下角点格式转换为中心宽高格式
+   public static double[] xyxy2centerWh(int x1, int y1, int x2, int y2,int w1,int h1){
+
+      double[] centerWh = new double[4];
+      BigDecimal dx1=BigDecimal.valueOf(x1);
+      BigDecimal  dy1=BigDecimal.valueOf(y1);
+      BigDecimal  dx2=BigDecimal.valueOf(x2);
+      BigDecimal dy2= BigDecimal.valueOf(y2);
+      BigDecimal  dw1=BigDecimal.valueOf(w1);
+      BigDecimal  dh1=BigDecimal.valueOf(h1);
+
+
+      centerWh[0] =((dx1.add(dx2)).divide(BigDecimal.valueOf(2))).divide(dw1).doubleValue(); // centerX
+      centerWh[1] = ((dy1.add(dy2)).divide(BigDecimal.valueOf(2))).divide(dh1).doubleValue(); // centerX
+      centerWh[2] = dx2.subtract(dx1).divide(dw1).doubleValue(); // width
+      centerWh[3] =  dy2.subtract(dy1).divide(dh1).doubleValue(); // width
+
+      return centerWh;
+   }
+   public static void main(String[] args) {
+      // 中心宽高格式转换为左上角点和右下角点格式
+//      int[] xyxy = ConverxyUtil.centerWh2xyxy("0.215149 0.557373 0.067749 0.329590",8192,4096);
+//
+//      System.out.println("x1=" + xyxy[0] + ", y1=" + xyxy[1] + ", x2=" + xyxy[2] + ", y2=" + xyxy[3]);
+//
+//      // 左上角点和右下角点格式转换为中心宽高格式
+//      double[] centerWh = ConverxyUtil.xyxy2centerWh(xyxy[0], xyxy[1], xyxy[2], xyxy[3],8192,4096);
+//      System.out.println("centerX=" + centerWh[0] + ", centerY=" + centerWh[1] + ", width=" + centerWh[2] + ", height=" + centerWh[3]);
+//      int[] xyxy1 = ConverxyUtil.centerWh2xyxy("0.21514892578125 0.5572509765625 0.0677490234375 0.329833984375",8192,4096);
+//      System.out.println("x1=" + xyxy1[0] + ", y1=" + xyxy1[1] + ", x2=" + xyxy1[2] + ", y2=" + xyxy1[3]);
+//
+////      Object labelVal = ConverxyUtil.getLabelVal("1");
+////      System.out.println(labelVal);
+
+      File tempFile=new File("C:\\Users\\4DAGE\\Downloads\\KK-UR4UGMSHEK3\\images\\0.txt");
+      List<String> s = FileUtil.readUtf8Lines(tempFile);
+
+
+      List<JSONObject> shapeJsons=new ArrayList<>();
+      //转换labelimg标注处理的结果
+      for (String s1 : s) {
+         int[] ints = ConverxyUtil.centerWh2xyxy(s1, 4096,2048);
+         String[] s2 = s1.split(" ");
+         JSONObject shapeJson=new JSONObject();
+         shapeJson.put("bbox",ints);
+         shapeJson.put("color",ConverxyUtil.getColor(s2[0]));
+         shapeJson.put("label",s1);
+         shapeJson.put("category",ConverxyUtil.getLabelVal(s2[0]));
+         shapeJson.put("score",0);
+         shapeJsons.add(shapeJson);
+      }
+      System.out.println(shapeJsons);
+   }
+}

+ 98 - 0
src/main/java/com/fdkankan/scene/util/OssBodySegmentUtil.java

@@ -0,0 +1,98 @@
+package com.fdkankan.scene.util;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.http.HttpUtil;
+import com.aliyun.imageseg20191230.models.SegmentBodyResponse;
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.tea.TeaException;
+import com.fdkankan.common.util.FileUtils;
+import com.fdkankan.scene.httpclient.MyClient;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.io.File;
+
+@Slf4j
+@Component
+@RefreshScope
+public class OssBodySegmentUtil {
+
+    @Value("${oss.bodySegment.point:oss-cn-shanghai.aliyuncs.com}")
+    private String endPoint;
+
+    @Value("${oss.bodySegment.imagesegPoint:imageseg.cn-shanghai.aliyuncs.com}")
+    private String imagesegEndPoint;
+
+    @Value("${fyun.key}")
+    private String accessKeyId;
+
+    @Value("${fyun.secret}")
+    private String accessKeySecret;
+
+    @Value("${oss.bodySegment.bucket:4dkankan-huadong}")
+    private String bucket;
+
+    @Resource
+    private MyClient myClient;
+
+    public void uploadOss(String filePath, String key){
+        OSS ossClient = new OSSClientBuilder().build(endPoint, accessKeyId, accessKeySecret);
+        try {
+            File file = new File(filePath);
+            if (!file.exists()) {
+                log.error("要上传的文件不存在:" + filePath);
+                return;
+            }
+            ossClient.putObject(bucket, key, new File(filePath));
+        } catch (Exception e) {
+            log.error(e.toString() + filePath);
+        } finally {
+            ossClient.shutdown();
+        }
+    }
+
+    public void extracted(String imageUrl, String dir, String fileName) throws Exception {
+        try {
+            com.aliyun.imageseg20191230.Client client = this.createClient();
+            com.aliyun.imageseg20191230.models.SegmentBodyRequest segmentBodyRequest =
+                    new com.aliyun.imageseg20191230.models.SegmentBodyRequest().setImageURL(imageUrl);
+            com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
+            // 复制代码运行请自行打印 API 的返回值
+            SegmentBodyResponse segmentBodyResponse = client.segmentBodyWithOptions(segmentBodyRequest, runtime);
+            String imageURL = segmentBodyResponse.getBody().getData().getImageURL();
+            log.info("人体抠图imageURL:{}", imageURL);
+            myClient.downloadFile(imageURL, dir, fileName);
+        }catch (Exception e){
+            log.error("人体抠图失败,imageUrl:" + imageUrl, e);
+            myClient.downloadFile(imageUrl, dir, fileName);
+        }
+
+    }
+
+    public static void main(String[] args) {
+        FileUtils.downLoadFromUrl("http://vibktprfx-prod-prod-damo-eas-cn-shanghai.oss-cn-shanghai.aliyuncs.com/segment-body/2023-02-24/5d44fe44-308c-44c3-8e1d-2d4cbe601f86/image.png?Expires=1677208715&OSSAccessKeyId=LTAI4FoLmvQ9urWXgSRpDvh1&Signature=4ZyzaOz6W1nBD9s3KQuFN10c%2BPw%3D",
+                "1.png","D:\\test");
+    }
+
+    /**
+     * 使用AK&SK初始化账号Client
+     * @return Client
+     * @throws Exception
+     */
+    public com.aliyun.imageseg20191230.Client createClient() throws Exception {
+        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
+                // 必填,您的 AccessKey ID
+                .setAccessKeyId(accessKeyId)
+                // 必填,您的 AccessKey Secret
+                .setAccessKeySecret(accessKeySecret);
+        // 访问的域名
+        config.endpoint = this.imagesegEndPoint;
+        return new com.aliyun.imageseg20191230.Client(config);
+    }
+
+}

+ 97 - 0
src/main/java/com/fdkankan/scene/util/test.java

@@ -0,0 +1,97 @@
+package com.fdkankan.scene.util;
+// This file is auto-generated, don't edit it. Thanks.
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.thread.ThreadUtil;
+import cn.hutool.http.HttpUtil;
+import com.aliyun.imageseg20191230.Client;
+import com.aliyun.imageseg20191230.models.SegmentBodyResponse;
+import com.aliyun.tea.TeaException;
+import com.aliyun.teautil.Common;
+
+import java.io.File;
+
+public class test {
+
+    /**
+     * 使用AK&SK初始化账号Client
+     *
+     * @param accessKeyId
+     * @param accessKeySecret
+     * @return Client
+     * @throws Exception
+     */
+    public static com.aliyun.imageseg20191230.Client createClient(String accessKeyId, String accessKeySecret) throws Exception {
+        com.aliyun.teaopenapi.models.Config config = new com.aliyun.teaopenapi.models.Config()
+                // 必填,您的 AccessKey ID
+                .setAccessKeyId(accessKeyId)
+                // 必填,您的 AccessKey Secret
+                .setAccessKeySecret(accessKeySecret);
+        // 访问的域名
+        config.endpoint = "imageseg.cn-shanghai.aliyuncs.com";
+        return new com.aliyun.imageseg20191230.Client(config);
+    }
+
+    public static void main(String[] args_) throws Exception {
+
+        java.util.List<String> args = java.util.Arrays.asList(args_);
+        // 工程代码泄露可能会导致AccessKey泄露,并威胁账号下所有资源的安全性。以下代码示例仅供参考,建议使用更安全的 STS 方式,更多鉴权访问方式请参见:https://help.aliyun.com/document_detail/378657.html
+        com.aliyun.imageseg20191230.Client client = test.createClient("LTAIUrvuHqj8pvry", "JLOVl0k8Ke0aaM8nLMMiUAZ3EiiqI4");
+        ThreadUtil.execAsync(() -> {
+            extracted(client, "https://4dkankan-huadong.oss-cn-shanghai.aliyuncs.com/segment/1.jpg", "1");
+
+        });
+        ThreadUtil.execAsync(() -> {
+            extracted(client, "https://4dkankan-huadong.oss-cn-shanghai.aliyuncs.com/segment/2.jpg", "2");
+
+        });
+        ThreadUtil.sleep(1000);
+        ThreadUtil.execAsync(() -> {
+            extracted(client, "https://4dkankan-huadong.oss-cn-shanghai.aliyuncs.com/segment/3.jpg", "3");
+
+        });
+        ThreadUtil.execAsync(() -> {
+            extracted(client, "https://4dkankan-huadong.oss-cn-shanghai.aliyuncs.com/segment/4.webp", "4");
+
+        });
+//      ThreadUtil.sleep(2000);
+//      ThreadUtil.sleep(3000);
+
+//      ThreadUtil.sleep(4000);
+
+
+    }
+
+    private static void extracted(Client client, String imageUrl, String imgName) {
+
+        com.aliyun.imageseg20191230.models.SegmentBodyRequest segmentBodyRequest = new com.aliyun.imageseg20191230.models.SegmentBodyRequest()
+                .setImageURL(imageUrl);
+        com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
+        try {
+            // 复制代码运行请自行打印 API 的返回值
+            long stime = System.currentTimeMillis();
+            System.out.println("开始-----------" + imgName);
+            SegmentBodyResponse segmentBodyResponse = client.segmentBodyWithOptions(segmentBodyRequest, runtime);
+            String imageURL = segmentBodyResponse.getBody().getData().getImageURL();
+            long etime = System.currentTimeMillis();
+            System.out.printf("执行时长:%d 毫秒.----%s", (etime - stime), imgName);
+            File file = FileUtil.file("C:\\Users\\4DAGE\\Downloads\\抠像测试\\抠像测试\\1\\" + imgName + ".png");
+            if (FileUtil.exist(file)) {
+                FileUtil.del(file);
+            }
+            System.out.println(imageURL);
+            ThreadUtil.sleep(1000);
+            HttpUtil.downloadFile(imageURL, FileUtil.file(file));
+        } catch (TeaException error) {
+            // 如有需要,请打印 error
+            String s = Common.assertAsString(error.message);
+            System.out.println("错误1" + s);
+        } catch (Exception _error) {
+            TeaException error = new TeaException(_error.getMessage(), _error);
+            // 如有需要,请打印 error
+            String s = Common.assertAsString(error.message);
+            System.out.println("错误2" + s);
+
+        }
+    }
+}

+ 29 - 0
src/main/java/com/fdkankan/scene/vo/BaseJsonArrayParamVO.java

@@ -0,0 +1,29 @@
+package com.fdkankan.scene.vo;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * <p>
+ * 通用data类型参数类
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/2/10
+ **/
+@Data
+public class BaseJsonArrayParamVO extends BaseSceneParamVO{
+
+    @NotNull(message = "data不能为空")
+//    private List<LinkPanParamVO> linkPans;
+    private List<JSONObject> data;
+
+    private List<JSONObject> styles;
+
+}

+ 23 - 0
src/main/java/com/fdkankan/scene/vo/DeleteSidListParamVO.java

@@ -0,0 +1,23 @@
+package com.fdkankan.scene.vo;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import java.util.List;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/2/18
+ **/
+@Data
+public class DeleteSidListParamVO extends BaseSceneParamVO{
+
+    @NotEmpty(message = "sid不能为空")
+    private List<String> sidList;
+
+}

+ 1 - 4
src/main/java/com/fdkankan/scene/vo/DeleteLinkSceneStylesParamVO.java

@@ -14,10 +14,7 @@ import lombok.Data;
  * @since 2022/2/8
  **/
 @Data
-public class DeleteLinkSceneStylesParamVO {
-
-    @NotBlank(message = "场景码不能为空")
-    private String num;
+public class DeleteStylesParamVO extends BaseSceneParamVO{
 
     @NotNull(message = "sidList不能为空")
     private List<String> sidList;

+ 20 - 0
src/main/java/com/fdkankan/scene/vo/SaveFiltersParamVO.java

@@ -0,0 +1,20 @@
+package com.fdkankan.scene.vo;
+
+import javax.validation.constraints.NotBlank;
+import lombok.Data;
+
+/**
+ * <p>
+ * 通用data类型参数类
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/2/10
+ **/
+@Data
+public class SaveFiltersParamVO extends BaseDataParamVO{
+
+    //是否恢复默认(0-否,1-是)
+    private Integer reset;
+
+}

+ 35 - 0
src/main/java/com/fdkankan/scene/vo/SceneAsynOperLogParamVO.java

@@ -0,0 +1,35 @@
+package com.fdkankan.scene.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/12/7
+ **/
+@Data
+public class SceneAsynOperLogParamVO extends BaseSceneParamVO{
+
+    /**
+    * 操作类型(upload-上传,download-下载)
+    */
+    private String operType;
+
+    /**
+     * 模块名称
+     */
+    private String module;
+
+    /**
+     * 功能
+     */
+    private String func;
+
+
+}

+ 44 - 0
src/main/java/com/fdkankan/scene/vo/SceneEditControlsParamVO.java

@@ -1,5 +1,6 @@
 package com.fdkankan.scene.vo;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
@@ -76,5 +77,48 @@ public class SceneEditControlsParamVO implements Serializable {
      */
     private Integer showRule;
 
+    /**
+     * 是否展示标尺(0-不需要,1-需要)
+     */
+    private Integer showScale;
+
+    /**
+     * 是否展示分享场景(0-不需要,1-需要)
+     */
+    private Integer showShare;
+
+    /**
+     * 是否展示分享热点(0-不需要,1-需要)
+     */
+    private Integer showTagshare;
+
+    /**
+     * 是否展示合照开关(0-不需要,1-需要)
+     */
+    private Integer showCapture;
+
+    /**
+     * 多媒体标签标题
+     */
+    private Integer showTagTitle;
+
+    /**
+     * 指示牌标签标题
+     */
+    private Integer showBillboardTitle;
+
+    /**
+     * 视频监控标签标题
+     */
+    private Integer showCameraTitle;
+
+    /**
+     * 场景关联标签标题
+     */
+    private Integer showLinkTitle;
+
+
+
+
 
 }

+ 40 - 0
src/main/java/com/fdkankan/scene/vo/SceneEditControlsVO.java

@@ -1,5 +1,6 @@
 package com.fdkankan.scene.vo;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
@@ -66,5 +67,44 @@ public class SceneEditControlsVO implements Serializable {
      */
     private Integer showRule;
 
+    /**
+     * 是否展示标尺(0-不需要,1-需要)
+     */
+    private Integer showScale;
+
+    /**
+     * 是否展示分享场景(0-不需要,1-需要)
+     */
+    private Integer showShare;
+
+    /**
+     * 是否展示分享热点(0-不需要,1-需要)
+     */
+    private Integer showTagshare;
+
+    /**
+     * 是否展示合照开关(0-不需要,1-需要)
+     */
+    private Integer showCapture;
+
+    /**
+     * 多媒体标签标题
+     */
+    private Integer showTagTitle;
+
+    /**
+     * 指示牌标签标题
+     */
+    private Integer showBillboardTitle;
+
+    /**
+     * 视频监控标签标题
+     */
+    private Integer showCameraTitle;
+
+    /**
+     * 场景关联标签标题
+     */
+    private Integer showLinkTitle;
 
 }

+ 6 - 0
src/main/java/com/fdkankan/scene/vo/SceneEditInfoParamVO.java

@@ -1,5 +1,6 @@
 package com.fdkankan.scene.vo;
 
+import com.alibaba.fastjson.JSONObject;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
@@ -73,6 +74,11 @@ public class SceneEditInfoParamVO extends BaseSceneParamVO{
 
     private SceneEditControlsParamVO controls;
 
+    /**
+     * 分享配置
+     */
+    private JSONObject sns;
+
 
 
 

+ 21 - 0
src/main/java/com/fdkankan/scene/vo/SceneInfoVO.java

@@ -2,6 +2,7 @@ package com.fdkankan.scene.vo;
 
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.annotation.TableField;
 import java.util.List;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
@@ -135,6 +136,11 @@ public class SceneInfoVO {
     private String sceneKind;
 
     /**
+     * 算法模型类型(dam,3dtiles)
+     */
+    private String modelKind;
+
+    /**
      * 空间视频数据
      */
     private String boxVideos;
@@ -223,5 +229,20 @@ public class SceneInfoVO {
      */
     private Integer surveillances;
 
+    /**
+     * 场景容量 单位 MB
+     */
+    private Integer space;
+
+    /**
+     * 分享信息
+     */
+    private JSONObject sns;
+
+    /**
+     * 是否有指示牌(0-否,1-是)
+     */
+    private Integer billboards;
+
 
 }

+ 39 - 0
src/main/java/com/fdkankan/scene/vo/SceneMarkShapeDetectParamVO.java

@@ -0,0 +1,39 @@
+package com.fdkankan.scene.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/1/19
+ **/
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SceneMarkShapeDetectParamVO {
+
+    /**
+     * 场景码
+     */
+    @NotBlank(message = "场景码不能为空")
+    private String num;
+
+    /**
+     *  推送域名
+     */
+    private String webSite;
+
+    /**
+     *  保存路径。可以为空,不为空可以查看结果
+     */
+    private String saveDir="";
+}

+ 36 - 0
src/main/java/com/fdkankan/scene/vo/SceneMarkShapeParamVO.java

@@ -0,0 +1,36 @@
+package com.fdkankan.scene.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/1/19
+ **/
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SceneMarkShapeParamVO {
+
+    /**
+     * 场景码
+     */
+    @NotBlank(message = "场景码不能为空")
+    private String num;
+
+    /**
+     * 图片名称路径
+     */
+    private String imagePath;
+
+
+}

+ 46 - 0
src/main/java/com/fdkankan/scene/vo/SceneMarkShapeReDetectParamVO.java

@@ -0,0 +1,46 @@
+package com.fdkankan.scene.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/1/19
+ **/
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SceneMarkShapeReDetectParamVO {
+
+    /**
+     * 场景码
+     */
+    private String num;
+
+    /**
+     *  推送域名
+     */
+    private String webSite;
+    /**
+     *  图片名称
+     */
+    private String imagePath;
+
+    /**
+     *  保存路径。可以为空,不为空可以查看结果
+     */
+    private String saveDir="";
+
+    /**
+     *  1,场景的单张图片重新进入训练  2,整个场景的推理进入训练
+     */
+    private Integer detectType;
+
+}

+ 2 - 0
src/main/java/com/fdkankan/scene/vo/UploadPanoramaVO.java

@@ -20,6 +20,8 @@ import lombok.NoArgsConstructor;
 @AllArgsConstructor
 public class UploadPanoramaVO {
 
+    private int asyn;
+
     private Integer successCnt;
 
     private List<String> failList;

+ 13 - 50
src/main/resources/bootstrap-prod-eur.yml

@@ -3,14 +3,11 @@ spring:
     name: 4dkankan-center-scene
   cloud:
     nacos:
+      server-addr: 172.31.47.163:8848
+      namespace: 4dkankan-v4-prod-eur
       config:
-        server-addr: 172.31.42.151:8848
         file-extension: yaml
-        namespace: 4dkankan-pro-eur
-        extension-configs:
-          - data-id: 4dkankan-center-scene.yaml
-            group: DEFAULT_GROUP
-            refresh: true
+        namespace: ${spring.cloud.nacos.namespace}
         shared-configs:
           - data-id: common-db-config.yaml
             group: DEFAULT_GROUP
@@ -20,54 +17,20 @@ spring:
             group: DEFAULT_GROUP
             refresh: true
 
-          - data-id: other-config.yaml
+          - data-id: common-config.yaml
             group: DEFAULT_GROUP
             refresh: true
 
-          - data-id: common-upload-config.yaml
+          - data-id: common-fyun-config.yaml
             group: DEFAULT_GROUP
             refresh: true
-      discovery:
-        server-addr: 172.31.42.151:8848
-        namespace: 4dkankan-pro-eur
-    sentinel:
-      transport:
-        dashboard: 172.31.42.151:8888
-#        dashboard: localhost:8888
-        heartbeat-interval-ms: 500
-        port: 8719
-      eager: true #取消sentinel控制台懒加载
-      #sentinel配置持久化nacos
-      datasource:
-        #流控规则
-        flow:
-          nacos:
-            server-addr: ${spring.cloud.nacos.config.server-addr}
-            dataId: ${spring.application.name}-flow-rules
-            groupId: SENTINEL_GROUP
-            namespace: 4dkankan-pro
-            rule-type: flow
-        #熔断规则
-        degrade:
-          nacos:
-            server-addr: ${spring.cloud.nacos.config.server-addr}
-            dataId: ${spring.application.name}-degrade-rules
-            groupId: SENTINEL_GROUP
-            namespace: 4dkankan-pro
-            rule-type: degrade
-#      log:
-#        dir: ./logs # 默认值${home}/logs/csp/
-#        switch-pid: true # 日志带上线程id
-
-#开启feign熔断降级,如果没有开启,feign调用链路不会显示再sentinel控制中
-#feign:
-#  sentinel:
-#    enabled: true
-
-feign:
-  httpclient:
-    connection-timeout: 200000
-
-
 
+          - data-id: common-rabbitmq-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
 
+          - data-id: forest-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+      discovery:
+        namespace: ${spring.cloud.nacos.namespace}

+ 4 - 0
src/main/resources/bootstrap-prod.yml

@@ -28,6 +28,10 @@ spring:
           - data-id: common-rabbitmq-config.yaml
             group: DEFAULT_GROUP
             refresh: true
+
+          - data-id: forest-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
       discovery:
         namespace: ${spring.cloud.nacos.namespace}
 

+ 4 - 0
src/main/resources/bootstrap-test-eur.yml

@@ -28,6 +28,10 @@ spring:
           - data-id: common-rabbitmq-config.yaml
             group: DEFAULT_GROUP
             refresh: true
+
+          - data-id: forest-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
       discovery:
         namespace: ${spring.cloud.nacos.namespace}
 

+ 5 - 0
src/main/resources/bootstrap-test.yml

@@ -28,8 +28,13 @@ spring:
           - data-id: common-rabbitmq-config.yaml
             group: DEFAULT_GROUP
             refresh: true
+
+          - data-id: forest-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
       discovery:
         namespace: ${spring.cloud.nacos.namespace}
+#        namespace: public
 
 
 

+ 5 - 0
src/main/resources/mapper/scene/SceneAsynOperLogMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fdkankan.scene.mapper.ISceneAsynOperLogMapper">
+
+</mapper>

+ 5 - 0
src/main/resources/mapper/scene/SceneCleanOrigMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fdkankan.scene.mapper.ISceneCleanOrigMapper">
+
+</mapper>

+ 5 - 0
src/main/resources/mapper/scene/SceneColdStorageLogMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fdkankan.scene.mapper.ISceneColdStorageLogMapper">
+
+</mapper>

+ 5 - 0
src/main/resources/mapper/scene/SceneColdStorageMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.fdkankan.scene.mapper.ISceneColdStorageMapper">
+
+</mapper>

+ 42 - 1
src/main/resources/mapper/scene/ScenePlusMapper.xml

@@ -1,5 +1,46 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.fdkankan.com.fdkankan.scene.mapper.IScenePlusMapper">
+<mapper namespace="com.fdkankan.scene.mapper.IScenePlusMapper">
+
+    <select id="selectCleanOrigScene" resultType="com.fdkankan.scene.bean.SceneBean">
+        select plus.num, ext.data_source
+        from t_scene_plus plus
+        left join t_scene_plus_ext ext on plus.id = ext.plus_id
+        where plus.scene_status in (1,-2) and ext.algorithm_time <![CDATA[ < ]]> #{time}
+        and ext.data_source is NOT null
+        and NOT EXISTS (select o.num from t_scene_clean_orig o where o.rec_status = 'A' and o.num = plus.num and ext.algorithm_time <![CDATA[ < ]]> o.create_time)
+    </select>
+
+    <select id="selectCleanOrigSceneDeleted" resultType="com.fdkankan.scene.bean.SceneBean">
+        select plus.num, ext.data_source
+        from t_scene_plus plus
+        left join t_scene_plus_ext ext on plus.id = ext.plus_id
+        where plus.rec_status = 'I' and plus.update_time <![CDATA[ < ]]> #{time}
+        and ext.data_source is NOT null
+        and NOT EXISTS (select o.num from t_scene_clean_orig o where o.rec_status = 'A' and o.num = plus.num and o.type = 2)
+    </select>
+
+    <select id="listCleanOss4TestCamera" resultType="com.fdkankan.scene.bean.SceneBean">
+        select plus.num, ext.data_source
+        from t_scene_plus plus
+        left join t_scene_plus_ext ext on plus.id = ext.plus_id
+        where plus.scene_status in (1,-2) and plus.rec_status = 'A' and ext.algorithm_time <![CDATA[ < ]]> #{time}
+        and ext.data_source is NOT null
+        and plus.camera_id in
+        <foreach collection="cameraIds" item="cameraId" open="(" close=")" separator=",">
+            #{cameraId}
+        </foreach>
+        and NOT EXISTS (select o.num from t_scene_clean_orig o where o.rec_status = 'A' and o.num = plus.num and o.type = 3 and ext.algorithm_time <![CDATA[ < ]]> o.create_time)
+    </select>
+
+    <select id="selectColdStorageScene" resultType="com.fdkankan.scene.bean.SceneBean">
+        select plus.num, ext.data_source
+        from t_scene_plus plus
+        left join t_scene_plus_ext ext on plus.id = ext.plus_id
+        where plus.scene_status in (1,-2) and ext.algorithm_time <![CDATA[ < ]]> #{time}
+        and ext.data_source is NOT null
+        and NOT EXISTS (select c.num from t_scene_cold_storage c where c.rec_status = 'A' AND c.`state` = 1 and c.num = plus.num)
+        and NOT EXISTS (select o.num from t_scene_clean_orig o where o.rec_status = 'A' and o.state != -1 and o.num = plus.num and ext.algorithm_time <![CDATA[ < ]]> o.create_time)
+    </select>
 
 </mapper>

+ 39 - 1
src/main/resources/mapper/scene/SceneProMapper.xml

@@ -1,5 +1,43 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.fdkankan.com.fdkankan.scene.mapper.ISceneProMapper">
+<mapper namespace="com.fdkankan.scene.mapper.ISceneProMapper">
+
+    <select id="selectCleanOrigScene" resultType="com.fdkankan.scene.bean.SceneBean">
+        select pro.num, pro.data_source
+        from t_scene_pro pro
+        where pro.status in (1,-2) and pro.create_time <![CDATA[ < ]]> #{time}
+        and pro.data_source is not null
+        and NOT EXISTS (select o.num from t_scene_clean_orig o where o.rec_status = 'A' and o.num = pro.num and pro.create_time <![CDATA[ < ]]> o.create_time)
+    </select>
+
+    <select id="listCleanOss4DeletedScene" resultType="com.fdkankan.scene.bean.SceneBean">
+        select pro.num, pro.data_source
+        from t_scene_pro pro
+        where pro.rec_status = 'I' and pro.update_time <![CDATA[ < ]]> #{time}
+        and pro.data_source is not null
+        and NOT EXISTS (select o.num from t_scene_clean_orig o where o.rec_status = 'A' and o.num = pro.num and o.type = 2)
+    </select>
+
+    <select id="listCleanOss4TestCamera" resultType="com.fdkankan.scene.bean.SceneBean">
+        select pro.num, pro.data_source
+        from t_scene_pro pro
+        where pro.status in (1,-2) and pro.rec_status = 'A' and pro.create_time <![CDATA[ < ]]> #{time}
+        and pro.data_source is not null
+        and pro.camera_id in
+        <foreach collection="cameraIds" item="cameraId" open="(" close=")" separator=",">
+            #{cameraId}
+        </foreach>
+        and NOT EXISTS (select o.num from t_scene_clean_orig o where o.rec_status = 'A' and o.num = pro.num and o.type = 3 and pro.create_time <![CDATA[ < ]]> o.create_time)
+    </select>
+
+    <select id="selectColdStorageScene" resultType="com.fdkankan.scene.bean.SceneBean">
+        select pro.num, pro.data_source
+        from t_scene_pro pro
+        where pro.status in (1,-2) and pro.create_time <![CDATA[ < ]]> #{time}
+        and pro.data_source is not null
+        and pro.is_upgrade = 0
+        and NOT EXISTS (select c.num from t_scene_cold_storage c where c.rec_status = 'A' and c.state = 1 and c.num = pro.num)
+        and NOT EXISTS (select o.num from t_scene_clean_orig o where o.rec_status = 'A' and o.state != -1 and o.num = pro.num and pro.create_time <![CDATA[ < ]]> o.create_time)
+    </select>
 
 </mapper>

+ 0 - 23
src/test/java/com/fdkankan/scene/SceneApplicationTests.java

@@ -1,23 +0,0 @@
-package com.fdkankan.scene;
-
-import org.junit.jupiter.api.Test;
-import org.springframework.boot.test.context.SpringBootTest;
-
-@SpringBootTest
-class ApplicationTests {
-
-    @Test
-    void contextLoads() {
-    }
-
-
-
-    @Test
-    public String test2() throws Exception {
-
-
-        return "123";
-
-    }
-
-}