Browse Source

Merge branch 'release' into feature-local-jg

# Conflicts:
#	pom.xml
#	src/main/java/com/fdkankan/scene/Interceptor/CheckPermitAspect.java
#	src/main/java/com/fdkankan/scene/controller/SceneEditController.java
#	src/main/java/com/fdkankan/scene/controller/TestController.java
#	src/main/java/com/fdkankan/scene/controller/V3Controller.java
#	src/main/java/com/fdkankan/scene/listener/RabbitMqListener.java
#	src/main/java/com/fdkankan/scene/service/IScenePlusService.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/ScenePlusServiceImpl.java
#	src/main/java/com/fdkankan/scene/service/impl/SceneProServiceImpl.java
#	src/main/java/com/fdkankan/scene/service/impl/SceneUploadServiceImpl.java
#	src/main/resources/bootstrap-dev.yml
#	src/main/resources/bootstrap-test-eur.yml
#	src/main/resources/bootstrap-test.yml
#	src/main/resources/logback-spring.xml
dsx 2 years ago
parent
commit
5821a56d4c
75 changed files with 2593 additions and 399 deletions
  1. 19 2
      pom.xml
  2. 61 0
      src/main/java/com/fdkankan/scene/Interceptor/TokenInterceptor.java
  3. 27 0
      src/main/java/com/fdkankan/scene/bean/BoxModelBean.java
  4. 28 8
      src/main/java/com/fdkankan/scene/bean/SceneJsonBean.java
  5. 38 0
      src/main/java/com/fdkankan/scene/config/InterceptorConfig.java
  6. 1 1
      src/main/java/com/fdkankan/scene/controller/FileConvertController.java
  7. 4 4
      src/main/java/com/fdkankan/scene/controller/SceneProV3Controller.java
  8. 4 4
      src/main/java/com/fdkankan/scene/controller/PicSceneProgressController.java
  9. 3 3
      src/main/java/com/fdkankan/scene/controller/SceneController.java
  10. 0 23
      src/main/java/com/fdkankan/scene/controller/SceneCooperationController.java
  11. 0 21
      src/main/java/com/fdkankan/scene/controller/SceneDataDownloadController.java
  12. 162 1
      src/main/java/com/fdkankan/scene/controller/SceneEditController.java
  13. 0 21
      src/main/java/com/fdkankan/scene/controller/SceneProEditV3Controller.java
  14. 0 21
      src/main/java/com/fdkankan/scene/controller/SceneResourceController.java
  15. 0 21
      src/main/java/com/fdkankan/scene/controller/SceneResourceCooperationController.java
  16. 0 21
      src/main/java/com/fdkankan/scene/controller/VideoSceneProgressController.java
  17. 1 6
      src/main/java/com/fdkankan/scene/entity/Camera.java
  18. 1 1
      src/main/java/com/fdkankan/scene/entity/CameraDetail.java
  19. 1 7
      src/main/java/com/fdkankan/scene/entity/Company.java
  20. 87 0
      src/main/java/com/fdkankan/scene/entity/DownloadTourVideo.java
  21. 105 0
      src/main/java/com/fdkankan/scene/entity/SceneAsynOperLog.java
  22. 1 1
      src/main/java/com/fdkankan/scene/entity/SceneCooperation.java
  23. 3 3
      src/main/java/com/fdkankan/scene/entity/SceneDataDownload.java
  24. 1 1
      src/main/java/com/fdkankan/scene/entity/SceneEditControls.java
  25. 13 1
      src/main/java/com/fdkankan/scene/entity/SceneEditInfo.java
  26. 19 1
      src/main/java/com/fdkankan/scene/entity/SceneEditInfoExt.java
  27. 7 1
      src/main/java/com/fdkankan/scene/entity/ScenePlus.java
  28. 13 1
      src/main/java/com/fdkankan/scene/entity/ScenePlusExt.java
  29. 1 1
      src/main/java/com/fdkankan/scene/entity/ScenePro.java
  30. 1 1
      src/main/java/com/fdkankan/scene/entity/SceneRepairLog.java
  31. 3 3
      src/main/java/com/fdkankan/scene/entity/SceneResource.java
  32. 1 1
      src/main/java/com/fdkankan/scene/entity/SceneResourceCooperation.java
  33. 1 1
      src/main/java/com/fdkankan/scene/entity/SceneUpload.java
  34. 84 0
      src/main/java/com/fdkankan/scene/entity/Surveillance.java
  35. 1 1
      src/main/java/com/fdkankan/scene/entity/User.java
  36. 1 1
      src/main/java/com/fdkankan/scene/entity/UserIncrement.java
  37. 3 3
      src/main/java/com/fdkankan/scene/generate/AutoGenerate.java
  38. 77 0
      src/main/java/com/fdkankan/scene/listener/RabbitMqListener.java
  39. 18 0
      src/main/java/com/fdkankan/scene/mapper/IDownloadTourVideoMapper.java
  40. 18 0
      src/main/java/com/fdkankan/scene/mapper/ISceneAsynOperLogMapper.java
  41. 18 0
      src/main/java/com/fdkankan/scene/mapper/ISurveillanceMapper.java
  42. 27 99
      src/main/java/com/fdkankan/scene/schedule/ScheduleJob.java
  43. 24 0
      src/main/java/com/fdkankan/scene/service/IBoxModelService.java
  44. 28 0
      src/main/java/com/fdkankan/scene/service/IDownloadTourVideoService.java
  45. 24 0
      src/main/java/com/fdkankan/scene/service/ISceneAsynOperLogService.java
  46. 9 0
      src/main/java/com/fdkankan/scene/service/ISceneEditInfoService.java
  47. 3 3
      src/main/java/com/fdkankan/scene/service/IScenePlusService.java
  48. 2 0
      src/main/java/com/fdkankan/scene/service/ISceneProService.java
  49. 29 0
      src/main/java/com/fdkankan/scene/service/ISurveillanceService.java
  50. 245 0
      src/main/java/com/fdkankan/scene/service/impl/BoxModelServiceImpl.java
  51. 145 0
      src/main/java/com/fdkankan/scene/service/impl/DownloadTourVideoServiceImpl.java
  52. 118 0
      src/main/java/com/fdkankan/scene/service/impl/SceneAsynOperLogServiceImpl.java
  53. 1 1
      src/main/java/com/fdkankan/scene/service/impl/SceneDataDownloadServiceImpl.java
  54. 359 57
      src/main/java/com/fdkankan/scene/service/impl/SceneEditInfoServiceImpl.java
  55. 16 0
      src/main/java/com/fdkankan/scene/service/impl/SceneEditServiceImpl.java
  56. 87 9
      src/main/java/com/fdkankan/scene/service/impl/ScenePlusServiceImpl.java
  57. 210 43
      src/main/java/com/fdkankan/scene/service/impl/SceneProServiceImpl.java
  58. 5 0
      src/main/java/com/fdkankan/scene/service/impl/SceneUploadServiceImpl.java
  59. 107 0
      src/main/java/com/fdkankan/scene/service/impl/SurveillanceServiceImpl.java
  60. 25 0
      src/main/java/com/fdkankan/scene/vo/BaseJsonDataParamVO.java
  61. 20 0
      src/main/java/com/fdkankan/scene/vo/BaseSidParamVO.java
  62. 21 0
      src/main/java/com/fdkankan/scene/vo/DownloadTourVideoVO.java
  63. 20 0
      src/main/java/com/fdkankan/scene/vo/SaveFiltersParamVO.java
  64. 35 0
      src/main/java/com/fdkankan/scene/vo/SceneAsynOperLogParamVO.java
  65. 5 0
      src/main/java/com/fdkankan/scene/vo/SceneAuthVO.java
  66. 3 1
      src/main/java/com/fdkankan/scene/vo/SceneDataDownloadVO.java
  67. 5 0
      src/main/java/com/fdkankan/scene/vo/SceneEditInfoParamVO.java
  68. 25 0
      src/main/java/com/fdkankan/scene/vo/SceneInfoVO.java
  69. 45 0
      src/main/java/com/fdkankan/scene/vo/SurveillanceParamVO.java
  70. 41 0
      src/main/java/com/fdkankan/scene/vo/SurveillanceVO.java
  71. 2 0
      src/main/java/com/fdkankan/scene/vo/UploadPanoramaVO.java
  72. 32 0
      src/main/resources/bootstrap-prod-eur.yml
  73. 39 0
      src/main/resources/bootstrap-prod.yml
  74. 5 0
      src/main/resources/mapper/scene/SceneAsynOperLogMapper.xml
  75. 5 0
      src/main/resources/mapper/scene/SurveillanceMapper.xml

+ 19 - 2
pom.xml

@@ -85,6 +85,24 @@
         </dependency>
 
         <dependency>
+            <groupId>com.fdkankan</groupId>
+            <artifactId>4dkankan-utils-rabbitmq</artifactId>
+            <version>3.0.0-SNAPSHOT</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fdkankan</groupId>
+            <artifactId>4dkankan-utils-image</artifactId>
+            <version>3.0.0-SNAPSHOT</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
         </dependency>
@@ -230,14 +248,13 @@
 
 
     <build>
+        <finalName>${artifactId}</finalName>
         <plugins>
             <plugin>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
             </plugin>
-
         </plugins>
-
     </build>
 
     <distributionManagement>

+ 61 - 0
src/main/java/com/fdkankan/scene/Interceptor/TokenInterceptor.java

@@ -0,0 +1,61 @@
+package com.fdkankan.scene.Interceptor;
+
+
+import cn.hutool.http.ContentType;
+import com.alibaba.fastjson.JSON;
+import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.redis.constant.RedisKey;
+import com.fdkankan.redis.util.RedisUtil;
+import com.fdkankan.web.response.ResultData;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpHeaders;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+@Component
+@Slf4j
+public class TokenInterceptor implements HandlerInterceptor {
+
+	@Autowired
+	private RedisUtil redisUtil;
+
+	@Override
+	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+		response.setHeader(HttpHeaders.CONTENT_TYPE, ContentType.JSON.getValue());
+		response.setCharacterEncoding(StandardCharsets.UTF_8.name());
+		String token = request.getHeader("token");
+		if(StringUtils.isEmpty(token)){
+			this.needLogin(request,response);
+			return false;
+		}
+		try {
+			String redisKey = String.format(RedisKey.USER_TOKEN_KEY, token);
+			if(redisUtil.hasKey(redisKey)){
+				redisUtil.expire(redisKey,2 * 60 * 60);
+				return true;
+			}
+		}catch (Exception e){
+			log.error("校验token缓存出错", e);
+		}
+		this.needLogin(request,response);
+		return false;
+	}
+
+	private void needLogin(HttpServletRequest request, HttpServletResponse response) {
+		try {
+			ResultData error = ResultData.error(ErrorCode.TOKEN_NOT_FOUND);
+			response.getWriter().append(JSON.toJSONString(error));
+		} catch (IOException e) {
+			log.info("LoginInterceptor|needLogin|IOException|" + e);
+			e.printStackTrace();
+		}
+	}
+
+}
+

+ 27 - 0
src/main/java/com/fdkankan/scene/bean/BoxModelBean.java

@@ -0,0 +1,27 @@
+package com.fdkankan.scene.bean;
+
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/5/10
+ **/
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class BoxModelBean {
+
+    private Long createTime;
+
+    private JSONObject boxModel;
+
+}

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

@@ -1,15 +1,15 @@
 package com.fdkankan.scene.bean;
 
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.fdkankan.scene.vo.SceneEditControlsVO;
+import java.util.Date;
+import java.util.List;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
 import lombok.Data;
 import lombok.NoArgsConstructor;
 
-import java.util.Date;
-import java.util.List;
-
 /**
  * <p>
  * scene.json实体类
@@ -91,11 +91,6 @@ public class SceneJsonBean {
      */
     private Integer linkVersion;
 
-//    /**
-//     * 户型图文件路径集合
-//     */
-//    private String[] floorPlanPaths;
-
     /**
      * 是否上传了户型图(0-否,1-是)
      */
