Browse Source

Merge branch 'release' into feature-local-jg

# Conflicts:
#	src/main/java/com/fdkankan/scene/generate/AutoGenerate.java
#	src/main/java/com/fdkankan/scene/service/impl/SceneCleanOrigServiceImpl.java
#	src/main/java/com/fdkankan/scene/service/impl/SceneEditInfoExtServiceImpl.java
#	src/main/java/com/fdkankan/scene/service/impl/SceneEditInfoServiceImpl.java
dsx 2 years ago
parent
commit
434d314a4c

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

@@ -3,9 +3,7 @@ package com.fdkankan.scene.controller;
 import com.fdkankan.common.constant.ErrorCode;
 import com.fdkankan.common.constant.SceneInfoReqType;
 import com.fdkankan.common.exception.BusinessException;
-import com.fdkankan.model.utils.CreateHouseJsonUtil;
 import com.fdkankan.scene.annotation.CheckPermit;
-import com.fdkankan.scene.entity.SceneAsynOperLog;
 import com.fdkankan.scene.service.*;
 import com.fdkankan.scene.vo.*;
 import com.fdkankan.web.controller.BaseController;
@@ -284,7 +282,7 @@ public class SceneEditController extends BaseController {
      **/
     @CheckPermit
     @PostMapping(value = "/styles/delete")
-    public ResultData deleteStyles(@RequestBody @Validated DeleteLinkSceneStylesParamVO param) throws Exception {
+    public ResultData deleteStyles(@RequestBody @Validated DeleteStylesParamVO param) throws Exception {
         return sceneEditInfoService.deleteStyles(param);
     }
 
@@ -888,4 +886,18 @@ public class SceneEditController extends BaseController {
         return ResultData.ok(sceneEditInfoExtService.listBillboards(param));
     }
 
+    /**
+     * 获取指示牌列表
+     * @param param
+     * @return
+     * @throws Exception
+     */
+    @CheckPermit
+    @PostMapping("/billboards/styles/delete")
+    public ResultData deleteBillboards(@RequestBody @Validated DeleteStylesParamVO param) throws Exception {
+        return ResultData.ok(sceneEditInfoExtService.deleteBillboardsStyles(param));
+    }
+
+
+
 }

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

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

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

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

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

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

+ 4 - 5
src/main/java/com/fdkankan/scene/service/ISceneEditInfoExtService.java

@@ -3,10 +3,7 @@ package com.fdkankan.scene.service;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.fdkankan.scene.entity.SceneEditInfoExt;
-import com.fdkankan.scene.vo.BaseJsonArrayParamVO;
-import com.fdkankan.scene.vo.BaseJsonDataParamVO;
-import com.fdkankan.scene.vo.BaseSceneParamVO;
-import com.fdkankan.scene.vo.DeleteSidListParamVO;
+import com.fdkankan.scene.vo.*;
 import com.fdkankan.web.response.ResultData;
 
 import java.util.List;
@@ -31,6 +28,8 @@ public interface ISceneEditInfoExtService extends IService<SceneEditInfoExt> {
 
     ResultData deleteBillboards(DeleteSidListParamVO param) throws Exception;
 
-    List<JSONObject> listBillboards(BaseSceneParamVO param) throws Exception;
+    JSONObject listBillboards(BaseSceneParamVO param) throws Exception;
+
+    ResultData deleteBillboardsStyles(DeleteStylesParamVO param) throws Exception;
 
 }

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

@@ -2,17 +2,15 @@ package com.fdkankan.scene.service;
 
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.fdkankan.scene.annotation.CheckPermit;
 import com.fdkankan.scene.vo.BaseSceneParamVO;
 import com.fdkankan.scene.vo.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;
 import com.fdkankan.scene.vo.BaseDataParamVO;
 import com.fdkankan.scene.vo.BaseFileParamVO;
 import com.fdkankan.scene.vo.DeleteLinkPanParamVO;
-import com.fdkankan.scene.vo.DeleteLinkSceneStylesParamVO;
+import com.fdkankan.scene.vo.DeleteStylesParamVO;
 import com.fdkankan.scene.vo.DeleteMosaicParamVO;
 import com.fdkankan.scene.vo.DeleteSidParamVO;
 import com.fdkankan.scene.vo.DownloadVO;
@@ -27,9 +25,7 @@ import com.fdkankan.scene.vo.SceneInfoParamVO;
 import com.fdkankan.scene.vo.SceneInfoVO;
 import java.io.IOException;
 import java.util.List;
-import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
+
 import org.springframework.web.multipart.MultipartFile;
 
 /**
@@ -100,7 +96,7 @@ public interface ISceneEditInfoService extends IService<SceneEditInfo> {
 
     ResultData deleteLinkPan(DeleteLinkPanParamVO param) throws Exception;
 
-    ResultData deleteStyles(DeleteLinkSceneStylesParamVO param) throws Exception;
+    ResultData deleteStyles(DeleteStylesParamVO param) throws Exception;
 
     ResultData deleteMosaics(DeleteMosaicParamVO param) throws Exception;
 

+ 278 - 3
src/main/java/com/fdkankan/scene/service/impl/SceneCleanOrigServiceImpl.java

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

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

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

+ 172 - 37
src/main/java/com/fdkankan/scene/service/impl/SceneEditInfoExtServiceImpl.java

@@ -10,6 +10,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.fdkankan.common.constant.CommonStatus;
 import com.fdkankan.common.constant.ErrorCode;
+import com.fdkankan.common.constant.FileBizType;
 import com.fdkankan.common.exception.BusinessException;
 import com.fdkankan.common.util.FileUtils;
 import com.fdkankan.model.constants.ConstantFilePath;
@@ -32,12 +33,15 @@ import com.fdkankan.scene.service.IScenePlusService;
 import com.fdkankan.scene.vo.BaseJsonArrayParamVO;
 import com.fdkankan.scene.vo.BaseSceneParamVO;
 import com.fdkankan.scene.vo.DeleteSidListParamVO;
+import com.fdkankan.scene.service.*;
+import com.fdkankan.scene.vo.*;
 import com.fdkankan.web.response.ResultData;
 import org.aspectj.apache.bcel.generic.RET;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
 
 /**
@@ -63,6 +67,8 @@ public class SceneEditInfoExtServiceImpl extends ServiceImpl<ISceneEditInfoExtMa
     private RedisLockUtil redisLockUtil;
     @Autowired
     private OssUtil ossUtil;
+    @Autowired
+    private ISceneUploadService sceneUploadService;
 
     @Override
     public SceneEditInfoExt getByScenePlusId(long scenePlusId) {
@@ -93,8 +99,7 @@ public class SceneEditInfoExtServiceImpl extends ServiceImpl<ISceneEditInfoExtMa
 
         this.addOrUpdateBillboards(param.getNum(), param.getData());
 
-        //写入本地文件,作为备份
-        this.writeBillboardJson(param.getNum());
+        this.addOrUpdateBillboardsStyles(param.getNum(), param.getStyles());
 
         //保存数据库
         SceneEditInfoExt sceneEditInfoExt = this.getByScenePlusId(scenePlus.getId());
@@ -106,6 +111,70 @@ public class SceneEditInfoExtServiceImpl extends ServiceImpl<ISceneEditInfoExtMa
         return ResultData.ok();
     }
 
+    private void addOrUpdateBillboardsStyles(String num, List<JSONObject> styles) throws Exception{
+
+        this.syncBillboardsStylesFromFileToRedis(num);
+
+        if(CollUtil.isEmpty(styles)){
+            return;
+        }
+
+        long time = Calendar.getInstance().getTimeInMillis();
+        Map<String, String> styleMap = new HashMap<>();
+        AtomicInteger index = new AtomicInteger();
+        styles.stream().forEach(style->{
+            String id = style.getString("sid");
+            style.put("createTime", time + index.getAndIncrement());
+            styleMap.put(id, style.toJSONString());
+        });
+
+        String key = String.format(RedisKey.SCENE_BILLBOARDS_STYLES, num);
+        redisUtil.hmset(key, styleMap);
+
+        //写入本地文件,作为备份
+        this.writeBillboardStylesJson(num);
+    }
+
+    private void syncBillboardsStylesFromFileToRedis(String num) throws Exception{
+
+        String key = String.format(RedisKey.SCENE_BILLBOARDS_STYLES, num);
+        boolean exist = redisUtil.hasKey(key);
+        if(exist){
+            return;
+        }
+        String lockKey = String.format(RedisLockKey.LOCK_BILLBOARDS_STYLES_SYNC, num);
+        String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
+        boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE);
+        if(!lock){
+            throw new BusinessException(ErrorCode.SYSTEM_BUSY);
+        }
+        try{
+            exist = redisUtil.hasKey(key);
+            if(exist){
+                return;
+            }
+            String stylesPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num);
+            String stylesData = FileUtils.readUtf8String(stylesPath + "billboards-styles.json");
+            if(StrUtil.isEmpty(stylesData)){
+                return;
+            }
+            JSONArray stylesArr = JSON.parseArray(stylesData);
+            if(CollUtil.isEmpty(stylesArr)){
+                return;
+            }
+            Map<String, String> styleMap = new HashMap<>();
+            for (Object style : stylesArr) {
+                JSONObject styleObj = (JSONObject)style;
+                String id = styleObj.getString("sid");
+                styleMap.put(id, styleObj.toJSONString());
+            }
+            redisUtil.hmset(key, styleMap);
+        }finally {
+            redisLockUtil.unlockLua(lockKey, lockVal);
+        }
+
+    }
+
     @Override
     public ResultData deleteBillboards(DeleteSidListParamVO param) throws Exception {
         ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
@@ -131,27 +200,52 @@ public class SceneEditInfoExtServiceImpl extends ServiceImpl<ISceneEditInfoExtMa
     }
 
     @Override
-    public List<JSONObject> listBillboards(BaseSceneParamVO param) throws Exception {
+    public JSONObject listBillboards(BaseSceneParamVO param) throws Exception {
 
+        JSONObject result = new JSONObject();
+        List<JSONObject> tags = new ArrayList<>();
+        List<JSONObject> styles = new ArrayList<>();
         ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
         SceneEditInfoExt sceneEditInfoExt = this.getByScenePlusId(scenePlus.getId());
-        if(sceneEditInfoExt.getBillboards() == CommonStatus.NO.code().intValue()){
-            return null;
-        }
 
         this.syncBillboardsFromFileToRedis(param.getNum());
+
+        //获取指示牌数据
         String key = String.format(RedisKey.SCENE_BILLBOARDS, param.getNum());
         List<String> list = redisUtil.hgetValues(key);
-        List<TagBean> sortList = list.stream().map(str -> {
-            JSONObject jsonObject = JSON.parseObject(str);
-            TagBean tagBean = new TagBean();
-            tagBean.setCreateTime(jsonObject.getLong("createTime"));
-            jsonObject.remove("createTime");
-            tagBean.setTag(jsonObject);
-            return tagBean;
-        }).collect(Collectors.toList());
-        sortList.sort(Comparator.comparingLong(TagBean::getCreateTime).reversed());
-        return sortList.stream().map(item -> item.getTag()).collect(Collectors.toList());
+        if(CollUtil.isNotEmpty(list)){
+            List<TagBean> sortList = list.stream().map(str -> {
+                JSONObject jsonObject = JSON.parseObject(str);
+                TagBean tagBean = new TagBean();
+                tagBean.setCreateTime(jsonObject.getLong("createTime"));
+                jsonObject.remove("createTime");
+                tagBean.setTag(jsonObject);
+                return tagBean;
+            }).collect(Collectors.toList());
+            sortList.sort(Comparator.comparingLong(TagBean::getCreateTime).reversed());
+            tags = sortList.stream().map(item -> item.getTag()).collect(Collectors.toList());
+        }
+        result.put("tags", tags);
+
+        //获取图标数据
+        this.syncBillboardsStylesFromFileToRedis(param.getNum());
+        key = String.format(RedisKey.SCENE_BILLBOARDS_STYLES, param.getNum());
+        List<String> sytlelist = redisUtil.hgetValues(key);
+        if(CollUtil.isNotEmpty(sytlelist)){
+            List<TagBean> stileSortList = sytlelist.stream().map(str -> {
+                JSONObject jsonObject = JSON.parseObject(str);
+                TagBean tagBean = new TagBean();
+                tagBean.setCreateTime(jsonObject.getLong("createTime"));
+                jsonObject.remove("createTime");
+                tagBean.setTag(jsonObject);
+                return tagBean;
+            }).collect(Collectors.toList());
+            stileSortList.sort(Comparator.comparingLong(TagBean::getCreateTime).reversed());
+            styles = stileSortList.stream().map(item -> item.getTag()).collect(Collectors.toList());
+        }
+        result.put("styles", styles);
+
+        return result;
     }
 
     private void deleteBillboards(String num, List<String> deleteSidList, String bucket) throws Exception {
@@ -166,27 +260,12 @@ public class SceneEditInfoExtServiceImpl extends ServiceImpl<ISceneEditInfoExtMa
             return;
         //从redis中移除热点数据
         redisUtil.hdel(key, deleteSidList.toArray());
-
-        String userDataPath = String.format(UploadFilePath.USER_EDIT_PATH, num);
-        //删除图片音频视频等资源文件
-        for (String data : deletDataList) {
-            if(StrUtil.isBlank(data)){
-                continue;
-            }
-            JSONObject jsonObject = JSON.parseObject(data);
-            String icon = jsonObject.getString("icon");
-            if(StrUtil.isEmpty(icon)){
-                continue;
-            }
-            ossUtil.deleteObject(bucket, userDataPath.concat(icon));
-        }
     }
 
-    private void addOrUpdateBillboards(String num, JSONArray data) throws Exception{
+    private void addOrUpdateBillboards(String num, List<JSONObject> data) throws Exception{
         Map<String, String> addOrUpdateMap = new HashMap<>();
         int i = 0;
-        for (Object item : data) {
-            JSONObject jsonObject = JSON.parseObject(JSON.toJSONString(item));
+        for (JSONObject jsonObject : data) {
             jsonObject.put("createTime", Calendar.getInstance().getTimeInMillis() + i++);
             addOrUpdateMap.put(jsonObject.getString("sid"), JSON.toJSONString(jsonObject));
         }
@@ -227,12 +306,12 @@ public class SceneEditInfoExtServiceImpl extends ServiceImpl<ISceneEditInfoExtMa
             if(StrUtil.isEmpty(billboardsData)){
                 return;
             }
-            JSONArray billboardArr = JSON.parseArray(billboardsData);
-            if(CollUtil.isEmpty(billboardArr)){
+            JSONArray tagsArr = JSON.parseArray(billboardsData);
+            if(CollUtil.isEmpty(tagsArr)){
                 return;
             }
             Map<String, String> map = new HashMap<>();
-            for (Object o : billboardArr) {
+            for (Object o : tagsArr) {
                 JSONObject jo = (JSONObject)o;
                 map.put(jo.getString("sid"), jo.toJSONString());
             }
@@ -249,6 +328,9 @@ public class SceneEditInfoExtServiceImpl extends ServiceImpl<ISceneEditInfoExtMa
         //批量写入缓存
         String key = String.format(RedisKey.SCENE_BILLBOARDS, num);
         redisUtil.hmset(key, addOrUpdateMap);
+
+        //写入本地文件,作为备份
+        this.writeBillboardJson(num);
     }
 
     /**
@@ -258,8 +340,9 @@ public class SceneEditInfoExtServiceImpl extends ServiceImpl<ISceneEditInfoExtMa
      * </p>
      * @author dengsixing
      * @date 2022/3/3
+     *
      **/
-    private void writeBillboardJson(String num) throws Exception{
+    private void writeBillboardJson(String num){
         String lockKey = String.format(RedisLockKey.LOCK_BILLBOARDS_SYNC, num);
         String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
         boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE);
@@ -281,6 +364,28 @@ public class SceneEditInfoExtServiceImpl extends ServiceImpl<ISceneEditInfoExtMa
         }
     }
 
