Forráskód Böngészése

Merge remote-tracking branch 'origin/release' into feature-local-jg

# Conflicts:
#	src/main/java/com/fdkankan/scene/Interceptor/CheckPermitAspect.java
#	src/main/java/com/fdkankan/scene/controller/SceneController.java
#	src/main/java/com/fdkankan/scene/generate/AutoGenerate.java
#	src/main/java/com/fdkankan/scene/listener/RabbitMqListener.java
#	src/main/java/com/fdkankan/scene/schedule/ScheduleJob.java
#	src/main/java/com/fdkankan/scene/service/ICommonService.java
#	src/main/java/com/fdkankan/scene/service/ILaserService.java
#	src/main/java/com/fdkankan/scene/service/ISceneService.java
#	src/main/java/com/fdkankan/scene/service/impl/CommonServiceImpl.java
#	src/main/java/com/fdkankan/scene/service/impl/LaserServiceImpl.java
#	src/main/java/com/fdkankan/scene/service/impl/SceneAsynOperLogServiceImpl.java
#	src/main/java/com/fdkankan/scene/service/impl/SceneEditInfoServiceImpl.java
#	src/main/java/com/fdkankan/scene/service/impl/SceneEditServiceImpl.java
#	src/main/java/com/fdkankan/scene/service/impl/SceneProServiceImpl.java
#	src/main/java/com/fdkankan/scene/service/impl/SceneServiceImpl.java
#	src/main/java/com/fdkankan/scene/service/impl/SceneUploadServiceImpl.java
#	src/main/java/com/fdkankan/scene/vo/SceneInfoVO.java
#	src/main/resources/bootstrap-dev.yml
dengsixing 8 hónapja
szülő
commit
4cfc9f3316
66 módosított fájl, 3187 hozzáadás és 250 törlés
  1. 6 0
      pom.xml
  2. 22 0
      src/main/java/com/fdkankan/scene/bean/SceneJsonBean.java
  3. 21 0
      src/main/java/com/fdkankan/scene/controller/FolderSceneController.java
  4. 30 2
      src/main/java/com/fdkankan/scene/controller/SceneAsynOperLogController.java
  5. 13 0
      src/main/java/com/fdkankan/scene/controller/SceneController.java
  6. 53 0
      src/main/java/com/fdkankan/scene/controller/SceneDynamicPanelController.java
  7. 67 29
      src/main/java/com/fdkankan/scene/controller/SceneEditController.java
  8. 53 0
      src/main/java/com/fdkankan/scene/controller/SceneEditDrawController.java
  9. 21 0
      src/main/java/com/fdkankan/scene/controller/SceneProEditController.java
  10. 48 0
      src/main/java/com/fdkankan/scene/entity/FolderScene.java
  11. 66 0
      src/main/java/com/fdkankan/scene/entity/SceneDynamicPanel.java
  12. 32 2
      src/main/java/com/fdkankan/scene/entity/SceneEditControls.java
  13. 26 2
      src/main/java/com/fdkankan/scene/entity/SceneEditInfoExt.java
  14. 10 3
      src/main/java/com/fdkankan/scene/entity/ScenePlusExt.java
  15. 285 0
      src/main/java/com/fdkankan/scene/entity/SceneProEdit.java
  16. 4 1
      src/main/java/com/fdkankan/scene/entity/SceneResource.java
  17. 20 0
      src/main/java/com/fdkankan/scene/entity/Surveillance.java
  18. 20 0
      src/main/java/com/fdkankan/scene/mapper/IFolderSceneMapper.java
  19. 18 0
      src/main/java/com/fdkankan/scene/mapper/ISceneDynamicPanelMapper.java
  20. 18 0
      src/main/java/com/fdkankan/scene/mapper/ISceneProEditMapper.java
  21. 47 0
      src/main/java/com/fdkankan/scene/mq/consumer/CopySceneConsumer.java
  22. 33 0
      src/main/java/com/fdkankan/scene/mq/consumer/SceneResourcePath.java
  23. 2 0
      src/main/java/com/fdkankan/scene/service/ICommonService.java
  24. 27 0
      src/main/java/com/fdkankan/scene/service/ICutModelService.java
  25. 17 0
      src/main/java/com/fdkankan/scene/service/IFolderSceneService.java
  26. 4 0
      src/main/java/com/fdkankan/scene/service/ILaserService.java
  27. 8 2
      src/main/java/com/fdkankan/scene/service/ISceneAsynOperLogService.java
  28. 6 0
      src/main/java/com/fdkankan/scene/service/ISceneCopyService.java
  29. 20 0
      src/main/java/com/fdkankan/scene/service/ISceneDrawService.java
  30. 25 0
      src/main/java/com/fdkankan/scene/service/ISceneDynamicPanelService.java
  31. 5 1
      src/main/java/com/fdkankan/scene/service/ISceneEditInfoService.java
  32. 17 0
      src/main/java/com/fdkankan/scene/service/ISceneProEditService.java
  33. 2 2
      src/main/java/com/fdkankan/scene/service/ISceneProService.java
  34. 2 0
      src/main/java/com/fdkankan/scene/service/ISceneResourceService.java
  35. 3 0
      src/main/java/com/fdkankan/scene/service/ISceneService.java
  36. 5 3
      src/main/java/com/fdkankan/scene/service/ISurveillanceService.java
  37. 12 0
      src/main/java/com/fdkankan/scene/service/IVisionService.java
  38. 7 0
      src/main/java/com/fdkankan/scene/service/IWbService.java
  39. 40 0
      src/main/java/com/fdkankan/scene/service/impl/CommonServiceImpl.java
  40. 264 0
      src/main/java/com/fdkankan/scene/service/impl/CutModelServiceImpl.java
  41. 24 0
      src/main/java/com/fdkankan/scene/service/impl/FolderSceneServiceImpl.java
  42. 59 0
      src/main/java/com/fdkankan/scene/service/impl/LaserServiceImpl.java
  43. 45 7
      src/main/java/com/fdkankan/scene/service/impl/SceneAsynOperLogServiceImpl.java
  44. 490 0
      src/main/java/com/fdkankan/scene/service/impl/SceneCopyServiceImpl.java
  45. 244 0
      src/main/java/com/fdkankan/scene/service/impl/SceneDrawServiceImpl.java
  46. 101 0
      src/main/java/com/fdkankan/scene/service/impl/SceneDynamicPanelServiceImpl.java
  47. 196 84
      src/main/java/com/fdkankan/scene/service/impl/SceneEditInfoServiceImpl.java
  48. 32 0
      src/main/java/com/fdkankan/scene/service/impl/SceneProEditServiceImpl.java
  49. 239 86
      src/main/java/com/fdkankan/scene/service/impl/SceneProServiceImpl.java
  50. 15 8
      src/main/java/com/fdkankan/scene/service/impl/SceneResourceServiceImpl.java
  51. 30 0
      src/main/java/com/fdkankan/scene/service/impl/SceneServiceImpl.java
  52. 8 4
      src/main/java/com/fdkankan/scene/service/impl/SceneUploadServiceImpl.java
  53. 61 13
      src/main/java/com/fdkankan/scene/service/impl/SurveillanceServiceImpl.java
  54. 58 0
      src/main/java/com/fdkankan/scene/service/impl/VisionServiceImpl.java
  55. 50 0
      src/main/java/com/fdkankan/scene/service/impl/WbServiceImpl.java
  56. 29 0
      src/main/java/com/fdkankan/scene/vo/SceneDynamicPanelParamVO.java
  57. 27 0
      src/main/java/com/fdkankan/scene/vo/SceneDynamicPanelVO.java
  58. 15 0
      src/main/java/com/fdkankan/scene/vo/SceneEditControlsParamVO.java
  59. 17 0
      src/main/java/com/fdkankan/scene/vo/SceneEditControlsVO.java
  60. 5 0
      src/main/java/com/fdkankan/scene/vo/SceneEditInfoParamVO.java
  61. 23 0
      src/main/java/com/fdkankan/scene/vo/SceneInfoVO.java
  62. 9 1
      src/main/java/com/fdkankan/scene/vo/SurveillanceParamVO.java
  63. 8 0
      src/main/java/com/fdkankan/scene/vo/SurveillanceVO.java
  64. 13 0
      src/main/resources/mapper/scene/FolderSceneMapper.xml
  65. 5 0
      src/main/resources/mapper/scene/SceneDynamicPanelMapper.xml
  66. 5 0
      src/main/resources/mapper/scene/SceneProEditMapper.xml

+ 6 - 0
pom.xml

@@ -203,6 +203,12 @@
             <version>1.0.5</version>
         </dependency>
 
+        <dependency>
+            <groupId>com.fdkankan</groupId>
+            <artifactId>4dkankan-utils-dxf</artifactId>
+            <version>3.0.0-SNAPSHOT</version>
+        </dependency>
+
     </dependencies>
 
     <dependencyManagement>

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

@@ -218,5 +218,27 @@ public class SceneJsonBean {
      */
     private Integer billboards;
 
+    /**
+     * 是否有模型裁剪(0-否,1-是)
+     */
+    private Integer cutModel;
+
+    /**
+     * 启动页信息
+     */
+    private JSONObject started;
+
+    /**
+     * 空间绘制
+     */
+    private Integer sceneDraw;
+
+    //动态面板
+    private int dynamicPanel;
+
+    private Integer floorLogoType;
+
+    private String orientation;
+
 
 }

+ 21 - 0
src/main/java/com/fdkankan/scene/controller/FolderSceneController.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 2024-07-31
+ */
+@RestController
+@RequestMapping("/scene/folderScene")
+public class FolderSceneController {
+
+}
+

+ 30 - 2
src/main/java/com/fdkankan/scene/controller/SceneAsynOperLogController.java

@@ -1,6 +1,14 @@
 package com.fdkankan.scene.controller;
 
 
+import com.fdkankan.scene.annotation.CheckPermit;
+import com.fdkankan.scene.service.ISceneAsynOperLogService;
+import com.fdkankan.scene.vo.SceneAsynOperLogParamVO;
+import com.fdkankan.web.response.ResultData;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+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;
@@ -10,12 +18,32 @@ import org.springframework.web.bind.annotation.RestController;
  *  前端控制器
  * </p>
  *
- * @author 
+ * @author
  * @since 2022-12-07
  */
 @RestController
-@RequestMapping("/scene/sceneAsynOperLog")
+@RequestMapping("/service/scene/edit")
 public class SceneAsynOperLogController {
 
+    @Autowired
+    private ISceneAsynOperLogService sceneAsynOperLogService;
+
+
+    /**
+     * <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);
+    }
+
+
 }
 

+ 13 - 0
src/main/java/com/fdkankan/scene/controller/SceneController.java

@@ -8,6 +8,7 @@ import com.fdkankan.scene.bean.LaserSceneBean;
 import com.fdkankan.scene.service.ILaserService;
 import com.fdkankan.scene.vo.*;
 import com.fdkankan.scene.annotation.CheckPermit;
+import com.fdkankan.scene.service.ISceneDynamicPanelService;
 import com.fdkankan.scene.service.ISceneService;
 import com.fdkankan.web.response.ResultData;
 import com.fdkankan.scene.service.ISceneEditInfoService;
@@ -38,6 +39,8 @@ public class SceneController extends BaseController {
     private ILaserService laserService;
     @Autowired
     private ISceneService sceneService;
+    @Autowired
+    private ISceneDynamicPanelService sceneDynamicPanelService;
 
     /**
      * <p>
@@ -144,5 +147,15 @@ public class SceneController extends BaseController {
         return ResultData.ok();
     }
 
+    /**
+     * 查询是否有动态面板数据
+     * @param num
+     * @return
+     */
+    @GetMapping("/checkDynamicPanel")
+    public ResultData checkDynamicPanel(@RequestParam("num") String num){
+        return ResultData.ok(sceneDynamicPanelService.checkDynamicPanel(num));
+    }
+
 }
 

+ 53 - 0
src/main/java/com/fdkankan/scene/controller/SceneDynamicPanelController.java

@@ -0,0 +1,53 @@
+package com.fdkankan.scene.controller;
+
+
+import com.fdkankan.scene.annotation.CheckPermit;
+import com.fdkankan.scene.service.ISceneDynamicPanelService;
+import com.fdkankan.scene.vo.BaseJsonDataParamVO;
+import com.fdkankan.web.response.ResultData;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.Valid;
+
+/**
+ * <p>
+ * 场景动态面板 前端控制器
+ * </p>
+ *
+ * @author
+ * @since 2024-05-21
+ */
+@RestController
+@RequestMapping("/service/scene/edit/dynamicPanel")
+public class SceneDynamicPanelController {
+
+    @Autowired
+    private ISceneDynamicPanelService sceneDynamicPanelService;
+
+    /**
+     * 获取动态面板列表
+     * @param num
+     * @return
+     */
+    @CheckPermit
+    @GetMapping("/list")
+    public ResultData list(@RequestParam("num") String num){
+        return ResultData.ok(sceneDynamicPanelService.list(num));
+    }
+
+    /**
+     * 修改动态面板
+     * @param param
+     * @return
+     */
+    @CheckPermit
+    @PostMapping("/update")
+    public ResultData update(@RequestBody @Valid BaseJsonDataParamVO param){
+        sceneDynamicPanelService.update(param);
+        return ResultData.ok();
+    }
+
+
+}
+

+ 67 - 29
src/main/java/com/fdkankan/scene/controller/SceneEditController.java

@@ -8,20 +8,15 @@ 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;
 import lombok.extern.log4j.Log4j2;
 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.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.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import java.io.IOException;
+
 /**
  * 场景编辑管理
  */
