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

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.pcloud.analysisengine.browse.dto.BookBrowseAndScanStatsDTO;
import com.pcloud.analysisengine.browse.dto.BrowseCacheRecordDto;
import com.pcloud.appcenter.app.dto.AppDto;
import com.pcloud.book.base.dto.CountDto;
import com.pcloud.book.base.exception.BookBizException;
import com.pcloud.book.book.biz.BookAdviserBiz;
import com.pcloud.book.book.biz.BookBiz;
import com.pcloud.book.book.biz.BookFundBiz;
import com.pcloud.book.book.biz.BookLabelBiz;
import com.pcloud.book.book.biz.BookQrcodeWxworkBiz;
import com.pcloud.book.book.constant.BookConstant;
import com.pcloud.book.book.dao.BookAdviserDao;
import com.pcloud.book.book.dto.AdviserBookInfoDTO;
import com.pcloud.book.book.dto.AdviserManageDto;
import com.pcloud.book.book.dto.AviserBookInfoParam;
import com.pcloud.book.book.dto.BookAdviserDto;
import com.pcloud.book.book.dto.BookCountAndAdviserIdDTO;
import com.pcloud.book.book.dto.BookCountByAdvisersDto;
import com.pcloud.book.book.dto.BookCountDto;
import com.pcloud.book.book.dto.BookDataStatisticsDTO;
import com.pcloud.book.book.dto.BookDto;
import com.pcloud.book.book.dto.BookQrcodeStatisticsDTO;
import com.pcloud.book.book.dto.BookRequestVO;
import com.pcloud.book.book.dto.BookResourceStatisticsDTO;
import com.pcloud.book.book.dto.BookRightsSettingDTO;
import com.pcloud.book.book.dto.BookStatisticsResultDto;
import com.pcloud.book.book.dto.BookVarietyStatsDto;
import com.pcloud.book.book.dto.BookVarietyStatsRequestDto;
import com.pcloud.book.book.dto.ERPPublishNumDTO;
import com.pcloud.book.book.dto.ErpBookInfoDTO;
import com.pcloud.book.book.dto.QrcodeStatisticsDTO;
import com.pcloud.book.book.entity.Book;
import com.pcloud.book.book.entity.BookAdviser;
import com.pcloud.book.book.enums.BookQrcodeType;
import com.pcloud.book.book.set.BookSet;
import com.pcloud.book.book.vo.AgentBookStatsDetailVO;
import com.pcloud.book.book.vo.BookServeInfo;
import com.pcloud.book.book.vo.BookServesListDTO;
import com.pcloud.book.book.vo.ErpAdviserBookVO;
import com.pcloud.book.book.vo.PcloudAdviserBookVO;
import com.pcloud.book.book.vo.QrCodeVO;
import com.pcloud.book.book.vo.QrcodeInfoDto;
import com.pcloud.book.book.vo.request.RelateRaysBookApprovalVO;
import com.pcloud.book.book.vo.request.UpdateBookRobotProcessDto;
import com.pcloud.book.consumer.analysisengine.BrowseRecordConsr;
import com.pcloud.book.consumer.app.AppConsr;
import com.pcloud.book.consumer.channel.QrcodeSceneConsr;
import com.pcloud.book.consumer.common.ExportConsr;
import com.pcloud.book.consumer.erp.ErpConsr;
import com.pcloud.book.consumer.label.LabelConsr;
import com.pcloud.book.consumer.message.MessageConsr;
import com.pcloud.book.consumer.message.TemplateConsr;
import com.pcloud.book.consumer.raystask.MainLineConsr;
import com.pcloud.book.consumer.resource.ProductConsr;
import com.pcloud.book.consumer.settlement.BookConsr;
import com.pcloud.book.consumer.trade.TradeConsr;
import com.pcloud.book.consumer.user.AdviserConsr;
import com.pcloud.book.consumer.user.AgentConsr;
import com.pcloud.book.consumer.user.BookcaseConsr;
import com.pcloud.book.consumer.user.ChannelConsr;
import com.pcloud.book.consumer.wechatgroup.WechatGroupConsr;
import com.pcloud.book.es.biz.ESBookAndAdviserBiz;
import com.pcloud.book.group.biz.BookGroupBiz;
import com.pcloud.book.group.biz.ResourcePageBiz;
import com.pcloud.book.group.dao.BookAppletSceneDao;
import com.pcloud.book.group.dao.BookGroupDao;
import com.pcloud.book.group.dao.BookGroupServeDao;
import com.pcloud.book.group.dao.ResourcePageItemDao;
import com.pcloud.book.group.dto.BookAppletSceneDTO;
import com.pcloud.book.group.dto.BookGroupDTO;
import com.pcloud.book.group.dto.BookGroupServeCountDTO;
import com.pcloud.book.group.dto.BookServeDTO;
import com.pcloud.book.group.dto.BookServeLabelDTO;
import com.pcloud.book.group.entity.BookGroupServe;
import com.pcloud.book.group.enums.AppAndProductTypeEnum;
import com.pcloud.book.group.enums.JoinGroupTypeEnum;
import com.pcloud.book.mq.producer.UpdateSuperSearchProducer;
import com.pcloud.book.rightsSetting.biz.RightsSettingBiz;
import com.pcloud.book.rightsSetting.constants.RightsSettingConstant;
import com.pcloud.book.rightsSetting.dao.RightsSettingDAO;
import com.pcloud.book.rightsSetting.dto.BookRightsCountsDto;
import com.pcloud.book.rightsSetting.dto.RightsSettingDto;
import com.pcloud.book.rightsSetting.dto.RightsSettingQueryDTO;
import com.pcloud.book.rightsSetting.entity.RightsSetting;
import com.pcloud.book.rightsSetting.entity.RightsSettingNow;
import com.pcloud.book.rightsSetting.entity.RightsSettingTitle;
import com.pcloud.book.util.common.ThreadPoolUtils;
import com.pcloud.book.util.common.YesOrNoEnums;
import com.pcloud.channelcenter.base.constants.MessageFromTypeEnum;
import com.pcloud.channelcenter.base.exceptions.ChannelBizException;
import com.pcloud.channelcenter.qrcode.dto.AdviserQrcodeSceneDTO;
import com.pcloud.channelcenter.qrcode.dto.QrcodeLocationDto;
import com.pcloud.channelcenter.qrcode.dto.QrcodeMessageDTO;
import com.pcloud.channelcenter.qrcode.dto.QrcodeSceneDto;
import com.pcloud.channelcenter.qrcode.vo.BookQrcodeVO;
import com.pcloud.channelcenter.wechat.dto.AccountSettingDto;
import com.pcloud.channelcenter.wechat.dto.MessageDto;
import com.pcloud.common.constant.CacheConstant;
import com.pcloud.common.core.aspect.ParamLog;
import com.pcloud.common.core.constant.ProductTypeConstant;
import com.pcloud.common.core.constant.SceneCode;
import com.pcloud.common.core.constant.SendType;
import com.pcloud.common.core.constant.SystemCode;
import com.pcloud.common.enums.AppTypeEnum;
import com.pcloud.common.exceptions.BizException;
import com.pcloud.common.page.PageBeanNew;
import com.pcloud.common.page.PageParam;
import com.pcloud.common.utils.DateUtils;
import com.pcloud.common.utils.ListUtils;
import com.pcloud.common.utils.NumberUtil;
import com.pcloud.common.utils.ServeLinkUtils;
import com.pcloud.common.utils.cache.redis.JedisClusterUtils;
import com.pcloud.common.utils.string.StringUtil;
import com.pcloud.facade.tradecenter.dto.Amount4BookAdviserDto;
import com.pcloud.raystask.entity.AdviserDefault;
import com.pcloud.readercenter.common.enums.YesOrNoNumEnum;
import com.pcloud.resourcecenter.product.dto.ProductDto;
import com.pcloud.resourcecenter.product.dto.ProductLabelDto;
import com.pcloud.resourcecenter.product.dto.ProductTypeDto;
import com.pcloud.usercenter.party.adviser.dto.AdviserBaseInfoDto;
import com.pcloud.usercenter.user.entity.UserLogin;
import com.pcloud.wechatgroup.group.dto.GroupScanUserStatsDTO;
import com.pcloud.wechatgroup.group.dto.GroupUserCountDTO;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * @描述：编辑管理书籍逻辑层接口实现类
 * @作者：songx
 * @创建时间：2016年12月30日,下午5:23:32 @版本：1.0
 */
@Service("bookAdviserBiz")
public class BookAdviserBizImpl implements BookAdviserBiz {

	/**
	 *
	 */
	private static final Logger LOGGER = LoggerFactory.getLogger(BookAdviserBizImpl.class);

	@Autowired
	private BookAdviserDao bookAdviserDao;

	@Autowired
	private BookBiz bookBiz;

	@Autowired
	private BookSet bookSet;

	@Autowired
	private QrcodeSceneConsr qrcodeSceneConsr;

	@Autowired
	private TemplateConsr templateConsr;

	@Autowired
	private AdviserConsr adviserConsr;

	@Autowired
	private MainLineConsr mainLineConsr;

	@Autowired
	private BookcaseConsr bookcaseConsr;

	@Autowired
	private BookConsr bookConsr;

	@Autowired
	private ChannelConsr channelConsr;

    @Autowired
    private BookGroupBiz bookGroupBiz;

    @Autowired
    private BookGroupDao bookGroupDao;
    @Autowired
    private RightsSettingBiz rightsSettingBiz;
    @Autowired
	private RightsSettingDAO rightsSettingDAO;

    @Autowired
	private ESBookAndAdviserBiz esBookAndAdviserBiz;

    @Autowired
	private BookFundBiz bookFundBiz;
    @Autowired
	private WechatGroupConsr wechatGroupConsr;
    @Autowired
	private BrowseRecordConsr browseRecordConsr;
    @Autowired
	private ErpConsr erpConsr;
    @Autowired
	private TradeConsr tradeConsr;
    @Autowired
	private ExportConsr exportConsr;
	@Autowired
	private AgentConsr agentConsr;
	@Autowired
	private MessageConsr messageConsr;
	@Autowired
	private BookAppletSceneDao bookAppletSceneDao;
	@Autowired
	private BookAdviserBiz bookAdviserBiz;
	@Autowired
	private BookQrcodeWxworkBiz bookQrcodeWxworkBiz;
	@Autowired
	private ProductConsr productConsr;
	@Autowired
	private AppConsr appConsr;
	@Autowired
	private LabelConsr labelConsr;
	@Autowired
	private BookLabelBiz bookLabelBiz;
	@Autowired
	private BookGroupServeDao bookGroupServeDao;
	@Autowired
	private ResourcePageBiz resourcePageBiz;
	@Autowired
	private UpdateSuperSearchProducer searchProducer;
	@Autowired
	private ResourcePageItemDao resourcePageItemDao;

    @Override
    public List<BookDto> listByAdviserId(Long adviserId) {
		if(null == adviserId) {
			return Lists.newArrayList();
		}
		final List<Long> bookIds = bookAdviserDao.listBookIdsByAdviser(adviserId);
		if(CollectionUtils.isEmpty(bookIds)) {
			return Lists.newArrayList();
		}
		final Map<Long, BookDto> map = bookBiz.listBaseByIds(bookIds);
		if(CollectionUtils.isEmpty(map)) {
			return Lists.newArrayList();
		}
		return Lists.newArrayList(map.values());
    }

    /**
	 * 创建编辑管理书籍关系
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void create(BookAdviser bookAdviser) throws BizException {
		LOGGER.info("创建编辑与书籍关联关系【START】bookAdviser=" + bookAdviser);
		checkParam(bookAdviser);
		// 验证渠道编辑是否为一个出版社
		checkIsSameAgent(bookAdviser.getChannelId(), bookAdviser.getAdviserId());

		// 判断编辑是否已经设置过该书籍的推广信息
		BookAdviserDto bookAdviserDto = this.getByAdviserContainsDelete(bookAdviser);
		if (bookAdviserDto != null && BookConstant.BOOK_ADVISER_NO_DELETE.equals(bookAdviserDto.getIsDelete())) {
			UpdateBookRobotProcessDto dto=new UpdateBookRobotProcessDto();
			dto.setBookId(bookAdviser.getBookId());
			dto.setIsOpenRobotProcess(bookAdviser.getIsOpenRobotProcess());
			bookBiz.updateIsOpenRobotProcess(bookAdviser.getAdviserId(),dto);
			BookGroupDTO dtoByBookId = bookGroupBiz.getDTOByBookId(bookAdviser.getBookId(), bookAdviser.getChannelId(), bookAdviser.getAdviserId());
			if(dtoByBookId!=null){
				bookGroupBiz.createBookGroupAppletUrl(dtoByBookId.getId(),bookAdviser.getBookId(),bookAdviser.getChannelId(), bookAdviser.getAdviserId());
			}
			bookAdviser.setBookAdviserId(bookAdviserDto.getBookAdviserId());
			return;
		}

		if (bookAdviserDto != null && BookConstant.BOOK_ADVISER_DELETE.equals(bookAdviserDto.getIsDelete())) { // 编辑之前设置过，但是已经删除，走恢复流程
			// 20190723-刘娜【ID1001264】社群书删除后，再创建时不要自动恢复
			recoverBook4Adviser(bookAdviser.getBookId(), bookAdviser.getAdviserId(), bookAdviser.getChannelId(),
					bookAdviser.getTempletId(), bookAdviser.getSecondTempletId(),
					bookAdviser.getGraLabelId(), bookAdviser.getSubLabelId(), bookAdviser.getVerLabelId(), bookAdviser.getAreaLabelId(),
					false,bookAdviser.getThirdTempletId());
			bookAdviser.setBookAdviserId(bookAdviserDto.getBookAdviserId());
		} else {
			// 判断是否配置过该书籍推广信息
			checkIsHaveOtherAdviser(bookAdviser.getBookId(), bookAdviser.getChannelId(), bookAdviser.getAdviserId());
			try {
				LOGGER.info("【书籍-编辑】编辑设置书籍推广信息,<START>.[bookAdviser]=" + bookAdviser.toString());
				// 默认是主编辑
				bookAdviser.setIsMainEditor(true);
				bookAdviserDao.insert(bookAdviser);
				esBookAndAdviserBiz.updateBookAndAdviserToES(Collections.singletonList(bookAdviser.getBookId()));
				BookGroupDTO dtoByBookId = bookGroupBiz.getDTOByBookId(bookAdviser.getBookId(), bookAdviser.getChannelId(), bookAdviser.getAdviserId());
				if(dtoByBookId!=null){
					bookGroupBiz.createBookGroupAppletUrl(dtoByBookId.getId(),bookAdviser.getBookId(),bookAdviser.getChannelId(), bookAdviser.getAdviserId());
				}
			} catch (DataIntegrityViolationException e) {
				throw new BookBizException(BookBizException.DB_DML_FAIL, "该书刊已经被别的编辑添加过");
			} catch (Exception e) {
				LOGGER.error("【书籍-编辑】编辑设置书籍推广信息,<ERROR>.[BookAdviserDao.insert]" + e.getMessage(), e);
				throw new BookBizException(BookBizException.DB_DML_FAIL, "设置书刊推广信息失败");
			}

			// 周任务书刊埋点
			mainLineConsr.sendAddBookTask(bookAdviser.getBookId(), bookAdviser.getAdviserId());
		}
		LOGGER.info("创建编辑与书籍关联关系【END】");
	}

	/**
	 * 是否有其他编辑加过这本书
	 * @param bookId 图书标识
	 * @param channelId 运营标识
	 */
	void  checkIsHaveOtherAdviser(Long bookId, Long channelId, Long adviserId) throws BizException{
		LOGGER.info("是否有其他编辑加过这本书bookId="+bookId+"channelId="+channelId);
		if (bookId == null || channelId == null) {
			throw new BookBizException(BookBizException.PARAM_IS_ERROR, "图书不存在！");
		}
		List<BookAdviserDto> advisers = bookAdviserDao.getAdvisers(bookId);
		if(ListUtils.isEmpty(advisers)){
			return;
		}
		Boolean isHaveOtherChannel = false;
		Boolean isMySelf = false;
		for(BookAdviserDto bookAdviserDto : advisers){
			if(!channelId.equals(bookAdviserDto.getChannelId())){
				isHaveOtherChannel = true;
			}
			if(bookAdviserDto.getAdviserId().equals(adviserId)) {
				isMySelf = true;
			}
		}
		if(isHaveOtherChannel){
			throw new BookBizException(BookBizException.DB_SELECT_MORE, "已在其它运营平台存在");
		}else{
			if (!isMySelf || advisers.size() > 1) {
				throw new BookBizException(BookBizException.DB_SELECT_MORE, "已被其它编辑增加成功");
			}
		}
	}

	/**
	 * 校验是否同一出版社
	 *
	 * @param channelId
	 *            运营标识
	 * @param adviserId
	 *            编辑标识
	 */
	private void checkIsSameAgent(Long channelId, Long adviserId) {
		if (!channelConsr.judgeChannelAdviserRelationship(channelId, adviserId)) {
			throw new BookBizException(BookBizException.PARAM_IS_ERROR, "渠道编辑非同一出版社，不能创建书籍");
		}
	}

