Jelajahi Sumber

add offline

xiewj 3 bulan lalu
induk
melakukan
5b1845f9a6
32 mengubah file dengan 1643 tambahan dan 10 penghapusan
  1. 18 0
      720yun_fd_base/gis_common/src/main/java/com/gis/common/annotation/LogAnnotation.java
  2. 51 0
      720yun_fd_base/gis_common/src/main/java/com/gis/common/aop/ListenerLogRegister.java
  3. 22 0
      720yun_fd_base/gis_common/src/main/java/com/gis/common/constant/CommonConstant.java
  4. 28 0
      720yun_fd_base/gis_common/src/main/java/com/gis/common/constant/ImageType.java
  5. 27 0
      720yun_fd_base/gis_common/src/main/java/com/gis/common/constant/ImageTypeDetail.java
  6. 32 0
      720yun_fd_base/gis_common/src/main/java/com/gis/common/constant/UploadFilePath.java
  7. 3 1
      720yun_fd_base/gis_common/src/main/java/com/gis/common/util/CmdUtils.java
  8. 18 0
      720yun_fd_base/gis_common/src/main/java/com/gis/common/util/FileUtils.java
  9. 4 0
      720yun_fd_base/gis_domain/pom.xml
  10. 109 0
      720yun_fd_base/gis_domain/src/main/java/com/gis/domain/bean/SceneEditControlsBean.java
  11. 250 0
      720yun_fd_base/gis_domain/src/main/java/com/gis/domain/bean/SceneViewInfoBean.java
  12. 16 0
      720yun_fd_base/gis_domain/src/main/java/com/gis/domain/dto/WorkOfflineDTO.java
  13. 21 0
      720yun_fd_base/gis_domain/src/main/java/com/gis/domain/dto/WorkOfflineDetailDTO.java
  14. 16 0
      720yun_fd_base/gis_domain/src/main/java/com/gis/domain/dto/WorkOfflineDoneDTO.java
  15. 5 0
      720yun_fd_base/gis_domain/src/main/java/com/gis/domain/entity/WorkEntity.java
  16. 1 0
      720yun_fd_base/gis_oss/src/main/java/com/gis/oss/constant/CmdConstant.java
  17. 24 0
      720yun_fd_base/gis_service/src/main/java/com/gis/service/IDownloadService.java
  18. 3 0
      720yun_fd_base/gis_service/src/main/java/com/gis/service/WorkService.java
  19. 689 0
      720yun_fd_base/gis_service/src/main/java/com/gis/service/impl/DownloadServiceImpl.java
  20. 8 0
      720yun_fd_base/gis_service/src/main/java/com/gis/service/impl/WorkServiceImpl.java
  21. 60 0
      720yun_fd_base/gis_service/src/main/java/com/gis/util/DownloadUtil.java
  22. 3 3
      720yun_fd_consumer/src/main/java/com/gis/listener/container/DoSliceQueueListener.java
  23. 2 2
      720yun_fd_consumer/src/main/java/com/gis/listener/container/PanoMigrateSceneQueueListener.java
  24. 2 0
      720yun_fd_consumer/src/main/java/com/gis/listener/container/PanoPayStatusSceneQueueListener.java
  25. 19 1
      720yun_fd_consumer/src/main/java/com/gis/listener/container/RabbitMQConfig.java
  26. 2 0
      720yun_fd_consumer/src/main/java/com/gis/listener/container/SceneQueueListener.java
  27. 2 0
      720yun_fd_consumer/src/main/java/com/gis/listener/container/SceneWorkQueueListener.java
  28. 131 0
      720yun_fd_consumer/src/main/java/com/gis/listener/container/WorkOfflineListener.java
  29. 2 1
      720yun_fd_consumer/src/main/resources/application-sit.yml
  30. 68 2
      720yun_fd_manage/src/main/java/com/gis/controller/WorkController.java
  31. 2 0
      720yun_fd_manage/src/main/resources/application-sit.yml
  32. 5 0
      pom.xml

+ 18 - 0
720yun_fd_base/gis_common/src/main/java/com/gis/common/annotation/LogAnnotation.java

@@ -0,0 +1,18 @@
+package com.gis.common.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * @author Xiewj
+ * @date 2025/5/6
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface LogAnnotation {
+}
+
+
+

+ 51 - 0
720yun_fd_base/gis_common/src/main/java/com/gis/common/aop/ListenerLogRegister.java

@@ -0,0 +1,51 @@
+package com.gis.common.aop;
+
+import cn.hutool.core.util.IdUtil;
+import com.yomahub.tlog.core.rpc.TLogLabelBean;
+import com.yomahub.tlog.core.rpc.TLogRPCHandler;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.amqp.core.Message;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author Xiewj
+ * @date 2025/4/30
+ */
+@Aspect
+@Component
+public class ListenerLogRegister {
+
+    public static final TLogRPCHandler T_LOG_RPC_HANDLER = new TLogRPCHandler();
+
+    @Pointcut("@annotation(com.gis.common.annotation.LogAnnotation)")
+    public void registryTarget(){}
+
+    @Before("registryTarget()")
+    public void processLog(JoinPoint joinPoint) {
+        Message message = findFirstArgumentOfType(joinPoint, Message.class);
+        String messageId = (message != null) ?  message.getMessageProperties().getMessageId()  : IdUtil.getSnowflakeNextIdStr();
+
+        TLogLabelBean labelBean = new TLogLabelBean(null, null, null, messageId, null);
+
+        // 假设你有地方可以设置或记录 messageId
+        // labelBean.setMessageId(messageId); // 如果支持的话
+
+        T_LOG_RPC_HANDLER.processProviderSide(labelBean);
+    }
+
+    /**
+     * 从 JoinPoint 中查找指定类型的第一个参数
+     */
+    private <T> T findFirstArgumentOfType(JoinPoint joinPoint, Class<T> type) {
+        Object[] args = joinPoint.getArgs();
+        for (Object arg : args) {
+            if (type.isInstance(arg)) {
+                return type.cast(arg);
+            }
+        }
+        return null;
+    }
+}

+ 22 - 0
720yun_fd_base/gis_common/src/main/java/com/gis/common/constant/CommonConstant.java

@@ -0,0 +1,22 @@
+package com.gis.common.constant;
+
+
+public class CommonConstant {
+
+    public static final String[] prefixArr = new String[]{
+            UploadFilePath.DATA_VIEW_PATH,
+            UploadFilePath.VOICE_VIEW_PATH,
+            UploadFilePath.VIDEOS_VIEW_PATH,
+            UploadFilePath.IMG_VIEW_PATH,
+            UploadFilePath.USER_VIEW_PATH,
+    };
+
+    public static final ImageType[] imageTypes = new ImageType[]{
+            ImageType.builder().name("4k_face").size("4096").ranges(new String[]{"0", "511", "1023", "1535", "2047","2559","3071","3583"}).build(),
+            ImageType.builder().name("2k_face").size("2048").ranges(new String[]{"0", "511", "1023", "1535"}).build(),
+            ImageType.builder().name("1k_face").size("1024").ranges(new String[]{"0", "511"}).build(),
+            ImageType.builder().name("512_face").size("512").ranges(new String[]{"0"}).build()
+    };
+
+
+}

+ 28 - 0
720yun_fd_base/gis_common/src/main/java/com/gis/common/constant/ImageType.java

@@ -0,0 +1,28 @@
+package com.gis.common.constant;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/2/24
+ **/
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImageType {
+
+    private String name;
+
+    private String size;
+
+    private String[] ranges;
+
+}

+ 27 - 0
720yun_fd_base/gis_common/src/main/java/com/gis/common/constant/ImageTypeDetail.java

@@ -0,0 +1,27 @@
+package com.gis.common.constant;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/2/24
+ **/
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class ImageTypeDetail {
+
+    private String i;
+    private String j;
+    private String x;
+    private String y;
+
+}

+ 32 - 0
720yun_fd_base/gis_common/src/main/java/com/gis/common/constant/UploadFilePath.java

@@ -0,0 +1,32 @@
+package com.gis.common.constant;
+
+/**
+ * @author Xiewj
+ * @date 2025/5/6
+ */
+public class UploadFilePath {
+
+    public static final String EDIT_PATH = "scene_edit_data/%s/";
+    public static final String VIEW_PATH = "scene_view_data/%s/";
+    public static final String USER_EDIT_PATH = "scene_edit_data/%s/user/";
+    public static final String USER_VIEW_PATH = "scene_view_data/%s/user/";
+    public static final String DATA_EDIT_PATH = "scene_edit_data/%s/data/";
+    public static final String DATA_VIEW_PATH = "scene_view_data/%s/data/";
+    public static final String IMG_EDIT_PATH = "scene_edit_data/%s/images/";
+    public static final String IMG_VIEW_PATH = "scene_view_data/%s/images/";
+    public static final String VIDEOS_EDIT_PATH = "scene_edit_data/%s/video/";
+    public static final String VIDEOS_VIEW_PATH = "scene_view_data/%s/video/";
+    public static final String VOICE_EDIT_PATH = "scene_edit_data/%s/voice/";
+    public static final String VOICE_VIEW_PATH = "scene_view_data/%s/voice/";
+    public static final String SCENE_NUM_PATH = "scene/%s";
+    public static final String IMG_CACHES_PATH = "scene/%s/caches/images/";
+    public static final String VIDEOS_CACHES_PATH = "scene/%s/caches/videos/";
+    public static final String DOWNLOADS_QRCODE = "downloads/scene/%s/QRcode/";
+    public static final String DOWNLOADS_TOUR_VIDEO = "downloads/scene/%s/tour/";
+    public static final String BUILD_LOG_PATH = "build_log/%s/";
+    public static final String MANAGE_FILE_PATH = "manage/%s/%s";
+    public static final String scene_result_data_path = "scene_result_data/%s/";
+
+    public UploadFilePath() {
+    }
+}