@@ -53,6 +48,10 @@ public class SceneEditController extends BaseController {
     private ISceneAsynOperLogService sceneAsynOperLogService;
     @Autowired
     private ISceneEditInfoExtService sceneEditInfoExtService;
+    @Autowired
+    private ICutModelService cutModelService;
+    @Autowired
+    private IVisionService visionService;
 
     /**
      * <p>
@@ -199,8 +198,8 @@ public class SceneEditController extends BaseController {
      **/
     @CheckPermit
     @PostMapping(value = "/downloadModel")
-    public ResultData downloadTexData(@RequestParam("num") String num) throws Exception {
-        return sceneProService.downloadTexData(num);
+    public ResultData downloadModel(@RequestParam("num") String num) throws Exception {
+        return sceneProService.downloadModel(num);
     }
 
     /**
@@ -215,8 +214,8 @@ public class SceneEditController extends BaseController {
      **/
     @CheckPermit
     @PostMapping(value = "/uploadModel")
-    public ResultData uploadObjAndImg(@RequestParam("num") String num, @RequestParam("file") MultipartFile file) throws Exception {
-        return sceneProService.uploadObjAndImg(num, file);
+    public ResultData uploadModel(@RequestParam("num") String num, @RequestParam("file") MultipartFile file) throws Exception {
+        return sceneProService.uploadModel(num, file);
     }
 
     /**
@@ -318,6 +317,36 @@ public class SceneEditController extends BaseController {
 
     /**
      * <p>
+     保存户型图
+     * </p>
+     * @author dengsixing
+     * @date 2022/1/20
+     * @param param
+     * @return com.fdkankan.web.response.ResultData
+     **/
+    @CheckPermit
+    @GetMapping(value = "/cad/dxf/download")
+    public ResultData saveCadDxf(@RequestParam String num, @RequestParam Integer subgroup) throws Exception{
+        return sceneEditInfoService.downloadDxf(num, subgroup);
+    }
+
+    /**
+     * <p>
+     保存户型图
+     * </p>
+     * @author dengsixing
+     * @date 2022/1/20
+     * @param param
+     * @return com.fdkankan.web.response.ResultData
+     **/
+    @CheckPermit
+    @PostMapping(value = "/cad/dxf/upload")
+    public ResultData uploadDxf(@RequestParam MultipartFile file, @RequestParam String num, Integer subgroup) throws Exception{
+        return sceneEditInfoService.uploadDxf(file, num, subgroup);
+    }
+
+    /**
+     * <p>
      重置户型图
      * </p>
      * @author dengsixing
@@ -751,13 +780,13 @@ public class SceneEditController extends BaseController {
      **/
     @CheckPermit
     @PostMapping("/surveillance/save")
-    ResultData saveSurveillance(@RequestBody @Validated SurveillanceParamVO param){
+    ResultData saveSurveillance(@RequestBody @Validated SurveillanceParamVO param) throws Exception {
         return surveillanceService.saveSurveillance(param);
     }
 
     @CheckPermit
     @PostMapping("/surveillance/delete")
-    public ResultData deleteSurveillance(@RequestBody @Validated BaseSidParamVO param){
+    public ResultData deleteSurveillance(@RequestBody @Validated BaseSidParamVO param) throws IOException {
         return surveillanceService.deleteSurveillance(param);
     }
 
@@ -827,21 +856,6 @@ public class SceneEditController extends BaseController {
     }
 
     /**
-     * <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
      */
@@ -898,6 +912,30 @@ public class SceneEditController extends BaseController {
         return ResultData.ok(sceneEditInfoExtService.deleteBillboardsStyles(param));
     }
 
+    @CheckPermit
+    @PostMapping(value = "/cutModel/save")
+    public ResultData saveCutModel(@RequestBody @Validated BaseJsonArrayParamVO param) throws Exception {
+        return cutModelService.saveCutModel(param);
+    }
+
+    @CheckPermit
+    @PostMapping(value = "/cutModel/list")
+    public ResultData listCutModel(@RequestBody @Validated BaseSceneParamVO param) throws Exception {
+        return ResultData.ok(cutModelService.listCutModel(param));
+    }
+
+    @CheckPermit
+    @PostMapping(value = "/cutModel/delete")
+    public ResultData deleteCutModel(@RequestBody @Validated DeleteSidListParamVO param) throws Exception {
+        return cutModelService.deleteCutModel(param);
+    }
+
+    @CheckPermit
+    @GetMapping(value = "/point/getLatAndLon")
+    public ResultData getPointLatAndLon(@RequestParam String num) throws Exception {
+        return ResultData.ok(visionService.getPointLatAndLon(num));
+    }
+
 
 
 }

+ 53 - 0
src/main/java/com/fdkankan/scene/controller/SceneEditDrawController.java

@@ -0,0 +1,53 @@
+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.scene.annotation.CheckPermit;
+import com.fdkankan.scene.service.*;
+import com.fdkankan.scene.vo.*;
+import com.fdkankan.web.controller.BaseController;
+import com.fdkankan.web.response.ResultData;
+import lombok.extern.log4j.Log4j2;
+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 java.io.IOException;
+
+/**
+ * 场景编辑管理
+ */
+@Log4j2
+@RestController
+@RequestMapping("/service/scene/edit/sceneDraw")
+public class SceneEditDrawController extends BaseController {
+
+    @Autowired
+    private ISceneDrawService sceneDrawService;
+
+    @CheckPermit
+    @GetMapping(value = "/list")
+    public ResultData listSceneDraw(@RequestParam("num") String num) throws Exception {
+        return ResultData.ok(sceneDrawService.listSceneDraw(num));
+    }
+
+    @CheckPermit
+    @PostMapping(value = "/save")
+    public ResultData saveSceneDraw(@RequestBody @Validated BaseJsonArrayParamVO param) throws Exception {
+        sceneDrawService.saveSceneDraw(param);
+        return ResultData.ok();
+    }
+
+    @CheckPermit
+    @PostMapping(value = "/delete")
+    public ResultData deleteSceneDraw(@RequestBody @Validated DeleteSidListParamVO param) throws Exception {
+        sceneDrawService.deleteSceneDraw(param);
+        return ResultData.ok();
+    }
+
+
+
+}

+ 21 - 0
src/main/java/com/fdkankan/scene/controller/SceneProEditController.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>
+ * pro场景编辑数据表 前端控制器
+ * </p>
+ *
+ * @author 
+ * @since 2024-07-31
+ */
+@RestController
+@RequestMapping("/scene/sceneProEdit")
+public class SceneProEditController {
+
+}
+

+ 48 - 0
src/main/java/com/fdkankan/scene/entity/FolderScene.java

@@ -0,0 +1,48 @@
+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 2024-07-31
+ */
+@Getter
+@Setter
+@TableName("t_folder_scene")
+public class FolderScene implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    @TableField("folder_id")
+    private Long folderId;
+
+    @TableField("scene_id")
+    private Long sceneId;
+
+    @TableField("rec_status")
+    @TableLogic(value = "A",delval = "I")
+    private String recStatus;
+
+    @TableField("create_time")
+    private Date createTime;
+
+    @TableField("update_time")
+    private Date updateTime;
+
+
+}

+ 66 - 0
src/main/java/com/fdkankan/scene/entity/SceneDynamicPanel.java

@@ -0,0 +1,66 @@
+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 2024-05-21
+ */
+@Getter
+@Setter
+@TableName("t_scene_dynamic_panel")
+public class SceneDynamicPanel implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 主键
+     */
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 场景码
+     */
+    @TableField("num")
+    private String num;
+
+    /**
+     * sid
+     */
+    @TableField("sid")
+    private String sid;
+
+    /**
+     * 创建时间
+     */
+    @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;
+
+
+}

+ 32 - 2
src/main/java/com/fdkankan/scene/entity/SceneEditControls.java

@@ -9,10 +9,10 @@ import java.util.Date;
 
 /**
  * <p>
- * 
+ *
  * </p>
  *
- * @author 
+ * @author
  * @since 2022-01-20
  */
 @Getter
@@ -137,6 +137,36 @@ public class SceneEditControls implements Serializable {
     @TableField("show_link_title")
     private Integer showLinkTitle;
 
+    /**
+     * 是否显示空间绘制标题
+     */
+    @TableField("show_draw_title")
+    private Integer showDrawTitle;
+
+    /**
+     * 是否显示全部模型
+     */
+    @TableField("show_all_model")
+    private Integer showAllModel;
+
+    /**
+     * 是否显示监控范围
+     */
+    @TableField("show_surveil_scope")
+    private Integer showSurveilScope;
+
+    /**
+     * 是否显示cad底图
+     */
+    @TableField("show_texture")
+    private Integer showTexture;
+
+    /**
+     * 是否显示cad底图
+     */
+    @TableField("show_panos")
+    private Integer showPanos;
+
 
     /**
      * 创建时间

+ 26 - 2
src/main/java/com/fdkankan/scene/entity/SceneEditInfoExt.java

@@ -11,10 +11,10 @@ import lombok.Setter;
 
 /**
  * <p>
- * 
+ *
  * </p>
  *
- * @author 
+ * @author
  * @since 2022-03-07
  */
 @Getter
@@ -97,12 +97,36 @@ public class SceneEditInfoExt {
     private Integer billboards;
 
     /**
+     * 是否有指示牌(0-否,1-是)
+     */
+    @TableField("cut_model")
+    private Integer cutModel;
+
+    /**
+     * 是否有指示牌(0-否,1-是)
+     */
+    @TableField("scene_draw")
+    private Integer sceneDraw;
+
+    /**
      * 分享配置信息
      */
     @TableField("sns_info")
     private String snsInfo;
 
     /**
+     * 启动页信息
+     */
+    @TableField("started")
+    private String started;
+
+    /**
+     * 地面logo类型(0-指北针,1-图标)
+     */
+    @TableField("floor_logo_type")
+    private Integer floorLogoType;
+
+    /**
      * 创建时间
      */
     @TableField("create_time")

+ 10 - 3
src/main/java/com/fdkankan/scene/entity/ScenePlusExt.java

@@ -12,10 +12,10 @@ import lombok.Setter;
 
 /**
  * <p>
- * 
+ *
  * </p>
  *
- * @author 
+ * @author
  * @since 2022-03-16
  */
 @Getter
@@ -151,6 +151,9 @@ public class ScenePlusExt implements Serializable {
     @TableField("yun_file_bucket")
     private String yunFileBucket;
 
+    @TableField("orientation")
+    private String orientation;
+
     /**
      * 创建时间
      */
@@ -170,5 +173,9 @@ public class ScenePlusExt implements Serializable {
     @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
-
+    /**
+     * 是否是mesh场景
+     */
+    @TableField("is_obj")
+    private Integer isObj;
 }

+ 285 - 0
src/main/java/com/fdkankan/scene/entity/SceneProEdit.java

@@ -0,0 +1,285 @@
+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>
+ * pro场景编辑数据表
+ * </p>
+ *
+ * @author 
+ * @since 2024-07-31
+ */
+@Getter
+@Setter
+@TableName("t_scene_pro_edit")
+public class SceneProEdit implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * pro场景id
+     */
+    @TableField("pro_id")
+    private Long proId;
+
+    /**
+     * 创建时间
+     */
+    @TableField("create_time")
+    private Date createTime;
+
+    /**
+     * 大场景的密钥
+     */
+    @TableField("scene_key")
+    private String sceneKey;
+
+    /**
+     * 展示页面密码,0不需要,1需要
+     */
+    @TableField("need_key")
+    private Integer needKey;
+
+    /**
+     * 版本
+     */
+    @TableField("version")
+    private Integer version;
+
+    /**
+     * 表示缩略图是否存在
+     */
+    @TableField("thumb_status")
+    private Integer thumbStatus;
+
+    /**
+     * 地面点位标志
+     */
+    @TableField("marker_logo")
+    private String markerLogo;
+
+    /**
+     * 0表示默认,1表示自己上传
+     */
+    @TableField("floor_logo")
+    private String floorLogo;
+
+    /**
+     * 标记大小
+     */
+    @TableField("floor_logo_size")
+    private Integer floorLogoSize;
+
+    /**
+     * 要上传的热点的id集合,用逗号隔开
+     */
+    @TableField("hots_ids")
+    private String hotsIds;
+
+    /**
+     * 表示初始点信息
+     */
+    @TableField("entry")
+    private String entry;
+
+    /**
+     * 背景音乐名称
+     */
+    @TableField("bg_music")
+    private String bgMusic;
+
+    /**
+     * 记录的状态,A: 生效,I: 禁用
+     */
+    @TableField("rec_status")
+    @TableLogic(value = "A",delval = "I")
+    private String recStatus;
+
+    /**
+     * 更新时间
+     */
+    @TableField("update_time")
+    private Date updateTime;
+
+    /**
+     * 普通录屏文件地址
+     */
+    @TableField("screencap_voice_src")
+    private String screencapVoiceSrc;
+
+    /**
+     * 录音文件地址
+     */
+    @TableField("screencap_voice_sound")
+    private String screencapVoiceSound;
+
+    /**
+     * 同步录音地址
+     */
+    @TableField("screencap_voice_soundsync")
+    private String screencapVoiceSoundsync;
+
+    /**
+     * 选择的类型,sound为screencapVoiceSound,file为screencapVoiceSrc,soundsync为screencap_voice_soundsync
+     */
+    @TableField("screencap_voice_type")
+    private String screencapVoiceType;
+
+    /**
+     * 录屏文件地址
+     */
+    @TableField("play_data")
+    private String playData;
+
+    /**
+     * 重新建模的版本
+     */
+    @TableField("floor_edit_ver")
+    private Integer floorEditVer;
+
+    /**
+     * 正式发布重新建模的版本
+     */
+    @TableField("floor_publish_ver")
+    private Integer floorPublishVer;
+
+    /**
+     * 录屏图片存放文件
+     */
+    @TableField("screencap_thumb")
+    private String screencapThumb;
+
+    /**
+     * 分享的logo和生成二维码的logo
+     */
+    @TableField("share_logo")
+    private String shareLogo;
+
+    /**
+     * 小地图浏览
+     */
+    @TableField("map_visi")
+    private Integer mapVisi;
+
+    /**
+     * 自动导览
+     */
+    @TableField("tour_visi")
+    private Integer tourVisi;
+
+    /**
+     * vr模式
+     */
+    @TableField("vr_visi")
+    private Integer vrVisi;
+
+    /**
+     * 展示页面是否显示标尺
+     */
+    @TableField("ruler_visi")
+    private Integer rulerVisi;
+
+    /**
+     * 展示页面cad图在平面图是否显示
+     */
+    @TableField("cad_img_visi")
+    private Integer cadImgVisi;
+
+    /**
+     * cad平面图
+     */
+    @TableField("floor_plan_png")
+    private String floorPlanPng;
+
+    /**
+     * cad平面图参数
+     */
+    @TableField("cad_info")
+    private String cadInfo;
+
+    @TableField("pano_visi")
+    private Integer panoVisi;
+
+    @TableField("m2d_visi")
+    private Integer m2dVisi;
+
+    @TableField("m3d_visi")
+    private Integer m3dVisi;
+
+    @TableField("measure_visi")
+    private Integer measureVisi;
+
+    /**
+     * 肖安需求,场景于场景之间的关联
+     */
+    @TableField("link_scene")
+    private String linkScene;
+
+    @TableField("overlay")
+    private String overlay;
+
+    /**
+     * 是否显示底部logo,1显示,0不显示
+     */
+    @TableField("show_logo_bottom")
+    private Boolean showLogoBottom;
+
+    /**
+     * 全景图版本号
+     */
+    @TableField("images_version")
+    private Integer imagesVersion;
+
+    /**
+     * 上传的背景音乐
+     */
+    @TableField("bg_music_name")
+    private String bgMusicName;
+
+    @TableField("jump_scene")
+    private Boolean jumpScene;
+
+    /**
+     * 旋转角度
+     */
+    @TableField("floor_plan_angle")
+    private String floorPlanAngle;
+
+    /**
+     * 场景下载次数
+     */
+    @TableField("download_num")
+    private Integer downloadNum;
+
+    /**
+     * 绿幕抠图json数据
+     */
+    @TableField("videos_user")
+    private String videosUser;
+
+    /**
+     * 大场景序号(随心装场景码)
+     */
+    @TableField("vr_num")
+    private String vrNum;
+
+    /**
+     * 随心装封面图
+     */
+    @TableField("vr_thumb")
+    private String vrThumb;
+
+
+}

+ 4 - 1
src/main/java/com/fdkankan/scene/entity/SceneResource.java

@@ -12,7 +12,7 @@ import java.util.Date;
  * 场景资源表
  * </p>
  *
- * @author 
+ * @author
  * @since 2022-01-20
  */
 @Getter
@@ -55,6 +55,9 @@ public class SceneResource implements Serializable {
     @TableField("description")
     private String description;
 
+    @TableField("version")
+    private String version;
+
     /**
      * 创建时间
      */

+ 20 - 0
src/main/java/com/fdkankan/scene/entity/Surveillance.java

@@ -65,6 +65,26 @@ public class Surveillance implements Serializable {
     private String playUrl;
 
     /**
+     * 类型
+     */
+    @TableField("url_type")
+    private Integer urlType;
+
+
+    /**
+     * 播放地址
+     */
+    @TableField("file_name")
+    private String  fileName;
+
+    /**
+     * 封面图
+     */
+    @TableField("poster")
+    private String  poster;
+
+
+    /**
      * 创建时间
      */
     @TableField("create_time")

+ 20 - 0
src/main/java/com/fdkankan/scene/mapper/IFolderSceneMapper.java

@@ -0,0 +1,20 @@
+package com.fdkankan.scene.mapper;
+
+import com.fdkankan.scene.entity.FolderScene;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * <p>
+ * 文件夹和场景关联表 Mapper 接口
+ * </p>
+ *
+ * @author 
+ * @since 2024-07-31
+ */
+@Mapper
+public interface IFolderSceneMapper extends BaseMapper<FolderScene> {
+
+    FolderScene getByType(@Param("sceneId")Long sceneId, @Param("type")Integer type);
+}

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

@@ -0,0 +1,18 @@
+package com.fdkankan.scene.mapper;
+
+import com.fdkankan.scene.entity.SceneDynamicPanel;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 场景动态面板 Mapper 接口
+ * </p>
+ *
+ * @author 
+ * @since 2024-05-21
+ */
+@Mapper
+public interface ISceneDynamicPanelMapper extends BaseMapper<SceneDynamicPanel> {
+
+}

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

@@ -0,0 +1,18 @@
+package com.fdkankan.scene.mapper;
+
+import com.fdkankan.scene.entity.SceneProEdit;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * pro场景编辑数据表 Mapper 接口
+ * </p>
+ *
+ * @author 
+ * @since 2024-07-31
+ */
+@Mapper
+public interface ISceneProEditMapper extends BaseMapper<SceneProEdit> {
+
+}

+ 47 - 0
src/main/java/com/fdkankan/scene/mq/consumer/CopySceneConsumer.java

@@ -0,0 +1,47 @@
+package com.fdkankan.scene.mq.consumer;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fdkankan.redis.util.RedisUtil;
+import com.fdkankan.scene.service.ISceneCopyService;
+import com.rabbitmq.client.Channel;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.annotation.Queue;
+import org.springframework.amqp.rabbit.annotation.RabbitListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 场景封存解封 mq
+ */
+@Slf4j
+@Component
+public class CopySceneConsumer {
+
+
+    @Autowired
+    ISceneCopyService sceneCopyService;
+    @RabbitListener(
+            queuesToDeclare = @Queue("${queue.scene.copy:ucenter-copy-scene}") ,
+            concurrency = "1"
+    )
+    public void consumerQueue(Channel channel, Message message)  {
+        try {
+            String messageId = message.getMessageProperties().getMessageId();
+            String msg = new String(message.getBody(), StandardCharsets.UTF_8);
+            log.info("copy-scene--messageId:{},msg:{}",messageId,msg);
+            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
+
+            JSONObject jsonObject = JSONObject.parseObject(msg);
+            String oldNum = jsonObject.getString("oldNum");
+            String newNum = jsonObject.getString("newNum");
+            sceneCopyService.copyScene(oldNum,newNum);
+        }catch (Exception e){
+            log.info("copy-scene----消费失败",e);
+        }
+
+    }
+
+}

+ 33 - 0
src/main/java/com/fdkankan/scene/mq/consumer/SceneResourcePath.java

@@ -0,0 +1,33 @@
+package com.fdkankan.scene.mq.consumer;
+
+public class SceneResourcePath {
+    /*
+     * data/data{SceneNum}
+     * images/images{SceneNum}
+     * video/video{SceneNum}
+     * voice/voice{SceneNum}
+     */
+    public static String nasBasePath = "/mnt/4Dkankan/scene/";
+    public static String nasBasePath_v4 = "/mnt/4Dkankan/scene_v4/";
+    public static String qrCodeBasePath = "/mnt/4Dkankan/sceneQRcode/";
+
+    public static String dataPath = "data/data%s";
+    public static String imagesPath = "images/images%s";
+    public static String videoPath = "video/video%s";
+    public static String voicePath = "voice/voice%s";
+
+
+    public static final String EDIT_PATH_v4 =  "scene_edit_data/%s/";
+    public static final String VIEW_PATH_v4 =  "scene_view_data/%s/";
+
+    public static final String SCENE_RESULT_DATA_PATH = "scene_result_data/%s/";
+
+    public static final String DATA_EDIT_PATH =  "scene_edit_data/%s/data";
+    public static final String DATA_VIEW_PATH =  "scene_view_data/%s/data";
+    public static final String USER_VIEW_PATH =  "scene_view_data/%s/user";
+    public static final String DYNAMIC_VIEW_PATH =  "scene_view_data/%s/user/dynamicPanel.json";
+    public static final String DYNAMIC_EDIT_PATH =  "scene_edit_data/%s/user/dynamicPanel.json";
+
+    public static final String DOWNLOADS_QRCODE = "downloads/scene/%s/QRcode/";
+
+}

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

@@ -14,4 +14,6 @@ public interface ICommonService {
      *               value: Map<String ,Object> 参数map
      */
     public void initUserEditData(String num, Set<String> bizs, Map<String, Map<String ,Object>> params);
+
+    void transferToFlv(String num, String fileName, String bucket) throws Exception;
 }

+ 27 - 0
src/main/java/com/fdkankan/scene/service/ICutModelService.java

@@ -0,0 +1,27 @@
+package com.fdkankan.scene.service;
+
+import cn.hutool.core.collection.CollUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.fdkankan.model.constants.UploadFilePath;
+import com.fdkankan.redis.constant.RedisKey;
+import com.fdkankan.scene.vo.BaseJsonArrayParamVO;
+import com.fdkankan.scene.vo.BaseSceneParamVO;
+import com.fdkankan.scene.vo.DeleteSidListParamVO;
+import com.fdkankan.web.response.ResultData;
+
+import java.io.IOException;
+import java.util.List;
+import java.util.stream.Collectors;
+
+public interface ICutModelService {
+
+    ResultData saveCutModel(BaseJsonArrayParamVO param) throws Exception;
+
+    List<JSONObject> listCutModel(BaseSceneParamVO param) throws Exception;
+
+    ResultData deleteCutModel(DeleteSidListParamVO param) throws Exception;
+
+    void publicCutModel(String num, String bucket) throws IOException;
+
+}

+ 17 - 0
src/main/java/com/fdkankan/scene/service/IFolderSceneService.java

@@ -0,0 +1,17 @@
+package com.fdkankan.scene.service;
+
+import com.fdkankan.scene.entity.FolderScene;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 文件夹和场景关联表 服务类
+ * </p>
+ *
+ * @author 
+ * @since 2024-07-31
+ */
+public interface IFolderSceneService extends IService<FolderScene> {
+
+    FolderScene getByType(Long sceneId, Integer type);
+}

+ 4 - 0
src/main/java/com/fdkankan/scene/service/ILaserService.java

@@ -14,4 +14,8 @@ public interface ILaserService {
 
     public void editScene(String num, LaserSceneBean sceneBean);
 
+    void copy(String oldNum , String newNum, String  path,Boolean flag);
+
+    void cloudPointBuild(String oldNum, String newNum);
+
 }

+ 8 - 2
src/main/java/com/fdkankan/scene/service/ISceneAsynOperLogService.java

@@ -1,5 +1,7 @@
 package com.fdkankan.scene.service;
 
+import com.fdkankan.common.constant.SceneAsynFuncType;
+import com.fdkankan.common.constant.SceneAsynOperType;
 import com.fdkankan.scene.entity.SceneAsynOperLog;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.fdkankan.scene.vo.SceneAsynOperLogParamVO;
@@ -12,13 +14,17 @@ import org.springframework.web.bind.annotation.RequestBody;
  *  服务类
  * </p>
  *
- * @author 
+ * @author
  * @since 2022-12-07
  */
 public interface ISceneAsynOperLogService extends IService<SceneAsynOperLog> {
 
     ResultData getAsynOperLog(SceneAsynOperLogParamVO param);
 
-    void cleanDownloadPanorama();
+    void cleanDownloadOssPage(String asynFuncType, int preMonth);
+
+    void checkSceneAsynOper(String num, String operType, String module, String function);
+
+    void cleanLog(String num, String moduleType, String funcType, String... operTypes);
 
 }

+ 6 - 0
src/main/java/com/fdkankan/scene/service/ISceneCopyService.java

@@ -0,0 +1,6 @@
+package com.fdkankan.scene.service;
+
+public interface ISceneCopyService {
+
+    void copyScene(String oldNum,String newNum);
+}

+ 20 - 0
src/main/java/com/fdkankan/scene/service/ISceneDrawService.java

@@ -0,0 +1,20 @@
+package com.fdkankan.scene.service;
+
+import com.alibaba.fastjson.JSONObject;
+import com.fdkankan.scene.vo.BaseJsonArrayParamVO;
+import com.fdkankan.scene.vo.DeleteSidListParamVO;
+
+import java.io.IOException;
+import java.util.List;
+
+public interface ISceneDrawService {
+
+    void saveSceneDraw(BaseJsonArrayParamVO param) throws Exception;
+
+    List<JSONObject> listSceneDraw(String num) throws Exception;
+
+    void deleteSceneDraw(DeleteSidListParamVO param) throws Exception;
+
+    void publicSceneDraw(String sceneNum, String bucket) throws IOException;
+
+}

+ 25 - 0
src/main/java/com/fdkankan/scene/service/ISceneDynamicPanelService.java

@@ -0,0 +1,25 @@
+package com.fdkankan.scene.service;
+
+import com.fdkankan.scene.entity.SceneDynamicPanel;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.scene.vo.BaseJsonDataParamVO;
+import com.fdkankan.scene.vo.SceneDynamicPanelVO;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 场景动态面板 服务类
+ * </p>
+ *
+ * @author
+ * @since 2024-05-21
+ */
+public interface ISceneDynamicPanelService extends IService<SceneDynamicPanel> {
+
+    List<SceneDynamicPanelVO> list(String num);
+
+    void update(BaseJsonDataParamVO param);
+
+    Byte checkDynamicPanel(String num);
+}

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

@@ -33,7 +33,7 @@ import org.springframework.web.multipart.MultipartFile;
  *  服务类
  * </p>
  *
- * @author 
+ * @author
  * @since 2022-01-18
  */
 public interface ISceneEditInfoService extends IService<SceneEditInfo> {
@@ -52,6 +52,10 @@ public interface ISceneEditInfoService extends IService<SceneEditInfo> {
 
     ResultData saveCad(BaseDataParamVO param) throws Exception;
 
+    ResultData uploadDxf(MultipartFile file, String num, Integer subgroup) throws Exception;
+
+    ResultData downloadDxf(String num, Integer subgroup) throws Exception;
+
     ResultData resetCad(String num) throws IOException;
 
     ResultData renameCad(RenameCadParamVO param) throws IOException;

+ 17 - 0
src/main/java/com/fdkankan/scene/service/ISceneProEditService.java

@@ -0,0 +1,17 @@
+package com.fdkankan.scene.service;
+
+import com.fdkankan.scene.entity.SceneProEdit;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * pro场景编辑数据表 服务类
+ * </p>
+ *
+ * @author 
+ * @since 2024-07-31
+ */
+public interface ISceneProEditService extends IService<SceneProEdit> {
+
+    SceneProEdit getByProId(Long sceneProId);
+}

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

@@ -46,9 +46,9 @@ public interface ISceneProService extends IService<ScenePro> {
 
     void updateUserIdByCameraId(Long userId, Long cameraId);
 
-    ResultData uploadObjAndImg(String num, MultipartFile file) throws Exception;
+    ResultData uploadModel(String num, MultipartFile file) throws Exception;
 
-    ResultData downloadTexData(String num) throws Exception;
+    ResultData downloadModel(String num) throws Exception;
 
     ScenePro getByNum(String num);
 

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

@@ -17,4 +17,6 @@ public interface ISceneResourceService extends IService<SceneResource> {
 
     List<SceneResource> findByCooperationId(Long id);
 
+    long countByVersion(String version);
+
 }

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

@@ -7,6 +7,7 @@ import com.fdkankan.web.response.ResultData;
 import org.springframework.web.multipart.MultipartFile;
 
 import java.nio.file.FileSystemException;
+import java.util.Map;
 
 public interface ISceneService extends IService<Scene> {
 
@@ -26,4 +27,6 @@ public interface ISceneService extends IService<Scene> {
 
     boolean updateStatus(String sceneCode, Integer status);
 
+    void saveSceneOientation(Map<String, Object> map);
+
 }

+ 5 - 3
src/main/java/com/fdkankan/scene/service/ISurveillanceService.java

@@ -6,6 +6,8 @@ import com.fdkankan.scene.vo.BaseSidParamVO;
 import com.fdkankan.scene.vo.SurveillanceParamVO;
 import com.fdkankan.scene.vo.SurveillanceVO;
 import com.fdkankan.web.response.ResultData;
+
+import java.io.IOException;
 import java.util.List;
 
 /**
@@ -13,14 +15,14 @@ import java.util.List;
  * 监控推拉流信息 服务类
  * </p>
  *
- * @author 
+ * @author
  * @since 2022-09-16
  */
 public interface ISurveillanceService extends IService<Surveillance> {
 
-    ResultData saveSurveillance(SurveillanceParamVO param);
+    ResultData saveSurveillance(SurveillanceParamVO param) throws Exception;
 
-    ResultData deleteSurveillance(BaseSidParamVO param);
+    ResultData deleteSurveillance(BaseSidParamVO param) throws IOException;
 
     List<SurveillanceVO> listSurveillance(String num);
 

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

@@ -0,0 +1,12 @@
+package com.fdkankan.scene.service;
+
+import com.fdkankan.web.response.ResultData;
+
+import java.util.List;
+import java.util.Map;
+
+public interface IVisionService {
+
+    List<Map<String, Object>> getPointLatAndLon(String num);
+
+}

+ 7 - 0
src/main/java/com/fdkankan/scene/service/IWbService.java

@@ -0,0 +1,7 @@
+package com.fdkankan.scene.service;
+
+public interface IWbService {
+
+    void sendMq(String num);
+
+}

+ 40 - 0
src/main/java/com/fdkankan/scene/service/impl/CommonServiceImpl.java

@@ -7,14 +7,26 @@ import com.fdkankan.scene.factory.UserEditData.UserEditDataHandlerFactory;
 import com.fdkankan.scene.service.ICommonService;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
+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.model.utils.CreateObjUtil;
+import com.fdkankan.scene.service.ICommonService;
+import org.springframework.stereotype.Service;
 
 import java.util.Map;
 import java.util.Set;
+import javax.annotation.Resource;
+import java.io.File;
 
 @Slf4j
 @Service
 public class CommonServiceImpl implements ICommonService {
 
+    @Resource
+    private FYunFileServiceInterface fYunFileService;
+
     @Override
     public void initUserEditData(String num, Set<String> bizs, Map<String, Map<String ,Object>> params) {
         if(StrUtil.isEmpty(num) || CollUtil.isEmpty(bizs)){
@@ -26,4 +38,32 @@ public class CommonServiceImpl implements ICommonService {
         }
     }
 
+    @Override
+    public void transferToFlv(String num, String fileName, String bucket) throws Exception {
+        String userEditPath = String.format(UploadFilePath.USER_EDIT_PATH, num);
+        String localImagesPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num);
+        String localFilePath = localImagesPath + fileName;
+
+        File targetFile = new File(localImagesPath);
+        if (!targetFile.exists()){
+            targetFile.mkdirs();
+        }
+
+        targetFile = new File(localFilePath);
+        if (targetFile.exists()){
+            FileUtils.deleteFile(localFilePath);
+        }
+
+        //从用户编辑目录中下载视频到本地
+        String filePath = userEditPath + fileName;
+        fYunFileService.downloadFile(bucket, filePath, localImagesPath + fileName);
+
+        //视频格式转换
+        CreateObjUtil.mp4ToFlv(localFilePath, localFilePath.replace("mp4", "flv"));
+
+        //上传
+        String flvFileName = fileName.replace("mp4", "flv");
+        fYunFileService.uploadFile(bucket, localFilePath.replace("mp4", "flv"), userEditPath+flvFileName);
+    }
+
 }

+ 264 - 0
src/main/java/com/fdkankan/scene/service/impl/CutModelServiceImpl.java

@@ -0,0 +1,264 @@
+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.update.LambdaUpdateWrapper;
+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.SceneEditInfoExt;
+import com.fdkankan.scene.entity.ScenePlus;
+import com.fdkankan.scene.entity.ScenePlusExt;
+import com.fdkankan.scene.service.*;
+import com.fdkankan.scene.vo.BaseJsonArrayParamVO;
+import com.fdkankan.scene.vo.BaseSceneParamVO;
+import com.fdkankan.scene.vo.DeleteFileParamVO;
+import com.fdkankan.scene.vo.DeleteSidListParamVO;
+import com.fdkankan.web.response.ResultData;
+import com.google.j2objc.annotations.AutoreleasePool;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+public class CutModelServiceImpl implements ICutModelService {
+
+    private final String CUT_MODEL_JSON_NAME = "cutModel.json";
+
+    @Autowired
+    private IScenePlusService scenePlusService;
+    @Autowired
+    private IScenePlusExtService scenePlusExtService;
+    @Autowired
+    private ISceneEditInfoExtService sceneEditInfoExtService;
+    @Autowired
+    private ISceneEditInfoService sceneEditInfoService;
+    @Autowired
+    private RedisUtil redisUtil;
+    @Autowired
+    private RedisLockUtil redisLockUtil;
+    @Autowired
+    private FYunFileServiceInterface fYunFileService;
+    @Autowired
+    private ISceneUploadService sceneUploadService;
+
+
+    @Override
+    public ResultData saveCutModel(BaseJsonArrayParamVO param) throws Exception {
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+
+        this.addOrUpdate(param.getNum(), param.getData());
+
+        //保存数据库
+        SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId());
+        this.updateDb(param.getNum(), scenePlus.getId());
+//        this.updateById(sceneEditInfoExt);
+
+        sceneEditInfoService.upgradeVersionById(sceneEditInfoExt.getEditInfoId());
+
+        return ResultData.ok();
+    }
+
+    @Override
+    public List<JSONObject> listCutModel(BaseSceneParamVO param) throws Exception {
+
+        List<JSONObject> tags = new ArrayList<>();
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+        SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId());
+
+        this.syncFileToRedis(param.getNum());
+
+        //获取裁剪模型数据
+        String key = String.format(RedisKey.SCENE_CUT_MODEL, 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());
+        }
+
+        return tags;
+    }
+
+    @Override
+    public ResultData deleteCutModel(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.syncFileToRedis(param.getNum());
+
+        //处理删除状态数据
+        List<String> deleteList = this.deleteCutModel(param.getNum(), deleteSidList, bucket);
+
+        //写入本地文件,作为备份
+        this.writeFile(param.getNum());
+
+        //保存数据库
+        SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId());
+        this.updateDb(param.getNum(), scenePlus.getId());
+        sceneEditInfoService.upgradeVersionById(sceneEditInfoExt.getEditInfoId());
+
+        return ResultData.ok();
+    }
+
+    @Override
+    public void publicCutModel(String sceneNum, String bucket) throws IOException {
+        String Key = String.format(RedisKey.SCENE_CUT_MODEL, sceneNum);
+        String userEditPath = String.format(UploadFilePath.USER_EDIT_PATH, sceneNum) + "cutModel.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);
+    }
+
+    private List<String> deleteCutModel(String num, List<String> deleteSidList, String bucket) throws Exception {
+        if(CollUtil.isEmpty(deleteSidList)){
+            return null;
+        }
+
+        //从redis中加载热点数据
+        String key = String.format(RedisKey.SCENE_CUT_MODEL, num);
+        List<String> deletDataList = redisUtil.hMultiGet(key, deleteSidList);
+        if(CollUtil.isNotEmpty(deletDataList)){
+            redisUtil.hdel(key, deleteSidList.toArray());
+        }
+        return deletDataList;
+    }
+
+    private void updateDb(String num, Long scenePlusId){
+        //查询缓存是否包含热点数据
+        String key = String.format(RedisKey.SCENE_CUT_MODEL, num);
+        Map<String, String> cutModelMap = redisUtil.hmget(key);
+        boolean hasCutModel= false;
+        for (Map.Entry<String, String> tagMap : cutModelMap.entrySet()) {
+            if(StrUtil.isEmpty(tagMap.getValue())){
+                continue;
+            }
+            hasCutModel = true;
+            break;
+        }
+
+        //更改热点状态
+        sceneEditInfoExtService.update(
+                new LambdaUpdateWrapper<SceneEditInfoExt>()
+                        .set(SceneEditInfoExt::getCutModel, hasCutModel ? CommonStatus.YES.code().intValue() : CommonStatus.NO.code().intValue())
+                        .eq(SceneEditInfoExt::getScenePlusId,scenePlusId));
+    }
+
+    private void addOrUpdate(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.syncFileToRedis(num);
+
+        //处理新增和修改数据
+        this.addOrUpdateHandler(num, addOrUpdateMap);
+    }
+
+    private void addOrUpdateHandler(String num, Map<String, String> addOrUpdateMap){
+        if(CollUtil.isEmpty(addOrUpdateMap))
+            return;
+
+        //批量写入缓存
+        String key = String.format(RedisKey.SCENE_CUT_MODEL, num);
+        redisUtil.hmset(key, addOrUpdateMap);
+
+        //写入本地文件,作为备份
+        this.writeFile(num);
+    }
+
+    private void writeFile(String num){
+        String lockKey = String.format(RedisLockKey.LOCK_CUT_MODEL_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_CUT_MODEL, num);
+            String cutModelJsonPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + CUT_MODEL_JSON_NAME;
+            if(!redisUtil.hasKey(dataKey)){
+                FileUtil.del(cutModelJsonPath);
+                return;
+            }
+            Map<String, String> cutModelmap = redisUtil.hmget(dataKey);
+            List<JSONObject>  list = cutModelmap.entrySet().stream().map(entry->JSON.parseObject(entry.getValue())).collect(Collectors.toList());
+            FileUtil.writeUtf8String(JSON.toJSONString(list), cutModelJsonPath);
+        }finally {
+            redisLockUtil.unlockLua(lockKey, lockVal);
+        }
+    }
+
+    private void syncFileToRedis(String num) throws Exception{
+
+        String key = String.format(RedisKey.SCENE_CUT_MODEL, num);
+        boolean exist = redisUtil.hasKey(key);
+        if(exist){
+            return;
+        }
+        String lockKey = String.format(RedisLockKey.LOCK_CUT_MODEL_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 cutModelFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + CUT_MODEL_JSON_NAME;
+            String cutModelData = FileUtils.readUtf8String(cutModelFilePath);
+            if(StrUtil.isEmpty(cutModelData)){
+                return;
+            }
+            JSONArray tagsArr = JSON.parseArray(cutModelData);
+            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);
+        }
+    }
+
+}

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

@@ -0,0 +1,24 @@
+package com.fdkankan.scene.service.impl;
+
+import com.fdkankan.scene.entity.FolderScene;
+import com.fdkankan.scene.mapper.IFolderSceneMapper;
+import com.fdkankan.scene.service.IFolderSceneService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 文件夹和场景关联表 服务实现类
+ * </p>
+ *
+ * @author 
+ * @since 2024-07-31
+ */
+@Service
+public class FolderSceneServiceImpl extends ServiceImpl<IFolderSceneMapper, FolderScene> implements IFolderSceneService {
+
+    @Override
+    public FolderScene getByType(Long sceneId, Integer type) {
+        return getBaseMapper().getByType(sceneId,type);
+    }
+}

+ 59 - 0
src/main/java/com/fdkankan/scene/service/impl/LaserServiceImpl.java

@@ -11,6 +11,16 @@ import com.fdkankan.scene.util.forest.HttpClient;
 import com.fdkankan.scene.util.forest.SuccessCallback;
 import java.io.File;
 import javax.annotation.PostConstruct;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
+import com.fdkankan.rabbitmq.util.RabbitMqProducer;
+import com.fdkankan.scene.service.ILaserService;
+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 java.util.HashMap;
+import java.util.Map;
 
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -36,6 +46,22 @@ public class LaserServiceImpl implements ILaserService {
     private String host = "127.0.0.1";
     private int port;
 
+    @Autowired
+    RabbitMqProducer rabbitMqProducer;
+    @Autowired
+    private FYunFileServiceInterface fYunFileService;
+
+    @Value("${4dkk.laserService.cloud-point-fyun-path:testdata/%s/data/bundle_%s/building/}")
+    private String cloudPointFyunPath;
+    @Value("${4dkk.laserService.bucket:laser-data}")
+    private String bucket;
+    @Value("${queue.application.laser.cloud-point-build:laser-cloud-point-build}")
+    private String cloudPointBuild;
+    @Value("${queue.application.laser.copy-scene:laser-copy-scene}")
+    private String laserCopyScene;
+    @Value("${queue.application.laser.copy-scene:laser-copy-scene-init}")
+    private String laserInitCopyScene;
+
     @PostConstruct
     public void initAddress(){
         String setting = fdkkLaserConfig.getBinPath() + File.separator + "setting.json";
@@ -51,4 +77,37 @@ public class LaserServiceImpl implements ILaserService {
         String api = String.format(LaserApiConstant.EDIT_SCENE, num);
         httpClient.postJson(host, port, api, sceneBean, new SuccessCallback(), new ErrorCallback());
     }
+
+    @Override
+    public void copy(String oldNum, String newNum, String path, Boolean flag) {
+        Map<String,Object> params = new HashMap<>();
+        params.put("sceneCode", newNum);
+        params.put("oldSceneCode", oldNum);
+        params.put("path",path);
+        params.put("init",flag);
+        if(flag){
+            rabbitMqProducer.sendByWorkQueue(laserInitCopyScene,params);
+            return;
+        }
+        rabbitMqProducer.sendByWorkQueue(laserCopyScene,params);
+    }
+
+    @Override
+    public void cloudPointBuild(String oldSceneCode,String sceneCode) {
+        if (!fYunFileService.fileExist(bucket,String.format(cloudPointFyunPath,oldSceneCode,oldSceneCode) +"vision_edit.txt")){
+            return;
+        }
+        log.info("开始同步点云编辑文件");
+        // 上传点云编辑文件,并通知激光系统
+        fYunFileService.copyFileBetweenBucket(bucket,String.format(cloudPointFyunPath,oldSceneCode,oldSceneCode) + "vision_edit.txt",
+                bucket,String.format(cloudPointFyunPath,sceneCode,sceneCode) + "vision_edit.txt");
+
+        fYunFileService.copyFileBetweenBucket(bucket,String.format(cloudPointFyunPath,oldSceneCode,oldSceneCode) + "uuidcloud",
+                bucket,String.format(cloudPointFyunPath,sceneCode,sceneCode) + "uuidcloud");
+
+        Map<String, Object> params = new HashMap<>();
+        params.put("sceneNum", sceneCode);
+        params.put("businessType", 0);
+        rabbitMqProducer.sendByWorkQueue(cloudPointBuild, params);
+    }
 }

+ 45 - 7
src/main/java/com/fdkankan/scene/service/impl/SceneAsynOperLogServiceImpl.java

@@ -3,6 +3,7 @@ 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.ArrayUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -11,6 +12,9 @@ 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.common.constant.*;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
 import com.fdkankan.scene.entity.SceneAsynOperLog;
 import com.fdkankan.scene.entity.ScenePlus;
 import com.fdkankan.scene.entity.ScenePlusExt;
@@ -24,6 +28,7 @@ import com.fdkankan.scene.vo.SceneAsynOperLogParamVO;
 import com.fdkankan.web.response.ResultData;
 import java.io.IOException;
 import java.nio.file.FileSystemException;
+import java.util.Arrays;
 import java.util.Calendar;
 import java.util.List;
 import java.util.stream.Collectors;
@@ -36,7 +41,7 @@ import org.springframework.stereotype.Service;
  *  服务实现类
  * </p>
  *
- * @author 
+ * @author
  * @since 2022-12-07
  */
 @Slf4j
@@ -87,20 +92,20 @@ public class SceneAsynOperLogServiceImpl extends ServiceImpl<ISceneAsynOperLogMa
     }
 
     @Override
-    public void cleanDownloadPanorama() {
+    public void cleanDownloadOssPage(String asynFuncType, int preMonth) {
 
         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()));
+                .eq(SceneAsynOperLog::getFunc, asynFuncType));
         if(CollUtil.isEmpty(downloadList)){
             return;
         }
-        DateTime preMonth = DateUtil.offsetMonth(Calendar.getInstance().getTime(), -1);
+        DateTime preDate = DateUtil.offsetMonth(Calendar.getInstance().getTime(), -preMonth);
         List<SceneAsynOperLog> deleteList = downloadList.parallelStream().filter(log -> {
-            if (log.getCreateTime().before(preMonth)) {
-                return Boolean.TRUE;
+            if (log.getCreateTime().before(preDate)) {
+                return true;
             }
             return false;
         }).collect(Collectors.toList());
@@ -119,10 +124,43 @@ public class SceneAsynOperLogServiceImpl extends ServiceImpl<ISceneAsynOperLogMa
                     ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
                     ossUtil.deleteObject(scenePlusExt.getYunFileBucket(), item.getUrl());
                 }catch (FileSystemException e){
-
+                    log.warn("删除oss下载压缩包失败,key:{}", item.getUrl());
                 }
             }
         });
 
     }
