package com.fdkanfang.web.backend;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fdkanfang.common.constant.ConstantFilePath;
import com.fdkanfang.common.constant.MsgCode;
import com.fdkanfang.common.constant.TypeCode;
import com.fdkanfang.common.enums.ImageResolutionRate;
import com.fdkanfang.common.enums.ResultCodeEnum;
import com.fdkanfang.common.exception.BaseRuntimeException;
import com.fdkanfang.common.exception.CommonBaseException;
import com.fdkanfang.common.model.PageDto;
import com.fdkanfang.common.util.*;
import com.fdkanfang.domain.backend.*;
import com.fdkanfang.domain.dto.*;
import com.fdkanfang.domain.response.HouseResponse;
import com.fdkanfang.domain.response.UserResponse;
import com.fdkanfang.service.backend.*;
import com.fdkanfang.web.backend.utils.UserUtils;
import com.fdkanfang.web.mq.config.RabbitConfig;
import com.github.pagehelper.PageInfo;
import io.swagger.annotations.*;
import lombok.extern.log4j.Log4j2;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.Logical;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.task.TaskExecutor;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StopWatch;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import javax.mail.MessagingException;
import javax.validation.Valid;
import java.io.File;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.function.Function;


/**
 * Created by owen on 2020/2/18 0018 12:17
 */
@Api(tags = "房源管理")
@RestController
@RequestMapping("manage/house")
@Transactional
@Log4j2
public class HouseController extends BaseController {

    // 服务器文件保存位置
    @Value("${output.file.path}")
    private String OUTPATH;

    @Value("${server.domain}")
    private String domain;

    @Value("${4dkankan.host}")
    private String KankanHost;

    @Value("${admin.email.account}")
    private String adminEmailAccount;

    @Value("${oss.image.file.path}")
    private String ossPath;

    @Value("${oss.query.url}")
    private String ossQueryUrl;

    @Value("${scale.image.remote.call.path}")
    private String scalImageBash;

    @Autowired
    private HouseService2 houseService2;

    @Autowired
    private ImageService2 imageService2;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private ISceneProService sceneProService;

    @Autowired
    private ISceneProEditService sceneProEditService;

    @Autowired
    private RoleService2 roleService;

    @Autowired
    private UserUtils userUtils;

    @Autowired
    private UserService2 userService2;

    @Autowired
    private OssCheckPointUploadUtil ossCheckPointUploadUtil;


    @ApiOperation("房源列表")
    @PostMapping("list")
    public R list(@RequestBody PageDto param) {

        String token = getToken();
        // 获取用户角色
        List<String> userRoles = userUtils.getRolesByToken(token);
        UserEntity user = userUtils.getUserByToken(token);
        Long userId = user.getId();
        PageInfo<HouseResponse> page = null;
        if (CollectionUtils.isEmpty(userRoles)) {
            log.info("用户权限为空，无法获取房源列表");
            throw new CommonBaseException(ResultCodeEnum.D101, "权限不足");
        }
        if (userRoles.size() == 3) {
            //管理员获取全部房源列表
            page = new PageInfo<>(houseService2.findBySearchKeyForEditOrUploader(param, null, null));
        } else if (userRoles.size() == 2) {
            if (userRoles.contains("edit") && userRoles.contains("upload")) {
                //同时拥有编辑和上传权限
                page = new PageInfo<>(houseService2.findBySearchKeyForEditOrUploader(param, userId, userId));
            } else if (userRoles.contains("edit") && !userRoles.contains("upload")) {
                //只拥有编辑权限
                page = new PageInfo<>(houseService2.findBySearchKeyForEditOrUploader(param, userId, null));
            } else if (!userRoles.contains("edit") && userRoles.contains("upload")) {
                //只拥有上传权限
                page = new PageInfo<>(houseService2.findBySearchKeyForEditOrUploader(param, null, userId));
            } else {
                //理论上不存在此分支情况
                log.error("上传的权限超出了当前有效权限范围");
                throw new CommonBaseException(ResultCodeEnum.D101, "存在无效权限");
            }

        } else if (userRoles.size() == 1) {
            if (userRoles.contains("edit")) {
                //只拥有编辑权限
                page = new PageInfo<>(houseService2.findBySearchKeyForEditOrUploader(param, userId, null));
            } else if (userRoles.contains("upload")) {
                //只拥有上传权限
                page = new PageInfo<>(houseService2.findBySearchKeyForEditOrUploader(param, null, userId));
            } else {
                //只有管理用户的权限，理论不应该单独给这种角色
                log.warn("用户[{}]只单独给了用户管理权限", userId);
                throw new CommonBaseException(ResultCodeEnum.D101, "当前权限不能查看数据");
            }
        } else {
            log.info("用户[{}]的权限超过3个，默认给拉取所有房源");
            //默认获取全部
            page = new PageInfo<>(houseService2.findBySearchKeyForEditOrUploader(param, null, null));
        }

        return new R(2000, page);
    }