+ 3 - 1
720yun_fd_base/gis_common/src/main/java/com/gis/common/util/CmdUtils.java

@@ -166,5 +166,7 @@ public class CmdUtils {
         }
 
     }
-
+    public static void callLineSh(String command){
+        callLine(command, null);
+    }
 }

+ 18 - 0
720yun_fd_base/gis_common/src/main/java/com/gis/common/util/FileUtils.java

@@ -0,0 +1,18 @@
+package com.gis.common.util;
+
+import cn.hutool.core.io.FileUtil;
+import com.alibaba.fastjson.JSON;
+
+import java.io.File;
+import java.util.regex.Matcher;
+
+/**
+ * @author Xiewj
+ * @date 2025/5/6
+ */
+public class FileUtils {
+
+    public static void writeUtf8String(final Object content, final String filePath )  {
+        FileUtil.writeUtf8String(JSON.toJSONStringWithDateFormat(content,"yyyy-MM-dd HH:mm:ss"), filePath.replaceAll("/", Matcher.quoteReplacement(File.separator)));
+    }
+}

+ 4 - 0
720yun_fd_base/gis_domain/pom.xml

@@ -17,5 +17,9 @@
         <groupId>com.gis</groupId>
         <artifactId>gis_common</artifactId>
     </dependency>
+    <dependency>
+            <groupId>com.fdkankan</groupId>
+            <artifactId>4dkankan-common-utils</artifactId>
+    </dependency>
     </dependencies>
 </project>

+ 109 - 0
720yun_fd_base/gis_domain/src/main/java/com/gis/domain/bean/SceneEditControlsBean.java

@@ -0,0 +1,109 @@
+package com.gis.domain.bean;
+
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/1/18
+ **/
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SceneEditControlsBean implements Serializable {
+
+    /**
+     * 是否展示小地图(0-不展示,1-展示)
+     */
+    private Integer showMap;
+
+    /**
+     * 是否需要密码(0-不需要,1-需要)
+     */
+    private Integer showLock;
+
+    /**
+     * 是否展示标题(0-不需要,1-需要)
+     */
+    private Integer showTitle;
+
+    /**
+     * 是否展示漫游按钮(0-不需要,1-需要)
+     */
+    private Integer showPanorama;
+
+    /**
+     * 是否展示3D按钮(0-不需要,1-需要)
+     */
+    private Integer showDollhouse;
+
+    /**
+     * 是否展示2D按钮(0-不需要,1-需要)
+     */
+    private Integer showFloorplan;
+
+    /**
+     * 是否展示VR(0-不需要,1-需要)
+     */
+    private Integer showVR;
+
+    /**
+     * 是否展示自动导览(0-不需要,1-需要)
+     */
+    private Integer showTour;
+
+    /**
+     * 是否展示测量线(0-不需要,1-需要)
+     */
+    private Integer showRule;
+
+    /**
+     * 是否展示标尺(0-不需要,1-需要)
+     */
+    private Integer showScale;
+
+    /**
+     * 是否展示分享场景(0-不需要,1-需要)
+     */
+    private Integer showShare;
+
+    /**
+     * 是否展示分享热点(0-不需要,1-需要)
+     */
+    private Integer showTagshare;
+
+    /**
+     * 是否展示合照开关(0-不需要,1-需要)
+     */
+    private Integer showCapture;
+
+    /**
+     * 多媒体标签标题
+     */
+    private Integer showTagTitle;
+
+    /**
+     * 指示牌标签标题
+     */
+    private Integer showBillboardTitle;
+
+    /**
+     * 视频监控标签标题
+     */
+    private Integer showCameraTitle;
+
+    /**
+     * 场景关联标签标题
+     */
+    private Integer showLinkTitle;
+
+}

+ 250 - 0
720yun_fd_base/gis_domain/src/main/java/com/gis/domain/bean/SceneViewInfoBean.java

@@ -0,0 +1,250 @@
+package com.gis.domain.bean;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import lombok.AllArgsConstructor;
+import lombok.Builder;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * <p>
+ * TODO
+ * </p>
+ *
+ * @author dengsixing
+ * @since 2022/1/19
+ **/
+@Data
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class SceneViewInfoBean implements Serializable {
+
+    private static final long serialVersionUID = 1l;
+
+    /**
+     * 场景码
+     */
+    private String num;
+
+    /**
+     * 地面logo名称
+     */
+    private String floorLogo;
+
+    /**
+     * 地面logo大小
+     */
+    private Integer floorLogoSize;
+
+    /**
+     * 地面logo文件名称
+     */
+    private String floorLogoFile;
+
+    /**
+     * 背景音乐
+     */
+    private String music;
+
+    /**
+     * 背景音乐文件名称
+     */
+    private String musicFile;
+
+    /**
+     * 浏览密码
+     */
+    private String scenePassword;
+
+    /**
+     * 场景标题
+     */
+    private String title;
+
+    /**
+     * 场景描述
+     */
+    private String description;
+
+    private SceneEditControlsBean controls;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+//    /**
+//     * 点位数量
+//     */
+//    private Integer panoCount;
+//
+//    /**
+//     * 球幕视频数量
+//     */
+//    private Integer videoCount;
+
+    /**
+     * 版本
+     */
+    private Integer version;
+
+    /**
+     * 图片版本
+     */
+    private Integer imgVersion;
+
+    /**
+     * 场景关联版本
+     */
+    private Integer linkVersion;
+
+    /**
+     * 是否上传了户型图(0-否,1-是)
+     */
+    private Byte floorPlanUser;
+
+//    private String cadInfo;
+//
+//    private Byte isUploadObj;
+//
+//    private Integer floorEditVer;
+//
+//    private Integer floorPublishVer;
+
+    /**
+     * 初始点信息
+     */
+    private String entry;
+
+    /**
+     * 全景图加载方式,tiles/1k:1k瓦片图,tiles/2:2k瓦片图,tiles/4k:4k瓦片图,pan:全景图 ,local:本地切片,cube:立体图
+     */
+    private String sceneResolution;
+
+    /**
+     * 场景来源,lite:双目lite相机,pro:八目相机,minion:双面转台相机,laser:激光相机,virtual:虚拟场景,sketch:图片建模场景
+     */
+    private String sceneFrom;
+
+    /**
+     * 切图方式(tiles:瓦片图,face:切片图,pan:全景图 ,local:本地切片,cube:立体图)
+     */
+    private String sceneKind;
+
+    /**
+     * 算法模型类型(dam,3dtiles)
+     */
+    private String modelKind;
+
+    /**
+     * 空间视频数据
+     */
+    private String boxVideos;
+    /**
+     * 空间贴图数据
+     */
+    private String boxPhotos;
+
+    /**
+     * 空间模型数据
+     */
+    private String boxModels;
+
+    /**
+     *点位视频
+     */
+    private String videos;
+
+    /**
+     * 是否有热点数据
+     */
+    private Integer tags;
+
+    /**
+     * 加载logo名
+     */
+    private String loadingLogo;
+
+    /**
+     * 加载logo文件名
+     */
+    private String loadingLogoFile;
+
+    /**
+     * 数据同步方式
+     */
+    private String dataSync;
+
+    /**
+     * 户型角度
+     */
+    private Float floorPlanAngle;
+
+    /**
+     * 指南针角度
+     */
+    private Float floorPlanCompass;
+
+    /**
+     * 用户上传自定义平面图
+     */
+    private JSONArray floorPlanUpload;
+
+    /**
+     * 是否保存导览
+     */
+    private Integer tours;
+
+    /**
+     * 是否有马赛克
+     */
+    private Integer mosaic;
+
+    /**
+     * 马赛克列表
+     */
+    private List<JSONObject> mosaicList;
+
+    /**
+     * 水印文件名
+     */
+    private String waterMark;
+
+    /**
+     * 是否有场景关联(0-否,1-是)
+     */
+    private Integer links;
+
+    /**
+     * 是否有滤镜(0-否,1-是)
+     */
+    private Integer filters;
+
+    /**
+     * 是否有监控摄像头数据
+     */
+    private Integer surveillances;
+
+    /**
+     * 场景容量 单位 MB
+     */
+    private Integer space;
+
+    /**
+     * 分享信息
+     */
+    private JSONObject sns;
+
+    /**
+     * 是否有指示牌(0-否,1-是)
+     */
+    private Integer billboards;
+
+
+}

+ 16 - 0
720yun_fd_base/gis_domain/src/main/java/com/gis/domain/dto/WorkOfflineDTO.java

@@ -0,0 +1,16 @@
+package com.gis.domain.dto;
+
+import lombok.Data;
+
+/**
+ * @author Xiewj
+ * @date 2024/4/3
+ */
+@Data
+public class WorkOfflineDTO {
+
+    private String workId;
+
+    private String path;
+
+}

