Browse Source

重新实现店铺推荐功能

huxz 8 years ago
parent
commit
ad3bc5c62d
22 changed files with 805 additions and 58 deletions
  1. 56 0
      src/main/java/com/uas/platform/b2c/advertise/ad/api/StoreAdsController.java
  2. 40 0
      src/main/java/com/uas/platform/b2c/advertise/ad/dao/StoreAdsDao.java
  3. 142 0
      src/main/java/com/uas/platform/b2c/advertise/ad/model/StoreAds.java
  4. 13 0
      src/main/java/com/uas/platform/b2c/advertise/ad/model/StoreAdsType.java
  5. 55 0
      src/main/java/com/uas/platform/b2c/advertise/ad/service/StoreAdsService.java
  6. 132 0
      src/main/java/com/uas/platform/b2c/advertise/ad/service/impl/StoreAdsServiceImpl.java
  7. 28 0
      src/main/java/com/uas/platform/b2c/prod/store/controller/StoreInformationController.java
  8. 20 0
      src/main/java/com/uas/platform/b2c/prod/store/exception/EmptyParameterException.java
  9. 14 0
      src/main/java/com/uas/platform/b2c/prod/store/model/StoreIn.java
  10. 17 0
      src/main/java/com/uas/platform/b2c/prod/store/service/StoreInService.java
  11. 65 1
      src/main/java/com/uas/platform/b2c/prod/store/service/impl/StoreInServiceImpl.java
  12. 9 1
      src/main/java/com/uas/platform/b2c/prod/store/service/impl/StoreViolationsServiceImpl.java
  13. 7 0
      src/main/webapp/resources/js/admin/controllers/StoreInfoListCtrl.js
  14. 34 1
      src/main/webapp/resources/js/common/module/store_admin_violations_module.js
  15. 47 0
      src/main/webapp/resources/js/common/query/storeInfo.js
  16. 38 17
      src/main/webapp/resources/js/provider/controllers/ProviderFactoriesCtrl.js
  17. 42 12
      src/main/webapp/resources/js/provider/controllers/ProviderHomeCtrl.js
  18. 19 3
      src/main/webapp/resources/js/provider/controllers/ProviderListCtrl.js
  19. 22 18
      src/main/webapp/resources/view/admin/store/fragments/enterprise_info.html
  20. 2 2
      src/main/webapp/resources/view/admin/store_info_list.html
  21. 1 1
      src/main/webapp/resources/view/provider/home/sale_outstanding_store.html
  22. 2 2
      src/main/webapp/resources/view/provider/provider_factories.html

+ 56 - 0
src/main/java/com/uas/platform/b2c/advertise/ad/api/StoreAdsController.java

@@ -0,0 +1,56 @@
+package com.uas.platform.b2c.advertise.ad.api;
+
+import com.uas.platform.b2c.advertise.ad.model.StoreAds;
+import com.uas.platform.b2c.advertise.ad.service.StoreAdsService;
+import com.uas.platform.b2c.prod.store.model.StoreType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.web.PageableDefault;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 店铺广告接口类
+ *
+ * @author huxz
+ * @version 2017-08-30 10:38:36 创建文件
+ */
+@RestController
+@RequestMapping(value = "/api/ads/store")
+public class StoreAdsController {
+
+	private final StoreAdsService adsService;
+
+	@Autowired
+	public StoreAdsController(StoreAdsService adsService) {
+		this.adsService = adsService;
+	}
+
+	/**
+	 * 用户获取热销店铺列表信息
+	 * tip: 分页查询默认从第0页开始进行查询,因而,第1页查询不到信息
+	 *
+	 * @param page		分页参数
+	 * @param types		店铺类型
+	 */
+	@RequestMapping(method = RequestMethod.GET, value = "/sales-list", produces = MediaType.APPLICATION_JSON_VALUE)
+	List<StoreAds> showSalesListWhenUserQuery(@PageableDefault(size = 5, sort = "updateTime", direction = Sort.Direction.DESC) Pageable page, StoreType[] types) {
+		return adsService.showSalesListWhenUserQuery(page, types);
+	}
+
+	/**
+	 * 用户获取优秀店铺列表信息
+	 *
+	 * @param page		分页参数
+	 * @param types		店铺类型
+	 */
+	@RequestMapping(method = RequestMethod.GET, value = "/excellence-list", produces = MediaType.APPLICATION_JSON_VALUE)
+	List<StoreAds> showExcellenceListWhenUserQuery(@PageableDefault(size = 5, sort = "updateTime", direction = Sort.Direction.DESC) Pageable page, StoreType[] types) {
+		return adsService.showExcellenceListWhenUserQuery(page, types);
+	}
+}

+ 40 - 0
src/main/java/com/uas/platform/b2c/advertise/ad/dao/StoreAdsDao.java

@@ -0,0 +1,40 @@
+package com.uas.platform.b2c.advertise.ad.dao;
+
+import com.uas.platform.b2c.advertise.ad.model.StoreAds;
+import com.uas.platform.b2c.advertise.ad.model.StoreAdsType;
+import com.uas.platform.b2c.prod.store.model.StoreType;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+@Repository
+public interface StoreAdsDao extends JpaSpecificationExecutor<StoreAds>, JpaRepository<StoreAds, Long> {
+
+	/**
+	 * 根据店铺ID获取店铺广告信息
+	 *
+	 * @param storeId	店铺ID
+	 */
+	List<StoreAds> findByStoreId(Long storeId);
+
+	/**
+	 * 根据店铺ID和店铺广告类型查询店铺广告信息
+	 *
+	 * @param storeId	店铺ID
+	 * @param type		店铺广告类型
+	 */
+	StoreAds findByStoreIdAndType(Long storeId, StoreAdsType type);
+
+	/**
+	 * 分页获取某种广告类型的特定店铺类型的店铺广告信息
+	 *
+	 * @param type 		店铺广告类型
+	 * @param types		店铺类型
+	 * @param pageable	分页参数
+	 */
+	Page<StoreAds> findByTypeAndStoreTypeIn(StoreAdsType type, StoreType[] types, Pageable pageable);
+}

