public Map<String, Object> routeSearch(Map<String, Object> params) {
    if (isFreness(params)) {
      ArgCheckUtils.validataRequiredArgs("toDest", "page", params);
    } else {
      ArgCheckUtils.validataRequiredArgs("fromDest", "toDest", "page", params);
    }
    Map<String, Object> resultMap = new HashMap<String, Object>();

    ClientRouteSearchVO searchVo = new ClientRouteSearchVO();
    searchVo.setChannel(Constant.CHANNEL.CLIENT.name());
    List<String> productTypes = new ArrayList<String>();
    productTypes.add(Constant.PRODUCT_TYPE.ROUTE.name());
    searchVo.setProductType(productTypes);

    if (params.get("pageSize") != null) {
      searchVo.setPageSize(Integer.parseInt(params.get("pageSize").toString()));
    }

    if (params.get("subject") != null) {
      searchVo.setSubject(params.get("subject").toString());
    }

    if (params.get("palceId") != null) {
      searchVo.setPlaceId(params.get("palceId").toString());
    }

    searchVo.setPage(Integer.valueOf(params.get("page").toString()));

    if (params.get("searchType") != null) {
      if (params.get("subProductType") != null && !"".equals(params.get("subProductType"))) {
        String searchType = params.get("searchType").toString();
        if (this.isNotOverSeaTravel(searchType)) {
          if (params.get("fromDest") != null) {
            String fromDest = params.get("fromDest").toString();
            if (fromDest.contains(",")) {
              fromDest = fromDest.substring(0, fromDest.lastIndexOf(","));
              params.put("fromDest", fromDest);
            }
          }
        }
      }
    }

    if (params.get("subProductType") != null) {
      if (this.isFreness(params)) {
        params.put("fromDest", null);
      }
      searchVo.setSubProductType(ClientUtils.convetToList(params.get("subProductType").toString()));
    } else {
      searchVo.setSubProductType(new ArrayList<String>());
    }

    if (params.get("fromDest") != null) {
      searchVo.setFromDest(params.get("fromDest").toString());
    }

    if (params.get("toDest") != null) {
      searchVo.setToDest(StringUtil.subStringStrNoSuffix(params.get("toDest").toString(), 60));
    }

    if (params.get("sort") != null) {
      searchVo.setSort(params.get("sort").toString());
    }
    if (params.get("day") != null) {
      searchVo.setVisitDay(params.get("day").toString());
    }

    if (params.get("keyword") != null) {
      searchVo.setKeyword(StringUtil.subStringStrNoSuffix(params.get("keyword").toString(), 60));
    }

    Page<ProductBean> pageConfig = vstClientProductService.routeSearch(searchVo);
    List<MobileProductTitle> mpList = new ArrayList<MobileProductTitle>();
    Map<String, String> visitMap = new HashMap<String, String>();

    for (ProductBean productBean : pageConfig.getAllItems()) {
      if (!StringUtil.isEmptyString(productBean.getRouteTopic())) {
        String[] topics = productBean.getRouteTopic().split(",");
        for (String string : topics) {
          String str = StringUtils.trimAllWhitespace(string);
          visitMap.put(str, str);
        }
      }
    }

    List<Map<String, Object>> topicList = new ArrayList<Map<String, Object>>();
    Iterator<Entry<String, String>> it = visitMap.entrySet().iterator();

    // subjectList列表
    Map<String, Object> t_m = new HashMap<String, Object>();
    t_m.put("title", "全部主题");
    t_m.put("value", "");
    topicList.add(t_m);
    while (it.hasNext()) {
      Map<String, Object> m = new HashMap<String, Object>();
      Map.Entry<String, String> entry = (Map.Entry<String, String>) it.next();
      String key = entry.getKey();
      m.put("title", key);
      m.put("value", key);
      topicList.add(m);
    }

    for (ProductBean productBean : pageConfig.getItems()) {
      // 过滤掉超级自由行
      if ("true".equals(productBean.getSelfPack())) {
        continue;
      }
      MobileProductTitle mp = new MobileProductTitle();
      mp.setProductName(productBean.getProductName());
      mp.setMarketPriceYuan(productBean.getMarketPrice());
      mp.setSmallImage(productBean.getSmallImage());
      mp.setSellPriceYuan(productBean.getSellPrice());
      mp.setProductId(productBean.getProductId());
      mp.setClientOnly(Constant.CHANNEL.CLIENT.name().equals(productBean.getProductChannel()));
      // 返现金额 分
      mp.setMaxCashRefund(
          null == productBean.getCashRefund()
              ? 0l
              : PriceUtil.convertToFen(productBean.getCashRefund()));
      mp.setCmtNum(productBean.getCmtNum()); // 点评数
      mp.setSubProductType(productBean.getSubProductType()); // 主题类型
      mp.setVisitDay(productBean.getVisitDay() + ""); // 天数
      try {
        ProductSearchInfo psi =
            this.productSearchInfoService.queryProductSearchInfoByProductId(
                productBean.getProductId());
        mp.setHasBusinessCoupon(ClientUtils.hasBusinessCoupon(psi)); // 优惠
      } catch (Exception e) {
        e.printStackTrace();
      }

      mpList.add(mp);
    }

    resultMap.put("subjects", topicList);
    resultMap.put("datas", mpList);
    resultMap.put("isLastPage", isLastPage(pageConfig));
    return resultMap;
  }
  /** 获得景点酒店详细信息 */
  @Override
  public MobilePlace getPlace(Map<String, Object> param) {
    ArgCheckUtils.validataRequiredArgs("placeId", param);
    Long placeId = Long.valueOf(param.get("placeId") + "");
    Place place = this.placeService.queryPlaceByPlaceId(placeId);
    if (place == null) {
      throw new NotFoundException("未找到相关景点");
    }

    // 景点基本介绍
    MobilePlace mp = new MobilePlace();
    mp.setScenicOpenTime(place.getScenicOpenTime());
    mp.setId(place.getPlaceId());
    mp.setName(place.getName());
    mp.setAddress(place.getAddress());
    mp.setHasActivity("Y".equals(place.getIsHasActivity()));
    mp.setDescription(StringUtil.filterOutHTMLTags(place.getDescription())); // 景点介绍
    if (mp.getDescription() != null) {
      String d = mp.getDescription().replaceAll("&nbsp;", "").replaceAll("&amp;", "");
      mp.setDescription(d);
    }
    mp.setRecommendReason(StringUtil.filterOutHTMLTags(place.getRemarkes()));
    mp.setStage(place.getStage());
    mp.setOrderNotice(ClientUtils.filterOutHTMLTags(place.getOrderNotice()));
    mp.setImportantTips(place.getImportantTips());

    // 旅游保障
    mp.setGuaranteeOptions(this.getGuaranteeOptions(place));

    // 是否收藏.
    mp.setHasIn(false); // 默认false
    if (param.get("userNo") != null) {
      String userId = param.get("userNo").toString();
      if (!StringUtil.isEmptyString(userId)) {
        UserUser user = userUserProxy.getUserUserByUserNo(userId);
        if (user != null) {
          Map<String, Object> p = new HashMap<String, Object>();
          p.put("objectId", placeId);
          p.put("userId", user.getId());
          List<MobileFavorite> queryMobileFavoriteLis =
              mobileFavoriteService.queryMobileFavoriteList(p);
          if (null != queryMobileFavoriteLis && queryMobileFavoriteLis.size() > 0) {
            mp.setHasIn(true);
          }
        }
      }
    }

    // 标的(城市,景点,酒店)相关搜索
    PlaceSearchInfo psi = placeSearchInfoService.getPlaceSearchInfoByPlaceId(placeId);

    if (psi.getTodayOrderLastTime() != null) {
      // 最晚可订时间
      MobilePlaceAddInfo mpAddInfo = new MobilePlaceAddInfo();
      Date todayOrderLastTime = psi.getTodayOrderLastTime();
      Date today = new Date();
      SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
      // 是否可定今日票
      Calendar c = Calendar.getInstance();
      c.setTime(todayOrderLastTime);
      if (sdf.format(todayOrderLastTime).equals(sdf.format(today))) {
        String hourStr = "";
        String minuteStr = "";
        if (c.get(Calendar.HOUR_OF_DAY) == 0) {
          hourStr = "00";
        } else if (c.get(Calendar.HOUR_OF_DAY) > 0 && c.get(Calendar.HOUR_OF_DAY) < 10) {
          hourStr = "0" + c.get(Calendar.HOUR_OF_DAY);
        } else {
          hourStr = String.valueOf(c.get(Calendar.HOUR_OF_DAY));
        }
        if (c.get(Calendar.MINUTE) == 0) {
          minuteStr = "00";
        } else if (c.get(Calendar.MINUTE) > 0 && c.get(Calendar.MINUTE) < 10) {
          minuteStr = "0" + c.get(Calendar.MINUTE);
        } else {
          minuteStr = String.valueOf(c.get(Calendar.MINUTE));
        }
        mpAddInfo.setTicketType(Constant.TICKET_TYPE.TIKET_TODAY.getCode());
        mpAddInfo.setLastOrderTimeDesc("当天" + hourStr + ":" + minuteStr + "前");
      } else {
        Calendar c2 = Calendar.getInstance();
        c2.setTime(new Date());
        long milliseconds1 = c.getTimeInMillis();
        long milliseconds2 = c2.getTimeInMillis();
        long diff = 0;

        if (milliseconds1 > milliseconds2) {
          diff = milliseconds1 - milliseconds2;
        } else {
          diff = milliseconds2 - milliseconds1;
        }

        long nd = 1000 * 24 * 60 * 60; // 一天的毫秒数
        long nh = 1000 * 60 * 60; // 一小时的毫秒数
        long nm = 1000 * 60; // 一分钟的毫秒数

        long diffDays = diff / nd + 1; // 计算差多少天
        long diffHour = diff % nd / nh; // 计算差多少小时
        long diffMinute = diff % nd % nh / nm; // 计算差多少分钟

        String diffHourStr = "";
        String diffMinuteStr = "";

        if (diffHour == 0) {
          diffHourStr = "00";
        } else if (diffHour > 0 && diffHour < 10) {
          diffHourStr = "0" + diffHour;
        } else {
          diffHourStr = diffHour + "";
        }

        if (diffMinute == 0) {
          diffMinuteStr = "00";
        } else if (diffMinute > 0 && diffMinute < 10) {
          diffMinuteStr = "0" + diffMinute;
        } else {
          diffMinuteStr = diffMinute + "";
        }

        mpAddInfo.setTicketType(Constant.TICKET_TYPE.TIKET_NORMAL.getCode());
        mpAddInfo.setLastOrderTimeDesc(
            "前" + diffDays + "天" + diffHourStr + ":" + diffMinuteStr + "前");
      }

      mpAddInfo.setLastOrderTime(Calendar.getInstance().getTime());
      mp.setMpAddInfo(mpAddInfo);
    }

    mp.setCmtNum(null == psi.getCmtNum() ? "" : String.valueOf(psi.getCmtNum())); // 点评总数
    mp.setCmtStarts(null == psi.getCmtNiceRate() ? "" : psi.getCmtNiceRate() + ""); // 点评评价分数 .
    mp.setMarketPriceYuan(PriceUtil.convertToYuan(psi.getMarketPrice()));
    mp.setSellPriceYuan(psi.getProductsPriceInteger().floatValue());
    Map<String, Object> coordinateParam = new HashMap<String, Object>();
    coordinateParam.put("placeId", placeId);
    List<PlaceCoordinateVo> listGoogle =
        placeCoordinateGoogleService.getGoogleMapListByParams(coordinateParam);
    if (!listGoogle.isEmpty()) {
      PlaceCoordinateVo pcv = listGoogle.get(0);
      mp.setGoogleLatitude(pcv.getLatitude());
      mp.setGoogleLongitude(pcv.getLongitude());
    }

    List<PlaceCoordinateVo> listBaidu =
        placeCoordinateBaiduService.getBaiduMapListByParams(coordinateParam);
    if (!listBaidu.isEmpty()) {
      PlaceCoordinateVo pcv = listBaidu.get(0);
      mp.setBaiduLatitude(pcv.getLatitude());
      mp.setBaiduLongitude(pcv.getLongitude());
    }

    // 图片
    PlacePhoto pp = new PlacePhoto();
    pp.setType(PlacePhotoTypeEnum.LARGE.name());
    pp.setPlaceId(place.getPlaceId());
    List<PlacePhoto> ppList = this.placePhotoService.queryByPlacePhoto(pp);
    if (!"1".equals(mp.getStage())) {
      List<String> imageList = new ArrayList<String>();
      if (ppList != null && ppList.size() != 0) {
        for (PlacePhoto placePhoto : ppList) {
          if (!StringUtil.isEmptyString(placePhoto.getImagesUrl())) {
            imageList.add(placePhoto.getImagesUrl());
          }
        }
      }
      mp.setImageList(imageList);
    }

    Map<String, Object> parameters = new HashMap<String, Object>();
    parameters.put("placeId", placeId);
    if (place.getMiddleImage() != null) {
      mp.setMiddleImage(place.getMiddleImage());
    } else {
      mp.setMiddleImage(psi.getMiddleImage());
    }

    List<CmtLatitudeStatistics> cmtLatitudeStatisticsList =
        cmtLatitudeStatistisService.getLatitudeStatisticsList(parameters);
    List<PlaceCmtScoreVO> pcsVoList = new ArrayList<PlaceCmtScoreVO>();
    for (CmtLatitudeStatistics cmtLatitudeStatistics : cmtLatitudeStatisticsList) {
      PlaceCmtScoreVO pcv = new PlaceCmtScoreVO();
      pcv.setName(cmtLatitudeStatistics.getLatitudeName());
      pcv.setScore(
          null == cmtLatitudeStatistics.getAvgScore()
              ? ""
              : cmtLatitudeStatistics.getAvgScore() + "");
      if (cmtLatitudeStatistics.getLatitudeId().equals("FFFFFFFFFFFFFFFFFFFFFFFFFFFF")) {
        pcv.setName("总评");
        pcv.setMain(true);
      }
      pcsVoList.add(pcv);
    }
    mp.setPlaceCmtScoreList(pcsVoList);

    // 判断是否有门票产品 和 自由行产品

    mp.setHasRoute(psi.getRouteNum() > 0 || psi.getFreenessNum() > 0);
    ProductList productList =
        this.productSearchInfoService.getIndexProductByPlaceIdAnd4TypeAndTicketBranch(
            place.getPlaceId(), 1000, Constant.CHANNEL.CLIENT.name());
    if (productList != null && productList.getProductTicketList().size() > 0) {
      mp.setHasTicket(true);
    }
    /** ********** V3.1 ************** */
    // 设置主题类型 subject
    mp.setSubject(place.getFirstTopic());
    // 返现金额 (是分 还是元)
    mp.setMaxCashRefund(
        StringUtils.isEmpty(psi.getCashRefund())
            ? 0l
            : PriceUtil.convertToFen(psi.getCashRefund()));
    // 是否今日可定

    mp.setCanOrderToday(psi.canOrderTodayCurrentTimeForPlace());

    // 交通信息
    mp.setTrafficInfo(
        place.getTrafficInfo() == null
            ? ""
            : ClientUtils.filterOutHTMLTags(place.getTrafficInfo()));
    try {
      mp.setHasBusinessCoupon(ClientUtils.hasBusinessCoupon(psi)); // 优惠
    } catch (Exception e) {
      e.printStackTrace();
    }
    return mp;
  }