+
+    @Override
+    public 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 = this.list(queryWrapper);
+        if(CollUtil.isNotEmpty(waittingLogList)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5066);
+        }
+    }
+
+    @Override
+    public void cleanLog(String num, String moduleType, String funcType, String... operTypes) {
+        LambdaQueryWrapper<SceneAsynOperLog> wrapper = new LambdaQueryWrapper<SceneAsynOperLog>()
+                .eq(SceneAsynOperLog::getNum, num)
+                .eq(SceneAsynOperLog::getModule, moduleType)
+                .eq(SceneAsynOperLog::getFunc, funcType);
+        if(ArrayUtil.isNotEmpty(operTypes)){
+            wrapper.in(SceneAsynOperLog::getOperType, operTypes);
+        }
+        this.remove(wrapper);
+    }
 }

+ 490 - 0
src/main/java/com/fdkankan/scene/service/impl/SceneCopyServiceImpl.java

@@ -0,0 +1,490 @@
+package com.fdkankan.scene.service.impl;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.extra.qrcode.QrCodeUtil;
+import cn.hutool.extra.qrcode.QrConfig;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.fdkankan.common.constant.SceneVersionType;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.common.util.FileUtils;
+import com.fdkankan.common.util.SnowflakeIdGenerator;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
+import com.fdkankan.rabbitmq.util.RabbitMqProducer;
+import com.fdkankan.scene.entity.*;
+import com.fdkankan.scene.mq.consumer.SceneResourcePath;
+import com.fdkankan.scene.service.*;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import java.io.File;
+import java.util.*;
+
+@Service
+@Slf4j
+public class SceneCopyServiceImpl implements ISceneCopyService {
+
+    @Autowired
+    ISceneProService sceneProService;
+    @Autowired
+    ISceneProEditService sceneProEditService;
+    @Autowired
+    IScenePlusService scenePlusService;
+    @Autowired
+    IScenePlusExtService scenePlusExtService;
+    @Autowired
+    ISceneEditInfoService sceneEditInfoService;
+    @Autowired
+    ISceneEditInfoExtService sceneEditInfoExtService;
+    @Autowired
+    ISceneEditControlsService sceneEditControlsService;
+    @Autowired
+    ISurveillanceService surveillanceService;
+    @Autowired
+    IFolderSceneService folderSceneService;
+
+    @Autowired
+    ILaserService laserService;
+    @Autowired
+    FYunFileServiceInterface fYunFileServiceInterface;
+    @Autowired
+    RabbitMqProducer rabbitMqProducer;
+    @Override
+    public void copyScene(String oldNum, String newNum) {
+        ScenePro scenePro = sceneProService.getByNum(oldNum);
+        if(scenePro != null && scenePro.getIsUpgrade() == 0){
+            cpV3(scenePro,oldNum,newNum);
+        }
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(oldNum);
+        if(scenePlus != null){
+            cpV4(scenePlus,oldNum,newNum);
+        }
+    }
+
+    private void cpV4(ScenePlus scenePlus, String oldNum, String newNum) {
+        try {
+            Long plusId = scenePlus.getId();
+            ScenePlusExt plusExt = scenePlusExtService.getScenePlusExtByPlusId(plusId);
+            if(plusExt == null){
+                return;
+            }
+            scenePlus.setNum(newNum);
+            scenePlus.setTitle(scenePlus.getTitle() +"(copy)");
+            scenePlus.setSceneStatus(0);
+            scenePlus.setId(null);
+            scenePlusService.save(scenePlus);
+
+            this.saveFolder(plusId,scenePlus.getId());
+
+            String oldDataSource = plusExt.getDataSource();
+            String newDataSource = this.getNewDataSource(oldDataSource);
+            log.info("sceneCopy-V4-oldNum:{},oldDataSource:{},newNum:{},newDataSource:{}", oldNum,oldDataSource,newNum,newDataSource);
+
+            String newVideos = plusExt.getVideos();
+            if(StrUtil.isNotEmpty(newVideos)){
+                newVideos = plusExt.getVideos().replaceAll("/data/data" + oldNum, "/scene_view_data/" + newNum + "/data").replaceAll(oldNum, newNum);
+            }
+            plusExt.setId(null);
+            plusExt.setPlusId(scenePlus.getId());
+            plusExt.setDataSource(newDataSource);
+            plusExt.setWebSite(plusExt.getWebSite().replace(oldNum, newNum));
+            plusExt.setThumb(plusExt.getThumb().replace(oldNum, newNum));
+            plusExt.setVideos(newVideos);
+            plusExt.setViewCount(0);
+            scenePlusExtService.save(plusExt);
+
+            SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(plusId);
+            Long sceneEditInfoId = sceneEditInfo.getId();
+
+            sceneEditInfo.setId(null);
+            sceneEditInfo.setScenePlusId(scenePlus.getId());
+            sceneEditInfo.setSceneProId(null);
+            sceneEditInfo.setTitle(scenePlus.getTitle());
+            sceneEditInfoService.save(sceneEditInfo);
+
+            SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByEditInfoId(sceneEditInfoId);
+            sceneEditInfoExt.setId(null);
+            sceneEditInfoExt.setEditInfoId(sceneEditInfo.getId());
+            sceneEditInfoExt.setScenePlusId(scenePlus.getId());
+            sceneEditInfoExt.setSceneProId(null);
+            sceneEditInfoExtService.save(sceneEditInfoExt);
+
+            SceneEditControls sceneEditControls = sceneEditControlsService.getBySceneEditId(sceneEditInfoId);
+            sceneEditControls.setId(null);
+            sceneEditControls.setEditInfoId(sceneEditInfo.getId());
+            sceneEditControlsService.save(sceneEditControls);
+
+            List<Surveillance> list = surveillanceService.list(new LambdaQueryWrapper<Surveillance>().eq(Surveillance::getNum, oldNum));
+            if (!Objects.isNull(list)) {
+                list.stream().forEach(item -> {
+                    item.setNum(newNum);
+                    item.setId(null);
+                    surveillanceService.save(item);
+                });
+            }
+
+            if(scenePlus.getSceneSource() == 4 || scenePlus.getSceneSource() == 5){  //深时复制
+                laserService.copy(oldNum,newNum,newDataSource,true);
+            }else {
+                laserService.cloudPointBuild(oldNum,newNum);
+            }
+
+            //重新生成编辑页基础设置二维码
+            this.createNewQrCode(SceneVersionType.V4.code(),sceneEditInfoExt.getShareLogoImg(),newNum,plusExt.getWebSite());
+            //copyDataSource
+            //cn.hutool.core.io.FileUtil.copyContent(new File(oldDataSource),new File(newDataSource),true);
+
+            this.copyOssAndNasV4(oldNum,newNum);
+
+            //修改 oss status.json ,nas scene.json
+            String targetData = String.format(SceneResourcePath.DATA_VIEW_PATH,newNum);
+            this.updateOssJson(targetData,oldNum,newNum,"status.json");
+
+            this.updateNasSceneJson(targetData,oldNum,newNum,scenePlus.getTitle(),"v4","scene.json");
+
+            if(scenePlus.getSceneSource() == 4 || scenePlus.getSceneSource() == 5){  //深时复制
+                laserService.copy(oldNum,newNum,newDataSource,false);
+            }else {
+                scenePlus.setSceneStatus(-2);
+                scenePlusService.updateById(scenePlus);
+                sendMq(oldNum,newNum);
+            }
+        }catch (Exception e){
+            log.error("copy-V4-error-oldNum:{},newNum:{}",oldNum,newNum,e);
+            scenePlus.setSceneStatus(-1);
+            scenePlusService.updateById(scenePlus);
+        }
+
+    }
+
+    private void cpV3(ScenePro scenePro ,String oldNum,String newNum) {
+        try {
+            Long sceneProId = scenePro.getId();
+            scenePro.setNum(newNum);
+            scenePro.setId(null);
+            scenePro.setSceneName(scenePro.getSceneName() +"(copy)");
+            scenePro.setViewCount(0);
+            scenePro.setThumb(scenePro.getThumb().replaceAll(oldNum,scenePro.getNum()));
+            scenePro.setWebSite(scenePro.getWebSite().replaceAll(oldNum,scenePro.getNum()));
+            scenePro.setStatus(0);
+            sceneProService.save(scenePro);
+
+            this.saveFolder(sceneProId,scenePro.getId());
+
+            String oldDataSource = scenePro.getDataSource();
+            String newDataSource = this.getNewDataSource(oldDataSource);
+            if(StringUtils.isBlank(newDataSource)){
+                log.info("cpv3-error-newDataSource为空:{}",newDataSource);
+                return;
+            }
+            log.info("sceneCopy-v3-oldNum:{},oldDataSource:{},newNum:{},newDataSource:{}", oldNum,oldDataSource,newNum,newDataSource);
+            scenePro.setDataSource(newDataSource);
+
+            SceneProEdit oldEditScene = sceneProEditService.getByProId(sceneProId);
+            oldEditScene.setId(null);
+            oldEditScene.setProId(scenePro.getId());
+            oldEditScene.setScreencapVoiceSrc(oldEditScene.getScreencapVoiceSrc() == null ? null : oldEditScene.getScreencapVoiceSrc().replace(oldNum, scenePro.getNum()));
+            oldEditScene.setScreencapVoiceSound(oldEditScene.getScreencapVoiceSound() == null ? null : oldEditScene.getScreencapVoiceSound().replace(oldNum, scenePro.getNum()));
+            oldEditScene.setScreencapVoiceSoundsync(oldEditScene.getScreencapVoiceSoundsync() == null ? null : oldEditScene.getScreencapVoiceSoundsync().replace(oldNum, scenePro.getNum()));
+            oldEditScene.setPlayData(oldEditScene.getPlayData() == null ? null : oldEditScene.getPlayData().replace(oldNum, scenePro.getNum()));
+            oldEditScene.setScreencapThumb(oldEditScene.getScreencapThumb() == null ? null : oldEditScene.getScreencapThumb().replace(oldNum, scenePro.getNum()));
+            oldEditScene.setFloorPlanPng(oldEditScene.getFloorPlanPng() == null ? null : oldEditScene.getFloorPlanPng().replace(oldNum, scenePro.getNum()));
+            sceneProEditService.save(oldEditScene);
+
+            if(scenePro.getSceneSource() == 4 || scenePro.getSceneSource() == 5) {  //深时复制
+                laserService.copy(oldNum,newNum,newDataSource,true);
+            }
+            //重新生成编辑页基础设置二维码
+            this.createNewQrCode(SceneVersionType.V3.code(),oldEditScene.getShareLogo(),newNum,scenePro.getWebSite());
+            //copyDataSource
+            // cn.hutool.core.io.FileUtil.copyContent(new File(oldDataSource),new File(newDataSource),true);
+            String sourceData = String.format(SceneResourcePath.dataPath, oldNum);
+            String targetData = String.format(SceneResourcePath.dataPath, scenePro.getNum());
+            this.copyOssAndNasV3(oldNum,scenePro.getNum(),sourceData,targetData);
+            //修改 oss status.json ,nas scene.json
+            this.updateOssJson(targetData,oldNum,newNum,"status.json");
+            this.updateOssJson(targetData,oldNum,newNum,"hot.json");
+            this.updateNasSceneJson(targetData,oldNum,newNum,scenePro.getSceneName(),"v3","scene.json");
+            this.updateNasSceneJson(targetData,oldNum,newNum,scenePro.getSceneName(),"v3","hot.json");
+
+            String sourceImages = String.format(SceneResourcePath.imagesPath, oldNum);
+            String targetImages = String.format(SceneResourcePath.imagesPath, scenePro.getNum());
+            this.copyOssAndNasV3(oldNum,scenePro.getNum(),sourceImages,targetImages);
+
+            String sourceVideo = String.format(SceneResourcePath.videoPath, oldNum);
+            String targetVideo = String.format(SceneResourcePath.videoPath, scenePro.getNum());
+            this.copyOssAndNasV3(oldNum,scenePro.getNum(),sourceVideo,targetVideo);
+
+            String sourceVoice = String.format(SceneResourcePath.voicePath, oldNum);
+            String targetVoice = String.format(SceneResourcePath.voicePath, scenePro.getNum());
+            this.copyOssAndNasV3(oldNum,scenePro.getNum(),sourceVoice,targetVoice);
+
+            if(scenePro.getSceneSource() == 4 || scenePro.getSceneSource() == 5){  //深时复制
+                laserService.copy(oldNum,newNum,newDataSource,false);
+            }else {
+                scenePro.setStatus(-2);
+                sceneProService.updateById(scenePro);
+                sendMq(oldNum,newNum);
+            }
+        }catch (Exception e){
+            log.info("cpv3-error:{},{}",oldNum,newNum,e);
+            scenePro.setStatus(-1);
+            sceneProService.updateById(scenePro);
+        }
+
+    }
+
+    private void saveFolder(Long oldSceneId,Long newSceneId) {
+        FolderScene folderScene = folderSceneService.getByType(oldSceneId, null);
+        if(folderScene!= null){
+            folderScene.setId(null);
+            folderScene.setSceneId(newSceneId);
+            folderSceneService.save(folderScene);
+        }
+    }
+
+
+    @Value("${queue.scene.copy.result:ucenter-copy-scene-result}")
+    private String ucenterCpResultQueue;
+
+    private void sendMq(String oldNum, String newNum) {
+        HashMap<String,Object> map = new HashMap<>();
+        map.put("oldNum",oldNum);
+        map.put("newNum",newNum);
+        rabbitMqProducer.sendByWorkQueue(ucenterCpResultQueue,map);
+    }
+
+
+
+    public String getNewDataSource(String oldDataSource){
+
+        String newDataSource = null;
+        if(StringUtils.isBlank(oldDataSource)){
+            log.info("oldDataSource为空:{}",oldDataSource);
+            return null;
+        }
+        if(!oldDataSource.contains("/")){
+            log.info("oldDataSource格式错误:{}",oldDataSource);
+            return null;
+        }
+
+        String time = com.fdkankan.common.util.DateUtil.date2String(new Date(), com.fdkankan.common.util.DateUtil.YYYYMMDDHHMMSSSSS_DATA_FORMAT);
+        String[] split = oldDataSource.split("/");
+        if(split.length == 6 ){
+            String oldFileId = split[4];
+            Long fileId = new SnowflakeIdGenerator(1,1).nextId();
+            newDataSource = oldDataSource.replace(oldFileId,fileId.toString());
+
+            String snCodeTime = split[5];
+            if(!snCodeTime.contains("_") || snCodeTime.split("_").length <= 1){
+                log.info("oldDataSource格式错误:{}",oldDataSource);
+            }
+            newDataSource = newDataSource.replace(snCodeTime.split("_")[1],time);
+            //this.copyFdage(oldDataSource,newDataSource,time);
+        }
+        if(newDataSource == null){
+            log.info("newDataSource格式错误:{}",newDataSource);
+        }
+        return newDataSource;
+    }
+
+
+    public  void createNewQrCode(String sceneVersion,String logoPath ,String newNum, String webSite){
+        String localLogoPath = null;
+        try {
+            if(StringUtils.isNotBlank(logoPath)){
+                if(sceneVersion.equals(SceneVersionType.V3.code())){
+                    localLogoPath = SceneResourcePath.nasBasePath + logoPath;
+                }else{
+                    localLogoPath = SceneResourcePath.qrCodeBasePath + newNum +"/logo/logo.png";
+                    fYunFileServiceInterface.downloadFile(logoPath,localLogoPath);
+                }
+            }
+            String outPathZh = SceneResourcePath.qrCodeBasePath + newNum + ".png";
+            String outPathEn = SceneResourcePath.qrCodeBasePath + newNum + "_en.png";
+            QrConfig qrConfig = QrConfig.create();
+            qrConfig.setWidth(1024);
+            qrConfig.setHeight(1024);
+            if(!ObjectUtils.isEmpty(localLogoPath)){
+                qrConfig.setImg(localLogoPath);
+            }
+            QrCodeUtil.generate(webSite, qrConfig, FileUtil.file(outPathZh));
+            QrCodeUtil.generate(webSite + "&lang=en", qrConfig, FileUtil.file(outPathEn));
+
+            fYunFileServiceInterface.uploadFile(outPathZh, String.format(SceneResourcePath.DOWNLOADS_QRCODE, newNum) + newNum + ".png");
+            fYunFileServiceInterface.uploadFile(outPathEn, String.format(SceneResourcePath.DOWNLOADS_QRCODE, newNum) + newNum + "_en.png");
+        }catch (Exception e){
+            log.info("copy-scene-error:{},newNum:{},error:{}",newNum,e);
+        }
+
+    }
+
+
+    public void updateNasSceneJson(String targetPath, String oldNum, String newNum,String newSceneName,String sceneVersion,String fileName) {
+        String fileContent = null;
+        if("v3".equals(sceneVersion)){
+            String localPath = SceneResourcePath.nasBasePath + targetPath + "/" + fileName;
+            File file = new File(localPath);
+            if(!file.exists()){
+                log.error("sceneCopy-error--localFileExist:localPath:{},oldNum:{},newNum:{}",localPath,oldNum,newNum);
+                return;
+            }
+            fileContent = FileUtil.readUtf8String(file);
+        }
+        if("v4".equals(sceneVersion)){
+            String ossStatusJsonPath =  targetPath + "/" + fileName;
+            if(!fYunFileServiceInterface.fileExist(ossStatusJsonPath)){
+                log.error("sceneCopy-error--ossFileExist:targetPath:{},oldNum:{},newNum:{}",ossStatusJsonPath,oldNum,newNum);
+                return;
+            }
+            fileContent = fYunFileServiceInterface.getFileContent(ossStatusJsonPath);
+        }
+
+        if(StringUtils.isNotBlank(fileContent)){
+            //v3编辑器使用
+            String localPath = SceneResourcePath.nasBasePath + targetPath +"/" + fileName;
+            File file = new File(localPath);
+            if(!file.getParentFile().exists()){
+                file.getParentFile().mkdirs();
+            }
+            String newJson = fileContent.replaceAll(oldNum,newNum);
+            try {
+                if("v3".equals(sceneVersion)){
+                    if(fileName.contains("scene.json")){
+                        JSONObject jsonObject = JSONObject.parseObject(newJson);
+                        jsonObject.put("sceneName",newSceneName);
+                        FileUtils.writeFile(localPath ,jsonObject.toJSONString());
+                        String sceneJsonPath = String.format(SceneResourcePath.dataPath+"/"+fileName, newNum);
+                        fYunFileServiceInterface.uploadFile(localPath, sceneJsonPath);
+                    }else {
+                        FileUtils.writeFile(localPath ,newJson);
+                    }
+
+                }
+                if("v4".equals(sceneVersion)){
+                    JSONObject jsonObject = JSONObject.parseObject(newJson);
+                    jsonObject.put("title",newSceneName);
+                    jsonObject.put("dynamicPanel",0);
+                    FileUtils.writeFile(localPath, jsonObject.toJSONString());
+
+                    String sceneJsonPath = String.format(SceneResourcePath.DATA_VIEW_PATH+"/" + fileName, newNum);
+                    fYunFileServiceInterface.uploadFile(localPath, sceneJsonPath);
+
+                    //修改图片名称
+                    String filePath = String.format(SceneResourcePath.USER_VIEW_PATH, newNum) ;
+                    List<String> files = fYunFileServiceInterface.listRemoteFiles(filePath);
+                    for (String ossFilePath : files) {
+                        if(ossFilePath.contains(oldNum)){
+                            String oldName = ossFilePath;
+                            ossFilePath = ossFilePath.replace(oldNum,newNum);
+                            fYunFileServiceInterface.copyFileInBucket(oldName,ossFilePath);
+                            fYunFileServiceInterface.deleteFile(oldName);
+                        }
+                    }
+                    String dynamicViewPath = String.format(SceneResourcePath.DYNAMIC_VIEW_PATH, newNum);
+                    String dynamicEditPath = String.format(SceneResourcePath.DYNAMIC_EDIT_PATH, newNum);
+                    if(fYunFileServiceInterface.fileExist(dynamicViewPath)){
+                        fYunFileServiceInterface.deleteFile(dynamicViewPath);
+                    }
+                    if(fYunFileServiceInterface.fileExist(dynamicEditPath)){
+                        fYunFileServiceInterface.deleteFile(dynamicEditPath);
+                    }
+
+                }
+            }catch (Exception e){
+                log.error("writeFile-error:{}",e);
+            }
+
+        }
+
+    }
+
+
+    public void updateOssJson(String targetPath,String oldNum, String newNum,String fileName) {
+        String ossStatusJsonPath =  targetPath + "/" + fileName;
+
+        if(!fYunFileServiceInterface.fileExist(ossStatusJsonPath)){
+            log.error("sceneCopy-error--ossFileExist:targetPath:{},oldNum:{},newNum:{}",ossStatusJsonPath,oldNum,newNum);
+            return;
+        }
+        String localPath = SceneResourcePath.nasBasePath + ossStatusJsonPath;
+        File file = new File(localPath);
+        if(!file.getParentFile().exists()){
+            file.getParentFile().mkdirs();
+        }
+        String fileContent = fYunFileServiceInterface.getFileContent(ossStatusJsonPath);
+        if(StringUtils.isNotBlank(fileContent)){
+            String newJson = fileContent.replaceAll(oldNum,newNum);
+            try {
+                FileUtils.writeFile(localPath, newJson);
+                fYunFileServiceInterface.uploadFile(localPath,ossStatusJsonPath);
+            }catch (Exception e){
+                log.error("writeFile-error:{}",e);
+            }
+        }
+
+    }
+
+    private void copyOssAndNasV3(String oldNum ,String newNum ,String sourcePath,String targetPath){
+        log.info("sceneCopy-ossSource-oldNum:{},newNum:{},sourcePath:{},targetPath:{}",oldNum,newNum,sourcePath,targetPath);
+        fYunFileServiceInterface.copyFileInBucket(sourcePath,targetPath);
+        File fileData = new File(SceneResourcePath.nasBasePath + sourcePath);
+        if(fileData.exists()){
+            if(targetPath.contains("images")){
+                this.delLink(fileData.getPath());
+            }
+            cn.hutool.core.io.FileUtil.copyContent(fileData,new File(SceneResourcePath.nasBasePath + targetPath),true);
+        }
+    }
+    private  void copyOssAndNasV4(String oldNum,String newNum){
+        // 拷贝场景编辑资源
+        String oldEditPath = String.format(SceneResourcePath.EDIT_PATH_v4, oldNum);
+        String newEditPath = String.format(SceneResourcePath.EDIT_PATH_v4, newNum);
+        fYunFileServiceInterface.copyFileInBucket(oldEditPath, newEditPath);
+
+        // 拷贝场景展示资源
+        String oldViewPath = String.format(SceneResourcePath.VIEW_PATH_v4, oldNum);
+        String newViewPath = String.format(SceneResourcePath.VIEW_PATH_v4, newNum);
+        fYunFileServiceInterface.copyFileInBucket(oldViewPath, newViewPath);
+
+        //复制计算结果文件
+        String oldResultPath = String.format(SceneResourcePath.SCENE_RESULT_DATA_PATH, oldNum);
+        String newResultPath = String.format(SceneResourcePath.SCENE_RESULT_DATA_PATH, newNum);
+        fYunFileServiceInterface.copyFileInBucket(oldResultPath, newResultPath);
+
+        // 拷贝本地资源
+        String oldPath = SceneResourcePath.nasBasePath + oldNum;
+        String newPath = SceneResourcePath.nasBasePath + newNum;
+        if(new File(oldPath).exists()){
+            FileUtil.copyContent(new File(oldPath), new File(newPath),true);
+        }
+        String oldPath_v4 = SceneResourcePath.nasBasePath_v4 + oldNum;
+        String newPath_v4 = SceneResourcePath.nasBasePath_v4 + newNum;
+        if(new File(oldPath_v4).exists()){
+            FileUtil.copyContent(new File(oldPath_v4), new File(newPath_v4),true);
+        }
+    }
+
+
+    public void delLink(String path) {
+        String panPath = path +"/panorama";
+        File file = new File(panPath);
+        if(file.exists()){
+            File[] files = file.listFiles();
+            if(files == null || files.length == 0){
+                return;
+            }
+            for (File file1 : files) {
+                String linkPath =file1.getPath() + "/capture";
+                log.info("delLink--filePath:{}",linkPath);
+                org.apache.commons.io.FileUtils.deleteQuietly(new File(linkPath));
+            }
+        }
+    }
+
+}