    /**
     * 服务器版本+垂直校验
     * <p>
     * 使用mq队列
     * <p>
     * 上传文件，不能使用json传参，只能用表单
     * <p>
     * 如果图片审核不通过，就直接把这条记录禁用or删除，从新添加一条。
     * 修改只能修改房源信息，不能修改图片
     * <p>
     * 上传的图片必须是以xxx_xxx.jpg 格式命名，xxx_:图片所属的户型
     * <p>
     * <p>
     * 这里要用手写的表单验证验证方式
     * <p>
     * 提前把垂直校验，模型图片地址写入数据库，需要配合状态来判断算法计算是否完成；
     */
    @RequiresRoles(value = {"admin", "edit", "upload"}, logical = Logical.OR)
    @ApiOperation("新增或修改房源信息 + 垂直校验")
    @PostMapping(value = "save", consumes = {"multipart/form-data"})
    @Transactional(rollbackFor = Exception.class)
    public R save(HouseDto param) {

        if (StringUtils.isBlank(param.getDistrictName())) {
            log.error("小区名称不能为空");
            return new R(MsgCode.e_COMMON_3001, "小区名称不能为空");
        }
        if (null == param.getFloor() || !StringUtils.isNoneBlank(param.getUnitType(), param.getArea(), param.getOrientation())) {
            return new R(MsgCode.e_COMMON_3001, "楼层/户型/面积/朝向不能为空");
        }

        List<String> fileNames = param.getFileNames();
        if (CollectionUtils.isEmpty(fileNames)) {
            return new R(MsgCode.e_COMMON_3001, "照片名称列表不能为空");
        }
        boolean isNewAdd = false;
        HouseEntity house = null;
        if (null != param.getIsCreate() && param.getIsCreate().compareTo(0) == 0) {
            isNewAdd = true;
        }
        house = updateOrInsertHouse(param);
        // 只有新增是才保存图片，修改时另外处理
        if (isNewAdd) {
            //场景码
            String sceneCode = house.getSceneCode();
            boolean needSendMqMsg = false;
            String directoryName = OUTPATH + sceneCode + File.separator + "input_img" + File.separator;
            FileUtil.mkdir(directoryName);
            HashMap<String, String> ossVerticalImageHighMap = new HashMap<>();
            HashMap<String, String> ossVerticalImageLowMap = new HashMap<>();
            String imageHighPath = null;
            String imageLowPath = null;
            ImageResolutionRate maxTotalResolutionRate = null;
            for (String filename : fileNames) {
                JSONObject jsonObject = JSON.parseObject(filename);
                if (null == jsonObject) {
                    log.error("转换json对象失败:{}", filename);
                    continue;
                }
                //原始照片在oss的路径
                String origin = jsonObject.getString("origin");
                String newFileName = jsonObject.getString("name");
                if (!StringUtils.isNoneEmpty(origin, newFileName)) {
                    continue;
                }
                newFileName =  checkAndChangeFileName(newFileName);
                //从oss获取照片，然后用新的名字下载到本地
                Map<String, Object> ossInfo = getOssBucketInfo(origin);
                if (CollectionUtils.isEmpty(ossInfo)) {
                    log.info("oss数据解析失败，跳过");
                    continue;
                }
                String bucketName = (String) ossInfo.get("ossBucket");
                String ossObjKey = (String) ossInfo.get("ossKey");
                if (!StringUtils.isNoneBlank(bucketName, ossObjKey)) {
                    log.info("oss的bucketName数据解析失败，跳过");
                    continue;
                }
                String oldImageName = "";
                int index = ossObjKey.lastIndexOf("/");
                if (index == -1) {
                    log.error("[{}]获取不到改名前的名称", ossObjKey);
                    continue;
                }
                oldImageName = ossObjKey.substring(index + 1);
                log.info("照片改名前的名称为:{}", oldImageName);
                //这里改名
                String newFilePath = directoryName + newFileName;
                String oldFilePath = directoryName + oldImageName;
                File oldImageFile = new File(oldFilePath);
                File newImageFile = new File(newFilePath);
                try {
                    org.apache.commons.io.FileUtils.copyFile(oldImageFile, newImageFile);
                } catch (IOException e) {
                    log.error("改名操作出现异常，跳过");
                    e.printStackTrace();
                    continue;
                }
                boolean del = FileUtils.deleteFile(oldFilePath);
                log.info("删除的文件目录为:{}，删除结果为:{}", oldFilePath, del);
                //用于四维看看的
                imageHighPath = OUTPATH + sceneCode + "/output_img/" + newFileName;
                //用于sketch，sketch的image表需要存储这个路径，给前端使用
                imageLowPath = OUTPATH + sceneCode + "/output_img_low/" + newFileName;
                // 提前把算法的图片路径存到数据库，但不代表算法运行成功，最后好是要看house的状态；
                String ossVerticalHighPath = ConstantFilePath.OSS_IMAGE_PATH + sceneCode + "/pan/high/" + newFileName;
                String ossVerticalLowPath = ConstantFilePath.OSS_IMAGE_PATH + sceneCode + "/pan/low/" + newFileName;
                //TODO:这里需要计算分辨率
                //照片分辨率
                int totalResolutinRate = 0;
                try {
                    totalResolutinRate = getImageResolutinoRate(newImageFile);
                } catch (IOException e) {
                    log.error("计算照片[{}]分辨率出异常", newFilePath);
                    e.printStackTrace();
                }
                ImageResolutionRate maxResolutionRate = ImageResolutionRate.getResolutionRateByRate(totalResolutinRate);
                log.info("照片{}的像素为:{}", newFilePath, totalResolutinRate);
                if(null == maxResolutionRate){
                    throw new CommonBaseException(ResultCodeEnum.D101 , "照片分辨率超过识别范围");
                }
                if (null == maxTotalResolutionRate) {
                    maxTotalResolutionRate = maxResolutionRate;
                } else {
                    if (null != maxResolutionRate && maxResolutionRate.getOrder() > maxTotalResolutionRate.getOrder()) {
                        maxTotalResolutionRate = maxResolutionRate;
                    }
                }
                addNewImage(param.getId(), newFileName, newFilePath, ossVerticalLowPath, maxResolutionRate);
                // 封装垂直校验后的图片到信息到oss，key为照片在本地的路径，value为照片在oss中的目录路径
                //给四维看看的前端加载使用
                ossVerticalImageHighMap.put(imageHighPath, ossVerticalHighPath);   //四维看看用的，文件太大
                //给sketch的前端使用
                ossVerticalImageLowMap.put(imageLowPath, ossVerticalLowPath);   //sketch用的，文件适中
                needSendMqMsg = true;
            }
            String imageRateStr = null != maxTotalResolutionRate ? maxTotalResolutionRate.name() : "";
            log.info("计算得到的照片最大分辨率为:{}", imageRateStr);
            insertScene(imageRateStr, house);
            if (needSendMqMsg) {
                HashMap<Object, Object> mqMap = new HashMap<>();
                mqMap.put("ossImageHigh", ossVerticalImageHighMap);
                mqMap.put("ossImageLow", ossVerticalImageLowMap);
                mqMap.put("id", house.getId());
                mqMap.put("basePath", OUTPATH);

                mqMap.put("dataDescribe", "");
                log.info("houseId: {}", house.getId());
                //发消息到mq
                rabbitTemplate.convertAndSend(RabbitConfig.VERTICAL_EXCHANGE, RabbitConfig.VERTICAL_QUEUE_ROUTING, mqMap);
            }
            //新增这里，给管理员发送邮件
            String emailContent = "【四维看看 Sketch】温馨提示：用户上传了新的房源，请尽快完成制作。点击立即登录查看：https://sk.4dkankan.com";
            String subject = "四维看看sketch通知";

            try {
                MailUtils.sendHtmlMail(adminEmailAccount, subject, emailContent);
            } catch (UnsupportedEncodingException e) {
                log.error("发送邮件给管理员出错");
                e.printStackTrace();
            } catch (MessagingException e) {
                log.error("发送邮件给管理员出错");
                e.printStackTrace();
            }
        }
        return new R(MsgCode.SUCCESS_CODE, house);
    }

