package com.pcloud.book.applet.biz.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Lists;
import com.pcloud.appcenter.app.dto.AppDto;
import com.pcloud.book.applet.biz.AppletBooklistBiz;
import com.pcloud.book.applet.biz.AppletNewsBiz;
import com.pcloud.book.applet.biz.AppletRecordBiz;
import com.pcloud.book.applet.dao.AppletBooklistDao;
import com.pcloud.book.applet.dao.AppletRecordDao;
import com.pcloud.book.applet.dao.AppletRecordDayServeDao;
import com.pcloud.book.applet.dao.AppletRecordServeDao;
import com.pcloud.book.applet.dto.AppletAppOrProductDTO;
import com.pcloud.book.applet.dto.AppletBooklistDTO;
import com.pcloud.book.applet.dto.AppletNewsDTO;
import com.pcloud.book.applet.dto.AppletOuterBooklistDTO;
import com.pcloud.book.applet.dto.AppletRecordDTO;
import com.pcloud.book.applet.dto.AppletTrackDTO;
import com.pcloud.book.applet.dto.AppletUserBookcaseDTO;
import com.pcloud.book.applet.dto.BookDTO4Booklist;
import com.pcloud.book.applet.dto.ReadBookRecordDTO;
import com.pcloud.book.applet.entity.AppletFootstepRecord;
import com.pcloud.book.applet.entity.AppletRecord;
import com.pcloud.book.applet.entity.AppletRecordDayServe;
import com.pcloud.book.applet.entity.AppletRecordServe;
import com.pcloud.book.applet.entity.AppletTrack;
import com.pcloud.book.applet.enums.AppletRecordTypeEnum;
import com.pcloud.book.applet.mapper.AppletFootstepRecordMapper;
import com.pcloud.book.applet.mapper.AppletTrackMapper;
import com.pcloud.book.base.exception.BookBizException;
import com.pcloud.book.book.constant.BookConstant;
import com.pcloud.book.book.dao.BookDao;
import com.pcloud.book.book.dto.BookDto;
import com.pcloud.book.consumer.app.AppConsr;
import com.pcloud.book.consumer.channel.QrcodeSceneConsr;
import com.pcloud.book.consumer.reader.ReaderConsr;
import com.pcloud.book.consumer.resource.ProductConsr;
import com.pcloud.book.copyright.biz.BookAuthServeBiz;
import com.pcloud.book.group.biz.WeworkTeacherBiz;
import com.pcloud.book.group.dto.WxWorkTeacherDTO;
import com.pcloud.book.group.enums.AppAndProductTypeEnum;
import com.pcloud.book.group.tools.SendWeixinRequestTools;
import com.pcloud.book.rightsSetting.biz.RightsSettingBiz;
import com.pcloud.book.skill.biz.PcloudGroupActivityBiz;
import com.pcloud.book.applet.dto.GroupActivity4AppletDTO;
import com.pcloud.book.util.common.CommonUtils;
import com.pcloud.book.util.common.ThreadPoolUtils;
import com.pcloud.book.util.properties.BookProps;
import com.pcloud.channelcenter.base.constants.MessageFromTypeEnum;
import com.pcloud.channelcenter.wechat.dto.AccountSettingDto;
import com.pcloud.common.constant.LinkServeConstant;
import com.pcloud.common.core.aspect.ParamLog;
import com.pcloud.common.exceptions.BizException;
import com.pcloud.common.page.PageBeanNew;
import com.pcloud.common.page.PageParam;
import com.pcloud.common.utils.BeanUtils;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.NumberUtil;
import com.pcloud.common.utils.cache.redis.JedisClusterUtils;
import com.pcloud.common.utils.string.StringUtil;
import com.pcloud.readercenter.common.enums.YesOrNoNumEnum;
import com.pcloud.resourcecenter.product.dto.ProductDto;
import com.pcloud.resourcecenter.product.dto.ProductLabelDto;

import org.apache.commons.collections.MapUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.stream.Collectors;

import static com.pcloud.book.book.constant.BookConstant.READER_COUNT_MAP;

/**
 * (AppletRecord)表服务实现类
 *
 * @author makejava
 * @since 2020-08-27 15:49:57
 */
@Service("appletRecordBiz")
public class AppletRecordBizImpl implements AppletRecordBiz {

    private static final Logger LOGGER = LoggerFactory.getLogger(AppletRecordBizImpl.class);

    private static final String HANDLE_APPLET_RECORD_TYPE_CODE_KEY = "BOOK:AppletRecordBizImpl:handleAppletRecordTypeCode";
    private static final String HANDLE_APPLET_RECORD_TYPE_CODE_STATUS_KEY = "BOOK:AppletRecordBizImpl:handleAppletRecordTypeCode:runStatus";

    @Autowired
    private AppletRecordDao appletRecordDao;
    @Autowired
    private ProductConsr productConsr;
    @Autowired
    private AppConsr appConsr;
    @Autowired
    private AppletNewsBiz appletNewsBiz;
    @Autowired
    private PcloudGroupActivityBiz pcloudGroupActivityBiz;
    @Autowired
    private AppletBooklistBiz appletBooklistBiz;
    @Autowired
    private RightsSettingBiz rightsSettingBiz;
    @Autowired
    private QrcodeSceneConsr qrcodeSceneConsr;
    @Autowired
    private AppletBooklistDao appletBooklistDao;
    @Autowired
    private AppletRecordDayServeDao appletRecordDayServeDao;
    @Autowired
    private AppletRecordServeDao appletRecordServeDao;
    @Autowired
    private WeworkTeacherBiz weworkTeacherBiz;
    @Autowired
    private AppletFootstepRecordMapper appletFootstepRecordMapper;
    @Autowired
    private BookDao bookDao;
    @Autowired
    private AppletTrackMapper appletTrackMapper;
    @Autowired
    private ReaderConsr readerConsr;
    @Autowired
    private BookProps bookProps;
    @Autowired
    private BookAuthServeBiz bookAuthServeBiz;

    @Override
    @ParamLog("通过ID查询单条数据")
    public AppletRecord getById(Long id) {
        return appletRecordDao.getById(id);
    }

    @Override
    @ParamLog("查询多条数据")
    public PageBeanNew getList(Integer currentPage, Integer numPerPage) {
        PageBeanNew pageBeanNew = appletRecordDao.listPageNew(new PageParam(currentPage, numPerPage), null, "getList");
        List recordList = pageBeanNew.getRecordList();
        if (ListUtils.isEmpty(recordList)) {
            return pageBeanNew;
        }
        // 加载其它数据

        return pageBeanNew;
    }