+ 244 - 0
src/main/java/com/fdkankan/scene/service/impl/SceneDrawServiceImpl.java

@@ -0,0 +1,244 @@
+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.update.LambdaUpdateWrapper;
+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.SceneEditInfoExt;
+import com.fdkankan.scene.entity.ScenePlus;
+import com.fdkankan.scene.entity.ScenePlusExt;
+import com.fdkankan.scene.service.*;
+import com.fdkankan.scene.vo.BaseJsonArrayParamVO;
+import com.fdkankan.scene.vo.DeleteFileParamVO;
+import com.fdkankan.scene.vo.DeleteSidListParamVO;
+import com.fdkankan.web.response.ResultData;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+public class SceneDrawServiceImpl implements ISceneDrawService {
+
+    private final String SCENE_DRAW_JSON_NAME = "sceneDraw.json";
+
+    @Autowired
+    private IScenePlusService scenePlusService;
+    @Autowired
+    private IScenePlusExtService scenePlusExtService;
+    @Autowired
+    private RedisUtil redisUtil;
+    @Autowired
+    private RedisLockUtil redisLockUtil;
+    @Autowired
+    private ISceneEditInfoExtService sceneEditInfoExtService;
+    @Autowired
+    private ISceneEditInfoService sceneEditInfoService;
+    @Resource
+    private FYunFileServiceInterface fYunFileService;
+
+    @Override
+    public void saveSceneDraw(BaseJsonArrayParamVO param) throws Exception {
+
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+
+        this.addOrUpdate(param.getNum(), param.getData());
+
+        //保存数据库
+        SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId());
+        this.updateDb(param.getNum(), scenePlus.getId());
+
+        sceneEditInfoService.upgradeVersionById(sceneEditInfoExt.getEditInfoId());
+    }
+
+    private void updateDb(String num, Long scenePlusId){
+        //查询缓存是否包含热点数据
+        String key = String.format(RedisKey.SCENE_DRAW, num);
+        Map<String, String> map = redisUtil.hmget(key);
+        boolean hasSceneDraw= false;
+        for (Map.Entry<String, String> tagMap : map.entrySet()) {
+            if(StrUtil.isEmpty(tagMap.getValue())){
+                continue;
+            }
+            hasSceneDraw = true;
+            break;
+        }
+
+        //更改热点状态
+        sceneEditInfoExtService.update(
+                new LambdaUpdateWrapper<SceneEditInfoExt>()
+                        .set(SceneEditInfoExt::getSceneDraw, hasSceneDraw ? CommonStatus.YES.code().intValue() : CommonStatus.NO.code().intValue())
+                        .eq(SceneEditInfoExt::getScenePlusId,scenePlusId));
+    }
+
+    private void addOrUpdate(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.syncFileToRedis(num);
+
+        //处理新增和修改数据
+        this.addOrUpdateHandler(num, addOrUpdateMap);
+    }
+
+    private void addOrUpdateHandler(String num, Map<String, String> addOrUpdateMap){
+        if(CollUtil.isEmpty(addOrUpdateMap))
+            return;
+
+        //批量写入缓存
+        String key = String.format(RedisKey.SCENE_DRAW, num);
+        redisUtil.hmset(key, addOrUpdateMap);
+
+        //写入本地文件,作为备份
+        this.writeFile(num);
+    }
+
+    private void writeFile(String num){
+        String lockKey = String.format(RedisLockKey.LOCK_SCENE_DRAW, 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_DRAW, num);
+            String sceneDrawJsonPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + SCENE_DRAW_JSON_NAME;
+            if(!redisUtil.hasKey(dataKey)){
+                FileUtil.del(sceneDrawJsonPath);
+                return;
+            }
+            Map<String, String> map = redisUtil.hmget(dataKey);
+            List<JSONObject>  list = map.entrySet().stream().map(entry->JSON.parseObject(entry.getValue())).collect(Collectors.toList());
+            FileUtil.writeUtf8String(JSON.toJSONString(list), sceneDrawJsonPath);
+        }finally {
+            redisLockUtil.unlockLua(lockKey, lockVal);
+        }
+    }
+
+    private void syncFileToRedis(String num) throws Exception{
+
+        String key = String.format(RedisKey.SCENE_DRAW, num);
+        boolean exist = redisUtil.hasKey(key);
+        if(exist){
+            return;
+        }
+        String lockKey = String.format(RedisLockKey.LOCK_SCENE_DRAW, 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 sceneDrawFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + SCENE_DRAW_JSON_NAME;
+            String sceneDrawData = FileUtils.readUtf8String(sceneDrawFilePath);
+            if(StrUtil.isEmpty(sceneDrawData)){
+                return;
+            }
+            JSONArray tagsArr = JSON.parseArray(sceneDrawData);
+            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);
+        }
+    }
+
+    @Override
+    public List<JSONObject> listSceneDraw(String num) throws Exception {
+        List<JSONObject> tags = new ArrayList<>();
+        this.syncFileToRedis(num);
+
+        //获取裁剪模型数据
+        String key = String.format(RedisKey.SCENE_DRAW, num);
+        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());
+        }
+
+        return tags;
+    }
+
+    @Override
+    public void deleteSceneDraw(DeleteSidListParamVO param) throws Exception {
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+        List<String> deleteSidList = param.getSidList();
+        this.syncFileToRedis(param.getNum());
+        //处理删除状态数据
+        this.deleteCache(param.getNum(), deleteSidList);
+        //写入本地文件,作为备份
+        this.writeFile(param.getNum());
+        //保存数据库
+        SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId());
+        this.updateDb(param.getNum(), scenePlus.getId());
+        sceneEditInfoService.upgradeVersionById(sceneEditInfoExt.getEditInfoId());
+    }
+
+    private List<String> deleteCache(String num, List<String> deleteSidList) {
+        if(CollUtil.isEmpty(deleteSidList)){
+            return null;
+        }
+
+        //从redis中加载热点数据
+        String key = String.format(RedisKey.SCENE_DRAW, num);
+        List<String> deletDataList = redisUtil.hMultiGet(key, deleteSidList);
+        if(CollUtil.isNotEmpty(deletDataList)){
+            redisUtil.hdel(key, deleteSidList.toArray());
+        }
+        return deletDataList;
+    }
+
+    @Override
+    public void publicSceneDraw(String sceneNum, String bucket) throws IOException {
+        String Key = String.format(RedisKey.SCENE_DRAW, sceneNum);
+        String userEditPath = String.format(UploadFilePath.USER_EDIT_PATH, sceneNum) + SCENE_DRAW_JSON_NAME;
+        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);
+    }
+}