    public Map<String, Object> getOssBucketInfo(String ossUrl) {
        Map<String, Object> result = new HashMap<>();
        if (StringUtils.isBlank(ossUrl)) {
            return result;
        }
        log.info("oss资源的路径为:{}", ossUrl);
        int bucketStar = ossUrl.indexOf("://");
        if (bucketStar == -1) {
            log.error("oss路径没有://");
            return result;
        }
        bucketStar += 3;
        int buckeEnd = ossUrl.indexOf(".");
        if (buckeEnd == -1) {
            log.error("oss路径没有./");
            return result;
        }
        String buckeName = ossUrl.substring(bucketStar, buckeEnd);
        log.info("解析的buckeName={}", buckeName);
        int keyStart = ossUrl.indexOf("com/");
        if (keyStart == -1) {
            log.error("oss路径没有com/");
            return result;
        }
        keyStart += 5;
        String key = ossUrl.substring(keyStart, ossUrl.length());
        log.info("解析出来的oss key={}", key);
        result.put("ossBucket", buckeName);
        result.put("ossKey", key);
        return result;
    }



    //    @RequiresRoles(value = {"admin", "edit", "upload"}, logical = Logical.OR)
    @ApiOperation("生成houseId和场景码")
    @PostMapping(value = "addPosition")
    @Transactional(rollbackFor = Exception.class)
    public R addPosition() {
        return new R(MsgCode.SUCCESS_CODE, generateHouseIdAndSceneNum());
    }