+ 142 - 0
src/main/java/com/uas/platform/b2c/advertise/ad/model/StoreAds.java

@@ -0,0 +1,142 @@
+package com.uas.platform.b2c.advertise.ad.model;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.uas.platform.b2c.core.utils.JacksonUtils;
+import com.uas.platform.b2c.prod.store.model.StoreIn;
+import com.uas.platform.b2c.prod.store.model.StoreType;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Index;
+import javax.persistence.SequenceGenerator;
+import javax.persistence.Table;
+import javax.persistence.Transient;
+import java.util.Date;
+
+/**
+ * 店铺广告实体类
+ *
+ * @author huxz
+ * @version 2017-08-30 09:29:29 创建文件
+ */
+@Entity
+@Table(name = "store$ads", indexes = @Index(name = "store_ads_type_unique", columnList = "ad_type,ad_st_id", unique = true))
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class StoreAds {
+
+	/**
+	 * ID
+	 */
+	@Id
+	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "store$ads_gen")
+	@SequenceGenerator(name = "store$ads_gen", sequenceName = "store$ads_seq", allocationSize = 1)
+	@Column(name = "id")
+	private Long id;
+
+	/**
+	 * 广告类型
+	 */
+	@Column(name = "ad_type")
+	@Enumerated(EnumType.STRING)
+	private StoreAdsType type;
+
+	/**
+	 * 店铺类型
+	 */
+	@Column(name = "ad_st_type")
+	@Enumerated(EnumType.STRING)
+	private StoreType storeType;
+
+	/**
+	 * 店铺ID
+	 */
+	@Column(name = "ad_st_id")
+	private Long storeId;
+
+	/**
+	 * 店铺信息
+	 */
+	@Transient
+	private StoreIn store;
+
+	/**
+	 * 店铺创建时间
+	 */
+	@Column(name = "ad_create_time")
+	private Date createTime;
+
+	/**
+	 * 店铺更新时间
+	 */
+	@Column(name = "ad_update_time")
+	private Date updateTime;
+
+	public StoreAds() {
+	}
+
+	public Long getId() {
+		return id;
+	}
+
+	public void setId(Long id) {
+		this.id = id;
+	}
+
+	public StoreAdsType getType() {
+		return type;
+	}
+
+	public void setType(StoreAdsType type) {
+		this.type = type;
+	}
+
+	public StoreType getStoreType() {
+		return storeType;
+	}
+
+	public void setStoreType(StoreType storeType) {
+		this.storeType = storeType;
+	}
+
+	public Long getStoreId() {
+		return storeId;
+	}
+
+	public void setStoreId(Long storeId) {
+		this.storeId = storeId;
+	}
+
+	public StoreIn getStore() {
+		return store;
+	}
+
+	public void setStore(StoreIn store) {
+		this.store = store;
+	}
+
+	public Date getCreateTime() {
+		return createTime;
+	}
+
+	public void setCreateTime(Date createTime) {
+		this.createTime = createTime;
+	}
+
+	public Date getUpdateTime() {
+		return updateTime;
+	}
+
+	public void setUpdateTime(Date updateTime) {
+		this.updateTime = updateTime;
+	}
+
+	@Override
+	public String toString() {
+		return JacksonUtils.toJson(this);
+	}
+}

+ 13 - 0
src/main/java/com/uas/platform/b2c/advertise/ad/model/StoreAdsType.java

@@ -0,0 +1,13 @@
+package com.uas.platform.b2c.advertise.ad.model;
+
+/**
+ * 店铺广告类型
+ *
+ * @author huxz
+ * @version 2017-08-30 09:18:59 创建文件
+ */
+public enum StoreAdsType {
+	NEW_LIST,			// 新开店铺
+	SALES_LIST,			// 热销店铺
+	EXCELLENCE_LIST		// 优秀店铺
+}

+ 55 - 0
src/main/java/com/uas/platform/b2c/advertise/ad/service/StoreAdsService.java

@@ -0,0 +1,55 @@
+package com.uas.platform.b2c.advertise.ad.service;
+
+import com.uas.platform.b2c.advertise.ad.model.StoreAds;
+import com.uas.platform.b2c.advertise.ad.model.StoreAdsType;
+import com.uas.platform.b2c.prod.store.model.StoreType;
+import org.springframework.data.domain.Pageable;
+
+import java.util.List;
+
+/**
+ * 店铺广告业务类
+ *
+ * @author huxz
+ * @version 2017-08-30 09:46:15 创建文件
+ */
+public interface StoreAdsService {
+
+	/**
+	 * 管理推荐时,保存店铺广告信息
+	 *
+	 * @param ads	店铺广告信息
+	 */
+	StoreAds saveWhenAdminRecommend(StoreAds ads);
+
+	/**
+	 * 取消店铺推荐时,删除推荐信息
+	 *
+	 * @param storeId	店铺ID
+	 * @param type		店铺广告类型
+	 */
+	StoreAds deleteOneWhenAdminCancel(Long storeId, StoreAdsType type);
+
+	/**
+	 * 当店铺关闭时,删除对应店铺的广告信息
+	 *
+	 * @param storeId	店铺ID
+	 */
+	List<StoreAds> deleteWhenStoreClose(Long storeId);
+
+	/**
+	 * 用户获取热销店铺列表信息
+	 *
+	 * @param page		分页参数
+	 * @param types		店铺类型
+	 */
+	List<StoreAds> showSalesListWhenUserQuery(Pageable page, StoreType[] types);
+
+	/**
+	 * 用户获取优秀店铺列表信息
+	 *
+	 * @param page		分页参数
+	 * @param types		店铺类型
+	 */
+	List<StoreAds> showExcellenceListWhenUserQuery(Pageable page, StoreType[] types);
+}