    @Override
    @ParamLog("新增足迹埋点")
    public Long insert(AppletRecord appletRecord) {
        ThreadPoolUtils.APPLET_RECORD.execute(()-> {
            insertCheck(appletRecord);
            AppletRecordDTO appletRecordDTO = new AppletRecordDTO();
            BeanUtils.copyProperties(appletRecord, appletRecordDTO);
            fillTypeCode(Lists.newArrayList(appletRecordDTO));
            BeanUtils.copyProperties(appletRecordDTO, appletRecord);
            appletRecordDao.insert(appletRecord);
            //判断日表是否有数据
            AppletRecordDayServe appletRecordDayServe = new AppletRecordDayServe();
            BeanUtils.copyProperties(appletRecord, appletRecordDayServe);
            AppletRecordServe appletRecordServe = new AppletRecordServe();
            BeanUtils.copyProperties(appletRecord, appletRecordServe);
            AppletRecordDayServe appletRecordDayServe4Data = appletRecordDayServeDao.getByTypeAndServeId(appletRecord.getWechatUserId(), appletRecord.getRecordType(), appletRecord.getFromId(), DateUtil.today());
            if (null != appletRecordDayServe4Data) {
                //更新
                appletRecordDayServe.setId(appletRecordDayServe4Data.getId());
                appletRecordDayServeDao.update(appletRecordDayServe);
            } else {
                //新增
                appletRecordDayServeDao.insert(appletRecordDayServe);
            }
            //判断总表是否有数据
            AppletRecordServe appletRecordServe4Data = appletRecordServeDao.getByTypeAndServeId(appletRecord.getWechatUserId(), appletRecord.getRecordType(), appletRecord.getFromId());
            if (null != appletRecordServe4Data) {
                //更新
                appletRecordServe.setId(appletRecordServe4Data.getId());
                appletRecordServeDao.update(appletRecordServe);
            } else {
                //新增
                appletRecordServeDao.insert(appletRecordServe);
            }
        });
        return appletRecord.getId();
    }