	/**
	 * 校验参数
	 * @param bookAdviser
	 */
	private void checkParam(BookAdviser bookAdviser) {
		if (bookAdviser.getBookId() == null) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "请选择书刊");
		}
		if (bookAdviser.getChannelId() == null) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "请选择运营平台");
		}
		if (bookAdviser.getAdviserId() == null) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "会话失效,请重新登录");
		}
	}

	/**
	 * 删除编辑和书籍的推广信息
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteByBook(Long bookId) throws BizException {
		if (bookId == null) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "请选择书刊");
		}
		LOGGER.info("【书籍-编辑】删除编辑和书籍的推广信息,<START>.[bookId]=" + bookId);
		bookAdviserDao.deleteByBook(bookId);
		esBookAndAdviserBiz.updateBookAndAdviserToES(Collections.singletonList(bookId));
	}

	/**
	 * 批量删除编辑和书籍的推广信息
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteByBooks(List<Long> bookIds) throws BizException {
		if (bookIds == null || bookIds.isEmpty()) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "请选择书刊");
		}

		try {
			LOGGER.info("【书籍-编辑】批量删除书刊的推广信息,<START>.[bookIds]=" + bookIds.toString());
			bookAdviserDao.deleteByBooks(bookIds);
			esBookAndAdviserBiz.updateBookAndAdviserToES(bookIds);
		} catch (Exception e) {
			LOGGER.error("【书籍-编辑】批量删除书刊的推广信息,<ERROR>.[bookAdviserDao.deleteByBooks]" + e.getMessage(), e);
			throw new BookBizException(BookBizException.DB_DML_FAIL, "批量删除书刊的推广信息失败");
		}
	}

	/**
	 * 获取编辑设置的书籍推广信息
	 */
	@Override
	public BookAdviserDto getByAdviser(BookAdviser bookAdviser) throws BizException {
		if (bookAdviser == null) {
			return null;
		}
		if (StringUtils.isEmpty(bookAdviser.getSerialNumber())) {
			bookAdviser.setSerialNumber(null);
		}
		return bookAdviserDao.getByAdviser(bookAdviser);
	}

	/**
	 * 获取编辑设置的书籍推广信息
	 */
	@Override
	public BookAdviserDto getBase(Long bookId, Long channelId, Long adviserId) throws BizException {
		return bookAdviserDao.getBase(bookId, channelId, adviserId);
	}


	/**
	 * 获取编辑设置的书籍推广信息(包含删除或未删除的)
	 */
	private BookAdviserDto getByAdviserContainsDelete(BookAdviser bookAdviser) throws BizException {
		return bookAdviserDao.getByAdviserContainsDelete(bookAdviser);
	}

	/**
	 * 统计编辑推广的图书总数
	 */
	@Override
	public Map<Long, BookAdviserDto> getCountByAdvisers(List<Long> adviserIds) throws BizException {
		try {
			return bookAdviserDao.getCountByAdvisers(adviserIds);
		} catch (Exception e) {
			LOGGER.error("【书籍-代理】统计推广的书刊总数,<ERROR>.[BookAdviserDao.getCountByAdvisers]" + e.getMessage(), e);
			throw new BookBizException(BookBizException.DB_DML_FAIL, "统计推广的书刊总数失败");
		}
	}

	/**
	 * 根据ISBN获取书刊信息
	 */
	public BookAdviserDto getByIsbnEx(String isbn, Long channelId) throws BizException {
		LOGGER.info("【编辑书刊】根据ISBN获取书刊信息,<START>.[isbn]=" + isbn);
		if (StringUtil.isEmpty(isbn)) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "请选择书刊");
		}
		try {
			Map<String, Object> paramMap = Maps.newHashMap();
			paramMap.put("isbn", isbn);
			paramMap.put("channelId", channelId);
			return bookAdviserDao.getByIsbn(paramMap);
		} catch (Exception e) {
			LOGGER.error("【书刊基础】根据ISBN获取书刊信息,<ERROR>.[getByIsbn]:" + e.getMessage(), e);
			throw BizException.DB_SELECT_IS_FAIL;
		}
	}

	/**
	 * 根据ISBN获取书刊信息
	 */
	@Override
	public BookAdviserDto getByIsbn(String isbn, Long channelId) throws BizException {
		LOGGER.info("【编辑书刊】根据ISBN获取书刊信息,<START>.[isbn]=" + isbn);
		if (StringUtil.isEmpty(isbn)) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "请选择书刊");
		}
		BookAdviserDto bookAdviserDto = null;
		try {
			Map<String, Object> paramMap = Maps.newHashMap();
			paramMap.put("isbn", isbn);
			paramMap.put("channelId", channelId);
			bookAdviserDto = bookAdviserDao.getByIsbn(paramMap);
			return bookAdviserDto;
		} catch (Exception e) {
			LOGGER.error("【书刊基础】根据ISBN获取书刊信息,<ERROR>.[getByIsbn]:" + e.getMessage(), e);
			throw BizException.DB_SELECT_IS_FAIL;
		}
	}

	/**
	 * 获取配置过书籍的编辑top1
	 */
	@Override
	public Long getAdviserTop1(Long bookId, Long channelId) {
		LOGGER.info("【编辑书刊】获取配置过书籍的编辑top1,<START>.[bookId]=" + bookId + ",[channelId]");
		try {
			Map<String, Object> paramMap = Maps.newHashMap();
			paramMap.put("bookId", bookId);
			paramMap.put("channelId", channelId);
			return bookAdviserDao.getAdviserTop1(paramMap);
		} catch (Exception e) {
			LOGGER.error("【编辑书刊】获取配置过书籍的编辑top1,<ERROR>.[getByIsbn]:" + e.getMessage(), e);
			throw BizException.DB_SELECT_IS_FAIL;
		}
	}

	/**
	 * 根据书籍和渠道删除书籍编辑关联信息
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteByBookAndChannel(Long bookId, Long channelId) throws BizException {
		LOGGER.info("【编辑书刊】根据书籍和渠道删除书籍编辑关联信息,<START>.[bookId]=" + bookId + ",[channelId]=" + channelId);
		try {
			Map<String, Object> paramMap = Maps.newHashMap();
			paramMap.put("bookId", bookId);
			paramMap.put("channelId", channelId);
			bookAdviserDao.deleteByBookAndChannel(paramMap);
			esBookAndAdviserBiz.updateBookAndAdviserToES(Collections.singletonList(bookId));
		} catch (Exception e) {
			LOGGER.error("【编辑书刊】根据书籍和渠道删除书籍编辑关联信息,<ERROR>.[deleteByBookAndChannel]:" + e.getMessage(), e);
			throw new BookBizException(BookBizException.DB_DML_FAIL, "根据书籍和渠道删除书籍编辑关联信息失败");
		}
	}

	/**
	 * 根据图书信息获取主编辑ID
	 */
	@Override
	public Long getMainAdviserId(Long bookId, Long channelId) {
		LOGGER.info("根据图书信息获取主编辑ID,<START>.[bookId]=" + bookId + ",[channelId]=" + channelId);
		if (null == bookId || null == channelId) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "书刊信息缺失！");
		}
		try {
			Long mainAdviserId = bookAdviserDao.getMainAdviserId(bookId, channelId);
			return mainAdviserId;
		} catch (Exception e) {
			LOGGER.error("根据图书信息获取主编辑ID,<ERROR>.[getMainAdviserId]:" + e.getMessage(), e);
			throw BizException.DB_SELECT_IS_FAIL;
		}

	}

	/**
	 * 编辑管理--获取编辑列表（平台端）
	 */
	@Override
	public List<AdviserManageDto> getAdviserList(Long bookId) {
		LOGGER.info("【书刊管理-编辑管理】编辑管理--获取编辑列表（平台端）,<START>.[bookId]=" + bookId);
		List<AdviserManageDto> adviserManageDtos = bookAdviserDao.getAdviserList(bookId);
		List<Long> adviserIds = bookAdviserDao.getAdviserIdsByBookId(bookId);
		bookSet.setAdviserDetailInfo(adviserManageDtos, adviserIds);
		return adviserManageDtos;
	}

	/**
	 * 编辑管理--删除副编辑
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void delViceAdviser(List<BookAdviser> bookAdvisers) {
		if (ListUtils.isEmpty(bookAdvisers)) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "书刊信息缺失！");
		}
		LOGGER.info("编辑管理--删除副编辑,<START>.[bookAdvisers]=" + bookAdvisers.toString());
		// 删除副编辑
		bookAdviserDao.delViceAdviser(bookAdvisers);
		BookDto bookDto = bookBiz.getBaseById(bookAdvisers.get(0).getBookId());
		for (BookAdviser bookAdviser : bookAdvisers) {
				// 删除副编辑二维码关联关系
			qrcodeSceneConsr.deleteAdviserBookQrRelation(bookAdviser.getAdviserId(), bookAdviser.getBookId());
		    sendBookDeleteTemplate(bookAdviser.getAdviserId(), bookDto.getBookName());
		}
	}

	/**
	 * 发送书刊移除模板消息
	 * @param adviserId 编辑标识
	 * @param bookName 图书名称
	 */
	void sendBookDeleteTemplate(Long adviserId, String bookName) {
		try {
			// 发送模板消息
			Long agentId = adviserConsr.getAgentIdByAdviser(adviserId);
			Map<String, String> temParam = new HashMap<>();
			temParam.put("first", "编辑变更");
			temParam.put("keyword1", "RAYS编辑");
			temParam.put("keyword2", "您的书刊" + StringUtil.addBracket(bookName) + "已被移除，请知悉");
			temParam.put("remark", "请抽空处理");
			templateConsr.sendManage(SceneCode.PROJECT_TASK_SCENE.value, agentId, adviserId,
					SystemCode.adviser.code, "", temParam, SendType.SEND_BY_PARTY_ID.value, false);
		} catch (Exception e) {
			LOGGER.error("编辑管理--删除副编辑,发送模板消息失败<ERROR>"+e.getMessage());
		}
	}

	/**
	 * 创建默认图书与编辑的关系
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public Long createDefaultBook(Long channelId, Long adviserId) {
		if (channelId == null) {
			//获取默认运营
			channelId = adviserConsr.getDefaultChannel(adviserId);
		}
		if(channelId == null) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "运营不存在");
		}
		if (adviserId == null) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "编辑不存在");
		}
		BookAdviser bookAdviser = new BookAdviser();
		// 获取bookId
		BookDto book = bookBiz.getByIsbn(BookConstant.DEFAULT_BOOK_ISBN, null);
		if (book == null) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "请选择书刊");
		}
		bookAdviser.setBookId(book.getBookId());
		bookAdviser.setChannelId(channelId);
		bookAdviser.setAdviserId(adviserId);
		bookAdviser.setIsMainEditor(false);
		try {
			LOGGER.info("【书籍-编辑】编辑设置书籍推广信息,<START>.[bookAdviser]=" + bookAdviser.toString());
			// 默认是主编辑
			bookAdviserDao.insert(bookAdviser);
			esBookAndAdviserBiz.updateBookAndAdviserToES(Collections.singletonList(bookAdviser.getBookId()));
		} catch (Exception e) {
			LOGGER.warn("【书籍-编辑】编辑设置书籍推广信息,<ERROR>.[BookAdviserDao.insert]" + e.getMessage(), e);
		}
		AdviserDefault adviserDefault = new AdviserDefault();
		adviserDefault.setAdviserId(adviserId);
		adviserDefault.setBookId(book.getBookId());
		mainLineConsr.sendDefaultId(adviserDefault);
		return book.getBookId();
	}

	/**
	 * 获取默认创建的图书
	 */
	@Override
	public BookAdviserDto getDefaultBook(Long channelId, Long adviserId) {
		BookAdviser bookAdviser = new BookAdviser();
		// 获取bookId
		BookDto book = bookBiz.getByIsbn("9787507600000", null);
		if (book == null) {
			throw new BookBizException(BookBizException.PARAM_IS_NULL, "请选择书刊");
		}
		bookAdviser.setBookId(book.getBookId());
		bookAdviser.setChannelId(channelId);
		bookAdviser.setAdviserId(adviserId);
		BookAdviserDto bookAdviserDto = this.getByAdviser(bookAdviser);
		if (bookAdviserDto != null) {
			BookDto bookDto = bookBiz.getBaseById(bookAdviserDto.getBookId());
			bookAdviserDto.setBookDto(bookDto);
		}
		return bookAdviserDto;
	}

	/**
	 * 出版社下编辑的所有书刊的数目
	 */
	@Override
	public Integer getBookCount(Long agentId) {
		LOGGER.info("出版社下编辑的所有书刊的数目,<START>.[agentId]=" + agentId);
		List<Long> adviserIds = adviserConsr.getByAgentId(agentId);
		Integer bookCount = null;
		try {
			if (!ListUtils.isEmpty(adviserIds)) {
				bookCount = bookAdviserDao.getBookCount(adviserIds);
			}
		} catch (Exception e) {
			LOGGER.error("出版社下编辑的所有书刊的数目,<ERROR>.[getBookCount]:" + e.getMessage(), e);
			throw BizException.DB_SELECT_IS_FAIL;
		}
		return bookCount;
	}

	/**
	 * 时代大屏用
	 */
	@Override
	public Integer getBookCounts(List<Long> agentIds) {
		if(ListUtils.isEmpty(agentIds)){
			return 0;
		}
		Long agentId=agentIds.get(0);
		if(agentIds.size()>1){
			//如果查所有的出版社下的编辑。就传-1
			agentId=-1L;
		}
		List<Long> adviserIds = adviserConsr.getByAgentId(agentId);
		Integer bookCount = null;
		try {
			if (!ListUtils.isEmpty(adviserIds)) {
				bookCount = bookAdviserDao.getBookCount(adviserIds);
			}
		} catch (Exception e) {
			LOGGER.error("出版社下编辑的所有书刊的数目,<ERROR>.[getBookCount]:" + e.getMessage(), e);
			throw BizException.DB_SELECT_IS_FAIL;
		}
		return bookCount;
	}

	/**
	 * 更新图书模板
	 */
	@ParamLog("更新图书模板")
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateBookTemplet(Book book) {
		BookAdviser bookAdviser = new BookAdviser();
		bookAdviser.setBookId(book.getBookId());
		bookAdviser.setTempletId(book.getTempletId());
		bookAdviser.setAdviserId(book.getLastModifiedUser());
		bookAdviser.setChannelId(book.getChannelId());
		bookAdviser.setSecondTempletId(book.getSecondTempletId());
		bookAdviser.setThirdTempletId(book.getThirdTempletId());
		bookAdviser.setGraLabelId(book.getGraLabelId());
		bookAdviser.setSubLabelId(book.getSubLabelId());
		bookAdviser.setAreaLabelId(book.getAreaLabelId());
		bookAdviser.setVerLabelId(book.getVerLabelId());
		bookAdviser.setProLabelId(book.getProLabelId());
		bookAdviser.setDepLabelId(book.getDepLabelId());
		bookAdviser.setPurLabelId(book.getPurLabelId());
		bookAdviser.setVolLabelId(book.getVolLabelId());
		bookAdviserDao.updateBookTempletAndLabel(bookAdviser);
		esBookAndAdviserBiz.updateBookAndAdviserToES(Collections.singletonList(bookAdviser.getBookId()));
	}

	/**
	 * 每日新增书刊数-出版
	 */
	@Override
	public List<BookCountDto> listBookCountByDate4Agent(Long agentId) {
		LOGGER.info("每日新增书刊数-出版<START>.[agentId]=" + agentId);
		// 获取所有编辑
		List<Long> adviserIds = adviserConsr.getByAgentId(agentId);
		List<BookCountDto> bookCounts = null;
		String startDate = DateUtils.getShortDateStr(DateUtils.addDay(new Date(), -14));
		String endDate = DateUtils.getShortDateStr(DateUtils.addDay(new Date(), -1));
		if (!ListUtils.isEmpty(adviserIds)) {
			Map<String, Object> paramMap = new HashMap<>();
			paramMap.put("adviserIds", adviserIds);
			paramMap.put("startDate", startDate);
			paramMap.put("endDate", endDate);
			bookCounts = bookAdviserDao.listBookCountByDate4Agent(paramMap);
		}
		this.setZoreRecord(bookCounts, startDate, endDate);
		return bookCounts;
	}

	@Override
	public List<BookCountDto> listBookCountByDate4Agents(List<Long> agentIds) {
		if(ListUtils.isEmpty(agentIds)){
			return new ArrayList<>();
		}
		Long agentId=agentIds.get(0);
		if(agentIds.size()>1){
			//如果查所有的出版社下的编辑。就传-1
			agentId=-1L;
		}
		// 获取所有编辑
		List<Long> adviserIds = adviserConsr.getByAgentId(agentId);
		List<BookCountDto> bookCounts = null;
		String startDate = DateUtils.getShortDateStr(DateUtils.addDay(new Date(), -14));
		String endDate = DateUtils.getShortDateStr(DateUtils.addDay(new Date(), -1));
		if (!ListUtils.isEmpty(adviserIds)) {
			Map<String, Object> paramMap = new HashMap<>();
			paramMap.put("adviserIds", adviserIds);
			paramMap.put("startDate", startDate);
			paramMap.put("endDate", endDate);
			bookCounts = bookAdviserDao.listBookCountByDate4Agent(paramMap);
		}
		this.setZoreRecord(bookCounts, startDate, endDate);
		return bookCounts;
	}

	/**
	 * 填充不存在的日期中的值为0
	 *
	 * @param bookCounts
	 * @param startTime
	 * @param endTime
	 * @throws BizException
	 */
	public void setZoreRecord(List<BookCountDto> bookCounts, String startTime, String endTime) throws BizException {
		if (!ListUtils.isEmpty(bookCounts)) {
			// 计算开始时间和结束时间相差多少天，含当天所以要+1
			int dateDiff = (int) (DateUtils.getDateDiff(endTime, startTime) + 1);
			List<String> dates = DateUtils.getLastDays(endTime, dateDiff);
			for (String date : dates) {
				boolean bool = false;
				for (BookCountDto bookCountDto : bookCounts) {
					if (date.equals(bookCountDto.getDate())) {
						bool = true;
					}
				}
				if (!bool) {
					BookCountDto bookCount = new BookCountDto();
					bookCount.setDate(date);
					bookCount.setBookCount(0);
					bookCounts.add(bookCount);
				}
			}
			bookCounts.sort((BookCountDto dto1, BookCountDto dto2) -> dto1.getDate().compareTo(dto2.getDate()));
		}
	}

	/**
	 * 删除书籍（编辑端）
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteBook4Adviser(Long bookId, Long adviserId, Long channelId) {
		LOGGER.info("删除书籍（编辑端）<START>.[bookId]=" + bookId + ",[adviserId]=" + adviserId + ",channelId=" + channelId);
		Map<String, Long> paramMap = new HashMap<>();
		paramMap.put("bookId", bookId);
		paramMap.put("adviserId", adviserId);
		paramMap.put("channelId", channelId);
		// 查询当前编辑是否是主编辑
		Boolean isMainAdviser = bookAdviserDao.isMainAdviser4Book(paramMap);
		if (isMainAdviser) {
			deleteBook4MainAdviser(bookId,adviserId,channelId);
		} else {
			deleteBook4ViceAdviser(bookId,adviserId,channelId);
		}
		//更新超级搜索es
		searchProducer.deleteBook(bookId, adviserId, channelId);

	}

	/**
	 * 删除主编辑书籍
	 * @param bookId 图书标识
	 * @param adviserId 编辑标识
	 * @param channelId 运营标识
	 */
	@Transactional(rollbackFor = Exception.class)
	public void deleteBook4MainAdviser(Long bookId, Long adviserId, Long channelId) {
		LOGGER.info("删除主编辑书籍<START>.[bookId]=" + bookId + ",[adviserId]=" + adviserId + ",channelId=" + channelId);
		// 查询是否有收益
		BigDecimal bookIncome = bookConsr.getBookIncomeInfo(bookId, channelId, adviserId);
		// 没有收益，删除主编辑的书，同时删除副编辑的书以及副编辑下所有关联内容
		if (bookIncome != null && bookIncome.compareTo(new BigDecimal(0))==1) {
			throw new BookBizException(BookBizException.NO_DELETE_ERROR, "该图书已产生收益,不能被删除！");
		} else {
			// 删除图书关联二维码
			qrcodeSceneConsr.deleteByBook(bookId, channelId, null);
			// 删除书籍编辑的状态
			updateBookAdviserStatus(bookId, null, channelId, null,null, null, null,
					null, null, BookConstant.BOOK_ADVISER_DELETE, null, null);
			// 删除读者端的书架的书籍
			bookcaseConsr.deleteBookForAdviser(bookId, channelId, adviserId);
		}
	}

	/**
	 * 删除副编辑书籍（编辑端）
	 *
	 * @param bookId
	 *            图书标识
	 * @param adviserId
	 *            编辑标识
	 * @param channelId
	 *            运营标识
	 */
	@Transactional(rollbackFor = Exception.class)
	public void deleteBook4ViceAdviser(Long bookId, Long adviserId, Long channelId) {
		LOGGER.info("删除副编辑书籍<START>.[bookId]=" + bookId + ",[adviserId]=" + adviserId + ",channelId=" + channelId);
		// 删除图书关联二维码
		qrcodeSceneConsr.deleteByBook(bookId, channelId, adviserId);
		// 删除书籍编辑的状态
		updateBookAdviserStatus(bookId, adviserId, channelId, null,null, null, null, null,
				null, BookConstant.BOOK_ADVISER_DELETE, null, null);
		// 删除读者端的书架的书籍
		bookcaseConsr.deleteBookForAdviser(bookId, channelId, adviserId);
	}

	/**
	 * 恢复书籍-编辑
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public void recoverBook4Adviser(Long bookId, Long adviserId, Long channelId, Long templetId,Long secondTempletId,
									Long graLabelId, Long subLabelId, Long verLabelId, Long areaLabelId,
									Boolean recoverScene, Long thirdTempletId) {
		LOGGER.info("恢复书籍-编辑 <START>.[bookId]=" + bookId + ",adviserId=" + adviserId + ",channelId=" + channelId + " templetId= " + templetId + "secondTempletId=" + secondTempletId);
		checkIsHaveOtherAdviser(bookId, channelId, adviserId);
		// 恢复书籍编辑的状态
		updateBookAdviserStatus(bookId, adviserId, channelId, templetId, secondTempletId, graLabelId, subLabelId, verLabelId, areaLabelId, BookConstant.BOOK_ADVISER_NO_DELETE,BookConstant.MAIN_ADVISER, thirdTempletId);
		// 恢复图书关联的二维码 20190723-刘娜【ID1001264】社群书删除后，再创建时不要自动恢复
		if (recoverScene) {
			bookGroupBiz.recoverByBookId(bookId, channelId, adviserId);
			qrcodeSceneConsr.recoverByBook(bookId, channelId, adviserId);
		}

	}

	/**
	 * 修改书籍编辑的状态（删除或者恢复）
	 * @param bookId 圖書標識
	 * @param adviserId 编辑标识
	 * @param channelId 运营标识
	 * @param secondTempletId 第二级标题id
	 * @param deleteStatus 删除状态
	 * @param isMainAdviser
	 * @param thirdTempletId
	 */
	private void updateBookAdviserStatus(Long bookId, Long adviserId, Long channelId, Long templetId, Long secondTempletId,
										 Long graLabelId, Long subLabelId, Long verLabelId, Long areaLabelId,
										 Integer deleteStatus, Integer isMainAdviser, Long thirdTempletId) {
		LOGGER.info("修改书籍编辑的状态（删除或者恢复） <START>.[bookId]=" + bookId + ",adviserId=" + adviserId + ",channelId="
				+ channelId + ",deleteStatus=" + deleteStatus+",isMainAdviser="+isMainAdviser+"templetId"+templetId);
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("bookId", bookId);
		paramMap.put("adviserId", adviserId);
		paramMap.put("channelId", channelId);
		paramMap.put("isMainAdviser", isMainAdviser);
		paramMap.put("status", deleteStatus);
		paramMap.put("templetId", templetId);
		paramMap.put("secondTempletId",secondTempletId);
		paramMap.put("thirdTempletId",thirdTempletId);
		paramMap.put("graLabelId",graLabelId);
		paramMap.put("subLabelId",subLabelId);
		paramMap.put("verLabelId",verLabelId);
		paramMap.put("areaLabelId",areaLabelId);
		bookAdviserDao.updateBook4Adviser(paramMap);
		esBookAndAdviserBiz.updateBookAndAdviserToES(Collections.singletonList(bookId));
		if (BookConstant.BOOK_ADVISER_DELETE.equals(deleteStatus)) {
            bookGroupBiz.deleteByBookId(bookId, channelId, adviserId);
        }
	}

	/**
	 * 获取编辑的图书总数
	 */
	@Override
	public CountDto getAdviserBookCount(Long adviserId) {
		LOGGER.info("获取编辑的图书总数 <START>.[adviserId]=" + adviserId);
		CountDto countDto = new CountDto();
		Integer count = bookAdviserDao.getAdviserBookCount(adviserId);
		countDto.setCount(count);
        Integer bookGroupCount = bookGroupDao.getBookGroupCount(adviserId);
        countDto.setBookGroupCount(bookGroupCount);
		return countDto;
	}

	/**
	 * 设置图书使用模板
	 */
	@Override
	public void setBookTemplet(BookAdviser bookAdviser) {
		LOGGER.info("设置图书使用模板【START】bookAdviser="+bookAdviser);
		bookAdviserDao.updateBookTemplet(bookAdviser);
		esBookAndAdviserBiz.updateBookAndAdviserToES(Collections.singletonList(bookAdviser.getBookId()));
	}
	@Override
	@ParamLog(value = "获取图书基本信息", isBefore = false, isAfterReturn = false)
	public Map<String, AdviserBookInfoDTO> listAdviserBookInfo(AviserBookInfoParam aviserBookInfoParam) {
		if (ListUtils.isEmpty(aviserBookInfoParam.getBookIds())) return null;
		List<AdviserBookInfoDTO> adviserBookInfoDTOS = bookAdviserDao.listAdviserBookInfo(aviserBookInfoParam);
		if (ListUtils.isEmpty(adviserBookInfoDTOS)) return null;
		Map<String, AdviserBookInfoDTO> adviserBookInfoDTOMap = new HashMap<>();
		for (AdviserBookInfoDTO adviserBookInfoDTO : adviserBookInfoDTOS) {
			adviserBookInfoDTOMap.put(adviserBookInfoDTO.getBookId() + "-" + adviserBookInfoDTO.getChannelId() + "-" + adviserBookInfoDTO.getAdviserId(), adviserBookInfoDTO);
		}
		return adviserBookInfoDTOMap;
	}

	@Override
	public Map<Long, BookCountAndAdviserIdDTO> getBookCountByAdviserId(BookCountByAdvisersDto bookCountByAdvisersDto) {
		return bookAdviserDao.getBookCountByAdviserId(bookCountByAdvisersDto);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void refactorData(Long parentId,Long originTempletId, Long secondTempletId) {
		LOGGER.info("begin refactorData");
		int effectRows = bookAdviserDao.updateBookBySecondTempletId(parentId,originTempletId,secondTempletId);
		try {
			List<Long> bookIds=bookAdviserDao.getBookIdsByTempletId(originTempletId);
			esBookAndAdviserBiz.updateBookAndAdviserToES(bookIds);
		}catch (Exception e){
			LOGGER.error("更新编辑和书es失败"+originTempletId);
		}

		LOGGER.info("refactorData effect rows : {}",effectRows);
		LOGGER.info("end refactorData");
	}

	@Override
	@ParamLog("获取编辑书刊列表(ERP项目用)")
	public PageBeanNew<ErpAdviserBookVO> listAdviserBook4Erp(String isbn, String uniqueNumber, String adviserName, Long agentId, Integer currentPage, Integer numPerPage) {
		Map<String, Object> paramMap = new HashMap<>();
		if(!StringUtil.isEmpty(isbn)){
			String [] nameList = isbn.trim().split("[\u00A0|\u3000|\u0020]");
			paramMap.put("nameList", Lists.newArrayList(nameList));
		}
		paramMap.put("isbn", isbn);
		paramMap.put("uniqueNumber", uniqueNumber);
		if(!StringUtil.isEmpty(adviserName)) {
			List<Long> adviserIds = adviserConsr.getAdviserIdsByName(adviserName);
			if(CollectionUtils.isEmpty(adviserIds)) {
				return new PageBeanNew<>(currentPage, numPerPage, new ArrayList<>());
			}
			paramMap.put("adviserIds", adviserIds);
		}

		if(agentId != null && agentId > 0){
			List<Long> allAdvisers4Agent = adviserConsr.getByAgentId(agentId);
			if(CollectionUtils.isEmpty(allAdvisers4Agent)) {
				return new PageBeanNew<>(currentPage, numPerPage, new ArrayList<>());
			}
			if(paramMap.containsKey("adviserIds")){
				List<Long> adviserIds = (List<Long>)paramMap.get("adviserIds");
				adviserIds.retainAll(allAdvisers4Agent);
			} else {
				paramMap.put("adviserIds", allAdvisers4Agent);
			}
		}
		PageBeanNew<ErpAdviserBookVO> pageBeanNew = bookAdviserDao.listPageNew(new PageParam(currentPage, numPerPage), paramMap, "listAdviserBook4Erp");
		List<ErpAdviserBookVO> bookVOS = pageBeanNew.getRecordList();
		if(!CollectionUtils.isEmpty(bookVOS)) {
			List<Long> adviserIds = bookVOS.stream().filter(s -> s.getAdviserId() != null).map(ErpAdviserBookVO::getAdviserId).distinct().collect(Collectors.toList());
			List<Long> channelIds = bookVOS.stream().filter(s -> s.getChannelId() != null).map(ErpAdviserBookVO::getChannelId).distinct().collect(Collectors.toList());
			List<Long> bookIds = bookVOS.stream().filter(s -> s.getBookId() != null).map(ErpAdviserBookVO::getBookId).distinct().collect(Collectors.toList());
			Map<Long, UserLogin> userLoginInfoMap= adviserConsr.getUserLoginInfoList(adviserIds);
			Map<Long, AdviserBaseInfoDto> adviserAgentMap = adviserConsr.getAdviserId2AdviserInfoDtoMap(adviserIds);
			Map<Long, String> channelNameMap = channelConsr.getNamesByIdList(channelIds);
			List<Long> list = bookFundBiz.listHaveFundBooks(bookIds);
			for (ErpAdviserBookVO bookVO : bookVOS) {
				Long adviserId = bookVO.getAdviserId();
				if(adviserId != null && MapUtils.isNotEmpty(userLoginInfoMap) && userLoginInfoMap.containsKey(adviserId)) {
					UserLogin userLogin = userLoginInfoMap.get(adviserId);
					bookVO.setAdviserAccount(userLogin!=null ? userLogin.getUserName() :null);
					bookVO.setAdviserPwd(userLogin!=null ? userLogin.getCurrentPassword() :null);
				}
				if(adviserId != null && MapUtils.isNotEmpty(adviserAgentMap) && adviserAgentMap.containsKey(adviserId)) {
					AdviserBaseInfoDto adviserBaseInfoDto = adviserAgentMap.get(adviserId);
					bookVO.setAgentName(null!=adviserBaseInfoDto ? adviserBaseInfoDto.getAgentName() :"--");
					bookVO.setAdviserName(null!=adviserBaseInfoDto ? adviserBaseInfoDto.getPartyName() :"--");
					bookVO.setPhoneNum(null!=adviserBaseInfoDto ? adviserBaseInfoDto.getPhoneNum() :"--");
				}
				if(bookVO.getChannelId() != null && MapUtils.isNotEmpty(channelNameMap) && channelNameMap.containsKey(bookVO.getChannelId())) {
					bookVO.setChannelName(channelNameMap.get(bookVO.getChannelId()));
				}
				bookVO.setIsFundSupport(false);
				if(!ListUtils.isEmpty(list) && list.contains(bookVO.getBookId())) {
					bookVO.setIsFundSupport(true);
				}
			}
		}
		return pageBeanNew;
	}

    /**
     * 设置书刊是否已下印状态
     */
	@Override
	public void setIsPrint(BookAdviser bookAdviser) throws BizException {
        if (null == bookAdviser.getBookId() || null == bookAdviser.getIsPrint()) {
            throw new BookBizException(BookBizException.PARAM_IS_NULL, "参数有误！");
        }
        bookAdviserDao.setIsPrint(bookAdviser);
    }

	@Override
	public BookRightsSettingDTO getBookRightsSetting(Long bookId, Long channelId, Long adviserId) {
		BookRightsSettingDTO bookRightsSettingDTO = new BookRightsSettingDTO();
		BookAdviserDto adviserDto = bookAdviserDao.getBase(bookId,channelId,adviserId);
		if (null!=adviserDto){
			RightsSettingDto rightsSettingDto = rightsSettingBiz.getByLabel(adviserDto.getTempletId(),
					adviserDto.getSecondTempletId(),adviserDto.getGraLabelId(),adviserDto.getSubLabelId(), adviserDto.getVolLabelId(), adviserDto.getVerLabelId(), adviserDto.getThirdTempletId());
			if (null!= rightsSettingDto){
				bookRightsSettingDTO.setRightsSettingDetail(rightsSettingDto.getDetail());
				bookRightsSettingDTO.setRightsSettingIntroduce(rightsSettingDto.getIntroduce());
				bookRightsSettingDTO.setRightsSettingCount(rightsSettingDto.getCount());
			}
		}
		return bookRightsSettingDTO;
	}

	@Override
	public BookAdviserDto getOneMainBook(Long bookId) {
		return bookAdviserDao.getOneMainBook(bookId);
	}

	@Override
	public Map<String, BookStatisticsResultDto> getBookRightsCount(List<BookRequestVO> requestVOS){
		Map<String, BookStatisticsResultDto> result = MapUtil.newHashMap();
		if(CollUtil.isEmpty(requestVOS)){
			return result;
		}
		BookStatisticsResultDto dto;
		Integer rightsCount = 0;
		Integer rightsType = 0;
		for (BookRequestVO vo : requestVOS) {
			if(vo.getBookId() == null || vo.getAdviserId() == null || vo.getChannelId() == null){
				continue;
			}
			String bookAdviserChannel = vo.getBookId() + "_" + vo.getAdviserId() + "_" + vo.getChannelId();
			String key =  CacheConstant.BOOK  + "bookAdviser:getBookRightsCount:" + bookAdviserChannel;
			dto = JedisClusterUtils.getJson(key, BookStatisticsResultDto.class);
			if(dto == null){
				rightsCount = getRightsettingCounts(vo.getBookId(), vo.getAdviserId(), vo.getChannelId());
				rightsType = rightsSettingBiz.getRightsTypeByBookId4AppletHome(vo.getBookId(), vo.getAdviserId(), vo.getChannelId());
				dto = BookStatisticsResultDto.builder()
						.bookAdviserChannel(bookAdviserChannel)
						.bookId(vo.getBookId())
						.adviserId(vo.getAdviserId())
						.channelId(vo.getChannelId())
						.rightsCount(rightsCount)
						.rightsType(rightsType)
						.build();
				JedisClusterUtils.setJson(key, dto, 1800);
			}
			result.put(bookAdviserChannel, dto);
		}
		return result;
	}

	@Override
	@ParamLog("获取某本书关联的二维码")
	public PageBeanNew<QrCodeVO> getQrList(Long bookId, Long adviserId, Long channelId,Integer type, Integer currentPage, Integer numPerPage) {
		if (null == bookId || null == adviserId || null == channelId || null == currentPage || null == numPerPage ){
			throw new BookBizException(BookBizException.ERROR, "参数为空");
		}
		//type 代表的是过滤二维码。如果是0,展示所有的二维码。如果是1(展示没有资源的码。但是要过滤小睿教育的书的非公众号二维码)
		List<Long> xiaoRuiEducation = channelConsr.isXiaoRuiEducation(Lists.newArrayList(bookId));
		//JoinGroupTypeEnum.XIAORUI的码迁到渠道了。不走这里查)
		List<BookGroupDTO> bookGroupDTOList=bookGroupDao.getDTOByBookIdList(bookId, channelId, adviserId);
		Set<Long> groupQrcodeSet=new HashSet<>();
		Set<Long> xiaoruiSet=new HashSet<>();
		List<QrCodeVO> qrCodeVOS = new ArrayList<>();
		if(CollUtil.isNotEmpty(bookGroupDTOList)){
			for (BookGroupDTO bookGroupDTO : bookGroupDTOList) {
				Integer joinGroupType = bookGroupDTO.getJoinGroupType();
				if(null!=joinGroupType){
					//群二维码和客服机器人
					if(JoinGroupTypeEnum.GROUP_QRCODE.getCode().equals(joinGroupType) || JoinGroupTypeEnum.ROBOT.getCode().equals(joinGroupType)){
						groupQrcodeSet.add(bookGroupDTO.getId());
					}
					//（**不包括群二维码，小睿）资源数量
					if(!JoinGroupTypeEnum.GROUP_QRCODE.getCode().equals(joinGroupType)){
						xiaoruiSet.add(bookGroupDTO.getId());
					}
				}
			}
			List<Long> groupQrcodeList = new ArrayList<>(groupQrcodeSet);
			List<Long> xiaoruiList = new ArrayList<>(xiaoruiSet);

			//分开查3种类型的资源数量
			//群二维码和客服机器人
			Map<Long, BookGroupServeCountDTO> groupQrCodeMap =CollUtil.isEmpty(groupQrcodeList) ? new HashMap<>() : bookGroupServeDao.mapGroupQrcodeServeCount(groupQrcodeList);
			//（**不包括群二维码，小睿）资源数量
			Map<Long, BookGroupServeCountDTO> xiaoruiMap =CollUtil.isEmpty(xiaoruiList) ? new HashMap<>() : bookGroupServeDao.mapXiaoRuiGroupQrcodeServeCount(xiaoruiList);

			//计算码的销售额
			List<Long> bookGroupIds =CollUtil.isEmpty(bookGroupDTOList) ? new ArrayList<>() : bookGroupDTOList.stream().filter(a -> null != a.getId() && null!=a.getJoinGroupType()
			&& !JoinGroupTypeEnum.XIAORUI.getCode().equals(a.getJoinGroupType())).map(a -> a.getId()).distinct().collect(Collectors.toList());
			Map<Long, BigDecimal> groupListSaleInfoMap = tradeConsr.getGroupListSaleInfo(bookGroupIds);
			//小睿的销售额 要用sceneId查


			QrCodeVO qrCodeVO;
			for (BookGroupDTO bookGroupDTO : bookGroupDTOList) {
				qrCodeVO = new QrCodeVO();
				qrCodeVO.setQrCodeName(bookGroupDTO.getGroupQrcodeName());
				qrCodeVO.setQrCodeUrl(bookGroupDTO.getGroupQrcodeUrl());
				qrCodeVO.setServeCount(0);
				qrCodeVO.setRightsCount(0);
				qrCodeVO.setSceneId(bookGroupDTO.getId());
				qrCodeVO.setJoinGroupType(bookGroupDTO.getJoinGroupType());
				qrCodeVO.setRightsCount(0);
				qrCodeVO.setSaleMoney(new BigDecimal(0));
				if(JoinGroupTypeEnum.GROUP_QRCODE.getCode().equals(bookGroupDTO.getJoinGroupType())){
					if(CollUtil.isNotEmpty(groupQrCodeMap) && groupQrCodeMap.containsKey(bookGroupDTO.getId())){
						BookGroupServeCountDTO bookGroupServeCountDTO = groupQrCodeMap.get(bookGroupDTO.getId());
						qrCodeVO.setServeCount(bookGroupServeCountDTO.getServeCount());
					}
				}else{
					if(CollUtil.isNotEmpty(xiaoruiMap) && xiaoruiMap.containsKey(bookGroupDTO.getId())){
						BookGroupServeCountDTO bookGroupServeCountDTO = xiaoruiMap.get(bookGroupDTO.getId());
						qrCodeVO.setServeCount(bookGroupServeCountDTO.getServeCount());
					}
					if(JoinGroupTypeEnum.ROBOT.getCode().equals(bookGroupDTO.getJoinGroupType())){
						if(CollUtil.isNotEmpty(groupQrCodeMap) && groupQrCodeMap.containsKey(bookGroupDTO.getId())){
							BookGroupServeCountDTO bookGroupServeCountDTO = groupQrCodeMap.get(bookGroupDTO.getId());
							if(null!=bookGroupServeCountDTO && null!=bookGroupServeCountDTO.getServeCount()) {
								qrCodeVO.setServeCount((null == qrCodeVO.getServeCount() ? 0 : qrCodeVO.getServeCount()) + bookGroupServeCountDTO.getServeCount());
							}
						}
					}
				}
				//设置销售额
				if(CollUtil.isNotEmpty(groupListSaleInfoMap) && groupListSaleInfoMap.containsKey(bookGroupDTO.getId())){
					qrCodeVO.setSaleMoney(groupListSaleInfoMap.get(bookGroupDTO.getId()));
				}
				qrCodeVO.setCodeType("group");
				qrCodeVO.setXiaoRuiEducation(false);
				if(CollUtil.isNotEmpty(xiaoRuiEducation) && xiaoRuiEducation.contains(bookId)){
					qrCodeVO.setXiaoRuiEducation(true);
				}
				qrCodeVOS.add(qrCodeVO);
			}
		}
		List<QrcodeSceneDto> qrcodeSceneDtos = qrcodeSceneConsr.getQrCodeList(bookId, adviserId, channelId);
		if (!ListUtils.isEmpty(qrcodeSceneDtos)) {
			List<Long> sceneIds = qrcodeSceneDtos.stream().map(x -> x.getSceneId()).collect(Collectors.toList());
			List<Long> qrcodeSceneIds = qrcodeSceneDtos.stream().filter(a->null!=a.getQrcodeType() && "wechat".equalsIgnoreCase(a.getQrcodeType())).map(x -> x.getSceneId()).collect(Collectors.toList());
			//之前小睿的码。现在叫rays码
			List<Long> ruiList = qrcodeSceneDtos.stream().filter(a->null!=a.getQrcodeType() && ("ali".equalsIgnoreCase(a.getQrcodeType()) || "own".equalsIgnoreCase(a.getQrcodeType()))).map(x -> x.getSceneId()).collect(Collectors.toList());
			//小睿的资源数量。要在resource_page_item查
			Map<Long, BookGroupServeCountDTO> ruiMap=CollUtil.isNotEmpty(ruiList) ? resourcePageItemDao.mapQrServeCount(ruiList) : new HashMap<>();
			// 企业微信群资源数
			Map<Long, BookGroupServeCountDTO> bookQrcodeWxworkMap = bookQrcodeWxworkBiz.mapWxWorkServeCount4SceneIds(sceneIds, BookQrcodeType.OFFICIAL_ACCOUNTS.getCode());
			//计算码的销售额
			Map<Long, BigDecimal> sceneListSaleInfoMap = tradeConsr.getSceneListSaleInfo(sceneIds);
			for (QrcodeSceneDto e : qrcodeSceneDtos) {
				QrCodeVO qrCodeVO1 = new QrCodeVO();
				qrCodeVO1.setQrCodeName(e.getSceneName());
				qrCodeVO1.setQrCodeUrl(e.getQrcodeUrl());
				BookGroupServeCountDTO serveCountDTO = bookQrcodeWxworkMap.get(e.getSceneId());
				qrCodeVO1.setServeCount(0);
				//公众号二维码才算渠道原来的资源
				if(CollUtil.isNotEmpty(qrcodeSceneIds) && qrcodeSceneIds.contains(e.getSceneId())){
					qrCodeVO1.setServeCount((ListUtils.isEmpty(e.getMessages()) ? 0 : e.getMessages().size()) + ((serveCountDTO == null || null==serveCountDTO.getServeCount()) ? 0 : serveCountDTO.getServeCount()));
				}
				if(CollUtil.isNotEmpty(ruiMap) && ruiMap.containsKey(e.getSceneId())){
					BookGroupServeCountDTO bookGroupServeCountDTO = ruiMap.get(e.getSceneId());
					if(null!=bookGroupServeCountDTO && null!=bookGroupServeCountDTO.getServeCount()){
						qrCodeVO1.setServeCount(bookGroupServeCountDTO.getServeCount());
					}
				}
				//设置二维码类型和书刊是否是小睿教育的书
				qrCodeVO1.setCodeType(e.getQrcodeType());
				qrCodeVO1.setXiaoRuiEducation(false);
				if(CollUtil.isNotEmpty(xiaoRuiEducation) && xiaoRuiEducation.contains(bookId)){
					qrCodeVO1.setXiaoRuiEducation(true);
				}
				qrCodeVO1.setSceneId(e.getSceneId());
				qrCodeVO1.setSaleMoney(new BigDecimal(0));
				if(CollUtil.isNotEmpty(sceneListSaleInfoMap) && sceneListSaleInfoMap.containsKey(e.getSceneId())){
					qrCodeVO1.setSaleMoney(sceneListSaleInfoMap.get(e.getSceneId()));
				}
				qrCodeVOS.add(qrCodeVO1);
			}
		}
		if (ListUtils.isEmpty(qrCodeVOS)){
			return new PageBeanNew<>(currentPage, numPerPage,new ArrayList<>());
		}
		List<QrCodeVO> record = new ArrayList<>();
		//type 代表的是过滤二维码。如果是0,展示所有的二维码。如果是1(展示没有资源的码。但是要过滤小睿教育的书的非公众号二维码)
		if(null!=type && 1==type) {
			qrCodeVOS = qrCodeVOS.stream().filter(a -> (null == a.getServeCount() || 0 == a.getServeCount()) && !(null != a.getXiaoRuiEducation() && a.getXiaoRuiEducation() && !"wechat".equalsIgnoreCase(a.getCodeType()))).collect(Collectors.toList());
		}
		if (qrCodeVOS.size() > (currentPage + 1) * numPerPage){
			record = qrCodeVOS.subList(currentPage * numPerPage,(currentPage + 1) * numPerPage);
		} else {
			record = qrCodeVOS.subList(currentPage * numPerPage, qrCodeVOS.size());
		}
		return new PageBeanNew<>(currentPage, numPerPage,qrCodeVOS.size(), record);
	}

	private Integer getRightsettingCounts(Long bookId, Long adviserId, Long channelId) {
		Long rightsSettingId = bookGroupBiz.getRightsSettingId4Book(adviserId, channelId, bookId);
		int i=0;
		if(null!=rightsSettingId){
			RightsSettingQueryDTO rightsSettingQueryDTO=new RightsSettingQueryDTO();
			rightsSettingQueryDTO.setAdviserId(adviserId);
			rightsSettingQueryDTO.setBookId(bookId);
			rightsSettingQueryDTO.setChannelId(channelId);
			rightsSettingQueryDTO.setRightsSettingTypes(Lists.newArrayList(2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19));
			rightsSettingQueryDTO.setRightsSettingId(rightsSettingId);
			RightsSetting rightsSetting = rightsSettingBiz.getRightsSettingItemsByTypeListNew(rightsSettingQueryDTO);
			if(null!=rightsSetting && null!=rightsSetting.getRightsSettingNow()){
				RightsSettingNow rightsSettingNow = rightsSetting.getRightsSettingNow();
				if(CollUtil.isNotEmpty(rightsSettingNow.getRightsSettingTitles())){
					for (RightsSettingTitle rightsSettingTitle : rightsSettingNow.getRightsSettingTitles()) {
						if(CollUtil.isEmpty(rightsSettingTitle.getRightsSettingItemList())){
							continue;
						}
						i+=rightsSettingTitle.getRightsSettingItemList().size();
					}
				}

			}
		}
		return i;
	}

	@Override
	public Map<String, BookResourceStatisticsDTO> mapResourceTotalCount(List<Long> adviserIds, List<Long> bookIds, List<Long> channelIds){
		Map<String, BookResourceStatisticsDTO> mapBookResourceStatistics = new HashMap<>();
		if(CollectionUtils.isEmpty(adviserIds) || CollectionUtils.isEmpty(bookIds) || CollectionUtils.isEmpty(channelIds)){
			throw new ChannelBizException(ChannelBizException.FILED_NULL, "adviserIds、bookIds、channelIds 参数为空！");
		}
		//公众号二维码
		Future<Map<String, QrcodeMessageDTO>> mapQrcodeMessageSubmit = ThreadPoolUtils.OTHER_POOL.submit(() -> channelConsr.mapResourceCount(adviserIds, bookIds, channelIds,1));
		//Rays二维码
		Future<Map<String, QrcodeMessageDTO>> mapRaysCodeMessageSubmit = ThreadPoolUtils.OTHER_POOL.submit(() -> channelConsr.mapResourceCount(adviserIds, bookIds, channelIds,2));
		Future<Map<String, BookGroupServeCountDTO>> mapBookGroupServeCountSubmit = ThreadPoolUtils.OTHER_POOL.submit(() -> bookGroupBiz.mapBookGroupServeCount(adviserIds, bookIds, channelIds));
		Future<Map<String, BookGroupServeCountDTO>> mapBookGroupQrcodeSubmit = ThreadPoolUtils.OTHER_POOL.submit(() -> bookGroupBiz.mapBookGroupQrcodeServeCount(adviserIds, bookIds, channelIds, JoinGroupTypeEnum.GROUP_QRCODE.getCode()));
		Future<Map<String, BookGroupServeCountDTO>> mapBookGroupRobotServeCountSubmit = ThreadPoolUtils.OTHER_POOL.submit(()-> bookGroupBiz.mapBookGroupQrcodeServeCount(adviserIds, bookIds, channelIds, JoinGroupTypeEnum.ROBOT.getCode()));
	//	Future<Map<Long, Integer>> rightsMapSubmit = ThreadPoolUtils.OTHER_POOL.submit(()-> bookAdviserBiz.rightsCountByBookIds(bookIds));
		//rays码的资源数量
		Future<Map<String, BookGroupServeCountDTO>> raysCodeServeCountSubmit = ThreadPoolUtils.OTHER_POOL.submit(()-> resourcePageBiz.mapRaysCodeServeCount(adviserIds, bookIds, channelIds));
		Future<Map<Long, Integer>> rightsMapSubmit = ThreadPoolUtils.OTHER_POOL.submit(()-> bookAdviserBiz.rightsCountByBookIds(bookIds));
		Map<String, QrcodeMessageDTO> mapQrcodeMessage =new HashMap<>();
		Map<String, QrcodeMessageDTO> mapRaysCodeMessage =new HashMap<>();
		Map<String, BookGroupServeCountDTO> mapWxworkServeCount =new HashMap<>();
		Map<String, BookGroupServeCountDTO> mapBookGroupServeCount = new HashMap<>();
		Map<String, BookGroupServeCountDTO> mapBookGroupQrcodeServeCount = new HashMap<>();
		Map<String, BookGroupServeCountDTO> mapBookGroupRobotServeCount =new HashMap<>();
		Map<String, BookGroupServeCountDTO> raysCodeServeCount =new HashMap<>();
	/*	Map<Long, Integer> rightsMap=new HashMap<>();*/
		try {
			mapQrcodeMessage = mapQrcodeMessageSubmit.get(ThreadPoolUtils.REMOTE_TIME_OUT, TimeUnit.SECONDS);
		} catch (InterruptedException | ExecutionException | TimeoutException e) {
			LOGGER.error("获取二维码信息错误: {}==", e);
		}
		try {
			mapRaysCodeMessage = mapRaysCodeMessageSubmit.get(ThreadPoolUtils.REMOTE_TIME_OUT, TimeUnit.SECONDS);
		} catch (InterruptedException | ExecutionException | TimeoutException e) {
			LOGGER.error("获取Rays二维码信息错误: {}==", e);
		}
		if(CollUtil.isNotEmpty(mapQrcodeMessage)){
			// 只查询公众号二维码中未被删除的sceneId对应的企业微信资源数
			String strSceneIds = mapQrcodeMessage.values().stream().map(x -> x.getSceneIdStr()).collect(Collectors.joining(","));
			mapWxworkServeCount = bookQrcodeWxworkBiz.mapWxWorkServeCount4BookIds(adviserIds, bookIds, channelIds, strSceneIds);
		}
		try {
			mapBookGroupServeCount = mapBookGroupServeCountSubmit.get();
		}catch (InterruptedException | ExecutionException e) {
			LOGGER.error("获取资源服务数量错误: {}==", e);
		}
		try {
			mapBookGroupQrcodeServeCount = mapBookGroupQrcodeSubmit.get();
		} catch (InterruptedException | ExecutionException e) {
			LOGGER.error("批量获取书下的资源数错误: {}==", e);
		}
		try {
			mapBookGroupRobotServeCount = mapBookGroupRobotServeCountSubmit.get();
		} catch (InterruptedException | ExecutionException e) {
			LOGGER.error("批量获取书下的资源数小睿错误: {}==", e);
		}
		try {
			raysCodeServeCount = raysCodeServeCountSubmit.get();
		} catch (InterruptedException | ExecutionException e) {
			LOGGER.error("批量获取rays码下的资源数量错误: {}==", e);
		}
		/*try {
			rightsMap = rightsMapSubmit.get();
		} catch (InterruptedException | ExecutionException e) {
			LOGGER.error("获取权益数量错误: {}==", e);
		}*/
		if(mapQrcodeMessage == null || mapQrcodeMessage.isEmpty()){
			mapQrcodeMessage = new HashMap<>();
		}
		if(mapBookGroupServeCount == null || mapBookGroupServeCount.isEmpty()){
			mapBookGroupServeCount = new HashMap<>();
		}
		if(mapBookGroupQrcodeServeCount == null || mapBookGroupQrcodeServeCount.isEmpty()){
			mapBookGroupQrcodeServeCount = new HashMap<>();
		}
		if(mapBookGroupRobotServeCount == null || mapBookGroupRobotServeCount.isEmpty()){
			mapBookGroupRobotServeCount = new HashMap<>();
		}
		List<String> bookChannelAdviserIds = mapQrcodeMessage.keySet().stream().collect(Collectors.toList());
		bookChannelAdviserIds.addAll(mapRaysCodeMessage.keySet().stream().collect(Collectors.toList()));
		bookChannelAdviserIds.addAll(mapBookGroupServeCount.keySet().stream().collect(Collectors.toList()));
		bookChannelAdviserIds.addAll(mapBookGroupQrcodeServeCount.keySet().stream().collect(Collectors.toList()));
		bookChannelAdviserIds.addAll(mapBookGroupRobotServeCount.keySet().stream().collect(Collectors.toList()));
		bookChannelAdviserIds = bookChannelAdviserIds.stream().distinct().collect(Collectors.toList());

		//处理渠道查询二维码rays码的资源数量,从book出数量
		if(CollUtil.isNotEmpty(mapRaysCodeMessage)){
			for (Entry<String, QrcodeMessageDTO> entry : mapRaysCodeMessage.entrySet()) {
				if(CollUtil.isNotEmpty(raysCodeServeCount) && raysCodeServeCount.containsKey(entry.getKey())){
					//book这边rays码的资源
						BookGroupServeCountDTO bookGroupServeCountDTO = raysCodeServeCount.get(entry.getKey());
						if (null != bookGroupServeCountDTO) {
							entry.getValue().setServeCount(null!=bookGroupServeCountDTO.getServeCount() ? bookGroupServeCountDTO.getServeCount() : 0);
						}
				}
			}
		}

		// 处理权益数
	/*	if(rightsMap!=null && !rightsMap.isEmpty()){
			for (BookGroupServeCountDTO bookGroupServeCountDTO : mapBookGroupServeCount.values()) {
				if(!JoinGroupTypeEnum.XIAORUI.getCode().equals(bookGroupServeCountDTO.getJoinGroupType())){
					continue;
				}
				// 如果是小睿码，则显示权益数
				Integer count = rightsMap.get(bookGroupServeCountDTO.getBookId());
				bookGroupServeCountDTO.setRightsCount(count);
			}
		}*/

		BookResourceStatisticsDTO bookResourceStatisticsDTO;
		for (String bookChannelAdviserId : bookChannelAdviserIds) {
			// mapBookGroupServeCount 包含了（客服机器人、1v1、小睿）
			// mapBookGroupRobotServeCount 查的是1v1
			// 他们是同一个码，所以只能算一个码数量
			boolean added = false;

			bookResourceStatisticsDTO = new BookResourceStatisticsDTO();
			QrcodeMessageDTO qrcodeMessageDTO = mapQrcodeMessage.get(bookChannelAdviserId);
			QrcodeMessageDTO raysCodeMessageDTO = mapRaysCodeMessage.get(bookChannelAdviserId);
			BookGroupServeCountDTO bookQrcodeWxwork = mapWxworkServeCount.get(bookChannelAdviserId);
			BookGroupServeCountDTO bookGroupServeCountDTO = mapBookGroupServeCount.get(bookChannelAdviserId);
			BookGroupServeCountDTO bookGroupQrcodeServeCountDTO = mapBookGroupQrcodeServeCount.get(bookChannelAdviserId);
			BookGroupServeCountDTO bookGroupRobotServeCountDTO = mapBookGroupRobotServeCount.get(bookChannelAdviserId);
			if(qrcodeMessageDTO != null){
				if(StringUtil.isEmpty(bookResourceStatisticsDTO.getBookChannelAdviserId())){
					BeanUtils.copyProperties(qrcodeMessageDTO, bookResourceStatisticsDTO);
					bookResourceStatisticsDTO.setQrcodeCount(0);
					bookResourceStatisticsDTO.setServeCount(0);
				}
				// 企业微信
				if(bookQrcodeWxwork != null){
					bookResourceStatisticsDTO.setServeCount(bookResourceStatisticsDTO.getServeCount() + bookQrcodeWxwork.getServeCount());
				}
				bookResourceStatisticsDTO.setServeCount(bookResourceStatisticsDTO.getServeCount() + qrcodeMessageDTO.getServeCount());
				bookResourceStatisticsDTO.setQrcodeCount(bookResourceStatisticsDTO.getQrcodeCount() + qrcodeMessageDTO.getQrcodeCount());
			}
			if(raysCodeMessageDTO != null){
				if(StringUtil.isEmpty(bookResourceStatisticsDTO.getBookChannelAdviserId())){
					BeanUtils.copyProperties(raysCodeMessageDTO, bookResourceStatisticsDTO);
					bookResourceStatisticsDTO.setQrcodeCount(0);
					bookResourceStatisticsDTO.setServeCount(0);
				}
				bookResourceStatisticsDTO.setServeCount(bookResourceStatisticsDTO.getServeCount() + raysCodeMessageDTO.getServeCount());
				bookResourceStatisticsDTO.setQrcodeCount(bookResourceStatisticsDTO.getQrcodeCount() + raysCodeMessageDTO.getQrcodeCount());
			}
			if(bookGroupServeCountDTO != null){
				if(StringUtil.isEmpty(bookResourceStatisticsDTO.getBookChannelAdviserId())){
					BeanUtils.copyProperties(bookGroupServeCountDTO, bookResourceStatisticsDTO);
					bookResourceStatisticsDTO.setQrcodeCount(0);
					bookResourceStatisticsDTO.setServeCount(0);
				}
				bookResourceStatisticsDTO.setServeCount(bookResourceStatisticsDTO.getServeCount() + bookGroupServeCountDTO.getServeCount());
				if(!added){
					bookResourceStatisticsDTO.setQrcodeCount(bookResourceStatisticsDTO.getQrcodeCount() + bookGroupServeCountDTO.getQrcodeCount());
					added = true;
				}
			}
			if(bookGroupQrcodeServeCountDTO != null){
				if(StringUtil.isEmpty(bookResourceStatisticsDTO.getBookChannelAdviserId())){
					BeanUtils.copyProperties(bookGroupQrcodeServeCountDTO, bookResourceStatisticsDTO);
					bookResourceStatisticsDTO.setQrcodeCount(0);
					bookResourceStatisticsDTO.setServeCount(0);
				}
				bookResourceStatisticsDTO.setServeCount(bookResourceStatisticsDTO.getServeCount() + bookGroupQrcodeServeCountDTO.getServeCount());
				bookResourceStatisticsDTO.setQrcodeCount(bookResourceStatisticsDTO.getQrcodeCount() + bookGroupQrcodeServeCountDTO.getQrcodeCount());
			}
			if(bookGroupRobotServeCountDTO != null){
				if(StringUtil.isEmpty(bookResourceStatisticsDTO.getBookChannelAdviserId())){
					BeanUtils.copyProperties(bookGroupRobotServeCountDTO, bookResourceStatisticsDTO);
					bookResourceStatisticsDTO.setQrcodeCount(0);
					bookResourceStatisticsDTO.setServeCount(0);
				}
				bookResourceStatisticsDTO.setServeCount(bookResourceStatisticsDTO.getServeCount() + bookGroupRobotServeCountDTO.getServeCount());
				if(!added) {
					bookResourceStatisticsDTO.setQrcodeCount(bookResourceStatisticsDTO.getQrcodeCount() + bookGroupRobotServeCountDTO.getQrcodeCount());
					added = true;
				}
			}
			// 设置默认值
			int rightsCount = 0;
			if(bookGroupServeCountDTO != null && null!=bookGroupServeCountDTO.getJoinGroupType() && JoinGroupTypeEnum.XIAORUI.getCode().equals(bookGroupServeCountDTO.getJoinGroupType())) {
				// 如果是小睿码，则设置权益数
			//	rightsCount = null == bookGroupServeCountDTO.getRightsCount() ? 0 : bookGroupServeCountDTO.getRightsCount();
			}
			bookResourceStatisticsDTO.setRightsCount(rightsCount);
			bookResourceStatisticsDTO.setServeTotalCount(bookResourceStatisticsDTO.getServeCount() + rightsCount);
			bookResourceStatisticsDTO.setServeTotalCount(bookResourceStatisticsDTO.getServeCount());
			mapBookResourceStatistics.put(bookChannelAdviserId, bookResourceStatisticsDTO);
		}
		return mapBookResourceStatistics;
	}

	@Override
	public Map<String, BookDataStatisticsDTO> mapBookDataStatistics(List<Long> adviserIds, List<Long> bookIds, List<Long> channelIds) {
		if(CollectionUtils.isEmpty(adviserIds) || CollectionUtils.isEmpty(bookIds) || CollectionUtils.isEmpty(channelIds)){
			throw new ChannelBizException(ChannelBizException.FILED_NULL, "adviserIds、bookIds、channelIds 参数为空！");
		}
		Map<String, BookDataStatisticsDTO> resultMap = new HashMap<>();
		BookDataStatisticsDTO bookDataStatisticsDTO;
		// 获取配置了书刊权益的书
		// Future<Map<Long, RightsSettingDto>> rightsMapSubmit = ThreadPoolUtils.OTHER_THREAD_POOL.submit(() -> rightsSettingBiz.listByBookIds(bookIds));
		Future<Map<String, BrowseCacheRecordDto>> bookScanAndUvSubmit = ThreadPoolUtils.OTHER_THREAD_POOL.submit(() -> browseRecordConsr.getBookScanAndUv(adviserIds, channelIds, bookIds));
		Future<Map<String, BookAdviserDto>> bookAdviserSubmit = ThreadPoolUtils.OTHER_THREAD_POOL.submit(() -> bookAdviserBiz.getBookInfoByBookIds(bookIds, adviserIds, channelIds));



		// 获取现代纸书统计数据
		Map<String, BrowseCacheRecordDto> bookScanAndUv = new HashMap<>();
		/*
		Map<Long, RightsSettingDto> rightsMap = new HashMap<>();
		try {
			rightsMap = rightsMapSubmit.get();
		} catch (InterruptedException | ExecutionException e) {
			LOGGER.error("获取配置了书刊权益的书错误: {}==", e);
		}
		*/
		try {
			bookScanAndUv = bookScanAndUvSubmit.get(ThreadPoolUtils.REMOTE_TIME_OUT, TimeUnit.SECONDS);
		} catch (InterruptedException | ExecutionException | TimeoutException e) {
			LOGGER.error("获取现代纸书统计数据错误: {}==", e);
		}

		Map<String, BookAdviserDto> bookAdviserDtoMap = new HashMap<>();
		try {
			bookAdviserDtoMap = bookAdviserSubmit.get(ThreadPoolUtils.REMOTE_TIME_OUT, TimeUnit.SECONDS);
		} catch (InterruptedException | ExecutionException | TimeoutException e) {
			LOGGER.error("获取现代纸书是否小睿流程错误: {}==", e);
		}

		// 根据条件筛选出社群书数据
		List<BookGroupDTO> bookGroupList = bookGroupDao.getDTOByBookIdsAdviserIdsChannelIds(bookIds, adviserIds, channelIds);
		if(!CollectionUtils.isEmpty(bookGroupList)){
			List<Long> bookGroupIds = bookGroupList.stream().map(x -> x.getId()).collect(Collectors.toList());
			Future<Map<Long, GroupUserCountDTO>> scanCountByGroupSubmit = ThreadPoolUtils.OTHER_THREAD_POOL.submit(() -> wechatGroupConsr.getScanCountByGroup(bookGroupIds, null));
			Map<Long, GroupUserCountDTO> scanCountByGroup = new HashMap<>();
			try {
				scanCountByGroup = scanCountByGroupSubmit.get(ThreadPoolUtils.REMOTE_TIME_OUT, TimeUnit.SECONDS);
			} catch (InterruptedException | ExecutionException | TimeoutException e) {
				LOGGER.error("获取社群码扫码次数/人数错误: {}==", e);
			}

			for (BookGroupDTO bookGroupDTO : bookGroupList) {
				GroupUserCountDTO groupUserCountDTO = scanCountByGroup.get(bookGroupDTO.getId());
				bookDataStatisticsDTO = new BookDataStatisticsDTO();
				bookDataStatisticsDTO.setBookChannelAdviserId(bookGroupDTO.getBookId()+"_"+bookGroupDTO.getChannelId()+"_"+bookGroupDTO.getCreateUser());
				bookDataStatisticsDTO.setAdviserId(bookGroupDTO.getCreateUser());
				bookDataStatisticsDTO.setBookId(bookGroupDTO.getBookId());
				bookDataStatisticsDTO.setChannelId(bookGroupDTO.getChannelId());
                bookDataStatisticsDTO.setScanCount(0L);
                bookDataStatisticsDTO.setUserCount(0L);
                if(groupUserCountDTO != null){
                    bookDataStatisticsDTO.setScanCount(groupUserCountDTO.getCount().longValue());
                    bookDataStatisticsDTO.setUserCount(groupUserCountDTO.getUserCount().longValue());
                }
				if(resultMap.containsKey(bookDataStatisticsDTO.getBookChannelAdviserId())){
                    BookDataStatisticsDTO bookDataStatisticsDTO1 = resultMap.get(bookDataStatisticsDTO.getBookChannelAdviserId());
                    if(null!=bookDataStatisticsDTO1){
                        bookDataStatisticsDTO.setScanCount(bookDataStatisticsDTO1.getScanCount() + bookDataStatisticsDTO.getScanCount());
                        bookDataStatisticsDTO.setUserCount(bookDataStatisticsDTO1.getUserCount() + bookDataStatisticsDTO.getUserCount());
                    }
                }
				bookDataStatisticsDTO.setBookCategory(JoinGroupTypeEnum.getBookTypeName(bookGroupDTO.getJoinGroupType()));
				bookDataStatisticsDTO.setJoinGroupType(bookGroupDTO.getJoinGroupType());
				/*if(rightsMap.containsKey(bookGroupDTO.getBookId())){
					bookDataStatisticsDTO.setBookCategory(JoinGroupTypeEnum.getBookTypeName(bookGroupDTO.getJoinGroupType()) + "(已配置书刊权益)");
				}*/
				resultMap.put(bookDataStatisticsDTO.getBookChannelAdviserId(), bookDataStatisticsDTO);
			}
		}
		// 综合
		for (BrowseCacheRecordDto browseCacheRecordDto : bookScanAndUv.values()) {
			String bookChannelAdviserId = browseCacheRecordDto.getJournalId() + "_" + browseCacheRecordDto.getChannelId() + "_" + browseCacheRecordDto.getAdviserId();
			bookDataStatisticsDTO = resultMap.get(bookChannelAdviserId);
			if(bookDataStatisticsDTO != null){
				bookDataStatisticsDTO.setScanCount(bookDataStatisticsDTO.getScanCount() + browseCacheRecordDto.getScanCount());
				bookDataStatisticsDTO.setUserCount(bookDataStatisticsDTO.getUserCount() + browseCacheRecordDto.getBrowserCounts());
				bookDataStatisticsDTO.setBookCategory("现代纸书、" + JoinGroupTypeEnum.getBookTypeName(bookDataStatisticsDTO.getJoinGroupType()));
				/*if(rightsMap.containsKey(browseCacheRecordDto.getJournalId())){
					bookDataStatisticsDTO.setBookCategory("现代纸书、社群书(已配置书刊权益)");
				}*/
				continue;
			}
			bookDataStatisticsDTO = new BookDataStatisticsDTO();
			bookDataStatisticsDTO.setBookChannelAdviserId(bookChannelAdviserId);
			bookDataStatisticsDTO.setAdviserId(browseCacheRecordDto.getAdviserId());
			bookDataStatisticsDTO.setBookId(browseCacheRecordDto.getJournalId());
			bookDataStatisticsDTO.setChannelId(browseCacheRecordDto.getChannelId());
			bookDataStatisticsDTO.setScanCount(browseCacheRecordDto.getScanCount());
			bookDataStatisticsDTO.setUserCount(browseCacheRecordDto.getBrowserCounts());
			bookDataStatisticsDTO.setBookCategory("现代纸书");
			resultMap.put(bookDataStatisticsDTO.getBookChannelAdviserId(), bookDataStatisticsDTO);
		}
		// 判断现代纸书是否开启小睿流程
		for (BookAdviserDto dto : bookAdviserDtoMap.values()) {
			String bookChannelAdviserId = dto.getBookId() + "_" + dto.getChannelId() + "_" + dto.getAdviserId() ;
			bookDataStatisticsDTO = resultMap.get(bookChannelAdviserId);
			if(bookDataStatisticsDTO != null){
				if(YesOrNoNumEnum.YES.getValue().equals(dto.getIsOpenRobotProcess()) && bookDataStatisticsDTO.getBookCategory().indexOf("小睿书") == -1){
					bookDataStatisticsDTO.setBookCategory(bookDataStatisticsDTO.getBookCategory()+"、小睿书");
				}
				continue;
			}
			bookDataStatisticsDTO = new BookDataStatisticsDTO();
			bookDataStatisticsDTO.setBookChannelAdviserId(bookChannelAdviserId);
			bookDataStatisticsDTO.setAdviserId(dto.getAdviserId());
			bookDataStatisticsDTO.setBookId(dto.getBookId());
			bookDataStatisticsDTO.setChannelId(dto.getChannelId());
			bookDataStatisticsDTO.setBookCategory(YesOrNoNumEnum.YES.getValue().equals(dto.getIsOpenRobotProcess()) ? "小睿书" : "现代纸书");
			resultMap.put(bookDataStatisticsDTO.getBookChannelAdviserId(), bookDataStatisticsDTO);
		}
		return resultMap;
	}

	@Override
	public Integer getBookCountByAgentAndTime(Long agentId, String startTime, String endTime) {
		List<Long> adviserIds = adviserConsr.getByAgentId(agentId);
		Integer bookCount = 0;
		if (!ListUtils.isEmpty(adviserIds)) {
			bookCount = bookAdviserDao.getBookCountByTime(adviserIds, startTime, endTime);
		}
		return bookCount;
	}

	@Override
	public Map<String, BookQrcodeStatisticsDTO> mapBookQrcodeStatistics(List<Long> adviserIds, List<Long> bookIds, List<Long> channelIds) {
		Map<String, BookQrcodeStatisticsDTO> resultMap = new HashMap<>();
		BookQrcodeStatisticsDTO bookQrcodeStatisticsDTO;
		//是否小睿教育的书
		List<Long> xiaoRuiEducation =CollUtil.isEmpty(bookIds) ? new ArrayList<>() : channelConsr.isXiaoRuiEducation(bookIds);
		// 社群书统计
		//JoinGroupTypeEnum.XIAORUI的码迁到渠道了。不走这里查)
		List<BookGroupDTO> bookGroupList = bookGroupDao.getDTOByBookIdsAdviserIdsChannelIds(bookIds, adviserIds, channelIds);
		//计算每个二维码下面的资源数量
		Map<Long, BookGroupServeCountDTO> groupQrCodeMap=new HashMap<>();
		Map<Long, BookGroupServeCountDTO> xiaoruiMap=new HashMap<>();
		Set<Long> groupQrcodeSet=new HashSet<>();
		Set<Long> xiaoruiSet=new HashSet<>();
		List<QrCodeVO> qrCodeVOS = new ArrayList<>();
		if(CollUtil.isNotEmpty(bookGroupList)){
			for (BookGroupDTO bookGroupDTO : bookGroupList) {
				Integer joinGroupType = bookGroupDTO.getJoinGroupType();
				if(null!=joinGroupType){
					//群二维码和客服机器人
					if(JoinGroupTypeEnum.GROUP_QRCODE.getCode().equals(joinGroupType) || JoinGroupTypeEnum.ROBOT.getCode().equals(joinGroupType)){
						groupQrcodeSet.add(bookGroupDTO.getId());
					}
					//（**不包括群二维码，小睿）资源数量
					if(!JoinGroupTypeEnum.GROUP_QRCODE.getCode().equals(joinGroupType)){
						xiaoruiSet.add(bookGroupDTO.getId());
					}
				}
			}
			List<Long> groupQrcodeList = new ArrayList<>(groupQrcodeSet);
			List<Long> xiaoruiList = new ArrayList<>(xiaoruiSet);
			//分开查3种类型的资源数量
			//群二维码和客服机器人
			groupQrCodeMap =CollUtil.isEmpty(groupQrcodeList) ? new HashMap<>() : bookGroupServeDao.mapGroupQrcodeServeCount(groupQrcodeList);
			//（**不包括群二维码，小睿）资源数量
			xiaoruiMap =CollUtil.isEmpty(xiaoruiList) ? new HashMap<>() : bookGroupServeDao.mapXiaoRuiGroupQrcodeServeCount(xiaoruiList);
		}
		if(CollUtil.isNotEmpty(bookGroupList)){
			bookGroupList = bookGroupList.stream().filter(a -> null != a.getJoinGroupType() && !JoinGroupTypeEnum.XIAORUI.getCode().equals(a.getJoinGroupType())).collect(Collectors.toList());
		}
        if(!CollectionUtils.isEmpty(bookGroupList)){
			List<Long> bookGroupIds = bookGroupList.stream().map(x -> x.getId()).collect(Collectors.toList());
			Map<Long, GroupUserCountDTO> scanCountByGroup = wechatGroupConsr.getScanCountByGroup(bookGroupIds, null);

			for (BookGroupDTO bookGroupDTO : bookGroupList) {
				GroupUserCountDTO groupUserCountDTO = scanCountByGroup.get(bookGroupDTO.getId());
				String bookAdviserId = bookGroupDTO.getBookId() + "_" + bookGroupDTO.getChannelId() + "_" + bookGroupDTO.getCreateUser();
				bookQrcodeStatisticsDTO = new BookQrcodeStatisticsDTO();
				bookQrcodeStatisticsDTO.setBookChannelAdviserId(bookGroupDTO.getBookId()+"_"+bookGroupDTO.getChannelId()+"_"+bookGroupDTO.getCreateUser());
				bookQrcodeStatisticsDTO.setAdviserId(bookGroupDTO.getCreateUser());
				bookQrcodeStatisticsDTO.setBookId(bookGroupDTO.getBookId());
				bookQrcodeStatisticsDTO.setChannelId(bookGroupDTO.getChannelId());

				QrcodeStatisticsDTO qrcodeStatisticsDTO = new QrcodeStatisticsDTO();
				qrcodeStatisticsDTO.setId(bookGroupDTO.getId());
				qrcodeStatisticsDTO.setQrcodeName(bookGroupDTO.getGroupQrcodeName());
				qrcodeStatisticsDTO.setQrcodeUrl(bookGroupDTO.getGroupQrcodeUrl());
				qrcodeStatisticsDTO.setCounts(0L);
				qrcodeStatisticsDTO.setBrowserCounts(0L);
				qrcodeStatisticsDTO.setServeCount(0);
				qrcodeStatisticsDTO.setCodeType("group");
				qrcodeStatisticsDTO.setXiaoRuiEducation(false);
				if(CollUtil.isNotEmpty(xiaoRuiEducation) && xiaoRuiEducation.contains(bookGroupDTO.getBookId())){
					qrcodeStatisticsDTO.setXiaoRuiEducation(true);
				}
				if(groupUserCountDTO != null){
					qrcodeStatisticsDTO.setCounts(groupUserCountDTO.getCount().longValue());
					qrcodeStatisticsDTO.setBrowserCounts(groupUserCountDTO.getUserCount().longValue());
				}
				if(JoinGroupTypeEnum.GROUP_QRCODE.getCode().equals(bookGroupDTO.getJoinGroupType())){
					if(CollUtil.isNotEmpty(groupQrCodeMap) && groupQrCodeMap.containsKey(bookGroupDTO.getId())){
						BookGroupServeCountDTO bookGroupServeCountDTO = groupQrCodeMap.get(bookGroupDTO.getId());
						qrcodeStatisticsDTO.setServeCount(bookGroupServeCountDTO.getServeCount());
					}
				}else{
					if(CollUtil.isNotEmpty(xiaoruiMap) && xiaoruiMap.containsKey(bookGroupDTO.getId())){
						BookGroupServeCountDTO bookGroupServeCountDTO = xiaoruiMap.get(bookGroupDTO.getId());
						qrcodeStatisticsDTO.setServeCount(bookGroupServeCountDTO.getServeCount());
					}
					if(JoinGroupTypeEnum.ROBOT.getCode().equals(bookGroupDTO.getJoinGroupType())){
						if(CollUtil.isNotEmpty(groupQrCodeMap) && groupQrCodeMap.containsKey(bookGroupDTO.getId())){
							BookGroupServeCountDTO bookGroupServeCountDTO = groupQrCodeMap.get(bookGroupDTO.getId());
							if(null!=bookGroupServeCountDTO && null!=bookGroupServeCountDTO.getServeCount()) {
								qrcodeStatisticsDTO.setServeCount((null == qrcodeStatisticsDTO.getServeCount() ? 0 : qrcodeStatisticsDTO.getServeCount()) + bookGroupServeCountDTO.getServeCount());
							}
						}
					}
				}
				qrcodeStatisticsDTO.setTotalCount(qrcodeStatisticsDTO.getServeCount());
                bookQrcodeStatisticsDTO.getQrcodeSceneDtoList().add(qrcodeStatisticsDTO);
                bookQrcodeStatisticsDTO.setQrcodeSceneDtoList(Lists.newArrayList(qrcodeStatisticsDTO));
                if(resultMap.containsKey(bookQrcodeStatisticsDTO.getBookChannelAdviserId())){
                    BookQrcodeStatisticsDTO bookQrcodeStatisticsDTO1 = resultMap.get(bookQrcodeStatisticsDTO.getBookChannelAdviserId());
                    if(null!=bookQrcodeStatisticsDTO1 && CollUtil.isNotEmpty(bookQrcodeStatisticsDTO1.getQrcodeSceneDtoList())){
                        List<QrcodeStatisticsDTO> qrcodeSceneDtoList = bookQrcodeStatisticsDTO1.getQrcodeSceneDtoList();
                        qrcodeSceneDtoList.add(qrcodeStatisticsDTO);
                        bookQrcodeStatisticsDTO.setQrcodeSceneDtoList(qrcodeSceneDtoList);
                    }
                }
                resultMap.put(bookQrcodeStatisticsDTO.getBookChannelAdviserId(), bookQrcodeStatisticsDTO);
			}
		}

		// 现代纸书统计
		List<QrcodeSceneDto> qrcodeSceneDtos = channelConsr.listQrcodeScene(adviserIds, bookIds, channelIds);
		if(CollectionUtils.isEmpty(qrcodeSceneDtos)){
			qrcodeSceneDtos = Lists.newArrayList();
		}
		List<Long> sceneIds =CollUtil.isEmpty(qrcodeSceneDtos) ? new ArrayList<>() : qrcodeSceneDtos.stream().map(x -> x.getSceneId()).collect(Collectors.toList());
		//公众号二维码
		List<Long> qrCodeSceneIds =CollUtil.isEmpty(qrcodeSceneDtos) ? new ArrayList<>() : qrcodeSceneDtos.stream().filter(a->null!=a.getQrcodeType()
				&& "wechat".equalsIgnoreCase(a.getQrcodeType())).map(x -> x.getSceneId()).collect(Collectors.toList());
		//之前小睿的码。现在叫rays码
		List<Long> ruiList =CollUtil.isEmpty(qrcodeSceneDtos) ? new ArrayList<>() : qrcodeSceneDtos.stream().filter(a->null!=a.getQrcodeType()
				&& ("ali".equalsIgnoreCase(a.getQrcodeType()) || "own".equalsIgnoreCase(a.getQrcodeType()))
		).map(x -> x.getSceneId()).collect(Collectors.toList());
		//小睿的资源数量。要在resource_page_item查
		Map<Long, BookGroupServeCountDTO> ruiMap=CollUtil.isNotEmpty(ruiList) ? resourcePageItemDao.mapQrServeCount(ruiList) : new HashMap<>();
		// 企业微信群资源数
		Map<Long, BookGroupServeCountDTO> bookQrcodeWxworkMap =CollUtil.isEmpty(sceneIds) ? new HashMap<>() : bookQrcodeWxworkBiz.mapWxWorkServeCount4SceneIds(sceneIds, BookQrcodeType.OFFICIAL_ACCOUNTS.getCode());
		// 查询图书是否开启小睿流程
		Map<String, BookAdviserDto> bookAdviserMap = bookAdviserBiz.getBookInfoByBookIds(bookIds, adviserIds, channelIds);
		String bookChannelAdviserId;
		String bookAdviserChannelId;
		for (QrcodeSceneDto qrcodeSceneDto : qrcodeSceneDtos) {
			bookChannelAdviserId = qrcodeSceneDto.getAdviserBookId() + "_" + qrcodeSceneDto.getChannelPartyId() + "_" + qrcodeSceneDto.getAdviserId();
			bookQrcodeStatisticsDTO = resultMap.get(bookChannelAdviserId);
			if(bookQrcodeStatisticsDTO == null){
				bookQrcodeStatisticsDTO = new BookQrcodeStatisticsDTO();
				bookQrcodeStatisticsDTO.setBookChannelAdviserId(bookChannelAdviserId);
				bookQrcodeStatisticsDTO.setAdviserId(qrcodeSceneDto.getAdviserId());
				bookQrcodeStatisticsDTO.setBookId(qrcodeSceneDto.getAdviserBookId());
				bookQrcodeStatisticsDTO.setChannelId(qrcodeSceneDto.getChannelPartyId());
				bookAdviserChannelId = qrcodeSceneDto.getAdviserBookId() + "_" + qrcodeSceneDto.getAdviserId() + "_" + qrcodeSceneDto.getChannelPartyId();
				if(CollUtil.isNotEmpty(bookAdviserMap) && bookAdviserMap.containsKey(bookAdviserChannelId)){
					bookQrcodeStatisticsDTO.setIsOpenRobotProcess(bookAdviserMap.get(bookAdviserChannelId).getIsOpenRobotProcess());
				}
				resultMap.put(bookQrcodeStatisticsDTO.getBookChannelAdviserId(), bookQrcodeStatisticsDTO);
			}
			QrcodeStatisticsDTO qrcodeStatisticsDTO = new QrcodeStatisticsDTO();
			qrcodeStatisticsDTO.setId(qrcodeSceneDto.getSceneId());
			qrcodeStatisticsDTO.setQrcodeName(qrcodeSceneDto.getSceneName());
			qrcodeStatisticsDTO.setQrcodeUrl(qrcodeSceneDto.getQrcodeUrl());
			qrcodeStatisticsDTO.setCounts(qrcodeSceneDto.getCounts());
			qrcodeStatisticsDTO.setBrowserCounts(qrcodeSceneDto.getBrowserCounts());
			//设置二维码类型和二维码下面配置的资源数量。一般资源和企业微信数量
			qrcodeStatisticsDTO.setCodeType(qrcodeSceneDto.getQrcodeType());
			qrcodeStatisticsDTO.setServeCount(qrcodeSceneDto.getServeCount());
			if(CollUtil.isNotEmpty(ruiMap) && ruiMap.containsKey(qrcodeSceneDto.getSceneId())){
				BookGroupServeCountDTO bookGroupServeCountDTO = ruiMap.get(qrcodeSceneDto.getSceneId());
				if(null!=bookGroupServeCountDTO && null!=bookGroupServeCountDTO.getServeCount()){
					qrcodeStatisticsDTO.setServeCount(bookGroupServeCountDTO.getServeCount());
				}
			}
			//计算公众号二维码下面的资源数（包括普通资源和配置的企业微信数量）
			if(CollUtil.isNotEmpty(qrCodeSceneIds) && qrCodeSceneIds.contains(qrcodeSceneDto.getSceneId())){
				if(CollUtil.isNotEmpty(bookQrcodeWxworkMap) && bookQrcodeWxworkMap.containsKey(qrcodeSceneDto.getSceneId())){
					BookGroupServeCountDTO bookGroupServeCountDTO = bookQrcodeWxworkMap.get(qrcodeSceneDto.getSceneId());
					if(null!=bookGroupServeCountDTO && null!=bookGroupServeCountDTO.getServeCount()){
						qrcodeStatisticsDTO.setServeCount((null==qrcodeSceneDto.getServeCount() ? 0 : qrcodeSceneDto.getServeCount()) + bookGroupServeCountDTO.getServeCount());
					}
				}
			}

			qrcodeStatisticsDTO.setXiaoRuiEducation(false);
			if(CollUtil.isNotEmpty(xiaoRuiEducation) && xiaoRuiEducation.contains(qrcodeSceneDto.getAdviserBookId())){
				qrcodeStatisticsDTO.setXiaoRuiEducation(true);
			}
			qrcodeStatisticsDTO.setTotalCount(qrcodeStatisticsDTO.getServeCount());
			bookQrcodeStatisticsDTO.getQrcodeSceneDtoList().add(qrcodeStatisticsDTO);
		}
		// 筛选出疑似未印刷的二维码（扫码人数<=20 || 扫码次数<=40）
		/*Iterator<BookQrcodeStatisticsDTO> iterator = resultMap.values().iterator();
		while(iterator.hasNext()) {
			BookQrcodeStatisticsDTO item = iterator.next();
			for (int i = item.getQrcodeSceneDtoList().size() - 1; i >= 0; i--) {
				QrcodeStatisticsDTO qrcodeStatisticsDTO = item.getQrcodeSceneDtoList().get(i);
				if(qrcodeStatisticsDTO.getBrowserCounts() <= 20 || qrcodeStatisticsDTO.getCounts() <= 40){
					continue;
				}
				item.getQrcodeSceneDtoList().remove(qrcodeStatisticsDTO);
				if(item.getQrcodeSceneDtoList().size() == 0){
					iterator.remove();
					resultMap.remove(item);
				}
			}
		}*/
		return resultMap;
	}

	@Override
	public PageBeanNew<QrcodeStatisticsDTO> getBookQrcodeStatistics(Long adviserId, Long bookId, Long channelId, Integer currentPage, Integer numPerPage) {
		if(!NumberUtil.isNumber(adviserId) || !NumberUtil.isNumber(bookId) || !NumberUtil.isNumber(channelId)){
			throw new BizException(BizException.PARAM_IS_NULL.getCode(), "参数不能为空");
		}
		Map<String, BookQrcodeStatisticsDTO> bookQrcodeStatisticsDTOMap = this.mapBookQrcodeStatistics(Lists.newArrayList(adviserId), Lists.newArrayList(bookId), Lists.newArrayList(channelId));
		if(MapUtils.isEmpty(bookQrcodeStatisticsDTOMap)){
			return new PageBeanNew<>(currentPage, numPerPage, 0, Lists.newArrayList());
		}
		String bookChannelAdviserId = bookId + "_" + channelId + "_" + adviserId;
		BookQrcodeStatisticsDTO bookQrcodeStatisticsDTO = bookQrcodeStatisticsDTOMap.get(bookChannelAdviserId);
		List<QrcodeStatisticsDTO> qrcodeSceneDtoList = bookQrcodeStatisticsDTO.getQrcodeSceneDtoList();
		if(CollectionUtils.isEmpty(qrcodeSceneDtoList)){
			return new PageBeanNew<>(currentPage, numPerPage, 0, Lists.newArrayList());
		}
		return new PageBeanNew(currentPage, numPerPage, qrcodeSceneDtoList.size(),qrcodeSceneDtoList.stream().skip(currentPage * numPerPage).limit(numPerPage).collect(Collectors.toList()));
	}


	@Override
	public Map<String, Object> getRayBookCountAndRate(Boolean showRate) {
		Map<String, Object> map = Maps.newHashMap();
		Long bookCount = bookAdviserDao.getRayBookCount(null, null);
		map.put("totalCount", bookCount);
		if (showRate) {
			//展示同比上周增长率
			String thisWeekStart = DateUtils.formatDate(DateUtils.getWeekStart(new Date()));
			Long thisWeekCount = bookAdviserDao.getRayBookCount(thisWeekStart, DateUtils.currentTime());
			Date lastWeekStart = DateUtils.addDay(DateUtils.getWeekStart(new Date()), -7);
			Date lastWeekEnd = DateUtils.addDay(new Date(), -7);
			Long lastWeekCount = bookAdviserDao.getRayBookCount(DateUtils.formatDate(lastWeekStart, DateUtils.DATE_FORMAT_DATETIME), DateUtils.formatDate(lastWeekEnd, DateUtils.DATE_FORMAT_DATETIME));
			Long addCount = thisWeekCount - lastWeekCount;
			BigDecimal rate = (lastWeekCount.equals(0L)) ? BigDecimal.ZERO :
					new BigDecimal(addCount.doubleValue() / lastWeekCount).setScale(4, BigDecimal.ROUND_HALF_UP);
			map.put("weekGrowthRate", rate);
		}
		return map;
	}

	@Override
	public Integer getIsRui(Long adviserId, Long bookId, Long channelId) {
		return bookAdviserDao.getIsRui(adviserId, bookId, channelId);
	}

	@Override
	public PageBeanNew<PcloudAdviserBookVO> listAdviserBook4Pcloud(String keyword, Integer currentPage, Integer numPerPage) {
		Map<String, Object> paramMap = new HashMap<>();
		paramMap.put("keyword", keyword);

		PageBeanNew<PcloudAdviserBookVO> pageBeanNew = bookAdviserDao.listPageNew(new PageParam(currentPage, numPerPage), paramMap, "listAdviserBook4Pcloud");
		List<PcloudAdviserBookVO> bookVOS = pageBeanNew.getRecordList();
		if(!CollectionUtils.isEmpty(bookVOS)) {
			List<Long> adviserIds = bookVOS.stream().filter(s -> s.getAdviserId() != null).map(PcloudAdviserBookVO::getAdviserId).distinct().collect(Collectors.toList());
			Map<Long, AdviserBaseInfoDto> adviserAgentMap = adviserConsr.getAdviserId2AdviserInfoDtoMap(adviserIds);
			for (PcloudAdviserBookVO bookVO : bookVOS) {
				Long adviserId = bookVO.getAdviserId();
				if(adviserId != null && MapUtils.isNotEmpty(adviserAgentMap) && adviserAgentMap.containsKey(adviserId)) {
					AdviserBaseInfoDto adviserBaseInfoDto = adviserAgentMap.get(adviserId);
					bookVO.setPublish(null != adviserBaseInfoDto ? adviserBaseInfoDto.getAgentName() : "--");
					bookVO.setAuthor(null != adviserBaseInfoDto ? adviserBaseInfoDto.getPartyName() : "--");
					bookVO.setAgentId(null != adviserBaseInfoDto ? adviserBaseInfoDto.getAgentId() : 0);
				}
			}
		}
		return pageBeanNew;
	}

    @Override
    public Map<String, BookAdviserDto> getBookInfoByBookIds(List<Long> bookIds, List<Long> adviserIds, List<Long> channelIds) {
		if(CollectionUtils.isEmpty(bookIds) || CollectionUtils.isEmpty(adviserIds) || CollectionUtils.isEmpty(channelIds)){
			return new HashMap<>();
		}
		List<BookAdviserDto> bookAdviserDtos = bookAdviserDao.getBookInfoByBookIds(bookIds, adviserIds, channelIds);
		if(CollectionUtils.isEmpty(bookAdviserDtos)){
			return new HashMap<>();
		}
		Map<String, BookAdviserDto> resultMap = new HashMap<>();
		for (BookAdviserDto bookAdviserDto : bookAdviserDtos) {
			String bookAdviserChannelId = bookAdviserDto.getBookId() + "_" + bookAdviserDto.getAdviserId() + "_" + bookAdviserDto.getChannelId();
			if(resultMap.containsKey(bookAdviserChannelId)){
				continue;
			}
			resultMap.put(bookAdviserChannelId, bookAdviserDto);
		}
        return resultMap;
    }

    @Override
	public BookAdviserDto getBookByBookIdAdviserId(Long bookId, Long adviserId){
		return bookAdviserDao.getBookByBookIdAdviserId(bookId,adviserId);
	}

	@Override
	public Map<Long, BookVarietyStatsDto> getAdviserBookVarietyStats(List<BookVarietyStatsRequestDto> requestDtos) {
		Map<Long, BookVarietyStatsDto> result = new HashMap<>();
		if (CollUtil.isEmpty(requestDtos)) {
			return result;
		}

		// agent -> adviser 映射 默认使用merge实现而不是put，如果出现key重复会调用mergeFunction方法，(key1, key2) -> key1
		Map<Long, List<Long>> map = requestDtos.stream().collect(Collectors.toMap(BookVarietyStatsRequestDto::getAgentId, BookVarietyStatsRequestDto::getAdviserIds, (key1, key2) -> key1));
		// adviser 集合
		List<Long> adviserIds = map.values().stream().flatMap(Collection::stream).distinct().collect(Collectors.toList());
		if (CollUtil.isEmpty(adviserIds)){
			return result;
		}
		// 查询 bookAdviser
		List<BookAdviserDto> bookAdviserDtos = bookAdviserDao.getAdviserBookVarietyStats(adviserIds);

		// 统计扫码量（人）及浏览量（人）
		List<BookBrowseAndScanStatsDTO> dtos = new ArrayList<>();
		bookAdviserDtos.forEach(dto -> {
			if (Objects.nonNull(dto)) {
				BookBrowseAndScanStatsDTO statsDTO = new BookBrowseAndScanStatsDTO();
				statsDTO.setAdviserId(dto.getAdviserId());
				statsDTO.setChannelId(dto.getChannelId());
				statsDTO.setBookId(dto.getBookId());
				dtos.add(statsDTO);
			}
		});
		// 分析引擎获取非社群书统计结果
		List<BookBrowseAndScanStatsDTO> browseAndScanStats = browseRecordConsr.getBookBrowseAndScanStats(dtos);

		// 微信群获取社群书统计结果
		List<GroupScanUserStatsDTO> bookGroupScanStats = wechatGroupConsr.getBookGroupScanStats(adviserIds);

		// 查询印册量
		List<ERPPublishNumDTO> finalPublishNumDto = new ArrayList<>();
		List<ERPPublishNumDTO> dataFromDB = bookAdviserDao.getErpPublishNumQueryParams(adviserIds);
		if (CollUtil.isNotEmpty(dataFromDB)) {
			List<ERPPublishNumDTO> dataFromErp = erpConsr.getBookExpectPublishNum(dataFromDB);
			// 根据ERP填充数据
			finalPublishNumDto = dataFromErp.stream().map(
					// 匹配 adviserId channelId bookId
					erpData -> dataFromDB.stream().filter(
							dbData -> Objects.equals(dbData.getAdviserId(), erpData.getAdviserId())
									&& Objects.equals(dbData.getBookId(), erpData.getBookId())
									&& Objects.equals(dbData.getChannelId(), erpData.getChannelId())
					).findFirst().map(
							// 填充印册量
							dbData -> {
								dbData.setExpectPublishNum(erpData.getExpectPublishNum());
								return dbData;
							}
					).orElse(null)
			).collect(Collectors.toList());

		}

		// 组装数据
		Set<Long> agentIds = map.keySet();
		for (Long agentId : agentIds) {
			BookVarietyStatsDto varietyStatsDto = null;
			if (CollUtil.isNotEmpty(bookAdviserDtos)) {
				varietyStatsDto = new BookVarietyStatsDto();

				// 统计做书品种
				List<BookAdviserDto> collect = bookAdviserDtos.stream().filter(x -> map.get(agentId).contains(x.getAdviserId())).collect(Collectors.toList());
				if (CollUtil.isNotEmpty(collect)) {
					// 累计做书品种数
					varietyStatsDto.setVarietyTotal((int) collect.stream().map(BookAdviserDto::getBookId).distinct().count());
					// 本季度做书品种数
					varietyStatsDto.setVarietyThisQuarter((int) collect.stream().filter(x -> getAgentQuarterDigital(x.getCreatedDate()) == getAgentQuarterDigital(new Date())).map(BookAdviserDto::getBookId).distinct().count());
					// 上季度做书品种数
					varietyStatsDto.
							setVarietyLastQuarter((int) collect.stream().filter(x -> getAgentQuarterDigital(x.getCreatedDate()) == getAgentLastQuarterDigital(new Date())).map(BookAdviserDto::getBookId).distinct().count());
				}

				if (CollUtil.isNotEmpty(browseAndScanStats)){
					List<BookBrowseAndScanStatsDTO> scanStatsDTOS = browseAndScanStats.stream().filter(x -> map.get(agentId).contains(x.getAdviserId())).collect(Collectors.toList());
					if (CollUtil.isNotEmpty(scanStatsDTOS)) {
						// 累计扫码量
						varietyStatsDto.setScanTotal(scanStatsDTOS.stream().filter(x->Objects.nonNull(x.getBookScanTotal())).mapToInt(BookBrowseAndScanStatsDTO::getBookScanTotal).sum());
						// 累计扫码人数
						varietyStatsDto.setScanUserTotal(scanStatsDTOS.stream().filter(x->Objects.nonNull(x.getBookScanUserTotal())).mapToInt(BookBrowseAndScanStatsDTO::getBookScanUserTotal).sum());
						// 累计浏览量
						varietyStatsDto.setBrowseTotal(scanStatsDTOS.stream().filter(x->Objects.nonNull(x.getBookBrowseTotal())).mapToInt(BookBrowseAndScanStatsDTO::getBookBrowseTotal).sum());
						// 累计浏览人数
						varietyStatsDto.setBrowseUserTotal(scanStatsDTOS.stream().filter(x->Objects.nonNull(x.getBookBrowseUserTotal())).mapToInt(BookBrowseAndScanStatsDTO::getBookBrowseUserTotal).sum());


						// 筛选本季度数据
						List<BookBrowseAndScanStatsDTO> thisQuarterCollect = scanStatsDTOS.stream().filter(
								x -> Objects.nonNull(x.getBookScanTotal()) && StrUtil.isNotBlank(x.getDateStr())
										&& getAgentQuarterDigital(DateUtil.parse(x.getDateStr(), "yyyyMM").toJdkDate()) == getAgentQuarterDigital(new Date())
						).collect(Collectors.toList());
						if (CollUtil.isNotEmpty(thisQuarterCollect)){
							// 本季度扫码量
							varietyStatsDto.setScanThisQuarter(thisQuarterCollect.stream().mapToInt(BookBrowseAndScanStatsDTO::getBookScanTotal).sum());
							// 本季度扫码人数
							varietyStatsDto.setScanUserThisQuarter(thisQuarterCollect.stream().mapToInt(BookBrowseAndScanStatsDTO::getBookScanUserTotal).sum());
							// 本季度浏览量
							varietyStatsDto.setBrowseThisQuarter(thisQuarterCollect.stream().mapToInt(BookBrowseAndScanStatsDTO::getBookBrowseTotal).sum());
							// 本季度浏览人数
							varietyStatsDto.setBrowseUserThisQuarter(thisQuarterCollect.stream().mapToInt(BookBrowseAndScanStatsDTO::getBookBrowseUserTotal).sum());
						}


						// 筛选上季度数据
						List<BookBrowseAndScanStatsDTO> lastQuarterCollect = scanStatsDTOS.stream().filter(
								x -> Objects.nonNull(x.getBookScanTotal()) && StrUtil.isNotBlank(x.getDateStr())
										&& getAgentQuarterDigital(DateUtil.parse(x.getDateStr(), "yyyyMM").toJdkDate()) == getAgentLastQuarterDigital(new Date())
						).collect(Collectors.toList());
						if (CollUtil.isNotEmpty(lastQuarterCollect)){
							// 上季度扫码量
							varietyStatsDto.setScanLastQuarter(lastQuarterCollect.stream().mapToInt(BookBrowseAndScanStatsDTO::getBookScanTotal).sum());
							// 上季度扫码人数
							varietyStatsDto.setScanUserLastQuarter(lastQuarterCollect.stream().mapToInt(BookBrowseAndScanStatsDTO::getBookScanUserTotal).sum());
							// 上季度浏览量
							varietyStatsDto.setBrowseLastQuarter(lastQuarterCollect.stream().mapToInt(BookBrowseAndScanStatsDTO::getBookBrowseTotal).sum());
							// 上季度浏览人数
							varietyStatsDto.setBrowseUserLastQuarter(lastQuarterCollect.stream().mapToInt(BookBrowseAndScanStatsDTO::getBookBrowseUserTotal).sum());
						}
					}
				}

				if (CollUtil.isNotEmpty(bookGroupScanStats)) {
					List<GroupScanUserStatsDTO> statsDTOS = bookGroupScanStats.stream().filter(x -> map.get(agentId).contains(x.getAdviserId())).collect(Collectors.toList());
					if (CollUtil.isNotEmpty(statsDTOS)) {

						// 扫码人数
						long scanUser = statsDTOS.stream().map(GroupScanUserStatsDTO::getWxUserId).distinct().count();
						// 扫码量
						int scan = statsDTOS.stream().filter(x->Objects.nonNull(x.getScanTotal())).mapToInt(groupScanUserStatsDTO -> Math.toIntExact(groupScanUserStatsDTO.getScanTotal())).sum();

						// 补充累计扫码量（社群书部分）
						varietyStatsDto.setScanTotal(varietyStatsDto.getScanTotal() == null ? scan : varietyStatsDto.getScanTotal() + scan);
						// 补充累计扫码人数（社群书部分）
						varietyStatsDto.setScanUserTotal(Math.toIntExact(varietyStatsDto.getScanUserTotal() == null ? scanUser : varietyStatsDto.getScanUserTotal() + scanUser));
						// 补充累计浏览量（社群书部分）
						varietyStatsDto.setBrowseTotal(varietyStatsDto.getBrowseTotal() == null ? scan : varietyStatsDto.getBrowseTotal() + scan);
						// 补充累计浏览量（社群书部分）
						varietyStatsDto.setBrowseUserTotal(varietyStatsDto.getBrowseUserTotal() == null ? (int) scanUser : (int) (varietyStatsDto.getBrowseUserTotal() + scanUser));


						// 筛选本季度
						List<GroupScanUserStatsDTO> thisQuarterCollect = statsDTOS.stream().filter(
								x -> Objects.nonNull(x.getCreateDay())
										&& getAgentQuarterDigital(x.getCreateDay()) == getAgentQuarterDigital(new Date())
						).collect(Collectors.toList());
						if (CollUtil.isNotEmpty(thisQuarterCollect)) {
							scan = thisQuarterCollect.stream().filter(x->Objects.nonNull(x.getScanTotal())).mapToInt(groupScanUserStatsDTO -> Math.toIntExact(groupScanUserStatsDTO.getScanTotal())).sum();
							scanUser = thisQuarterCollect.stream().map(GroupScanUserStatsDTO::getWxUserId).distinct().count();
							// 补充本季度扫码量（社群书部分）
							varietyStatsDto.setScanThisQuarter(varietyStatsDto.getScanThisQuarter() == null ? scan : varietyStatsDto.getScanThisQuarter() + scan);
							// 补充本季度扫码人数（社群书部分）
							varietyStatsDto.setScanUserThisQuarter(Math.toIntExact(varietyStatsDto.getScanUserThisQuarter() == null ? scanUser : varietyStatsDto.getScanUserThisQuarter() + scanUser));
							// 补充本季度浏览量（社群书部分）
							varietyStatsDto.setBrowseThisQuarter(varietyStatsDto.getBrowseThisQuarter() == null ? scan : varietyStatsDto.getBrowseThisQuarter() + scan);
							// 补充本季度浏览量（社群书部分）
							varietyStatsDto.setBrowseUserThisQuarter(varietyStatsDto.getBrowseUserThisQuarter() == null ? (int) scanUser : (int) (varietyStatsDto.getBrowseUserThisQuarter() + scanUser));
						}


						// 筛选上季度
						List<GroupScanUserStatsDTO> lastQuarterCollect = statsDTOS.stream().filter(
								x -> Objects.nonNull(x.getCreateDay())
										&& getAgentQuarterDigital(x.getCreateDay()) == getAgentLastQuarterDigital(new Date())
						).collect(Collectors.toList());
						if (CollUtil.isNotEmpty(thisQuarterCollect)) {
							scan = lastQuarterCollect.stream().filter(x->Objects.nonNull(x.getScanTotal())).mapToInt(groupScanUserStatsDTO -> Math.toIntExact(groupScanUserStatsDTO.getScanTotal())).sum();
							scanUser = lastQuarterCollect.stream().map(GroupScanUserStatsDTO::getWxUserId).distinct().count();
							// 补充上季度扫码量（社群书部分）
							varietyStatsDto.setScanLastQuarter(varietyStatsDto.getScanLastQuarter() == null ? scan : varietyStatsDto.getScanLastQuarter() + scan);
							// 补充上季度扫码人数（社群书部分）
							varietyStatsDto.setScanUserLastQuarter(Math.toIntExact(varietyStatsDto.getScanUserLastQuarter() == null ? scanUser : varietyStatsDto.getScanUserLastQuarter() + scanUser));
							// 补充上季度浏览量（社群书部分）
							varietyStatsDto.setBrowseLastQuarter(varietyStatsDto.getBrowseLastQuarter() == null ? scan : varietyStatsDto.getBrowseLastQuarter() + scan);
							// 补充上季度浏览量（社群书部分）
							varietyStatsDto.setBrowseUserLastQuarter(varietyStatsDto.getBrowseUserLastQuarter() == null ? (int) scanUser : (int) (varietyStatsDto.getBrowseUserLastQuarter() + scanUser));
						}
					}
				}
			}



			// 统计印册量
			if (CollUtil.isNotEmpty(finalPublishNumDto)) {
				if (Objects.isNull(varietyStatsDto)) {
					varietyStatsDto = new BookVarietyStatsDto();
				}
				List<ERPPublishNumDTO> collect = finalPublishNumDto.stream().filter(x -> Objects.nonNull(x.getExpectPublishNum()) && map.get(agentId).contains(x.getAdviserId())).collect(Collectors.toList());
				if (CollUtil.isNotEmpty(collect)) {
					// 累计印刷量
					varietyStatsDto.setPrintTotal((int) collect.stream().mapToLong(ERPPublishNumDTO::getExpectPublishNum).sum());
					// 本季度印刷量
					varietyStatsDto.setPrintThisQuarter((int) collect.stream().filter(x -> getAgentQuarterDigital(x.getCreateDate()) == getAgentQuarterDigital(new Date())).mapToLong(ERPPublishNumDTO::getExpectPublishNum).sum());
					// 上季度印刷量
					varietyStatsDto.setPrintLastQuarter((int) collect.stream().filter(x -> getAgentQuarterDigital(x.getCreateDate()) == getAgentLastQuarterDigital(new Date())).mapToLong(ERPPublishNumDTO::getExpectPublishNum).sum());
				}
			}

			if (Objects.nonNull(varietyStatsDto)) {
				result.put(agentId, varietyStatsDto);
			}
		}
		return result;
	}

	@Override
	public PageBeanNew<AgentBookStatsDetailVO> getAgentBookStatsDetail(Long agentId, String name, Date startDate, Date endDate,
																	   Integer isRay, Integer currentPage, Integer numPerPage) {
		String cacheKey = String.format("%s_AGENT_BOOK_STATS_DETAIL_%s:%s:%s:%s:%s:%s:%s", CacheConstant.BOOK, agentId, name, startDate, endDate, isRay, currentPage, numPerPage);
		String cache = JedisClusterUtils.get(cacheKey);
		if (StrUtil.isNotBlank(cache)){
			PageBeanNew<AgentBookStatsDetailVO> pageBeanNew = JSONObject.parseObject(cache, new TypeReference<PageBeanNew<AgentBookStatsDetailVO>>() {});
			if (Objects.nonNull(pageBeanNew)){
				return pageBeanNew;
			}
		}

		if (Objects.isNull(agentId)){
			return new PageBeanNew<>();
		}
		// 获取出版社下的编辑集合
		List<Long> advisers = adviserConsr.getByAgentId(agentId);
		if (CollUtil.isEmpty(advisers)){
			return new PageBeanNew<>();
		}
		// 编辑姓名集合
		Map<Long, String> adviserNames = adviserConsr.getNames(advisers);

		// 根据ERP编号 项目编号查询图书信息
		List<ErpBookInfoDTO> raysBookIds = new ArrayList<>();
		if (Objects.nonNull(endDate) || StrUtil.isNotBlank(name)){
			raysBookIds = erpConsr.searchBookInfo(name, advisers, startDate, endDate);
			if (CollUtil.isEmpty(raysBookIds) && (StrUtil.isBlank(name) || Objects.nonNull(endDate))){
				return new PageBeanNew<>();
			}
		}

		// 分页查询图书
		Map<String, Object> map = new HashMap<>();
		map.put("isRay", isRay);
		map.put("raysBookIds", CollUtil.isEmpty(raysBookIds) ? null : raysBookIds);
		map.put("name", name);
		map.put("advisers", advisers);
		PageBeanNew<AgentBookStatsDetailVO> pageBeanNew = bookAdviserDao.listPageNew(new PageParam(currentPage, numPerPage), map, "getAgentBookStatsDetail");
		if (CollUtil.isEmpty(pageBeanNew.getRecordList())){
			return pageBeanNew;
		}

		// 统计扫码量（人）及浏览量（人）
		List<AdviserQrcodeSceneDTO> sceneRequestDTOS = new ArrayList<>();
		List<Amount4BookAdviserDto> amountRequestDtos = new ArrayList<>();
		List<BookBrowseAndScanStatsDTO> requestDtos = new ArrayList<>();
		List<ErpBookInfoDTO> finalRaysBookIds = new ArrayList<>();
		pageBeanNew.getRecordList().forEach(dto -> {
			if (Objects.nonNull(dto) && (Objects.nonNull(dto.getAdviserId()) || Objects.nonNull(dto.getChannelId()) || Objects.nonNull(dto.getBookId()))) {
				BookBrowseAndScanStatsDTO statsDTO = new BookBrowseAndScanStatsDTO();
				statsDTO.setAdviserId(dto.getAdviserId());
				statsDTO.setChannelId(dto.getChannelId());
				statsDTO.setBookId(dto.getBookId());
				requestDtos.add(statsDTO);

				Amount4BookAdviserDto amount4BookAdviserDto = new Amount4BookAdviserDto();
				amount4BookAdviserDto.setAdviserId(dto.getAdviserId());
				amount4BookAdviserDto.setChannelId(dto.getChannelId());
				amount4BookAdviserDto.setBookId(dto.getBookId());
				amountRequestDtos.add(amount4BookAdviserDto);

				AdviserQrcodeSceneDTO adviserQrcodeSceneDTO = new AdviserQrcodeSceneDTO();
				adviserQrcodeSceneDTO.setAdviserId(dto.getAdviserId());
				adviserQrcodeSceneDTO.setChannelId(dto.getChannelId());
				adviserQrcodeSceneDTO.setBookId(dto.getBookId());
				sceneRequestDTOS.add(adviserQrcodeSceneDTO);

				ErpBookInfoDTO erpBookInfoDTO = new ErpBookInfoDTO();
				erpBookInfoDTO.setAdviserId(dto.getAdviserId());
				erpBookInfoDTO.setRaysBookId(Objects.nonNull(dto.getBookId())?Math.toIntExact(dto.getBookId()):null);
				erpBookInfoDTO.setRaysChannelId(Objects.nonNull(dto.getChannelId())?Math.toIntExact(dto.getChannelId()):null);
				finalRaysBookIds.add(erpBookInfoDTO);
			}
		});

		// 分析引擎获取非社群书统计结果
		List<BookBrowseAndScanStatsDTO> browseAndScanStats = browseRecordConsr.getBookBrowseAndScanStats(requestDtos);

		// 微信群获取社群书统计结果
		List<Long> bookGroupIds = pageBeanNew.getRecordList().stream().filter(x -> Objects.nonNull(x.getBookGroupId())).map(AgentBookStatsDetailVO::getBookGroupId).distinct().collect(Collectors.toList());
		List<GroupScanUserStatsDTO> bookGroupScanStats = wechatGroupConsr.getAdviserBookGroupScanStats(bookGroupIds);

		// 查询交易信息
		List<Amount4BookAdviserDto> amount4BookAdviser = tradeConsr.getAmount4BookAdviser(amountRequestDtos);

		// 查询二维码信息
		List<AdviserQrcodeSceneDTO> sceneDTOS = channelConsr.listQrcodeSceneByBookAdviserIds(sceneRequestDTOS);

		List<Long> bookGroupIdList = pageBeanNew.getRecordList().stream().filter(Objects::nonNull).map(AgentBookStatsDetailVO::getBookGroupId).distinct().filter(Objects::nonNull).collect(Collectors.toList());
		List<BookGroupDTO> dtoByBookGroupIds = new ArrayList<>();
		if (CollUtil.isNotEmpty(bookGroupIdList)){
			// 查询社群码信息
			dtoByBookGroupIds = bookGroupDao.getDTOByIds(bookGroupIdList);
		}

		Map<Long, BookGroupDTO> bookGroupDTOMap = new HashMap<>();
		if (CollUtil.isNotEmpty(dtoByBookGroupIds)){
			bookGroupDTOMap = dtoByBookGroupIds.stream().collect(Collectors.toMap(BookGroupDTO::getId, x -> x, (key1, key2) -> key2));
		}


		// ERP再次查询图书信息
		raysBookIds = erpConsr.searchRaysBookId(finalRaysBookIds);

		// 组装信息
		for (AgentBookStatsDetailVO detailVO : pageBeanNew.getRecordList()) {
			// 填充ERP信息

			if (Objects.nonNull(detailVO) && Objects.nonNull(detailVO.getBookAdviserId())) {
				// 填充二维码信息
				if (CollUtil.isNotEmpty(sceneDTOS)) {
					List<AdviserQrcodeSceneDTO> qrcodeSceneDTOS = sceneDTOS.stream().filter(
							sceneDTO -> Objects.equals(sceneDTO.getBookId(), detailVO.getBookId())
									&& Objects.equals(sceneDTO.getAdviserId(), detailVO.getAdviserId())
									&& Objects.equals(sceneDTO.getChannelId(), detailVO.getChannelId())
					).collect(Collectors.toList());
					if (CollUtil.isNotEmpty(qrcodeSceneDTOS)) {
						List<QrcodeInfoDto> qrcodeList = new ArrayList<>();
						for (AdviserQrcodeSceneDTO qrcodeSceneDTO : qrcodeSceneDTOS) {
							QrcodeInfoDto qrcodeInfoDto = new QrcodeInfoDto();
							qrcodeInfoDto.setLocationName(StrUtil.isNotBlank(qrcodeSceneDTO.getLocationName()) ? qrcodeSceneDTO.getLocationName() : "二维码");
							qrcodeInfoDto.setQrcodeUrl(qrcodeSceneDTO.getQrcodeUrl());
							qrcodeList.add(qrcodeInfoDto);
						}
						detailVO.setQrcodeList(qrcodeList);
					}

				}

				// 填充社群码
				if (CollUtil.isNotEmpty(bookGroupDTOMap) && Objects.nonNull(detailVO.getBookGroupId())
						&& Objects.nonNull(bookGroupDTOMap.get(detailVO.getBookGroupId()))
				&& StrUtil.isNotBlank(bookGroupDTOMap.get(detailVO.getBookGroupId()).getGroupQrcodeUrl())){
					QrcodeInfoDto qrcodeInfoDto = new QrcodeInfoDto();
					qrcodeInfoDto.setLocationName("二维码");
					qrcodeInfoDto.setQrcodeUrl(bookGroupDTOMap.get(detailVO.getBookGroupId()).getGroupQrcodeUrl());
					List<QrcodeInfoDto> qrcodeInfoDtos = CollUtil.isEmpty(detailVO.getQrcodeList())?new ArrayList<>():detailVO.getQrcodeList();
					qrcodeInfoDtos.add(qrcodeInfoDto);
					detailVO.setQrcodeList(qrcodeInfoDtos);
				}

				if (CollUtil.isNotEmpty(raysBookIds)) {
					raysBookIds.stream().filter(
							erpBookInfoDTO -> Objects.equals(erpBookInfoDTO.getRaysBookId(),Objects.isNull(detailVO.getBookId())?null:detailVO.getBookId().intValue())
									&&Objects.equals(erpBookInfoDTO.getAdviserId(),detailVO.getAdviserId())
									&&Objects.equals(erpBookInfoDTO.getRaysChannelId(),Objects.isNull(detailVO.getChannelId())?null:detailVO.getChannelId().intValue())
					).findAny().ifPresent(
							dto->{
								detailVO.setProjectNumber(dto.getProjectNumber());
								detailVO.setErpNumber(dto.getErpNumber());
								detailVO.setExpectPublishNum(Objects.isNull(dto.getPublishNum())?null:Math.toIntExact(dto.getPublishNum()));
								detailVO.setToProjectTime(dto.getBuildTime());
							}
					);
				}
			}

			// 填充编辑信息
			if (Objects.nonNull(detailVO) && Objects.nonNull(detailVO.getAdviserId())) {
				if (CollUtil.isNotEmpty(adviserNames)) {
					detailVO.setAdviserName(adviserNames.get(detailVO.getAdviserId()));
				}
			}

			// 填充浏览、扫码信息
			if (Objects.nonNull(detailVO) && CollUtil.isNotEmpty(browseAndScanStats)){
				browseAndScanStats.stream().filter(
						bookBrowseAndScanStatsDTO -> Objects.equals(bookBrowseAndScanStatsDTO.getBookId(),detailVO.getBookId())
								&&Objects.equals(bookBrowseAndScanStatsDTO.getAdviserId(),detailVO.getAdviserId())
								&&Objects.equals(bookBrowseAndScanStatsDTO.getChannelId(),detailVO.getChannelId())
				).findFirst().ifPresent(item->{
					detailVO.setBrowseTotal(item.getBookBrowseTotal());
					detailVO.setBrowseUserTotal(item.getBookBrowseUserTotal());
					detailVO.setScanTotal(item.getBookScanTotal());
					detailVO.setScanUserTotal(item.getBookScanUserTotal());
				});
			}

			// 补充社群书信息
			if (Objects.nonNull(detailVO) && CollUtil.isNotEmpty(bookGroupScanStats) && Objects.nonNull(detailVO.getBookGroupId())){
				List<GroupScanUserStatsDTO> collect = bookGroupScanStats.stream().filter(x -> Objects.equals(x.getBookGroupId(), detailVO.getBookGroupId())).collect(Collectors.toList());
				if (CollUtil.isNotEmpty(collect)){
					// 浏览量 扫码量
					int total = (int) collect.stream().mapToLong(GroupScanUserStatsDTO::getScanTotal).sum();
					// 浏览人数 扫码人数
					int user = (int) collect.stream().map(GroupScanUserStatsDTO::getWxUserId).distinct().count();
					detailVO.setScanTotal(Objects.nonNull(detailVO.getScanTotal()) ? detailVO.getScanTotal() + total : total);
					detailVO.setBrowseTotal(Objects.nonNull(detailVO.getBrowseTotal()) ? detailVO.getBrowseTotal() + total : total);
					detailVO.setScanUserTotal(Objects.nonNull(detailVO.getScanUserTotal()) ? detailVO.getScanUserTotal() + user : user);
					detailVO.setBrowseUserTotal(Objects.nonNull(detailVO.getBrowseUserTotal()) ? detailVO.getBrowseUserTotal() + user : user);
				}
			}

			// 填充交易信息
			if (Objects.nonNull(detailVO) && CollUtil.isNotEmpty(amount4BookAdviser)){
				amount4BookAdviser.stream().filter(
						amount4BookAdviserDto -> Objects.equals(amount4BookAdviserDto.getBookId(),detailVO.getBookId())
								&&Objects.equals(amount4BookAdviserDto.getAdviserId(),detailVO.getAdviserId())
								&&Objects.equals(amount4BookAdviserDto.getChannelId(),detailVO.getChannelId())
				).findFirst().ifPresent(
						dto->{
							detailVO.setAmountTotal(dto.getAmountTotal());
						}
				);
			}
		}
		JedisClusterUtils.set(cacheKey, JSONObject.toJSONString(pageBeanNew), 60 * 60 * 24);
		return pageBeanNew;
	}


	@Override
	public void exportAgentBookStatsDetail(Long agentId, String name, Date startDate, Date endDate, Integer isRay) {
		// 开线程导出数据
		ThreadPoolUtils.EXPORT_THREAD_POOL.execute(() -> {
			String agentName = agentConsr.getNameById(agentId);
			// 标题
			String excelTitle = String.format("%s做书明细导出-%s", agentName, DateUtil.format(new Date(), "yyyyMMdd"));
			// 列名称
			String[] rowsName = {"书刊ID", "书刊名称", "ISBN", "ERP编号", "项目编号", "编辑ID", "编辑名称", "是否小睿书", "立项时间", "印册量", "总浏览量", "总浏览人数", "总扫码量", "总扫码人数", "成交金额"};
			// 数据列
			List<Object[]> dataList = new ArrayList<>();

			// 分页查询，每次查询1000条
			PageBeanNew<AgentBookStatsDetailVO> pageBeanNew = getAgentBookStatsDetail(agentId, name, startDate, endDate, isRay, 0, 1000);
			while (Objects.nonNull(pageBeanNew) && pageBeanNew.getCurrentPage() < pageBeanNew.getPageCount()) {

				List<AgentBookStatsDetailVO> detailVOS = pageBeanNew.getRecordList();
				for (AgentBookStatsDetailVO detailVO : detailVOS) {
					if (Objects.nonNull(detailVO)) {
						Object[] objects = new Object[]{
								Objects.nonNull(detailVO.getBookId()) ? detailVO.getBookId() : "--",
								Objects.nonNull(detailVO.getBookName()) ? detailVO.getBookName() : "--",
								Objects.nonNull(detailVO.getIsbn()) ? detailVO.getIsbn() : "--",
								Objects.nonNull(detailVO.getErpNumber()) ? detailVO.getErpNumber() : "--",
								Objects.nonNull(detailVO.getProjectNumber()) ? detailVO.getProjectNumber() : "--",
								Objects.nonNull(detailVO.getAdviserId()) ? String.valueOf(detailVO.getAdviserId()) : "--",
								Objects.nonNull(detailVO.getAdviserName()) ? detailVO.getAdviserName() : "--",
								Objects.equals(detailVO.getIsRay(), 1) ? "是" : "否",
								Objects.nonNull(detailVO.getToProjectTime()) ? DateUtil.format(detailVO.getToProjectTime(), "yyyy-MM-dd HH:mm:ss") : "--",
								Objects.nonNull(detailVO.getExpectPublishNum()) ? String.valueOf(detailVO.getExpectPublishNum()) : "0",
								Objects.nonNull(detailVO.getBrowseTotal()) ? String.valueOf(detailVO.getBrowseTotal()) : "0",
								Objects.nonNull(detailVO.getBrowseUserTotal()) ? String.valueOf(detailVO.getBrowseUserTotal()) : "0",
								Objects.nonNull(detailVO.getScanTotal()) ? String.valueOf(detailVO.getScanTotal()) : "0",
								Objects.nonNull(detailVO.getScanUserTotal()) ? String.valueOf(detailVO.getScanUserTotal()) : "0",
								Objects.nonNull(detailVO.getAmountTotal()) ? detailVO.getAmountTotal().toString() : "0",
						};
						dataList.add(objects);
					}
				}
				pageBeanNew = getAgentBookStatsDetail(agentId, name, startDate, endDate, isRay, pageBeanNew.getCurrentPage() + 1, 1000);
			}
			String url = exportConsr.exportExcel(excelTitle, rowsName, dataList);
			sendMsg4ExportAgentBookStatsDetail(agentName,-1,url,new Date());
		});
	}

	@Override
	@ParamLog("购书流程获取书籍基本信息")
	public BookDto getBookDetail4Buy(Long bookId, Long adviserId, Long channelId) {
		BookDto bookDto = bookBiz.getBaseById4Buy(bookId, adviserId, channelId);
		if (null == bookDto) {
			return  new BookDto();
		}
		bookBiz.fillAgentSale(Lists.newArrayList(bookDto));
		bookSet.setLabelNames(Lists.newArrayList(bookDto));
		return bookDto;
	}

	public void sendMsg4ExportAgentBookStatsDetail(String agentName, long data, String url, Date sendDate) {
		LOGGER.info("发送出版社做书明细导出Excel完成站内信【Start】data=" + data + "url=" + url);
		String letterType = "pcloud_book_download";
		String content = String.format("{\"commitTime\":\"%s\",\"type\":\"" + agentName + "做书明细导出\"}", DateUtils.formatDate(sendDate));
		String fileName = DateUtils.today();
		messageConsr.sendLetter(data, 0L, content, SystemCode.pcloud.code, letterType, url, fileName);
		LOGGER.info("发送出版社做书明细导出Excel完成站内信【END】");
	}

    /**
	 * 根据日期获取出版社季度表示
	 * 第一季度：12 1 2</p>
	 * 第二季度：3 4 5</p>
	 * 第三季度：6 7 8</p>
	 * 第四季度：9 10 11</p>
	 * @return 202001
	 */
	private int getAgentQuarterDigital(Date date) {
		if (Objects.isNull(date)) {
			date = new Date();
		}
		int month = DateUtil.month(date) + 1;
		int year = DateUtil.year(date);
		if (month < 3) {
			year--;
			month = 12;
		}
		return year * 100 + (month / 3);
	}

	/**
	 * 获取上一个季度
	 */
	private int getAgentLastQuarterDigital(Date date){

		if (Objects.isNull(date)){
			date = new Date();
		}
		return getAgentQuarterDigital(DateUtil.offsetMonth(date,-3));
	}

	@Override
	public List<BookServeDTO> getAnswerServesByBook(Long bookId, Long adviserId, Long channelId) {
		List<BookServeDTO> answerList = new ArrayList<>();
		List<BookServeDTO> bookServeVOS = bookGroupBiz.getBookAndBookGroupServeIds(adviserId, bookId, channelId);
		bookGroupBiz.fillBookServe(bookServeVOS);
		bookGroupBiz.removeCanNotBuy(bookServeVOS);
		if (!ListUtils.isEmpty(bookServeVOS)) {
			answerList = bookServeVOS.stream().
					filter(s -> s.getServeName().contains("答案") || s.getFromType().equals(AppTypeEnum.ANSWER.value)).collect(Collectors.toList());
		}
		return answerList;
	}

    /**
     * 导出编辑书刊列表(ERP项目用)
     */
    @Override
    public Map<String, Object> exportAdviserBook4Erp(String isbn, String uniqueNumber, String adviserName, Long agentId) {
        if(StringUtils.isBlank(isbn) && StringUtils.isBlank(uniqueNumber) && StringUtils.isBlank(adviserName) && !NumberUtil.isNumber(agentId)){
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "请筛选后再下载！");
        }
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("isbn", isbn);
        paramMap.put("uniqueNumber", uniqueNumber);
        if(!StringUtil.isEmpty(adviserName)) {
            List<Long> adviserIds = adviserConsr.getAdviserIdsByName(adviserName);
            if(CollectionUtils.isEmpty(adviserIds)) {
                throw new BookBizException(BookBizException.PARAM_IS_ERROR, "当前列表为空，请重新筛选再下载！");
            }
            paramMap.put("adviserIds", adviserIds);
        }
		if(agentId != null && agentId > 0){
			List<Long> allAdvisers4Agent = adviserConsr.getByAgentId(agentId);
			if(CollectionUtils.isEmpty(allAdvisers4Agent)) {
				throw new BookBizException(BookBizException.PARAM_IS_ERROR, "当前列表为空，请重新筛选再下载！");
			}
			if(paramMap.containsKey("adviserIds")){
				List<Long> adviserIds = (List<Long>)paramMap.get("adviserIds");
				adviserIds.retainAll(allAdvisers4Agent);
			} else {
				paramMap.put("adviserIds", allAdvisers4Agent);
			}
		}
        List<ErpAdviserBookVO> bookVOS = bookAdviserDao.listAdviserBook4Erp(paramMap);
        if(ListUtils.isEmpty(bookVOS)){
            throw new BookBizException(BookBizException.PARAM_IS_ERROR, "当前列表为空，请重新筛选再下载！");
        }
        List<CompletableFuture<Boolean>> futures = new ArrayList();

		int limitNumber = 100;
        for (int i = 0; i < (bookVOS.size() % limitNumber == 0 ? bookVOS.size() / limitNumber : bookVOS.size() / limitNumber + 1); i++) {
            List<ErpAdviserBookVO> bookVOList = bookVOS.stream().skip(i * limitNumber).limit(limitNumber).collect(Collectors.toList());
            futures.add(CompletableFuture.supplyAsync(() -> {
                this.setBookInfo4Erp(bookVOList);
                return true;
            }));
        }
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).join();
        // 标题
        String excelTitle ="关联rays书刊信息导出";
        // 列名称
        String[] rowsName = {"书名", "书号", "序号", "编辑名称", "所属出版社", "图书ID"};
        // 数据列
        List<Object[]> dataList = new ArrayList<>();
        bookVOS.forEach(e->{
            Object[] objects = new Object[]{
                    Objects.nonNull(e.getBookName()) ? e.getBookName() : "--",
                    Objects.nonNull(e.getIsbn()) ? e.getIsbn() : "--",
                    Objects.nonNull(e.getSerialNumber()) ? e.getSerialNumber() : "--",
                    Objects.nonNull(e.getAdviserName()) ? e.getAdviserName() : "--",
                    Objects.nonNull(e.getAgentName()) ? e.getAgentName() : "--",
                    Objects.nonNull(e.getBookId()) ? String.valueOf(e.getBookId()) : "--"
            };
            dataList.add(objects);
        });
        String url = exportConsr.exportExcel(excelTitle, rowsName, dataList);
        Map<String,Object> result=new HashMap<>();
        result.put("fileUrl", url);
        return result;
    }

	@Override
	@ParamLog("扫公众号码是否推小程序链接")
	public void updateSendMiniUrlState(Long bookId, Long adviserId, Long channelId, Integer isSendMiniUrl) {
    	bookAdviserDao.updateSendMiniUrlState(bookId, adviserId, channelId, isSendMiniUrl);

	}

	@Override
	public BookDto getBookByBookIdAdviserIdChannelId(Long bookId, Long channelId, Long adviserId) {
		return bookAdviserDao.getBookByBookIdAdviserIdChannelId(bookId, channelId, adviserId);
	}

	@Override
	@ParamLog("通过bookid获取小程序码")
	public BookAppletSceneDTO getBookAppletByBookId(Long bookId, Long channelId, Long adviserId) {
		return  bookAppletSceneDao.getBookAppletByBookId(bookId, channelId, adviserId);
	}

	@Override
	public BookDto getLatestAdviserBookByIsbn(String isbn) {
		return bookAdviserDao.getLatestAdviserBookByIsbn(isbn);
	}

	private void setBookInfo4Erp(List<ErpAdviserBookVO> bookVOS) {
        List<Long> adviserIds = bookVOS.stream().filter(s -> s.getAdviserId() != null).map(ErpAdviserBookVO::getAdviserId).distinct().collect(Collectors.toList());
        List<Long> channelIds = bookVOS.stream().filter(s -> s.getChannelId() != null).map(ErpAdviserBookVO::getChannelId).distinct().collect(Collectors.toList());
        List<Long> bookIds = bookVOS.stream().filter(s -> s.getBookId() != null).map(ErpAdviserBookVO::getBookId).distinct().collect(Collectors.toList());
        Map<Long, UserLogin> userLoginInfoMap = adviserConsr.getUserLoginInfoList(adviserIds);
        Map<Long, AdviserBaseInfoDto> adviserAgentMap = adviserConsr.getAdviserId2AdviserInfoDtoMap(adviserIds);
        Map<Long, String> channelNameMap = channelConsr.getNamesByIdList(channelIds);
        List<Long> list = bookFundBiz.listHaveFundBooks(bookIds);
        for (ErpAdviserBookVO bookVO : bookVOS) {
            Long adviserId = bookVO.getAdviserId();
            if (adviserId != null && MapUtils.isNotEmpty(userLoginInfoMap) && userLoginInfoMap.containsKey(adviserId)) {
                UserLogin userLogin = userLoginInfoMap.get(adviserId);
                bookVO.setAdviserAccount(userLogin != null ? userLogin.getUserName() : null);
                bookVO.setAdviserPwd(userLogin != null ? userLogin.getCurrentPassword() : null);
            }
            if (adviserId != null && MapUtils.isNotEmpty(adviserAgentMap) && adviserAgentMap.containsKey(adviserId)) {
                AdviserBaseInfoDto adviserBaseInfoDto = adviserAgentMap.get(adviserId);
                bookVO.setAgentName(null != adviserBaseInfoDto ? adviserBaseInfoDto.getAgentName() : "--");
                bookVO.setAdviserName(null != adviserBaseInfoDto ? adviserBaseInfoDto.getPartyName() : "--");
            }
            if (bookVO.getChannelId() != null && MapUtils.isNotEmpty(channelNameMap) && channelNameMap.containsKey(bookVO.getChannelId())) {
                bookVO.setChannelName(channelNameMap.get(bookVO.getChannelId()));
            }
            bookVO.setIsFundSupport(false);
            if (!ListUtils.isEmpty(list) && list.contains(bookVO.getBookId())) {
                bookVO.setIsFundSupport(true);
            }
        }
    }


	/**
	 *erp获取二维码下面配置了企业微信的二维码
	 */
	@Override
	public List<Long> getHasWxWorkCode(List<Long> sceneIds) {
		return bookQrcodeWxworkBiz.getHasWxWorkCode(sceneIds);
	}

	/**
	 * erp获取rays自有码下面是否配置了资源
	 * @param sceneIds
	 * @return
	 */
	@Override
	public List<Long> getHasResourceCode4Erp(List<Long> sceneIds) {
		if(CollUtil.isEmpty(sceneIds)){
			return new ArrayList<>();
		}
		List<Long> result=resourcePageItemDao.getHasResourceCode4Erp(sceneIds);
		return result;
	}

	@Override
	@ParamLog("根据agentId获取书籍id")
	public void getBookIdsByAgentId(Long agentId) {
		if (null == agentId) {
			return;
		}
		List<Long> adviserIds = adviserConsr.getByAgentId(agentId);
		if (ListUtils.isEmpty(adviserIds)) {
			return;
		}
		String key =  CacheConstant.BOOK  + "BOOKIDS4AGENT:" + agentId;
		//为空的话从数据库查询并缓存5分钟
		if (StringUtil.isEmpty(JedisClusterUtils.get(key))) {
			List<ERPPublishNumDTO> erpPublishNumQueryParams = bookAdviserDao.getErpPublishNumQueryParams(adviserIds);
			if (ListUtils.isEmpty(erpPublishNumQueryParams)) {
				return;
			}
			Integer expireTime = 60 * 5;
			JedisClusterUtils.setJsonList(key, erpPublishNumQueryParams, expireTime);
		}
	}



	public void getBookIdsByAgentIdAndMonth(Long agentId,int month) {
		if (null == agentId) {
			return;
		}
		List<Long> adviserIds = adviserConsr.getByAgentId(agentId);
		if (ListUtils.isEmpty(adviserIds)) {
			return;
		}
		String key =  CacheConstant.BOOK  + "BOOKIDS4AGENT:" + agentId+"_"+month;
		//为空的话从数据库查询并缓存5分钟
		if (StringUtil.isEmpty(JedisClusterUtils.get(key))) {
			List<ERPPublishNumDTO> erpPublishNumQueryParams = bookAdviserDao.getErpPublishNumQueryParamsByMonth(adviserIds,month);
			if (ListUtils.isEmpty(erpPublishNumQueryParams)) {
				return;
			}
			Integer expireTime = 60 * 5;
			JedisClusterUtils.setJsonList(key, erpPublishNumQueryParams, expireTime);
		}
	}

	@Override
	public List<Long> getBooksByAgentToken(Long agentId, int index,int month) {
		if (null == agentId) {
			return new ArrayList<>();
		}
		List<Long> result = new ArrayList<>();
		String key =  CacheConstant.BOOK  + "BOOKIDS4AGENT:" + agentId+"_"+month;
		if (StringUtil.isEmpty(JedisClusterUtils.get(key))) {
			List<Long> adviserIds = adviserConsr.getByAgentId(agentId);
			List<ERPPublishNumDTO> erpPublishNumQueryParams = bookAdviserDao.getErpPublishNumQueryParamsByMonth(adviserIds,month);
			if (ListUtils.isEmpty(erpPublishNumQueryParams)) {
				return new ArrayList<>();
			}
			Integer expireTime = 60 * 5;
			JedisClusterUtils.setJsonList(key, erpPublishNumQueryParams, expireTime);
			List<ERPPublishNumDTO> booksByIndex = getBooksByIndex(index, erpPublishNumQueryParams);
			for (ERPPublishNumDTO erpPublishNumDTO : booksByIndex) {
				result.add(erpPublishNumDTO.getBookId());
			}
		}else{
			List<ERPPublishNumDTO> bookList = JedisClusterUtils.getJsonList(key, ERPPublishNumDTO.class);
			List<ERPPublishNumDTO> booksByIndex = getBooksByIndex(index, bookList);
			for (ERPPublishNumDTO erpPublishNumDTO : booksByIndex) {
				result.add(erpPublishNumDTO.getBookId());
			}
		}
		return result;
	}

	private static List<ERPPublishNumDTO>getBooksByIndex(int index,List<ERPPublishNumDTO>source){
		if(source==null){
			return new ArrayList<>();
		}
		List<ERPPublishNumDTO> result = new ArrayList<>();
		if((index-1)*500>source.size()){
			return result;
		}else{
			for(int i=index*500;i<(index+1)*500;i++){
				if(source.size()>i) {
					result.add(source.get(i));
				}else {
					break;
				}
			}
		}
		return result;

	}


	@Override
	public BookServeInfo listBookServes4Book(String cursor, Integer limit) {
		Long lastId = null;
		if (StringUtil.isNotBlank(cursor)) lastId = Long.parseLong(JedisClusterUtils.get(cursor));
		limit = (Objects.isNull(limit) || limit < 1 || limit > 100) ? 20 : limit;


		List<BookServesListDTO> bookServesListDTOS = bookAdviserDao.listBookServes4Book(lastId, limit);
		if(CollUtil.isEmpty(bookServesListDTOS)) return new BookServeInfo();
		Long maxId = bookServesListDTOS.stream().filter(Objects::nonNull).map(BookServesListDTO::getBookAdviserId).max(Long::compareTo).orElse(0L);
		String key = UUID.randomUUID().toString();
		JedisClusterUtils.set(key,String.valueOf(maxId), 2 * 60 * 60);
		BookServeInfo bookServeInfo = new BookServeInfo();
		bookServeInfo.setCursor(key);

		// 年级科目版本上下册标签
		CompletableFuture<Map<Long, String>> newLabelIdFuture = CompletableFuture.supplyAsync(() -> bookLabelBiz.getLabelMapByIds(Stream.of(
				bookServesListDTOS.stream().filter(Objects::nonNull).map(BookServesListDTO::getGraLabelId),
				bookServesListDTOS.stream().filter(Objects::nonNull).map(BookServesListDTO::getSubLabelId),
				bookServesListDTOS.stream().filter(Objects::nonNull).map(BookServesListDTO::getVerLabelId),
				bookServesListDTOS.stream().filter(Objects::nonNull).map(BookServesListDTO::getVolLabelId)
		).flatMap(Function.identity()).filter(Objects::nonNull).distinct().collect(Collectors.toList())), ThreadPoolUtils.SMALL_THREAD_POOL);

		// 专业深度目的标签
		CompletableFuture<Map<Long, String>> oldLabelIdFuture = CompletableFuture.supplyAsync(() -> labelConsr.getLabelName(Stream.of(
				bookServesListDTOS.stream().filter(Objects::nonNull).map(BookServesListDTO::getProLabelId),
				bookServesListDTOS.stream().filter(Objects::nonNull).map(BookServesListDTO::getPurLabelId),
				bookServesListDTOS.stream().filter(Objects::nonNull).map(BookServesListDTO::getDepLabelId)
		).flatMap(Function.identity()).filter(Objects::nonNull).distinct().collect(Collectors.toList())), ThreadPoolUtils.SMALL_THREAD_POOL);

		Stream<CompletableFuture<Void>> futureStream = bookServesListDTOS.stream().filter(Objects::nonNull).map(bookServesListDTO -> CompletableFuture.runAsync(() -> {
			List<BookServeDTO> bookServeVOS = bookGroupBiz.getBookAndBookGroupServeIds(bookServesListDTO.getAdviserId(), bookServesListDTO.getBookId(), bookServesListDTO.getChannelId());
			bookGroupBiz.removeCanNotBuy(bookServeVOS);
			bookServesListDTO.setBookServeList(warpAndFillBookServeLabelDTO(bookServeVOS));
		}, ThreadPoolUtils.SMALL_THREAD_POOL));

		CompletableFuture[] completableFutures = Stream.concat(Stream.of(newLabelIdFuture, oldLabelIdFuture), futureStream).toArray(CompletableFuture[]::new);

		CompletableFuture<Void> allCompletableFuture = CompletableFuture.allOf(completableFutures);

		try{
			allCompletableFuture.get();
			Map<Long, String> newLabelMap = Optional.ofNullable(newLabelIdFuture.get()).orElse(new HashMap<>());
			Map<Long, String> oldLabelMap = Optional.ofNullable(oldLabelIdFuture.get()).orElse(new HashMap<>());
			bookServesListDTOS.forEach(book->{
				book.setProLabelName(Optional.ofNullable(oldLabelMap.get(book.getProLabelId())).orElse(""));
				book.setPurLabelName(Optional.ofNullable(oldLabelMap.get(book.getPurLabelId())).orElse(""));
				book.setDepLabelName(Optional.ofNullable(oldLabelMap.get(book.getDepLabelId())).orElse(""));

				book.setGraLabelName(Optional.ofNullable(newLabelMap.get(book.getGraLabelId())).orElse(""));
				book.setSubLabelName(Optional.ofNullable(newLabelMap.get(book.getSubLabelId())).orElse(""));
				book.setVerLabelName(Optional.ofNullable(newLabelMap.get(book.getVerLabelId())).orElse(""));
				book.setVolLabelName(Optional.ofNullable(newLabelMap.get(book.getVolLabelId())).orElse(""));
			});

		}catch (InterruptedException | ExecutionException e) {
			LOGGER.warn("listBookServes4Book 异步任务处理失败");
		}
		bookServeInfo.setBookServesListDTOS(bookServesListDTOS);

		return bookServeInfo;
	}

	private List<BookServeLabelDTO> warpAndFillBookServeLabelDTO(List<BookServeDTO> serveDTOList) {

		if (ListUtils.isEmpty(serveDTOList)) {
			return new ArrayList<>();
		}
		List<BookServeLabelDTO> list = serveDTOList.stream().filter(Objects::nonNull).map(x -> {
			BookServeLabelDTO bookServeLabelDTO = new BookServeLabelDTO();
			BeanUtils.copyProperties(x, bookServeLabelDTO);
			return bookServeLabelDTO;
		}).collect(Collectors.toList());

		List<Long> appIds = Optional.of(list).map(x ->
				x.stream().filter(item -> Objects.nonNull(item) && StrUtil.equals(item.getServeType(), AppAndProductTypeEnum.APP.value)).map(BookServeLabelDTO::getServeId)
						.distinct().collect(Collectors.toList())
		).orElse(new ArrayList<>());

		List<Long> productIds = Optional.of(list).map(x ->
				x.stream().filter(item -> Objects.nonNull(item) && StrUtil.equals(item.getServeType(), AppAndProductTypeEnum.PRODUCT.value)).map(BookServeLabelDTO::getServeId)
						.distinct().collect(Collectors.toList())
		).orElse(new ArrayList<>());


		Map<Long, ProductDto> productDtoMap = new HashMap<>();
		Map<Long, AppDto> appDtoMap = new HashMap<>();
		if (!ListUtils.isEmpty(productIds)) {
			productDtoMap = productConsr.getProBasesByIds(productIds);
		}
		if (!ListUtils.isEmpty(appIds)) {
			appDtoMap = appConsr.mapByIds(appIds);
		}
		ArrayList<AppDto> appDtos = new ArrayList<>(appDtoMap.values());
		List<Long> labelIds = Stream.of(
				appDtos.stream().filter(Objects::nonNull).map(AppDto::getProLabelId),
				appDtos.stream().filter(Objects::nonNull).map(AppDto::getPurLabelId),
				appDtos.stream().filter(Objects::nonNull).map(AppDto::getDepLabelId)
		).flatMap(Function.identity()).filter(Objects::nonNull).distinct().collect(Collectors.toList());

		Map<Long, String> labelNameMap = labelConsr.getLabelName(labelIds);

		List<BookServeLabelDTO> removeList = new ArrayList<>();
		for (BookServeLabelDTO bookServeDTO : list) {
			if (!MapUtils.isEmpty(productDtoMap) && AppAndProductTypeEnum.PRODUCT.value.equals(bookServeDTO.getServeType())) {
				ProductDto productDto = productDtoMap.get(bookServeDTO.getServeId());
				if (productDto != null) {
					bookServeDTO.setServeName(productDto.getProductName());
					bookServeDTO.setCoverImg(productDto.getCoverImg());
					bookServeDTO.setProLabelId(Optional.ofNullable(productDto.getProductLabels()).map(x->x.get(0)).map(ProductLabelDto::getProLabelId).orElse(null));
					bookServeDTO.setProLabelName(Optional.ofNullable(productDto.getProductLabels()).map(x->x.get(0)).map(ProductLabelDto::getProLabelName).orElse(""));
					bookServeDTO.setPurLabelId(Optional.ofNullable(productDto.getProductLabels()).map(x->x.get(0)).map(ProductLabelDto::getPurLabelId).orElse(null));
					bookServeDTO.setPurLabelName(Optional.ofNullable(productDto.getProductLabels()).map(x->x.get(0)).map(ProductLabelDto::getPurLabelName).orElse(""));
					bookServeDTO.setDepLabelId(Optional.ofNullable(productDto.getProductLabels()).map(x->x.get(0)).map(ProductLabelDto::getDepLabelId).orElse(null));
					bookServeDTO.setDepLabelName(Optional.ofNullable(productDto.getProductLabels()).map(x->x.get(0)).map(ProductLabelDto::getDepLabelName).orElse(""));
					ProductTypeDto productTypeDto = productDto.getProductTypeDto();
					if (productTypeDto != null) {
						bookServeDTO.setFromType(productTypeDto.getTypeCode());
						bookServeDTO.setFromTypeName(productTypeDto.getTypeName());
					}
					if (!StringUtil.isEmpty(productDto.getSkipUrl())){
						bookServeDTO.setHasThirdLink(true);
					} else {
						bookServeDTO.setHasThirdLink(false);
					}
					if (bookGroupBiz.checkRayUrl(productDto.getSkipUrl()) && ProductTypeConstant.ARTICLE.equals(bookServeDTO.getFromType())){
						removeList.add(bookServeDTO);
					}
				} else {
					removeList.add(bookServeDTO);
				}
			}
			if (!MapUtils.isEmpty(appDtoMap) && AppAndProductTypeEnum.APP.value.equals(bookServeDTO.getServeType())) {
				AppDto appDto = appDtoMap.get(bookServeDTO.getServeId());
				if (appDto != null) {

					bookServeDTO.setServeName(appDto.getTitle());
					bookServeDTO.setCoverImg(appDto.getSquareImg());
					bookServeDTO.setFromType(appDto.getTypeCode());
					bookServeDTO.setFromTypeName(appDto.getTypeName());
					if (!StringUtil.isEmpty(appDto.getTurnUrl())){
						bookServeDTO.setHasThirdLink(true);
					} else {
						bookServeDTO.setHasThirdLink(false);
					}
					if (bookGroupBiz.checkRayUrl(appDto.getTurnUrl()) && AppTypeEnum.ARTICLE.value.equals(appDto.getTypeCode())){
						removeList.add(bookServeDTO);
					}
					bookServeDTO.setProLabelId(appDto.getProLabelId());
					bookServeDTO.setProLabelName(labelNameMap.get(appDto.getProLabelId()));
					bookServeDTO.setPurLabelId(appDto.getPurLabelId());
					bookServeDTO.setPurLabelName(labelNameMap.get(appDto.getPurLabelId()));
					bookServeDTO.setDepLabelId(appDto.getDepLabelId());
					bookServeDTO.setDepLabelName(labelNameMap.get(appDto.getDepLabelId()));
				} else {
					removeList.add(bookServeDTO);
				}
			}
		}
		list.removeAll(removeList);
		List<BookServeLabelDTO> toRemoveList = new ArrayList<>();
		for (BookServeLabelDTO item : list) {
			if ((AppAndProductTypeEnum.APP.value.equals(item.getServeType()) && ArrayUtils.contains(RightsSettingConstant.APPLET_APP_NOT_SUPPORT, item.getFromType()))
					|| (AppAndProductTypeEnum.PRODUCT.value.equals(item.getServeType()) && ArrayUtils.contains(RightsSettingConstant.APPLET_PRODUCT_NOT_SUPPORT, item.getFromType())) || StringUtil.isEmpty(item.getFromType())) {
				toRemoveList.add(item);
			}
		}
		if (!ListUtils.isEmpty(toRemoveList)) {
			list.removeAll(toRemoveList);
		}
		return list;
	}

	/**
	 * 小睿书下面的书刊权益数量
	 */
	@Override
	public Map<Long, Integer> rightsCountByBookIds(List<Long> bookIds) {
		if(CollUtil.isEmpty(bookIds)){
			return new HashMap<>();
		}
		List<BookRightsCountsDto> bookRightsCountsDtos = rightsSettingDAO.rightsCountByBookIds(bookIds);
		Map<Long, Integer> result = CollUtil.isEmpty(bookRightsCountsDtos) ? new HashMap<>() : bookRightsCountsDtos.stream().collect(Collectors.toMap(a -> a.getBookId(), a -> a.getCount(), (k1, k2) -> k2));
		return result;
	}

	@Override
	public PageBeanNew<BookQrcodeVO> qrList4AdviserBookNew(Long bookId, Long channelId, Long adviserId, String sceneName, Integer currentPage, Integer numPerPage) {

		// 获取 book_group 二维码列表 仅包含 自有码
		CompletableFuture<List<BookQrcodeVO>> bookGroupIdFuture = CompletableFuture.supplyAsync(() -> {
			List<Long> locationIds = null;
			if (StrUtil.isNotBlank(sceneName)) {
				// 模糊匹配印码位置
				locationIds = qrcodeSceneConsr.getLocationIds4Name(sceneName);
			}
			if (CollUtil.isEmpty(locationIds)) locationIds = null;
			return Optional.ofNullable(bookGroupDao.listBookQrcodes(bookId, channelId, adviserId, sceneName, locationIds)).orElse(new ArrayList<>());
		}, ThreadPoolUtils.OTHER_POOL);

		// 获取 qrcode_scene 二维码列表 包含 自有码 和 公众号码
		CompletableFuture<List<BookQrcodeVO>> qrcodeSceneFuture = CompletableFuture.supplyAsync(
				() -> Optional.ofNullable(qrcodeSceneConsr.qrList4AdviserBookNew(bookId, channelId, adviserId, sceneName)).orElse(new ArrayList<>()));

		try {
			// 等待查询结果
			CompletableFuture.allOf(bookGroupIdFuture, qrcodeSceneFuture).get();
			List<BookQrcodeVO> bookQrcodeList = bookGroupIdFuture.get();
			List<BookQrcodeVO> qrcodeSceneList = qrcodeSceneFuture.get();
			bookQrcodeList.addAll(qrcodeSceneList);

			int totalCount = bookQrcodeList.size();
			// 对结果进行排序 序号正序，时间倒序
			// TODO 是否对结果进行缓存？
			bookQrcodeList.sort(Comparator.nullsFirst(Comparator.comparing(BookQrcodeVO::getSeq, Comparator.nullsLast(Integer::compareTo)))
					.thenComparing(Comparator.nullsFirst(Comparator.comparing(BookQrcodeVO::getLastModifiedDate)).reversed()));
			// 手动分页
			List<BookQrcodeVO> pageList = CollUtil.page(currentPage, numPerPage, bookQrcodeList);

			fillPageList(pageList);
			return new PageBeanNew<>(currentPage, numPerPage, totalCount, pageList);
		} catch (InterruptedException | ExecutionException e) {
			LOGGER.warn("获取图书二维码，异步任务失败！", e);
			return new PageBeanNew<>(currentPage, numPerPage, 0, new ArrayList<>());
		}
	}

	/**
	 * 填充手动分页结果
	 */
	private void fillPageList(List<BookQrcodeVO> pageList) {

		if (CollUtil.isEmpty(pageList)) return;

		// 分组
		Map<String, List<Long>> map = pageList.stream().collect(
				Collectors.groupingBy(BookQrcodeVO::getSource, Collectors.mapping(BookQrcodeVO::getSceneId, Collectors.toList())));

		// 二维码标签 二维码印码位置 二维码类型 二维码ID 二维码地址 服务
		// 区分二维码来源 分别去book 和 channel 填充信息
		List<Long> bookGroupIds = Optional.ofNullable(map).map(x -> x.get("bookGroup")).orElse(new ArrayList<>());
		List<Long> qrcodeSceneIds = Optional.ofNullable(map).map(x -> x.get("qrcodeScene")).orElse(new ArrayList<>());
		//渠道中的自有码id
		List<Long> aliQrcodeSceneIds =  pageList.stream().filter(s->"ali".equals(s.getQrcodeType())).map(BookQrcodeVO::getSceneId).collect(Collectors.toList());

		// 获取渠道中二维码信息-包含 自有码和公众号码 返回结果对二维码类型进行了纠正
		CompletableFuture<Map<Long, BookQrcodeVO>> qrcodeSceneFuture = CompletableFuture.supplyAsync(() ->
				Optional.ofNullable(channelConsr.getQrList4SceneIds(qrcodeSceneIds))
				.map(x -> x.stream().filter(Objects::nonNull).collect(Collectors.toMap(BookQrcodeVO::getSceneId, Function.identity())))
				.orElse(new HashMap<>()));

		if (CollUtil.isEmpty(bookGroupIds)){
			Map<Long, BookQrcodeVO> qrcodeVOMap = null;
			try {
				qrcodeVOMap = Optional.ofNullable(qrcodeSceneFuture.get()).orElse(new HashMap<>());
			} catch (InterruptedException | ExecutionException e) {
				LOGGER.warn("[fillPageList] 异步获取信息失败");
				return;
			}
			for (BookQrcodeVO bookQrcodeVO : pageList) {
				if (Objects.isNull(bookQrcodeVO) || Objects.isNull(bookQrcodeVO.getSceneId())) continue;
				if (Objects.nonNull(qrcodeVOMap.get(bookQrcodeVO.getSceneId())))
					BeanUtils.copyProperties(qrcodeVOMap.get(bookQrcodeVO.getSceneId()), bookQrcodeVO);
			}
			return;
		}

		// 查询 book_group 码信息
		CompletableFuture<List<BookQrcodeVO>> bookGroupFuture = CompletableFuture.completedFuture(bookGroupDao.listBookQrcodeVOByIds(bookGroupIds));

		CompletableFuture<Map<Long, BookQrcodeVO>> bookGroupMapFuture = bookGroupFuture.thenApplyAsync(list ->
				Optional.ofNullable(list).map(x -> x.stream().filter(Objects::nonNull).collect(Collectors.toMap(BookQrcodeVO::getSceneId, Function.identity()))).orElse(new HashMap<>()));

		CompletableFuture<Map<Long, AccountSettingDto>> accountSettingMapFuture = bookGroupMapFuture.thenApplyAsync(it -> {
			if (CollUtil.isEmpty(it) || CollUtil.isEmpty(it.values())) return new HashMap<>();
			List<Long> channelIds = it.values().stream().filter(Objects::nonNull).map(BookQrcodeVO::getChannelPartyId).filter(Objects::nonNull).distinct().collect(Collectors.toList());
			return Optional.ofNullable(channelConsr.listWechat(channelIds)).orElse(new HashMap<>());
		});

		// 获取标签名称信息
		CompletableFuture<Map<Long, String>> bookGroupLabelMapFuture = bookGroupFuture.thenApplyAsync(list -> {
			List<Long> labelIds = list.parallelStream().filter(Objects::nonNull).map(bookQrcodeVO ->
					CollUtil.toList(bookQrcodeVO.getProLabelId(), bookQrcodeVO.getPurLabelId(), bookQrcodeVO.getDepLabelId()))
					.flatMap(List::stream).filter(Objects::nonNull).distinct().collect(Collectors.toList());
			return labelConsr.getLabelName(labelIds);
		}, ThreadPoolUtils.OTHER_POOL);

		// 获取印码位置信息
		CompletableFuture<Map<Long, String>> bookGroupLocationMapFuture = bookGroupFuture.thenApplyAsync(list -> {
			List<Long> locationIds = list.parallelStream().filter(Objects::nonNull).map(vos ->
					Optional.ofNullable(vos.getQrcodeLocations()).map(x -> x.stream().filter(Objects::nonNull)
							.map(QrcodeLocationDto::getLocationId).distinct().collect(Collectors.toList()))
							.orElse(new ArrayList<>())
			).flatMap(List::stream).filter(Objects::nonNull).distinct().collect(Collectors.toList());
			return channelConsr.listLocationNames(locationIds);
		}, ThreadPoolUtils.OTHER_POOL);


		// 填充配置的服务信息
		// 查询 book_group_serve
		CompletableFuture<List<BookGroupServe>> bookGroupServeFuture = CompletableFuture.completedFuture(
				Optional.ofNullable(resourcePageBiz.getServeListByBookGroupAndSceneIds(bookGroupIds, aliQrcodeSceneIds)).orElse(new ArrayList<>()));

		// 查询 book_group_serve 作品信息
		// 查询作品ID
		CompletableFuture<List<Long>> bookGroupProductIdFuture = bookGroupServeFuture.thenApplyAsync(bookGroupServes ->
				bookGroupServes.stream().filter(x -> Objects.nonNull(x) && Objects.nonNull(x.getServeId())
				&& Objects.equals(AppAndProductTypeEnum.PRODUCT.value, x.getServeType())).map(BookGroupServe::getServeId)
						.collect(Collectors.toList()), ThreadPoolUtils.OTHER_POOL);
		// 查询作品信息
		CompletableFuture<Map<Long, ProductDto>> bookGroupServeProductMapFuture = bookGroupProductIdFuture.thenApplyAsync(productIds ->
				productConsr.getProBasesByIds(productIds), ThreadPoolUtils.OTHER_POOL);
		// 查询是否超级作者作品
		CompletableFuture<Map<Long, Boolean>> isSuperMapFuture = bookGroupProductIdFuture.thenApplyAsync(productIds ->
				Optional.ofNullable(productConsr.getIsSuperByProductIdList(productIds)).orElse(new HashMap<>()));



		// 查询 book_group_serve 应用信息
		CompletableFuture<Map<Long, AppDto>> bookGroupServesAppMapFuture = bookGroupServeFuture.thenApplyAsync(bookGroupServes -> {
			// 作品ID 列表
			List<Long> appIds = bookGroupServes.stream().filter(x -> Objects.nonNull(x) && Objects.nonNull(x.getServeId())
					&& Objects.equals(AppAndProductTypeEnum.APP.value, x.getServeType())).map(BookGroupServe::getServeId).collect(Collectors.toList());
			return appConsr.mapByIds(appIds);
		}, ThreadPoolUtils.OTHER_POOL);

		// 查询统计信息
		CompletableFuture<Map<Long, GroupUserCountDTO>> bookGroupStatsMapFuture = CompletableFuture.supplyAsync(() ->
				Optional.ofNullable(wechatGroupConsr.getScanCountByGroup(bookGroupIds)).orElse(new HashMap<>()));


		try {
			CompletableFuture.allOf(qrcodeSceneFuture, bookGroupFuture, bookGroupLabelMapFuture, bookGroupLocationMapFuture,
					bookGroupServeFuture, bookGroupProductIdFuture, bookGroupServeProductMapFuture, isSuperMapFuture,
					bookGroupServesAppMapFuture, bookGroupStatsMapFuture, accountSettingMapFuture).get();
			Map<Long, BookQrcodeVO> bookGroupMap = Optional.ofNullable(bookGroupMapFuture.get()).orElse(new HashMap<>());
			Map<Long, BookQrcodeVO> qrcodeVOMap = Optional.ofNullable(qrcodeSceneFuture.get()).orElse(new HashMap<>());
			Map<Long, String> labelNameMap = Optional.ofNullable(bookGroupLabelMapFuture.get()).orElse(new HashMap<>());
			Map<Long, GroupUserCountDTO> bookGroupStatsMap = Optional.ofNullable(bookGroupStatsMapFuture.get()).orElse(new HashMap<>());

			Map<Long, List<BookGroupServe>> bookGroupServeMap = Optional.ofNullable(bookGroupServeFuture.get()).map(x -> x.stream()
					.filter(s->s.getBookGroupId()!= null).collect(Collectors.groupingBy(BookGroupServe::getBookGroupId))).orElse(new HashMap<>());
			Map<Long, List<BookGroupServe>> aliSceneServeMap = Optional.ofNullable(bookGroupServeFuture.get()).map(x -> x.stream()
					.filter(s->s.getSceneId()!= null).collect(Collectors.groupingBy(BookGroupServe::getSceneId))).orElse(new HashMap<>());

			Map<Long, String> bookGroupLocationMap = Optional.ofNullable(bookGroupLocationMapFuture.get()).orElse(new HashMap<>());
			Map<Long, AppDto> bookGroupAppMap = Optional.ofNullable(bookGroupServesAppMapFuture.get()).orElse(new HashMap<>());
			Map<Long, Boolean> isSuperMap = Optional.ofNullable(isSuperMapFuture.get()).orElse(new HashMap<>());
			Map<Long, ProductDto> bookGroupProductMap = Optional.ofNullable(bookGroupServeProductMapFuture.get()).orElse(new HashMap<>());
			Map<Long, AccountSettingDto> accountSettingDtoMap = Optional.ofNullable(accountSettingMapFuture.get()).orElse(new HashMap<>());

			for (BookQrcodeVO bookQrcodeVO : pageList) {
				if (Objects.isNull(bookQrcodeVO) || Objects.isNull(bookQrcodeVO.getSceneId())) continue;
				if (Objects.equals(bookQrcodeVO.getSource(), "qrcodeScene")) {
					// 填充渠道中的码(同时纠正码的类型)
					if (Objects.nonNull(qrcodeVOMap.get(bookQrcodeVO.getSceneId()))) {
						BeanUtils.copyProperties(qrcodeVOMap.get(bookQrcodeVO.getSceneId()), bookQrcodeVO);

						if ("ali".equals(bookQrcodeVO.getQrcodeType())) {
							//渠道中的自建码资源从H5资源页查
							Long sceneId = bookQrcodeVO.getSceneId();
							BookQrcodeVO qrcodeVO = Optional.ofNullable(qrcodeVOMap.get(sceneId)).orElse(new BookQrcodeVO());
							// 填充资源列表
							if (CollUtil.isEmpty(aliSceneServeMap) || CollUtil.isEmpty(aliSceneServeMap.get(sceneId))){
								bookQrcodeVO.setMessages(new ArrayList<>());
								continue;
							}
							// 填充资源明细
							List<BookGroupServe> bookGroupServes = aliSceneServeMap.get(sceneId);
							List<MessageDto> messageDtos = this.getMessageDTOList(bookGroupServes, bookGroupProductMap, isSuperMap, bookGroupAppMap, qrcodeVO);
							bookQrcodeVO.setMessages(messageDtos);
						}
					}

				} else if (Objects.equals(bookQrcodeVO.getSource(), "bookGroup")) {

					// 社群码将ID赋值给BookGroupId
					Long sceneId = bookQrcodeVO.getSceneId();
					BookQrcodeVO qrcodeVO = Optional.ofNullable(bookGroupMap.get(sceneId)).orElse(new BookQrcodeVO());
					BeanUtils.copyProperties(qrcodeVO,bookQrcodeVO);
					bookQrcodeVO.setBookGroupId(sceneId);
					bookQrcodeVO.setSceneId(null);

					// 填充标签名称
					bookQrcodeVO.setProLabelName(Optional.ofNullable(bookQrcodeVO.getProLabelId()).map(labelNameMap::get).orElse(""));
					bookQrcodeVO.setPurLabelName(Optional.ofNullable(bookQrcodeVO.getPurLabelId()).map(labelNameMap::get).orElse(""));
					bookQrcodeVO.setDepLabelName(Optional.ofNullable(bookQrcodeVO.getDepLabelId()).map(labelNameMap::get).orElse(""));

					// 填充统计信息
					bookQrcodeVO.setCounts(Optional.ofNullable(sceneId).map(bookGroupStatsMap::get).map(GroupUserCountDTO::getCount).map(Long::valueOf).orElse(0L));
					bookQrcodeVO.setBrowseCounts(Optional.ofNullable(sceneId).map(bookGroupStatsMap::get).map(GroupUserCountDTO::getCount).map(Long::valueOf).orElse(0L));
					bookQrcodeVO.setBrowserCounts(Optional.ofNullable(sceneId).map(bookGroupStatsMap::get).map(GroupUserCountDTO::getUserCount).map(Long::valueOf).orElse(0L));

					// 填充印码位置信息
					List<QrcodeLocationDto> qrcodeLocations = bookQrcodeVO.getQrcodeLocations();
					if (CollUtil.isEmpty(qrcodeLocations)) {
						bookQrcodeVO.setQrcodeLocations(new ArrayList<>());
					} else {
						qrcodeLocations.forEach(it -> {
							if (Objects.nonNull(it) && Objects.nonNull(it.getLocationId())) {
								it.setLocationName(Optional.ofNullable(bookGroupLocationMap.get(it.getLocationId())).orElse(""));
							}
						});
					}

					// 填充资源列表
					if (CollUtil.isEmpty(bookGroupServeMap) || CollUtil.isEmpty(bookGroupServeMap.get(sceneId))){
						bookQrcodeVO.setMessages(new ArrayList<>());
						continue;
					}

					// 填充资源明细
					List<BookGroupServe> bookGroupServes = bookGroupServeMap.get(sceneId);
					List<MessageDto> messageDtos = this.getMessageDTOList(bookGroupServes, bookGroupProductMap, isSuperMap, bookGroupAppMap, qrcodeVO);
					bookQrcodeVO.setMessages(messageDtos);
				}

			}


		} catch (InterruptedException | ExecutionException e) {
			LOGGER.warn("[fillPageList] 异步获取信息失败");
		}


	}

	private List<MessageDto> getMessageDTOList(List<BookGroupServe> bookGroupServes, Map<Long, ProductDto> bookGroupProductMap,
											   Map<Long, Boolean> isSuperMap, Map<Long, AppDto> bookGroupAppMap, BookQrcodeVO qrcodeVO) {
		List<MessageDto> messageDtos = new ArrayList<>(bookGroupServes.size());
		for (BookGroupServe bookGroupServe : bookGroupServes) {
			MessageDto messageDto = new MessageDto();
			messageDto.setFromId(bookGroupServe.getServeId());
			messageDto.setTypeCode(bookGroupServe.getServeType());
			messageDto.setUrl(bookGroupServe.getServeUrl());
			messageDto.setFromType(bookGroupServe.getTypeCode());
			if(Objects.equals(bookGroupServe.getServeType(), MessageFromTypeEnum.PRODUCT.value)){
				ProductDto productDto = Optional.ofNullable(bookGroupServe.getServeId()).map(bookGroupProductMap::get).orElse(new ProductDto());
				messageDto.setPicUrl(Optional.ofNullable(productDto.getCoverImg()).orElse(""));
				messageDto.setPosterPicUrl(Optional.ofNullable(productDto.getCoverImg()).orElse(""));
				messageDto.setServiceLead(Optional.ofNullable(productDto.getProductName()).orElse(""));
				messageDto.setTitle(Optional.ofNullable(productDto.getProductName()).orElse(""));
				messageDto.setTypeCodeName(Optional.ofNullable(productDto.getProductTypeDto()).map(ProductTypeDto::getTypeName).orElse(""));
				messageDto.setShortTitle(Optional.ofNullable(messageDto.getTypeCodeName()).orElse(""));
				messageDto.setCoverImg(Optional.ofNullable(productDto.getCoverImg()).orElse(""));
				messageDto.setSuper(Optional.ofNullable(messageDto.getFromId()).map(isSuperMap::get).orElse(false));
				String serveLink = ServeLinkUtils.getServeLink(bookGroupServe.getServeType(), productDto.getProductTypeCode(),
						String.valueOf(bookGroupServe.getServeId()), null, String.valueOf(qrcodeVO.getChannelPartyId()),
						String.valueOf(qrcodeVO.getAdviserId()), null);
				messageDto.setUrl(serveLink);
			}else if (Objects.equals(bookGroupServe.getServeType(), MessageFromTypeEnum.APP.value)){
				AppDto appDto = Optional.ofNullable(bookGroupServe.getServeId()).map(bookGroupAppMap::get).orElse(new AppDto());
				messageDto.setPicUrl(Optional.ofNullable(appDto.getTransverseImg()).orElse(""));
				messageDto.setPosterPicUrl(Optional.ofNullable(appDto.getTransverseImg()).orElse(""));
				messageDto.setServiceLead(Optional.ofNullable(appDto.getTitle()).orElse(""));
				messageDto.setShortTitle(Optional.ofNullable(appDto.getTypeName()).orElse(""));
				messageDto.setTitle(Optional.ofNullable(appDto.getTitle()).orElse(""));
				messageDto.setTypeCodeName(Optional.ofNullable(appDto.getTypeName()).orElse(""));
				messageDto.setCoverImg(Optional.ofNullable(appDto.getSquareImg()).orElse(""));
				String serveLink = ServeLinkUtils.getServeLink(bookGroupServe.getServeType(), appDto.getTypeCode(),
						String.valueOf(bookGroupServe.getServeId()), null, String.valueOf(qrcodeVO.getChannelPartyId()),
						String.valueOf(qrcodeVO.getAdviserId()), null);
				messageDto.setUrl(serveLink);
			}
			messageDtos.add(messageDto);
		}
		return messageDtos;
	}

	@Override
	public void updateOpenCatalogState(Long bookId, Long adviserId, Long channelId, Integer isOpenCatalog) {
		bookAdviserDao.updateOpenCatalogState(bookId, adviserId, channelId, isOpenCatalog);
	}

	@Override
	public PageBeanNew<AdviserBookInfoDTO> getAllAdviserBook(Integer currentPage, Integer numPerPage) {
		return bookAdviserDao.listPageNew(new PageParam(currentPage, numPerPage),new HashMap<>(),"getAllAdviserBook");
	}

	@Override
	public Map<Long, BookDto> getBookMapByAdviserBookIds(List<Long> adviserBookIds) {
		return bookAdviserDao.getBookMapByAdviserBookIds(adviserBookIds);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateRaysField4Erp(List<RelateRaysBookApprovalVO> relateRaysBookList){
		if(CollUtil.isEmpty(relateRaysBookList)){
			return;
		}
		for (RelateRaysBookApprovalVO vo : relateRaysBookList) {
			if(vo.getIsApproval() == null){
				vo.setIsApproval(0);
			}
		}
		bookAdviserDao.updateRaysField4Erp(relateRaysBookList);
	}

	@Override
	public Boolean hasApprovalBook4Adviser(Long adviserId) {
		Integer count = bookAdviserDao.hasApprovalBook4Adviser(adviserId);
		return count > 0 ? true : false;
	}

	@Override
	@ParamLog("更新书籍手机号登录状态")
	public void updateBookPhoneAuth(Long bookId, Long adviserId, Long channelId, Integer bookPhoneAuth) {
		if (null == bookId || null == adviserId  || null == channelId || null == bookPhoneAuth) {
			throw new BizException(BizException.PARAM_IS_NULL.getCode(), "参数为空请确认");
		}
		bookAdviserDao.updateBookPhoneAuth(bookId, adviserId, channelId, bookPhoneAuth);

	}

	@Override
	@ParamLog("获取手机号登录状态")
	public Integer getBookPhoneAuth(Long sceneId, Long bookId, Long adviserId, Long channelId) {
		Integer bookPhoneAuth = YesOrNoEnums.NO.getValue();
		if(null == sceneId && null == bookId && null == adviserId && null == channelId) {
			return bookPhoneAuth;
		}
		if (null != bookId) {
			bookPhoneAuth = bookAdviserDao.getBookPhoneAuth(bookId, adviserId, channelId);
		} else if (null != sceneId) {
			//根据sceneId获取二维码信息
			Map<Long, QrcodeSceneDto> qrcodeSceneDtoMap = qrcodeSceneConsr.listBaseInfoByIds(Lists.newArrayList(sceneId));
			if (MapUtils.isEmpty(qrcodeSceneDtoMap) || null == qrcodeSceneDtoMap.get(sceneId)) {
				return bookPhoneAuth;
			}
			QrcodeSceneDto qrcodeSceneDto = qrcodeSceneDtoMap.get(sceneId);
			if (null == qrcodeSceneDto || null == qrcodeSceneDto.getAdviserBookId()) {
				return bookPhoneAuth;
			}
			bookPhoneAuth = bookAdviserDao.getBookPhoneAuth(qrcodeSceneDto.getAdviserBookId(), qrcodeSceneDto.getCreatedByUserLogin(),qrcodeSceneDto.getChannelPartyId());
		}

		return bookPhoneAuth;
	}
}