+ 132 - 0
src/main/java/com/uas/platform/b2c/advertise/ad/service/impl/StoreAdsServiceImpl.java

@@ -0,0 +1,132 @@
+package com.uas.platform.b2c.advertise.ad.service.impl;
+
+import com.uas.platform.b2c.advertise.ad.dao.StoreAdsDao;
+import com.uas.platform.b2c.advertise.ad.model.StoreAds;
+import com.uas.platform.b2c.advertise.ad.model.StoreAdsType;
+import com.uas.platform.b2c.advertise.ad.service.StoreAdsService;
+import com.uas.platform.b2c.prod.store.dao.StoreInDao;
+import com.uas.platform.b2c.prod.store.exception.EmptyParameterException;
+import com.uas.platform.b2c.prod.store.model.StoreIn;
+import com.uas.platform.b2c.prod.store.model.StoreType;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+
+/**
+ * 店铺广告业务实现类
+ *
+ * @author huxz
+ * @version 2017-08-30 09:46:15 创建文件
+ */
+@Service
+public class StoreAdsServiceImpl implements StoreAdsService {
+
+	private final StoreAdsDao adsDao;
+
+	private final StoreInDao storeInDao;
+
+	@Autowired
+	public StoreAdsServiceImpl(StoreAdsDao adsDao, StoreInDao storeInDao) {
+		this.adsDao = adsDao;
+		this.storeInDao = storeInDao;
+	}
+
+	@Override
+	public StoreAds saveWhenAdminRecommend(StoreAds ads) {
+		if (ads.getStoreType() == null || ads.getStoreId() == null || ads.getType() == null) {
+			return null;
+		}
+		Date date = new Date();
+
+		ads.setCreateTime(date);
+		ads.setUpdateTime(date);
+
+		return adsDao.save(ads);
+	}
+
+	@Override
+	public StoreAds deleteOneWhenAdminCancel(Long storeId, StoreAdsType type) {
+		if (storeId == null) {
+			throw new EmptyParameterException("店铺ID不能为空");
+		}
+		if (type == null) {
+			throw new EmptyParameterException("店铺广告类型不能为空");
+		}
+
+		StoreAds ads = adsDao.findByStoreIdAndType(storeId, type);
+		if (ads != null) {
+			adsDao.delete(ads);
+		}
+		return ads;
+	}
+
+	@Override
+	public List<StoreAds> deleteWhenStoreClose(Long storeId) {
+		if (storeId == null) {
+			return Collections.emptyList();
+		}
+
+		List<StoreAds> adsList = adsDao.findByStoreId(storeId);
+		if (CollectionUtils.isEmpty(adsList)) {
+			return Collections.emptyList();
+		}
+
+		adsDao.delete(adsList);
+		return adsList;
+	}
+
+	@Override
+	public List<StoreAds> showSalesListWhenUserQuery(Pageable page, StoreType[] types) {
+		if (page == null || types == null || types.length == 0) {
+			return Collections.emptyList();
+		}
+
+		Page<StoreAds> adsPage = adsDao.findByTypeAndStoreTypeIn(StoreAdsType.SALES_LIST, types, page);
+		List<StoreAds> adsList = CollectionUtils.isEmpty(adsPage.getContent()) ? Collections.<StoreAds>emptyList() : adsPage.getContent();
+
+		handlerStoreAdsInformation(adsList);
+
+		// TODO 统计订单的数量
+
+		return adsList;
+	}
+
+	@Override
+	public List<StoreAds> showExcellenceListWhenUserQuery(Pageable page, StoreType[] types) {
+		if (page == null || types == null || types.length == 0) {
+			return Collections.emptyList();
+		}
+
+		Page<StoreAds> adsPage = adsDao.findByTypeAndStoreTypeIn(StoreAdsType.EXCELLENCE_LIST, types, page);
+		List<StoreAds> adsList = CollectionUtils.isEmpty(adsPage.getContent()) ? Collections.<StoreAds>emptyList() : adsPage.getContent();
+
+		handlerStoreAdsInformation(adsList);
+
+		return adsList;
+	}
+
+	/**
+	 * 处理店铺广告信息,并添加店铺信息
+	 *
+	 * @param adsList	店铺广告列表
+	 */
+	private void handlerStoreAdsInformation(List<StoreAds> adsList) {
+		Iterator<StoreAds> iterator = adsList.iterator();
+		while (iterator.hasNext()) {
+			StoreAds ads = iterator.next();
+			StoreIn store = storeInDao.findOne(ads.getStoreId());
+			if (store == null) {
+				iterator.remove();
+			} else {
+				ads.setStore(store);
+			}
+		}
+	}
+}

+ 28 - 0
src/main/java/com/uas/platform/b2c/prod/store/controller/StoreInformationController.java

@@ -1,15 +1,19 @@
 package com.uas.platform.b2c.prod.store.controller;
 
+import com.uas.platform.b2c.advertise.ad.model.StoreAdsType;
 import com.uas.platform.b2c.prod.store.model.StoreIn;
 import com.uas.platform.b2c.prod.store.model.StoreStatus;
 import com.uas.platform.b2c.prod.store.service.StoreInService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
 import org.springframework.stereotype.Controller;
 import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
+import org.springframework.web.bind.annotation.ResponseBody;
 
 /**
  * 店铺页面调整控制器
@@ -51,4 +55,28 @@ public class StoreInformationController {
 		}
 	}
 
+	/**
+	 * 当管理员推荐店铺的时候,保存店铺的广告信息
+	 *
+	 * @param type		店铺广告类型
+	 * @param store		店铺信息
+	 */
+	@ResponseBody
+	@RequestMapping(method = RequestMethod.PUT, value = "/auth/api/store/tag-store", produces = MediaType.APPLICATION_JSON_VALUE)
+	public StoreIn tagStoreInWhenAdminRecommend(StoreAdsType type, @RequestBody StoreIn store) {
+		return storeService.tagStoreInWhenAdminRecommend(type, store);
+	}
+
+	/**
+	 * 当管理员推荐店铺的时候,取消推荐店铺
+	 *
+	 * @param type		店铺广告类型
+	 * @param store		店铺信息
+	 */
+	@ResponseBody
+	@RequestMapping(method = RequestMethod.PUT, value = "/auth/api/store/cancel-tag", produces = MediaType.APPLICATION_JSON_VALUE)
+	public StoreIn cancelStoreTagsWhenAdminCancel(StoreAdsType type, @RequestBody StoreIn store) {
+		return storeService.cancelStoreTagsWhenAdminCancel(type, store);
+	}
+
 }