    private void insertCheck(AppletRecord appletRecord) {
        if (null == appletRecord) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "appletRecord为空");
        }
        if (null == appletRecord.getRecordType()) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "recordType不能为空");
        }
        if (null == appletRecord.getWechatUserId()) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "wechatUserId不能为空");
        }
        if (null == appletRecord.getFromId() || StringUtil.isEmpty(appletRecord.getFromName())) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "fromId或fromName为空");
        }
        if (AppletRecordTypeEnum.BOOK.value.equals(appletRecord.getRecordType()) && null !=  appletRecord.getFromId() &&
                (null == appletRecord.getChannelId() || null == appletRecord.getAdviserId())) {
            return;
        }

    }

    @Override
    @ParamLog("修改")
    public void update(AppletRecord appletRecord) {
        if (appletRecord == null || !NumberUtil.isNumber(appletRecord.getId())) {
            throw BizException.PARAM_IS_NULL;
        }
        appletRecordDao.update(appletRecord);
    }

    @Override
    @ParamLog("删除")
    public void deleteById(Long id) {
        appletRecordDao.deleteById(id);
    }

    @Override
    @ParamLog(value = "我的足迹", isAfterReturn = false)
    public PageBeanNew<AppletRecordDTO> listAppletRecord(Long wechatUserId, String date, List<Integer> recordTypes, String queryName,
                                                         Integer currentPage, Integer numPerPage, String typeName, Long officialAccountsId) {

        List<Long> wechatUserIds = readerConsr.getRelateUserIdList(wechatUserId, officialAccountsId);
        Map<String, Object> paramMap = new HashMap<>();
        if (!ListUtils.isEmpty(recordTypes) && !recordTypes.contains(AppletRecordTypeEnum.NEWS.value) && !recordTypes.contains(AppletRecordTypeEnum.PRODUCT.value)) {
            typeName = null;
        }
        paramMap.put("wechatUserIds", wechatUserIds);
        if (!ListUtils.isEmpty(recordTypes)) {
            paramMap.put("recordTypes", recordTypes);
        }
        if (!StringUtil.isEmpty(queryName)) {
            paramMap.put("queryName", queryName);
        }
        if (!StringUtil.isEmpty(typeName)) {
            paramMap.put("typeName", typeName);
        }
        List<AppletRecordDTO> recordList = null;
        PageBeanNew<AppletRecordDTO> listAppletRecord = new PageBeanNew<>();
        Integer bookType = null;
        if (StringUtil.isEmpty(date)) {
            //从总表中查
            listAppletRecord = appletRecordServeDao.listPageNew(new PageParam(currentPage, numPerPage), paramMap, "listAppletRecord");
            bookType = YesOrNoNumEnum.NO.getValue();
        } else {
            //从天表中查
            if (!StringUtil.isEmpty(date)) {
                paramMap.put("date", date);
            }
            listAppletRecord = appletRecordDayServeDao.listPageNew(new PageParam(currentPage, numPerPage), paramMap, "listAppletRecord");
            bookType = YesOrNoNumEnum.YES.getValue();

        }
        recordList = listAppletRecord.getRecordList();
        fillAppletRecord(recordList, bookType, wechatUserId);
        return listAppletRecord;
    }

    @Override
    public List<String> listUnreachableDate(Long wechatUserId) {
        //　获取过去30天所有日期集合
        List<DateTime> dateTimes = DateUtil.rangeToList(DateUtil.offsetDay(new Date(), -30), new Date(), DateField.DAY_OF_YEAR);
        List<Date> reachableDate = new ArrayList<>();
        if (Objects.nonNull(wechatUserId)) {
            reachableDate = appletRecordDao.listReachableDate(wechatUserId);
        }
        List<DateTime> collect = reachableDate.stream().filter(Objects::nonNull).map(DateUtil::beginOfDay).collect(Collectors.toList());
        // 筛选出没有埋点记录的日期
        return dateTimes.stream().filter(x -> !collect.contains(DateUtil.beginOfDay(x))).map(x -> DateUtil.format(x, DatePattern.NORM_DATE_FORMAT)).collect(Collectors.toList());
    }

    @Override
    public Map<Long, AppletAppOrProductDTO> getAppOrProductBrowseCount(Integer recordType, List<Long> serveIds) {
        Map<Long, AppletAppOrProductDTO> appletAppOrProductDTOMap = appletRecordDao.getAppOrProductBrowseCount(recordType, serveIds);
        return MapUtils.isEmpty(appletAppOrProductDTOMap) ? new HashMap<>() : appletAppOrProductDTOMap;
    }

    @Override
    @ParamLog("获取足迹目录")
    public List<AppletRecordDTO> getAppletRecordCatalogue(Long wechatUserId, String date, Long officialAccountsId) {
        List<Long> wechatUserIds = readerConsr.getRelateUserIdList(wechatUserId, officialAccountsId);
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("wechatUserIds", wechatUserIds);
        List<AppletRecordDTO> appletRecordDTOS = null;
        if (StringUtil.isEmpty(date)) {
            //从总表中查
            appletRecordDTOS = appletRecordServeDao.getAppletRecordCatalogue(paramMap);
         } else {
            //从天表中查
            paramMap.put("date", date);
            appletRecordDTOS = appletRecordDayServeDao.getAppletRecordCatalogue(paramMap);
        }
        Boolean isContinue = true;
        if (!ListUtils.isEmpty(appletRecordDTOS)) {
            Iterator<AppletRecordDTO> iterator = appletRecordDTOS.iterator();
            while (iterator.hasNext()) {
                AppletRecordDTO appletRecordDTO = iterator.next();
                if (Objects.equals(AppletRecordTypeEnum.ADVISER_GROUP.value, appletRecordDTO.getRecordType()) ||
                        Objects.equals(AppletRecordTypeEnum.MODEL_GROUP.value, appletRecordDTO.getRecordType()) ||
                        Objects.equals(AppletRecordTypeEnum.THIRD_GROUP.value, appletRecordDTO.getRecordType())) {
                    if (isContinue) {
                        appletRecordDTO.setTypeName(AppletRecordTypeEnum.ADVISER_GROUP.desc);
                        isContinue = false;
                    }else {
                        iterator.remove();
                    }
                } else if (Objects.equals(AppletRecordTypeEnum.BOOK.value, appletRecordDTO.getRecordType())) {
                    //填充书籍信息
                    appletRecordDTO.setTypeName(AppletRecordTypeEnum.BOOK.desc);
                } else if (Objects.equals(AppletRecordTypeEnum.BOOK_RECOMMEND.value, appletRecordDTO.getRecordType())) {
                    //填充书单推荐信息
                    appletRecordDTO.setTypeName(AppletRecordTypeEnum.BOOK_RECOMMEND.desc);
                } else if (Objects.equals(AppletRecordTypeEnum.BOOK_LIST.value, appletRecordDTO.getRecordType())) {
                    //填充精选书单信息
                    appletRecordDTO.setTypeName(AppletRecordTypeEnum.BOOK_LIST.desc);
                } else if (Objects.equals(AppletRecordTypeEnum.WX_WORK_TEACHER.value, appletRecordDTO.getRecordType())) {
                    // 填充企业微信客服
                    appletRecordDTO.setTypeName(AppletRecordTypeEnum.WX_WORK_TEACHER.desc);
                }
            }
        }
        return ListUtils.isEmpty(appletRecordDTOS) ? new ArrayList<>() : appletRecordDTOS;
    }

    @Override
    public void HandleTypeCode() {
        LOGGER.info("手动处理应用作品和资讯的typeCode");
        Map<String, Object> paramMap = new HashMap<>();
        List<AppletRecordDTO> recordList = null;
        PageBeanNew<AppletRecordDTO> listAppletRecord = new PageBeanNew<>();
        List<Integer> recordTypes = Lists.newArrayList(1, 5,6);
        paramMap.put("recordTypes", recordTypes);
         Integer currentPage = 0;
        Integer numPerPage = 100;
        Integer pageCount = 0;
        listAppletRecord = appletRecordServeDao.listPageNew(new PageParam(currentPage, numPerPage), paramMap, "listAppletRecord");
        pageCount = listAppletRecord.getPageCount();
        while (currentPage < pageCount) {
            listAppletRecord = appletRecordServeDao.listPageNew(new PageParam(currentPage, numPerPage), paramMap, "listAppletRecord");
            if (!ListUtils.isEmpty(listAppletRecord.getRecordList())) {
                HandleTypeCode4List(listAppletRecord.getRecordList());
            }
            LOGGER.info("处理服务表数据currentPage：{}", currentPage);
            ++currentPage;
        }
        listAppletRecord = appletRecordDayServeDao.listPageNew(new PageParam(currentPage, numPerPage), paramMap, "listAppletRecord");
        pageCount = listAppletRecord.getPageCount();
        currentPage = 0;
        while (currentPage < pageCount) {
            listAppletRecord = appletRecordDayServeDao.listPageNew(new PageParam(currentPage, numPerPage), paramMap, "listAppletRecord");
            if (!ListUtils.isEmpty(listAppletRecord.getRecordList())) {
                HandleTypeCode4ListDay(listAppletRecord.getRecordList());
            }
            LOGGER.info("处理服务天表数据currentPage：{}", currentPage);
            ++currentPage;
        }
    }

    @Override
    @ParamLog("新增用户阅读本书服务记录")
    public void addReadBookRecord(ReadBookRecordDTO readBookRecordDTO) {
        ThreadPoolUtils.BOOK_READ_RECORD.execute(() -> {
            Long bookId = readBookRecordDTO.getBookId();
            Long channelId = readBookRecordDTO.getChannelId();
            Long adviserId = readBookRecordDTO.getAdviserId();
            String redisKey4Random = "BOOK:READER_COUNT:" + bookId + ":" + channelId + ":" + adviserId;
            String redisKey4Set = "BOOK:READER_SET:" + bookId + ":" + channelId + ":" + adviserId;
            Integer readerCount = null;
            if (JedisClusterUtils.exists(redisKey4Random)) {
                JedisClusterUtils.expire(redisKey4Random, BookConstant.BOOK_CACHE_SECOUND);
            } else {
                List<Integer> readerCountList = READER_COUNT_MAP.get(DateUtil.hour(new Date(), Boolean.TRUE));
                readerCount = RandomUtil.randomInt(readerCountList.get(0), readerCountList.get(1));
                JedisClusterUtils.set(redisKey4Random, readerCount.toString(), BookConstant.BOOK_CACHE_SECOUND);
            }
            if ( Objects.equals(YesOrNoNumEnum.YES.getValue(), readBookRecordDTO.getRecordType())) {
                JedisClusterUtils.sadd(redisKey4Set, readBookRecordDTO.getWechatUserId().toString());
                JedisClusterUtils.expire(redisKey4Set, BookConstant.BOOK_CACHE_SECOUND);
            } else if (Objects.equals(YesOrNoNumEnum.NO.getValue(), readBookRecordDTO.getRecordType())) {
                JedisClusterUtils.srem(redisKey4Set, readBookRecordDTO.getWechatUserId().toString());
                JedisClusterUtils.expire(redisKey4Set, BookConstant.BOOK_CACHE_SECOUND);
            }
        });
    }

    @Override
    public void addFootstep(Long wechatUserId, Integer fromType, String typeName, List<Integer> recordTypes) {
        AppletFootstepRecord appletFootstepRecord = new AppletFootstepRecord();
        if (CollUtil.isEmpty(recordTypes)) {
            appletFootstepRecord.setRecordTypes(null);
        } else {
            appletFootstepRecord.setRecordTypes(recordTypes.stream().map(x ->
                    Optional.ofNullable(x).map(String::valueOf).orElse("")).filter(StrUtil::isNotBlank).collect(Collectors.joining(",")));
        }
        appletFootstepRecord.setTypeName(typeName);
        appletFootstepRecord.setWechatUserId(wechatUserId);
        appletFootstepRecord.setFromType(fromType);
        appletFootstepRecordMapper.insert(appletFootstepRecord);
    }

    @Override
    public void track(Long wechatUserId, Long officialAccountsId, AppletTrackDTO trackDTO) {
        AppletTrack track = new AppletTrack();
        track.setWechatUserId(wechatUserId);
        track.setOfficialAccountsId(officialAccountsId);
        track.setPage(trackDTO.getPage());
        track.setTrackType(trackDTO.getTrackType());
        track.setElementName(trackDTO.getElementName());
        track.setExtJson(trackDTO.getExtJson());
        track.setVersion(trackDTO.getVersion());
        track.setRemark(trackDTO.getRemark());
        appletTrackMapper.insert(track);
    }

    private void HandleTypeCode4ListDay(List<AppletRecordDTO> recordList) {
        fillTypeCode(recordList);
        appletRecordDayServeDao.batchUpdate(recordList);
    }



    private void HandleTypeCode4List(List<AppletRecordDTO> recordList) {
        fillTypeCode(recordList);
        appletRecordServeDao.batchUpdate(recordList);
    }

    private void fillTypeCode(List<AppletRecordDTO> recordList) {
        fillAppletRecord(recordList, YesOrNoNumEnum.YES.getValue(), null);
        recordList.stream().forEach(appletRecordDTO -> {
            if (Objects.equals(AppletRecordTypeEnum.NEWS.value, appletRecordDTO.getRecordType()) && null != appletRecordDTO.getAppletNewsDTO()) {
                //填充资讯信息
                appletRecordDTO.setTypeName(appletRecordDTO.getAppletNewsDTO().getSource());
            } else if (Objects.equals(AppletRecordTypeEnum.PRODUCT.value, appletRecordDTO.getRecordType()) && null != appletRecordDTO.getAppletAppOrProductDTO()) {
                //填充作品信息
                appletRecordDTO.setTypeCode(appletRecordDTO.getAppletAppOrProductDTO().getServeTypeCode());
                appletRecordDTO.setTypeName(appletRecordDTO.getAppletAppOrProductDTO().getServeTypeName());
            } else if (Objects.equals(AppletRecordTypeEnum.APP.value, appletRecordDTO.getRecordType())  && null != appletRecordDTO.getAppletAppOrProductDTO()) {
                //填充应用信息
                appletRecordDTO.setTypeCode(appletRecordDTO.getAppletAppOrProductDTO().getServeTypeCode());
                appletRecordDTO.setTypeName(appletRecordDTO.getAppletAppOrProductDTO().getServeTypeName());
            }
        });
    }

    @Override
    public  void fillAppletRecord(List<AppletRecordDTO> recordList, Integer bookType, Long wechatUserId) {
        if (ListUtils.isEmpty(recordList)) {
            return;
        }
        //根据不同的类型填充不同的数据
        List<Long> newsIds = recordList.stream().filter(appletRecordDTO -> AppletRecordTypeEnum.NEWS.value.equals(appletRecordDTO.getRecordType())).
                map(AppletRecordDTO::getFromId).distinct().collect(Collectors.toList());
        List<Long> bookGroupClassifyIds = recordList.stream().filter(appletRecordDTO -> AppletRecordTypeEnum.ADVISER_GROUP.value.equals(appletRecordDTO.getRecordType())).
                map(AppletRecordDTO::getFromId).distinct().collect(Collectors.toList());
        List<Long> activityGroupIds4Model = recordList.stream().filter(appletRecordDTO -> AppletRecordTypeEnum.MODEL_GROUP.value.equals(appletRecordDTO.getRecordType())).
                map(AppletRecordDTO::getFromId).distinct().collect(Collectors.toList());
        List<Long> activityGroupIds4Third = recordList.stream().filter(appletRecordDTO -> AppletRecordTypeEnum.THIRD_GROUP.value.equals(appletRecordDTO.getRecordType())).
                map(AppletRecordDTO::getFromId).distinct().collect(Collectors.toList());
        List<Long> productIds = recordList.stream().filter(appletRecordDTO -> AppletRecordTypeEnum.PRODUCT.value.equals(appletRecordDTO.getRecordType())).
                map(AppletRecordDTO::getFromId).distinct().collect(Collectors.toList());
        List<Long> appIds = recordList.stream().filter(appletRecordDTO -> AppletRecordTypeEnum.APP.value.equals(appletRecordDTO.getRecordType())).
                map(AppletRecordDTO::getFromId).distinct().collect(Collectors.toList());
        List<AppletRecordDTO> appletRecordDTOS4Book = recordList.stream().filter(appletRecordDTO -> AppletRecordTypeEnum.BOOK.value.equals(appletRecordDTO.getRecordType())).
                collect(Collectors.toList());
        List<Long> bookRecommendIds = recordList.stream().filter(appletRecordDTO -> AppletRecordTypeEnum.BOOK_RECOMMEND.value.equals(appletRecordDTO.getRecordType())).
                map(AppletRecordDTO::getFromId).distinct().collect(Collectors.toList());
        List<Long> bookListIds = recordList.stream().filter(appletRecordDTO -> AppletRecordTypeEnum.BOOK_LIST.value.equals(appletRecordDTO.getRecordType())).
                map(AppletRecordDTO::getFromId).distinct().collect(Collectors.toList());
        List<Long> wxWorkTeacherIds = recordList.stream().filter(appletRecordDTO -> AppletRecordTypeEnum.WX_WORK_TEACHER.value.equals(appletRecordDTO.getRecordType())).
                map(AppletRecordDTO::getFromId).distinct().collect(Collectors.toList());
        List<Long> bookIds = recordList.stream().filter(appletRecordDTO -> AppletRecordTypeEnum.PRODUCT.value.equals(appletRecordDTO.getRecordType()) || AppletRecordTypeEnum.APP.value.equals(appletRecordDTO.getRecordType()))
                .map(AppletRecordDTO::getBookId).filter(e -> null != e).distinct().collect(Collectors.toList());
        Map<Long, BookDto> bookDtoMap;
        CompletableFuture<Map<Long, BookDto>> bookDtoMapFuture = null;
        if (CollUtil.isNotEmpty(bookIds)) {
            bookDtoMapFuture = CompletableFuture.supplyAsync(() ->
                    Optional.ofNullable(bookDao.getMapByIds(bookIds)).orElse(new HashMap<>()), ThreadPoolUtils.FILL_APPLET_RECORD);
        }

        //资源map
        Map<Long, AppletNewsDTO> newsDtoMap = new HashMap<>();
        Future<Map<Long, AppletNewsDTO>> newsDtoMapFuture = null;
        Map<Long, GroupActivity4AppletDTO> groupDtoMap4BookGroupClassify = new HashMap<>();
        Future<Map<Long, GroupActivity4AppletDTO>> groupDtoMap4BookGroupClassifyFuture = null;
        Map<Long, GroupActivity4AppletDTO> groupDtoMap4ModelGroup = new HashMap<>();
        Future<Map<Long, GroupActivity4AppletDTO>> groupDtoMap4ModelGroupFuture = null;
        Map<Long, GroupActivity4AppletDTO> groupDtoMap4ThirdGroup = new HashMap<>();
        Future<Map<Long, GroupActivity4AppletDTO>> groupDtoMap4ThirdGroupFuture = null;
        Map<Long, ProductDto> productDtoMap = new HashMap<>();
        Future<Map<Long, ProductDto>> productDtoMapFuture = null;
        Map<Long, AppDto> appDtoMap = new HashMap<>();
        Future<Map<Long, AppDto>> appDtoMappFuture = null;
        Map<Long, AppletUserBookcaseDTO> appletUserBookcaseDTOMap = new HashMap<>();
        Future<Map<Long, AppletUserBookcaseDTO>> appletUserBookcaseDTOMapFuture = null;
        Map<Long, AppletOuterBooklistDTO> appletOuterBooklistDTOMap = new HashMap<>();
        Future<Map<Long, AppletOuterBooklistDTO>> appletOuterBooklistDTOMapFuture = null;
        Map<Long, AppletBooklistDTO> appletBooklistDTOMap = new HashMap<>();
        Future<Map<Long, AppletBooklistDTO>> appletBooklistDTOMapFuture = null;
        Future<Map<Long, WxWorkTeacherDTO>> wxWorkTeacherDTOHashMapFuture = null;

        if (!ListUtils.isEmpty(newsIds)) {
            newsDtoMapFuture = ThreadPoolUtils.FILL_APPLET_RECORD.submit(() -> appletNewsBiz.getByIds4Record(newsIds));
        }
        if (!ListUtils.isEmpty(bookGroupClassifyIds)) {
            groupDtoMap4BookGroupClassifyFuture = ThreadPoolUtils.FILL_APPLET_RECORD.submit(() -> pcloudGroupActivityBiz.getByIds4NowRecord(bookGroupClassifyIds, AppletRecordTypeEnum.ADVISER_GROUP.value));
        }
        if (!ListUtils.isEmpty(activityGroupIds4Model)) {
            groupDtoMap4ModelGroupFuture = ThreadPoolUtils.FILL_APPLET_RECORD.submit(() -> pcloudGroupActivityBiz.getByIds4NowRecord(activityGroupIds4Model, AppletRecordTypeEnum.MODEL_GROUP.value));
        }
        if (!ListUtils.isEmpty(activityGroupIds4Third)) {
            groupDtoMap4ThirdGroupFuture = ThreadPoolUtils.FILL_APPLET_RECORD.submit(() -> pcloudGroupActivityBiz.getByIds4NowRecord(activityGroupIds4Third, AppletRecordTypeEnum.THIRD_GROUP.value));
        }
        if (!ListUtils.isEmpty(productIds)) {
            productDtoMapFuture = ThreadPoolUtils.FILL_APPLET_RECORD.submit(() -> productConsr.getProBasesByIds(productIds));
        }
        if (!ListUtils.isEmpty(appIds)) {
            appDtoMappFuture = ThreadPoolUtils.FILL_APPLET_RECORD.submit(() -> appConsr.mapByIds4AuditPass(appIds));
        }
        if (!ListUtils.isEmpty(appletRecordDTOS4Book) && YesOrNoNumEnum.NO.getValue().equals(bookType)) {
            appletUserBookcaseDTOMapFuture = ThreadPoolUtils.FILL_APPLET_RECORD.submit(() -> appletRecordServeDao.getBookMap(appletRecordDTOS4Book));
        } else if (!ListUtils.isEmpty(appletRecordDTOS4Book) && YesOrNoNumEnum.YES.getValue().equals(bookType)){
            appletUserBookcaseDTOMapFuture = ThreadPoolUtils.FILL_APPLET_RECORD.submit(() -> appletRecordDayServeDao.getBookMap(appletRecordDTOS4Book));
        }
        if (!ListUtils.isEmpty(bookRecommendIds)) {
            appletOuterBooklistDTOMapFuture = ThreadPoolUtils.FILL_APPLET_RECORD.submit(() -> appletBooklistBiz.getByIds(bookRecommendIds));
        }
        if (!ListUtils.isEmpty(bookListIds)) {
            appletBooklistDTOMapFuture = ThreadPoolUtils.FILL_APPLET_RECORD.submit(() -> appletBooklistBiz.getBookListMap(bookListIds));
        }
        if (!ListUtils.isEmpty(wxWorkTeacherIds)) {
            wxWorkTeacherDTOHashMapFuture = ThreadPoolUtils.FILL_APPLET_RECORD.submit(() -> weworkTeacherBiz.getWxWorkTeacherByIds(wxWorkTeacherIds));
        }

        // 应用作品类型的答案补充书名和封面
        bookDtoMap = Optional.ofNullable(bookDtoMapFuture).map(future -> {
            Map<Long, BookDto> map = null;
            try {
                map = future.get();
            } catch (InterruptedException | ExecutionException e) {
                LOGGER.warn("[AppletRecordBizImpl.fillAppletRecord] 异步获取图书信息失败", e);
            }
            return map;
        }).orElse(new HashMap<>());

        //存储已经删除群的群分类; 精选文章类型并且跳转链接包含qrcode.5rs.me
        Iterator<AppletRecordDTO> iterator = recordList.iterator();
        while (iterator.hasNext()) {
            AppletRecordDTO appletRecordDTO = iterator.next();
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.NO.getValue());
            if (Objects.equals(AppletRecordTypeEnum.NEWS.value, appletRecordDTO.getRecordType()) && null != newsDtoMap) {
                //填充资讯信息
                filllAppletNews4Record(newsDtoMap, newsDtoMapFuture, appletRecordDTO);
            } else if (Objects.equals(AppletRecordTypeEnum.ADVISER_GROUP.value, appletRecordDTO.getRecordType())) {
                //填充编辑群信息
                fillGroup4Record(groupDtoMap4BookGroupClassify, groupDtoMap4BookGroupClassifyFuture, appletRecordDTO);
            } else if (Objects.equals(AppletRecordTypeEnum.MODEL_GROUP.value, appletRecordDTO.getRecordType())) {
                //填充模板群信息
                fillGroup4Record(groupDtoMap4ModelGroup, groupDtoMap4ModelGroupFuture, appletRecordDTO);
            } else if (Objects.equals(AppletRecordTypeEnum.THIRD_GROUP.value, appletRecordDTO.getRecordType())) {
                //填充第三方群信息
                fillGroup4Record(groupDtoMap4ThirdGroup, groupDtoMap4ThirdGroupFuture, appletRecordDTO);
            } else if (Objects.equals(AppletRecordTypeEnum.PRODUCT.value, appletRecordDTO.getRecordType())) {
                if ("ANSWER".equals(appletRecordDTO.getTypeCode())) {
                    appletRecordDTO.setBookName(Optional.ofNullable(bookDtoMap.get(appletRecordDTO.getBookId())).map(BookDto::getBookName).orElse(""));
                    appletRecordDTO.setCoverImg(Optional.ofNullable(bookDtoMap.get(appletRecordDTO.getBookId())).map(BookDto::getCoverImg).orElse(""));
                }
                //填充作品信息
                fillProduct4Record(productDtoMap, productDtoMapFuture, appletRecordDTO, wechatUserId);
            } else if (Objects.equals(AppletRecordTypeEnum.APP.value, appletRecordDTO.getRecordType())) {
                if ("ANSWER".equals(appletRecordDTO.getTypeCode())) {
                    appletRecordDTO.setBookName(Optional.ofNullable(bookDtoMap.get(appletRecordDTO.getBookId())).map(BookDto::getBookName).orElse(""));
                    appletRecordDTO.setCoverImg(Optional.ofNullable(bookDtoMap.get(appletRecordDTO.getBookId())).map(BookDto::getCoverImg).orElse(""));
                }
                //填充应用信息
                fillApp4Record(appDtoMap, appDtoMappFuture, appletRecordDTO, wechatUserId);
            } else if (Objects.equals(AppletRecordTypeEnum.BOOK.value, appletRecordDTO.getRecordType())) {
                //填充书籍信息
                fillBook4Record(appletUserBookcaseDTOMap, appletUserBookcaseDTOMapFuture, appletRecordDTO);
            } else if (Objects.equals(AppletRecordTypeEnum.BOOK_RECOMMEND.value, appletRecordDTO.getRecordType())) {
                //填充书单推荐信息
                fillAppletOuterBooklist4Record(appletOuterBooklistDTOMap, appletRecordDTO, appletOuterBooklistDTOMapFuture);
            } else if (Objects.equals(AppletRecordTypeEnum.BOOK_LIST.value, appletRecordDTO.getRecordType())) {
                //填充精选书单信息
                fillAppletBooklist4Record(appletBooklistDTOMap, appletBooklistDTOMapFuture, appletRecordDTO);
            } else if (Objects.equals(AppletRecordTypeEnum.WX_WORK_TEACHER.value, appletRecordDTO.getRecordType())) {
                // 填充企业微信客服
                fillWxWorkTeacher4Record(wxWorkTeacherDTOHashMapFuture, appletRecordDTO);
            }
        }
    }

    private void fillWxWorkTeacher4Record(Future<Map<Long, WxWorkTeacherDTO>> wxWorkTeacherDTOHashMapFuture, AppletRecordDTO appletRecordDTO) {
        Map<Long, WxWorkTeacherDTO> wxWorkTeacherDTOHashMap = null;
        try {
            wxWorkTeacherDTOHashMap = wxWorkTeacherDTOHashMapFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            LOGGER.error("获取企业微信客服错误: {}==", e);
        }
        if (MapUtil.isEmpty(wxWorkTeacherDTOHashMap)) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        WxWorkTeacherDTO wxWorkTeacherDTO = wxWorkTeacherDTOHashMap.get(appletRecordDTO.getFromId());
        if (null == wxWorkTeacherDTO) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        appletRecordDTO.setFromName(wxWorkTeacherDTO.getNickname());
        appletRecordDTO.setWxWorkTeacherDTO(wxWorkTeacherDTO);
    }

    private void fillAppletBooklist4Record(Map<Long, AppletBooklistDTO> appletBooklistDTOMap, Future<Map<Long, AppletBooklistDTO>> appletBooklistDTOMapFuture, AppletRecordDTO appletRecordDTO) {
        try {
            appletBooklistDTOMap = appletBooklistDTOMapFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            LOGGER.error("获取精选书单错误: {}==", e);
        }
        if (MapUtil.isEmpty(appletBooklistDTOMap)) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        AppletBooklistDTO appletBooklistDTO = appletBooklistDTOMap.get(appletRecordDTO.getFromId());
        if (null == appletBooklistDTO) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        List<BookDTO4Booklist> bookList = appletBooklistDao.getBookBaseByBooklistId(appletBooklistDTO.getId(), 0, 3);
        appletBooklistDTO.setBookDTO4Booklists(ListUtils.isEmpty(bookList) ? new ArrayList<>() : bookList);
        appletRecordDTO.setAppletBooklistDTO(appletBooklistDTO);
    }

    private void fillAppletOuterBooklist4Record(Map<Long, AppletOuterBooklistDTO> appletOuterBooklistDTOMap, AppletRecordDTO appletRecordDTO, Future<Map<Long, AppletOuterBooklistDTO>> appletOuterBooklistDTOMapFuture) {
        try {
            appletOuterBooklistDTOMap = appletOuterBooklistDTOMapFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            LOGGER.error("获取书单推荐错误: {}==", e);
        }
        if (MapUtil.isEmpty(appletOuterBooklistDTOMap)) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        AppletOuterBooklistDTO outerBooklistDTO = appletOuterBooklistDTOMap.get(appletRecordDTO.getFromId());
        if (null == outerBooklistDTO) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        appletRecordDTO.setAppletOuterBooklistDTO(outerBooklistDTO);
    }

    private void fillBook4Record(Map<Long, AppletUserBookcaseDTO> appletUserBookcaseDTOMap, Future<Map<Long, AppletUserBookcaseDTO>> appletUserBookcaseDTOMapFuture, AppletRecordDTO appletRecordDTO) {
        try {
            appletUserBookcaseDTOMap = appletUserBookcaseDTOMapFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            LOGGER.error("获取书籍错误: {}==", e);
        }
        if (MapUtil.isEmpty(appletUserBookcaseDTOMap)) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        AppletUserBookcaseDTO appletUserBookcaseDTO = appletUserBookcaseDTOMap.get(appletRecordDTO.getId());
        if (null == appletUserBookcaseDTO) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        appletRecordDTO.setAppletUserBookcaseDTO(appletUserBookcaseDTO);
    }

    private void fillGroup4Record(Map<Long, GroupActivity4AppletDTO> groupDtoMap4BookGroupClassify, Future<Map<Long, GroupActivity4AppletDTO>> groupDtoMap4BookGroupClassifyFuture, AppletRecordDTO appletRecordDTO) {
        //填充群信息
        try {
            groupDtoMap4BookGroupClassify = groupDtoMap4BookGroupClassifyFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            LOGGER.error("获取群错误: {}==", e);
        }
        if (MapUtil.isEmpty(groupDtoMap4BookGroupClassify)) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        GroupActivity4AppletDTO groupActivity4AppletDTO = groupDtoMap4BookGroupClassify.get(appletRecordDTO.getFromId());
        if (null == groupActivity4AppletDTO) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        appletRecordDTO.setAppletGroupDTO(groupActivity4AppletDTO);
    }

    private void filllAppletNews4Record(Map<Long, AppletNewsDTO> newsDtoMap, Future<Map<Long, AppletNewsDTO>> newsDtoMapFuture, AppletRecordDTO appletRecordDTO) {
        //填充资讯信息
        try {
            newsDtoMap = newsDtoMapFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            LOGGER.error("获取资讯错误: {}==", e);
        }
        if (MapUtil.isEmpty(newsDtoMap)) {
            appletRecordDao.updateDeleteState(appletRecordDTO.getFromId(), appletRecordDTO.getRecordType());
            return;
        }
        AppletNewsDTO appletNewsDTO = newsDtoMap.get(appletRecordDTO.getFromId());
        if (null == appletNewsDTO || Objects.equals(YesOrNoNumEnum.YES.getValue(), appletNewsDTO.getIsDelete())) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        appletNewsDTO.setNewsType(appletNewsDTO.getType());
        appletNewsDTO.setNewsName(appletRecordDTO.getFromName());
        appletRecordDTO.setAppletNewsDTO(appletNewsDTO);
        appletRecordDTO.setShowState(appletNewsDTO.getShowState() ? YesOrNoNumEnum.YES.getValue() : YesOrNoNumEnum.NO.getValue());
        appletRecordDTO.setIsDelete(appletNewsDTO.getIsDelete());
    }

    private void fillApp4Record(Map<Long, AppDto> appDtoMap, Future<Map<Long, AppDto>> appDtoMappFuture, AppletRecordDTO appletRecordDTO, Long wechatUserId) {
        try {
            appDtoMap = appDtoMappFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            LOGGER.error("获取app错误: {}==", e);
        }
        if (MapUtil.isEmpty(appDtoMap)) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        AccountSettingDto accountSettingDto;
        AppDto appDto = appDtoMap.get(appletRecordDTO.getFromId());
        AppletAppOrProductDTO appletAppOrProductDTO = new AppletAppOrProductDTO();
        if (appDto == null || appDto.getIsDelete()) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        if (!StringUtil.isEmpty(appletRecordDTO.getLinkUrl()) && appletRecordDTO.getLinkUrl().contains("qrcode.5rs.me") && "ARTICLE".equals(appDto.getTypeCode())) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        appletAppOrProductDTO.setServeName(appDto.getTitle());
        appletAppOrProductDTO.setServePic(appDto.getSquareImg());
        appletAppOrProductDTO.setServeTypeCode(appDto.getTypeCode());
        appletAppOrProductDTO.setServeTypeName(appDto.getTypeName());
        appletRecordDTO.setPurLabelId(appDto.getPurLabelId());
        appletRecordDTO.setProLabelId(appDto.getProLabelId());
        appletRecordDTO.setDepLabelId(appDto.getDepLabelId());
        accountSettingDto = qrcodeSceneConsr.getWechatInfo(appDto.getChannelId());
        if (null == accountSettingDto) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        String resultLinkUrl = SendWeixinRequestTools.splitUrl(accountSettingDto, appletRecordDTO.getLinkUrl());
        appletAppOrProductDTO.setResultUrl(resultLinkUrl);
        if (!StringUtil.isEmpty(appDto.getTurnUrl())){
            appletAppOrProductDTO.setHasThirdLink(true);
        } else {
            appletAppOrProductDTO.setHasThirdLink(false);
        }
        appletAppOrProductDTO.setServeType(AppAndProductTypeEnum.APP.value);
        appletAppOrProductDTO.setServeId(appletRecordDTO.getFromId());
        //优化跳转
        try {
            if (LinkServeConstant.APPLINK.contains(appletAppOrProductDTO.getServeTypeCode())) {
                if (appDto != null && !StringUtil.isEmpty(appDto.getTurnUrl())) {
                    if (appDto.getTurnUrl().contains("5rs.me/") || appDto.getTurnUrl().contains("raysgo.com/") || appDto.getTurnUrl().contains("raysyun.com/")
                            || null == wechatUserId) {
                        appletAppOrProductDTO.setResultUrl(appDto.getTurnUrl());
                    } else {
                        Long sceneId = CommonUtils.getSceneId(appletAppOrProductDTO.getResultUrl());
                        if (null != sceneId) {
                            // 判断版权保护
                            Map<String, Boolean> bookAuthMap = bookAuthServeBiz.listIsOpen4ServeIdsAndQrcode(sceneId, Lists.newArrayList(appDto.getAppId()));
                            if (CollUtil.isEmpty(bookAuthMap) || null == bookAuthMap.get(MessageFromTypeEnum.APP.value + appDto.getAppId()) || false == bookAuthMap.get(MessageFromTypeEnum.APP.value + appDto.getAppId())) {
                                //外链跳转到指定中间页
                                String jumpUrl =  BookProps.getProductDomain() + "transfer?offId=" + accountSettingDto.getAccountSettingId() + "&appId=" + appDto.getAppId() + "&url=" +
                                        URLEncoder.encode(appDto.getTurnUrl()) + "&sceneId=" + sceneId + "&wechatUserId=" + wechatUserId;
                                appletAppOrProductDTO.setResultUrl(jumpUrl);
                            }
                        }
                    }
                }

            }
        } catch (Exception e) {
           LOGGER.error("填充外链失败：{}",e.getMessage());
        }
        appletRecordDTO.setAppletAppOrProductDTO(appletAppOrProductDTO);
    }

    private void fillProduct4Record(Map<Long, ProductDto> productDtoMap, Future<Map<Long, ProductDto>> productDtoMapFuture, AppletRecordDTO appletRecordDTO, Long wechatUserId) {
        try {
            productDtoMap = productDtoMapFuture.get();
        } catch (InterruptedException | ExecutionException e) {
            LOGGER.error("获取product错误: {}==", e);
        }
        if (MapUtil.isEmpty(productDtoMap)) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        AccountSettingDto accountSettingDto = null;
        ProductDto productDto = productDtoMap.get(appletRecordDTO.getFromId());
        AppletAppOrProductDTO appletAppOrProductDTO = new AppletAppOrProductDTO();
        if (productDto == null || YesOrNoNumEnum.YES.getValue().equals(productDto.getIsDelete())) {
            appletRecordDTO.setSourceDelete(YesOrNoNumEnum.YES.getValue());
            return;
        }
        appletAppOrProductDTO.setServeName(productDto.getProductName());
        appletAppOrProductDTO.setServePic(productDto.getCoverImg());
        if (productDto.getProductTypeDto() != null) {
            appletAppOrProductDTO.setServeTypeCode(productDto.getProductTypeDto().getTypeCode());
            appletAppOrProductDTO.setServeTypeName(productDto.getProductTypeDto().getTypeName());
        }
        if (!ListUtils.isEmpty(productDto.getProductLabels())) {
            ProductLabelDto labelDto = productDto.getProductLabels().get(0);
            appletRecordDTO.setProLabelId(labelDto.getProLabelId());
            appletRecordDTO.setPurLabelId(labelDto.getPurLabelId());
            appletRecordDTO.setDepLabelId(labelDto.getDepLabelId());
        }
        //获取channelId,/C1404/product/display/10234028?adviserId=1001587&proType=MEMBER&source_type=QRCODE
        Long channelId = null;
        String url = appletRecordDTO.getLinkUrl();
        if (!StringUtil.isEmpty(url) && url.contains("/C") && !url.startsWith("https")) {
            url = url.substring(url.indexOf("/C") + 2);
            url = url.substring(0, url.indexOf("/"));
            if (!StringUtil.isEmpty(url)) {
                channelId = Long.valueOf(url);
            }
        }
        if (null != channelId) {
            accountSettingDto = qrcodeSceneConsr.getWechatInfo(channelId);
            if (null != accountSettingDto) {
                String resultLinkUrl = SendWeixinRequestTools.splitUrl(accountSettingDto, productDto.getTurnUrl());
                appletAppOrProductDTO.setResultUrl(resultLinkUrl);
            }
        } else {
            appletAppOrProductDTO.setResultUrl(appletRecordDTO.getLinkUrl());
        }
        if (!StringUtil.isEmpty(productDto.getSkipUrl())){
            appletAppOrProductDTO.setHasThirdLink(true);
        } else {
            appletAppOrProductDTO.setHasThirdLink(false);
        }
        appletAppOrProductDTO.setServeType(AppAndProductTypeEnum.PRODUCT.value);
        appletAppOrProductDTO.setServeId(appletRecordDTO.getFromId());
        //优化跳转
        try {
            if (LinkServeConstant.PRODUCTLINK.contains(appletAppOrProductDTO.getServeTypeCode())) {
                if (productDto != null && !StringUtil.isEmpty(productDto.getSkipUrl()) && null != accountSettingDto) {
                    Double adviserPrice = CollUtil.isNotEmpty(productDto.getSpecification()) ? productDto.getSpecification().get(0).getAdvisePrice(): 0D;
                    //原存在逻辑不处理
                    if (productDto.getSkipUrl().contains("5rs.me/") || productDto.getSkipUrl().contains("raysgo.com/") || productDto.getSkipUrl().contains("raysyun.com/")) {
                        appletAppOrProductDTO.setResultUrl(productDto.getSkipUrl());
                    } else if (null != wechatUserId && adviserPrice.equals(0D)){
                        Long sceneId = CommonUtils.getSceneId(appletAppOrProductDTO.getResultUrl());
                        if (null != sceneId) {
                            // 判断版权保护
                            Map<String, Boolean> bookAuthMap = bookAuthServeBiz.listIsOpen4ServeIdsAndQrcode(sceneId, Lists.newArrayList(productDto.getProductId()));
                            if (CollUtil.isEmpty(bookAuthMap) || null == bookAuthMap.get(MessageFromTypeEnum.PRODUCT.value + productDto.getProductId()) || false == bookAuthMap.get(MessageFromTypeEnum.PRODUCT.value + productDto.getProductId())) {
                                //外链跳转到指定中间页
                                String jumpUrl =  BookProps.getProductDomain() + "transfer?offId=" + accountSettingDto.getAccountSettingId() +  "&url=" +
                                        URLEncoder.encode(productDto.getSkipUrl()) + "&sceneId=" + sceneId + "&wechatUserId=" + wechatUserId +  "&productId=" + productDto.getProductId() ;
                                appletAppOrProductDTO.setResultUrl(jumpUrl);
                            }

                        }

                    }
                }

            }
        } catch (Exception e) {
           LOGGER.error("填充外链失败：{}", e.getMessage());
        }
        appletRecordDTO.setAppletAppOrProductDTO(appletAppOrProductDTO);
    }

    @Override
    public Object handleAppletRecordTypeCode(Long lastAppletRecordId){
        LOGGER.info("手动处理应用作品和资讯的typeCode");
        if(lastAppletRecordId == null){
            lastAppletRecordId = 0L;
        }
        String runStatus = "running";
        String lock = JedisClusterUtils.get(HANDLE_APPLET_RECORD_TYPE_CODE_KEY);
        if(!StringUtil.isEmpty(lock)){
            throw new BizException(BizException.DB_DML_FAIL.getCode(), "请不要重复执行");
        }
        JedisClusterUtils.set(HANDLE_APPLET_RECORD_TYPE_CODE_KEY, "lock", 3600);
        // 解除停止状态
        JedisClusterUtils.set(HANDLE_APPLET_RECORD_TYPE_CODE_STATUS_KEY, "running", 3600);
        Map<String, Object> paramMap;
        try {
            while ("running".equalsIgnoreCase(runStatus)) {
                paramMap = MapUtil.<String, Object>builder()
                        .put("recordTypes", Lists.newArrayList(5, 6))
                        .put("offset", 0)
                        .put("limit", 100)
                        .put("lastAppletRecordId", lastAppletRecordId)
                        .build();
                // 每次处理100条数据
                List<AppletRecordDTO> recordList = appletRecordDao.getHandleAppletRecordTypeCode(paramMap);
                if (CollectionUtil.isNotEmpty(recordList)) {
                    fillTypeCode4List(recordList);
                    appletRecordDao.batchUpdateTypeCode(recordList);
                    lastAppletRecordId = recordList.get(recordList.size()-1).getId();
                } else {
                    runStatus = "complete";
                    break;
                }
                Thread.sleep(1);
                runStatus = JedisClusterUtils.get(HANDLE_APPLET_RECORD_TYPE_CODE_STATUS_KEY);
            }
            return MapUtil.<String, Object>builder()
                    .put("runStatus", runStatus)
                    .put("lastAppletRecordId", lastAppletRecordId)
                    .put("msg", "stop".equalsIgnoreCase(runStatus) ? "执行被终止" : "执行完成")
                    .build();
        } catch (Exception e){
            LOGGER.info("handleAppletRecordTypeCode 执行出现异常，lastAppletRecordId：" + lastAppletRecordId.toString(), e);
            return MapUtil.<String, Object>builder()
                    .put("runStatus", runStatus)
                    .put("lastAppletRecordId", lastAppletRecordId)
                    .put("msg", "执行出现异常")
                    .build();
        } finally {
            // 移除执行锁
            JedisClusterUtils.del(HANDLE_APPLET_RECORD_TYPE_CODE_KEY);
        }
    }

    private void fillTypeCode4List(List<AppletRecordDTO> recordList) {
        fillAppletRecord(recordList, YesOrNoNumEnum.YES.getValue(), null);
        recordList.stream().forEach(appletRecordDTO -> {
            if (Objects.equals(AppletRecordTypeEnum.PRODUCT.value, appletRecordDTO.getRecordType()) && null != appletRecordDTO.getAppletAppOrProductDTO()) {
                // 填充作品信息
                appletRecordDTO.setTypeCode(appletRecordDTO.getAppletAppOrProductDTO().getServeTypeCode());
            } else if (Objects.equals(AppletRecordTypeEnum.APP.value, appletRecordDTO.getRecordType())  && null != appletRecordDTO.getAppletAppOrProductDTO()) {
                // 填充应用信息
                appletRecordDTO.setTypeCode(appletRecordDTO.getAppletAppOrProductDTO().getServeTypeCode());
            }
        });
    }

    @Override
    public void stopHandleAppletRecordTypeCode() {
        JedisClusterUtils.set(HANDLE_APPLET_RECORD_TYPE_CODE_STATUS_KEY, "stop", 3600);
    }

    @Override
    public AppletRecordDTO getLatestAppletRecord(Long wechatUserId, Long officialAccountsId) {
        List<Long> wechatUserIds = readerConsr.getRelateUserIdList(wechatUserId, officialAccountsId);
        Map<String, Object> paramMap = new HashMap<>();
        List<Integer> recordTypes = Arrays.asList(AppletRecordTypeEnum.APP.value,AppletRecordTypeEnum.PRODUCT.value,AppletRecordTypeEnum.BOOK.value);
        paramMap.put("wechatUserIds", wechatUserIds);
        paramMap.put("recordTypes", recordTypes);
        paramMap.put("limit", 10);
        List<AppletRecordDTO> recordList = appletRecordServeDao.listAppletRecordLimit(paramMap);
        if (ListUtils.isEmpty(recordList)) {
            return new AppletRecordDTO();
        }
        fillAppletRecord(recordList, YesOrNoNumEnum.NO.getValue(), wechatUserId);
        recordList = recordList.stream().filter(x -> x.getSourceDelete() == 0).collect(Collectors.toList());
        if (ListUtils.isEmpty(recordList)) {
            return new AppletRecordDTO();
        }
        return recordList.get(0);

    }
}