@@ -122,6 +117,11 @@ public class SceneJsonBean {
     private String sceneKind;
 
     /**
+     * 算法模型类型(dam,3dtiles)
+     */
+    private String modelKind;
+
+    /**
      * 空间视频数据
      */
     private String boxVideos;
@@ -132,6 +132,11 @@ public class SceneJsonBean {
     private String boxPhotos;
 
     /**
+     * 空间模型数据
+     */
+    private String boxModels;
+
+    /**
      *点位视频
      */
     private String videos;
@@ -164,6 +169,11 @@ public class SceneJsonBean {
     private Float floorPlanCompass;
 
     /**
+     * 用户上传自定义平面图
+     */
+    private JSONArray floorPlanUpload;
+
+    /**
      * 是否保存导览
      */
     private Integer tours;
@@ -188,5 +198,15 @@ public class SceneJsonBean {
      */
     private String waterMark;
 
+    /**
+     * 是否有滤镜(0-否,1-是)
+     */
+    private Integer filters;
+
+    /**
+     * 是否有监控摄像头数据
+     */
+    private Integer surveillances;
+
 
 }

+ 38 - 0
src/main/java/com/fdkankan/scene/config/InterceptorConfig.java

@@ -0,0 +1,38 @@
+package com.fdkankan.scene.config;
+
+import com.fdkankan.scene.Interceptor.TokenInterceptor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+
+@Configuration
+public class InterceptorConfig implements WebMvcConfigurer {
+
+	@Autowired
+	private TokenInterceptor tokenInterceptor;
+
+//	@Override
+//	public void addCorsMappings(CorsRegistry registry) {
+//		registry.addMapping("/**").allowCredentials(true).allowedHeaders("*").allowedOrigins("*").allowedMethods("*");
+//
+//	}
+
+	@Override
+	public void addInterceptors(InterceptorRegistry registry) {
+		registry.addInterceptor(tokenInterceptor).addPathPatterns("/service/scene/edit/**");
+//				.excludePathPatterns("/**/sso/**","/app/**","/test/**","/**/inner/**")
+
+		WebMvcConfigurer.super.addInterceptors(registry);
+	}
+
+	@Override
+	public void addResourceHandlers(ResourceHandlerRegistry registry) {
+		WebMvcConfigurer.super.addResourceHandlers(registry);
+	}
+
+}
+

+ 1 - 1
src/main/java/com/fdkankan/scene/controller/FileConvertController.java

@@ -19,7 +19,7 @@ import org.springframework.web.multipart.MultipartFile;
  * @since 2022/5/17
  **/
 @RestController
-@RequestMapping("/service/common/convert")
+@RequestMapping("/service/scene/common/convert")
 public class FileConvertController extends BaseController {
 
     @Autowired

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

@@ -7,15 +7,15 @@ import org.springframework.web.bind.annotation.RestController;
 
 /**
  * <p>
- * pro场景表 前端控制器
+ *  前端控制器
  * </p>
  *
  * @author 
- * @since 2022-04-22
+ * @since 2022-12-07
  */
 @RestController
-@RequestMapping("/scene/sceneProV3")
-public class SceneProV3Controller {
+@RequestMapping("/scene/sceneAsynOperLog")
+public class SceneAsynOperLogController {
 
 }
 

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

@@ -7,15 +7,15 @@ import org.springframework.web.bind.annotation.RestController;
 
 /**
  * <p>
- * 视频重算进度 前端控制器
+ *  前端控制器
  * </p>
  *
  * @author 
- * @since 2022-01-14
+ * @since 2022-10-09
  */
 @RestController
-@RequestMapping("/scene/picSceneProgress")
-public class PicSceneProgressController {
+@RequestMapping("/scene/sceneClean")
+public class SceneCleanController {
 
 }
 

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

@@ -79,9 +79,9 @@ public class SceneController extends BaseController {
      * @param param
      * @return com.fdkankan.web.response.ResultData
      **/
-    @PostMapping(value = "/downLoadZSData")
-    public ResultData downLoadZSData(@Validated BaseSceneParamVO param) throws Exception{
-        return scenePlusService.downLoadZSData(param);
+    @GetMapping(value = "/downLoadZSData")
+    public ResultData downLoadZSData(String sceneNum) throws Exception{
+        return scenePlusService.downLoadZSData(sceneNum);
     }
 
     @PostMapping("/initScene")

+ 0 - 23
src/main/java/com/fdkankan/scene/controller/SceneCooperationController.java

@@ -1,23 +0,0 @@
-package com.fdkankan.scene.controller;
-
-
-import com.fdkankan.web.controller.BaseController;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- *  前端控制器
- * </p>
- *
- * @author dengsixing
- * @since 2021-12-23
- */
-@RestController
-@RequestMapping("/service/scene/user/scene/cooperation")
-public class SceneCooperationController extends BaseController {
-
-
-
-}
-

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

@@ -1,21 +0,0 @@
-package com.fdkankan.scene.controller;
-
-
-import org.springframework.web.bind.annotation.RequestMapping;
-
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * 安居客场景数据下载 前端控制器
- * </p>
- *
- * @author dengsixing
- * @since 2021-12-23
- */
-@RestController
-@RequestMapping("/scene/sceneDataDownload")
-public class SceneDataDownloadController {
-
-}
-

+ 162 - 1
src/main/java/com/fdkankan/scene/controller/SceneEditController.java

@@ -3,16 +3,24 @@ 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.web.response.ResultData;
+import com.fdkankan.model.utils.CreateHouseJsonUtil;
 import com.fdkankan.scene.annotation.CheckPermit;
+import com.fdkankan.scene.entity.SceneAsynOperLog;
+import com.fdkankan.scene.service.IBoxModelService;
+import com.fdkankan.scene.service.IDownloadTourVideoService;
+import com.fdkankan.scene.service.ISceneAsynOperLogService;
 import com.fdkankan.scene.service.ISceneEditInfoService;
 import com.fdkankan.scene.service.ISceneEditService;
+import com.fdkankan.scene.service.IScenePlusService;
 import com.fdkankan.scene.service.ISceneProService;
 import com.fdkankan.scene.service.ISceneUploadService;
+import com.fdkankan.scene.service.ISurveillanceService;
 import com.fdkankan.scene.vo.BallScreenVideoParamVO;
 import com.fdkankan.scene.vo.BaseDataParamVO;
 import com.fdkankan.scene.vo.BaseFileParamVO;
+import com.fdkankan.scene.vo.BaseJsonDataParamVO;
 import com.fdkankan.scene.vo.BaseSceneParamVO;
+import com.fdkankan.scene.vo.BaseSidParamVO;
 import com.fdkankan.scene.vo.DeleteFileParamVO;
 import com.fdkankan.scene.vo.DeleteHotIconParamVO;
 import com.fdkankan.scene.vo.DeleteHotParamVO;
@@ -25,16 +33,20 @@ import com.fdkankan.scene.vo.FileNameAndDataParamVO;
 import com.fdkankan.scene.vo.FileParamVO;
 import com.fdkankan.scene.vo.LocalesParamVO;
 import com.fdkankan.scene.vo.RenameCadParamVO;
+import com.fdkankan.scene.vo.SaveFiltersParamVO;
 import com.fdkankan.scene.vo.SaveLinkPanParamVO;
 import com.fdkankan.scene.vo.SaveTagsParamVO;
 import com.fdkankan.scene.vo.SaveTagsVisibleParamVO;
+import com.fdkankan.scene.vo.SceneAsynOperLogParamVO;
 import com.fdkankan.scene.vo.SceneAuthVO;
 import com.fdkankan.scene.vo.SceneEditInfoParamVO;
 import com.fdkankan.scene.vo.SceneEditInfoVO;
 import com.fdkankan.scene.vo.SceneInfoParamVO;
 import com.fdkankan.scene.vo.SceneInfoVO;
+import com.fdkankan.scene.vo.SurveillanceParamVO;
 import com.fdkankan.scene.vo.UploadContentParamVO;
 import com.fdkankan.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;
@@ -57,6 +69,9 @@ import org.springframework.web.multipart.MultipartFile;
 @RequestMapping("/service/scene/edit")
 public class SceneEditController extends BaseController {
 
+    @Value("${spring.profiles.active}")
+    private String env;
+
     @Autowired
     private ISceneProService sceneProService;
     @Autowired
@@ -65,6 +80,16 @@ public class SceneEditController extends BaseController {
     private ISceneUploadService sceneUploadService;
     @Autowired
     private ISceneEditService sceneEditService;
+    @Autowired
+    private IDownloadTourVideoService downloadTourVideoService;
+    @Autowired
+    private ISurveillanceService surveillanceService;
+    @Autowired
+    private IBoxModelService boxModelService;
+    @Autowired
+    private IScenePlusService scenePlusService;
+    @Autowired
+    private ISceneAsynOperLogService sceneAsynOperLogService;
 
     /**
      * <p>
@@ -643,6 +668,16 @@ public class SceneEditController extends BaseController {
         return sceneEditService.deleteTour(param);
     }
 
+    @PostMapping(value = "/tour/video/upload")
+    public ResultData uploadTourVideo(@RequestParam("num") String num, @RequestParam("file") MultipartFile file) throws Exception {
+        return downloadTourVideoService.uploadTourVideo(num, file);
+    }
+
+    @PostMapping(value = "/tour/video/download")
+    public ResultData downloadTourVideo(@RequestParam("num") String num) throws Exception {
+        return downloadTourVideoService.downloadTourVideo(num);
+    }
+
     /**
      * <p>
      添加马赛克
@@ -718,4 +753,130 @@ public class SceneEditController extends BaseController {
         return sceneEditInfoService.deleteWaterMark(param);
     }
 
+    /**
+     * 删除水印
+     * @param param
+     * @return
+     * @throws Exception
+     */
+    @CheckPermit
+    @PostMapping(value = "/filter/save")
+    public ResultData saveFilter(@RequestBody @Validated SaveFiltersParamVO param) throws Exception{
+        return sceneEditInfoService.saveFilter(param);
+    }
+
+    /**
+     * 删除水印
+     * @param param
+     * @return
+     * @throws Exception
+     */
+    @CheckPermit
+    @PostMapping(value = "/filter/list")
+    public ResultData listFilter(@RequestBody @Validated BaseSceneParamVO param) throws Exception{
+        return sceneEditInfoService.listFilter(param);
+    }
+
+    /**
+     * <p>
+     添加监控
+     * </p>
+     * @author dengsixing
+     * @date 2022/9/20
+     * @param param
+     * @return com.fdkankan.common.response.ResultData
+     **/
+    @CheckPermit
+    @PostMapping("/surveillance/save")
+    ResultData saveSurveillance(@RequestBody @Validated SurveillanceParamVO param){
+        return surveillanceService.saveSurveillance(param);
+    }
+
+    @CheckPermit
+    @PostMapping("/surveillance/delete")
+    public ResultData deleteSurveillance(@RequestBody @Validated BaseSidParamVO param){
+        return surveillanceService.deleteSurveillance(param);
+    }
+
+    @CheckPermit
+    @PostMapping("/surveillance/list")
+    public ResultData listSurveillance(@RequestBody @Validated BaseSceneParamVO param){
+        return ResultData.ok(surveillanceService.listSurveillance(param.getNum()));
+    }
+
+    /**
+     * <p>
+     上传空间模型
+     * </p>
+     * @author dengsixing
+     * @date 2022/10/19
+     * @param num
+     * @param sid
+     * @param file
+     * @return com.fdkankan.common.response.ResultData
+     **/
+    @CheckPermit
+    @PostMapping("/model/box/upload")
+    public ResultData uploadBoxModel(
+        @RequestParam(value = "num") String num,
+        @RequestParam(value = "sid") String sid,
+        @RequestParam(value = "file") MultipartFile file) throws Exception {
+        return boxModelService.uploadBoxModel(num, sid, file);
+    }
+
+    /**
+     * <p>
+     保存空间模型
+     * </p>
+     * @author dengsixing
+     * @date 2022/10/19
+     * @param param
+     * @return com.fdkankan.common.response.ResultData
+     **/
+    @CheckPermit
+    @PostMapping("/model/box/save")
+    public ResultData saveBoxModel(@RequestBody @Validated BaseJsonDataParamVO param) throws Exception {
+        return boxModelService.saveBoxModel(param);
+    }
+
+    /**
+     * <p>
+     删除空间模型
+     * </p>
+     * @author dengsixing
+     * @date 2022/10/19
+     * @param param
+     * @return com.fdkankan.common.response.ResultData
+     **/
+    @CheckPermit
+    @PostMapping("/model/box/delete")
+    public ResultData delBoxModel(@RequestBody @Validated DeleteSidParamVO param) throws Exception {
+        return boxModelService.deleteBoxModel(param);
+    }
+
+    /**
+     * 上传二维码和分享的logo
+     * @return
+     */
+    @PostMapping(value = "/uploadShareLogo")
+    public ResultData uploadShareLogo(@RequestParam("num") String num, @RequestParam("file") MultipartFile file) throws Exception {
+        return scenePlusService.uploadShareLogo(num, file);
+    }
+
+    /**
+     * <p>
+     删除空间模型
+     * </p>
+     * @author dengsixing
+     * @date 2022/10/19
+     * @param param
+     * @return com.fdkankan.common.response.ResultData
+     **/
+    @CheckPermit
+    @PostMapping("/getAsynOperLog")
+    public ResultData getAsynOperLog(@RequestBody @Validated SceneAsynOperLogParamVO param){
+        return sceneAsynOperLogService.getAsynOperLog(param);
+    }
+
+
 }

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

@@ -1,21 +0,0 @@
-package com.fdkankan.scene.controller;
-
-
-import org.springframework.web.bind.annotation.RequestMapping;
-
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * pro场景编辑数据表 前端控制器
- * </p>
- *
- * @author 
- * @since 2022-04-22
- */
-@RestController
-@RequestMapping("/scene/sceneProEditV3")
-public class SceneProEditV3Controller {
-
-}
-

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

@@ -1,21 +0,0 @@
-package com.fdkankan.scene.controller;
-
-
-import org.springframework.web.bind.annotation.RequestMapping;
-
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * 场景资源表 前端控制器
- * </p>
- *
- * @author dengsixing
- * @since 2021-12-23
- */
-@RestController
-@RequestMapping("/scene/sceneResource")
-public class SceneResourceController {
-
-}
-

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

@@ -1,21 +0,0 @@
-package com.fdkankan.scene.controller;
-
-
-import org.springframework.web.bind.annotation.RequestMapping;
-
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * 场景资源和协作用户关联表 前端控制器
- * </p>
- *
- * @author dengsixing
- * @since 2021-12-23
- */
-@RestController
-@RequestMapping("/scene/sceneResourceCooperation")
-public class SceneResourceCooperationController {
-
-}
-

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

@@ -1,21 +0,0 @@
-package com.fdkankan.scene.controller;
-
-
-import org.springframework.web.bind.annotation.RequestMapping;
-
-import org.springframework.web.bind.annotation.RestController;
-
-/**
- * <p>
- * 视频重算进度 前端控制器
- * </p>
- *
- * @author 
- * @since 2022-01-14
- */
-@RestController
-@RequestMapping("/scene/videoSceneProgress")
-public class VideoSceneProgressController {
-
-}
-

+ 1 - 6
src/main/java/com/fdkankan/scene/entity/Camera.java

@@ -80,11 +80,6 @@ public class Camera implements Serializable {
      * 记录的状态,A: 生效,I: 禁用
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
-
-    @TableField("is_out")
-    private Boolean isOut;
-
-
 }

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

@@ -134,7 +134,7 @@ public class CameraDetail implements Serializable {
      * 记录的状态,A: 生效,I: 禁用
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
     @TableField("user_camera_version")

+ 1 - 7
src/main/java/com/fdkankan/scene/entity/Company.java

@@ -65,12 +65,6 @@ public class Company implements Serializable {
     private Integer showLogo;
 
     /**
-     * t_manager表的id
-     */
-    @TableField("manager_id")
-    private Long managerId;
-
-    /**
      * 新增的相机是否注册,0否,1删
      */
     @TableField("camera_delete")
@@ -92,7 +86,7 @@ public class Company implements Serializable {
      * 记录的状态,A: 生效,I: 禁用
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
     @TableField("calculate_flexibility")

+ 87 - 0
src/main/java/com/fdkankan/scene/entity/DownloadTourVideo.java

@@ -0,0 +1,87 @@
+package com.fdkankan.scene.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.util.Date;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 导览视频转换记录表
+ * </p>
+ *
+ * @author 
+ * @since 2022-10-12
+ */
+@Getter
+@Setter
+@TableName("t_download_tour_video")
+public class DownloadTourVideo implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 场景码
+     */
+    @TableField("num")
+    private String num;
+
+    /**
+     * 视频转换状态(0-等待中,1-成功,2-失败)
+     */
+    @TableField("state")
+    private Integer state;
+
+    /**
+     * 转换失败原因
+     */
+    @TableField("reason")
+    private String reason;
+
+    /**
+     * 文件名称
+     */
+    @TableField("file_name")
+    private String fileName;
+
+    /**
+     * 本地临时文件地址
+     */
+    @TableField("local_path")
+    private String localPath;
+
+    /**
+     * 导览视频目录地址
+     */
+    @TableField("download_path")
+    private String downloadPath;
+
+    /**
+     * 创建时间
+     */
+    @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;
+
+
+}

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

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

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

@@ -46,7 +46,7 @@ public class SceneCooperation implements Serializable {
     @TableField("update_time")
     private Date updateTime;
 
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     @TableField("rec_status")
     private String recStatus;
 

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

@@ -28,8 +28,8 @@ public class SceneDataDownload implements Serializable {
     /**
      * 场景码
      */
-    @TableField("num")
-    private String num;
+    @TableField("scene_num")
+    private String sceneNum;
 
     /**
      * 文件md5
@@ -59,7 +59,7 @@ public class SceneDataDownload implements Serializable {
      * 记录的状态,A: 生效,I: 禁用
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
 

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

@@ -104,7 +104,7 @@ public class SceneEditControls implements Serializable {
      * 记录的状态,A: 生效,I: 禁用
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
 

+ 13 - 1
src/main/java/com/fdkankan/scene/entity/SceneEditInfo.java

@@ -149,6 +149,12 @@ public class SceneEditInfo implements Serializable {
     private String boxPhotos;
 
     /**
+     * 空间模型数据
+     */
+    @TableField("box_models")
+    private String boxModels;
+
+    /**
      * 是否需要处理球幕视频
      */
     @TableField("build_video_status")
@@ -173,6 +179,12 @@ public class SceneEditInfo implements Serializable {
     private String loadingLogoFile;
 
     /**
+     * 用户上传自定义平面图数据
+     */
+    @TableField("floor_plan_upload")
+    private String floorPlanUpload;
+
+    /**
      * 创建时间
      */
     @TableField("create_time")
@@ -188,7 +200,7 @@ public class SceneEditInfo implements Serializable {
      * 记录的状态,A: 生效,I: 禁用
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
 

+ 19 - 1
src/main/java/com/fdkankan/scene/entity/SceneEditInfoExt.java

@@ -73,6 +73,24 @@ public class SceneEditInfoExt {
     private Integer links;
 
     /**
+     * 是否有滤镜(0-否,1-是)
+     */
+    @TableField("filters")
+    private Integer filters;
+
+    /**
+     * 是否有监控摄像头(0-否,1-是)
+     */
+    @TableField("surveillances")
+    private Integer surveillances;
+
+    /**
+     * 二维码logo路径(oss相对路径)
+     */
+    @TableField("share_logo_img")
+    private String shareLogoImg;
+
+    /**
      * 创建时间
      */
     @TableField("create_time")
@@ -88,7 +106,7 @@ public class SceneEditInfoExt {
      * 记录的状态,A: 生效,I: 禁用
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
 

+ 7 - 1
src/main/java/com/fdkankan/scene/entity/ScenePlus.java

@@ -95,6 +95,12 @@ public class ScenePlus implements Serializable {
     private Integer recommend;
 
     /**
+     * 是否有housetype文件(0-否,1-是)
+     */
+    @TableField("house_type")
+    private Integer houseType;
+
+    /**
      * 创建时间
      */
     @TableField("create_time")
@@ -110,7 +116,7 @@ public class ScenePlus implements Serializable {
      * 记录的状态,A: 生效,I: 禁用
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
 

+ 13 - 1
src/main/java/com/fdkankan/scene/entity/ScenePlusExt.java

@@ -125,6 +125,18 @@ public class ScenePlusExt implements Serializable {
     private String sceneKind;
 
     /**
+     * 算法模型类型(dam,3dtiles)
+     */
+    @TableField("model_kind")
+    private String modelKind;
+
+    /**
+     * 算法计算完成时间
+     */
+    @TableField("algorithm_time")
+    private Date algorithmTime;
+
+    /**
      * 计算耗时
      */
     @TableField("compute_time")
@@ -155,7 +167,7 @@ public class ScenePlusExt implements Serializable {
      * 记录的状态,A: 生效,I: 禁用
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
 

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

@@ -157,7 +157,7 @@ public class ScenePro implements Serializable {
     /**
      * 记录的状态,A: 生效,I: 禁用
      */
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     @TableField("rec_status")
     private String recStatus;
 

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

@@ -62,7 +62,7 @@ public class SceneRepairLog implements Serializable {
      * 记录的状态,A: 生效,I: 禁用
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
 

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

@@ -28,8 +28,8 @@ public class SceneResource implements Serializable {
     /**
      * 权限名称
      */
-    @TableField("resource_name")
-    private String resourceName;
+    @TableField("name")
+    private String name;
 
     /**
      * 英文名
@@ -71,7 +71,7 @@ public class SceneResource implements Serializable {
      * 记录的状态,A: 生效,I: 禁用
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
 

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

@@ -53,7 +53,7 @@ public class SceneResourceCooperation implements Serializable {
      * 记录的状态,A: 生效,I: 禁用
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
 

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

@@ -66,7 +66,7 @@ public class SceneUpload implements Serializable {
      * 记录的状态,A: 生效,I: 禁用
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
 

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

@@ -0,0 +1,84 @@
+package com.fdkankan.scene.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.util.Date;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 监控推拉流信息
+ * </p>
+ *
+ * @author 
+ * @since 2022-09-16
+ */
+@Getter
+@Setter
+@TableName("t_surveillance")
+public class Surveillance implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Long id;
+
+    /**
+     * 场景码
+     */
+    @TableField("num")
+    private String num;
+
+    /**
+     * 监控名称
+     */
+    @TableField("name")
+    private String name;
+
+    /**
+     * 监控唯一标识
+     */
+    @TableField("sid")
+    private String sid;
+
+    /**
+     * panoId
+     */
+    @TableField("pano_id")
+    private String panoId;
+
+    /**
+     * 摄像头设置信息
+     */
+    @TableField("data")
+    private String data;
+
+    /**
+     * 播放地址
+     */
+    @TableField("play_url")
+    private String playUrl;
+
+    /**
+     * 创建时间
+     */
+    @TableField("create_time")
+    private Date createTime;
+
+    /**
+     * 更新时间
+     */
+    @TableField("update_time")
+    private Date updateTime;
+
+    @TableField("rec_status")
+    @TableLogic(value = "A", delval = "I")
+    private String recStatus;
+
+
+}

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

@@ -128,7 +128,7 @@ public class User implements Serializable {
      * 记录的状态,A: 生效,I: 禁用
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
     /**

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

@@ -74,7 +74,7 @@ public class UserIncrement implements Serializable {
      * 记录的状态,A: 生效,I: 禁用
      */
     @TableField("rec_status")
-    @TableLogic("A")
+    @TableLogic(value = "A", delval = "I")
     private String recStatus;
 
     /**

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

@@ -15,10 +15,10 @@ public class AutoGenerate {
 
     public static void main(String[] args) {
 
-        String path =System.getProperty("user.dir") + "\\4dkankan-center-scene";
+        String path =System.getProperty("user.dir");
 
-        generate(path,"test", getTables(new String[]{
-                "t_scene_cooperation"
+        generate(path,"scene", getTables(new String[]{
+                "t_scene_asyn_oper_log"
         }));
 
 //        generate(path,"goods", getTables(new String[]{

+ 77 - 0
src/main/java/com/fdkankan/scene/listener/RabbitMqListener.java

@@ -0,0 +1,77 @@
+package com.fdkankan.scene.listener;
+
+import com.alibaba.fastjson.JSON;
+import com.fdkankan.scene.entity.DownloadTourVideo;
+import com.fdkankan.scene.service.IDownloadTourVideoService;
+import com.rabbitmq.client.Channel;
+import java.nio.charset.StandardCharsets;
+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.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/4/19
+ **/
+@Slf4j
+@Component
+public class RabbitMqListener {
+
+    @Value("${queue.scene.transfer-tour-video}")
+    private String downloadTourVideoQueue;
+
+    @Autowired
+    private IDownloadTourVideoService downloadTourVideoService;
+
+
+
+
+    /**
+     * 开启了手动确认模式,如果没有手动确认,消费者不会重试,当服务重启时会再次消费,因为rabbitmq认为你还没有处理完你的业务
+     * queuesToDeclare = @Queue("${queue.modeling.modeling-test}"),  如果队列不不存在会自动创建队列
+     * concurrency = "3"    设置消费线程数,每个线程每次只拉取一条消息消费
+     */
+    @RabbitListener(
+        queuesToDeclare = @Queue("${queue.scene.transfer-tour-video}")
+    )
+    public void transferTourVideo(Channel channel, Message message) throws Exception {
+        String messageId = message.getMessageProperties().getMessageId();
+        String msg = new String(message.getBody(), StandardCharsets.UTF_8);
+        log.info("开始消费消息,id:{},queue:{},content:{}", messageId, downloadTourVideoQueue, msg);
+        DownloadTourVideo downloadTourVideo = JSON.parseObject(msg, DownloadTourVideo.class);
+        downloadTourVideoService.transferTourVideo(downloadTourVideo);
+        log.info("deliverTag:" + message.getMessageProperties().getDeliveryTag());
+        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
+        log.info("结束消费消息,id:{}", messageId);
+    }
+
+    /**
+     * 开启了手动确认模式,如果没有手动确认,消费者不会重试,当服务重启时会再次消费,因为rabbitmq认为你还没有处理完你的业务
+     * queuesToDeclare = @Queue("${queue.modeling.modeling-test}"),  如果队列不不存在会自动创建队列
+     * concurrency = "3"    设置消费线程数,每个线程每次只拉取一条消息消费
+     */
+    @RabbitListener(
+        queuesToDeclare = @Queue("test_dsx")
+    )
+    public void test(Channel channel, Message message) throws Exception {
+        String messageId = message.getMessageProperties().getMessageId();
+        String msg = new String(message.getBody(), StandardCharsets.UTF_8);
+        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
+        log.info("开始消费消息,id:{},queue:{},content:{}", messageId, "test_dsx", msg);
+        Thread.sleep(10000L);
+        log.info("deliverTag:" + message.getMessageProperties().getDeliveryTag());
+        log.info("结束消费消息,id:{}", messageId);
+    }
+
+
+
+
+}

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

@@ -0,0 +1,18 @@
+package com.fdkankan.scene.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fdkankan.scene.entity.DownloadTourVideo;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 导览视频转换记录表 Mapper 接口
+ * </p>
+ *
+ * @author 
+ * @since 2022-10-12
+ */
+@Mapper
+public interface IDownloadTourVideoMapper extends BaseMapper<DownloadTourVideo> {
+
+}

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

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

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

@@ -0,0 +1,18 @@
+package com.fdkankan.scene.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.fdkankan.scene.entity.Surveillance;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 监控推拉流信息 Mapper 接口
+ * </p>
+ *
+ * @author 
+ * @since 2022-09-16
+ */
+@Mapper
+public interface ISurveillanceMapper extends BaseMapper<Surveillance> {
+
+}

+ 27 - 99
src/main/java/com/fdkankan/scene/schedule/ScheduleJob.java

@@ -1,99 +1,27 @@
-package com.fdkankan.scene.schedule;//package com.fdkankan.scene.schedule;
-//
-//import com.fdkankan.common.util.RubberSheetingUtil;
-//import com.fdkankan.rabbitmq.util.RabbitMqProducer;
-//import com.fdkankan.redis.constant.RedisKey;
-//import com.fdkankan.redis.constant.RedisLockKey;
-//import com.fdkankan.redis.util.RedisLockUtil;
-//import com.fdkankan.scene.service.IScene3dNumService;
-//import com.fdkankan.scene.service.ISceneService;
-//import lombok.extern.slf4j.Slf4j;
-//import org.springframework.beans.factory.annotation.Autowired;
-//import org.springframework.beans.factory.annotation.Value;
-//import org.springframework.scheduling.annotation.Scheduled;
-//import org.springframework.stereotype.Component;
-//
-//@Slf4j
-//@Component
-//public class ScheduleJob {
-//
-//    @Value("${environment}")
-//    private String environment;
-//    @Value("${queue.modeling.modeling-call}")
-//    private String queueModelingCall;
-//    @Value("${scaling.mq.threshold.modeling-call}")
-//    private String modelingCallMqThreshold;
-//
-//    @Autowired
-//    ISceneService sceneService;
-//    @Autowired
-//    private IScene3dNumService scene3dNumService;
-//    @Autowired
-//    private RedisLockUtil redisLockUtil;
-//    @Autowired
-//    RubberSheetingUtil rubberSheetingUtil;
-//    @Autowired
-//    RabbitMqProducer rabbitMqProducer;
-//
-////    /**
-////     * 更新浏览量
-////     */
-////    @Scheduled(cron = "0 0/10 * * * ? ")
-////    public void updateViewCount() {
-////        if("hq".equals(environment)){
-////            return;
-////        }
-////        log.info("执行定时任务开始:更新浏览量");
-////        try {
-////            //更新浏览量
-////            sceneService.updatePv();
-////        } catch (Exception e) {
-////            log.error("更新浏览量定时任务出错:", e);
-////        }
-////        log.info("执行定时任务结束:更新浏览量");
-////    }
-////
-////    /**
-////     * <p>
-////            定时生成场景码
-////            查询码池中未使用场景码数量,如果小于阈值,执行批量生成
-////     * </p>
-////     * @author dengsixing
-////     * @date 2022/3/26
-////     **/
-////    @Scheduled(cron = "0 0/1 * * * ? ")
-////    public void generateSceneCode(){
-////        log.info("执行定时任务开始:批量生成场景码");
-////        scene3dNumService.batchCreateSceneNum();
-////        log.info("执行定时任务结束:批量生成场景码");
-////    }
-//
-////    /**
-////     * 开启场景计算弹性伸缩
-////     */
-////    @Scheduled(cron = "0 0/5 8-21 * * ? ")
-////    public void startupModelingServer() {
-////        if("hq".equals(environment)){
-////            return;
-////        }
-////        boolean lock = redisLockUtil.lock(
-////            RedisLockKey.LOCK_STARTUP_MODELING_SERVER, RedisKey.EXPIRE_TIME_5_MINUTE);
-////        if(!lock){
-////            return;
-////        }
-////        try {
-////            //当mq排队数大于指定数量时使用弹性升缩
-////            int mqNum = rabbitMqProducer.getMessageCount(queueModelingCall);
-////            log.info("每5分钟查询一次排队队列,mqNum:" + mqNum);
-////            if(mqNum - Integer.parseInt(modelingCallMqThreshold) > 0){
-////                String responce = rubberSheetingUtil.createEcs();
-////                log.info("开启弹性伸缩:{}", responce);
-////            }
-////        } catch (Exception e) {
-////            log.error(e.getMessage());
-////        }finally {
-////            redisLockUtil.unlockLua(RedisLockKey.LOCK_STARTUP_MODELING_SERVER);
-////        }
-////    }
-//
-//}
+package com.fdkankan.scene.schedule;
+
+import com.fdkankan.scene.service.ISceneAsynOperLogService;
+import lombok.extern.log4j.Log4j2;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+@RefreshScope
+@Log4j2
+@Component
+public class ScheduleJob {
+
+    @Autowired
+    private ISceneAsynOperLogService sceneAsynOperLogService;
+
+    /**
+     * 每天凌晨一点执行
+     */
+    @Scheduled(cron="0 0 1 * * ?")
+    public void cleanDownloadPanorama() {
+        log.info("定时清除全景图压缩包开始");
+        sceneAsynOperLogService.cleanDownloadPanorama();
+        log.info("定时清除全景图压缩包完毕");
+    }
+}

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

@@ -0,0 +1,24 @@
+package com.fdkankan.scene.service;
+
+import com.fdkankan.scene.vo.BaseJsonDataParamVO;
+import com.fdkankan.scene.vo.DeleteSidParamVO;
+import com.fdkankan.web.response.ResultData;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/10/19
+ **/
+public interface IBoxModelService {
+
+    ResultData uploadBoxModel(String num, String sid, MultipartFile file) throws Exception;
+
+    ResultData saveBoxModel(BaseJsonDataParamVO param) throws Exception;
+
+    ResultData deleteBoxModel(DeleteSidParamVO param) throws Exception;
+
+}

+ 28 - 0
src/main/java/com/fdkankan/scene/service/IDownloadTourVideoService.java

@@ -0,0 +1,28 @@
+package com.fdkankan.scene.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.scene.entity.DownloadTourVideo;
+import com.fdkankan.web.response.ResultData;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * <p>
+ * 导览视频转换记录表 服务类
+ * </p>
+ *
+ * @author 
+ * @since 2022-10-12
+ */
+public interface IDownloadTourVideoService extends IService<DownloadTourVideo> {
+
+    DownloadTourVideo getWaitingByNum(String num);
+
+    void removeByNum(String num);
+
+    ResultData uploadTourVideo(String num, MultipartFile file) throws Exception;
+
+    void transferTourVideo(DownloadTourVideo downloadTourVideo);
+
+    ResultData downloadTourVideo(String num);
+
+}

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

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

+ 9 - 0
src/main/java/com/fdkankan/scene/service/ISceneEditInfoService.java

@@ -2,6 +2,10 @@ package com.fdkankan.scene.service;
 
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.scene.annotation.CheckPermit;
+import com.fdkankan.scene.vo.BaseSceneParamVO;
+import com.fdkankan.scene.vo.SaveFiltersParamVO;
+import com.fdkankan.scene.vo.SurveillanceParamVO;
 import com.fdkankan.web.response.ResultData;
 import com.fdkankan.scene.entity.SceneEditInfo;
 import com.fdkankan.scene.vo.BallScreenVideoParamVO;
@@ -23,6 +27,9 @@ import com.fdkankan.scene.vo.SceneInfoParamVO;
 import com.fdkankan.scene.vo.SceneInfoVO;
 import java.io.IOException;
 import java.util.List;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.multipart.MultipartFile;
 
 /**
@@ -103,6 +110,8 @@ public interface ISceneEditInfoService extends IService<SceneEditInfo> {
 
     ResultData deleteWaterMark(BaseFileParamVO param) throws Exception;
 
+    ResultData saveFilter(SaveFiltersParamVO param) throws Exception;
 
+    ResultData listFilter(BaseSceneParamVO param) throws Exception;
 
 }

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

@@ -9,6 +9,7 @@ import com.fdkankan.scene.entity.ScenePlus;
 import com.fdkankan.scene.vo.SceneCheckKeyParamVO;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.multipart.MultipartFile;
 
 /**
  * <p>
@@ -28,7 +29,7 @@ public interface IScenePlusService extends IService<ScenePlus> {
 
     ResultData moveScene(List<String> numList, Long cameraId, Long userId);
 
-    ResultData downLoadZSData(BaseSceneParamVO param) throws Exception;
+    ResultData downLoadZSData(String num) throws Exception;
 
     ScenePlus checkSceneAvail(String num);
 
@@ -39,7 +40,6 @@ public interface IScenePlusService extends IService<ScenePlus> {
 
     ResultData editScene(LaserSceneBean param);
 
-
-
+    ResultData uploadShareLogo(String num, MultipartFile file) throws Exception;
 
 }

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

@@ -47,4 +47,6 @@ public interface ISceneProService extends IService<ScenePro> {
 
 //    ResultData downloadTexData(String num) throws Exception;
 
+    ScenePro getByNum(String num);
+
 }

+ 29 - 0
src/main/java/com/fdkankan/scene/service/ISurveillanceService.java

@@ -0,0 +1,29 @@
+package com.fdkankan.scene.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.fdkankan.scene.entity.Surveillance;
+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.util.List;
+
+/**
+ * <p>
+ * 监控推拉流信息 服务类
+ * </p>
+ *
+ * @author 
+ * @since 2022-09-16
+ */
+public interface ISurveillanceService extends IService<Surveillance> {
+
+    ResultData saveSurveillance(SurveillanceParamVO param);
+
+    ResultData deleteSurveillance(BaseSidParamVO param);
+
+    List<SurveillanceVO> listSurveillance(String num);
+
+    Surveillance getBySid(String num, String sid);
+
+}

+ 245 - 0
src/main/java/com/fdkankan/scene/service/impl/BoxModelServiceImpl.java

@@ -0,0 +1,245 @@
+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 cn.hutool.core.util.ZipUtil;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.common.constant.OperationType;
+import com.fdkankan.common.constant.ServerCode;
+import com.fdkankan.common.exception.BusinessException;
+import com.fdkankan.common.util.FileUtils;
+import com.fdkankan.common.util.OBJToGLBUtil;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
+import com.fdkankan.model.constants.ConstantFilePath;
+import com.fdkankan.model.constants.UploadFilePath;
+import com.fdkankan.model.utils.ComputerUtil;
+import com.fdkankan.scene.bean.BoxModelBean;
+import com.fdkankan.scene.entity.SceneEditInfo;
+import com.fdkankan.scene.entity.ScenePlus;
+import com.fdkankan.scene.entity.ScenePlusExt;
+import com.fdkankan.scene.service.IBoxModelService;
+import com.fdkankan.scene.service.ISceneEditInfoService;
+import com.fdkankan.scene.service.IScenePlusExtService;
+import com.fdkankan.scene.service.IScenePlusService;
+import com.fdkankan.scene.vo.BaseJsonDataParamVO;
+import com.fdkankan.scene.vo.DeleteSidParamVO;
+import com.fdkankan.web.response.ResultData;
+import com.google.common.collect.Lists;
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Set;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/10/19
+ **/
+@Slf4j
+@Service
+public class BoxModelServiceImpl implements IBoxModelService {
+
+    @Autowired
+    private FYunFileServiceInterface fYunFileService;
+    @Autowired
+    private IScenePlusService scenePlusService;
+    @Autowired
+    private ISceneEditInfoService sceneEditInfoService;
+    @Autowired
+    private IScenePlusExtService scenePlusExtService;
+
+    @Override
+    public ResultData uploadBoxModel(String num, String sid, MultipartFile file) throws Exception {
+
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
+        if(Objects.isNull(scenePlus)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
+        }
+        ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
+        String bucket = scenePlusExt.getYunFileBucket();
+
+        if(!file.getOriginalFilename().endsWith(".zip")){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_7015);
+        }
+
+        if(!FileUtils.checkFileSizeIsLimit(file.getSize(), 5, "M")){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_7023, "5M");
+        }
+        String path = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "boxModel/" + sid + "/";
+        String zipPath = path + file.getOriginalFilename();
+        String srcPath = path + "data/";
+        String glbPath = path + sid + ".glb";
+
+        FileUtil.del(path);
+        FileUtil.mkParentDirs(zipPath);
+        file.transferTo(new File(zipPath));
+
+        //解压
+        ZipUtil.unzip(zipPath,srcPath);
+
+        //校验是否包含目录,如果包含目录提示错误
+        File srcFile = new File(srcPath);
+        Arrays.stream(srcFile.listFiles()).forEach(subFile->{
+            if(subFile.isDirectory()){
+                throw new BusinessException(ErrorCode.FAILURE_CODE_5065);
+            }
+        });
+
+        //转glb
+        OBJToGLBUtil.objToGlb(srcPath, glbPath);
+
+        if(!ComputerUtil.checkComputeCompleted(glbPath, 3, 2000)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_7013);
+        }
+
+        //上传glb
+        fYunFileService.uploadFile(bucket, glbPath, String.format(UploadFilePath.USER_EDIT_PATH, num) + "boxModels/" + sid + ".glb");
+
+        return ResultData.ok(sid + ".glb");
+    }
+
+    public static void main(String[] args) {
+        ZipUtil.unzip("F:\\test\\新建文件夹\\police模型\\police模型.zip","F:\\test\\新建文件夹\\police模型\\maps");
+    }
+
+    @Override
+    public ResultData saveBoxModel(BaseJsonDataParamVO param) throws Exception {
+
+        JSONObject data = param.getData();
+        String sid = data.getString("sid");
+        if(StrUtil.isEmpty(sid)){
+            throw new BusinessException(ServerCode.PARAM_REQUIRED, sid);
+        }
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+        if(Objects.isNull(scenePlus))
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
+        ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
+
+        SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
+
+        //生成boxVideos数据
+        String boxPhotos = this.createBoxModels(param.getNum(), scenePlusExt.getYunFileBucket(), sid, data, sceneEditInfo, OperationType.ADDORUPDATE.code());
+
+        //更新数据库
+        this.updateBoxModels(sceneEditInfo, boxPhotos);
+
+        return ResultData.ok();
+    }
+
+    @Override
+    public ResultData deleteBoxModel(DeleteSidParamVO param) throws Exception {
+
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+        if(Objects.isNull(scenePlus))
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
+        ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
+
+        SceneEditInfo sceneEditInfo = sceneEditInfoService.getByScenePlusId(scenePlus.getId());
+
+        //根据sid移除json
+        String boxModels = this.createBoxModels(param.getNum(), scenePlusExt.getYunFileBucket(), param.getSid(), null, sceneEditInfo, OperationType.DELETE.code());
+
+        //写数据库
+        this.updateBoxModels(sceneEditInfo, boxModels);
+
+        return ResultData.ok();
+    }
+
+    private void updateBoxModels(SceneEditInfo sceneEditInfo, String boxModels){
+        sceneEditInfoService.update(new LambdaUpdateWrapper<SceneEditInfo>()
+            .set(SceneEditInfo::getBoxModels, boxModels)
+            .setSql("version = version + 1")
+            .eq(SceneEditInfo::getId, sceneEditInfo.getId()));
+    }
+
+    private String createBoxModels(String num, String bucket, String sid, JSONObject data, SceneEditInfo sceneEditInfo, int type) throws Exception{
+
+        String boxModels = null;
+        if(sceneEditInfo != null){
+            boxModels = sceneEditInfo.getBoxModels();
+        }
+        JSONArray boxModelsJson = null;
+        if (StrUtil.isNotEmpty(boxModels)) {
+            boxModelsJson = JSONArray.parseArray(boxModels);
+        }else {
+            boxModelsJson = new JSONArray();
+        }
+
+        String result = null;
+        //删除
+        if(type == OperationType.DELETE.code()){
+            Set<String> deleteFile = new HashSet<>();
+            if(boxModelsJson.size() == 0)
+                return null;
+            for(int i=0;i<boxModelsJson.size();++i){
+                JSONObject ele = boxModelsJson.getJSONObject(i);
+                if(ele.getString("sid").equals(sid)){
+                    boxModelsJson.remove(i);
+                    deleteFile.add(String.format(UploadFilePath.USER_EDIT_PATH, num) + sid + ".glb");
+                }
+            }
+            //删除资源文件
+            if(CollUtil.isNotEmpty(deleteFile))
+                deleteFile.stream().forEach(key -> {
+                    try {
+                        fYunFileService.deleteFile(bucket, key);
+                    } catch (IOException e) {
+                        log.warn("oss删除文件失败,key:{}", key);
+                    }
+                });
+        }else{
+            //更新
+            boolean exist = false;
+            for(int i=0;i<boxModelsJson.size();++i){
+                JSONObject ele = boxModelsJson.getJSONObject(i);
+                if(ele.getString("sid").equals(sid)){
+                    data.put("createTime", ele.getLong("createTime"));
+                    boxModelsJson.set(i, data);
+                    exist = true;
+                }
+            }
+            //新增
+            if(!exist){
+                data.put("createTime", Calendar.getInstance().getTimeInMillis());
+                boxModelsJson.add(data);
+            }
+
+        }
+        if(boxModelsJson.size() != 0){
+
+            List<BoxModelBean> list = Lists.newArrayList();
+            for (Object o : boxModelsJson) {
+                JSONObject jsonObject = (JSONObject)o;
+                list.add(BoxModelBean.builder().createTime(jsonObject.getLong("createTime")).boxModel(jsonObject).build());
+            }
+            //按创建时间倒叙排序
+            list.sort(Comparator.comparingLong(BoxModelBean::getCreateTime).reversed());
+
+            // list转JSONArray
+            JSONArray array = new JSONArray();
+            list.stream().forEach(bean->{
+                array.add(bean.getBoxModel());
+            });
+
+            result = array.toJSONString();
+        }
+
+        return result;
+    }
+}

+ 145 - 0
src/main/java/com/fdkankan/scene/service/impl/DownloadTourVideoServiceImpl.java

@@ -0,0 +1,145 @@
+package com.fdkankan.scene.service.impl;
+
+import cn.hutool.core.exceptions.ExceptionUtil;
+import cn.hutool.core.lang.UUID;
+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.fyun.face.FYunFileServiceInterface;
+import com.fdkankan.model.constants.ConstantFilePath;
+import com.fdkankan.model.constants.UploadFilePath;
+import com.fdkankan.model.utils.CreateObjUtil;
+import com.fdkankan.rabbitmq.util.RabbitMqProducer;
+import com.fdkankan.scene.entity.DownloadTourVideo;
+import com.fdkankan.scene.mapper.IDownloadTourVideoMapper;
+import com.fdkankan.scene.service.IDownloadTourVideoService;
+import com.fdkankan.scene.vo.DownloadTourVideoVO;
+import com.fdkankan.web.response.ResultData;
+import java.io.File;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import lombok.SneakyThrows;
+import org.apache.http.HttpHeaders;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * <p>
+ * 导览视频转换记录表 服务实现类
+ * </p>
+ *
+ * @author 
+ * @since 2022-10-12
+ */
+@Service
+public class DownloadTourVideoServiceImpl extends ServiceImpl<IDownloadTourVideoMapper, DownloadTourVideo> implements IDownloadTourVideoService {
+
+    @Value("${queue.scene.transfer-tour-video}")
+    private String downloadTourVideoQueue;
+    @Value("${fyun.type}")
+    private String type;
+    @Value("${fyun.bucket:4dkankan}")
+    private String bucket;
+
+    @Autowired
+    private RabbitMqProducer rabbitMqProducer;
+    @Autowired
+    private FYunFileServiceInterface fYunFileService;
+
+
+    @Override
+    public DownloadTourVideo getWaitingByNum(String num) {
+        return this.getOne(
+            new LambdaQueryWrapper<DownloadTourVideo>().eq(DownloadTourVideo::getNum, num)
+                .eq(DownloadTourVideo::getState, 0));
+    }
+
+    @Override
+    public void removeByNum(String num) {
+        this.remove(new LambdaQueryWrapper<DownloadTourVideo>().eq(DownloadTourVideo::getNum, num));
+    }
+
+    @Override
+    public ResultData uploadTourVideo(String num, MultipartFile file) throws Exception {
+
+        //查询是否有任务正在执行,如果有,直接返回
+        DownloadTourVideo waiting = this.getWaitingByNum(num);
+        if(Objects.nonNull(waiting)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5064);
+        }
+
+        String uuid = UUID.randomUUID().toString();
+        String fileName = file.getOriginalFilename();
+        String extName = cn.hutool.core.io.FileUtil.extName(fileName);
+        String tempFileName = uuid + "." + extName;
+        String srcPath = ConstantFilePath.SCENE_V4_PATH + num + "/tour/" + tempFileName;
+        File tempFile = new File(srcPath);
+        if(!tempFile.getParentFile().exists()){
+            tempFile.getParentFile().mkdirs();
+        }
+        file.transferTo(tempFile);
+
+        //先将旧纪录置为无效
+        this.removeByNum(num);
+
+        //写入新记录
+        DownloadTourVideo downloadTourVideo = new DownloadTourVideo();
+        downloadTourVideo.setNum(num);
+        downloadTourVideo.setFileName(fileName);
+        downloadTourVideo.setLocalPath(srcPath);
+        this.save(downloadTourVideo);
+
+        //发送mq
+        rabbitMqProducer.sendByWorkQueue(downloadTourVideoQueue, downloadTourVideo);
+
+        return ResultData.ok();
+    }
+
+    @Override
+    public void transferTourVideo(DownloadTourVideo downloadTourVideo) {
+
+        String destPath = null;
+        try {
+            String destFileName = UUID.randomUUID().toString() + ".mp4";
+            destPath = ConstantFilePath.SCENE_V4_PATH + downloadTourVideo.getNum() + "/tour/" + destFileName;
+            File destFile = new File(destPath);
+            if(!destFile.getParentFile().exists()){
+                destFile.getParentFile().mkdir();
+            }
+            String srcPath = downloadTourVideo.getLocalPath();
+            CreateObjUtil.formatMp4(srcPath, destPath);
+            //上传到oss
+            String ossPath = String.format(UploadFilePath.DOWNLOADS_TOUR_VIDEO, downloadTourVideo.getNum()) + downloadTourVideo.getFileName();
+            Map<String, String> headers = new HashMap<>();
+            headers.put(HttpHeaders.CONTENT_TYPE, "application/octet-stream");
+            fYunFileService.uploadFile(bucket, destPath, ossPath, headers);
+            downloadTourVideo.setDownloadPath(ossPath);
+            downloadTourVideo.setState(1);
+            this.updateById(downloadTourVideo);
+        }catch (Exception e) {
+            log.error("导览视频转换失败,num:" + downloadTourVideo.getNum() + "源路径:" + downloadTourVideo.getLocalPath(), e);
+            downloadTourVideo.setReason(ExceptionUtil.stacktraceToString(e, 3000));
+            downloadTourVideo.setState(2);
+            this.updateById(downloadTourVideo);
+        }
+
+    }
+
+    @Override
+    public ResultData downloadTourVideo(String num) {
+        DownloadTourVideoVO result = new DownloadTourVideoVO();
+        DownloadTourVideo downloadTourVideo = this.getOne(new LambdaQueryWrapper<DownloadTourVideo>().eq(DownloadTourVideo::getNum, num));
+        if(Objects.isNull(downloadTourVideo)){
+            result.setStatus(0);
+        }else{
+            result.setStatus(1);
+            result.setTransferStatus(downloadTourVideo.getState());
+            result.setPath(downloadTourVideo.getDownloadPath());
+        }
+        return ResultData.ok(result);
+    }
+}

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

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

+ 1 - 1
src/main/java/com/fdkankan/scene/service/impl/SceneDataDownloadServiceImpl.java

@@ -27,7 +27,7 @@ public class SceneDataDownloadServiceImpl extends ServiceImpl<ISceneDataDownload
     public SceneDataDownload findBySceneNum(String sceneNum) {
 
         List<SceneDataDownload> list = this.list(new LambdaQueryWrapper<SceneDataDownload>()
-                .eq(SceneDataDownload::getNum, sceneNum)
+                .eq(SceneDataDownload::getSceneNum, sceneNum)
                 .orderByDesc(SceneDataDownload::getId));
         if(CollUtil.isEmpty(list)){
             return null;

+ 359 - 57
src/main/java/com/fdkankan/scene/service/impl/SceneEditInfoServiceImpl.java

@@ -1,7 +1,18 @@
 package com.fdkankan.scene.service.impl;
+import cn.hutool.core.net.multipart.UploadFile;
+import cn.hutool.core.util.CharsetUtil;
+import com.fdkankan.common.constant.CommonOperStatus;
+import com.fdkankan.common.constant.SceneAsynFuncType;
+import com.fdkankan.common.constant.SceneAsynModuleType;
+import com.fdkankan.common.constant.SceneAsynOperType;
+import com.fdkankan.common.util.MD5;
+import com.fdkankan.scene.vo.SaveFiltersParamVO;
+import io.opencensus.metrics.LongGauge;
+import java.util.Date;
 
 import cn.hutool.core.bean.BeanUtil;
 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;
@@ -22,6 +33,16 @@ import com.fdkankan.model.constants.ConstantFilePath;
 import com.fdkankan.model.constants.UploadFilePath;
 import com.fdkankan.model.utils.CreateHouseJsonUtil;
 import com.fdkankan.model.utils.CreateObjUtil;
+import com.fdkankan.common.util.FileMd5Util;
+import com.fdkankan.common.util.FileUtils;
+import com.fdkankan.fyun.constant.FYunTypeEnum;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
+import com.fdkankan.model.constants.ConstantFilePath;
+import com.fdkankan.model.constants.UploadFilePath;
+import com.fdkankan.model.utils.ComputerUtil;
+import com.fdkankan.model.utils.CreateHouseJsonUtil;
+import com.fdkankan.model.utils.CreateObjUtil;
+import com.fdkankan.model.utils.SceneUtil;
 import com.fdkankan.redis.constant.RedisKey;
 import com.fdkankan.redis.constant.RedisLockKey;
 import com.fdkankan.redis.util.RedisLockUtil;
@@ -35,6 +56,10 @@ import com.fdkankan.scene.bean.StyleBean;
 import com.fdkankan.scene.bean.TagBean;
 import com.fdkankan.scene.bean.VertexBean;
 import com.fdkankan.scene.bean.WallBean;
+import com.fdkankan.scene.entity.CameraDetail;
+import com.fdkankan.scene.entity.Company;
+import com.fdkankan.scene.entity.SceneAsynOperLog;
+import com.fdkankan.scene.entity.SceneDataDownload;
 import com.fdkankan.scene.entity.SceneEditControls;
 import com.fdkankan.scene.entity.SceneEditInfo;
 import com.fdkankan.scene.entity.SceneEditInfoExt;
@@ -43,6 +68,9 @@ import com.fdkankan.scene.entity.ScenePlusExt;
 import com.fdkankan.scene.mapper.ISceneEditInfoMapper;
 import com.fdkankan.scene.oss.OssUtil;
 import com.fdkankan.scene.service.ILaserService;
+import com.fdkankan.scene.service.ICameraDetailService;
+import com.fdkankan.scene.service.ICompanyService;
+import com.fdkankan.scene.service.ISceneAsynOperLogService;
 import com.fdkankan.scene.service.ISceneDataDownloadService;
 import com.fdkankan.scene.service.ISceneEditControlsService;
 import com.fdkankan.scene.service.ISceneEditInfoExtService;
@@ -51,9 +79,11 @@ import com.fdkankan.scene.service.IScenePlusExtService;
 import com.fdkankan.scene.service.IScenePlusService;
 import com.fdkankan.scene.service.ISceneProService;
 import com.fdkankan.scene.service.ISceneUploadService;
+import com.fdkankan.scene.service.ISurveillanceService;
 import com.fdkankan.scene.vo.BallScreenVideoParamVO;
 import com.fdkankan.scene.vo.BaseDataParamVO;
 import com.fdkankan.scene.vo.BaseFileParamVO;
+import com.fdkankan.scene.vo.BaseSceneParamVO;
 import com.fdkankan.scene.vo.DeleteFileParamVO;
 import com.fdkankan.scene.vo.DeleteLinkPanParamVO;
 import com.fdkankan.scene.vo.DeleteLinkSceneStylesParamVO;
@@ -70,6 +100,9 @@ import com.fdkankan.scene.vo.SceneEditInfoVO;
 import com.fdkankan.scene.vo.SceneInfoParamVO;
 import com.fdkankan.scene.vo.SceneInfoVO;
 import com.fdkankan.web.response.ResultData;
+import com.fdkankan.scene.vo.SurveillanceVO;
+import com.fdkankan.scene.vo.UploadPanoramaVO;
+import com.fdkankan.web.response.ResultData;
 import com.google.common.collect.Lists;
 import com.google.errorprone.annotations.Var;
 import java.io.File;
@@ -86,6 +119,8 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 import lombok.extern.slf4j.Slf4j;
@@ -108,8 +143,13 @@ import org.springframework.web.multipart.MultipartFile;
 public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper, SceneEditInfo> implements ISceneEditInfoService {
 
     @Value("${ecs.checkFile.maxTimes:5}")
+    @Value("${fyun.host}")
+    private String ossUrlPrefix;
+    @Value("${fyun.type}")
+    private String fyunType;
+    @Value("${ecs.checkFile.maxTimes:20}")
     private int maxCheckTimes;
-    @Value("${ecs.checkFile.waitTime:5000}")
+    @Value("${ecs.checkFile.waitTime:1000}")
     private int waitTime;
 
     @Autowired
@@ -135,6 +175,11 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
     @Autowired
     private ILaserService laserService;
 
+    private ICompanyService companyService;
+    @Autowired
+    private ISurveillanceService surveillanceService;
+    @Autowired
+    private ISceneAsynOperLogService sceneAsynOperLogService;
 
     @Transactional
     @Override
@@ -239,6 +284,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         SceneJsonBean sceneJson = new SceneJsonBean();
         BeanUtil.copyProperties(sceneEditInfoExt, sceneJson);
         BeanUtil.copyProperties(sceneEditInfo, sceneJson);
+        sceneJson.setFloorPlanUpload(JSON.parseArray(sceneEditInfo.getFloorPlanUpload()));
         SceneEditControlsVO sceneEditControlsVO = BeanUtil.copyProperties(sceneEditControls, SceneEditControlsVO.class);
         sceneJson.setControls(sceneEditControlsVO);
         sceneJson.setNum(num);
@@ -247,6 +293,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         sceneJson.setSceneResolution(scenePlusExt.getSceneResolution());
         sceneJson.setSceneFrom(scenePlusExt.getSceneFrom());
         sceneJson.setSceneKind(scenePlusExt.getSceneKind());
+        sceneJson.setModelKind(scenePlusExt.getModelKind());
         if(StrUtil.isNotEmpty(scenePlusExt.getVideos())){
             sceneJson.setVideos(scenePlusExt.getVideos());
         }
@@ -260,6 +307,12 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         //发布场景关联相关数据
 //        this.publicLinkSceneData(num, bucket);
 
+        //发布滤镜数据
+        this.publicFilterData(num, sceneEditInfoExt.getFilters(), bucket);
+
+        //发布摄像头数据
+        this.publicSurveillance(num, sceneEditInfoExt.getSurveillances(), bucket);
+
         //本地写sceneJson文件
         String localSceneJsonPath = String.format(ConstantFilePath.SCENE_DATA_PATH_V4, num) + "scene.json";
         FileUtils.writeFile(localSceneJsonPath, JSON.toJSONString(sceneJson));
@@ -290,15 +343,55 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         sceneEditInfoExt.setEditInfoId(sceneEditInfo.getId());
         sceneEditInfoExtService.saveOrUpdate(sceneEditInfoExt);
 
+        scenePlus.setTitle(sceneEditInfo.getTitle());
+        scenePlus.setDescription(sceneEditInfo.getDescription());
+        scenePlus.setHouseType(this.existsHouseType(bucket, num));
+        scenePlusService.updateById(scenePlus);
+
         return ResultData.ok();
     }
 
+    private int existsHouseType(String bucket, String num){
+        String houseTypePath = String.format(UploadFilePath.USER_VIEW_PATH, num) + "houseType.json";
+        boolean exist = fYunFileService.fileExist(bucket, houseTypePath);
+        return exist ? CommonStatus.YES.code().intValue() : CommonStatus.NO.code().intValue();
+    }
+
+    private void publicSurveillance(String num, Integer surveillances, String bucket) throws IOException {
+        String surveillanceJsonPath = String.format(UploadFilePath.USER_EDIT_PATH, num) + "surveillance.json";
+        if(surveillances == CommonStatus.NO.code().intValue()){
+            fYunFileService.deleteFile(bucket, surveillanceJsonPath);
+            return;
+        }
+        List<SurveillanceVO> surveillanceList = surveillanceService.listSurveillance(num);
+        fYunFileService.uploadFile(bucket, JSON.toJSONString(surveillanceList).getBytes(StandardCharsets.UTF_8), surveillanceJsonPath);
+    }
+
+    private void publicFilterData(String num, int filters, String bucket) throws IOException {
+
+        String userEditPath = String.format(UploadFilePath.USER_EDIT_PATH, num);
+        if(filters == CommonStatus.NO.code()){
+            fYunFileService.deleteFile(bucket, userEditPath + "filter.json");
+            return;
+        }
+        String key = String.format(RedisKey.SCENE_filter_DATA, num);
+        List<String> list = redisUtil.lGet(key, 0, -1);
+        JSONArray jsonArray = new JSONArray();
+        list.stream().forEach(str->jsonArray.add(JSON.parseObject(str)));
+        fYunFileService.uploadFile(bucket, JSON.toJSONBytes(jsonArray), userEditPath + "filter.json");
+    }
+
     public void publicLinkSceneData(String num, String bucket) throws IOException {
 
         String imgEditPath = String.format(UploadFilePath.IMG_EDIT_PATH, num);
         String userEditPath = String.format(UploadFilePath.USER_EDIT_PATH, num);
         String imgViewPath = String.format(UploadFilePath.IMG_VIEW_PATH, num);
 
+        //清除发布目录中的场景关联图片
+        if(fYunFileService.fileExist(bucket,imgViewPath + "panorama")){
+            fYunFileService.deleteFolder(bucket,imgViewPath + "panorama");
+        }
+
         //生成links.json并上传到发布目录
         String linkPanKey = String.format(RedisKey.SCENE_LINKPAN_DATA, num);
         Map<String, String> linkPanMap = redisUtil.hmget(linkPanKey);
@@ -321,23 +414,28 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
     private void publicHotData(String sceneNum, SceneEditInfo sceneEditInfo, String bucket) throws IOException {
         String hotDataKey = String.format(RedisKey.SCENE_HOT_DATA, sceneNum);
         Map<String, String> hotMap = redisUtil.hmget(hotDataKey);
-        List<String> hotList = Lists.newArrayList();
-        hotMap.entrySet().stream().forEach(entry->{
-            if(StrUtil.isNotEmpty(entry.getValue())){
-                hotList.add(entry.getValue());
-            }
-        });
-        if(CollUtil.isNotEmpty(hotList)){
-            JSONArray jsonhots = new JSONArray();
-            hotList.stream().forEach(hot->{
-                jsonhots.add(JSONObject.parseObject(hot));
-            });
-            String hotJsonPath = String.format(UploadFilePath.USER_EDIT_PATH, sceneNum) + "hot.json";
-            ossUtil.uploadFileBytes(hotJsonPath, jsonhots.toString().getBytes(StandardCharsets.UTF_8));
 
-            //修改tags状态为是,标识有热点数据
-            this.saveTagsToSceneEditInfo(sceneNum, sceneEditInfo);
+        JSONArray tags = new JSONArray();
+        if(CollUtil.isNotEmpty(hotMap)){
+            List<TagBean> tagBeanList = hotMap.entrySet().stream().map(entry -> {
+                JSONObject jsonObject = JSON.parseObject(entry.getValue());
+                return TagBean.builder()
+                    .createTime(jsonObject.getLong("createTime"))
+                    .tag(jsonObject).build();
+            }).collect(Collectors.toList());
+            //按创建时间倒叙排序
+            tagBeanList.sort(Comparator.comparingLong(TagBean::getCreateTime).reversed());
+
+            //移除createTime字段
+            tagBeanList.stream().forEach(tagBean -> {
+                tags.add(tagBean.getTag());
+            });
         }
+
+        String hotJsonPath = String.format(UploadFilePath.USER_EDIT_PATH, sceneNum) + "hot.json";
+        ossUtil.uploadFileBytes(hotJsonPath, jsonhots.toString().getBytes(StandardCharsets.UTF_8));
+//        this.saveTagsToSceneEditInfo(sceneNum, sceneEditInfo);
+
     }
 
     @Override
@@ -364,6 +462,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
      * @return com.fdkankan.scene.vo.SceneInfoVO
      **/
     private SceneInfoVO getSceneInfo4Edit(String num) throws Exception{
+
         ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
         if(Objects.isNull(scenePlus)){
             throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
@@ -379,6 +478,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         SceneInfoVO sceneInfoVO = new SceneInfoVO();
         BeanUtil.copyProperties(sceneEditInfoExt, sceneInfoVO);
         BeanUtil.copyProperties(sceneEditInfo, sceneInfoVO);
+        sceneInfoVO.setFloorPlanUpload(JSON.parseArray(sceneEditInfo.getFloorPlanUpload()));
         if(Objects.isNull(sceneInfoVO.getFloorPlanAngle())){
             sceneInfoVO.setFloorPlanAngle(0f);
         }
@@ -392,12 +492,72 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         sceneInfoVO.setSceneResolution(scenePlusExt.getSceneResolution());
         sceneInfoVO.setSceneFrom(scenePlusExt.getSceneFrom());
         sceneInfoVO.setSceneKind(scenePlusExt.getSceneKind());
+        sceneInfoVO.setModelKind(scenePlusExt.getModelKind());
         sceneInfoVO.setVideos(scenePlusExt.getVideos());
-//        sceneInfoVO.setMosaicList(this.getMosaicList(num));
+        if(CommonStatus.YES.code().intValue() == sceneEditInfoExt.getMosaic()){
+            sceneInfoVO.setMosaicList(this.getMosaicList(num));
+        }
+
+        this.SortBoxVideos(sceneInfoVO);
 
         return sceneInfoVO;
     }
 
+    private void SortBoxVideos(SceneInfoVO sceneInfoVO){
+        String boxVideos = sceneInfoVO.getBoxVideos();
+        if(StrUtil.isEmpty(boxVideos)){
+            return;
+        }
+        JSONArray boxVideoArr = JSON.parseArray(boxVideos);
+        if(CollUtil.isEmpty(boxVideoArr)){
+            return;
+        }
+        List<TagBean> tagBeanList = boxVideoArr.stream().map(o -> {
+            JSONObject item = (JSONObject) o;
+            return TagBean.builder()
+                .createTime(item.getLong("createTime"))
+                .tag(item).build();
+        }).collect(Collectors.toList());
+
+        //按创建时间倒叙排序
+        tagBeanList.sort(Comparator.comparingLong(TagBean::getCreateTime).reversed());
+
+        //移除createTime字段
+        List<JSONObject> boxVideoList = tagBeanList.stream().map(tagBean -> {
+            JSONObject tag = tagBean.getTag();
+            tag.remove("createTime");
+            return tag;
+        }).collect(Collectors.toList());
+
+        sceneInfoVO.setBoxVideos(JSON.toJSONString(boxVideoList));
+    }
+
+    /**
+     * <p>
+            getInfo接口返回字段扩展
+     * </p>
+     * @author dengsixing
+     * @date 2022/3/9
+     **/
+    private void setExtData(SceneInfoVO sceneInfoVO, Long cameraId) throws Exception{
+
+        if(Objects.isNull(cameraId)){
+            return;
+        }
+
+        CameraDetail cameraDetail = cameraDetailService.findByCameraId(cameraId);
+        if(Objects.isNull(cameraDetail)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_7010);
+        }
+        if(Objects.isNull(cameraDetail.getCompanyId())){
+            return;
+        }
+        Company company = companyService.getById(cameraDetail.getCompanyId());
+        if(Objects.isNull(company)){
+            return;
+        }
+        sceneInfoVO.setDataSync(company.getDataSync());
+    }
 
     /**
      * <p>
@@ -436,6 +596,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         //如果redis没找到,从scene.json中获取
         String objectName = String.format(ConstantFilePath.SCENE_VIEW_DATA_DATA_SCENEJSON, num);
         String objectContent = ossUtil.getFileContent(objectName);
+        log.info("获取scene.json内容,path:{}, content:{}", objectName, objectContent);
         if(StrUtil.isEmpty(objectContent))
             return null;
         sceneInfoVO = JSON.parseObject(objectContent, SceneInfoVO.class);
@@ -477,14 +638,16 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         //处理户型图数据
         //上传floorplan_user.json文件
         FileUtils.writeFile(localDataPath + "floorplan_user.json", floorJsonData);
-        ossUtil.uploadFile(editUserPath + "floorplan_user.json", localDataPath + "floorplan_user.json", false);
+        ossUtil.uploadFile(editUserPath + "floorplan_user.json", localDataPath + "floorplan.json", false);
 
         //写入数据库
         Byte floorPlanUser = null;
         if(StrUtil.isNotEmpty(floorJsonData)){
             JSONObject houseTypeJson = CreateHouseJsonUtil
                 .createHouseTypeJsonByUser(localDataPath + "floorplan_user.json");
-            ossUtil.uploadFileBytes(editUserPath + "houseType.json", houseTypeJson.toJSONString().getBytes(StandardCharsets.UTF_8));
+            if(Objects.nonNull(houseTypeJson)) {
+                ossUtil.uploadFileBytes(editUserPath + "houseType.json", houseTypeJson.toJSONString().getBytes(StandardCharsets.UTF_8));
+            }
 
             floorPlanUser = CommonStatus.YES.code();
         }
@@ -773,9 +936,11 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         String sceneJson = redisUtil.get(key);
         if(StrUtil.isNotEmpty(sceneJson)){
             SceneJsonBean sceneJsonBean = JSON.parseObject(sceneJson, SceneJsonBean.class);
-            sceneJsonBean.setVersion(version);
+            if(Objects.nonNull(version)){
+                sceneJsonBean.setVersion(version);
+            }
             if(Objects.nonNull(imgVersion)){
-                sceneJsonBean.setImgVersion(imgVersion + 1);
+                sceneJsonBean.setImgVersion(imgVersion);
             }
             redisUtil.set(key, JSON.toJSONString(sceneJsonBean));
         }
@@ -785,9 +950,11 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         sceneJson = ossUtil.getFileContent(sceneJsonPath);
         if(StrUtil.isNotEmpty(sceneJson)){
             SceneJsonBean sceneJsonBean = JSON.parseObject(sceneJson, SceneJsonBean.class);
-            sceneJsonBean.setVersion(version);
+            if(Objects.nonNull(version)){
+                sceneJsonBean.setVersion(version);
+            }
             if(Objects.nonNull(imgVersion)){
-                sceneJsonBean.setImgVersion(imgVersion + 1);
+                sceneJsonBean.setImgVersion(imgVersion);
             }
             ossUtil.uploadFileBytes(sceneJsonPath, JSON.toJSONString(sceneJsonBean).getBytes(StandardCharsets.UTF_8));
         }
@@ -1556,6 +1723,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         if(exist){
             return;
         }
+//        String uuid = cn.hutool.core.lang.UUID.randomUUID().toString();
         String lockKey = String.format(RedisLockKey.LOCK_MOSAIC_DATA_SYNC, num);
         boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_1_MINUTE);
         if(!lock){
@@ -1566,8 +1734,8 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
             if(exist){
                 return;
             }
-            String filePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num);
-            String mosaicData = FileUtils.readFile(filePath + "mosaic.json");
+            String filePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "mosaic.json";
+            String mosaicData = FileUtils.readUtf8String(filePath);
             if(StrUtil.isEmpty(mosaicData)){
                 return;
             }
@@ -1606,16 +1774,16 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
             jsonArr.add(JSONObject.parseObject(mosaic));
         });
 
-
+        String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
         String lockKey = String.format(RedisLockKey.LOCK_MOSAIC_JSON, num);
-        boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_1_MINUTE);
+        boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE);
         if(!lock){
             return;
         }
         try{
             FileUtils.writeFile(mosaicPath, jsonArr.toJSONString());
         }finally {
-            redisLockUtil.unlockLua(lockKey);
+            redisLockUtil.unlockLua(lockKey, lockVal);
         }
     }
 
@@ -1833,14 +2001,19 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         List<String> deletDataList = redisUtil.hMultiGet(key, deleteSidList);
         if(CollUtil.isEmpty(deletDataList))
             return;
+        List<String> thumbNameList = deleteSidList.stream().map(sid -> {
+            String linkPan = redisUtil.hget(key, sid);
+            JSONObject linkPanObj = JSON.parseObject(linkPan);
+            return FileUtil.getPrefix(linkPanObj.getString("thumb"));
+        }).collect(Collectors.toList());
 
         //从redis中移除热点数据
         redisUtil.hdel(key, deleteSidList.toArray());
 
         //删除oss文件
         String imgEditPath = String.format(UploadFilePath.IMG_EDIT_PATH, num);
-        deleteSidList.stream().forEach(sid->{
-            ossUtil.deleteObject(imgEditPath + "panorama_edit/" + sid);
+        thumbNameList.stream().forEach(thumbName->{
+            ossUtil.deleteObject(imgEditPath + "panorama_edit/" + thumbName);
         });
 
     }
@@ -1994,15 +2167,16 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         jsonObject.put("styles", styleList);
 
         String linkScenePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "links.json";
+        String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
         String lockKey = String.format(RedisLockKey.LOCK_LINK_SCENE_JSON, num);
-        boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_1_MINUTE);
+        boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE);
         if(!lock){
             return;
         }
         try{
             cn.hutool.core.io.FileUtil.writeUtf8String(jsonObject.toJSONString(), linkScenePath);
         }finally {
-            redisLockUtil.unlockLua(lockKey);
+            redisLockUtil.unlockLua(lockKey, lockVal);
         }
     }
 
@@ -2043,7 +2217,8 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
             return;
         }
         String lockKey = String.format(RedisLockKey.LOCK_LINKPAN_STYLES_SYNC, num);
-        boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_1_MINUTE);
+        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);
         }
@@ -2053,7 +2228,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
                 return;
             }
             String linkSceneFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num);
-            String linkSceneData = FileUtils.readFile(linkSceneFilePath + "links.json");
+            String linkSceneData = FileUtils.readUtf8String(linkSceneFilePath + "links.json");
             if(StrUtil.isEmpty(linkSceneData)){
                 return;
             }
@@ -2070,7 +2245,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
             }
             redisUtil.hmset(key, styleMap);
         }finally {
-            redisLockUtil.unlockLua(lockKey);
+            redisLockUtil.unlockLua(lockKey, lockVal);
         }
 
     }
@@ -2104,7 +2279,8 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
             return;
         }
         String lockKey = String.format(RedisLockKey.LOCK_LINKPAN_DATA_SYNC, num);
-        boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_1_MINUTE);
+        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);
         }
@@ -2114,7 +2290,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
                 return;
             }
             String linkSceneFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num);
-            String linkSceneData = FileUtils.readFile(linkSceneFilePath + "links.json");
+            String linkSceneData = FileUtils.readUtf8String(linkSceneFilePath + "links.json");
             if(StrUtil.isEmpty(linkSceneData)){
                 return;
             }
@@ -2130,7 +2306,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
             }
             redisUtil.hmset(key, map);
         }finally {
-            redisLockUtil.unlockLua(lockKey);
+            redisLockUtil.unlockLua(lockKey, lockVal);
         }
     }
 
@@ -2186,11 +2362,23 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
         }else {
             boxVideosJson = new JSONArray();
         }
+        if(boxVideosJson.size() > 0){
+            int i = 1;
+            long timeInMillis = Calendar.getInstance().getTimeInMillis();
+            for (Object o : boxVideosJson) {
+                JSONObject item = (JSONObject)o;
+                if(Objects.nonNull(item.getLong("createTime"))){
+                    continue;
+                }
+                item.put("createTime", timeInMillis - (i++));
+            }
+        }
 
         String result = null;
         //删除
         if(type == OperationType.DELETE.code()){
-            Set<String> deleteFile = new HashSet<>();
+            Set<String> deleteVidoeFile = new HashSet<>();
+            Set<String> deletePicFile = new HashSet<>();
             if(boxVideosJson.size() == 0)
                 return null;
             for(int i=0;i<boxVideosJson.size();++i){
@@ -2199,11 +2387,11 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
 
                     String poster = ele.getString("poster");
                     if(StrUtil.isNotEmpty(poster))
-                        deleteFile.add(poster);
+                        deletePicFile.add(poster);
                     String url = ele.getString("url");
                     if(StrUtil.isNotEmpty(url)){
-                        deleteFile.add(url);
-                        deleteFile.add(url.replace(".mp4",".flv"));
+                        deleteVidoeFile.add(url);
+                        deleteVidoeFile.add(url.replace(".mp4",".flv"));
                     }
 
                     boxVideosJson.remove(i);
@@ -2211,27 +2399,34 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
             }
 
             //删除资源文件
-            if(CollUtil.isNotEmpty(deleteFile))
+            if(CollUtil.isNotEmpty(deleteVidoeFile))
                 sceneUploadService.delete(
                     DeleteFileParamVO.builder().num(num)
                         .bizType(FileBizType.BOX_VIDEO.code())
-                        .fileNames(new ArrayList<>(deleteFile)).build());
+                        .fileNames(new ArrayList<>(deleteVidoeFile)).build());
+            //删除资源文件
+            if(CollUtil.isNotEmpty(deleteVidoeFile))
+                sceneUploadService.delete(
+                    DeleteFileParamVO.builder().num(num)
+                        .bizType(FileBizType.BOX_POSTER.code())
+                        .fileNames(new ArrayList<>(deletePicFile)).build());
         }else{
 
-            // -: 2022/3/1 目前需求只保留一个,所以这里先注释掉,sid不同时,不追加
+            boxVideo.put("createTime", Calendar.getInstance().getTimeInMillis());
+
             //更新
-//            boolean exist = false;
-//            for(int i=0;i<boxVideosJson.size();++i){
-//                JSONObject ele = boxVideosJson.getJSONObject(i);
-//                if(ele.getString("sid").equals(sid)){
-//                    boxVideosJson.set(i, boxVideo);
-//                    exist = true;
-//                }
-//            }
-//        //新增
-//        if(!exist){
-//            boxVideosJson.add(boxVideo);
-//        }
+            boolean exist = false;
+            for(int i=0;i<boxVideosJson.size();++i){
+                JSONObject ele = boxVideosJson.getJSONObject(i);
+                if(ele.getString("sid").equals(sid)){
+                    boxVideosJson.set(i, boxVideo);
+                    exist = true;
+                }
+            }
+            //新增
+            if(!exist){
+                boxVideosJson.add(boxVideo);
+            }
 
             boxVideosJson.clear();
             boxVideosJson.add(boxVideo);
@@ -2426,4 +2621,111 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
 
         return ResultData.ok();
     }
+
+    @Override
+    public ResultData saveFilter(SaveFiltersParamVO param) throws Exception {
+
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+        if(Objects.isNull(scenePlus)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
+        }
+
+        String key = String.format(RedisKey.SCENE_filter_DATA, param.getNum());
+        JSONArray filterArr = JSON.parseArray(param.getData());
+        int filters = CommonStatus.YES.code();
+        if(CollUtil.isEmpty(filterArr)){
+            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);
+        }
+
+        //写本地文件,作为备份
+        this.writeFilter(param.getNum());
+
+        //如果页面选择恢复默认,filters字段值为否
+        if(Objects.nonNull(param.getReset()) && param.getReset() == CommonStatus.YES.code().intValue()){
+            filters = CommonStatus.NO.code();
+        }
+
+        //更新数据库
+        SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId());
+        sceneEditInfoExt.setFilters(filters);
+        sceneEditInfoExtService.updateById(sceneEditInfoExt);
+
+        return ResultData.ok();
+
+    }
+
+    private void writeFilter(String num) throws Exception{
+
+        String filterPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "filter.json";
+
+        String key = String.format(RedisKey.SCENE_filter_DATA, num);
+        List<String> filters = redisUtil.lGet(key, 0, -1);
+        if(CollUtil.isEmpty(filters)){
+            FileUtils.deleteFile(filterPath);
+            return;
+        }
+
+        String lockKey = String.format(RedisLockKey.LOCK_filter_JSON, 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{
+            FileUtils.writeFile(filterPath, JSON.toJSONString(filters));
+        }finally {
+            redisLockUtil.unlockLua(lockKey, lockVal);
+        }
+    }
+
+    private void syncFiltersFromFileToRedis(String num) throws Exception{
+
+        String key = String.format(RedisKey.SCENE_filter_DATA, num);
+        boolean exist = redisUtil.hasKey(key);
+        if(exist){
+            return;
+        }
+        String lockKey = String.format(RedisLockKey.LOCK_FILTER_DATA_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 filePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num);
+            String filterData = FileUtils.readUtf8String(filePath + "filter.json");
+            if(StrUtil.isEmpty(filterData)){
+                return;
+            }
+            JSONArray jsonArray = JSON.parseArray(filterData);
+            if(CollUtil.isEmpty(jsonArray)){
+                return;
+            }
+            redisUtil.lRightPushAll(key, jsonArray.stream().collect(Collectors.toList()));
+        }finally {
+            redisLockUtil.unlockLua(lockKey, lockVal);
+        }
+    }
+
+    @Override
+    public ResultData listFilter(BaseSceneParamVO param) throws Exception {
+
+        //同步数据
+        this.syncFiltersFromFileToRedis(param.getNum());
+
+        //查询redis
+        String key = String.format(RedisKey.SCENE_filter_DATA, param.getNum());
+        List<String> list = redisUtil.lGet(key, 0, -1);
+        List<JSONObject> collect =
+            list.stream().map(str -> JSON.parseObject(str)).collect(Collectors.toList());
+        return ResultData.ok(collect);
+    }
 }

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

@@ -28,11 +28,14 @@ import com.fdkankan.web.user.SSOUser;
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.Calendar;
+import java.util.Date;
 import java.util.List;
 import java.util.Objects;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
+import org.springframework.util.ObjectUtils;
 
 /**
  * <p>
@@ -59,10 +62,17 @@ public class SceneEditServiceImpl implements ISceneEditService {
     @Autowired
     private OssUtil ossUtil;
 
+    @Value("${scene.expired.month:#{null}}")
+    private Integer expiredMonth;
+
     @Override
     public SceneAuthVO getAuth(String num, SSOUser ssoUser){
 
         ScenePlus scenePlus = scenePlusService.getScenePlusByNum(num);
+        if(Objects.isNull(scenePlus)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
+        }
+        ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
 
         SceneAuthVO sceneAuthVO = new SceneAuthVO();
 
@@ -75,6 +85,12 @@ public class SceneEditServiceImpl implements ISceneEditService {
         sceneAuthVO.setInclude(new ArrayList<>());
         sceneAuthVO.setCompany(null);
 
+        //判断本地资源是否已本删除,如果已删除,前端根据字段值为true提示用户不能使用某些功能,需要重算
+        Date algorithmTime = scenePlusExt.getAlgorithmTime() == null ? scenePlus.getCreateTime() : scenePlusExt.getAlgorithmTime();
+        if (!ObjectUtils.isEmpty(expiredMonth) && com.fdkankan.common.util.DateUtil.delay(algorithmTime, expiredMonth, Calendar.MONTH).before(new Date())) {
+            sceneAuthVO.setSourceExpired(true);
+        }
+
         //判断该场景是否属于增值权益
         boolean isVip = true;
         //获取该相机是否有权益

+ 87 - 9
src/main/java/com/fdkankan/scene/service/impl/ScenePlusServiceImpl.java

@@ -4,6 +4,8 @@ import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.io.FileUtil;
 import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSON;
+import cn.hutool.extra.qrcode.QrCodeUtil;
+import cn.hutool.extra.qrcode.QrConfig;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
@@ -26,6 +28,13 @@ import com.fdkankan.scene.oss.OssUtil;
 import com.fdkankan.scene.service.ISceneEditControlsService;
 import com.fdkankan.scene.service.ISceneEditInfoExtService;
 import com.fdkankan.scene.vo.SceneEditControlsVO;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
+import com.fdkankan.model.constants.ConstantFilePath;
+import com.fdkankan.model.constants.UploadFilePath;
+import com.fdkankan.scene.entity.SceneEditInfoExt;
+import com.fdkankan.scene.entity.ScenePro;
+import com.fdkankan.scene.service.ISceneEditInfoExtService;
+import com.fdkankan.scene.service.ISceneProService;
 import com.fdkankan.web.response.ResultData;
 import com.fdkankan.redis.constant.RedisKey;
 import com.fdkankan.redis.constant.RedisLockKey;
@@ -46,11 +55,15 @@ import com.fdkankan.scene.vo.SceneDataDownloadVO;
 
 import java.io.File;
 import java.nio.charset.StandardCharsets;
+import java.io.File;
 import java.util.List;
 import java.util.Objects;
+import java.util.UUID;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
 
 /**
  * <p>
@@ -64,6 +77,11 @@ import org.springframework.stereotype.Service;
 @Service
 public class ScenePlusServiceImpl extends ServiceImpl<IScenePlusMapper, ScenePlus> implements IScenePlusService {
 
+    @Value("${main.url}")
+    private String mainUrl;
+    @Value("${scene.pro.new.url}")
+    private String sceneProNewUrl;
+
     @Autowired
     private IScenePlusExtService scenePlusExtService;
     @Autowired
@@ -85,6 +103,12 @@ public class ScenePlusServiceImpl extends ServiceImpl<IScenePlusMapper, ScenePlu
     @Autowired
     FdkkLaserConfig fdkkLaserConfig;
 
+    @Autowired
+    private ISceneProService sceneProService;
+    @Autowired
+    private FYunFileServiceInterface fYunFileService;
+    @Autowired
+    private ISceneEditInfoExtService sceneEditInfoExtService;
 
     @Override
     public ScenePlus getScenePlusByNum(String num) {
@@ -134,19 +158,30 @@ public class ScenePlusServiceImpl extends ServiceImpl<IScenePlusMapper, ScenePlu
     }
 
     @Override
-    public ResultData downLoadZSData(BaseSceneParamVO param) throws Exception {
-        String num = param.getNum();
+    public ResultData downLoadZSData(String num) throws Exception {
+
+        if(StrUtil.isEmpty(num)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_3001);
+        }
+
+        String version = "v4";
         ScenePlus scenePlus = this.getScenePlusByNum(num);
+        ScenePro scenePro = null;
         if(Objects.isNull(scenePlus)){
-            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
+            scenePro = sceneProService.getByNum(num);
+            version = "v3";
+            if(Objects.isNull(scenePro)){
+                throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
+            }
         }
 
         SceneDataDownload sceneDataDownload = sceneDataDownloadService.findBySceneNum(num);
         if(sceneDataDownload == null){
             throw new BusinessException(ErrorCode.FAILURE_CODE_5025);
         }
-
-        return ResultData.ok(BeanUtil.copyProperties(sceneDataDownload, SceneDataDownloadVO.class));
+        SceneDataDownloadVO sceneDataDownloadVO = BeanUtil.copyProperties(sceneDataDownload, SceneDataDownloadVO.class);
+        sceneDataDownloadVO.setVersion(version);
+        return ResultData.ok(sceneDataDownloadVO);
     }
 
     @Override
@@ -155,8 +190,8 @@ public class ScenePlusServiceImpl extends ServiceImpl<IScenePlusMapper, ScenePlu
         if(Objects.isNull(scenePlus)){
             throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
         }
-        if(SceneStatus.SUCCESS.code().equals(scenePlus.getSceneStatus())
-            && SceneStatus.NO_DISPLAY.code().equals(scenePlus.getSceneStatus())){
+        if(!SceneStatus.SUCCESS.code().equals(scenePlus.getSceneStatus())
+            && !SceneStatus.NO_DISPLAY.code().equals(scenePlus.getSceneStatus())){
             throw new BusinessException(ErrorCode.FAILURE_CODE_5033);
         }
         if(!PayStatus.PAY.code().equals(scenePlus.getPayStatus())){
@@ -171,7 +206,8 @@ public class ScenePlusServiceImpl extends ServiceImpl<IScenePlusMapper, ScenePlu
         String key = RedisKey.SCENE_VISIT_CNT;
         if(!redisUtil.hHasKey(key, sceneNum)){
             String lockKey = String.format(RedisLockKey.LOCK_SCENE_VISIT_CNT, sceneNum);
-            boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_10_MINUTE);
+            String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
+            boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_10_MINUTE);
             if(!lock){
                 return ResultData.ok();
             }
@@ -186,13 +222,55 @@ public class ScenePlusServiceImpl extends ServiceImpl<IScenePlusMapper, ScenePlu
                     redisUtil.hset(key,  sceneNum, Objects.isNull(viewCount) ? "0" : String.valueOf(viewCount));
                 }
             }finally {
-                redisLockUtil.unlockLua(lockKey);
+                redisLockUtil.unlockLua(lockKey, lockVal);
             }
         }
         redisUtil.hincr(key, sceneNum, 1);
         return ResultData.ok();
     }
 
+    @Override
+    public ResultData uploadShareLogo(String num, MultipartFile file) throws Exception {
+
+        ScenePlus scenePlus = this.getScenePlusByNum(num);
+        if (Objects.isNull(scenePlus)) {
+            return ResultData.error(ErrorCode.FAILURE_CODE_5005);
+        }
+        ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
+        SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId());
+
+        String fileName = file.getOriginalFilename();
+        String extName = fileName.substring(fileName.lastIndexOf("."));
+        File newFile = File.createTempFile(UUID.randomUUID().toString() ,extName);
+        file.transferTo(newFile);
+
+        String logoPath = newFile.getPath();
+
+        String outPathZh = ConstantFilePath.BASE_PATH + File.separator + "sceneQRcode/"+num+".png";
+        String outPathEn = ConstantFilePath.BASE_PATH + File.separator + "sceneQRcode/"+num+"_en.png";
+
+        String webSize = mainUrl + "/" + sceneProNewUrl + num;
+        QrCodeUtil.generate(webSize, QrConfig.create().setImg(logoPath).setWidth(512).setHeight(512), FileUtil.file(outPathZh));
+        QrCodeUtil.generate(webSize + "&lang=en", QrConfig.create().setImg(logoPath).setWidth(512).setHeight(512), FileUtil.file(outPathEn));
+        //上传logo图片
+        String ossLogoPath = String.format(UploadFilePath.DOWNLOADS_QRCODE, num) + "shareLogo" + extName;
+        fYunFileService.uploadFile(scenePlusExt.getYunFileBucket(), logoPath, ossLogoPath);
+
+        //上传二维码
+        fYunFileService.uploadFile(scenePlusExt.getYunFileBucket(), outPathZh, String.format(UploadFilePath.DOWNLOADS_QRCODE, num) + num + ".png");
+        fYunFileService.uploadFile(scenePlusExt.getYunFileBucket(), outPathEn, String.format(UploadFilePath.DOWNLOADS_QRCODE, num) + num + "_en.png");
+
+        sceneEditInfoExt.setShareLogoImg(ossLogoPath);
+        sceneEditInfoExtService.updateById(sceneEditInfoExt);
+
+        FileUtil.del(newFile);
+        FileUtil.del(new File(outPathEn));
+        FileUtil.del(new File(outPathZh));
+
+
+        return ResultData.ok();
+    }
+
     /**
      * <p>
      *     初始化场景数据

+ 210 - 43
src/main/java/com/fdkankan/scene/service/impl/SceneProServiceImpl.java

@@ -1,16 +1,20 @@
 package com.fdkankan.scene.service.impl;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.RuntimeUtil;
 import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 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.common.constant.*;
 import com.fdkankan.model.constants.ConstantFileName;
 import com.fdkankan.model.constants.ConstantFilePath;
 import com.fdkankan.model.constants.UploadFilePath;
@@ -53,17 +57,13 @@ import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import java.io.File;
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Calendar;
-import java.util.Comparator;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
 import java.util.Map.Entry;
-import java.util.Objects;
-import java.util.Set;
 import java.util.stream.Collectors;
 import lombok.extern.slf4j.Slf4j;
+import org.redisson.Redisson;
+import org.redisson.RedissonLock;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
@@ -82,6 +82,10 @@ import org.springframework.web.multipart.MultipartFile;
 @Service
 public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro> implements ISceneProService {
 
+    @Value("${fyun.host}")
+    private String ossUrlPrefix;
+    @Value("${fyun.type}")
+    private String fyunType;
     @Value("${main.url}")
     private String mainUrl;
     @Value("${scene.url}")
@@ -192,20 +196,12 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
     }
 
     private void addOrUpdateIcons(String num, List<String> icons) throws Exception{
-
+        if(CollUtil.isEmpty(icons)){
+            return;
+        }
         this.syncIconsFromFileToRedis(num);
-
         String key = String.format(RedisKey.SCENE_HOT_ICONS, num);
         redisUtil.sSet(key, icons.toArray());
-
-
-//        Map<String, String> addOrUpdateMap = new HashMap<>();
-//        hotDataList.stream().forEach(hotData -> {
-//            addOrUpdateMap.put(hotData.getSid(), hotData.getHotData());
-//        });
-
-        //处理新增和修改数据
-//        this.addOrUpdateHotData(num, addOrUpdateMap);
     }
 
     @Override
@@ -216,11 +212,15 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
         if (scenePlus == null)
             throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
         ScenePlusExt scenePlusExt = scenePlusExtService.getScenePlusExtByPlusId(scenePlus.getId());
+        String bucket = scenePlusExt.getYunFileBucket();
 
         List<String> deleteSidList = param.getSidList();
 
         //处理删除状态数据
-        this.deleteHotData(param.getNum(), deleteSidList, scenePlusExt.getYunFileBucket());
+        this.deleteHotData(param.getNum(), deleteSidList, bucket);
+
+        //删除导览中的热点数据
+        this.deleteHotDataFromTourJson(param.getNum(), param.getSidList(), bucket);
 
         //写入本地文件,作为备份
         this.writeHotJson(param.getNum());
@@ -233,6 +233,31 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
         return ResultData.ok();
     }
 
+    private void deleteHotDataFromTourJson(String num, List<String> sidList, String bucket){
+        String key = String.format(UploadFilePath.USER_EDIT_PATH, num) + "tour.json";
+        String tourJson = fYunFileService.getFileContent(bucket, key);
+        if(StrUtil.isEmpty(tourJson)){
+            return;
+        }
+        JSONArray jsonArray = JSON.parseArray(tourJson);
+        if(CollUtil.isEmpty(jsonArray)){
+            return;
+        }
+        jsonArray.stream().forEach(tour->{
+            JSONObject obj = (JSONObject) tour;
+            JSONArray itemArra = obj.getJSONArray("list");
+            itemArra.stream().forEach(item->{
+                JSONObject itemObj = (JSONObject) item;
+                String tagId = itemObj.getString("tagId");
+                if(tagId != null && sidList.contains(tagId)){
+                    itemObj.remove("tagId");
+                }
+            });
+        });
+        fYunFileService.uploadFile(bucket, jsonArray.toJSONString().getBytes(StandardCharsets.UTF_8), key);
+
+    }
+
     @Override
     public ResultData deleteIcons(DeleteHotIconParamVO param) throws Exception {
 
@@ -348,7 +373,8 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
             return;
         }
         String lockKey = String.format(RedisLockKey.LOCK_HOT_DATA_SYNC, num);
-        boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_1_MINUTE);
+        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);
         }
@@ -357,8 +383,8 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
             if(exist){
                 return;
             }
-            String tagsFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num);
-            String tagsData = FileUtils.readFile(tagsFilePath + "hot.json");
+            String tagsFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "hot.json";
+            String tagsData = FileUtils.readUtf8String(tagsFilePath);
             if(StrUtil.isEmpty(tagsData)){
                 return;
             }
@@ -374,7 +400,7 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
             }
             redisUtil.hmset(key, map);
         }finally {
-            redisLockUtil.unlockLua(lockKey);
+            redisLockUtil.unlockLua(lockKey, lockVal);
         }
     }
 
@@ -393,7 +419,8 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
             return;
         }
         String lockKey = String.format(RedisLockKey.LOCK_HOT_ICONS_SYNC, num);
-        boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_1_MINUTE);
+        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);
         }
@@ -402,8 +429,8 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
             if(exist){
                 return;
             }
-            String tagsFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num);
-            String tagsData = FileUtils.readFile(tagsFilePath + "hot.json");
+            String tagsFilePath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "hot.json";
+            String tagsData = FileUtils.readUtf8String(tagsFilePath);
             if(StrUtil.isEmpty(tagsData)){
                 return;
             }
@@ -414,7 +441,7 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
             }
             redisUtil.sSet(key,  iconArr.toJavaList(String.class).toArray());
         }finally {
-            redisLockUtil.unlockLua(lockKey);
+            redisLockUtil.unlockLua(lockKey, lockVal);
         }
 
     }
@@ -452,14 +479,15 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
 
         String hotJsonPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "hot.json";
         String lockKey = String.format(RedisLockKey.LOCK_HOT_JSON, num);
-        boolean lock = redisLockUtil.lock(lockKey, RedisKey.EXPIRE_TIME_1_MINUTE);
+        String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
+        boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE);
         if(!lock){
             return;
         }
         try{
             FileUtils.writeFile(hotJsonPath, jsonObject.toJSONString());
         }finally {
-            redisLockUtil.unlockLua(lockKey);
+            redisLockUtil.unlockLua(lockKey, lockVal);
         }
     }
 
@@ -521,7 +549,6 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
             }
         }
 
-
         //从redis中移除热点数据
         redisUtil.hdel(key, deleteSidList.toArray());
     }
@@ -642,14 +669,11 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
             editInfo.setScenePlusId(scenePlus.getId());
             sceneEditInfoService.save(editInfo);
         }else{
-            sceneEditInfoService.upgradeVersionById(editInfo.getId());
+            sceneEditInfoService.upgradeVersionAndImgVersionById(editInfo.getId());
             //更新scenejson缓存和oss文件版本号
-            sceneEditInfoService.upgradeSceneJsonVersion(param.getNum(), editInfo.getVersion() + 1, null, bucket);
+            sceneEditInfoService.upgradeSceneJsonVersion(param.getNum(), editInfo.getVersion() + 1, editInfo.getImgVersion() + 1, bucket);
         }
 
-        //更新scene.json版本号
-//        sceneEditInfoService.upgradeVersionToSceneJson(param.getNum());
-
         return ResultData.ok();
     }
 
@@ -723,7 +747,138 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
 //        return ResultData.ok();
 //    }
 
-    private void uploadFileofterRebuildPanoram(String path, String sceneNum, String bucket) throws Exception {
+    /**
+     * 老算法(dam)上传模型逻辑
+     * @param num
+     * @param bucket
+     * @param dataSource
+     * @param buildType
+     * @throws Exception
+     */
+    private void buildModel4Dam(String num, String bucket, String dataSource, String buildType, MultipartFile file) throws Exception {
+        //文件上传的位置可以自定义
+        String path = dataSource + "_obj2txt";
+        String zipPath = path + "/zip/";
+        String filePath =  path + "/extras/";
+        String resultPath = path + "/results/";
+
+        //压缩文件处理:解压缩,解压缩后复制等操作
+        this.objAndImgFileHandler(resultPath, filePath, zipPath, file);
+
+        //创建data.json
+        this.writeDataJson(path);
+
+        //调用算法,不同的类型调用不同的算法
+        if("V2".equals(buildType)){
+            CreateObjUtil.objToTxt(path , "1");
+        }
+        if("V3".equals(buildType)){
+            CreateObjUtil.build3dModel(path , "1");
+        }
+
+        //算法计算完后,生成压缩文件,上传到oss
+        this.uploadFileofterRebuildPanoram(path, filePath, num, bucket);
+    }
+
+    /**
+     * 新算法(3dtiles)上传模型逻辑
+     * @param num
+     * @param bucket
+     * @param dataSource
+     * @throws Exception
+     */
+    private void buildModel43dtiles(String num, String bucket, String dataSource, MultipartFile file) throws Exception {
+        //文件上传的位置可以自定义
+        String path = dataSource + "_obj2Tiles" + File.separator;
+        String meshPath = path  + "mesh";
+        String zipPath = path + "zip" + File.separator;
+        String zipFilePath = zipPath + file.getOriginalFilename();
+
+
+        //压缩文件处理:解压缩,解压缩后复制等操作
+        FileUtil.del(path);
+        FileUtil.mkdir(zipPath);
+        File zipFile = new File(zipFilePath);
+        file.transferTo(zipFile);
+        ZipUtil.unzip(zipFilePath, meshPath);
+
+        //检测文件
+        String floorsJsonPath = meshPath + File.separator + "floors.json";
+        if(!FileUtil.exist(floorsJsonPath)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5068);
+        }
+        String floorsJsonStr = FileUtil.readUtf8String(floorsJsonPath);
+        JSONObject floorsJsonObj = JSON.parseObject(floorsJsonStr);
+        JSONArray floorArr = floorsJsonObj.getJSONArray("floors");
+        if(CollUtil.isEmpty(floorArr)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5069);
+        }
+        Set<String> floorNameSet = new HashSet<>();
+        floorArr.stream().forEach(item->{
+            JSONObject itemObj = (JSONObject) item;
+            //楼层目录是否存在
+            String name = itemObj.getString("name");
+            if(StrUtil.isEmpty(name) || !FileUtil.exist(meshPath + File.separator + name)){
+                throw new BusinessException(ErrorCode.FAILURE_CODE_5070);
+            }
+            //检测obj文件是否存在
+            String objPath = itemObj.getString("objPath");
+            if(StrUtil.isEmpty(objPath) || !FileUtil.exist(path + objPath)){
+                throw new BusinessException(ErrorCode.FAILURE_CODE_5070);
+            }
+            if(floorNameSet.contains(name)){
+                throw new BusinessException(ErrorCode.FAILURE_CODE_5069);
+            }
+            floorNameSet.add(name);
+        });
+
+        //读取oss上的floors.jsoon用于校验用户上传的模型楼层数是否一一对应
+        String ossFloorsJson = fYunFileService.getFileContent(bucket, String.format(UploadFilePath.DATA_VIEW_PATH, num) + "mesh/floors.json");
+        JSONObject orginFloorsJsonObj = JSON.parseObject(ossFloorsJson);
+        JSONArray orginFloorArr = orginFloorsJsonObj.getJSONArray("floors");
+        Set<String> orginFloorNameSet = orginFloorArr.stream().map(item -> {
+            JSONObject itemObj = (JSONObject) item;
+            return itemObj.getString("name");
+        }).collect(Collectors.toSet());
+        if(floorNameSet.size() != orginFloorNameSet.size()){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5070);
+        }
+        orginFloorNameSet.stream().forEach(orginName->{
+            if(!floorNameSet.contains(orginName)){
+                throw new BusinessException(ErrorCode.FAILURE_CODE_5070);
+            }
+        });
+
+
+        //调用算法
+        String command = "bash /home/ubuntu/bin/Obj2Tiles.sh " + path;
+        log.info("上传3dtiles模型开始, num:{}, targetPath:{}", num, path);
+//        RuntimeUtil.exec(command);
+        CreateObjUtil.callshell(command);
+        log.info("上传3dtiles模型结束, num:{}, targetPath:{}", num, path);
+
+        //检测计算结果
+        String tilesPath = path + "3dtiles";
+        String tilesetJsonPath = tilesPath + File.separator + "tileset.json";
+        boolean success = ComputerUtil.checkComputeCompleted(tilesetJsonPath, maxCheckTimes, waitTime);
+        if(!success){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_7013);
+        }
+
+        //删除logs
+        FileUtil.del(tilesPath + File.separator + "logs");
+
+        //算法计算完后,生成压缩文件,上传到oss
+        //上传3dtiles
+        fYunFileService.deleteFolder(bucket, String.format(UploadFilePath.IMG_VIEW_PATH, num) + "3dtiles");
+        fYunFileService.uploadFileByCommand(bucket, tilesPath, String.format(UploadFilePath.IMG_VIEW_PATH, num) + "3dtiles");
+        //上传mesh
+        fYunFileService.deleteFolder(bucket, String.format(UploadFilePath.DATA_VIEW_PATH, num) + "mesh");
+        fYunFileService.uploadFileByCommand(bucket, meshPath, String.format(UploadFilePath.DATA_VIEW_PATH, num) + "mesh");
+
+    }
+
+    private void uploadFileofterRebuildPanoram(String path, String filePath, String sceneNum, String bucket) throws Exception {
         //因为共享目录有延迟,这里循环检测算法是否计算完毕3次,每次隔五秒
         String uploadJsonPath = path + File.separator + "results" +File.separator+"upload.json";
         boolean exist = ComputerUtil.checkComputeCompleted(uploadJsonPath, maxCheckTimes, waitTime);
@@ -758,13 +913,25 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
             }
         }
 
-        CreateObjUtil.convertTxtToDam( path + File.separator + "results" +File.separator+"modeldata.txt", path + File.separator + "results" +File.separator+ ConstantFileName.modelUUID+"_50k.dam");
-        CreateObjUtil.convertDamToLzma(path + File.separator + "results");
-        CreateObjUtil.convertTxtToDam( path + File.separator + "results" +File.separator+"modeldata.txt", path + File.separator + "results" + File.separator+ConstantFileName.modelUUID+"_50k.dam");
-        map.put(path + File.separator + "results" +File.separator+ConstantFileName.modelUUID+"_50k.dam.lzma", imgViewPath +ConstantFileName.modelUUID+"_50k.dam.lzma");
+        String damPath = path + File.separator + "results" +File.separator+ ConstantFileName.modelUUID+"_50k.dam";
+        CreateObjUtil.convertTxtToDam( path + File.separator + "results" +File.separator+"modeldata.txt", damPath);
+        boolean existDam = ComputerUtil.checkComputeCompleted(damPath, 5, 2);
+        if(!existDam){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_7013);
+        }
+//        CreateObjUtil.convertDamToLzma(path + File.separator + "results");
+//        CreateObjUtil.convertTxtToDam( path + File.separator + "results" +File.separator+"modeldata.txt", path + File.separator + "results" + File.separator+ConstantFileName.modelUUID+"_50k.dam");
+//        map.put(path + File.separator + "results" +File.separator+ConstantFileName.modelUUID+"_50k.dam.lzma", imgViewPath +ConstantFileName.modelUUID+"_50k.dam.lzma");
         map.put(path + File.separator + "results" +File.separator+ConstantFileName.modelUUID+"_50k.dam", imgViewPath+ConstantFileName.modelUUID+"_50k.dam");
 
-        //        fYunFileService.uploadMulFiles(bucket, map);
+        String ossMeshPath = String.format(UploadFilePath.DATA_VIEW_PATH, sceneNum) + "mesh";
+        //删除oss中的mesh
+        fYunFileService.deleteFolder(bucket, ossMeshPath);
+        //上传obj相关文件
+        List<String> fileNames = FileUtil.listFileNames(filePath);
+        fileNames.stream().forEach(name->map.put(filePath + name, ossMeshPath + File.separator + name));
+
+        fYunFileService.uploadMulFiles(bucket, map);
     }
 
     private void writeDataJson(String path) throws IOException {
@@ -804,7 +971,7 @@ public class SceneProServiceImpl extends ServiceImpl<ISceneProMapper, ScenePro>
         }
         file.transferTo(targetFile);
 
-        FileUtils.decompress(zipPath + file.getOriginalFilename(), zipPath + "data/");
+        ZipUtil.unzip(zipPath + file.getOriginalFilename(), zipPath + "data/");
 
         //源文件数据,判断是否有多个文件夹,有多个就提示错误,有一个就将文件夹里数据迁移到extras目录,无直接迁移到extras目录
         boolean flag = false;

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

@@ -2,6 +2,8 @@ package com.fdkankan.scene.service.impl;
 
 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.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
@@ -36,6 +38,7 @@ import java.util.Objects;
 import java.util.Set;
 import java.util.UUID;
 import javax.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -50,6 +53,7 @@ import org.springframework.web.multipart.MultipartFile;
  * @author 
  * @since 2022-01-19
  */
+@Slf4j
 @Service
 public class SceneUploadServiceImpl extends ServiceImpl<ISceneUploadMapper, SceneUpload> implements ISceneUploadService {
 
@@ -150,6 +154,7 @@ public class SceneUploadServiceImpl extends ServiceImpl<ISceneUploadMapper, Scen
                 log.error(ossPath+"上传文件失败"+e);
                 throw new BusinessException(ErrorCode.FAILURE_CODE_7013);
             }
+
             urlList.add(realFileName);
             try{
                 newFile.delete();

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

@@ -0,0 +1,107 @@
+package com.fdkankan.scene.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+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.exception.BusinessException;
+import com.fdkankan.scene.entity.SceneEditInfoExt;
+import com.fdkankan.scene.entity.ScenePlus;
+import com.fdkankan.scene.entity.Surveillance;
+import com.fdkankan.scene.mapper.ISurveillanceMapper;
+import com.fdkankan.scene.service.ISceneEditInfoExtService;
+import com.fdkankan.scene.service.IScenePlusService;
+import com.fdkankan.scene.service.ISurveillanceService;
+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.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 监控推拉流信息 服务实现类
+ * </p>
+ *
+ * @author 
+ * @since 2022-09-16
+ */
+@Service
+public class SurveillanceServiceImpl extends ServiceImpl<ISurveillanceMapper, Surveillance> implements ISurveillanceService {
+
+    @Autowired
+    private IScenePlusService scenePlusService;
+    @Autowired
+    private ISceneEditInfoExtService sceneEditInfoExtService;
+
+    @Override
+    public ResultData saveSurveillance(SurveillanceParamVO param) {
+
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+        if(Objects.isNull(scenePlus)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
+        }
+        SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId());
+
+        Surveillance surveillance = this.getBySid(param.getNum(), param.getSid());
+        if(Objects.isNull(surveillance)){
+            surveillance = new Surveillance();
+        }
+        surveillance.setSid(param.getSid());
+        surveillance.setPanoId(param.getPanoId());
+        surveillance.setNum(param.getNum());
+        surveillance.setName(param.getName());
+        surveillance.setData(param.getData().toJSONString());
+        surveillance.setPlayUrl(param.getPlayUrl());
+        this.saveOrUpdate(surveillance);
+
+        sceneEditInfoExt.setSurveillances(CommonStatus.YES.code().intValue());
+        sceneEditInfoExtService.updateById(sceneEditInfoExt);
+
+        return ResultData.ok();
+    }
+
+    @Override
+    public ResultData deleteSurveillance(BaseSidParamVO param) {
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+        if(Objects.isNull(scenePlus)){
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
+        }
+        SceneEditInfoExt sceneEditInfoExt = sceneEditInfoExtService.getByScenePlusId(scenePlus.getId());
+
+        this.remove(new LambdaQueryWrapper<Surveillance>().eq(Surveillance::getSid, param.getSid()));
+
+        long count = this.count(new LambdaQueryWrapper<Surveillance>().eq(Surveillance::getNum, param.getNum()));
+        if(count < 1){
+            sceneEditInfoExt.setSurveillances(CommonStatus.NO.code().intValue());
+        }
+        sceneEditInfoExtService.updateById(sceneEditInfoExt);
+        return ResultData.ok();
+    }
+
+    @Override
+    public List<SurveillanceVO> listSurveillance(String num) {
+        List<Surveillance> list = this.list(new LambdaQueryWrapper<Surveillance>().eq(Surveillance::getNum, num).orderByDesc(Surveillance::getId));
+        if(Objects.isNull(list)){
+            return null;
+        }
+        List<SurveillanceVO> voList = list.stream().map(item -> {
+            SurveillanceVO vo = BeanUtil.copyProperties(item, SurveillanceVO.class, "data");
+            vo.setData(JSON.parseObject(item.getData()));
+            return vo;
+        }).collect(Collectors.toList());
+        return voList;
+    }
+
+    @Override
+    public Surveillance getBySid(String num, String sid) {
+        return this.getOne(new LambdaQueryWrapper<Surveillance>().eq(Surveillance::getSid, sid).eq(Surveillance::getNum, num));
+    }
+
+}

+ 25 - 0
src/main/java/com/fdkankan/scene/vo/BaseJsonDataParamVO.java

@@ -0,0 +1,25 @@
+package com.fdkankan.scene.vo;
+
+import com.alibaba.fastjson.JSONObject;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import lombok.Data;
+
+/**
+ * <p>
+ * 通用data类型参数类
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/2/10
+ **/
+@Data
+public class BaseJsonDataParamVO {
+
+    @NotBlank(message = "场景码不能为空")
+    private String num;
+
+    @NotNull(message = "数据不能为空")
+    private JSONObject data;
+
+}

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

@@ -0,0 +1,20 @@
+package com.fdkankan.scene.vo;
+
+import javax.validation.constraints.NotBlank;
+import lombok.Data;
+
+/**
+ * <p>
+ * 通用sid类型参数类
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/2/10
+ **/
+@Data
+public class BaseSidParamVO extends BaseSceneParamVO{
+
+    @NotBlank(message = "sid不能为空")
+    private String sid;
+
+}

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

@@ -0,0 +1,21 @@
+package com.fdkankan.scene.vo;
+
+import lombok.Data;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/10/13
+ **/
+@Data
+public class DownloadTourVideoVO {
+
+    private Integer status;
+    private Integer transferStatus;
+    private String path;
+
+
+}

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

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

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

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

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

@@ -32,6 +32,11 @@ public class SceneAuthVO {
      */
     private boolean isVip;
 
+    /**
+     * 本地资源是否失效
+     */
+    private boolean sourceExpired;
+
     private Long company;
 
     private Object exclude;

+ 3 - 1
src/main/java/com/fdkankan/scene/vo/SceneDataDownloadVO.java

@@ -5,9 +5,11 @@ import lombok.Data;
 @Data
 public class SceneDataDownloadVO {
 
-    private String num;
+    private String sceneNum;
 
     private String fileMd5;
 
     private String downloadPath;
+
+    private String version;
 }

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

@@ -66,6 +66,11 @@ public class SceneEditInfoParamVO extends BaseSceneParamVO{
      */
     private String loadingLogoFile;
 
+    /**
+     * 用户上传自定义平面图数据
+     */
+    private String floorPlanUpload;
+
     private SceneEditControlsParamVO controls;
 
 

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

@@ -1,6 +1,8 @@
 package com.fdkankan.scene.vo;
 
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.annotation.TableField;
 import java.util.List;
 import lombok.AllArgsConstructor;
 import lombok.Builder;
@@ -134,6 +136,11 @@ public class SceneInfoVO {
     private String sceneKind;
 
     /**
+     * 算法模型类型(dam,3dtiles)
+     */
+    private String modelKind;
+
+    /**
      * 空间视频数据
      */
     private String boxVideos;
@@ -143,6 +150,11 @@ public class SceneInfoVO {
     private String boxPhotos;
 
     /**
+     * 空间模型数据
+     */
+    private String boxModels;
+
+    /**
      *点位视频
      */
     private String videos;
@@ -178,6 +190,11 @@ public class SceneInfoVO {
     private Float floorPlanCompass;
 
     /**
+     * 用户上传自定义平面图
+     */
+    private JSONArray floorPlanUpload;
+
+    /**
      * 是否保存导览
      */
     private Integer tours;
@@ -202,7 +219,15 @@ public class SceneInfoVO {
      */
     private Integer links;
 
+    /**
+     * 是否有滤镜(0-否,1-是)
+     */
+    private Integer filters;
 
+    /**
+     * 是否有监控摄像头数据
+     */
+    private Integer surveillances;
 
 
 }

+ 45 - 0
src/main/java/com/fdkankan/scene/vo/SurveillanceParamVO.java

@@ -0,0 +1,45 @@
+package com.fdkankan.scene.vo;
+
+import com.alibaba.fastjson.JSONObject;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotEmpty;
+import lombok.Data;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/9/16
+ **/
+@Data
+public class SurveillanceParamVO {
+
+    @NotBlank(message = "场景码不能为空")
+    private String num;
+
+    @NotEmpty(message = "数据不能为空")
+    private JSONObject data;
+
+    @NotBlank(message = "name不能为空")
+    private String name;
+
+    @NotBlank(message = "playUrl不能为空")
+    private String playUrl;
+
+    @NotBlank(message = "panoId不能为空")
+    private String panoId;
+
+    @NotBlank(message = "sid不能为空")
+    private String sid;
+
+    private String type;
+
+    private String deviceId;
+
+    private String channelId;
+
+    private String rtspUrl;
+
+}

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

@@ -0,0 +1,41 @@
+package com.fdkankan.scene.vo;
+
+import com.alibaba.fastjson.JSONObject;
+import java.io.Serializable;
+import lombok.Data;
+
+/**
+ * <p>
+ * 监控推拉流信息
+ * </p>
+ *
+ * @author 
+ * @since 2022-09-16
+ */
+@Data
+public class SurveillanceVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    /**
+     * 监控名称
+     */
+    private String name;
+
+    /**
+     * 摄像头设置信息
+     */
+    private JSONObject data;
+
+    /**
+     * 播放地址
+     */
+    private String playUrl;
+
+    private String sid;
+
+    private String panoId;
+
+}

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

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

+ 32 - 0
src/main/resources/bootstrap-prod-eur.yml

@@ -0,0 +1,32 @@
+spring:
+  application:
+    name: 4dkankan-center-scene
+  cloud:
+    nacos:
+      server-addr: 172.31.42.151:8848
+      namespace: 4dkankan-v4-prod-eur
+      config:
+        file-extension: yaml
+        namespace: ${spring.cloud.nacos.namespace}
+        shared-configs:
+          - data-id: common-db-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+
+          - data-id: common-redis-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+
+          - data-id: common-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+
+          - data-id: common-fyun-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+
+          - data-id: common-rabbitmq-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+      discovery:
+        namespace: ${spring.cloud.nacos.namespace}

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

@@ -0,0 +1,39 @@
+spring:
+  application:
+    name: 4dkankan-center-scene
+  cloud:
+    nacos:
+      server-addr: 172.20.1.63:8848
+      namespace: 4dkankan-v4-prod
+      config:
+        file-extension: yaml
+        namespace: ${spring.cloud.nacos.namespace}
+        shared-configs:
+          - data-id: common-db-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+
+          - data-id: common-redis-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+
+          - data-id: common-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+
+          - data-id: common-fyun-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+
+          - data-id: common-rabbitmq-config.yaml
+            group: DEFAULT_GROUP
+            refresh: true
+      discovery:
+        namespace: ${spring.cloud.nacos.namespace}
+
+
+
+
+
+
+

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

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

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