    @ApiOperation("从OSS上下载原始照片并生成缩略图")
    @PostMapping(value = "uploadImages")
    @Transactional(rollbackFor = Exception.class)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "file", value = "文件", paramType = "query", required = true, dataType = "List"),
            @ApiImplicitParam(name = "sceneCode", value = "场景码", paramType = "query", required = true, dataType = "String"),
            @ApiImplicitParam(name = "houseId", value = "房间ID", paramType = "query", required = true, dataType = "Long")
    })
    public Result uploadImages(@RequestParam(name = "sceneCode") String sceneCode,
                               @RequestParam(name = "ossBucketName") String ossBucketName,
                               @RequestParam(name = "ossObjectKey") String ossObjectKey) {

        return Result.success("成功", genScaleImage(ossBucketName, ossObjectKey, sceneCode));
    }


    @Transactional(rollbackFor = Exception.class)
    public void insertScene(String maxResolutionRate, HouseEntity house) {
        SceneProEntity sceneProEntity = new SceneProEntity();
        SceneProEditEntity sceneProEditEntity = new SceneProEditEntity();
        if (ImageResolutionRate.TWO_K.name().equals(maxResolutionRate)) {
            //2k
            sceneProEntity.setSceneScheme(11);
        }else if(ImageResolutionRate.FOUR_K.name().equals(maxResolutionRate)){
            //4k
            sceneProEntity.setSceneScheme(10);
        }else{
            //1k
//            sceneProEntity.setSceneScheme(12);
            sceneProEntity.setSceneScheme(4);
        }
        sceneProEntity.setNum(house.getSceneCode());
        //TODO:不知道为何数据库设置的默认不生效
        sceneProEditEntity.setM2dVisi(1);
        sceneProEditEntity.setM3dVisi(1);
        sceneProEditEntity.setPanoVisi(1);
        sceneProEditEntity.setMapVisi(1);
        int insertOne = sceneProService.save(sceneProEntity);
        if (insertOne != 1) {
            throw new CommonBaseException(ResultCodeEnum.D101, "新增scenePro记录失败");
        }
        sceneProEditEntity.setProId(sceneProEntity.getId());
        int insertTwo = sceneProEditService.save(sceneProEditEntity);
        if (insertTwo != 1) {
            throw new CommonBaseException(ResultCodeEnum.D101, "新增sceneProEdit记录失败");
        }
    }

    public String genScaleImage(String ossBucketName, String ossObjectKey, String sceneCode) {
        String scaleImageOssUrl = "";
        if (!StringUtils.isNoneEmpty(ossBucketName)) {
            log.error("oss的bucketName 和ossKey不能为空");
            return scaleImageOssUrl;
        }
        String fileName = "";
        int index = ossObjectKey.lastIndexOf("/");
        if (index != -1) {
            fileName = ossObjectKey.substring(index + 1, ossObjectKey.length());
        } else {
            log.error("ossObjectKey[{}]的格式不正确，无法提取文件名", ossObjectKey);
        }
        //缩略图上传oss的oss路径
        String imageOssPath = ossPath + "scal_" + fileName;
        //缩略图上传到oss后，查询这个照片的最终路径url
        scaleImageOssUrl = ossQueryUrl + imageOssPath;


        //原始照片从oss上下载到本地的目录
        String directoryName = OUTPATH + sceneCode + File.separator + "input_img" + File.separator;
        //原始照片下载到本地的全路径
        String localFile = ossCheckPointUploadUtil.downLoadOssFileWithSdk(directoryName, "",
                ossBucketName, ossObjectKey);

        //生成的缩略图本地存储的全路径名称
        String scaleImageFullPath = directoryName + "scal_" + fileName;

        if(StringUtils.isBlank(localFile)){
            throw new CommonBaseException(ResultCodeEnum.D101 , "下载原图失败");
        }

        //这里使用多线程异步处理
        final String totalFileName = fileName;
        TaskExecutor taskExecutor = (TaskExecutor) ApplicationContextGetBeanHelper.getBean("taskExecutor");
        CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
            //异步执行图片的压缩
            doScaleImage(sceneCode, totalFileName, imageOssPath , localFile , scaleImageFullPath);

        }, taskExecutor);
        future.exceptionally(new Function<Throwable, Void>() {
            @Override
            public Void apply(Throwable throwable) {
                log.info("异步调用算法脚本执行图片压缩出错了，将使用谷歌组件压缩图片");
                try {
                    StopWatch stopWatch = new StopWatch("time-watch2");
                    stopWatch.start("shell_scale_time2");
                    Thumbnails.of(localFile).size(980, 490).toFile(scaleImageFullPath);
                    stopWatch.stop();
                    log.info("使用谷歌组件照片压缩{}=========结束========耗时[{}]==" , totalFileName , stopWatch.getTotalTimeMillis());
                    //执行上传oss
                    ossCheckPointUploadUtil.upload2(scaleImageFullPath, imageOssPath);
                    //上传完oss后，要删除缩略图的本地文件
                    boolean delScaleResult = FileUtils.deleteFile(scaleImageFullPath);
                    if (!delScaleResult) {
                        log.error("删除本地缩略图[{}]失败", scaleImageFullPath);
                    }
                } catch (IOException e) {
                    log.error("场景[{}]的照片[{}]使用谷歌组件生成缩略图出现异常" , sceneCode , totalFileName);
                    e.printStackTrace();
                }
                return null;
            }
        });

        return scaleImageOssUrl;
    }

    public void doScaleImage(String sceneCode, String fileName,
                             String imageOssPath , String localFile ,
                             String scaleImageFullPath) {
        //原始照片从oss上下载到本地的目录
        String directoryName = OUTPATH + sceneCode + File.separator + "input_img" + File.separator;
        if (StringUtils.isNotBlank(localFile)) {
            //生成缩略图
            String cmd = scalImageBash + " " + fileName + " " + ("scal_" + fileName) + " " + directoryName;
//            String cmd = scalImageBash + " " + localFile + " " + scaleImageFullPath;
            log.info("压缩照片的linux指令为:{}", cmd);
            StopWatch stopWatch = new StopWatch("time-watch");
            stopWatch.start("shell_scale_time1");
            log.info("照片压缩{}=========开始==========" , fileName);
            // 调用算法的图片压缩指令，一直阻塞线程，直到照片生成
            CreateObjUtil.callshell(cmd);
            stopWatch.stop();
            log.info("照片压缩{}=========结束========耗时[{}]==" , fileName , stopWatch.getTotalTimeMillis());
            File resultFile = new File(scaleImageFullPath);
            if(!resultFile.exists()){
                throw new CommonBaseException(ResultCodeEnum.D101 , "脚本生成缩略图失败");
            }
            //执行上传oss
            ossCheckPointUploadUtil.upload2(scaleImageFullPath, imageOssPath);
            //上传完oss后，要删除缩略图的本地文件
            boolean delScalResult = FileUtils.deleteFile(scaleImageFullPath);
            if (!delScalResult) {
                log.error("删除本地缩略图[{}]失败", scaleImageFullPath);
            }
        }
    }


    private void addNewImage(long houseId,
                             String imageFileName, String imageLocalPath,
                             String ossVerticalHighPath,
                             ImageResolutionRate maxResolutionRate) {
        ImageEntity image = new ImageEntity();
        // 获取图片房间类型
        String imageType = StringUtils.substringBefore(imageFileName, "_");
        image.setType(imageType);
        image.setVerticalPath(ossVerticalHighPath);
        image.setFileName(imageFileName);
        // 这个参数给前端用，只要有文件名就可以了
        image.setPath(imageLocalPath);
        image.setLocalPath(imageLocalPath);

        image.setHouseId(houseId);
        // 默认所有图片都是一楼
        image.setFloor(1);

        image.setResolutionRate(null != maxResolutionRate ? maxResolutionRate.name() : null);
        int insert = imageService2.save(image);
        if (insert != 1) {
            throw new CommonBaseException(ResultCodeEnum.D101, "新增image记录失败");
        }
    }

    private String generalRandFileName(String fileName) {
        if (StringUtils.isBlank(fileName)) {
            return "";
        }
        int index = fileName.lastIndexOf(".");
        if (index != -1) {
            String name = fileName.substring(0, index);
            String form = fileName.substring(index, fileName.length());
            log.info("照片存名字部分为:{}", name);
            if (StringUtils.isNotBlank(name)) {
                Random random = new Random(10);
                name += System.currentTimeMillis() + random.nextInt(10);
                name += form;
                return name;
            }
        }
        return "";
    }

    private int getImageResolutinoRate(File localFile) throws IOException {
        if (null != localFile) {
            int totalResolutinRate = -1;
            SimpleImageInfo simpleImageInfo = new SimpleImageInfo(localFile);
            if (null != simpleImageInfo) {
                if (simpleImageInfo.getWidth() < simpleImageInfo.getHeight()) {
                    totalResolutinRate = simpleImageInfo.getHeight();
                } else {
                    totalResolutinRate = simpleImageInfo.getWidth();
                }
            }
            return totalResolutinRate;
        }
        return 0;
    }

    private void saveFileToLocal(CommonsMultipartFile file, String localFullPath) throws IOException {

        if (StringUtils.isBlank(localFullPath) || null == file) {
            return;
        }
        File newFile = new File(localFullPath);
        file.transferTo(newFile);
    }

    private String checkAndChangeFileName(String filename) {

        if (StringUtils.isBlank(filename)) {
            throw new CommonBaseException(ResultCodeEnum.D100, "文件名不能为空");
        }
        if (filename.contains(".JPG")) {
            int index = filename.lastIndexOf(".");
            String fileNameWithoutPostfix = filename.substring(0, index);
            filename = fileNameWithoutPostfix + ".jpg";
            log.info("照片的格式写成了大写，需要转成小写:{}", filename);
        }
        // 检查一下，生成模型的照片名称不能有"-"，否则生成模型会出现问题
        if (filename.contains("-")) {
            log.error("filename: {}", filename);
            throw new BaseRuntimeException(MsgCode.e_COMMON_3003, "图片命名不符合要求，不能包含符号-，请使用_");
        }
        if (RegexpUtils.isContainChinese(filename)) {
            log.error("图片名称不允许中文字符: {}", filename);
            throw new BaseRuntimeException(MsgCode.e_COMMON_3003, "图片名称不允许中文字符");
        }
        return filename;
    }

    private Map<String, Object> generateHouseIdAndSceneNum() {
        Map<String, Object> result = new HashMap<>();
        Integer byMaxNum = houseService2.findByMaxNum();
        // 用于第一条数据
        byMaxNum = (byMaxNum == null) ? 10000 : byMaxNum;
        byMaxNum += 1;
        String sceneCode = getSceneCode();
        HouseEntity house = new HouseEntity();
        UserEntity user = userUtils.getUserByToken(getToken());
        house.setUserId(user.getId());
        house.setNum(byMaxNum + 1);
        house.setSceneCode(sceneCode);
        house.setWebSite(domain + "?m=" + sceneCode);
        house.setFilePath(OUTPATH + sceneCode);
        int insert = houseService2.save(house);
        if (insert != 1) {
            log.error("新增房源失败");
            return result;
        }
        HouseEntity dbHouse = houseService2.findBySceneCode(sceneCode);
        if (null != dbHouse) {
            result.put("id", dbHouse.getId());
            result.put("sceneCode", sceneCode);
        }
        return result;
    }

    @Transactional(rollbackFor = Exception.class)
    public HouseEntity updateOrInsertHouse(HouseDto param) {
        if (null == param) {
            return null;
        }
        HouseEntity house = null;
        if (param.getId() == null) {
            house = new HouseEntity();
            UserEntity user = userUtils.getUserByToken(getToken());
            house.setUserId(user.getId());
            param.setId(null);
            BeanUtils.copyProperties(param, house);
            Integer byMaxNum = houseService2.findByMaxNum();
            // 用于第一条数据
            byMaxNum = (byMaxNum == null) ? 10000 : byMaxNum;
            String sceneCode = getSceneCode();
            house.setNum(byMaxNum + 1);
            house.setSceneCode(sceneCode);
            house.setWebSite(domain + "?m=" + sceneCode);
            house.setFilePath(OUTPATH + sceneCode);
            houseService2.save(house);
        } else {
            house = houseService2.findById(param.getId());
            if (house == null) {
                log.error("房源不存在： {}", param.getId());
                throw new CommonBaseException(ResultCodeEnum.D101, "房源不存在");
            }
            BeanUtils.copyProperties(param, house);
            if (StringUtils.isBlank(house.getSceneCode())) {
                house.setSceneCode(param.getSceneCode());
            }

            if (StringUtils.isBlank(house.getWebSite())) {
                house.setWebSite(domain + "?m=" + param.getSceneCode());
            }

            if (StringUtils.isBlank(house.getFilePath())) {
                house.setFilePath(OUTPATH + param.getSceneCode());
            }
            house.setUpdateTime(new Date());
            house.setStatus(0);
            houseService2.update(house);
        }
        return house;
    }


    @ApiOperation("预审")
    @ResponseBody
    @PostMapping(value = "/auditHouse")
    @Transactional(rollbackFor = Exception.class)
    public Result auditHouse(@RequestBody @ApiParam(name = "用户登录注册实体", value = "传入json格式", required = true) HouseAuditDto houseAuditDto) {
        if (StringUtils.isBlank(houseAuditDto.getDesc()) || null == houseAuditDto.getHouseId() || null == houseAuditDto.getResult()) {
            throw new CommonBaseException(ResultCodeEnum.D3001);
        }
        HouseEntity houseEntity = houseService2.findById(houseAuditDto.getHouseId());
        if (null == houseEntity) {
            throw new CommonBaseException(ResultCodeEnum.D101, "房源不存在");
        }
        if (houseAuditDto.getResult().compareTo(1) != 0 && houseAuditDto.getResult().compareTo(0) != 0) {
            throw new CommonBaseException(ResultCodeEnum.D101, "审批结果格式不正确");
        }

        houseEntity.setAuditResult(houseAuditDto.getResult());
        houseEntity.setAuditDesc(houseAuditDto.getDesc());
        houseEntity.setUpdateTime(new Date());
        int update = houseService2.update(houseEntity);
        if (update != 1) {
            throw new CommonBaseException(ResultCodeEnum.D101, "更新房源预审信息失败");
        }
        return Result.success();
    }

    @ApiOperation("标记不能编辑")
    @ResponseBody
    @PostMapping(value = "/markFail")
    public Result markCannotEditHouse(@RequestBody @ApiParam(name = "用户登录注册实体", value = "传入json格式", required = true) HouseAuditDto houseAuditDto) {
        if (StringUtils.isBlank(houseAuditDto.getDesc()) || null == houseAuditDto.getHouseId()) {
            throw new CommonBaseException(ResultCodeEnum.D3001);
        }
        HouseEntity houseEntity = houseService2.findById(houseAuditDto.getHouseId());
        if (null == houseEntity) {
            throw new CommonBaseException(ResultCodeEnum.D101, "房源不存在");
        }
        houseEntity.setCanNotEdit(0);
        houseEntity.setCanNotEditDesc(houseAuditDto.getDesc());
        houseEntity.setUpdateTime(new Date());
        int update = houseService2.update(houseEntity);
        if (update != 1) {
            throw new CommonBaseException(ResultCodeEnum.D101, "更新房源无法制作信息失败");
        }
        return Result.success();
    }

    /**
     * @param houseId
     * @param floor   可选参数
     */
    @ApiOperation("查询房源信息")
    @GetMapping("detail")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "houseId", value = "房源id", required = true),
            @ApiImplicitParam(name = "floor", value = "楼层", required = false)
    })
    public R detail(Long houseId, Integer floor) {
        HouseEntity house = houseService2.findById(houseId);
        List<ImageEntity> images = imageService2.findByHouseIdAndFloor(houseId, floor);
        if (null != house) {
            house.setImages(images);
            HouseResponse houseResponse = new HouseResponse();
            BeanUtil.copyProperties(house, houseResponse, CopyOptions.create().setIgnoreNullValue(true).setIgnoreError(true));
            if (null != house.getUserId()) {
                UserEntity uploader = userService2.findById(house.getUserId());
                if (null != uploader) {
                    houseResponse.setUploadName(uploader.getRealName());
                }
            }
            if (null != house.getHandler()) {
                UserEntity handler = userService2.findById(house.getHandler());
                if (null != handler) {
                    houseResponse.setHandlerName(handler.getRealName());
                }
            }
            return new R(MsgCode.SUCCESS_CODE, houseResponse);
        } else {
            return new R(MsgCode.ERROR_CODE, "房源不存在");
        }
    }


    @RequiresRoles(value = {"admin", "edit", "upload"}, logical = Logical.OR)
    @ApiOperation("删除房源(软删除)")
    @GetMapping("removes/{ids}")
    @Transactional(rollbackFor = Exception.class)
    public R removes(@PathVariable String ids) {

        List<String> userRoles = userUtils.getRolesByToken(getToken());
        String roleKey = null;
        if (userRoles.size() <= 1) {
            // 只有一个权限时
            roleKey = (String) userRoles.get(0);
            if (!"upload".equals(roleKey)) {
                log.warn("只有一个权限的非上传者角色，不能删除房源");
                throw new CommonBaseException(ResultCodeEnum.D101, "权限不足，不能删除房源");
            }
        } else if (userRoles.size() == 2) {
            if (userRoles.contains("edit") && userRoles.contains("admin")) {
                //理论上不会有这种权限组合
                log.warn("多于一个权限的角色，只有用户管理和编辑房源权限不能删除房源");
                throw new CommonBaseException(ResultCodeEnum.D101, "权限不足(缺少上传房源权限)，不能删除房源");
            }

        }

        String[] split = ids.split(",");
        for (String s : split) {
            HouseEntity houseEntity = houseService2.findById(Long.valueOf(s));
            if (houseEntity == null) {
                log.error("房源id有误，没有存在的房源");
                return new R(MsgCode.e_COMMON_3002, "没有存在的房源");
            }

            if (null != houseEntity.getStatus()) {

                if ((houseEntity.getStatus().compareTo(0) == 0) && (null != houseEntity.getStatus() && houseEntity.getStatus().compareTo(1) == 0)) {
                    //预审通过了的，还未垂直校验的，不能删除
                    log.error("房源垂直校验计算中不能删除");
                    throw new CommonBaseException(ResultCodeEnum.D101, "房源垂直校验计算中不能删除");
                }
                if (houseEntity.getStatus().compareTo(3) == 0) {
                    log.error("房源生成模型计算中不能删除");
                    throw new CommonBaseException(ResultCodeEnum.D101, "房源生成模型计算中不能删除");
                }


            }

            houseEntity.setRecStatus("I");
            houseEntity.setUpdateTime(new Date());
            int update = houseService2.update(houseEntity);
            if (update != 1) {
                log.error("删除房源失败[{}]", houseEntity.getId());
                throw new CommonBaseException(ResultCodeEnum.D101, "删除房源失败");
            }
        }
        return new R(MsgCode.SUCCESS_CODE, MsgCode.msg_SUCCESS);
    }


    /**
     * 更新sceneJson（写到另一个字段）, 保留原始sceneJson数据
     */
    @RequiresRoles(value = {"admin", "edit"}, logical = Logical.OR)
    @ApiOperation("更新sceneJson")
    @PostMapping("update/sceneJson")
    public R updateSceneJson(@Valid @RequestBody SceneJsonDto param) {

        HouseEntity house = houseService2.findById(param.getId());
        if (house == null) {
            log.error("房源id不存在");
            return new R(MsgCode.e_COMMON_3001, "房源id不存在");
        }

        house.setNewSceneJson(param.getSceneJson());
        house.setUpdateTime(new Date());

        houseService2.update(house);

        return new R(MsgCode.SUCCESS_CODE, MsgCode.msg_SUCCESS);
    }


    /**
     * 更新floorData数据
     */
    @RequiresRoles(value = {"admin", "edit"}, logical = Logical.OR)
    @ApiOperation("更新floorData")
    @PostMapping("update/floorData")
    public R updateFloorData(@Valid @RequestBody FloorDataVo param) {

        HouseEntity house = houseService2.findById(param.getId());
        if (house == null) {
            log.error("房源id不存在");
            return new R(MsgCode.e_COMMON_3001, "房源id不存在");
        }

        house.setFloorData(param.getFloorData());
        house.setUpdateTime(new Date());

        houseService2.update(house);
        return new R(MsgCode.SUCCESS_CODE, MsgCode.msg_SUCCESS);
    }


    @ApiOperation("获取楼层户型图")
    @GetMapping("image/find/floor/{houseId}/{floor}")
    public R findImageByFloor(@PathVariable Long houseId, @PathVariable Integer floor) {
        List<ImageEntity> images = imageService2.findByHouseIdAndFloor(houseId, floor);
        return new R(MsgCode.SUCCESS_CODE, images);
    }


    /**
     * 只有管理员才能分配制作人
     * 制作人是edit角色
     */
    @RequiresRoles(value = {"admin"}, logical = Logical.OR)
    @ApiOperation("获取制作人")
    @GetMapping("getHandler")
    public R getHandler() {
        // 根据edit权限查询用户
        List<UserResponse> usre = roleService.findUserByRoleKey("edit");
        return new R(MsgCode.SUCCESS_CODE, usre);
    }


    @RequiresRoles(value = {"admin"}, logical = Logical.OR)
    @ApiOperation("分配制作人")
    @GetMapping("setHandler/{houseId}/{userId}")
    public R setHandler(@PathVariable Long houseId, @PathVariable Long userId) {

        // 根据edit权限查询用户
        HouseEntity houseEntity = houseService2.findById(houseId);
        if (houseEntity == null) {
            log.error("房源不存在: {}", houseId);
            return new R(MsgCode.e_COMMON_3001, "房源不存在");
        }
        houseEntity.setHandler(userId);
        houseEntity.setUpdateTime(new Date());

        if (null != houseEntity.getAuditResult() && houseEntity.getAuditResult().compareTo(0) == 0) {
            //重新分配制作人，前面不通过的审批，需要擦除,TODO:需要添加一个上一状态，用于追踪
            houseEntity.setAuditResult(null);
            houseEntity.setAuditDesc(null);
            houseEntity.setCanNotEdit(1);
            houseEntity.setCanNotEditDesc(null);
        }

        if (null != houseEntity.getCanNotEdit() && houseEntity.getCanNotEdit().compareTo(0) == 0) {
            //重新分配制作人，前面不通过的审批，需要擦除,TODO:需要添加一个上一状态，用于追踪
            houseEntity.setAuditResult(null);
            houseEntity.setAuditDesc(null);
            houseEntity.setCanNotEdit(1);
            houseEntity.setCanNotEditDesc(null);
        }

        int update = houseService2.updateAll(houseEntity);
        if (update != 1) {
            throw new CommonBaseException(ResultCodeEnum.D101, "更新房源数据失败");
        }
        return new R(MsgCode.SUCCESS_CODE, MsgCode.msg_SUCCESS);
    }


    @ApiOperation("查询房源图片")
    @GetMapping("image/detail/{id}")
    public R imageDetail(@PathVariable Long id) {
        return new R(MsgCode.SUCCESS_CODE, imageService2.findById(id));
    }

    @RequiresRoles(value = {"admin", "edit"}, logical = Logical.OR)
    @ApiOperation("编辑图片信息")
    @PostMapping("image/edit")
    public R imageEdit(@RequestBody ImageDto param) {
        ImageEntity image = imageService2.findById(param.getId());
        if (image == null) {
            log.error("图片id不存在： {}", param.getId());
            throw new BaseRuntimeException(MsgCode.e_COMMON_3002, MsgCode.msg_COMMON_3002);
        }
        BeanUtils.copyProperties(param, image);
        image.setUpdateTime(new Date());

        imageService2.update(image);
        return new R(MsgCode.SUCCESS_CODE, MsgCode.msg_SUCCESS);
    }


    @RequiresRoles(value = {"admin", "edit"}, logical = Logical.OR)
    @ApiOperation("批量编辑图片信息")
    @PostMapping("image/edit/all")
    public R imageEdit(@RequestBody Map<Long, String> param) {

        for (Map.Entry<Long, String> a : param.entrySet()) {
            ImageEntity image = imageService2.findById(a.getKey());
            image.setUpdateTime(new Date());
            image.setIssue(a.getValue());
            imageService2.update(image);

        }

        return new R(MsgCode.SUCCESS_CODE, MsgCode.msg_SUCCESS);
    }


    /**
     * 陈世超的算法
     * 调用算法计算场景,生产全景图
     * <p>
     * 图片是用垂直校验后的图片
     * <p>
     * Content传到后台会生成两个文件：floorplan.json、vision.txt
     */
    @RequiresRoles(value = {"admin", "edit"}, logical = Logical.OR)
    @ApiOperation("生成模型")
    @PostMapping("rsa/pano")
    @Transactional(rollbackFor = Exception.class)
    public R rsaPano(@Valid @RequestBody PanoDto param) throws Exception {
        log.info("run rsaPano");

        if (param == null) {
            log.error("参数为空");
            return new R(50001, "error");
        }
        HouseEntity house = houseService2.findById(param.getHouseId());
        if (house == null) {
            log.error("房源不存在： {}", param.getHouseId());
            return new R(MsgCode.e_COMMON_3002, MsgCode.msg_COMMON_3002);
        }

        String sceneCode = house.getSceneCode();

        boolean flagQ = false;
        // data/kanfang/10001/pano
        String savePath = OUTPATH + sceneCode + "/" + TypeCode.SCENE_PANO;
        // 检查场景码对应的pano文件夹是否存在，存在则删除里面的内容（用户从新编辑场景）
        if (FileUtil.isDirectory(savePath)) {
            FileUtil.del(savePath);
            log.info("删除旧目录重新计算： {}", sceneCode);
        }

        log.warn("savePath: {}", savePath);
        String sourcePath = savePath + "/extras/";
        String resultSourcePath = savePath + "/results/";
        try {

            FileUtils.createDir(sourcePath);
            FileUtils.createDirIfExistThenDel(resultSourcePath);
            /**
             * 以下字段为给算法部传递的参数（data.json），用于生成模型和
             * 照片，提供前端使用,完整的参数如下：
             * {
             * 	"split_type": "SPLIT_V5",
             * 	"skybox_type": "SKYBOX_V5",
             * 	"extras": {
             * 		"has_vision_txt": true,
             * 		"has_floorplan_json": true,
             * 		"has_source_images": true
             *        }
             * }
             * */
            String content = "";
            //生成data.json供算法部使用
            JSONObject dataJson = new JSONObject();
            dataJson.put("split_type", "SPLIT_V5");
            String imageResolution = checkImageResolutionRate(house);
            if (ImageResolutionRate.TWO_K.name().equals(imageResolution)) {
                //2 K 照片
                dataJson.put("skybox_type", "SKYBOX_V7");
            } else if(ImageResolutionRate.FOUR_K.name().equals(imageResolution)){
                //4 k照片
                dataJson.put("skybox_type", "SKYBOX_V6");
            }else if(ImageResolutionRate.ONE_K.name().equals(imageResolution)){
                //1 k照片
//                dataJson.put("skybox_type", "SKYBOX_V9");
                dataJson.put("skybox_type", "SKYBOX_V1");
            }else{
                throw new CommonBaseException(ResultCodeEnum.D101 , "照片的分辨率非法，无法决策模型类别");
            }
            dataJson.put("extras", null);
            JSONObject extrasJson = new JSONObject();
            extrasJson.put("has_vision_txt", true);
            extrasJson.put("has_floorplan_json", true);
            extrasJson.put("has_source_images", true);
            dataJson.put("extras", extrasJson);
            FileUtils.fileWriter(dataJson.toJSONString(), savePath + "/data.json");
            log.warn("dataJson的生成路径: {}", savePath + "/data.json");

            // 解析json
            JSONObject original = JSON.parseObject(param.getContent());

            // 获取modelData, cameraData
            String floorPlan = original.getString("floorplan");
            String vision = original.getString("vision");

            if (floorPlan == null) {
                log.error("floorPlan不能为空");
                return new R(50002, "floorPlan不能为空");
            }

            if (vision == null) {
                log.error("vision不能为空");
                return new R(50002, "vision不能为空");
            }
            // json写入服务器
            FileUtils.fileWriter(floorPlan, sourcePath + "floorplan.json");
            FileUtils.fileWriter(vision, sourcePath + "vision.txt");
            FileUtils.fileWriter(vision, resultSourcePath + "vision.txt");
            log.info("floorplan.json生成完成");
            log.info("/extras/vision.txt,/results/vision.txt生成完成");
            // 复制垂直校验图片到指定目录
            String verticalImagePath = OUTPATH + sceneCode + "/output_img";
            String panoImagePath = sourcePath + "images/";
            // srcPath: /data/kanfang/10002/output_img
            log.info("srcPath: {}", verticalImagePath);
            // target: /data/kanfang/10002/pano/extras/images/
            log.info("target: {}", panoImagePath);
            FileUtil.copyFilesFromDir(new File(verticalImagePath), new File(panoImagePath), true);
            flagQ = true;

        } catch (Exception e) {
            e.printStackTrace();
            log.error("出错了……");
            return new R(50002, e.getMessage());
        }

        if (flagQ) {

            // 上传floorplan.json到oss, 并命名为floor.json
            HashMap<String, String> uploadJson = new HashMap<>();
            // osspath : images/images+sceneCode/floor.json
            uploadJson.put(sourcePath + "floorplan.json", ConstantFilePath.OSS_FLOOR_PATH + sceneCode + "/floor.json");
            AliyunOssUtil.uploadMulFiles(uploadJson);
            // savePath:/data/kanfang/房源编号/
            // basePath: /data/kanfang/10002/pano
            log.info("basePath: {}", savePath);
            log.info("houseId: {}", house.getId());

            // 每点击生成模型一次，就修改SceneProEditEntity的部分值
            SceneProEntity sceneProEntity = sceneProService.findBySceneNum(house.getSceneCode());
            if (sceneProEntity == null) {
                log.error("sceneProEntity对象不存在：{}", house.getSceneCode());
                return new R(MsgCode.ERROR_CODE, "sceneProEntity对象不存在");
            }

            // 修改房源状态, 3:模型计算中
            house.setStatus(3);
            house.setUpdateTime(new Date());
            int updateHouse = houseService2.update(house);
            if (updateHouse != 1) {
                throw new CommonBaseException(ResultCodeEnum.D101, "更新房源状态失败");
            }

            SceneProEditEntity proEditEntity = sceneProEditService.findByProId(sceneProEntity.getId());
            proEditEntity.setVersion(proEditEntity.getVersion() + 1);
            proEditEntity.setFloorEditVer(proEditEntity.getFloorEditVer() + 1);
            proEditEntity.setFloorPublishVer(proEditEntity.getFloorPublishVer() + 1);
            proEditEntity.setUpdateTime(new Date());

            int updateSceneProEdit = sceneProEditService.update(proEditEntity);
            if (updateSceneProEdit != 1) {
                throw new CommonBaseException(ResultCodeEnum.D101, "更新sceneProEdit状态失败");
            }
            log.info("更新SceneProEditEntity数据完成");

            //发消息到mq
            Map<String, Object> mqMap = formatMqReq(house, sceneProEntity, savePath, RabbitConfig.PANO_CALLBACK_QUEUE);
            String mqMapStr = JSON.toJSONString(mqMap);
            log.info("发送mq消息给四维看看建模:{}", mqMapStr);
            rabbitTemplate.convertAndSend(RabbitConfig.PANO_EXCHANGE, RabbitConfig.PANO_QUEUE_ROUTING, mqMapStr);
            log.info("Mq入队成功");

        }

        return new R(MsgCode.SUCCESS_CODE, house);
    }

    private Map<String, Object> formatMqReq(HouseEntity house, SceneProEntity sceneProEntity,
                                            String path, String callbackQueue) {
        Map<String, Object> result = new HashMap<>();
        if (null == house) {
            return result;
        }
        result.put("sceneName", house.getDistrictName());
        result.put("sceneNum", house.getSceneCode());
        result.put("sceneScheme", sceneProEntity.getSceneScheme());
        if (null != house.getUserId()) {
            UserEntity user = userService2.findById(house.getUserId());
            int kankanUserId = -1;
            if (null != user && null != user.getKankanUserId()) {
                kankanUserId = user.getKankanUserId();
            }
            result.put("userId", kankanUserId);
        }

        result.put("dataSource", path);
        result.put("callbackQueue", callbackQueue);
        return result;
    }

    private String checkImageResolutionRate(HouseEntity houseEntity) {
        if (null == houseEntity || null == houseEntity.getId()) {
            return null;
        }
        List<ImageEntity> imageEntities = imageService2.findByHouseId(houseEntity.getId());
        if (CollectionUtils.isEmpty(imageEntities)) {
            log.error("房源[{}]下面无照片");
            return null;
        }
        int sort = 0;
        ImageResolutionRate maxResolution = null;
        for (ImageEntity imageEntity : imageEntities) {
            if (StringUtils.isBlank(imageEntity.getResolutionRate())) {
                log.warn("房源[{}]的照片[{}]没有设置照片分辨率，跳过", houseEntity.getId(), imageEntity.getId());
                break;
            }
            ImageResolutionRate curResolution = ImageResolutionRate.getResolutionByName(imageEntity.getResolutionRate());
            if (null != curResolution) {
                if (curResolution.getOrder() > sort) {
                    sort = curResolution.getOrder();
                    maxResolution = curResolution;
                }
            }
        }
        log.info("房源[{}]的照片最大的分辨率为:{}", houseEntity.getId(), null != maxResolution ? maxResolution.name() : "空值");
        return null != maxResolution ? maxResolution.name() : null;
    }


    /***
     * 从四维看看获取唯一场景码
     */
    private String getSceneCode() {
        String url = KankanHost + "api/scene/finSkSceneNum";
        String kankanResult = HttpClientUtil.doPost(url);
        //解析返回结果
        JSONObject res = JSONObject.parseObject(kankanResult);
        log.info("四维看看返回登录数据:{}", null != res ? res.toJSONString() : "返回结果为null");
        Integer code = DataUtils.getInteger(res.get("code"));
        if (null == code || code.compareTo(0) != 0) {
            throw new CommonBaseException(ResultCodeEnum.D101, "从四维看看获取场景码失败");
        }
        String sceneCode = res.getString("msg");
        if (StringUtils.isBlank(sceneCode)) {
            throw new CommonBaseException(ResultCodeEnum.D101, "四维看看返回的场景码为空");
        }
        return sceneCode;
    }


}