+ 21 - 0
720yun_fd_base/gis_domain/src/main/java/com/gis/domain/dto/WorkOfflineDetailDTO.java

@@ -0,0 +1,21 @@
+package com.gis.domain.dto;
+
+import lombok.Data;
+
+/**
+ * @author Xiewj
+ * @date 2024/4/3
+ */
+@Data
+public class WorkOfflineDetailDTO {
+
+    private String workId; //作品id
+
+    private String path; //下载本地挂载磁盘路径
+
+    private Integer progress;
+
+    private String url;
+
+
+}

+ 16 - 0
720yun_fd_base/gis_domain/src/main/java/com/gis/domain/dto/WorkOfflineDoneDTO.java

@@ -0,0 +1,16 @@
+package com.gis.domain.dto;
+
+import lombok.Data;
+
+/**
+ * @author Xiewj
+ * @date 2024/4/3
+ */
+@Data
+public class WorkOfflineDoneDTO {
+
+    private String workId; //作品id
+
+    private String url; //http下载路径
+
+}

+ 5 - 0
720yun_fd_base/gis_domain/src/main/java/com/gis/domain/entity/WorkEntity.java

@@ -99,4 +99,9 @@ public class WorkEntity extends BaseStrEntity implements Serializable {
 
     @ApiModelProperty(value = "切图状态:-1切图失败 0等待中 1 排队 2切图中 3切图完成", name = "panoStatus")
     private Integer panoStatus;
+
+    @ApiModelProperty(value = "切图状态:-1失败 0未生成 1排队中 2生成中 3生成成功 ", name = "offlineStatus")
+    private Integer offlineStatus;
+
+    public String offlineUrl;
 }

+ 1 - 0
720yun_fd_base/gis_oss/src/main/java/com/gis/oss/constant/CmdConstant.java

@@ -57,4 +57,5 @@ public class CmdConstant {
 
     public static final String FYUN_DELETE = "bash /mnt/shell/fyun/fyun-deled.sh %s /%s %s %s %s";
 
+    public final static String RM_Folder = "rm -rf @Folder";
 }

+ 24 - 0
720yun_fd_base/gis_service/src/main/java/com/gis/service/IDownloadService.java

@@ -0,0 +1,24 @@
+package com.gis.service;
+
+public interface IDownloadService {
+    String downloadHandler(String num) throws Exception;
+
+    void downloadWithoutCutImg(String num) throws Exception;
+
+    void downloadMeshScene(String num) throws Exception;
+
+    void downloadMeshSceneV3(String num) throws Exception;
+
+
+    /**
+     *
+     * @param num
+     * @param path
+     * @param resolution 分辨路 2k 4k
+     * @param subPath 需要切图的子目录 tiles-场景本身全景图  panorama/d9rHSlO544803/tiles-场景关联全景图
+     * @throws Exception
+     */
+    void cutImg(String num, String path, String resolution, String subPath, String version) throws Exception;
+
+}
+

+ 3 - 0
720yun_fd_base/gis_service/src/main/java/com/gis/service/WorkService.java

@@ -80,4 +80,7 @@ public interface WorkService extends IService<WorkEntity> {
     WorkEntity findByNum(String num);
 
     void updatePanoStatus(String id, int panoStatus);
+
+    boolean updateOfflineStatus(String id, int offlineStatus);
+
 }

+ 689 - 0
720yun_fd_base/gis_service/src/main/java/com/gis/service/impl/DownloadServiceImpl.java