+    private void writeBillboardStylesJson(String num){
+        String lockKey = String.format(RedisLockKey.LOCK_BILLBOARDS_STYLES_SYNC, num);
+        String lockVal = cn.hutool.core.lang.UUID.randomUUID().toString();
+        boolean lock = redisLockUtil.lock(lockKey, lockVal, RedisKey.EXPIRE_TIME_1_MINUTE);
+        if(!lock){
+            return;
+        }
+        try{
+            String dataKey = String.format(RedisKey.SCENE_BILLBOARDS_STYLES, num);
+            String stylesPath = String.format(ConstantFilePath.SCENE_USER_PATH_V4, num) + "billboards-styles.json";
+            if(!redisUtil.hasKey(dataKey)){
+                FileUtil.del(stylesPath);
+                return;
+            }
+            Map<String, String> billboardStylesMap = redisUtil.hmget(dataKey);
+            List<JSONObject>  billboardStyleList = billboardStylesMap.entrySet().stream().map(entry->JSON.parseObject(entry.getValue())).collect(Collectors.toList());
+            FileUtil.writeUtf8String(JSON.toJSONString(billboardStyleList), stylesPath);
+        }finally {
+            redisLockUtil.unlockLua(lockKey, lockVal);
+        }
+    }
+
     private void updateBillboards(String num, SceneEditInfoExt sceneEditInfoExt){
         //查询缓存是否包含热点数据
         String key = String.format(RedisKey.SCENE_BILLBOARDS, num);
@@ -299,6 +404,36 @@ public class SceneEditInfoExtServiceImpl extends ServiceImpl<ISceneEditInfoExtMa
         this.updateById(sceneEditInfoExt);
     }
 