+ 20 - 0
src/main/java/com/uas/platform/b2c/prod/store/exception/EmptyParameterException.java

@@ -0,0 +1,20 @@
+package com.uas.platform.b2c.prod.store.exception;
+
+/**
+ * 参数为空异常
+ */
+public class EmptyParameterException extends RuntimeException {
+
+	private static final long serialVersionUID = 1L;
+
+	public EmptyParameterException() {
+	}
+
+	public EmptyParameterException(String message) {
+		super(message);
+	}
+
+	public EmptyParameterException(Throwable cause) {
+		super(cause);
+	}
+}

+ 14 - 0
src/main/java/com/uas/platform/b2c/prod/store/model/StoreIn.java

@@ -159,6 +159,12 @@ public class StoreIn implements Serializable {
 	@Column(name = "st_en_qualification", length = 4000)
 	private String enQualification;
 
+	/**
+	 * 店铺标签
+	 */
+	@Column(name = "st_tags")
+	private String tags = "[]";
+
 	/*+************************************************************************
 	 * 资质信息
 	 **************************************************************************/
@@ -365,4 +371,12 @@ public class StoreIn implements Serializable {
 	public void setBrands(Set<StoreBrandInfo> brands) {
 		this.brands = brands;
 	}
+
+	public String getTags() {
+		return tags;
+	}
+
+	public void setTags(String tags) {
+		this.tags = tags;
+	}
 }

+ 17 - 0
src/main/java/com/uas/platform/b2c/prod/store/service/StoreInService.java

@@ -1,5 +1,6 @@
 package com.uas.platform.b2c.prod.store.service;
 
+import com.uas.platform.b2c.advertise.ad.model.StoreAdsType;
 import com.uas.platform.b2c.prod.store.model.StoreApply;
 import com.uas.platform.b2c.prod.store.model.StoreIn;
 import com.uas.platform.b2c.prod.store.model.StoreStatus;
@@ -143,4 +144,20 @@ public interface StoreInService {
 	 * @param keyword     查询关键字
 	 */
 	Page<StoreIn> pageStoreInfoWhenAdminQuery(PageInfo pageInfo, StoreType type, StoreStatus status, String keyword);
+
+	/**
+	 * 当管理员推荐店铺的时候,保存店铺的广告信息
+	 *
+	 * @param type		店铺广告类型
+	 * @param store		店铺信息
+	 */
+	StoreIn tagStoreInWhenAdminRecommend(StoreAdsType type, StoreIn store);
+
+	/**
+	 * 当管理员推荐店铺的时候,取消店铺的广告推荐
+	 *
+	 * @param type		店铺广告类型
+	 * @param store		店铺信息
+	 */
+	StoreIn cancelStoreTagsWhenAdminCancel(StoreAdsType type, StoreIn store);
 }

+ 65 - 1
src/main/java/com/uas/platform/b2c/prod/store/service/impl/StoreInServiceImpl.java

@@ -1,7 +1,11 @@
 package com.uas.platform.b2c.prod.store.service.impl;
 
+import com.uas.platform.b2c.advertise.ad.model.StoreAds;
+import com.uas.platform.b2c.advertise.ad.model.StoreAdsType;
+import com.uas.platform.b2c.advertise.ad.service.StoreAdsService;
 import com.uas.platform.b2c.core.config.SysConf;
 import com.uas.platform.b2c.core.support.SystemSession;
+import com.uas.platform.b2c.core.utils.JacksonUtils;
 import com.uas.platform.b2c.core.utils.UuidUtils;
 import com.uas.platform.b2c.prod.commodity.dao.GoodsDao;
 import com.uas.platform.b2c.prod.product.component.dao.ComponentDao;
@@ -9,6 +13,7 @@ import com.uas.platform.b2c.prod.product.component.modal.Component;
 import com.uas.platform.b2c.prod.store.dao.QualificationDao;
 import com.uas.platform.b2c.prod.store.dao.StoreBrandInfoDao;
 import com.uas.platform.b2c.prod.store.dao.StoreInDao;
+import com.uas.platform.b2c.prod.store.exception.EmptyParameterException;
 import com.uas.platform.b2c.prod.store.model.Qualification;
 import com.uas.platform.b2c.prod.store.model.StoreApply;
 import com.uas.platform.b2c.prod.store.model.StoreBrandInfo;
@@ -71,16 +76,19 @@ public class StoreInServiceImpl implements StoreInService {
 
 	private final StoreBrandInfoDao brandInfoDao;
 
+	private final StoreAdsService adsService;
+
 	private final SysConf sysConf;
 
 	@Autowired
-	public StoreInServiceImpl(StoreInDao storeDao, QualificationDao qualificationDao, GoodsDao goodsDao, ComponentDao componentDao, PurchaseDao purchaseDao, StoreBrandInfoDao brandInfoDao, SysConf sysConf) {
+	public StoreInServiceImpl(StoreInDao storeDao, QualificationDao qualificationDao, GoodsDao goodsDao, ComponentDao componentDao, PurchaseDao purchaseDao, StoreBrandInfoDao brandInfoDao, StoreAdsService adsService, SysConf sysConf) {
 		this.storeDao = storeDao;
 		this.qualificationDao = qualificationDao;
 		this.goodsDao = goodsDao;
 		this.componentDao = componentDao;
 		this.purchaseDao = purchaseDao;
 		this.brandInfoDao = brandInfoDao;
+		this.adsService = adsService;
 		this.sysConf = sysConf;
 	}
 
@@ -417,6 +425,62 @@ public class StoreInServiceImpl implements StoreInService {
 		}, pageInfo);
 	}
 
+	@Override
+	@Transactional
+	public StoreIn tagStoreInWhenAdminRecommend(StoreAdsType type, StoreIn store) {
+		if (type == null) {
+			throw  new EmptyParameterException("店铺广告类型不能为空");
+		}
+		if (store == null || store.getId() == null) {
+			throw new EmptyParameterException("待推荐店铺的ID不能为空");
+		}
+
+		store = storeDao.findOne(store.getId());
+
+		StoreAds ads = new StoreAds();
+		ads.setStoreId(store.getId());
+		ads.setStoreType(store.getType());
+		ads.setType(type);
+
+		ads = adsService.saveWhenAdminRecommend(ads);
+
+		if (ads != null) {
+			// 为店铺打上标签
+			String tagsJson = StringUtils.isEmpty(store.getTags()) ? "[]" : store.getTags();
+			List<StoreAdsType> tags = JacksonUtils.fromJsonArray(tagsJson, StoreAdsType.class);
+			Set<StoreAdsType> tagSet = new HashSet<>(tags);
+			tagSet.add(type);
+			store.setTags(JacksonUtils.toJson(tagSet));
+
+			storeDao.save(store);
+		}
+		return store;
+	}
+
+	@Override
+	@Transactional
+	public StoreIn cancelStoreTagsWhenAdminCancel(StoreAdsType type, StoreIn store) {
+		if (type == null) {
+			throw  new EmptyParameterException("店铺广告类型不能为空");
+		}
+		if (store == null || store.getId() == null) {
+			throw new EmptyParameterException("待推荐店铺的ID不能为空");
+		}
+
+		store = storeDao.findOne(store.getId());
+		StoreAds ads = adsService.deleteOneWhenAdminCancel(store.getId(), type);
+
+		// 为店铺打上标签
+		String tagsJson = StringUtils.isEmpty(store.getTags()) ? "[]" : store.getTags();
+		List<StoreAdsType> tags = JacksonUtils.fromJsonArray(tagsJson, StoreAdsType.class);
+		Set<StoreAdsType> tagSet = new HashSet<>(tags);
+		tagSet.remove(type);
+		store.setTags(JacksonUtils.toJson(tagSet));
+
+		storeDao.save(store);
+		return store;
+	}
+
 	@Override
 	public List<StoreIn> findFiveStores(String types, Integer num) {
 		String[] typeArray = types.split("-");

+ 9 - 1
src/main/java/com/uas/platform/b2c/prod/store/service/impl/StoreViolationsServiceImpl.java

@@ -1,5 +1,6 @@
 package com.uas.platform.b2c.prod.store.service.impl;
 
+import com.uas.platform.b2c.advertise.ad.service.StoreAdsService;
 import com.uas.platform.b2c.common.account.model.User;
 import com.uas.platform.b2c.core.support.SystemSession;
 import com.uas.platform.b2c.prod.store.dao.StoreInDao;
@@ -42,12 +43,15 @@ import java.util.List;
 @Service
 public class StoreViolationsServiceImpl implements StoreViolationsService {
 
+	private final StoreAdsService storeAdsService;
+
 	private final StoreViolationsDao violationsDao;
 
 	private final StoreInDao storeInDao;
 
 	@Autowired
-	public StoreViolationsServiceImpl(StoreViolationsDao violationsDao, StoreInDao storeInDao) {
+	public StoreViolationsServiceImpl(StoreAdsService storeAdsService, StoreViolationsDao violationsDao, StoreInDao storeInDao) {
+		this.storeAdsService = storeAdsService;
 		this.violationsDao = violationsDao;
 		this.storeInDao = storeInDao;
 	}
@@ -104,8 +108,12 @@ public class StoreViolationsServiceImpl implements StoreViolationsService {
 		// 设置店铺状态为违规关店
 		storeIn.setUpdateTime(new Date());
 		storeIn.setStatus(StoreStatus.CLOSED);
+		storeIn.setTags("[]");		// 清除推荐标签信息
 		storeInDao.save(storeIn);
 
+		// 去除违规店铺的推荐状态
+		storeAdsService.deleteWhenStoreClose(storeIn.getId());
+
 		return ResultMap.success(violations);
 	}
 

+ 7 - 0
src/main/webapp/resources/js/admin/controllers/StoreInfoListCtrl.js

@@ -37,6 +37,13 @@ define([ 'app/app' ], function(app) {
 					if (!data.content || !Array.isArray(data.content)) {
 						data.content = [];
 					}
+					angular.forEach(data.content, function (store) {
+						var tags = JSON.parse(store.tags || '[]');
+						store.tagsObject = {};
+						for (var i = 0; i < tags.length; i++) {
+							store.tagsObject[tags[i]] = true;
+						}
+					});
 					$defer.resolve(data.content);
 					params.total(data.totalElements);
 					console.log(data);

+ 34 - 1
src/main/webapp/resources/js/common/module/store_admin_violations_module.js

@@ -23,11 +23,13 @@ define([ 'ngResource', 'common/query/storeViolations', 'ngTable', 'ngSanitize',
 	/**
 	 * 企业信息记录
 	 */
-	module.controller('EnterpriseInfoCtrl', ['$scope', 'StoreInfo', 'toaster', 'ConsignmentAgreementRecord', 'ngTableParams', 'BaseService', function ($scope, StoreInfo, toaster, ConsignmentAgreementRecord, ngTableParams, BaseService) {
+	module.controller('EnterpriseInfoCtrl', ['$scope', 'StoreInfo', 'toaster', 'ConsignmentAgreementRecord', 'StoreAdsInformation', 'ngTableParams', 'BaseService', function ($scope, StoreInfo, toaster, ConsignmentAgreementRecord, StoreAdsInformation, ngTableParams, BaseService) {
 		console.log('EnterpriseInfoCtrl');
 
 		$scope.showRecords = true;
 
+		$scope.tagStoreWithTag = tagStoreWithTag;
+
 		active();
 
 		/**
@@ -43,6 +45,12 @@ define([ 'ngResource', 'common/query/storeViolations', 'ngTable', 'ngSanitize',
 							return qualification.type === 'APTITUDE' && qualification.resourceUrl && qualification.resourceUrl !== '';
 						});
 					}
+					// 设置店铺推荐标签
+					var tags = JSON.parse($scope.store.tags || '[]');
+					$scope.store.tagsObject = {};
+					for (var i = 0; i < tags.length; i++) {
+						$scope.store.tagsObject[tags[i]] = true;
+					}
 					console.log($scope.store);
 					loadRecords($scope.store.enUU);
 				} else {
@@ -92,6 +100,31 @@ define([ 'ngResource', 'common/query/storeViolations', 'ngTable', 'ngSanitize',
 			});
 		}
 
+		/**
+		 * 为店铺打标签
+		 */
+		function tagStoreWithTag(store, tag) {
+			if ($scope.store.tagsObject[tag]) {
+				StoreAdsInformation.cancelStoreTagsWhenAdminCancel({type: tag}, store, function (store) {
+					toaster.pop('success', '操作成功');
+					$scope.tags = store.tags;
+					$scope.store.tagsObject[tag] = false;
+				}, function (error) {
+					toaster.pop('warning', '操作失败,请重试');
+					window.location.reload();
+				});
+			} else {
+				StoreAdsInformation.tagStoreInWhenAdminRecommend({type: tag}, store, function (store) {
+					toaster.pop('success', '操作成功');
+					$scope.tags = store.tags;
+					$scope.store.tagsObject[tag] = true;
+				}, function (error) {
+					toaster.pop('warning', '操作失败,请重试');
+					window.location.reload();
+				});
+			}
+		}
+
 	}]);
 
 	/**

+ 47 - 0
src/main/webapp/resources/js/common/query/storeInfo.js

@@ -226,5 +226,52 @@ define([ 'ngResource' ], function() {
 			}
 		});
 
+	}]).factory('StoreAdsInformation', ['$resource', function ($resource) {
+		return $resource('auth/api/store', {}, {
+			/**
+			 * 当管理员推荐店铺的时候,保存店铺的广告信息
+			 *
+			 * @param type		店铺广告类型
+			 * @param store		店铺信息
+			 */
+			tagStoreInWhenAdminRecommend: {
+				url: 'auth/api/store/tag-store',
+				method: 'PUT'
+			},
+			/**
+			 * 当管理员推荐店铺的时候,取消推荐店铺
+			 *
+			 * @param type		店铺广告类型
+			 * @param store		店铺信息
+			 */
+			cancelStoreTagsWhenAdminCancel: {
+				url: 'auth/api/store/cancel-tag',
+				method: 'PUT'
+			},
+			/**
+			 * 用户获取热销店铺列表信息
+			 *
+			 * @param page		页面,默认从0开始
+			 * @param size		页面大小
+			 * @param types		店铺类型
+			 */
+			showSalesListWhenUserQuery: {
+				url: 'api/ads/store/sales-list',
+				method: 'GET',
+				isArray: true
+			},
+			/**
+			 * 用户获取优秀店铺列表信息
+			 *
+			 * @param page		页面,默认从0开始
+			 * @param size		页面大小
+			 * @param types		店铺类型
+			 */
+			showExcellenceListWhenUserQuery: {
+				url: 'api/ads/store/excellence-list',
+				method: 'GET',
+				isArray: true
+			}
+		});
 	}]);
 });

+ 38 - 17
src/main/webapp/resources/js/provider/controllers/ProviderFactoriesCtrl.js

@@ -1,6 +1,6 @@
 define([ 'app/app', 'jquery-summernote' ], function(app) {
 	'use strict';
-	app.register.controller('ProviderFactoriesCtrl', ['$scope', '$rootScope', 'toaster', 'BrandActiveAPI', 'Carousel', 'StoreInfo', 'ngTableParams', 'BaseService', 'StoreCms', 'Order', function($scope, $rootScope, toaster, BrandActiveAPI, Carousel, StoreInfo, ngTableParams, BaseService, StoreCms, Order) {
+	app.register.controller('ProviderFactoriesCtrl', ['$scope', '$rootScope', 'toaster', 'BrandActiveAPI', 'Carousel', 'StoreInfo', 'ngTableParams', 'BaseService', 'StoreCms', 'Order', 'StoreAdsInformation', function($scope, $rootScope, toaster, BrandActiveAPI, Carousel, StoreInfo, ngTableParams, BaseService, StoreCms, Order, StoreAdsInformation) {
 		$rootScope.page = 'factories';
 		document.title = "原厂专区" + "-优软商城";
 
@@ -32,31 +32,52 @@ define([ 'app/app', 'jquery-summernote' ], function(app) {
 			/**
 			 * 获取销售排行信息
 			 */
-			StoreInfo.findTopStoreBySales({ isOriginal: true }, {}, function (stores) {
-				$scope.topSalesStores = stores || [];
-				angular.forEach($scope.topSalesStores, function (store) {
-					Order.countOneStoreOrder({storeUuid : store.uuid}, {}, function (data) {
-						store.orderCount = data.orderCount || 0;
-					}, function () {
-						store.orderCount = 0;
+			StoreAdsInformation.showSalesListWhenUserQuery({types: 'ORIGINAL_FACTORY'}, {}, function (data) {
+				if (angular.isArray(data) && data.length > 0) {
+					$scope.topSalesStores = data;
+					angular.forEach(data, function (storeAds) {
+						if (storeAds.store) {
+							storeAds.uuid = storeAds.store.uuid;
+							storeAds.logoUrl = storeAds.store.logoUrl;
+							storeAds.storeName = storeAds.store.storeName;
+							storeAds.description = storeAds.store.description;
+
+							// 获取店铺订单数量信息
+							Order.countOneStoreOrder({storeUuid : storeAds.store.uuid}, {}, function (data) {
+								storeAds.orderCount = data.orderCount || 0;
+							}, function () {
+								storeAds.orderCount = 0;
+							});
+						}
 					});
-				});
-			}, function (resp) {
+				} else {
+					$scope.topSalesStores = [];
+				}
+			}, function (error) {
+				console.log(error);
+				$scope.topSalesStores = [];
 			});
 
 			/**
 			 * 获取原厂推荐信息
 			 */
-			StoreInfo.fiveStoresByTypes({	num : 5, types : 'ORIGINAL_FACTORY' }, {}, function (data) {
-				console.log(data.length);
-				if (data.length > 0) {
+			StoreAdsInformation.showExcellenceListWhenUserQuery({types: 'ORIGINAL_FACTORY'}, {}, function (data) {
+				if (angular.isArray(data) && data.length > 0) {
 					$scope.recommendOriginal = data;
-					console.log($scope.recommendOriginal);
+					angular.forEach(data, function (storeAds) {
+						if (storeAds.store) {
+							storeAds.uuid = storeAds.store.uuid;
+							storeAds.logoUrl = storeAds.store.logoUrl;
+							storeAds.storeName = storeAds.store.storeName;
+							storeAds.description = storeAds.store.description;
+						}
+					});
 				} else {
-					$scope.recommendOriginal = null;
+					$scope.recommendOriginal = [];
 				}
-			}, function () {
-				$scope.recommendOriginal = null;
+			}, function (error) {
+				console.log(error);
+				$scope.recommendOriginal = [];
 			});
 
 			/**

+ 42 - 12
src/main/webapp/resources/js/provider/controllers/ProviderHomeCtrl.js

@@ -6,7 +6,7 @@
  */
 define(['app/app'], function(app) {
 
-	app.register.controller('ProviderHomeCtrl', ['$scope', 'StoreCms', 'Carousel', '$rootScope', 'ngTableParams', 'BaseService', 'StoreInfo', 'Order', function ($scope, StoreCms, Carousel, $rootScope, ngTableParams, BaseService, StoreInfo, Order) {
+	app.register.controller('ProviderHomeCtrl', ['$scope', 'StoreCms', 'Carousel', '$rootScope', 'ngTableParams', 'BaseService', 'StoreInfo', 'Order', 'StoreAdsInformation', function ($scope, StoreCms, Carousel, $rootScope, ngTableParams, BaseService, StoreInfo, Order, StoreAdsInformation) {
 
 		/**********************************************************************
 		 * 初始化
@@ -32,23 +32,53 @@ define(['app/app'], function(app) {
 		/**
 		 * 获取销售排行信息
 		 */
-		StoreInfo.findTopStoreBySales({ isOriginal: false }, {}, function (stores) {
-			$scope.topSalesStores = stores || [];
-			angular.forEach($scope.topSalesStores, function (store) {
-				Order.countOneStoreOrder({storeUuid : store.uuid}, {}, function (data) {
-					store.orderCount = data.orderCount || 0;
-				}, function () {
-					store.orderCount = 0;
+		StoreAdsInformation.showSalesListWhenUserQuery({types: 'AGENCY,DISTRIBUTION'}, {}, function (data) {
+			if (angular.isArray(data) && data.length > 0) {
+				$scope.topSalesStores = data;
+				angular.forEach(data, function (storeAds) {
+					if (storeAds.store) {
+						storeAds.uuid = storeAds.store.uuid;
+						storeAds.logoUrl = storeAds.store.logoUrl;
+						storeAds.storeName = storeAds.store.storeName;
+						storeAds.description = storeAds.store.description;
+
+						// 获取店铺订单数量信息
+						Order.countOneStoreOrder({storeUuid : storeAds.store.uuid}, {}, function (data) {
+							storeAds.orderCount = data.orderCount || 0;
+						}, function () {
+							storeAds.orderCount = 0;
+						});
+					}
 				});
-			});
-		}, function (resp) {
+			} else {
+				$scope.topSalesStores = [];
+			}
+		}, function (error) {
+			console.log(error);
+			$scope.topSalesStores = [];
 		});
 
 		/**
 		 * 获取优秀供应商信息
 		 */
-		StoreCms.getStoreCmsByUseForAndCmsType({ num:5, types:'AGENCY-DISTRIBUTION' }, function (exStoreCms) {
-			$scope.exStoreCms = exStoreCms || {};
+		StoreAdsInformation.showExcellenceListWhenUserQuery({types: 'AGENCY,DISTRIBUTION'}, {}, function (data) {
+			console.log(data);
+			if (angular.isArray(data) && data.length > 0) {
+				$scope.exStoreCms = data;
+				angular.forEach(data, function (storeAds) {
+					if (storeAds.store) {
+						storeAds.uuid = storeAds.store.uuid;
+						storeAds.logoUrl = storeAds.store.logoUrl;
+						storeAds.storeName = storeAds.store.storeName;
+						storeAds.description = storeAds.store.description;
+					}
+				});
+			} else {
+				$scope.exStoreCms = [];
+			}
+		}, function (error) {
+			console.log(error);
+			$scope.exStoreCms = [];
 		});
 
 		/**

+ 19 - 3
src/main/webapp/resources/js/provider/controllers/ProviderListCtrl.js

@@ -6,7 +6,7 @@
  */
 define(['app/app'], function(app) {
 
-	app.register.controller('ProviderListCtrl', ['$scope', 'StoreInfo', 'ngTableParams', 'BaseService', 'StoreCms', function ($scope, StoreInfo, ngTableParams, BaseService, StoreCms) {
+	app.register.controller('ProviderListCtrl', ['$scope', 'StoreInfo', 'ngTableParams', 'BaseService', 'StoreCms', 'StoreAdsInformation', function ($scope, StoreInfo, ngTableParams, BaseService, StoreCms, StoreAdsInformation) {
 
 		$scope.stores = {};
 
@@ -37,8 +37,24 @@ define(['app/app'], function(app) {
 		/**
 		 * 获取优秀供应商信息
 		 */
-		StoreCms.getStoreCmsByUseForAndCmsType({ num:5, types:'AGENCY-DISTRIBUTION' }, function (exStoreCms) {
-			$scope.exStoreCms = exStoreCms || {};
+		StoreAdsInformation.showExcellenceListWhenUserQuery({types: 'AGENCY,DISTRIBUTION'}, {}, function (data) {
+			console.log(data);
+			if (angular.isArray(data) && data.length > 0) {
+				$scope.exStoreCms = data;
+				angular.forEach(data, function (storeAds) {
+					if (storeAds.store) {
+						storeAds.uuid = storeAds.store.uuid;
+						storeAds.logoUrl = storeAds.store.logoUrl;
+						storeAds.storeName = storeAds.store.storeName;
+						storeAds.description = storeAds.store.description;
+					}
+				});
+			} else {
+				$scope.exStoreCms = [];
+			}
+		}, function (error) {
+			console.log(error);
+			$scope.exStoreCms = [];
 		});
 
 		$scope.search = function () {

+ 22 - 18
src/main/webapp/resources/view/admin/store/fragments/enterprise_info.html

@@ -301,23 +301,27 @@
 			</div>
 		</div>
 	</div>
-</div>
-<!--推荐相关内容 TODO huxz 暂时隐藏 -->
-<div class="recommend" style="display: none;">
-	<div class="recommend-list hot-icon">推荐成为:
-		<label>
-			<i class="hot"></i>热销
-			<input type="checkbox" id="hot">
-			<label for="hot"></label>
-		</label>
-		<label><i class="new"></i>新入驻
-			<input type="checkbox" id="new">
-			<label for="new"></label>
-		</label>
-		<label><i class="new-apply"></i>优秀供应商
-			<input type="checkbox" id="new-apply">
-			<label for="new-apply"></label>
-		</label>
+	<!--推荐相关内容 TODO huxz 暂时隐藏 -->
+	<div class="recommend" ng-if="store.status === 'OPENED'">
+		<div class="recommend-list hot-icon">推荐成为:
+			<label>
+				<i class="hot"></i>热销
+				<input type="checkbox" id="hot" ng-checked="store.tagsObject['SALES_LIST']" ng-click="tagStoreWithTag(store, 'SALES_LIST')">
+				<label for="hot"></label>
+			</label>
+			<label><i class="new"></i>优秀供应商
+				<input type="checkbox" id="new-apply" ng-checked="store.tagsObject['EXCELLENCE_LIST']" ng-click="tagStoreWithTag(store, 'EXCELLENCE_LIST')">
+				<label for="new-apply"></label>
+			</label>
+			<!--<label><i class="new"></i>新入驻
+				<input type="checkbox" id="new">
+				<label for="new"></label>
+			</label>
+			<label><i class="new-apply"></i>优秀供应商
+				<input type="checkbox" id="new-apply">
+				<label for="new-apply"></label>
+			</label>-->
+		</div>
 	</div>
+	<div class="back-store"><a ng-href="{{'store/' + storeUuid}}" target="_blank"><button>前往店铺</button></a></div>
 </div>
-<div class="back-store"><a ng-href="{{'store/' + storeUuid}}" target="_blank"><button>前往店铺</button></a></div>

+ 2 - 2
src/main/webapp/resources/view/admin/store_info_list.html

@@ -244,13 +244,13 @@
 				<td><span ng-bind="store.createTime | date : 'yyyy-MM-dd HH:mm:ss'"></span></td>
 				<td><span ng-bind="store.updateTime | date : 'yyyy-MM-dd HH:mm:ss'"></span></td>
 				<td class="hot-icon">
-					<div ng-if="newStoreMap[store.uuid]">
+					<div ng-if="store.tagsObject['SALES_LIST']">
 						<i class="hot"></i><span>热销</span>
 					</div>
 					<div ng-if="hotSalesMap[store.uuid]">
 						<i class="new"></i><span>新入驻</span>
 					</div>
-					<div ng-if="excellentSupplierMap[store.uuid]">
+					<div ng-if="store.tagsObject['EXCELLENCE_LIST']">
 						<i class="new-apply"></i><span>优秀供应商</span>
 					</div>
 				</td>

+ 1 - 1
src/main/webapp/resources/view/provider/home/sale_outstanding_store.html

@@ -74,7 +74,7 @@
 			<span>销售排行榜</span>
 		</div>
 		<ul class="list-unstyled list-inline">
-			<li ng-repeat="store in topSalesStores">
+			<li ng-repeat="store in topSalesStores | orderBy: '-orderCount'">
 				<div class="rank" ng-switch="$index">
 					<img ng-switch-when="0" src="static/img/store/home/first.png" width="40" height="33" />
 					<img ng-switch-when="1" src="static/img/store/home/second.png" width="40" height="33" />

+ 2 - 2
src/main/webapp/resources/view/provider/provider_factories.html

@@ -434,7 +434,7 @@
 	</div>
 </div>-->
 
-<div id="recommends"  class="container" ng-if="recommendOriginal">
+<div id="recommends"  class="container" ng-if="recommendOriginal && recommendOriginal.length > 0">
 	<div class="title-icon">原厂推荐</div>
 	<div class="hr-blue"></div>
 	<ul class="recommend-list list-unstyled list-inline">
@@ -459,7 +459,7 @@
 	</ul>
 </div>
 
-<div>
+<div style="margin-top: 20px;">
 	<!-- 供应商列表 -->
 	<div ng-include src="'static/view/provider/list/suppliers.html'"></div>
 </div>