@@ -0,0 +1,689 @@
+//package com.gis.service.impl;
+//
+//import cn.hutool.core.collection.CollUtil;
+//import cn.hutool.core.collection.ConcurrentHashSet;
+//import cn.hutool.core.date.DateUtil;
+//import cn.hutool.core.date.TimeInterval;
+//import cn.hutool.core.io.FileUtil;
+//import cn.hutool.core.util.StrUtil;
+//import cn.hutool.http.HttpUtil;
+//import com.alibaba.fastjson.JSON;
+//import com.alibaba.fastjson.JSONObject;
+//import com.alibaba.fastjson.serializer.SerializerFeature;
+//import com.fdkankan.common.constant.CommonStatus;
+//import com.fdkankan.common.constant.SceneKind;
+//import com.fdkankan.common.constant.SceneVersionType;
+//import com.fdkankan.common.constant.ServerCode;
+//import com.fdkankan.common.util.DateExtUtil;
+//import com.fdkankan.common.util.FileUtils;
+//import com.fdkankan.filestorage.FileStorageTemplate;
+//import com.gis.common.constant.CommonConstant;
+//import com.gis.common.constant.ImageTypeDetail;
+//import com.gis.common.constant.UploadFilePath;
+//import com.gis.common.util.CmdUtils;
+//import com.gis.common.util.RedisUtil;
+//import com.gis.common.constant.ImageType;
+//import com.gis.domain.bean.SceneEditControlsBean;
+//import com.gis.domain.bean.SceneViewInfoBean;
+//import com.gis.service.IDownloadService;
+//import com.gis.util.DownloadUtil;
+//import com.google.common.collect.Lists;
+//import lombok.extern.slf4j.Slf4j;
+//import lombok.var;
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.beans.factory.annotation.Value;
+//import org.springframework.stereotype.Service;
+//
+//import javax.annotation.Resource;
+//import java.io.File;
+//import java.io.UnsupportedEncodingException;
+//import java.net.URLEncoder;
+//import java.nio.file.Files;
+//import java.nio.file.Path;
+//import java.nio.file.Paths;
+//import java.util.*;
+//import java.util.concurrent.Callable;
+//import java.util.concurrent.ExecutorService;
+//import java.util.concurrent.Executors;
+//import java.util.concurrent.Future;
+//import java.util.stream.Collectors;
+//
+//@Slf4j(topic = "IDownloadService")
+//@Service
+//public class DownloadServiceImpl implements IDownloadService {
+//
+//    @Resource
+//    FileStorageTemplate fileStorageTemplate;
+//
+//
+//    private static final String[] prefixArr4v3 = new String[]{
+//            "data/data%s/", "images/images%s/", "voice/voice%s/", "video/video%s/"
+//    };
+//
+////    private static final List<ImageType> imageTypes = Lists.newArrayList();
+////    static{
+////        imageTypes.add(ImageType.builder().name("4k_face").size("4096").ranges(new String[]{"0", "511", "1023", "1535", "2047","2559","3071","3583"}).build());
+////        imageTypes.add(ImageType.builder().name("2k_face").size("2048").ranges(new String[]{"0", "511", "1023", "1535"}).build());
+////        imageTypes.add(ImageType.builder().name("1k_face").size("1024").ranges(new String[]{"0", "511"}).build());
+////        imageTypes.add(ImageType.builder().name("512_face").size("512").ranges(new String[]{"0"}).build());
+////    }
+//    @Autowired
+//    DownloadUtil downloadUtil;
+//
+//    @Value("${path.v4school}")
+//    private String v4localPath;
+//    @Value("${path.zip-local}")
+//    private String zipLocalFormat;
+//    @Value("${path.source-local}")
+//    private String sourceLocal;
+//    @Value("${fyun.bucket:4dkankan}")
+//    private String bucket;
+//    @Value("${download.config.public-url}")
+//    private String publicUrl;
+//    @Value("${path.v3school:#{null}}")
+//    private String v3localPath;
+//    @Value("${zip.nThreads}")
+//    private int zipNthreads;
+//    @Value("${download.config.resource-url}")
+//    private String resourceUrl;
+//    @Value("${path.zip-root}")
+//    private String wwwroot;
+//    @Value("${download.config.exe-content}")
+//    private String exeContent;
+//    @Value("${download.config.exe-content-v3:#{null}}")
+//    private String exeContentV3;
+//    @Value("${download.config.exe-name}")
+//    private String exeName;
+//    @Value("${url.v3.getInfo}")
+//    private String v3GetInfoUrl;
+//
+//    @Autowired
+//    private RedisUtil redisUtil;
+//
+//
+//    @Override
+//    public String downloadHandler(String num) throws Exception {
+//
+//        //zip包路径
+//        String zipPath = null;
+//        try {
+//            TimeInterval timer = DateUtil.timer();
+//
+//            //删除资源目录
+//            FileUtil.del(String.format(this.sourceLocal, num, ""));
+//
+//            //定义压缩包
+//            zipPath = String.format(this.zipLocalFormat, DateExtUtil.format(new Date(), DateExtUtil.dateStyle6), num);
+//            File zipFile = new File(zipPath);
+//            if(!zipFile.getParentFile().exists()){
+//                zipFile.getParentFile().mkdirs();
+//            }
+//
+//            SceneViewInfoBean sceneViewInfo = this.getSceneJson(num);
+//            String resolution = sceneViewInfo.getSceneResolution();
+//            //国际版存在已经切好图的情况,下载时不需要再切图,只需要把文件直接下载下来打包就可以了
+//            if(SceneKind.FACE.code().equals(sceneViewInfo.getSceneKind())){
+//                resolution = "notNeadCut";
+//            }
+//
+//            int imagesVersion = -1;
+//            Integer version = sceneViewInfo.getVersion();
+//            if(Objects.nonNull(version)){
+//                imagesVersion = version;
+//            }
+//
+//            //固定文件写入
+//            this.zipLocalFiles(num, "v4");
+//            log.info("打包固定文件耗时, num:{}, time:{}", num, timer.intervalRestart());
+//
+//            //oss文件写入
+//            this.zipOssFiles(num, resolution, true, SceneVersionType.V4.code());
+//            log.info("打包oss文件耗时, num:{}, time:{}", num, timer.intervalRestart());
+//
+//            //重新写入scene.json(去掉密码访问设置)
+//            this.zipSceneJson(num, sceneViewInfo);
+//
+//            //写入启动命令
+//            this.zipBat(num, "v4");
+//
+//            //打压缩包
+////            ZipUtil.zip(String.format(this.sourceLocal, num, ""), zipPath);
+//            this.zip(String.format(this.sourceLocal, num, ""), zipPath);
+//
+//            FileUtil.del(String.format(this.sourceLocal, num, ""));
+//
+//            return zipPath;
+//
+//            // TODO: 2024/1/4 生成的压缩包放哪里待定
+////            String uploadPath = String.format(this.zipOssFormat, num);
+////            fYunFileService.uploadFileByCommand(bucket, zipPath, uploadPath);
+//
+//        }catch (Exception e){
+//            //更新进度为下载失败
+//            throw e;
+//        }
+//    }
+//
+//    @Override
+//    public void downloadWithoutCutImg(String num) throws Exception {
+//
+//        //zip包路径
+//        try {
+//            TimeInterval timer = DateUtil.timer();
+//
+//            SceneViewInfoBean sceneViewInfo = this.getSceneJson(num);
+//            String resolution = sceneViewInfo.getSceneResolution();
+//            //国际版存在已经切好图的情况,下载时不需要再切图,只需要把文件直接下载下来打包就可以了
+//            if(SceneKind.FACE.code().equals(sceneViewInfo.getSceneKind())){
+//                resolution = "notNeadCut";
+//            }
+//
+//            //固定文件写入
+//            this.zipLocalFiles(num, "v4");
+//            log.info("打包固定文件耗时, num:{}, time:{}", num, timer.intervalRestart());
+//
+//            //oss文件写入
+//            this.zipOssFiles(num, resolution, false, SceneVersionType.V4.code());
+//            log.info("打包oss文件耗时, num:{}, time:{}", num, timer.intervalRestart());
+//
+//            //重新写入scene.json(去掉密码访问设置)
+//            this.zipSceneJson(num, sceneViewInfo);
+//
+//            //写入启动命令
+//            this.zipBat(num, "v4");
+//
+//        }catch (Exception e){
+//            //更新进度为下载失败
+//            log.error("场景下载失败,num:{}", num, e);
+//            throw e;
+//        }
+//    }
+//
+//    @Override
+//    public void downloadMeshScene(String num) throws Exception {
+//        //zip包路径
+//        try {
+//            TimeInterval timer = DateUtil.timer();
+//
+//            SceneViewInfoBean sceneViewInfo = this.getSceneJson(num);
+//            String resolution = sceneViewInfo.getSceneResolution();
+//            //国际版存在已经切好图的情况,下载时不需要再切图,只需要把文件直接下载下来打包就可以了
+//            if(SceneKind.FACE.code().equals(sceneViewInfo.getSceneKind())){
+//                resolution = "notNeadCut";
+//            }
+//
+//            //固定文件写入
+//            this.zipLocalFiles(num, "v4");
+//            log.info("打包固定文件耗时, num:{}, time:{}", num, timer.intervalRestart());
+//
+//            //oss文件写入
+//            this.zipOssFiles(num, resolution, true, SceneVersionType.V4.code());
+//            log.info("打包oss文件耗时, num:{}, time:{}", num, timer.intervalRestart());
+//
+//            //重新写入scene.json(去掉密码访问设置)
+//            this.zipSceneJson(num, sceneViewInfo);
+//
+//            //写入启动命令
+//            this.zipBat(num, "v4");
+//
+//            this.zip(String.format(this.sourceLocal, num, ""), String.format(zipLocalFormat, DateExtUtil.format(new Date(), DateExtUtil.dateStyle6), num));
+//
+////            String uploadPath = String.format(this.zipOssFormat, num);
+////            fYunFileService.uploadFile(String.format(zipLocalFormat, num, num), uploadPath);
+//
+//            log.info("总耗时, num:{}, time:{}", num, timer.intervalRestart());
+//
+//        }catch (Exception e){
+//            //更新进度为下载失败
+//            log.error("场景下载失败,num:{}", num, e);
+//            throw e;
+//        }finally {
+//            FileUtil.del(String.format(this.sourceLocal, num, ""));
+//        }
+//    }
+//
+//    @Override
+//    public void downloadMeshSceneV3(String num) throws Exception {
+//
+//        try {
+//            TimeInterval timer = DateUtil.timer();
+//
+//            //删除资源目录
+//            FileUtil.del(String.format(this.sourceLocal, num, ""));
+//
+//            //定义压缩包d
+//            String resolution = "2k";
+//            JSONObject getInfoJson = this.getInfo(num);
+//            // 转台、激光显示4k图片
+//            if (getInfoJson.getInteger("sceneSource") == 3 || getInfoJson.getInteger("sceneSource") == 4) {
+//                resolution = "4k";
+//            }
+//
+//            //固定文件写入
+//            timer.intervalRestart();
+//            this.zipLocalFiles(num, "v3");
+//            log.info("打包固定文件耗时, num:{}, time:{}", num, timer.intervalRestart());
+//
+//            //oss文件写入
+//            this.zipOssFiles(num, resolution, true, SceneVersionType.V3.code());
+//            log.info("打包oss文件耗时, num:{}, time:{}", num, timer.intervalRestart());
+//
+//            //重新写入scene.json(去掉密码访问设置)
+//            this.zipGetInfoJson(num, getInfoJson);
+//
+//            //写入启动命令
+//            this.zipBat(num, "v3");
+//
+//            //打压缩包
+//
+//            this.zip(String.format(this.sourceLocal, num, ""), String.format(zipLocalFormat, num, num));
+//
+//            log.info("总耗时, num:{}, time:{}", num, timer.intervalRestart());
+//
+//            //上传压缩包
+////            String uploadPath = String.format(this.zipOssFormat, num);
+////            fileStorageTemplate.uploadFile(String.format(zipLocalFormat, num, num), uploadPath);
+//
+//        }catch (Exception e){
+//            //更新进度为下载失败
+//            log.error("场景下载失败,num:{}", num, e);
+//            throw e;
+//        }
+//    }
+//
+//
+//    private void zipGetInfoJson(String num, JSONObject getInfo) throws Exception{
+//
+//        //访问密码置0
+//        String getInfoKey = String.format("data/data%s/", num) + "getInfo.json";
+//        String getInfoStr = getInfo.toString().replace(this.publicUrl, "");
+//        FileUtil.writeUtf8String(getInfoStr, String.format(this.sourceLocal, num, this.wwwroot + getInfoKey));
+//    }
+//    private  JSONObject getInfo(String num){
+//        String url = String.format(v3GetInfoUrl, num);
+//        String getInfoResult = HttpUtil.get(url);
+//        JSONObject jsonObject = JSONObject.parseObject(getInfoResult);
+//        if(Objects.isNull(jsonObject)
+//                || !ServerCode.SUCCESS.code().equals(jsonObject.getInteger("code"))
+//                || Objects.isNull(jsonObject.getJSONObject("data"))){
+//            throw new RuntimeException("获取getInfo信息失败,url=" + url);
+//        }
+//        JSONObject data = jsonObject.getJSONObject("data");
+//        if (data.getInteger("sceneSource") != 2)
+//        {
+//            data.put("sceneScheme", 3);
+//        }
+//        data.put("needKey", 0);
+//        data.put("sceneKey", "");
+//        return data;
+//    }
+//
+//    private Map<String, List<String>> getAllFilesV3(String num, String v3localPath, String bucket) throws Exception{
+//        //列出oss所有文件路径
+//        List<String> ossFilePaths = new ArrayList<>();
+//        for (String prefix : prefixArr4v3) {
+//            prefix = String.format(prefix, num);
+//            List<String> keys = fileStorageTemplate.getFileFolder(bucket, prefix);
+//            if(CollUtil.isEmpty(keys)){
+//                continue;
+//            }
+//            if(fileStorageTemplate.getActive().equalsIgnoreCase("aws")){
+//                keys = keys.stream().filter(key->{
+//                    if(key.contains("x-oss-process")){
+//                        return false;
+//                    }
+//                    return true;
+//                }).collect(Collectors.toList());
+//            }
+//            ossFilePaths.addAll(keys);
+//        }
+//
+//        //列出v3local所有文件路径
+//        File file = new File(v3localPath);
+//        List<String> localFilePaths = FileUtils.list(file);
+//
+//        HashMap<String, List<String>> map = new HashMap<>();
+//        map.put("ossFilePaths", ossFilePaths);
+//        map.put("localFilePaths", localFilePaths);
+//
+//        return map;
+//    }
+//
+//    private void zipBat(String num, String version) throws Exception{
+//        String batContent = String.format(this.exeContent, num);
+//        if("v3".equals(version)){
+//            batContent = String.format(this.exeContentV3, num);
+//        }
+////        this.zipBytes(out, exeName, batContent.getBytes());
+//        FileUtil.writeUtf8String(batContent, String.format(this.sourceLocal, num, exeName));
+//    }
+//
+//    private void zipSceneJson(String num, SceneViewInfoBean sceneViewInfo) throws Exception{
+//        //访问密码置0
+//        SceneEditControlsBean controls = sceneViewInfo.getControls();
+//        controls.setShowLock(CommonStatus.NO.code().intValue());
+//        String sceneJsonPath = String.format(UploadFilePath.DATA_VIEW_PATH, num) + "scene.json";
+//        FileUtil.writeUtf8String(JSON.toJSONString(sceneViewInfo, SerializerFeature.WriteNullStringAsEmpty, SerializerFeature.WriteNullNumberAsZero), String.format(this.sourceLocal, num, this.wwwroot + sceneJsonPath));
+//    }
+//
+//    private void zipOssFiles(String num, String resolution, boolean cutImg, String version) throws Exception{
+//
+////        fYunFileService.downloadFileByCommand(String.format(sourceLocal, num, this.wwwroot).concat(String.format(UploadFilePath.VIEW_PATH, num)), String.format(UploadFilePath.VIEW_PATH, num));
+////        FileUtil.del(String.format(sourceLocal, num, this.wwwroot).concat(String.format(UploadFilePath.IMG_VIEW_PATH, num)).concat("tiles"));
+//        List<String> strings = new ArrayList<>();
+//        if(version.equals(SceneVersionType.V4.code())){
+//            strings = fileStorageTemplate.getFileFolder(String.format(UploadFilePath.VIEW_PATH, num));
+//        }
+//        if(version.equals(SceneVersionType.V3.code())){
+//            List<String> dataList = fileStorageTemplate.getFileFolder(String.format(prefixArr4v3[0], num));
+//            if(CollUtil.isNotEmpty(dataList)){
+//                strings.addAll(dataList);
+//            }
+//            List<String> imgList =  fileStorageTemplate.getFileFolder(String.format(prefixArr4v3[1], num));
+//            if(CollUtil.isNotEmpty(imgList)){
+//                strings.addAll(imgList);
+//            }
+//            List<String> voiceList =  fileStorageTemplate.getFileFolder(String.format(prefixArr4v3[2], num));
+//            if(CollUtil.isNotEmpty(voiceList)){
+//                strings.addAll(voiceList);
+//            }
+//            List<String> videoList = fileStorageTemplate.getFileFolder(String.format(prefixArr4v3[3], num));
+//            if(CollUtil.isNotEmpty(videoList)){
+//                strings.addAll(videoList);
+//            }
+//        }
+//        strings.stream().forEach(str->{
+//            if(!str.contains("/tiles/4k/") && !str.contains("/tiles/2k/")
+//                    && !str.contains("dacf7dfa24ae47fab8fcebfe4dc41ab9_50k.dam") && !str.endsWith("/")){
+//                fileStorageTemplate.downloadFile(str, String.format(sourceLocal, num, this.wwwroot).concat(str));
+//            }
+//            if(str.contains("dacf7dfa24ae47fab8fcebfe4dc41ab9_50k.dam")){
+//                log.info("url:{}", "http://4dkankan.oss-cn-shenzhen-internal.aliyuncs.com/" + str);
+//                HttpUtil.downloadFile("http://4dkankan.oss-cn-shenzhen-internal.aliyuncs.com/" + str, String.format(sourceLocal, num, this.wwwroot).concat(str));
+//            }
+//        });
+////        fYunFileService.downloadFile(String.format(UploadFilePath.VIEW_PATH, num), String.format(sourceLocal, num, this.wwwroot));
+//
+//        //特殊文件处理
+//        this.reWriteFile(num);
+//
+//        //切图
+//        if(cutImg){
+//            String filePath = String.format(sourceLocal, num, this.wwwroot + String.format(UploadFilePath.IMG_VIEW_PATH, num) + "tiles/");
+//            if(version.equals(SceneVersionType.V3.code())){
+//                filePath = String.format(sourceLocal, num, this.wwwroot + String.format(prefixArr4v3[1], num) + "tiles/");
+//            }
+//            log.info("开始切图:{}", num);
+//            this.cutImg(num, filePath, resolution, "tiles", version);
+//            log.info("结束切图:{}", num);
+//
+//            //切图-场景关联
+//            String panoramaPath = String.format(sourceLocal, num, this.wwwroot + String.format(UploadFilePath.IMG_VIEW_PATH, num) + "panorama/");
+//            if(version.equals(SceneVersionType.V3.code())){
+//                panoramaPath = String.format(sourceLocal, num, this.wwwroot + String.format(prefixArr4v3[1], num) + "panorama/");
+//            }
+//            if(FileUtil.exist(panoramaPath)){
+//                Path directoryPath = Paths.get(panoramaPath); // 替换为你要查询的目录路径
+//                // 获取目录下的第一层子目录
+//                List<String> panoramaIdList = Files.list(directoryPath).filter(Files::isDirectory).map(file -> file.getFileName().toString()).collect(Collectors.toList());
+//                if(CollUtil.isNotEmpty(panoramaIdList)){
+//                    for (String panoramaId : panoramaIdList) {
+//                        this.cutImg(num, panoramaPath.concat(panoramaId).concat("/tiles/"), resolution, "panorama/".concat(panoramaId).concat("/tiles"), version);
+//                    }
+//                }
+//            }
+//        }
+//    }
+//
+//    @Override
+//    public void cutImg(String num, String path, String resolution, String subPath, String version) throws Exception {
+//
+//        String imageNumPath = String.format(UploadFilePath.IMG_VIEW_PATH, num);
+//        if(version.equals(SceneVersionType.V3.code())){
+//            imageNumPath = String.format(prefixArr4v3[1], num);
+//        }
+//        String tilesOssPath = imageNumPath.concat(subPath + "/" + resolution);
+//        List<String> cubeList = fileStorageTemplate.getFileFolder(tilesOssPath);
+//        ExecutorService executorService = Executors.newFixedThreadPool(this.zipNthreads);
+//        List<Future> futureList = new ArrayList<>();
+//        for (String key : cubeList) {
+//            Callable<Boolean> call = new Callable() {
+//                @Override
+//                public Boolean call() throws Exception {
+//                    processImage(key, resolution, path);
+//                    return true;
+//                }
+//            };
+//            futureList.add(executorService.submit(call));
+//        }
+//        for (Future future : futureList) {
+//            try {
+//                future.get();
+//            }catch (Exception e){
+//                log.error("切图失败", e);
+//                executorService.shutdownNow();
+//                throw new Exception("切图失败");
+//            }
+//        }
+//    }
+//
+////    private void zipOssFilesHandler(String num, String resolution,
+////                                    int imagesVersion, Set<String> cacheKeys,
+////                                    String filePath, String imageNumPath, String version) throws Exception{
+////
+////        if(filePath.endsWith("/")){
+////            return;
+////        }
+////
+////        //某个目录不需要打包
+////        if(filePath.contains(imageNumPath + "panorama/panorama_edit/"))
+////            return;
+////
+////        //切图
+////        if(!"notNeadCut".equals(resolution)){
+////            if((filePath.contains(imageNumPath + "panorama/") && filePath.contains("tiles/" + resolution))
+////                    || filePath.contains(imageNumPath + "tiles/" + resolution + "/")) {
+////                this.processImage(num, filePath, resolution, imagesVersion, cacheKeys);
+////                return;
+////            }
+////        }
+////
+////        //其他文件打包
+////        this.ProcessFiles(num, filePath, this.wwwroot, cacheKeys);
+////
+////    }
+//
+////    public void ProcessFiles(String num, String key, String prefix, Set<String> cacheKeys) throws Exception{
+////        if(cacheKeys.contains(key)){
+////            return;
+////        }
+////        if(key.equals(String.format(UploadFilePath.DATA_VIEW_PATH, num) + "scene.json")){
+////            return;
+////        }
+////        cacheKeys.add(key);
+////        String fileName = key.substring(key.lastIndexOf("/") + 1);
+////        String url = this.resourceUrl + key.replace(fileName, URLEncoder.encode(fileName, "UTF-8")) + "?t=" + Calendar.getInstance().getTimeInMillis();
+////        if(key.contains("hot.json") || key.contains("link-scene.json")){
+////            String content = fYunFileService.getFileContent(key);
+////            if(StrUtil.isEmpty(content)){
+////                return;
+////            }
+////            content = content.replace(publicUrl, "")
+//////                .replace(publicUrl+"v3/", "")
+////                    .replace("https://spc.html","spc.html")
+////                    .replace("https://smobile.html", "smobile.html");
+////
+////            FileUtil.writeUtf8String(content, String.format(sourceLocal, num, prefix + key));
+////        }else{
+////            try {
+////                this.downloadFile(url, String.format(sourceLocal, num, prefix + key));
+////            }catch (Exception e){
+////                log.info("下载文件报错,path:{}", String.format(sourceLocal, num, prefix + key));
+////            }
+////        }
+////    }
+//
+//    private void reWriteFile(String num){
+//        String filePath = String.format(sourceLocal, num, this.wwwroot + String.format(UploadFilePath.USER_VIEW_PATH, num) + "hot.json");
+//        if(FileUtil.exist(filePath)){
+//            String content = FileUtil.readUtf8String(filePath);
+//            content = content.replace(publicUrl, "")
+//                    .replace("https://spc.html","spc.html")
+//                    .replace("https://smobile.html", "smobile.html");
+//            FileUtil.writeUtf8String(content, filePath);
+//        }
+//    }
+//
+//    private void processImage(String key, String resolution, String path) throws Exception{
+//
+//        if(key.contains("x-oss-process") || key.endsWith("/")){
+//            return;
+//        }
+//
+//        String fileName = key.substring(key.lastIndexOf("/")+1, key.indexOf("."));//0_skybox0.jpg
+//        String ext = key.substring(key.lastIndexOf("."));
+//        String[] arr = fileName.split("_skybox");
+//        String dir = arr[0]; //0
+//        String num = arr[1]; //0
+//        if(StrUtil.isEmpty(fileName)
+//                || StrUtil.isEmpty(ext)
+//                || (".jpg".equals(ext) && ".png".equals(ext))
+//                ||  StrUtil.isEmpty(dir)
+//                || StrUtil.isEmpty(num)){
+//            throw new Exception("本地下载图片资源不符合规则,key:" + key);
+//        }
+//        for (ImageType imageType : CommonConstant.imageTypes) {
+//
+//            if(imageType.getName().equals("4k_face") && !"4k".equals(resolution)){
+//                continue;
+//            }
+//
+//            List<ImageTypeDetail> items = Lists.newArrayList();
+//            String[] ranges = imageType.getRanges();
+//            for(int i = 0; i < ranges.length; i++){
+//                String x = ranges[i];
+//                for(int j = 0; j < ranges.length; j++){
+//                    String y = ranges[j];
+//                    items.add(
+//                            ImageTypeDetail.builder()
+//                                    .i(String.valueOf(i))
+//                                    .j(String.valueOf(j))
+//                                    .x(x)
+//                                    .y(y)
+//                                    .build()
+//                    );
+//                }
+//            }
+//            List<ImageTypeDetail> imageTypeDetails = Collections.synchronizedList(items);
+////            synchronized(imageTypeDetails){
+//                imageTypeDetails.parallelStream().forEach(item->{
+//                String par = "?x-oss-process=image/resize,m_lfit,w_" + imageType.getSize() + "/crop,w_512,h_512,x_" + item.getX() + ",y_" + item.getY();
+////                if(FYunTypeEnum.AWS.code().equals(uploadType)){
+////                    par += "&imagesVersion="+ imagesVersion;
+////                }
+//                var url = this.resourceUrl + key;
+//                switch (fileStorageTemplate.getActive()){
+//                    case "oss":
+//                        url += par;
+//                        break;
+//                    case "aws":
+//                        try {
+//                            url += URLEncoder.encode(par.replace("/", "@"), "UTF-8");
+//                        } catch (UnsupportedEncodingException e) {
+//                            throw new RuntimeException(e);
+//                        }
+//                        break;
+//                }
+//                //key.split("/" + resolution + "/")[0] + "/" +
+//                var fky = dir + "/" + imageType.getName() +  num + "_" + item.getI()  + "_" + item.getJ() + ext;
+//
+//                    downloadUtil.downloadFile(url, path + fky,1);
+////                this.downloadFile(url, path);
+//                });
+////            }
+//        }
+//
+//    }
+//
+//
+//
+//    private void zipLocalFiles(String num, String version) throws Exception{
+//        String sourcePath = String.format(this.sourceLocal, num, "");
+//        String localPath = "v4".equals(version) ? this.v4localPath : this.v3localPath;
+//        FileUtil.copyContent(FileUtil.newFile(localPath), FileUtil.newFile(sourcePath), true);
+//        //写入code.txt
+//        FileUtil.writeUtf8String(num, String.format(sourceLocal, num, "code.txt"));
+//    }
+//
+//    private SceneViewInfoBean getSceneJson(String num){
+//        String sceneJsonData = (String) redisUtil.get(String.format("scenejson:num:%s", num));
+//        if(StrUtil.isEmpty(sceneJsonData)){
+//            try {
+//                sceneJsonData = fileStorageTemplate.getFileContent(bucket, String.format(UploadFilePath.DATA_VIEW_PATH, num) + "scene.json");
+//            } catch (Exception e) {
+//                throw new RuntimeException(e);
+//            }
+//        }
+//        sceneJsonData = sceneJsonData.replace(this.publicUrl, "");
+//        SceneViewInfoBean sceneInfoVO = JSON.parseObject(sceneJsonData, SceneViewInfoBean.class);
+//        sceneInfoVO.setScenePassword(null);
+//        if(Objects.isNull(sceneInfoVO.getFloorPlanAngle())){
+//            sceneInfoVO.setFloorPlanAngle(0f);
+//        }
+//        if(Objects.isNull(sceneInfoVO.getFloorPlanCompass())){
+//            sceneInfoVO.setFloorPlanCompass(0f);
+//        }
+//        SceneEditControlsBean controls = sceneInfoVO.getControls();
+//        if(Objects.isNull(controls.getShowShare())){
+//            controls.setShowShare(CommonStatus.YES.code().intValue());
+//        }
+//        if(Objects.isNull(controls.getShowCapture())){
+//            controls.setShowCapture(CommonStatus.YES.code().intValue());
+//        }
+//        if(Objects.isNull(controls.getShowBillboardTitle())){
+//            controls.setShowBillboardTitle(CommonStatus.YES.code().intValue());
+//        }
+//
+//        return sceneInfoVO;
+//    }
+//
+//    private Map<String, List<String>> getAllFiles(String num, String v4localPath, String bucket) throws Exception{
+//        //列出oss所有文件路径
+//        List<String> ossFilePaths = new ArrayList<>();
+//        for (String prefix : CommonConstant.prefixArr) {
+//            prefix = String.format(prefix, num);
+//            List<String> keys = fileStorageTemplate.getFileFolder(bucket, prefix);
+//            if(CollUtil.isEmpty(keys)){
+//                continue;
+//            }
+//            if(fileStorageTemplate.getActive().equalsIgnoreCase("aws")){
+//                keys = keys.stream().filter(key->{
+//                    if(key.contains("x-oss-process")){
+//                        return false;
+//                    }
+//                    return true;
+//                }).collect(Collectors.toList());
+//            }
+//            ossFilePaths.addAll(keys);
+//        }
+//
+//        //列出v3local所有文件路径
+//        File file = new File(v4localPath);
+//        List<String> localFilePaths = FileUtils.list(file);
+//
+//        HashMap<String, List<String>> map = new HashMap<>();
+//        map.put("ossFilePaths", ossFilePaths);
+//        map.put("localFilePaths", localFilePaths);
+//
+//        return map;
+//    }
+//
+//    private void zip(String sourcePath, String zipPath) throws Exception {
+//        FileUtil.mkParentDirs(zipPath);
+//        String cmd = "cd " + sourcePath + " && zip -r " + zipPath + " *";//&& mv -f " + zipPath + " "  + target
+//        CmdUtils.callLineSh(cmd);
+//    }
+//
+//
+//
+//}