+ 101 - 0
src/main/java/com/fdkankan/scene/service/impl/SceneDynamicPanelServiceImpl.java

@@ -0,0 +1,101 @@
+package com.fdkankan.scene.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+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.fdkankan.common.constant.CommonStatus;
+import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
+import com.fdkankan.model.constants.UploadFilePath;
+import com.fdkankan.scene.entity.SceneDynamicPanel;
+import com.fdkankan.scene.entity.SceneEditInfo;
+import com.fdkankan.scene.entity.ScenePlus;
+import com.fdkankan.scene.mapper.ISceneDynamicPanelMapper;
+import com.fdkankan.scene.service.ISceneDynamicPanelService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.fdkankan.scene.service.ISceneEditInfoService;
+import com.fdkankan.scene.service.IScenePlusService;
+import com.fdkankan.scene.vo.BaseJsonDataParamVO;
+import com.fdkankan.scene.vo.SceneDynamicPanelVO;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 场景动态面板 服务实现类
+ * </p>
+ *
+ * @author
+ * @since 2024-05-21
+ */
+@Service
+public class SceneDynamicPanelServiceImpl extends ServiceImpl<ISceneDynamicPanelMapper, SceneDynamicPanel> implements ISceneDynamicPanelService {
+
+    @Resource
+    private FYunFileServiceInterface fileServiceInterface;
+    @Autowired
+    private ISceneEditInfoService sceneEditInfoService;
+    @Autowired
+    private IScenePlusService scenePlusService;
+
+    @Override
+    public List<SceneDynamicPanelVO> list(String num) {
+        List<SceneDynamicPanel> list = this.list(new LambdaQueryWrapper<SceneDynamicPanel>().eq(SceneDynamicPanel::getNum, num));
+        return BeanUtil.copyToList(list, SceneDynamicPanelVO.class);
+    }
+
+    @Override
+    public void update(BaseJsonDataParamVO param) {
+        JSONObject data = param.getData();
+        String sid = data.getString("sid");
+        if(StrUtil.isEmpty(sid)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_3001, "sid can not be null");
+        }
+
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+        SceneDynamicPanel one = this.getOne(new LambdaQueryWrapper<SceneDynamicPanel>().eq(SceneDynamicPanel::getNum, param.getNum()).eq(SceneDynamicPanel::getSid, sid));
+        if(Objects.isNull(one)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_3001, "sid error");
+        }
+
+        //上传文件
+        String editPath = String.format(UploadFilePath.USER_EDIT_PATH, param.getNum()) + "dynamicPanel.json";
+        String viewPath = String.format(UploadFilePath.USER_VIEW_PATH, param.getNum()) + "dynamicPanel.json";
+
+        String fileContent = fileServiceInterface.getFileContent(editPath);
+        JSONArray jsonArray = JSON.parseArray(fileContent);
+        Map<String, JSONObject> map = new HashMap<>();
+        jsonArray.stream().forEach(v->{
+            JSONObject obj = (JSONObject) v;
+            map.put(obj.getString("sid"), obj);
+        });
+        JSONObject oldObj = map.get(sid);
+        if(Objects.nonNull(oldObj)){
+            data.put("text", oldObj.get("text"));
+        }
+        map.put(sid, data);
+        Collection<JSONObject> values = map.values();
+        fileServiceInterface.uploadFile(JSON.toJSONString(values).getBytes(StandardCharsets.UTF_8), editPath);
+        fileServiceInterface.uploadFile(JSON.toJSONString(values).getBytes(StandardCharsets.UTF_8), viewPath);
+
+        //更新版本号
+        SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
+        sceneEditInfoService.upgradeVersionById(sceneEditInfo.getId());
+    }
+
+    @Override
+    public Byte checkDynamicPanel(String num) {
+        Long count = this.count(new LambdaQueryWrapper<SceneDynamicPanel>().eq(SceneDynamicPanel::getNum, num));
+        return count > 0 ? CommonStatus.YES.code() : CommonStatus.NO.code();
+    }
+}

+ 196 - 84
src/main/java/com/fdkankan/scene/service/impl/SceneEditInfoServiceImpl.java

@@ -5,6 +5,7 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.io.IORuntimeException;
 import cn.hutool.core.util.CharsetUtil;
+import cn.hutool.core.util.CharsetUtil;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.ZipUtil;
 import com.alibaba.fastjson.JSON;
@@ -17,7 +18,13 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fdkankan.common.constant.*;
 import com.fdkankan.common.exception.BusinessException;
 import com.fdkankan.common.util.FileSizeUtil;
+import com.fdkankan.common.util.FileMd5Util;
+import com.fdkankan.common.util.FileSizeUtil;
 import com.fdkankan.common.util.FileUtils;
+import com.fdkankan.dxf.parse.utils.FdJsonToDxfUtil;
+import com.fdkankan.fyun.config.FYunFileConfig;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
+import com.fdkankan.fyun.util.OssFileUtil;
 import com.fdkankan.model.constants.ConstantFilePath;
 import com.fdkankan.model.constants.UploadFilePath;
 import com.fdkankan.model.utils.ComputerUtil;
@@ -32,6 +39,8 @@ import com.fdkankan.scene.bean.*;
 import com.fdkankan.scene.config.FdkkLaserConfig;
 import com.fdkankan.scene.constant.ConstantFileLocPath;
 import com.fdkankan.scene.entity.*;
+import com.fdkankan.scene.bean.*;
+import com.fdkankan.scene.entity.*;
 import com.fdkankan.scene.mapper.ISceneEditInfoMapper;
 import com.fdkankan.scene.oss.OssUtil;
 import com.fdkankan.scene.service.*;
@@ -39,6 +48,8 @@ import com.fdkankan.scene.util.CmdBuildUtil;
 import com.fdkankan.scene.util.MergeVideoUtil;
 import com.fdkankan.scene.util.VisionUtil;
 import com.fdkankan.scene.vo.*;
+import com.fdkankan.scene.service.*;
+import com.fdkankan.scene.vo.*;
 import com.fdkankan.web.response.ResultData;
 import com.google.common.collect.Lists;
 import com.google.errorprone.annotations.Var;
@@ -49,11 +60,21 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 
+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 org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.FileSystemException;
 import java.util.*;
+import java.util.*;
 import java.util.Map.Entry;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicInteger;
@@ -105,6 +126,18 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
     private ISceneAsynOperLogService sceneAsynOperLogService;
     @Autowired
     private ISceneService sceneService;