+    @Override
+    public ResultData deleteBillboardsStyles(DeleteStylesParamVO param) throws Exception {
+        ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
+        if (scenePlus == null)
+            throw new BusinessException(ErrorCode.FAILURE_CODE_5005);
+
+        List<String> sidList = param.getSidList();
+
+        this.syncBillboardsStylesFromFileToRedis(param.getNum());
+
+        String key = String.format(RedisKey.SCENE_BILLBOARDS_STYLES, param.getNum());
+        List<String> deleteList = redisUtil.hMultiGet(key, sidList);
+        redisUtil.hdel(key, sidList.toArray());
+
+        //写入本地文件,作为备份
+        this.writeBillboardStylesJson(param.getNum());
+
+        //删除oss文件
+        List<String> deleteFileList = deleteList.stream().map(str -> {
+            JSONObject parse = JSON.parseObject(str);
+            return parse.getString("url");
+        }).collect(Collectors.toList());
+        sceneUploadService.delete(
+                DeleteFileParamVO.builder()
+                        .num(param.getNum())
+                        .fileNames(deleteFileList)
+                        .bizType(FileBizType.BILLBOARD_ICON.code()).build());
+
+        return ResultData.ok();
+    }
 
 
 }

+ 40 - 6
src/main/java/com/fdkankan/scene/service/impl/SceneEditInfoServiceImpl.java