+ 8 - 0
720yun_fd_base/gis_service/src/main/java/com/gis/service/impl/WorkServiceImpl.java

@@ -2081,4 +2081,12 @@ public class WorkServiceImpl extends ServiceImpl<WorkMapper, WorkEntity> impleme
         wrapper.set(WorkEntity::getPanoStatus, panoStatus);
         update(wrapper);
     }
+
+    @Override
+    public boolean updateOfflineStatus(String id, int offlineStatus) {
+        LambdaUpdateWrapper<WorkEntity> wrapper=Wrappers.lambdaUpdate();
+        wrapper.eq(WorkEntity::getId, id);
+        wrapper.set(WorkEntity::getOfflineStatus, offlineStatus);
+        return update(wrapper);
+    }
 }

+ 60 - 0
720yun_fd_base/gis_service/src/main/java/com/gis/util/DownloadUtil.java

@@ -0,0 +1,60 @@
+package com.gis.util;
+
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.thread.ThreadUtil;
+import cn.hutool.core.util.RuntimeUtil;
+import cn.hutool.http.HttpUtil;
+import com.gis.common.exception.BaseRuntimeException;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.io.File;
+
+/**
+ * @author Xiewj
+ * @date 2024/1/12
+ */
+@Component
+@Slf4j
+public class DownloadUtil {
+
+    public final static String WGET_CMD = "wget -t 10 -N -O @out @url";
+
+    public  void downFile(String url, String path) throws Exception {
+        String cmd = WGET_CMD.replace("@out",path).replace("@url",url);
+        RuntimeUtil.exec(cmd);
+    }
+    public  void downloadFile(String url, String path,int index){
+        File file = new File(path);
+        if(!file.getParentFile().exists()){
+            file.getParentFile().mkdirs();
+        }
+        try {
+            try {
+                HttpUtil.downloadFileFromUrl(url,path);
+            }catch (Exception e){
+                log.error("下载失败,url:{}, path:{}", url, path, e);
+            }
+            if(!FileUtil.exist(path) || FileUtil.size(new File(path)) == 0){
+                while (index<=50){
+                    index++;
+                    HttpUtil.downloadFileFromUrl(url,path);
+                    if (FileUtil.size(new File(path))>0){
+                        log.info("文件第{}次下载成功:{}", index, path);
+                        return;
+                    }
+                    ThreadUtil.safeSleep(200);
+
+//                    HttpUtil.downloadFileFromUrl(url,path);
+                }
+            }else{
+                log.info("文件第{}次下载成功:{}", index, path);
+            }
+        } catch (Exception e) {
+            log.error("下载报错停止,url:{}, path:{}", url, path, e);
+            throw new BaseRuntimeException(-1,"下载报错停止,"+url+","+path);
+        }
+    }
+}