+    @Autowired
+    private ICutModelService cutModelService;
+    @Autowired
+    private ICommonService commonService;
+    @Autowired
+    private FYunFileConfig fYunFileConfig;
+    @Autowired
+    private ISceneDrawService sceneDrawService;
+    @Autowired
+    private ISceneDynamicPanelService sceneDynamicPanelService;
+    @Autowired
+    private IWbService wbService;
 
     @Transactional
     @Override
@@ -136,6 +169,13 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         if(Objects.nonNull(param.getSns())){
             sceneEditInfoExt.setSnsInfo(JSON.toJSONString(param.getSns()));
         }
+        if(Objects.nonNull(param.getStarted())){
+            sceneEditInfoExt.setStarted(JSON.toJSONString(param.getStarted()));
+        }
+        sceneEditInfoExt.setFloorLogoType(param.getFloorLogoType());
+//        else{
+//            sceneEditInfoExt.setStarted("");
+//        }
         sceneEditInfoExtService.updateById(sceneEditInfoExt);
 
         if(Objects.nonNull(param.getControls())){
@@ -212,7 +252,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
 
         //生成sceneJson
         SceneJsonBean sceneJson = new SceneJsonBean();
-        BeanUtil.copyProperties(sceneEditInfoExt, sceneJson);
+        BeanUtil.copyProperties(sceneEditInfoExt, sceneJson, "started");
         BeanUtil.copyProperties(sceneEditInfo, sceneJson);
         sceneJson.setFloorPlanUpload(JSON.parseArray(sceneEditInfo.getFloorPlanUpload()));
         SceneEditControlsVO sceneEditControlsVO = BeanUtil.copyProperties(sceneEditControls, SceneEditControlsVO.class);
@@ -224,6 +264,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         sceneJson.setSceneFrom(scenePlusExt.getSceneFrom());
         sceneJson.setSceneKind(scenePlusExt.getSceneKind());
         sceneJson.setModelKind(scenePlusExt.getModelKind());
+        sceneJson.setOrientation(scenePlusExt.getOrientation());
         if(StrUtil.isNotEmpty(scenePlusExt.getVideos())){
             sceneJson.setVideos(scenePlusExt.getVideos());
         }
@@ -234,6 +275,9 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         //发布分享配置
         sceneJson.setSns(JSON.parseObject(sceneEditInfoExt.getSnsInfo()));
 
+        //发布启动页配置
+        sceneJson.setStarted(JSON.parseObject(sceneEditInfoExt.getStarted()));
+
         //处理热点数据,生成hot.json
         this.publicHotData(num, bucket);
 
@@ -249,6 +293,14 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         //发布指示牌数据
         this.publicBillboardData(num, bucket);
 
+        //发布模型裁剪
+        cutModelService.publicCutModel(num, bucket);
+
+        //发布场景绘制
+        sceneDrawService.publicSceneDraw(num, bucket);
+
+        sceneJson.setDynamicPanel(sceneDynamicPanelService.checkDynamicPanel(num));
+
         //本地写sceneJson文件
         String localSceneJsonPath = String.format(scenePlusExt.getDataSource()+ ConstantFileLocPath.SCENE_DATA_PATH_V4, num) + "scene.json";
         FileUtils.writeFile(localSceneJsonPath, JSON.toJSONString(sceneJson));
@@ -290,6 +342,9 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
 //        scenePlus.setHouseType(this.existsHouseType(bucket, num));
         scenePlusService.updateById(scenePlus);
 
+        //推送文保系统
+        wbService.sendMq(num);
+
         return ResultData.ok();
     }
 
@@ -334,10 +389,26 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         if(CollUtil.isEmpty(linkPanMap)){
             return;
         }
-        JSONArray linkPanArr = new JSONArray();
-        linkPanMap.values().stream().forEach(linkPan->{
-            linkPanArr.add(JSON.parseObject(linkPan));
-        });
+        List<JSONObject> tags = Lists.newArrayList();
+        List<TagBean> tagBeanList = new ArrayList<>();
+        if(CollUtil.isNotEmpty(linkPanMap)){
+            linkPanMap.entrySet().stream().forEach(entry -> {
+                JSONObject jsonObject = JSON.parseObject(entry.getValue());
+                tagBeanList.add(
+                        TagBean.builder()
+                                .createTime(jsonObject.getLong("createTime"))
+                                .tag(jsonObject).build());
+            });
+            //按创建时间倒叙排序
+            tagBeanList.sort(Comparator.comparingLong(TagBean::getCreateTime).reversed());
+
+            //移除createTime字段
+            tags = tagBeanList.stream().map(tagBean -> {
+                JSONObject tag = tagBean.getTag();
+                tag.remove("createTime");
+                return tag;
+            }).collect(Collectors.toList());
+        }
         String linkScenePath = userEditPath + "links.json";
         ossUtil.uploadFileBytes(bucket, linkScenePath, linkPanArr.toString().getBytes(StandardCharsets.UTF_8));
 
@@ -426,7 +497,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByEditInfoId(sceneEditInfo.getId());
         SceneEditControls sceneEditControls = sceneEditControlsService.getBySceneEditId(sceneEditInfo.getId());
         SceneInfoVO sceneInfoVO = new SceneInfoVO();
-        BeanUtil.copyProperties(sceneEditInfoExt, sceneInfoVO);
+        BeanUtil.copyProperties(sceneEditInfoExt, sceneInfoVO, "started");
         BeanUtil.copyProperties(sceneEditInfo, sceneInfoVO);
         sceneInfoVO.setFloorPlanUpload(JSON.parseArray(sceneEditInfo.getFloorPlanUpload()));
         if(Objects.isNull(sceneInfoVO.getFloorPlanAngle())){
@@ -449,18 +520,24 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         }
         sceneInfoVO.setSpace(FileSizeUtil.convert(scenePlusExt.getSpace(), FileSizeUnitType.MB.code()));
         sceneInfoVO.setSns(JSON.parseObject(sceneEditInfoExt.getSnsInfo()));
+        sceneInfoVO.setStarted(JSON.parseObject(sceneEditInfoExt.getStarted()));
+        sceneInfoVO.setOrientation(scenePlusExt.getOrientation());
 
         sceneInfoVO.setBucket(mappping);
 
         this.SortBoxVideos(sceneInfoVO);
 
+        this.setExtData(sceneInfoVO, scenePlus.getCameraId());
+
+        sceneInfoVO.setDynamicPanel(sceneDynamicPanelService.checkDynamicPanel(num));
+
         return sceneInfoVO;
     }
 
     public static void main(String[] args) {
-//        String test = "";
-//        JSONObject jsonObject = JSON.parseObject(test);
-        FileUtil.copyContent(new File("D:\\4DMega\\4DKK_PROGRAM_DATA\\dvt600001_202206291618176080\\caches\\images"), new File("/mnt/4Dkankan/scene/1680825957743071232/caches/"), true);
+        String test = "";
+        JSONObject jsonObject = JSON.parseObject(test);
+        System.out.println(jsonObject);
     }
 
     private void SortBoxVideos(SceneInfoVO sceneInfoVO){
@@ -555,6 +632,9 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         if(Objects.isNull(sceneInfoVO.getFloorPlanCompass())){
             sceneInfoVO.setFloorPlanCompass(0f);
         }
+        if(Objects.isNull(sceneInfoVO.getFloorLogoType())){
+            sceneInfoVO.setFloorLogoType(1);
+        }
         SceneEditControlsVO controls = sceneInfoVO.getControls();
         if(Objects.isNull(controls.getShowShare())){
             controls.setShowShare(CommonStatus.YES.code().intValue());
@@ -565,6 +645,14 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         if(Objects.isNull(controls.getShowBillboardTitle())){
             controls.setShowBillboardTitle(CommonStatus.YES.code().intValue());
         }
+        if(Objects.isNull(controls.getShowDrawTitle())){
+            controls.setShowDrawTitle(CommonStatus.YES.code().intValue());
+        }
+        if(Objects.isNull(controls.getShowSurveilScope())){
+            controls.setShowSurveilScope(CommonStatus.YES.code().intValue());
+        }
+
+        sceneInfoVO.setPayStatus(scenePlus.getPayStatus());
 
         return sceneInfoVO;
     }
@@ -643,6 +731,91 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
     }
 
     @Override
+    public ResultData uploadDxf(MultipartFile file, String num, Integer subgroup) throws Exception {
+
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
+        ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
+
+        String extName =  FileUtil.extName(file.getOriginalFilename());
+        if(!"dxf".equals(extName)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_7007.code(), ErrorCode.FAILURE_CODE_7007.formatMessage("dxf"));
+        }
+        String dfxPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + UUID.randomUUID() + "." + extName;
+        String floorplanUserPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + UUID.randomUUID() + ".json";
+        file.transferTo(new File(dfxPath));
+        try {
+            String editUserPath = String.format(UploadFilePath.USER_EDIT_PATH, num);
+            FdJsonToDxfUtil.dxfToFdJson(dfxPath, floorplanUserPath);
+
+            String floorplanUserStr = FileUtil.readUtf8String(floorplanUserPath);
+            JSONObject floorplanUserObj = JSON.parseObject(floorplanUserStr);
+            JSONArray floors = floorplanUserObj.getJSONArray("floors");
+            JSONObject floor = floors.getJSONObject(0);
+
+            String ossFloorplanUserStr = fYunFileService.getFileContent(editUserPath + "floorplan.json");
+            JSONObject ossFloorplanUserObj = JSON.parseObject(ossFloorplanUserStr);
+            JSONArray ossFloors = ossFloorplanUserObj.getJSONArray("floors");
+            for(int i = 0; i < ossFloors.size(); i++){
+                JSONObject item =  (JSONObject) ossFloors.get(i);
+                Integer itemSubgroup =  item.getInteger("subgroup");
+                if(itemSubgroup == subgroup){
+                    ossFloors.set(i, floor);
+                }
+            }
+
+            FileUtil.writeUtf8String(ossFloorplanUserObj.toJSONString(), floorplanUserPath);
+
+            fYunFileService.uploadFile(scenePlusExt.getYunFileBucket(), floorplanUserPath, editUserPath + "floorplan.json");
+            JSONObject houseTypeJson = CreateHouseJsonUtil
+                    .createHouseTypeJsonByUser(floorplanUserPath);
+            if(Objects.nonNull(houseTypeJson)) {
+                fYunFileService.uploadFile(scenePlusExt.getYunFileBucket(), houseTypeJson.toJSONString().getBytes(), editUserPath + "houseType.json");
+            }
+
+            SceneEditInfo sceneEditInfoDb = this.getByScenePlusId(scenePlus.getId());
+            this.update(new LambdaUpdateWrapper<SceneEditInfo>()
+                    .setSql("version=version+" + 1)
+                    .set(SceneEditInfo::getFloorPlanUser, 1)
+                    .eq(SceneEditInfo::getId, sceneEditInfoDb.getId()));
+
+            SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByEditInfoId(sceneEditInfoDb.getId());
+            sceneEditInfoExt.setFloorPlanAngle(0f);
+            sceneEditInfoExt.setFloorPlanCompass(0f);
+            sceneEditInfoExtService.saveOrUpdate(sceneEditInfoExt);
+        }catch (Exception e){
+            log.error("cad文件转换失败");
+            ResultData.error(ErrorCode.FAILURE_CODE_7013);
+        }finally {
+            FileUtil.del(dfxPath);
+            FileUtil.del(floorplanUserPath);
+        }
+
+        return ResultData.ok();
+    }
+
+    @Override
+    public ResultData downloadDxf(String num, Integer subgroup) throws Exception {
+
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
+        ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
+        SceneEditInfo sceneEditInfo = this.getByScenePlusId(scenePlus.getId());
+        String ossFloorplanPath = String.format(UploadFilePath.DATA_VIEW_PATH, num) + "floorplan.json";
+        if(Objects.nonNull(sceneEditInfo.getFloorPlanUser()) && sceneEditInfo.getFloorPlanUser() == CommonStatus.YES.code().intValue()){
+            ossFloorplanPath = String.format(UploadFilePath.USER_EDIT_PATH, num) + "floorplan.json";
+        }
+
+        String localFloorplan = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + UUID.randomUUID() + ".json";
+        fYunFileService.downloadFile(scenePlusExt.getYunFileBucket(), ossFloorplanPath, localFloorplan);
+        String localDxf = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + UUID.randomUUID() + ".dxf";
+        FdJsonToDxfUtil.fdJsonToDxf(localFloorplan, localDxf, subgroup);
+        String key = OssFileUtil.getUploadTempFileKey(null, "dxf");
+        fYunFileService.uploadFile(scenePlusExt.getYunFileBucket(), localDxf, key);
+        String url = fYunFileConfig.getHost() + key;
+
+        return ResultData.ok(url);
+    }
+
+    @Override
     public ResultData resetCad(String num) throws IOException {
 
         ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
@@ -917,15 +1090,10 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         }
 
         //查询是否存在等待中的异步操作记录,如果存在,抛出业务异常,终止操作
-        this.checkSceneAsynOper(num, null, SceneAsynModuleType.UPLOAD_DOWNLOAD.code() , SceneAsynFuncType.PANORAMIC_IMAGE.code());
+        sceneAsynOperLogService.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())
-        );
+        sceneAsynOperLogService.cleanLog(num, SceneAsynModuleType.UPLOAD_DOWNLOAD.code(), SceneAsynFuncType.PANORAMIC_IMAGE.code());
 
 
         ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
@@ -1115,26 +1283,6 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         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 {
         ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
         ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
@@ -1228,7 +1376,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         }
 
         //查询是否存在等待中的异步操作记录,如果存在,抛出业务异常,终止操作
-        this.checkSceneAsynOper(num,null, SceneAsynModuleType.UPLOAD_DOWNLOAD.code() , SceneAsynFuncType.PANORAMIC_IMAGE.code());
+        sceneAsynOperLogService.checkSceneAsynOper(num,null, SceneAsynModuleType.UPLOAD_DOWNLOAD.code() , SceneAsynFuncType.PANORAMIC_IMAGE.code());
 
         ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
         String bucket = scenePlusExt.getYunFileBucket();
@@ -1278,12 +1426,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
             return ResultData.ok(map);
         }else{
             //清除旧的下载记录
-            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()));
+            sceneAsynOperLogService.cleanLog(num, SceneAsynModuleType.UPLOAD_DOWNLOAD.code(), SceneAsynFuncType.PANORAMIC_IMAGE.code(), SceneAsynOperType.DOWNLOAD.code());
 
             //开始异步执行下载全景图压缩包操作
             CompletableFuture.runAsync(() -> {
@@ -1398,7 +1541,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         SceneEditInfo sceneEditInfo = this.getByScenePlusId(scenePlus.getId());
 
         //转换视频格式
-        this.transferToFlv(param.getNum(), param.getFileName(), bucket);
+        commonService.transferToFlv(param.getNum(), param.getFileName(), bucket);
 
         //生成boxVideos数据
         String boxVideos = this.createBoxVideos(param.getNum(), sid, boxVideo, sceneEditInfo, OperationType.ADDORUPDATE.code());
@@ -2616,38 +2759,6 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         return result;
     }
 
-    private void transferToFlv(String num, String fileName, String bucket) throws Exception {
-        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
-
-        ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
-
-        String userEditPath = String.format(UploadFilePath.USER_EDIT_PATH, num);
-        String localImagesPath = String.format(scenePlusExt.getDataSource()+ConstantFileLocPath.SCENE_DATA_PATH_V4, num);
-        String localFilePath = localImagesPath + fileName;
-
-        File targetFile = new File(localImagesPath);
-        if (!targetFile.exists()){
-            targetFile.mkdirs();
-        }
-
-        targetFile = new File(localFilePath);
-        if (targetFile.exists()){
-            FileUtils.deleteFile(localFilePath);
-        }
-
-        //从用户编辑目录中下载视频到本地
-        String filePath = userEditPath + fileName;
-        ossUtil.downloadFile(bucket, filePath, localImagesPath + fileName);
-
-        //视频格式转换
-        MergeVideoUtil.ffmpegFormatFlv(localFilePath, localFilePath.replace("mp4", "flv"));
-
-        //上传
-        String flvFileName = fileName.replace("mp4", "flv");
-        ossUtil.uploadFile(bucket,userEditPath+flvFileName, localFilePath.replace("mp4", "flv"), false);
-        FileUtil.del(localFilePath);
-    }
-
     @Override
     public ResultData deleteMosaics(DeleteMosaicParamVO param) throws Exception {
 
@@ -2733,23 +2844,24 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         }
 
         String key = String.format(RedisKey.SCENE_filter_DATA, param.getNum());
+        redisUtil.del(key);//前端将全量数据传过来,所以这里先清空历史数据,然后保存前端数据即可
         JSONArray filterArr = JSON.parseArray(param.getData());
         int filters = CommonStatus.YES.code();
-        if(CollUtil.isEmpty(filterArr)){
+        //如果页面选择恢复默认,filters字段值为否
+        if(Objects.nonNull(param.getReset()) && param.getReset() == CommonStatus.YES.code().intValue()){
             filters = CommonStatus.NO.code();
-            redisUtil.del(key);
         }else{
-            List<String> filterList = filterArr.stream().map(item->JSON.toJSONString(item)).collect(Collectors.toList());
-            redisUtil.lRightPushAll(key, filterList);
+            if(CollUtil.isNotEmpty(filterArr)){
+                List<String> filterList = filterArr.stream().map(item->JSON.toJSONString(item)).collect(Collectors.toList());
+                redisUtil.lRightPushAll(key, filterList);
+            }else{
+                filters = CommonStatus.NO.code();
+            }
         }
 
         //写本地文件,作为备份
         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());

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

@@ -0,0 +1,32 @@
+package com.fdkankan.scene.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.fdkankan.scene.entity.SceneProEdit;
+import com.fdkankan.scene.mapper.ISceneProEditMapper;
+import com.fdkankan.scene.service.ISceneProEditService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * pro场景编辑数据表 服务实现类
+ * </p>
+ *
+ * @author 
+ * @since 2024-07-31
+ */
+@Service
+public class SceneProEditServiceImpl extends ServiceImpl<ISceneProEditMapper, SceneProEdit> implements ISceneProEditService {
+
+    public SceneProEdit getByProId(Long proId) {
+        LambdaQueryWrapper<SceneProEdit> wrapper = new LambdaQueryWrapper<>();
+        wrapper.eq(SceneProEdit::getProId,proId);
+        List<SceneProEdit> list = this.list(wrapper);
+        if(list != null && list.size() >0){
+            return list.get(0);
+        }
+        return null;
+    }
+}

+ 239 - 86
src/main/java/com/fdkankan/scene/service/impl/SceneProServiceImpl.java

@@ -15,6 +15,9 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fdkankan.common.constant.*;
 import com.fdkankan.common.exception.BusinessException;
 import com.fdkankan.common.util.FileUtils;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.common.util.FileUtils;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
 import com.fdkankan.model.constants.ConstantFileName;
 import com.fdkankan.model.constants.ConstantFilePath;
 import com.fdkankan.model.constants.UploadFilePath;
@@ -32,17 +35,22 @@ import com.fdkankan.redis.util.RedisLockUtil;
 import com.fdkankan.redis.util.RedisUtil;
 import com.fdkankan.scene.bean.IconBean;
 import com.fdkankan.scene.bean.LaserSceneBean;
+import com.fdkankan.scene.bean.SceneBean;
 import com.fdkankan.scene.bean.TagBean;
 import com.fdkankan.scene.constant.ConstantFileLocPath;
 import com.fdkankan.scene.entity.SceneEditInfo;
 import com.fdkankan.scene.entity.ScenePlus;
 import com.fdkankan.scene.entity.ScenePlusExt;
 import com.fdkankan.scene.entity.ScenePro;
+import com.fdkankan.scene.entity.*;
 import com.fdkankan.scene.mapper.ISceneProMapper;
 import com.fdkankan.scene.oss.OssUtil;
 import com.fdkankan.scene.service.*;
 import com.fdkankan.scene.vo.*;
 import com.fdkankan.web.response.ResultData;
+import com.fdkankan.scene.service.*;
+import com.fdkankan.scene.vo.*;
+import com.fdkankan.web.response.ResultData;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import lombok.extern.slf4j.Slf4j;
@@ -52,6 +60,15 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.annotation.Resource;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.Map.Entry;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Collectors;
+
 import java.io.File;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
@@ -108,6 +125,8 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
     private ILaserService laserService;
     @Autowired
     private ISceneService sceneService;
+    @Autowired
+    private ISceneAsynOperLogService sceneAsynOperLogService;
 
     @Transactional
     @Override
@@ -484,15 +503,29 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
             return;
 
         //数据验证,新增、修改状态,hotdata不能为空
+        Set<String> linkSids = new HashSet<>();
         for (String sid : addOrUpdateMap.keySet()) {
             String hotData = addOrUpdateMap.get(sid);
             if(StrUtil.isEmpty(hotData)){
                 throw new BusinessException(ErrorCode.FAILURE_CODE_7004);
             }
+            JSONObject jsonObject = JSON.parseObject(hotData);
+            String type = jsonObject.getString("type");
+            if("link".equals(type)){
+                linkSids.add(sid);
+            }
         }
 
-        //批量写入缓存
+        //如果是修改,且由多媒体改成link的方式,将原有的多媒体文件删除
         String key = String.format(RedisKey.SCENE_HOT_DATA, num);
+        List<String> updateList = redisUtil.hMultiGet(key, new ArrayList<>(linkSids));
+        try {
+            this.deleteHotMediaFile(num, updateList, false);
+        }catch (Exception e){
+            log.error("删除多媒体文件失败", e);
+        }
+
+        //批量写入缓存
         redisUtil.hmset(key, addOrUpdateMap);
     }
 