@@ -1,4 +1,8 @@
 package com.fdkankan.scene.service.impl;
+import cn.hutool.core.util.CharsetUtil;
+import com.fdkankan.common.constant.*;
+import com.fdkankan.common.util.FileSizeUtil;
+import com.fdkankan.scene.vo.SaveFiltersParamVO;
 
 import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.collection.CollUtil;
@@ -18,6 +22,7 @@ import com.fdkankan.common.constant.*;
 import com.fdkankan.common.exception.BusinessException;
 import com.fdkankan.common.util.FileSizeUtil;
 import com.fdkankan.common.util.FileUtils;
+import com.fdkankan.fyun.face.FYunFileServiceInterface;
 import com.fdkankan.model.constants.ConstantFilePath;
 import com.fdkankan.model.constants.UploadFilePath;
 import com.fdkankan.model.utils.ComputerUtil;
@@ -33,11 +38,40 @@ import com.fdkankan.scene.config.FdkkLaserConfig;
 import com.fdkankan.scene.constant.ConstantFileLocPath;
 import com.fdkankan.scene.entity.*;
 import com.fdkankan.scene.mapper.ISceneEditInfoMapper;
-import com.fdkankan.scene.oss.OssUtil;
-import com.fdkankan.scene.service.*;
-import com.fdkankan.scene.util.CmdBuildUtil;
-import com.fdkankan.scene.util.MergeVideoUtil;
-import com.fdkankan.scene.vo.*;
+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;
+import com.fdkankan.scene.service.ISceneEditInfoService;
+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.DeleteStylesParamVO;
+import com.fdkankan.scene.vo.DeleteMosaicParamVO;
+import com.fdkankan.scene.vo.DeleteSidParamVO;
+import com.fdkankan.scene.vo.DownloadVO;
+import com.fdkankan.scene.vo.FileNameAndDataParamVO;
+import com.fdkankan.scene.vo.FileParamVO;
+import com.fdkankan.scene.vo.RenameCadParamVO;
+import com.fdkankan.scene.vo.SaveLinkPanParamVO;
+import com.fdkankan.scene.vo.SceneCheckKeyParamVO;
+import com.fdkankan.scene.vo.SceneEditControlsVO;
+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.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;
@@ -2016,7 +2050,7 @@ public class SceneEditInfoServiceImpl extends ServiceImpl<ISceneEditInfoMapper,
     }
 
     @Override