+ 3 - 3
720yun_fd_consumer/src/main/java/com/gis/listener/container/DoSliceQueueListener.java

@@ -1,5 +1,6 @@
 package com.gis.listener.container;
 import com.alibaba.fastjson.JSONObject;
+import com.gis.common.annotation.LogAnnotation;
 import com.gis.domain.dto.DoSliceDTO;
 import com.gis.service.FodderService;
 import lombok.extern.slf4j.Slf4j;
@@ -24,21 +25,20 @@ public class DoSliceQueueListener implements ChannelAwareMessageListener {
     FodderService fodderService;
 
     @Override
+    @LogAnnotation
     public void onMessage(Message message, Channel channel) throws Exception {
 
         if (ObjectUtils.isEmpty(message.getBody())) {
             log.error("消息内容为空,退出构建,当前服务器id:{}" );
             return;
         }
-        String traceId = System.currentTimeMillis()+"";
-        MDC.put("TRACE_ID", traceId);
         long deliveryTag = message.getMessageProperties().getDeliveryTag();
         try {
             String msg = new String(message.getBody(), StandardCharsets.UTF_8);
             String messageId = message.getMessageProperties().getMessageId();
             log.info("场景doSliceQueue开始,id:{},deliveryTag:{},消息体:{}", messageId,deliveryTag,msg);
             DoSliceDTO dto = JSONObject.parseObject(msg, DoSliceDTO.class);
-            fodderService.doSlice(dto.getId(), traceId);
+            fodderService.doSlice(dto.getId(), messageId);
         }catch (Exception e){
             e.printStackTrace();
             log.error("场景doSliceQueue报错{}",e.getMessage());

+ 2 - 2
720yun_fd_consumer/src/main/java/com/gis/listener/container/PanoMigrateSceneQueueListener.java

@@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.gis.common.annotation.LogAnnotation;
 import com.gis.domain.entity.WorkEntity;
 import com.gis.domain.dto.OpenSceneMigrateDto;
 import com.gis.service.FodderService;
@@ -31,14 +32,13 @@ public class PanoMigrateSceneQueueListener implements ChannelAwareMessageListene
     @Autowired
     WorkService workService;
     @Override
+    @LogAnnotation
     public void onMessage(Message message, Channel channel) throws Exception {
 
         if (ObjectUtils.isEmpty(message.getBody())) {
             log.error("消息内容为空,退出构建,当前服务器id:{}" );
             return;
         }
-        String traceId = System.currentTimeMillis()+"";
-        MDC.put("TRACE_ID", traceId);
         long deliveryTag = message.getMessageProperties().getDeliveryTag();
         try {
             String msg = new String(message.getBody(), StandardCharsets.UTF_8);

+ 2 - 0
720yun_fd_consumer/src/main/java/com/gis/listener/container/PanoPayStatusSceneQueueListener.java

@@ -3,6 +3,7 @@ package com.gis.listener.container;
 import cn.hutool.core.util.ArrayUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSONObject;
+import com.gis.common.annotation.LogAnnotation;
 import com.gis.domain.entity.WorkEntity;
 import com.gis.domain.dto.SceneQueueDTO;
 import com.gis.service.FodderService;
@@ -30,6 +31,7 @@ public class PanoPayStatusSceneQueueListener implements ChannelAwareMessageListe
     @Autowired
     WorkService workService;
     @Override
+    @LogAnnotation
     public void onMessage(Message message, Channel channel) throws Exception {
         if (ObjectUtils.isEmpty(message.getBody())) {
             log.error("消息内容为空,退出构建,当前服务器id:{}" );

+ 19 - 1
720yun_fd_consumer/src/main/java/com/gis/listener/container/RabbitMQConfig.java

@@ -34,6 +34,9 @@ public class RabbitMQConfig {
     @Value("${queue.scene-queue}")
     String sceneQueue;
 
+    @Value("${queue.qjkk-work-offline}")
+    String workOffline;
+
     @Autowired
     QueueNameService queueNameService;
     @Autowired
@@ -46,7 +49,8 @@ public class RabbitMQConfig {
     PanoPayStatusSceneQueueListener panoPayStatusSceneQueueListener;
     @Autowired
     SceneQueueListener sceneQueueListener;
-
+    @Autowired
+    WorkOfflineListener workOfflineListener;
 
     @Bean
     public Queue doSliceQueue() {
@@ -139,4 +143,18 @@ public class RabbitMQConfig {
         container.setErrorHandler(t -> log.error("sceneWorkQueue 监听器发生异常", t));
         return container;
     }
+
+    @Bean
+    public SimpleMessageListenerContainer WorkOfflineContainer(ConnectionFactory connectionFactory) {
+        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer(connectionFactory);
+        log.info("workOfflineListener 启动,监听队列-{},动态伸缩启动-{}", workOffline, !isDynamic);
+        container.setQueueNames(workOffline);
+        container.setMessageListener(workOfflineListener);
+        container.setAutoStartup(!isDynamic); // 根据配置决定是否自动启动
+        container.setPrefetchCount(1);
+        container.setBatchSize(3);
+        container.setAcknowledgeMode(AcknowledgeMode.MANUAL);
+        container.setErrorHandler(t -> log.error("workOfflineListener  监听器发生异常", t));
+        return container;
+    }
 }

+ 2 - 0
720yun_fd_consumer/src/main/java/com/gis/listener/container/SceneQueueListener.java

@@ -4,6 +4,7 @@ import cn.hutool.core.util.ObjectUtil;
 import cn.hutool.core.util.StrUtil;
 import com.alibaba.fastjson.JSONObject;
 import com.fdkankan.filestorage.FileStorageTemplate;
+import com.gis.common.annotation.LogAnnotation;
 import com.gis.common.constant.ConfigConstant;
 import com.gis.common.mq.RabbitMqProducerUtil;
 import com.gis.domain.dto.RelicsSceneInitQueueDTO;
@@ -74,6 +75,7 @@ public class SceneQueueListener implements ChannelAwareMessageListener {
 
 
     @Override
+    @LogAnnotation
     public void onMessage(Message message, Channel channel) throws Exception {
         if (ObjectUtils.isEmpty(message.getBody())) {
             log.error("消息内容为空,退出构建,当前服务器id:{}" );

+ 2 - 0
720yun_fd_consumer/src/main/java/com/gis/listener/container/SceneWorkQueueListener.java

@@ -10,6 +10,7 @@ import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.fdkankan.filestorage.FileStorageTemplate;
+import com.gis.common.annotation.LogAnnotation;
 import com.gis.common.constant.ConfigConstant;
 import com.gis.common.mq.RabbitMqProducerUtil;
 import com.gis.common.util.CmdUtils;
@@ -115,6 +116,7 @@ public class SceneWorkQueueListener implements ChannelAwareMessageListener {
     @Autowired
     RedisUtil redisUtil;
     @Override
+    @LogAnnotation
     public void onMessage(Message message, Channel channel) throws Exception {
 
         if (ObjectUtils.isEmpty(message.getBody())) {

+ 131 - 0
720yun_fd_consumer/src/main/java/com/gis/listener/container/WorkOfflineListener.java

@@ -0,0 +1,131 @@
+package com.gis.listener.container;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.util.ObjUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.gis.common.annotation.LogAnnotation;
+import com.gis.common.util.FileUtils;
+import com.gis.common.util.Result;
+import com.gis.domain.dto.WorkOfflineDTO;
+import com.gis.domain.entity.WorkEntity;
+import com.gis.domain.entity.WorkNavigationEntity;
+import com.gis.domain.vo.WorkIdVO;
+import com.gis.domain.vo.WorkViewVo;
+import com.gis.oss.constant.CmdConstant;
+import com.gis.common.util.CmdUtils;
+import com.gis.oss.util.OssShUtil;
+import com.gis.service.*;
+import com.rabbitmq.client.Channel;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+import org.springframework.amqp.core.Message;
+import org.springframework.amqp.rabbit.listener.api.ChannelAwareMessageListener;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ObjectUtils;
+
+import javax.annotation.Resource;
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.util.List;
+
+/**
+ * @author Xiewj
+ * @date 2025/3/19
+ */
+@Component
+@Slf4j
+public class WorkOfflineListener implements ChannelAwareMessageListener {
+    @Autowired
+    WorkService workService;
+    /** 服务器文件地址*/
+    @Value("${server.file.path}")
+    public  String serverBasePath;
+    @Autowired
+    private WorkViewService workViewService;
+    @Autowired
+    private WorkNavigationService workNavigationService;
+    @Override
+    @LogAnnotation
+    public void onMessage(Message message, Channel channel) throws Exception {
+        if (ObjectUtils.isEmpty(message.getBody())) {
+            log.error("消息内容为空,退出构建,当前服务器id:{}" );
+            return;
+        }
+        long deliveryTag = message.getMessageProperties().getDeliveryTag();
+        String msg = new String(message.getBody(), StandardCharsets.UTF_8);
+        String messageId = message.getMessageProperties().getMessageId();
+        log.info("场景WorkOffline开始,id:{},deliveryTag:{},消息体:{}", messageId,deliveryTag,msg);
+        WorkOfflineDTO param = JSONObject.parseObject(msg, WorkOfflineDTO.class);
+        try {
+            WorkEntity workEntity = workService.getById(param.getWorkId());
+            if (ObjUtil.isNotEmpty(workEntity)){
+                //切图状态:-1失败 0未生成 1排队中 2生成中 3生成成功
+                workService.updateOfflineStatus(param.getWorkId(),2);
+                //下载接口数据。
+                String basePath=param.getPath()+ File.separator+"www";
+                if (!FileUtil.exist(basePath)){
+                    FileUtil.mkdir(basePath);
+                }
+                //id场景码接口
+                WorkIdVO workIdVO=new WorkIdVO();
+                BeanUtil.copyProperties(workEntity,workIdVO);
+                Result getIdInfo = Result.success(workIdVO);
+                String getIdInfoPath =basePath+File.separator+"panorama"+File.separator+"qjkankan"+File.separator+"web"+File.separator+"common"+File.separator+"getIdInfo";
+                FileUtils.writeUtf8String(getIdInfo, getIdInfoPath);
+                //view接口
+                String  getViewInfoPath =basePath+File.separator+"panorama"+File.separator+"qjkankan"+File.separator+"work"+File.separator+"view--workId="+workEntity.getId();
+                WorkViewVo viewInfo = workViewService.getViewInfo(workEntity.getId());
+                Result  getViewInfo= Result.success(viewInfo);
+                FileUtils.writeUtf8String(getViewInfo, getViewInfoPath);
+                //下载作品的OSS文件夹
+                String ossKey = "720yun_fd_manage/" + workEntity.getId();
+                OssShUtil.yunDownload(ossKey,basePath+File.separator+ossKey);
+
+
+                //处理关联的作品和场景
+                List<WorkNavigationEntity> workNavigationEntities = workNavigationService.selectByWorkId(workEntity.getId());
+                for (WorkNavigationEntity workNavigationEntity : workNavigationEntities) {
+                    if (ObjUtil.isNotEmpty(workNavigationEntity.getType())){
+                        if (workNavigationEntity.getType().equalsIgnoreCase("pano")){
+                            String PanoOssKey = "720yun_fd_manage/" + workNavigationEntity.getSceneCode();
+                            log.info("下载作品类-全景图:{},下载路径-PanoOssKey", workNavigationEntity.getSceneCode(),PanoOssKey);
+                            OssShUtil.yunDownload(PanoOssKey,basePath+File.separator+PanoOssKey);
+                        }else if (workNavigationEntity.getType().equalsIgnoreCase("4dkk")){
+                            //整合离线包
+                            log.info("整合mesh场景");
+                        }
+
+
+
+//                        if (workNavigationEntity.getType().equalsIgnoreCase("4dkk") && workNavigationEntity.getVersion().equalsIgnoreCase("V3")){
+//                            log.info("下载mesh场景 V3 ");
+//                            downloadService.downloadMeshSceneV3(workNavigationEntity.getSceneCode());
+//                        }
+//                        if (workNavigationEntity.getType().equalsIgnoreCase("4dkk") && workNavigationEntity.getVersion().equalsIgnoreCase("V4")){
+//                            log.info("下载mesh场景 V4 ");
+//                            downloadService.downloadMeshScene(workNavigationEntity.getSceneCode());
+//                        }
+
+
+                    }
+                }
+
+
+            }
+
+
+        }catch (Exception e){
+            log.error("场景WorkOffline报错{}",e.getMessage());
+            workService.updateOfflineStatus(param.getWorkId(),-1);
+            e.printStackTrace();
+        }finally {
+            channel.basicAck(deliveryTag, false);
+        }
+    }
+
+
+}

+ 2 - 1
720yun_fd_consumer/src/main/resources/application-sit.yml

@@ -78,7 +78,8 @@ queue:
     pano-migrate-scene-queue: pano-migrate-scene-queue
     pano-paystatus-scene-queue: pano-paystatus-scene-queue
     scene-queue-work: queue-pano-scene-work-A
-
+    qjkk-work-offline: qjkk-work-offline
+    qjkk-work-offline-done: qjkk-work-offline-done
 config:
     bashPath: 720yun_fd_manage/
 # application.yml

+ 68 - 2
720yun_fd_manage/src/main/java/com/gis/controller/WorkController.java

@@ -1,6 +1,7 @@
 package com.gis.controller;
 
 
+import cn.hutool.core.util.ObjUtil;
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
@@ -8,6 +9,7 @@ import com.gis.common.constant.ErrorEnum;
 import com.gis.common.constant.MsgCode;
 import com.gis.common.constant.RedisConstant;
 import com.gis.common.httpclient.FdkkClient;
+import com.gis.common.mq.RabbitMqProducerUtil;
 import com.gis.common.util.RedisUtil;
 import com.gis.common.util.Result;
 import com.gis.domain.dto.*;
@@ -19,6 +21,7 @@ import com.github.pagehelper.PageHelper;
 import io.swagger.annotations.*;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.transaction.annotation.Transactional;
 import org.springframework.web.bind.annotation.*;
@@ -26,7 +29,9 @@ import org.springframework.web.multipart.MultipartFile;
 
 import javax.annotation.Resource;
 import javax.validation.Valid;
+import java.io.File;
 import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
@@ -54,11 +59,16 @@ public class WorkController extends BaseController {
 
     @Autowired
     RedisUtil redisUtil;
-
-
+    @Autowired
+    RabbitMqProducerUtil rabbitMqProducerUtil;
     @Resource
     FdkkClient fdkkClient;
 
+    @Value("${queue.qjkk-work-offline}")
+    String workOffline;
+    /** 服务器文件地址*/
+    @Value("${server.file.path}")
+    public  String serverBasePath;
     @ApiOperation(value = "列表", position = 1)
     @PostMapping("list")
     public Result<WorkEntity> list(@RequestBody AgePageDto param) {
@@ -231,5 +241,61 @@ public class WorkController extends BaseController {
         return workService.delOss(ossPath);
     }
 
+    /*
+        * @Description:离线包下载
+        * @Param:
+    **/
+    @ApiOperation(value = "v2.0.0-下载离线包", notes = "")
+    @PostMapping("/downloadOffline")
+    public Result downloadOffline(String workId) {
+        Map<String,Object> map=new HashMap<>();
+        map.put("workId", workId);
+        rabbitMqProducerUtil.sendByWorkQueue(workOffline,map);
+        return Result.success();
+    }
+
+    /*
+     * @Description:离线包下载
+     * @Param:
+     **/
+    @ApiOperation(value = "v2.0.0-开始下载离线包重置状态", notes = "")
+    @PostMapping("/UpdateDownloadOfflineStatus")
+    public Result UpdateDownloadOfflineStatus(String workId) {
+        return Result.success(workService.updateOfflineStatus(workId,0));
+    }
+
+    /*
+     * @Description:离线包下载
+     * @Param:
+     **/
+    @ApiOperation(value = "v2.0.0-下载离线包详情", notes = "")
+    @PostMapping("/getOfflineDetail")
+    public Result getOfflineDetail(String workId) {
+        WorkEntity workEntity = workService.getById(workId);
+        WorkOfflineDetailDTO detailDTO=new WorkOfflineDetailDTO();
+        //切图状态:-1失败 0未生成 1排队中 2生成中 3生成成功
+        if (ObjUtil.isNotNull(workEntity)){
+            //初次 进来返回 路径
+            if  (workEntity.getOfflineStatus()==0){
+                String basePath=serverBasePath+
+                        File.separator+"offlineData"+
+                        File.separator+workId;
+                detailDTO.setPath(basePath);
+            }else if (workEntity.getOfflineStatus()==1){
+                detailDTO.setProgress(0);
+            }else if (workEntity.getOfflineStatus()==2){
+                //从redis获取生成进度
+                detailDTO.setProgress(10);
+            }else if (workEntity.getOfflineStatus()==3){
+                //从redis获取生成进度
+                detailDTO.setProgress(100);
+                detailDTO.setUrl(workEntity.getOfflineUrl());
+            }
+
+
+        }
+
+        return Result.success(detailDTO);
+    }
 
 }

+ 2 - 0
720yun_fd_manage/src/main/resources/application-sit.yml

@@ -92,5 +92,7 @@ queue:
     scene-queue: queue-pano-scene
     do-slice-queue: queue-do-slice
     relics-update-name-queue: relics-update-name-queue
+    qjkk-work-offline: qjkk-work-offline
+    qjkk-work-offline-done: qjkk-work-offline-done
 config:
     bashPath: ${project.name}/

+ 5 - 0
pom.xml

@@ -72,6 +72,11 @@
 
         <dependencies>
             <dependency>
+                <groupId>com.fdkankan</groupId>
+                <artifactId>4dkankan-common-utils</artifactId>
+                <version>3.0.0-SNAPSHOT</version>
+            </dependency>
+            <dependency>
                 <groupId>com.gis</groupId>
                 <artifactId>gis_common</artifactId>
                 <version>${gis.version}</version>