@@ -510,34 +543,83 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
         List<String> deletDataList = redisUtil.hMultiGet(key, deleteSidList);
         if(CollUtil.isEmpty(deletDataList))
             return;
-        String userDataPath = String.format(UploadFilePath.USER_EDIT_PATH, num);
 
+        //从redis中移除热点数据
+        redisUtil.hdel(key, deleteSidList.toArray());
+
+        //删除图片音频视频等资源文件
+        this.deleteHotMediaFile(num, deletDataList, true);
+
+    }
+
+    private void deleteHotMediaFile(String num, List<String> hotdataList, boolean deleteBgm) throws Exception {
+        if(CollUtil.isEmpty(hotdataList)){
+            return;
+        }
         //删除图片音频视频等资源文件
-        for (String data : deletDataList) {
+        List<String> deleteFileList = new ArrayList<>();
+        for (String data : hotdataList) {
             if(StrUtil.isBlank(data)){
                 continue;
             }
             JSONObject jsonObject = JSON.parseObject(data);
-            String sid = jsonObject.getString("sid");
-            if(jsonObject.containsKey("media")){
-                String fileType = jsonObject.getString("media");
-                if(fileType.contains("photo"))
-                {
-                    ossUtil.deleteObject(bucket, userDataPath + "hot"+sid+".jpg");
-                }
-                if(fileType.contains("audio") || fileType.contains("voice"))
-                {
-                    ossUtil.deleteObject(bucket,userDataPath + "hot"+sid+".mp3");
+
+            //删除背景音乐
+            if(deleteBgm){
+                JSONObject bgm = jsonObject.getJSONObject("bgm");
+                if(Objects.nonNull(bgm) && StrUtil.isNotEmpty(bgm.getString("src"))){
+                    String bgmSrc = bgm.getString("src");
+                    deleteFileList.add(bgmSrc);
                 }
-                if(fileType.contains("video"))
+            }
+
+
+            String type = jsonObject.getString("type");
+
+            if("media".equals(type)){//V4.13.0版本改成这种方式
+                //删除图片、视频
+                JSONArray media = jsonObject.getJSONArray("media");
+                media.stream().forEach(v->{
+                    JSONObject o = (JSONObject) v;
+                    String src = o.getString("src");
+                    if(StrUtil.isNotEmpty(src)){
+                        deleteFileList.add(src);
+                    }
+                });
+            }
+
+            /* v4.12版本之前是这种方式
+            "media": {
+                "image": [
                 {
-                    ossUtil.deleteObject(bucket,userDataPath + "hot"+sid+".mp4");
+                    "src": "FfRdi413774.jpg"
                 }
+		    ]
+            },
+            "type": "image"
+             */
+            if("image".equals(type) || "audio".equals(type) || "video".equals(type)){
+                //删除图片、视频
+                JSONObject media = jsonObject.getJSONObject("media");
+                JSONArray jsonArray = media.getJSONArray(type);
+                jsonArray.stream().forEach(v->{
+                    JSONObject o = (JSONObject) v;
+                    String src = o.getString("src");
+                    if(StrUtil.isNotEmpty(src)){
+                        deleteFileList.add(src);
+                    }
+                });
             }
         }
 
-        //从redis中移除热点数据
-        redisUtil.hdel(key, deleteSidList.toArray());
+        if(CollUtil.isEmpty(deleteFileList)){
+            return;
+        }
+        sceneUploadService.delete(
+                DeleteFileParamVO.builder()
+                        .num(num)
+                        .fileNames(deleteFileList)
+                        .bizType("tag-media").build());
     }
 
     @Override
@@ -637,7 +719,7 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
                 String currentPanoId = jo.getString("panoID");
                 JSONArray visibles = jo.getJSONArray("visibles");
                 JSONArray visibles3 = jo.getJSONArray("visibles3");
-                if (pano.getString("uuid").equals(currentPanoId)) {
+                if (pano.getString("uuid").replaceAll("-", "").equals(currentPanoId)) {
                     pano.put("visibles", visibles);
                     pano.put("visibles3", visibles3);
                 }
@@ -672,7 +754,7 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
     }
 
     @Override
-    public ResultData uploadObjAndImg(String num, MultipartFile file) throws Exception{
+    public ResultData uploadModel(String num, MultipartFile file) throws Exception{
         if(StrUtil.isEmpty(num)){
             throw new BusinessException(ServerCode.PARAM_REQUIRED, "num");
         }
@@ -684,6 +766,13 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
         if(scenePlus == null){
             throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
         }
+
+        //查询是否存在等待中的异步操作记录,如果存在,抛出业务异常,终止操作
+        sceneAsynOperLogService.checkSceneAsynOper(num, null, SceneAsynModuleType.UPLOAD_DOWNLOAD.code() , SceneAsynFuncType.MODEL.code());
+
+        //清除全景图异步操作记录,防止再次下载的时候请求到旧的压缩包
+        sceneAsynOperLogService.cleanLog(num, SceneAsynModuleType.UPLOAD_DOWNLOAD.code(), SceneAsynFuncType.MODEL.code());
+
         ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
         String bucket = scenePlusExt.getYunFileBucket();
 
@@ -697,31 +786,10 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
             this.buildModel4Dam(num, bucket, dataSource, scenePlusExt.getBuildType(), file);
         }
 
-        //更新版本信息
-        SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
-        if(Objects.isNull(sceneEditInfo)){
-            sceneEditInfo = new SceneEditInfo();
-            sceneEditInfo.setScenePlusId(scenePlus.getId());
-            sceneEditInfo.setFloorPublishVer(1);
-            sceneEditInfo.setFloorEditVer(1);
-            sceneEditInfo.setIsUploadObj(CommonStatus.YES.code());
-            sceneEditInfoService.save(sceneEditInfo);
-        }else{
-            sceneEditInfoService.update(
-                new LambdaUpdateWrapper<SceneEditInfo>()
-                    .setSql("version = version + 1")
-                    .setSql("floor_edit_ver = floor_edit_ver + 1")
-                    .setSql("floor_publish_ver = floor_publish_ver + 1")
-                    .setSql("img_version = img_version + 1")
-                    .set(SceneEditInfo::getIsUploadObj, CommonStatus.YES.code())
-                    .eq(SceneEditInfo::getId, sceneEditInfo.getId()));
-
-            sceneEditInfoService.upgradeSceneJsonVersion(num, sceneEditInfo.getVersion() + 1, sceneEditInfo.getImgVersion() + 1, bucket);
-        }
-
         return ResultData.ok();
     }
 
+
     /**
      * 老算法(dam)上传模型逻辑
      * @param num
@@ -743,10 +811,41 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
         //创建data.json
         this.writeDataJson(path);
 
-        CmdBuildUtil.BuildModelCommand(path);
-
-        //算法计算完后,生成压缩文件,上传到oss
-        this.uploadFileofterRebuildPanoram(path, filePath, num, bucket);
+        CompletableFuture.runAsync(() -> {
+            SceneAsynOperLog sceneAsynOperLog = new SceneAsynOperLog();
+            sceneAsynOperLog.setNum(num);
+            sceneAsynOperLog.setOperType(SceneAsynOperType.UPLOAD.code());
+            sceneAsynOperLog.setModule(SceneAsynModuleType.UPLOAD_DOWNLOAD.code());
+            sceneAsynOperLog.setFunc(SceneAsynFuncType.MODEL.code());
+            sceneAsynOperLogService.save(sceneAsynOperLog);
+            try {
+                //调用算法,不同的类型调用不同的算法
+                CmdBuildUtil.BuildModelCommand(path);
+
+                //算法计算完后,生成压缩文件,上传到oss
+                uploadFileofterBuildDamModel(path, filePath, num, bucket);
+
+                //更新版本信息
+                ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
+                SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
+                sceneEditInfoService.update(
+                        new LambdaUpdateWrapper<SceneEditInfo>()
+                                .setSql("version = version + 1")
+                                .setSql("floor_edit_ver = floor_edit_ver + 1")
+                                .setSql("floor_publish_ver = floor_publish_ver + 1")
+                                .setSql("img_version = img_version + 1")
+                                .set(SceneEditInfo::getIsUploadObj, CommonStatus.YES.code())
+                                .eq(SceneEditInfo::getId, sceneEditInfo.getId()));
+
+                sceneEditInfoService.upgradeSceneJsonVersion(num, sceneEditInfo.getVersion() + 1, sceneEditInfo.getImgVersion() + 1, bucket);
+
+                sceneAsynOperLog.setState(CommonOperStatus.SUCCESS.code());
+            } catch (Exception e) {
+                log.error("上传dam模型,num:" + num, e);
+                sceneAsynOperLog.setState(CommonOperStatus.FAILD.code());
+            }
+            sceneAsynOperLogService.updateById(sceneAsynOperLog);
+        });
     }
 
     /**
@@ -841,40 +940,64 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
             }
         });
 
+        SceneAsynOperLog sceneAsynOperLog = new SceneAsynOperLog();
+        sceneAsynOperLog.setNum(num);
+        sceneAsynOperLog.setOperType(SceneAsynOperType.UPLOAD.code());
+        sceneAsynOperLog.setModule(SceneAsynModuleType.UPLOAD_DOWNLOAD.code());
+        sceneAsynOperLog.setFunc(SceneAsynFuncType.MODEL.code());
+        sceneAsynOperLogService.save(sceneAsynOperLog);
+        CompletableFuture.runAsync(() -> {
+            try {
+                //调用算法
+                String command = "bash /home/ubuntu/bin/Obj2Tiles.sh " + path;
+                log.info("上传3dtiles模型开始, num:{}, targetPath:{}", num, path);
+                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);
+                }
 
-        //调用算法
-        String command = "bash /home/ubuntu/bin/Obj2Tiles.sh " + path;
-        log.info("上传3dtiles模型开始, num:{}, targetPath:{}", num, path);
-        CmdBuildUtil.Build3dtilesModel(path);
-        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");
+
+                //更新版本信息
+                ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
+                SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
+                sceneEditInfoService.update(
+                        new LambdaUpdateWrapper<SceneEditInfo>()
+                                .setSql("version = version + 1")
+                                .setSql("floor_edit_ver = floor_edit_ver + 1")
+                                .setSql("floor_publish_ver = floor_publish_ver + 1")
+                                .setSql("img_version = img_version + 1")
+                                .set(SceneEditInfo::getIsUploadObj, CommonStatus.YES.code())
+                                .eq(SceneEditInfo::getId, sceneEditInfo.getId()));
+
+                sceneEditInfoService.upgradeSceneJsonVersion(num, sceneEditInfo.getVersion() + 1, sceneEditInfo.getImgVersion() + 1, bucket);
+
+                sceneAsynOperLog.setState(CommonOperStatus.SUCCESS.code());
+            } catch (Exception e) {
+                log.error("上传全景图报错,num:" + num, e);
+                sceneAsynOperLog.setState(CommonOperStatus.FAILD.code());
+            }
+            sceneAsynOperLogService.updateById(sceneAsynOperLog);
+        });
 
-        //删除logs
-        FileUtil.del(tilesPath + File.separator + "logs");
-
-        //算法计算完后,生成压缩文件,上传到oss
-        //上传3dtiles
-        ossUtil.deleteObject(bucket,String.format(UploadFilePath.IMG_VIEW_PATH, num) + "3dtiles");
-        FileUtil.copyContent(
-                FileUtil.file(tilesPath),
-                FileUtil.file(FdkkLaserConfig.getProfile(bucket) + File.separator + String.format(UploadFilePath.IMG_VIEW_PATH, num) + "3dtiles"),
-                true);
-        //上传mesh
-        ossUtil.deleteObject(bucket,String.format(UploadFilePath.DATA_VIEW_PATH, num) + "mesh");
-        FileUtil.copyContent(
-                FileUtil.file(meshPath),
-                FileUtil.file(FdkkLaserConfig.getProfile(bucket) + File.separator + String.format(UploadFilePath.DATA_VIEW_PATH, num) + "mesh"),
-                true);
     }
 
-    private void uploadFileofterRebuildPanoram(String path, String filePath, String sceneNum, String bucket) throws Exception {
+    private void uploadFileofterBuildDamModel(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);
@@ -1039,7 +1162,7 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
         }
     }
 
-    public ResultData downloadTexData(String num) throws Exception {
+    public ResultData downloadModel(String num) throws Exception {
 
         if(StrUtil.isEmpty(num)){
             throw new BusinessException(ErrorCode.PARAM_REQUIRED);
@@ -1048,16 +1171,46 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
         if(scenePlus == null){
             throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
         }
+
+        //查询是否存在等待中的异步操作记录,如果存在,抛出业务异常,终止操作
+        sceneAsynOperLogService.checkSceneAsynOper(num,null, SceneAsynModuleType.UPLOAD_DOWNLOAD.code() , SceneAsynFuncType.MODEL.code());
+
+        //清除旧的下载记录
+        sceneAsynOperLogService.cleanLog(num, SceneAsynModuleType.UPLOAD_DOWNLOAD.code(), SceneAsynFuncType.MODEL.code(), SceneAsynOperType.DOWNLOAD.code());
+
         ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
         String bucket = scenePlusExt.getYunFileBucket();
 
         SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
 
-        if(ModelKind.THREE_D_TILE.code().equals(scenePlusExt.getModelKind())){
-            return this.downloadModel43dtiles(num, bucket, scenePlusExt, sceneEditInfo);
-        }
+        //开始异步执行下载全景图压缩包操作
+        CompletableFuture.runAsync(() -> {
+            SceneAsynOperLog sceneAsynOperLog = new SceneAsynOperLog();
+            sceneAsynOperLog.setNum(num);
+            sceneAsynOperLog.setOperType(SceneAsynOperType.DOWNLOAD.code());
+            sceneAsynOperLog.setModule(SceneAsynModuleType.UPLOAD_DOWNLOAD.code());
+            sceneAsynOperLog.setFunc(SceneAsynFuncType.MODEL.code());
+            sceneAsynOperLog.setVersion(sceneEditInfo.getImgVersion());
+            sceneAsynOperLogService.save(sceneAsynOperLog);
+            try {
+
+                String url = null;
+                if(ModelKind.THREE_D_TILE.code().equals(scenePlusExt.getModelKind())){
+                    url = downloadModel43dtiles(num, bucket, scenePlusExt, sceneEditInfo);
+                }else{
+                    url = downloadModel4Dam(num, bucket);
+                }
 
-        return this.downloadModel4Dam(num, bucket);
+                sceneAsynOperLog.setState(CommonOperStatus.SUCCESS.code());
+                sceneAsynOperLog.setUrl(url);
+            }catch (Exception e){
+                sceneAsynOperLog.setState(CommonOperStatus.FAILD.code());
+                log.error("下载模型压缩包失败,num:" + num, e);
+            }
+            sceneAsynOperLogService.saveOrUpdate(sceneAsynOperLog);
+        });
+
+        return ResultData.ok();
     }
 
     @Override
@@ -1065,7 +1218,7 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
         return this.getOne(new LambdaQueryWrapper<ScenePro>().eq(ScenePro::getNum, num));
     }
 
-    private ResultData downloadModel43dtiles(String num, String bucket, ScenePlusExt scenePlusExt, SceneEditInfo sceneEditInfo){
+    private String downloadModel43dtiles(String num, String bucket, ScenePlusExt scenePlusExt, SceneEditInfo sceneEditInfo){
 
         //下载mesh到本地
         String meshOssPath = String.format(UploadFilePath.DATA_VIEW_PATH, num) + "mesh/";
@@ -1081,8 +1234,8 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
         //删除本地文件
         FileUtil.del(meshLocalPath.concat("mesh"));
         FileUtil.del(zipFilePath);
-        String url = "downloads/extras/" + zipName + "?t=" + Calendar.getInstance().getTimeInMillis();
-        return ResultData.ok(url);
+        String url = "downloads/extras/" + zipName;
+        return url;
     }
 
     public static void main(String[] args) {
@@ -1092,7 +1245,7 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
     }
 
 
-    private ResultData downloadModel4Dam(String num, String bucket){
+    private String downloadModel4Dam(String num, String bucket){
         String localImagePath = String.format(ConstantFilePath.IMAGESBUFFER_FORMAT, num);
         if(!new File(localImagePath).exists()){
             new File(localImagePath).mkdirs();
@@ -1137,9 +1290,9 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
         ZipUtil.zip(meshPath, zipPath);
         //上传压缩包
         ossUtil.uploadFile(bucket,"downloads/extras/" + zipName, zipPath, false);
-        String url = "downloads/extras/" + zipName + "?t=" + Calendar.getInstance().getTimeInMillis();
+        String url = "downloads/extras/" + zipName;
         FileUtil.del(zipPath);
-        return ResultData.ok(url);
+        return url;
     }
 
     @Override

+ 15 - 8
src/main/java/com/fdkankan/scene/service/impl/SceneResourceServiceImpl.java

@@ -3,6 +3,8 @@ 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.common.constant.ErrorCode;
+import com.fdkankan.common.exception.BusinessException;
 import com.fdkankan.scene.entity.SceneResource;
 import com.fdkankan.scene.entity.SceneResourceCooperation;
 import com.fdkankan.scene.mapper.ISceneResourceMapper;
@@ -18,7 +20,7 @@ import org.springframework.stereotype.Service;
  * 场景资源表 服务实现类
  * </p>
  *
- * @author 
+ * @author
  * @since 2022-07-18
  */
 @Service
@@ -30,21 +32,26 @@ public class SceneResourceServiceImpl extends ServiceImpl<ISceneResourceMapper,
     @Override
     public List<SceneResource> findByCooperationId(Long sceneCooperationId) {
 
+        long countV4Resource = this.countByVersion("v4");
+
         List<SceneResourceCooperation> sceneResourceCooperationList
             = sceneResourceCooperationService.list(
             new LambdaQueryWrapper<SceneResourceCooperation>()
                 .eq(SceneResourceCooperation::getSceneCooperationId, sceneCooperationId));
 
-        List<Long> sceneResourceIdList = null;
-        if(CollUtil.isNotEmpty(sceneResourceCooperationList)){
-            sceneResourceIdList = sceneResourceCooperationList.stream()
-                .map(sceneResourceCooperation -> sceneResourceCooperation.getSceneResourceId())
-                .collect(Collectors.toList());
-        }
-        if(CollUtil.isEmpty(sceneResourceIdList)){
+        if(countV4Resource == sceneResourceCooperationList.size()){//如果协作菜单数量与资源数量相同,则返回空,由前端判断当前用户拥有所有该场景编辑权限
             return null;
         }
 
+        List<Long> sceneResourceIdList = sceneResourceCooperationList.stream()
+                .map(sceneResourceCooperation -> sceneResourceCooperation.getSceneResourceId())
+                .collect(Collectors.toList());
+
         return this.listByIds(sceneResourceIdList);
     }
+
+    @Override
+    public long countByVersion(String version) {
+        return this.count(new LambdaQueryWrapper<SceneResource>().eq(SceneResource::getVersion, version));
+    }
 }

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

@@ -12,6 +12,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.fdkankan.common.constant.CommonOperStatus;
 import com.fdkankan.common.constant.ErrorCode;
 import com.fdkankan.common.constant.SceneConstant;
@@ -30,6 +31,11 @@ import com.fdkankan.scene.entity.*;
 import com.fdkankan.scene.mapper.ISceneMapper;
 import com.fdkankan.scene.oss.OssUtil;
 import com.fdkankan.scene.service.*;
+import com.fdkankan.scene.entity.ScenePlus;
+import com.fdkankan.scene.entity.ScenePlusExt;
+import com.fdkankan.scene.service.IScenePlusExtService;
+import com.fdkankan.scene.service.IScenePlusService;
+import com.fdkankan.scene.service.ISceneService;
 import com.fdkankan.scene.util.OssBodySegmentUtil;
 import com.fdkankan.scene.vo.SceneParamVO;
 import com.fdkankan.web.response.ResultData;
@@ -85,6 +91,12 @@ public class SceneServiceImpl extends ServiceImpl<ISceneMapper, Scene> implement
     private ISurveillanceService surveillanceService;
     @Autowired
     private ISceneService sceneService;
+    public FYunFileConfig fYunFileConfig;
+    @Autowired
+    public IScenePlusService scenePlusService;
+    @Autowired
+    public IScenePlusExtService scenePlusExtService;
+
     @Override
     public ResultData uploadBodySegment(MultipartFile file, Integer rotate) throws Exception {
 
@@ -181,6 +193,24 @@ public class SceneServiceImpl extends ServiceImpl<ISceneMapper, Scene> implement
     }
 
     @Override
+    public void saveSceneOientation(Map<String, Object> map) {
+        String num = (String) map.get("num");
+        String orientation = (String)map.get("orientation");
+        Integer status = (Integer)map.get("status");
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
+        if(Objects.isNull(scenePlus)){
+            return;
+        }
+        ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
+        if(status == 0){
+            scenePlusExtService.update(new LambdaUpdateWrapper<ScenePlusExt>().eq(ScenePlusExt::getId, scenePlusExt.getId()).setSql("orientation = null"));
+        }else{
+            scenePlusExt.setOrientation(orientation);
+            scenePlusExtService.updateById(scenePlusExt);
+        }
+    }
+
+    @Override
     public ResultData getBodySegmentStatus(String uuid) {
 
         String progress = redisUtil.get(String.format(RedisKey.SCENE_BODY_SEGMENT, uuid));

+ 8 - 4
src/main/java/com/fdkankan/scene/service/impl/SceneUploadServiceImpl.java

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
 import cn.hutool.core.thread.ThreadUtil;
 import cn.hutool.core.date.DateUtil;
 import cn.hutool.core.date.TimeInterval;
+import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -12,6 +13,7 @@ import com.fdkankan.common.constant.ErrorCode;
 import com.fdkankan.common.constant.RecStatus;
 import com.fdkankan.common.constant.ServerCode;
 import com.fdkankan.common.util.FileUtils;
+import com.fdkankan.model.constants.ConstantFilePath;
 import com.fdkankan.model.constants.UploadFilePath;
 import com.fdkankan.common.exception.BusinessException;
 import com.fdkankan.scene.oss.OssUtil;
@@ -50,7 +52,7 @@ import org.springframework.web.multipart.MultipartFile;
  *  服务实现类
  * </p>
  *
- * @author 
+ * @author
  * @since 2022-01-19
  */
 @Slf4j
@@ -137,8 +139,10 @@ public class SceneUploadServiceImpl extends ServiceImpl<ISceneUploadMapper, Scen
             String fileName = file.getOriginalFilename();
             // 获取文件后缀
             String prefix = fileName.substring(fileName.lastIndexOf("."));
-            File newFile = File.createTempFile(UUID.randomUUID().toString() ,prefix);
-            file.transferTo(newFile);
+            String path = String.format(ConstantFilePath.SCENE_TMP_PATH_V4, num).concat(UUID.randomUUID().toString()).concat(prefix);
+//            File newFile = File.createTempFile(UUID.randomUUID().toString() ,prefix);
+            FileUtil.mkParentDirs(path);
+            file.transferTo(new File(path));
             String realFileName = fileName;
             if(files.size() ==1 && StringUtils.isNotBlank(sendFileName)){
                 realFileName = sendFileName ;
@@ -160,7 +164,7 @@ public class SceneUploadServiceImpl extends ServiceImpl<ISceneUploadMapper, Scen
             try{
                 newFile.delete();
             }catch (Exception e){
-                log.error("delete tempFile error ,===="+newFile.getAbsoluteFile());
+                log.warn("delete tempFile error ,===="+newFile.getAbsoluteFile());
             }
             //添加记录
             this.saveData(num,ossPath,bizType,userId);

+ 61 - 13
src/main/java/com/fdkankan/scene/service/impl/SurveillanceServiceImpl.java

@@ -1,37 +1,39 @@
 package com.fdkankan.scene.service.impl;
 
 import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSON;
 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.ServerCode;
 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.fyun.face.FYunFileServiceInterface;
+import com.fdkankan.model.constants.UploadFilePath;
+import com.fdkankan.scene.entity.*;
 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.service.*;
 import com.fdkankan.scene.vo.BaseSidParamVO;
 import com.fdkankan.scene.vo.SurveillanceParamVO;
 import com.fdkankan.scene.vo.SurveillanceVO;
 import com.fdkankan.web.response.ResultData;
+
+import java.io.IOException;
 import java.util.List;
 import java.util.Objects;
 import java.util.stream.Collectors;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
+import javax.annotation.Resource;
+
 /**
  * <p>
  * 监控推拉流信息 服务实现类
  * </p>
  *
- * @author 
+ * @author
  * @since 2022-09-16
  */
 @Service
@@ -43,14 +45,37 @@ public class SurveillanceServiceImpl extends ServiceImpl<ISurveillanceMapper, Su
     private ISceneEditInfoExtService sceneEditInfoExtService;
     @Autowired
     private ISceneEditInfoService sceneEditInfoService;
+    @Resource
+    private FYunFileServiceInterface yunFileService;
+    @Autowired
+    private IScenePlusExtService scenePlusExtService;
+    @Autowired
+    private ICommonService commonService;
 
     @Override
-    public ResultData saveSurveillance(SurveillanceParamVO param) {
+    public ResultData saveSurveillance(SurveillanceParamVO param) throws Exception {
+
+        if(param.getUrlType() == 1){
+            if(StrUtil.isEmpty(param.getPlayUrl())){
+                throw new BusinessException(ServerCode.PARAM_REQUIRED.code(), ServerCode.PARAM_REQUIRED.formatMessage("playUrl"));
+            }
+        }else{
+            if(StrUtil.isEmpty(param.getFileName()) || StrUtil.isEmpty(param.getPoster())){
+                throw new BusinessException(ServerCode.PARAM_REQUIRED.code(), ServerCode.PARAM_REQUIRED.formatMessage("fileName、poster"));
+            }
+        }
 
         ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
         if(Objects.isNull(scenePlus)){
             throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
         }
+        ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
+
+        //转换视频格式
+        if(param.getUrlType() == 2){
+            commonService.transferToFlv(param.getNum(), param.getFileName(), scenePlusExt.getYunFileBucket());
+        }
+
         SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
         SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId());
 
@@ -64,25 +89,36 @@ public class SurveillanceServiceImpl extends ServiceImpl<ISurveillanceMapper, Su
         surveillance.setName(param.getName());
         surveillance.setData(param.getData().toJSONString());
         surveillance.setPlayUrl(param.getPlayUrl());
+        surveillance.setUrlType(param.getUrlType());
+        surveillance.setFileName(param.getFileName());
+        surveillance.setPoster(param.getPoster());
         this.saveOrUpdate(surveillance);
 
         sceneEditInfoExt.setSurveillances(CommonStatus.YES.code().intValue());
         sceneEditInfoExtService.updateById(sceneEditInfoExt);
-
         sceneEditInfoService.upgradeVersionById(sceneEditInfo.getId());
 
-
         return ResultData.ok();
     }
 
     @Override
-    public ResultData deleteSurveillance(BaseSidParamVO param) {
+    public ResultData deleteSurveillance(BaseSidParamVO param) throws IOException {
         ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
         if(Objects.isNull(scenePlus)){
             throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
         }
+
+        Surveillance surveillance = this.getBySid(param.getNum(), param.getSid());
+        if(Objects.isNull(surveillance)){
+            return ResultData.ok("sid不存在");
+        }
+
+        ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
         SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
         SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId());
+        String bucket = scenePlusExt.getYunFileBucket();
+
+
 
         this.remove(new LambdaQueryWrapper<Surveillance>().eq(Surveillance::getSid, param.getSid()));
 
@@ -90,6 +126,18 @@ public class SurveillanceServiceImpl extends ServiceImpl<ISurveillanceMapper, Su
         if(count < 1){
             sceneEditInfoExt.setSurveillances(CommonStatus.NO.code().intValue());
         }
+
+        //如果是视频类型监控,需要删除oss文件
+        if(surveillance.getUrlType() == 2){
+            String userEditPath = String.format(UploadFilePath.USER_EDIT_PATH, param.getNum());
+            if(StrUtil.isNotEmpty(surveillance.getFileName())){
+                yunFileService.deleteFile(bucket, userEditPath.concat(surveillance.getFileName()));
+            }
+            if(StrUtil.isNotEmpty(surveillance.getPoster())){
+                yunFileService.deleteFile(bucket, userEditPath.concat(surveillance.getPoster()));
+            }
+        }
+
         sceneEditInfoExtService.updateById(sceneEditInfoExt);
 
         sceneEditInfoService.upgradeVersionById(sceneEditInfo.getId());

+ 58 - 0
src/main/java/com/fdkankan/scene/service/impl/VisionServiceImpl.java

@@ -0,0 +1,58 @@
+package com.fdkankan.scene.service.impl;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
+import com.fdkankan.model.constants.UploadFilePath;
+import com.fdkankan.scene.service.IVisionService;
+import com.google.common.collect.Lists;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+@Service
+@Slf4j
+public class VisionServiceImpl implements IVisionService {
+
+    @Resource
+    private FYunFileServiceInterface fYunFileService;
+
+    @Override
+    public List<Map<String, Object>> getPointLatAndLon(String num) {
+        List<Map<String, Object>> list = Lists.newArrayList();
+        String visionTxt = fYunFileService.getFileContent(String.format(UploadFilePath.IMG_VIEW_PATH, num) + "vision.txt");
+        JSONObject visionJson = JSON.parseObject(visionTxt);
+        if(!visionJson.containsKey("sweepLocations")){
+            return list;
+        }
+        JSONArray sweepLocations = visionJson.getJSONArray("sweepLocations");
+        for (int i = 0; i < sweepLocations.size(); ++i) {
+            JSONObject sweepItem = sweepLocations.getJSONObject(i);
+            String id = sweepItem.getString("id");
+            String uuid = sweepItem.getString("uuid");
+            JSONObject ggaLocation = sweepItem.getJSONObject("ggaLocation");
+            if (Objects.nonNull(ggaLocation)
+                    && StrUtil.isNotEmpty(ggaLocation.getString("lon"))
+                    && StrUtil.isNotEmpty(ggaLocation.getString("lat"))
+                    && StrUtil.isNotEmpty(ggaLocation.getString("alt"))) {
+                Map<String, Object> item = new HashMap<>();
+                item.put("lon", ggaLocation.getString("lon"));
+                item.put("lat", ggaLocation.getString("lat"));
+                item.put("alt", ggaLocation.getString("alt"));
+                item.put("id", id);
+                item.put("uuid", uuid);
+                list.add(item);
+            }
+        }
+
+        return list;
+    }
+}

+ 50 - 0
src/main/java/com/fdkankan/scene/service/impl/WbServiceImpl.java

@@ -0,0 +1,50 @@
+package com.fdkankan.scene.service.impl;
+
+import com.fdkankan.common.constant.SceneSource;
+import com.fdkankan.rabbitmq.util.RabbitMqProducer;
+import com.fdkankan.scene.entity.Camera;
+import com.fdkankan.scene.entity.CameraDetail;
+import com.fdkankan.scene.entity.ScenePlus;
+import com.fdkankan.scene.service.ICameraDetailService;
+import com.fdkankan.scene.service.ICameraService;
+import com.fdkankan.scene.service.IScenePlusService;
+import com.fdkankan.scene.service.IWbService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+@Slf4j
+@Service
+public class WbServiceImpl implements IWbService {
+
+    @Autowired
+    private RabbitMqProducer mqProducer;
+    @Autowired
+    private IScenePlusService scenePlusService;
+    @Autowired
+    private ICameraService cameraService;
+    @Autowired
+    private ICameraDetailService cameraDetailService;
+
+    @Override
+    public void sendMq(String num) {
+        try {
+            ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
+            Camera camera = cameraService.getById(scenePlus.getCameraId());
+            CameraDetail cameraDetail = cameraDetailService.findByCameraId(camera.getId());
+            if(Objects.isNull(cameraDetail.getCompanyId()) || cameraDetail.getCompanyId() != 26 || scenePlus.getSceneSource() != SceneSource.ZT.code().intValue()){
+                return;
+            }
+            Map<String, Object> params = new HashMap<>();
+            params.put("sceneCode", num);
+            params.put("sceneName", scenePlus.getTitle());
+            mqProducer.sendByWorkQueue("relics-update-name-queue", params);
+        }catch (Exception e){
+            log.error("发送看见场景到全景看看失败, num:{}", num, e);
+        }
+    }
+}

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

@@ -0,0 +1,29 @@
+package com.fdkankan.scene.vo;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 场景动态面板
+ * </p>
+ *
+ * @author
+ * @since 2024-05-21
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SceneDynamicPanelParamVO extends BaseSceneParamVO {
+
+    private static final long serialVersionUID = 1L;
+
+    private JSONObject data;
+
+}

+ 27 - 0
src/main/java/com/fdkankan/scene/vo/SceneDynamicPanelVO.java

@@ -0,0 +1,27 @@
+package com.fdkankan.scene.vo;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.*;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * <p>
+ * 场景动态面板
+ * </p>
+ *
+ * @author
+ * @since 2024-05-21
+ */
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SceneDynamicPanelVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String sid;
+
+}

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

@@ -117,6 +117,21 @@ public class SceneEditControlsParamVO implements Serializable {
      */
     private Integer showLinkTitle;
 
+    /**
+     * 空间绘制信息
+     */
+    private Integer showDrawTitle;
+
+    /**
+     * 是否显示全部模型
+     */
+    private Integer showAllModel;
+
+    private Integer showSurveilScope;
+
+    private Integer showTexture;
+
+    private Integer showPanos;
 
 
 

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

@@ -107,4 +107,21 @@ public class SceneEditControlsVO implements Serializable {
      */
     private Integer showLinkTitle;
 
+    /**
+     * 空间绘制信息
+     */
+    private Integer showDrawTitle;
+
+    /**
+     * 是否显示全部模型
+     */
+    private Integer showAllModel;
+
+    private Integer showSurveilScope;
+
+    private Integer showTexture;
+
+    private Integer showPanos;
+
+
 }

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

@@ -79,7 +79,12 @@ public class SceneEditInfoParamVO extends BaseSceneParamVO{
      */
     private JSONObject sns;
 
+    /**
+     * 启动页信息
+     */
+    private JSONObject started;
 
+    private Integer floorLogoType;
 
 
 }

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

@@ -246,5 +246,28 @@ public class SceneInfoVO {
 
     private String bucket;
 
+    /**
+     * 是否有模型裁剪(0-否,1-是)
+     */
+    private Integer cutModel = 0;
+
+    /**
+     * 启动页配置信息
+     */
+    private JSONObject started;
+
+    /**
+     * 空间绘制
+     */
+    private Integer sceneDraw;
+
+    //动态面板
+    private int dynamicPanel;
+
+    private Integer payStatus;
+
+    private Integer floorLogoType;
+
+    private String orientation;
 
 }

+ 9 - 1
src/main/java/com/fdkankan/scene/vo/SurveillanceParamVO.java

@@ -3,6 +3,8 @@ package com.fdkankan.scene.vo;
 import com.alibaba.fastjson.JSONObject;
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
 import lombok.Data;
 
 /**
@@ -25,9 +27,15 @@ public class SurveillanceParamVO {
     @NotBlank(message = "name不能为空")
     private String name;
 
-    @NotBlank(message = "playUrl不能为空")
     private String playUrl;
 
+    @NotNull(message = "urlType不能为空")
+    private Integer urlType = 1;
+
+    private String poster;
+
+    private String fileName;
+
     @NotBlank(message = "panoId不能为空")
     private String panoId;
 

+ 8 - 0
src/main/java/com/fdkankan/scene/vo/SurveillanceVO.java

@@ -4,6 +4,8 @@ import com.alibaba.fastjson.JSONObject;
 import java.io.Serializable;
 import lombok.Data;
 
+import javax.validation.constraints.NotNull;
+
 /**
  * <p>
  * 监控推拉流信息
@@ -34,6 +36,12 @@ public class SurveillanceVO implements Serializable {
      */
     private String playUrl;
 
+    private Integer urlType;
+
+    private String poster;
+
+    private String fileName;
+
     private String sid;
 
     private String panoId;

+ 13 - 0
src/main/resources/mapper/scene/FolderSceneMapper.xml

@@ -0,0 +1,13 @@
+<?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.IFolderSceneMapper">
+
+    <select id="getByType" resultType="com.fdkankan.scene.entity.FolderScene">
+        SELECT b.* from t_folder a left join t_folder_scene b on a.id = b.folder_id
+        where  b.rec_status ='A' and b.scene_id = #{sceneId}
+        <if test= 'type != null'>
+            and a.type = #{type}
+        </if>
+        limit 1
+    </select>
+</mapper>

+ 5 - 0
src/main/resources/mapper/scene/SceneDynamicPanelMapper.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.ISceneDynamicPanelMapper">
+
+</mapper>

+ 5 - 0
src/main/resources/mapper/scene/SceneProEditMapper.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.ISceneProEditMapper">
+
+</mapper>