-    public ResultData deleteStyles(DeleteLinkSceneStylesParamVO param) throws Exception {
+    public ResultData deleteStyles(DeleteStylesParamVO param) throws Exception {
         ScenePlus scenePlus = scenePlusService.getScenePlusByNum(param.getNum());
         if (scenePlus == null)
             throw new BusinessException(ErrorCode.FAILURE_CODE_5005);

+ 6 - 2
src/main/java/com/fdkankan/scene/vo/BaseJsonArrayParamVO.java

@@ -7,6 +7,7 @@ import lombok.Data;
 import javax.validation.constraints.NotBlank;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
+import java.util.List;
 
 /**
  * <p>
@@ -19,7 +20,10 @@ import javax.validation.constraints.NotNull;
 @Data
 public class BaseJsonArrayParamVO extends BaseSceneParamVO{
 
-    @NotEmpty(message = "数据不能为空")
-    private JSONArray data;
+    @NotNull(message = "data不能为空")
+//    private List<LinkPanParamVO> linkPans;
+    private List<JSONObject> data;
+
+    private List<JSONObject> styles;
 
 }

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

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

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

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

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

@@ -39,7 +39,7 @@
         left join t_scene_plus_ext ext on plus.id = ext.plus_id
         where plus.scene_status in (1,-2) and ext.algorithm_time <![CDATA[ < ]]> #{time}
         and ext.data_source is NOT null
-        and NOT EXISTS (select c.num from t_scene_cold_storage_log c where c.rec_status = 'A' and c.num = plus.num and ext.algorithm_time <![CDATA[ < ]]> c.create_time)
+        and NOT EXISTS (select c.num from t_scene_cold_storage c where c.rec_status = 'A' AND c.`state` = 1 and c.num = plus.num)
         and NOT EXISTS (select o.num from t_scene_clean_orig o where o.rec_status = 'A' and o.state != -1 and o.num = plus.num and ext.algorithm_time <![CDATA[ < ]]> o.create_time)
     </select>
 

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

@@ -36,7 +36,7 @@
         where pro.status in (1,-2) and pro.create_time <![CDATA[ < ]]> #{time}
         and pro.data_source is not null
         and pro.is_upgrade = 0
-        and NOT EXISTS (select c.num from t_scene_cold_storage_log c where c.rec_status = 'A' and c.num = pro.num and pro.create_time <![CDATA[ < ]]> c.create_time)
+        and NOT EXISTS (select c.num from t_scene_cold_storage c where c.rec_status = 'A' and c.state = 1 and c.num = pro.num)
         and NOT EXISTS (select o.num from t_scene_clean_orig o where o.rec_status = 'A' and o.state != -1 and o.num = pro.num and pro.create_time <![CDATA[ < ]]> o.create_time)
     </select>