Browse Source

Merge remote-tracking branch 'origin/feature-background-hulh-1212' into dev-mysql

# Conflicts:
#	src/main/java/com/uas/platform/b2c/prod/commodity/service/impl/GoodsServiceImpl.java
#	src/main/webapp/WEB-INF/views/normal/adminWithNav.html
#	src/main/webapp/resources/js/admin/app.js
dongbw 8 years ago
parent
commit
6302ef4374
61 changed files with 5825 additions and 128 deletions
  1. 5 0
      src/main/java/com/uas/platform/b2c/core/constant/SplitChar.java
  2. 16 0
      src/main/java/com/uas/platform/b2c/core/utils/RegexConstant.java
  3. 3 3
      src/main/java/com/uas/platform/b2c/external/erp/commodity/service/impl/ProductDetailERPServiceImpl.java
  4. 8 2
      src/main/java/com/uas/platform/b2c/prod/commodity/constant/StringConstant.java
  5. 51 0
      src/main/java/com/uas/platform/b2c/prod/commodity/controller/BackgroundRecordController.java
  6. 29 6
      src/main/java/com/uas/platform/b2c/prod/commodity/controller/GoodsController.java
  7. 38 1
      src/main/java/com/uas/platform/b2c/prod/commodity/controller/GoodsHistoryController.java
  8. 81 0
      src/main/java/com/uas/platform/b2c/prod/commodity/controller/GoodsModifyInfoController.java
  9. 24 0
      src/main/java/com/uas/platform/b2c/prod/commodity/dao/BackgroundRecordDao.java
  10. 8 0
      src/main/java/com/uas/platform/b2c/prod/commodity/dao/GoodsDao.java
  11. 9 0
      src/main/java/com/uas/platform/b2c/prod/commodity/dao/GoodsHistoryDao.java
  12. 25 0
      src/main/java/com/uas/platform/b2c/prod/commodity/dao/GoodsModifyInfoDao.java
  13. 13 0
      src/main/java/com/uas/platform/b2c/prod/commodity/dao/ModifyInfoDao.java
  14. 24 0
      src/main/java/com/uas/platform/b2c/prod/commodity/dao/TitleDao.java
  15. 101 0
      src/main/java/com/uas/platform/b2c/prod/commodity/model/BackgroundRecord.java
  16. 42 1
      src/main/java/com/uas/platform/b2c/prod/commodity/model/Goods.java
  17. 165 0
      src/main/java/com/uas/platform/b2c/prod/commodity/model/GoodsFilter.java
  18. 15 1
      src/main/java/com/uas/platform/b2c/prod/commodity/model/GoodsHistory.java
  19. 199 0
      src/main/java/com/uas/platform/b2c/prod/commodity/model/GoodsModifyInfo.java
  20. 122 0
      src/main/java/com/uas/platform/b2c/prod/commodity/model/ModifyInfo.java
  21. 115 0
      src/main/java/com/uas/platform/b2c/prod/commodity/model/Title.java
  22. 27 0
      src/main/java/com/uas/platform/b2c/prod/commodity/service/BackgroundRecordService.java
  23. 18 0
      src/main/java/com/uas/platform/b2c/prod/commodity/service/GoodsHistoryService.java
  24. 54 0
      src/main/java/com/uas/platform/b2c/prod/commodity/service/GoodsModifyInfoService.java
  25. 20 4
      src/main/java/com/uas/platform/b2c/prod/commodity/service/GoodsService.java
  26. 88 0
      src/main/java/com/uas/platform/b2c/prod/commodity/service/impl/BackgroundRecordServiceImpl.java
  27. 42 0
      src/main/java/com/uas/platform/b2c/prod/commodity/service/impl/GoodsHistoryServiceImpl.java
  28. 153 0
      src/main/java/com/uas/platform/b2c/prod/commodity/service/impl/GoodsModifyInfoServiceImpl.java
  29. 377 40
      src/main/java/com/uas/platform/b2c/prod/commodity/service/impl/GoodsServiceImpl.java
  30. 54 0
      src/main/java/com/uas/platform/b2c/prod/commodity/status/ModifyInfoStatus.java
  31. 43 0
      src/main/java/com/uas/platform/b2c/prod/commodity/type/ModifyConstant.java
  32. 33 0
      src/main/java/com/uas/platform/b2c/prod/commodity/util/SetUtil.java
  33. 19 1
      src/main/java/com/uas/platform/b2c/prod/store/controller/CommodityController.java
  34. 5 0
      src/main/java/com/uas/platform/b2c/prod/store/facade/CommodityFacade.java
  35. 16 0
      src/main/java/com/uas/platform/b2c/prod/store/facade/impl/CommodityFacadeImpl.java
  36. 5 0
      src/main/java/com/uas/platform/b2c/prod/store/service/CommodityService.java
  37. 5 0
      src/main/java/com/uas/platform/b2c/prod/store/service/impl/CommodityServiceImpl.java
  38. 10 0
      src/main/java/com/uas/platform/b2c/trade/order/dao/OrderDetailDao.java
  39. 5 5
      src/main/resources/spring/context.xml
  40. 2 0
      src/main/webapp/WEB-INF/views/normal/adminWithNav.html
  41. BIN
      src/main/webapp/resources/img/icon/icon-detail.png
  42. 28 9
      src/main/webapp/resources/js/admin/app.js
  43. 685 0
      src/main/webapp/resources/js/admin/controllers/product/productManageCtrl.js
  44. 291 0
      src/main/webapp/resources/js/admin/controllers/product/productManageDetailCtrl.js
  45. 2 0
      src/main/webapp/resources/js/admin/main.js
  46. 8 0
      src/main/webapp/resources/js/common/query/commodity.js
  47. 46 8
      src/main/webapp/resources/js/common/query/goods.js
  48. 12 0
      src/main/webapp/resources/js/common/query/logisticsPort.js
  49. 1 1
      src/main/webapp/resources/js/vendor/controllers/forstore/vendor_materialCtrl.js
  50. 445 0
      src/main/webapp/resources/lib/angular/angular-tree-control.js
  51. 46 46
      src/main/webapp/resources/view/admin/modal/billInfoModal.html
  52. 125 0
      src/main/webapp/resources/view/admin/modal/manage/ManageSoldOut.html
  53. 125 0
      src/main/webapp/resources/view/admin/modal/manage/detailsProduct_modal.html
  54. 125 0
      src/main/webapp/resources/view/admin/modal/manage/exportProduct_modal.html
  55. 395 0
      src/main/webapp/resources/view/admin/modal/manage/journal_modal.html
  56. 193 0
      src/main/webapp/resources/view/admin/modal/manage/manageAudit.html
  57. 208 0
      src/main/webapp/resources/view/admin/modal/manage/moreInfo_modal.html
  58. 78 0
      src/main/webapp/resources/view/admin/modal/manage/showContrastImg_modal.html
  59. 594 0
      src/main/webapp/resources/view/admin/product/productManage.html
  60. 330 0
      src/main/webapp/resources/view/admin/product/productManageDetail.html
  61. 19 0
      src/test/java/com/uas/platform/b2c/hulh/simple/StringTest.java

+ 5 - 0
src/main/java/com/uas/platform/b2c/core/constant/SplitChar.java

@@ -21,4 +21,9 @@ public class SplitChar {
 	 */
 	public static final String AND = "&";
 
+	/**
+	 * 字符  / 字符串
+	 */
+	public static final String SLASH = "/";
+
 }

+ 16 - 0
src/main/java/com/uas/platform/b2c/core/utils/RegexConstant.java

@@ -20,6 +20,11 @@ public class RegexConstant {
      */
     public static final String NumberData = "^[-+]?(([0-9]+)([.]([0-9]+))?|([.]([0-9]+))?)$";
 
+    /**
+     * 仅包含数字
+     */
+    public static final String ONLY_NUMBER = "^[0-9]*$";
+
     /**
      * 整数的正则表达式
      */
@@ -45,4 +50,15 @@ public class RegexConstant {
         Matcher matcher = numberPattern.matcher(str);
         return matcher.find();
     }
+
+    /**
+     * 判断字符串是否只有数字
+     * @param str
+     * @return
+     */
+    public static Boolean onlyHaveNumber(String str) {
+        Pattern numberPattern = Pattern.compile(ONLY_NUMBER);
+        Matcher matcher = numberPattern.matcher(str);
+        return matcher.find();
+    }
 }

+ 3 - 3
src/main/java/com/uas/platform/b2c/external/erp/commodity/service/impl/ProductDetailERPServiceImpl.java

@@ -118,7 +118,7 @@ public class ProductDetailERPServiceImpl implements ProductDetailERPService {
                             if (!CollectionUtils.isEmpty(goods)) {
                                 for (Goods good : goods) {
                                     if (Double.compare(subtractDecimal.doubleValue(), good.getReserve()) == 0) {// 差值等于此批次数量,直接下架此批次
-                                        goodsService.offShelfGoodsByProvider(good.getBatchCode(),true);
+                                        goodsService.offShelfGoodsByProvider(good.getBatchCode(), null, true);
                                         break;
                                     }
 
@@ -129,7 +129,7 @@ public class ProductDetailERPServiceImpl implements ProductDetailERPService {
                                         loggerInfo.info(SystemSession.getUser().getEnterprise().getEnName() + "更新库存: " + products.get(0).getProdNum() + ",self is" + good.getSelfSale());
                                         // 如果调整后的库存小于最小起订量直接下架
                                         if (good.getReserve() < good.getMinBuyQty()) {
-                                            goodsService.offShelfGoodsByProvider(good.getBatchCode(),true);
+                                            goodsService.offShelfGoodsByProvider(good.getBatchCode(), null, true);
                                         } else {
                                             goodsService.updateGoodsByERP(nowGood, good);
                                             goodsService.updateComponentTradeInfos(nowGood.getUuid());
@@ -138,7 +138,7 @@ public class ProductDetailERPServiceImpl implements ProductDetailERPService {
                                     }
 
                                     if (Double.compare(subtractDecimal.doubleValue(), good.getReserve()) > 0) {// 差值大于此批次数量,下架次批次,并继续下一批次调整
-                                        goodsService.offShelfGoodsByProvider(good.getBatchCode(),true);
+                                        goodsService.offShelfGoodsByProvider(good.getBatchCode(), null, true);
                                         subtractDecimal = subtractDecimal.subtract(BigDecimal.valueOf(good.getReserve()));
                                     }
                                 }

+ 8 - 2
src/main/java/com/uas/platform/b2c/prod/commodity/constant/StringConstant.java

@@ -1,11 +1,17 @@
 package com.uas.platform.b2c.prod.commodity.constant;
 
 /**
- *
- * @author yuj 2017-11-30 9:59
+ * 字符串常量
+ * @author hulh 2017年12月14日 11点22分
  */
 public class StringConstant {
 
+    public static final String CONSIGNMENT = "寄售";
+    public static final String SALE_SELF = "自营";
+    public static final String DEFAULT_IMG = "默认图片";
+    public static final String NEW_IMG = "新图片";
+    public static final String OLD_IMG = "旧图片";
+
     /**
      * 自定义标签
      */

+ 51 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/controller/BackgroundRecordController.java

@@ -0,0 +1,51 @@
+package com.uas.platform.b2c.prod.commodity.controller;
+
+import com.uas.platform.b2c.core.support.SystemSession;
+import com.uas.platform.b2c.core.support.log.UsageBufferedLogger;
+import com.uas.platform.b2c.prod.commodity.model.Title;
+import com.uas.platform.b2c.prod.commodity.service.BackgroundRecordService;
+import com.uas.platform.b2c.trade.support.ResultMap;
+import com.uas.platform.core.logging.BufferedLoggerManager;
+import org.springframework.beans.factory.annotation.Autowired;
+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.RestController;
+
+import java.util.Set;
+
+/**
+ * 表头记录的Controller层
+ *
+ * @author hulh 2017年12月14日 09点58分
+ */
+@RestController
+@RequestMapping(value = "/background/record")
+public class BackgroundRecordController {
+
+    @Autowired
+    private BackgroundRecordService recordService;
+
+    private final static UsageBufferedLogger logger = BufferedLoggerManager.getLogger(UsageBufferedLogger.class);
+
+    /**
+     * 根据useruu返回设置的表头信息
+     * @return
+     */
+    @RequestMapping(value = "/title", method = RequestMethod.GET)
+    public Set<Title> getTitleByUseruu() {
+        logger.log("超级后台", "获取表头信息,userUU : " + SystemSession.getUser().getUserUU());
+        return recordService.getTitleInfoByUseruu();
+    }
+
+    /**
+     * 更新表头信息
+     * @param titleSet 表头信息Set
+     * @return
+     */
+    @RequestMapping(value = "/update", method = RequestMethod.POST)
+    public ResultMap updateTitleInfo(@RequestBody Set<Title> titleSet) {
+        logger.log("超级后台", "更新表头信息,userUU : " + SystemSession.getUser().getUserUU());
+        return recordService.updateTitleInfo(titleSet);
+    }
+}

+ 29 - 6
src/main/java/com/uas/platform/b2c/prod/commodity/controller/GoodsController.java

@@ -8,10 +8,7 @@ import com.uas.platform.b2c.core.support.view.JxlsExcelView;
 import com.uas.platform.b2c.core.utils.FastjsonUtils;
 import com.uas.platform.b2c.core.utils.StringUtilB2C;
 import com.uas.platform.b2c.prod.commodity.dao.GoodsDao;
-import com.uas.platform.b2c.prod.commodity.model.Goods;
-import com.uas.platform.b2c.prod.commodity.model.GoodsHistory;
-import com.uas.platform.b2c.prod.commodity.model.GoodsQtyPrice;
-import com.uas.platform.b2c.prod.commodity.model.GoodsSimple;
+import com.uas.platform.b2c.prod.commodity.model.*;
 import com.uas.platform.b2c.prod.commodity.service.GoodsHistoryService;
 import com.uas.platform.b2c.prod.commodity.service.GoodsService;
 import com.uas.platform.b2c.prod.product.component.modal.ComponentInfo;
@@ -471,13 +468,14 @@ public class GoodsController {
      * 卖家下架已上架商品
      *
      * @param batchCodes 待下架商品批次号
+	 * @param downMsg   下架原因
      * @return the result map
      */
     @RequestMapping(value = "/provider/off/shelf", method = RequestMethod.PUT)
-	public ResultMap offShelfGoodsByProvider(String batchCodes) {
+	public ResultMap offShelfGoodsByProvider(String batchCodes, String downMsg) {
 		assert logger != null;
 		logger.log("货品管理", "下架上架商品");
-		return goodsService.offShelfGoodsByProvider(batchCodes,false);
+		return goodsService.offShelfGoodsByProvider(batchCodes, downMsg, false);
 	}
 
     /**
@@ -814,4 +812,29 @@ public class GoodsController {
 	public String modifyData() {
 		return  goodsService.modifyData();
 	}
+
+	/**
+	 * 根据分页参数和过滤对象分页获取数据
+	 *
+	 * @param params 分页参数
+	 * @param goodsFilter 过滤对象
+	 * @return
+	 */
+	@RequestMapping(value = "/background/page", method = RequestMethod.POST)
+	public Page<Goods> getPageDataOfBackground(PageParams params, @RequestBody GoodsFilter goodsFilter) {
+		PageInfo info = new PageInfo(params);
+		logger.log("后台产品管理", "分页获取Goods信息");
+		return goodsService.getPageDataOfBackground(info, goodsFilter);
+	}
+
+	/**
+	 * 根据id返回一个Goods数据
+	 * @param goodsId
+	 * @return
+	 */
+	@RequestMapping(value = "/one", method = RequestMethod.GET)
+	public Goods getGoodsById(Long goodsId) {
+		logger.log("后台产品管理", "根据id: " + goodsId + "返回goods数据");
+		return goodsService.getGoodsById(goodsId);
+	}
 }

+ 38 - 1
src/main/java/com/uas/platform/b2c/prod/commodity/controller/GoodsHistoryController.java

@@ -1,22 +1,32 @@
 package com.uas.platform.b2c.prod.commodity.controller;
 
+import com.uas.platform.b2c.core.support.log.UsageBufferedLogger;
+import com.uas.platform.b2c.prod.commodity.model.GoodsHistory;
 import com.uas.platform.b2c.prod.commodity.service.GoodsHistoryService;
 import com.uas.platform.b2c.trade.support.ResultMap;
+import com.uas.platform.core.logging.BufferedLoggerManager;
+import com.uas.platform.core.model.PageInfo;
+import com.uas.platform.core.model.PageParams;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
 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;
+
 /**
  * Created by yujia on 2017/7/28.
  * @version 2017年8月3日11:32:31 yuj 增加注释
  */
 @RestController
-@RequestMapping(value = "/trade/goodsHitory")
+@RequestMapping(value = "/trade/goodsHistory")
 public class GoodsHistoryController {
 
     private final GoodsHistoryService goodsHistoryService;
 
+    private static final UsageBufferedLogger logger = BufferedLoggerManager.getLogger(UsageBufferedLogger.class);
+
     /**
      * Instantiates a new Goods history controller.
      *
@@ -36,4 +46,31 @@ public class GoodsHistoryController {
     public ResultMap modifyGoodsHitory() {
         return goodsHistoryService.modifyGoodsHitory();
     }
+
+    /**
+     * 返回该批次号的上下架历史
+     *
+     * @param batchCode 批次号
+     * @return
+     */
+    @RequestMapping(value = "/data/batchCode", method = RequestMethod.GET)
+    public List<GoodsHistory> getDataByBatchCode(String batchCode) {
+        logger.log("获取上下架历史", "批次号" + batchCode);
+        return goodsHistoryService.findDataOfUpAndDown(batchCode);
+    }
+
+    /**
+     * 返回该批次号的上下架历史
+     *
+     * @param batchCode 批次号
+     * @return
+     */
+    @RequestMapping(value = "/page/batchCode", method = RequestMethod.GET)
+    public Page<GoodsHistory> getPageByBatchCode(PageParams params, String batchCode, Long startDate,
+                                                 Long endDate, String keyword) {
+        PageInfo info = new PageInfo(params);
+        logger.log("获取上下架历史", "批次号" + batchCode);
+        return goodsHistoryService.findPageByBatchCode(info, batchCode, startDate, endDate, keyword);
+    }
+
 }

+ 81 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/controller/GoodsModifyInfoController.java

@@ -0,0 +1,81 @@
+package com.uas.platform.b2c.prod.commodity.controller;
+
+import com.uas.platform.b2c.core.support.log.UsageBufferedLogger;
+import com.uas.platform.b2c.prod.commodity.model.GoodsModifyInfo;
+import com.uas.platform.b2c.prod.commodity.model.ModifyInfo;
+import com.uas.platform.b2c.prod.commodity.service.GoodsModifyInfoService;
+import com.uas.platform.core.logging.BufferedLoggerManager;
+import com.uas.platform.core.model.PageParams;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+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;
+
+/**
+ * 商品修改记录Controller
+ * @author hulh 2017年12月14日 11点22分
+ */
+@RestController
+@RequestMapping("/goods/modifyInfo")
+public class GoodsModifyInfoController {
+
+    @Autowired
+    private GoodsModifyInfoService modifyInfoService;
+
+    /**
+     * 输出日志
+     */
+    private static final UsageBufferedLogger logger = BufferedLoggerManager.getLogger(UsageBufferedLogger.class);
+
+    /**
+     * 根据批次号分页获取该Goods的修改记录
+     * @param params
+     * @param batchCode
+     * @return
+     */
+    @RequestMapping(value = "/page", method = RequestMethod.GET)
+    public Page<GoodsModifyInfo> getPageDataByBatchCode(PageParams params, String batchCode, Long startDate,
+                                                        Long endDate, String keyword) {
+        logger.log("产品信息记录", "分页获取该批次" + batchCode + "的修改记录");
+        return modifyInfoService.getPageModifyRecord(params, batchCode, startDate, endDate, keyword);
+    }
+
+    /**
+     * 根据批次号分页获取该Goods指定类型的修改记录明细
+     * @param params
+     * @param batchCode
+     * @return
+     */
+    @RequestMapping(value = "/detail/page", method = RequestMethod.GET)
+    public Page<GoodsModifyInfo> getPageDetailByBatchCode(PageParams params, String batchCode, Long startDate,
+                                                          Long endDate, String keyword) {
+        logger.log("产品信息记录", "分页获取该批次" + batchCode + "的修改记录明细");
+        return modifyInfoService.getPageModifyDetail(params, batchCode, startDate, endDate, keyword);
+    }
+
+    /**
+     * 根据批次号返回修改的信息
+     * @param batchCode 批次号
+     * @return
+     */
+    @RequestMapping(value = "/batchCode", method = RequestMethod.GET)
+    public List<GoodsModifyInfo> getGoodsModifyByBatchCode(String batchCode) {
+        logger.log("产品信息记录", "获取该批次" + batchCode + "的修改记录");
+        return modifyInfoService.getModifyRecord(batchCode);
+    }
+
+    /**
+     * 根据批次号审核商品
+     * @param batchCode 批次号
+     * @param pass      审核状态
+     * @param message   错误描述
+     */
+    @RequestMapping(value = "/audit/goods", method = RequestMethod.PUT)
+    public void auditedGoods(String batchCode, Boolean pass, String message) {
+        logger.log("产品信息记录", "审核该批次" + batchCode + "的修改记录");
+        modifyInfoService.auditedGoods(batchCode, pass, message);
+    }
+}

+ 24 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/dao/BackgroundRecordDao.java

@@ -0,0 +1,24 @@
+package com.uas.platform.b2c.prod.commodity.dao;
+
+import com.uas.platform.b2c.prod.commodity.model.BackgroundRecord;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 表头记录的dao层
+ *
+ * @author hulh 2017年12月13日 10点03分
+ */
+@Repository
+public interface BackgroundRecordDao extends JpaSpecificationExecutor<BackgroundRecord>,
+        JpaRepository<BackgroundRecord, Long> {
+
+    /**
+     * 根据useruu获取表头记录信息
+     *
+     * @param useruu
+     * @return
+     */
+    BackgroundRecord findByUseruu(Long useruu);
+}

+ 8 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/dao/GoodsDao.java

@@ -431,6 +431,14 @@ public interface GoodsDao extends JpaSpecificationExecutor<Goods>, JpaRepository
     @Query(value = "select distinct g.kindUuid from Goods g where g.storeid = :storeUuid and g.status=601 and g.kindUuid is not null")
 	Set<Long> findAllKindsByStoreUuid(@Param("storeUuid") String storeUuid);
 
+    /**
+     * 获取店铺的所有类目信息
+     *
+     * @return the set
+     */
+    @Query(value = "select distinct g.kindUuid from Goods g where g.kindUuid is not null")
+    Set<Long> findAllKinds();
+
     /**
      * 通过原厂型号获取全部店铺id
      *

+ 9 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/dao/GoodsHistoryDao.java

@@ -33,6 +33,15 @@ public interface GoodsHistoryDao extends JpaSpecificationExecutor<GoodsHistory>,
      */
     List<GoodsHistory> findByBatchCode(String batch);
 
+    /**
+     *  根据批次号和类型返回数据
+     * @param batchCode 批次号
+     * @param typeList  类型泪列表
+     * @return
+     */
+    @Query(value = "select g from GoodsHistory g where g.batchCode = :batchCode and g.operateType in :typeList order by g.updateDate desc")
+    List<GoodsHistory> findByBatchCodeInType(@Param("batchCode") String batchCode, @Param("typeList") List<String> typeList);
+
     /**
      * 根据UUID和状态查找对应的历史货物信息
      *

+ 25 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/dao/GoodsModifyInfoDao.java

@@ -0,0 +1,25 @@
+package com.uas.platform.b2c.prod.commodity.dao;
+
+import com.uas.platform.b2c.prod.commodity.model.GoodsModifyInfo;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * 商品修改dao层
+ * @author hulh
+ */
+@Repository
+public interface GoodsModifyInfoDao extends JpaSpecificationExecutor<GoodsModifyInfo>,
+        JpaRepository<GoodsModifyInfo, Long> {
+
+    /**
+     * 根据批次号返回修改记录
+     * @param batchCode 批次号
+     * @param status    审核状态
+     * @return
+     */
+    List<GoodsModifyInfo> findByBatchCodeAndStatus(String batchCode, Integer status);
+}

+ 13 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/dao/ModifyInfoDao.java

@@ -0,0 +1,13 @@
+package com.uas.platform.b2c.prod.commodity.dao;
+
+import com.uas.platform.b2c.prod.commodity.model.ModifyInfo;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+/**
+ * 商品修改明细dao层
+ * @author hulh
+ */
+public interface ModifyInfoDao extends JpaSpecificationExecutor<ModifyInfo>,
+        JpaRepository<ModifyInfo, Long> {
+}

+ 24 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/dao/TitleDao.java

@@ -0,0 +1,24 @@
+package com.uas.platform.b2c.prod.commodity.dao;
+
+import com.uas.platform.b2c.prod.commodity.model.Title;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+import org.springframework.data.jpa.repository.Modifying;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 表头信息的dao层
+ *
+ * @author hulh 2017年12月13日 10点03分
+ */
+@Repository
+public interface TitleDao extends JpaSpecificationExecutor<Title>,
+        JpaRepository<Title, Long> {
+
+    /**
+     * 删除指定表头记录下的表头信息
+     * @param recordid 表头记录id
+     */
+    @Modifying
+    void deleteByRecordid(Long recordid);
+}

+ 101 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/model/BackgroundRecord.java

@@ -0,0 +1,101 @@
+package com.uas.platform.b2c.prod.commodity.model;
+
+import javax.persistence.*;
+import java.util.Date;
+import java.util.Set;
+
+/**
+ * 超级后台表头记录类
+ * @author hulh 2017年12月13日 10点03分
+ */
+@Entity
+@Table(name = "background$record")
+public class BackgroundRecord {
+
+    /**
+     * 主键
+     */
+    @Id
+    @GeneratedValue
+    @Column(name = "re_id")
+    private Long id;
+
+    /**
+     * 账号userUU
+     */
+    @Column(name = "re_uu")
+    private Long useruu;
+
+    /**
+     * 店铺enuu
+     */
+    @Column(name = "re_enuu")
+    private Long enuu;
+
+    /**
+     * 表头信息Set
+     */
+    @OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
+    @JoinColumn(name = "re_id")
+    private Set<Title> titleSet;
+
+    /**
+     * 表头信息创建时间
+     */
+    @Column(name = "re_create_time")
+    private Date createTime;
+
+    /**
+     * 表头信息更新时间
+     */
+    @Column(name = "re_update_time")
+    private Date updateTime;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getUseruu() {
+        return useruu;
+    }
+
+    public void setUseruu(Long useruu) {
+        this.useruu = useruu;
+    }
+
+    public Long getEnuu() {
+        return enuu;
+    }
+
+    public void setEnuu(Long enuu) {
+        this.enuu = enuu;
+    }
+
+    public Set<Title> getTitleSet() {
+        return titleSet;
+    }
+
+    public void setTitleSet(Set<Title> titleSet) {
+        this.titleSet = titleSet;
+    }
+
+    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;
+    }
+}

+ 42 - 1
src/main/java/com/uas/platform/b2c/prod/commodity/model/Goods.java

@@ -288,6 +288,12 @@ public class Goods implements Serializable {
 	@Transient
 	private Integer restDays;
 
+	/**
+	 * 冻结数
+	 */
+	@Transient
+	private Integer frozen;
+
 	/**
 	 * 包装:托盘、管装、卷带
 	 */
@@ -509,6 +515,17 @@ public class Goods implements Serializable {
     @Column(name = "go_pronum")
     private String prodNum;
 
+	/**
+	 * 审核状态,未审核 0,已审核 1
+	 */
+	@Column(name = "go_audited")
+	private Short audited;
+
+	/**
+	 * 审核时间
+	 */
+	@Column(name = "go_audited_time")
+	private Date auditedTime;
 
 	@Transient
 	private String selfSale;
@@ -909,7 +926,15 @@ public class Goods implements Serializable {
 		return this;
 	}
 
-    public String getBranduuid() {
+	public Integer getFrozen() {
+		return frozen;
+	}
+
+	public void setFrozen(Integer frozen) {
+		this.frozen = frozen;
+	}
+
+	public String getBranduuid() {
         return branduuid;
     }
 
@@ -1577,6 +1602,22 @@ public class Goods implements Serializable {
 		return g;
 	}
 
+	public Short getAudited() {
+		return audited;
+	}
+
+	public void setAudited(Short audited) {
+		this.audited = audited;
+	}
+
+	public Date getAuditedTime() {
+		return auditedTime;
+	}
+
+	public void setAuditedTime(Date auditedTime) {
+		this.auditedTime = auditedTime;
+	}
+
 	/**
 	 * 产品转goods
 	 * @return

+ 165 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/model/GoodsFilter.java

@@ -0,0 +1,165 @@
+package com.uas.platform.b2c.prod.commodity.model;
+
+/**
+ * 超级后台产品管理过滤类,由于过滤属性太多
+ *
+ * @author hulh
+ */
+public class GoodsFilter {
+
+    /**
+     * 型号
+     */
+    private String code;
+
+    /**
+     * 品牌中文或英文名
+     */
+    private String brand;
+
+    /**
+     * 店铺名或店铺enuu
+     */
+    private String store;
+
+    /**
+     * 类目id,以-拼接
+     */
+    private String kindUuid;
+
+    /**
+     * 在售状态
+     */
+    private Integer saleStatus;
+
+    /**
+     * 在售数量
+     */
+    private Integer saleNum;
+
+    /**
+     * 币别
+     */
+    private String currency;
+
+    /**
+     * 销售方式,自营或寄售
+     */
+    private Boolean saleSelf;
+
+    /**
+     * 是否拆卖
+     */
+    private Boolean breakUp;
+
+    /**
+     * 产品类型,标准或非标
+     */
+    private Boolean standard;
+
+    /**
+     * 审核状态,未审核 0,已审核 1
+     */
+    private Short audited;
+
+    /**
+     * 是否有图片
+     */
+    private Boolean haveImg;
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getBrand() {
+        return brand;
+    }
+
+    public void setBrand(String brand) {
+        this.brand = brand;
+    }
+
+    public String getStore() {
+        return store;
+    }
+
+    public void setStore(String store) {
+        this.store = store;
+    }
+
+    public String getKindUuid() {
+        return kindUuid;
+    }
+
+    public void setKindUuid(String kindUuid) {
+        this.kindUuid = kindUuid;
+    }
+
+    public String getCurrency() {
+        return currency;
+    }
+
+    public void setCurrency(String currency) {
+        this.currency = currency;
+    }
+
+    public Boolean getSaleSelf() {
+        return saleSelf;
+    }
+
+    public void setSaleSelf(Boolean saleSelf) {
+        this.saleSelf = saleSelf;
+    }
+
+    public Boolean getBreakUp() {
+        return breakUp;
+    }
+
+    public void setBreakUp(Boolean breakUp) {
+        this.breakUp = breakUp;
+    }
+
+    public Boolean getStandard() {
+        return standard;
+    }
+
+    public void setStandard(Boolean standard) {
+        this.standard = standard;
+    }
+
+    public Short getAudited() {
+        return audited;
+    }
+
+    public void setAudited(Short audited) {
+        this.audited = audited;
+    }
+
+    public Boolean getHaveImg() {
+        return haveImg;
+    }
+
+    public void setHaveImg(Boolean haveImg) {
+        this.haveImg = haveImg;
+    }
+
+    public Integer getSaleStatus() {
+        return saleStatus;
+    }
+
+    public void setSaleStatus(Integer saleStatus) {
+        this.saleStatus = saleStatus;
+    }
+
+    public Integer getSaleNum() {
+        return saleNum;
+    }
+
+    public void setSaleNum(Integer saleNum) {
+        this.saleNum = saleNum;
+    }
+}

+ 15 - 1
src/main/java/com/uas/platform/b2c/prod/commodity/model/GoodsHistory.java

@@ -403,6 +403,12 @@ public class GoodsHistory {
 	@Column(name = "go_pronum")
 	private String prodNum;
 
+	/**
+	 * 下架原因
+	 */
+	@Column(name = "go_down_msg")
+	private String downMsg;
+
 	/**
 	 * 分段价格
 	 */
@@ -415,6 +421,7 @@ public class GoodsHistory {
 	@OneToOne(cascade = { CascadeType.REFRESH })
 	@JoinColumn(name = "log_operateuu", insertable = false, updatable = false)
 	private UserBaseInfo operater;
+
 	@Transient
 	private String enterpriseName;
 
@@ -1011,7 +1018,6 @@ public class GoodsHistory {
         this.batchCode = goods.getBatchCode();
         this.createdDate = goods.getCreatedDate();
         this.availableDays = goods.getAvailableDays();
-        this.updateDate = goods.getUpdateDate();
         this.minBuyQty = goods.getMinBuyQty();
         this.minPackQty = goods.getMinPackQty();
         this.publisherUU = goods.getPublisherUU();
@@ -1149,6 +1155,14 @@ public class GoodsHistory {
 		this.tag = tag;
 	}
 
+	public String getDownMsg() {
+		return downMsg;
+	}
+
+	public void setDownMsg(String downMsg) {
+		this.downMsg = downMsg;
+	}
+
 	public String getProdNum() {
 		return prodNum;
 	}

+ 199 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/model/GoodsModifyInfo.java

@@ -0,0 +1,199 @@
+package com.uas.platform.b2c.prod.commodity.model;
+
+import javax.persistence.*;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 商品修改记录类
+ * @author hulh 2017年12月14日 11点22分
+ */
+@Entity
+@Table(name = "trade$goods_modify")
+public class GoodsModifyInfo {
+
+    /**
+     * 主键
+     */
+    @Id
+    @GeneratedValue
+    @Column(name = "id")
+    private Long id;
+
+    /**
+     * 用户useruu
+     */
+    @Column(name = "mo_useruu")
+    private Long useruu;
+
+    /**
+     * 更新人
+     */
+    @Column(name = "mo_operate_name")
+    private String operateName;
+
+    /**
+     * 店铺enuu
+     */
+    @Column(name = "mo_enuu")
+    private Long enuu;
+
+    /**
+     * 商品批次号
+     */
+    @Column(name = "mo_batchcode")
+    private String batchCode;
+
+    /**
+     * 商品修改信息Set
+     */
+    @OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
+    @JoinColumn(name = "mo_id")
+    private List<ModifyInfo> infoList;
+
+    /**
+     * 审核人
+     */
+    @Column(name = "mo_audited_name")
+    private String auditedName;
+
+    /**
+     * 更新时间
+     */
+    @Column(name = "mo_audited_time")
+    private Date auditedTime;
+
+    /**
+     * 更新时间
+     */
+    @Column(name = "mo_update_time")
+    private Date updateTime;
+
+    /**
+     * 审核状态  10:未审核 11:通过 12:不通过
+     */
+    @Column(name = "mo_status")
+    private Integer status;
+
+    /**
+     * 审核不通过信息
+     */
+    @Column(name = "mo_message")
+    private String message;
+
+    /**
+     * 基本信息数
+     */
+    @Transient
+    private int basicCount;
+
+    /**
+     * 销售信息数
+     */
+    @Transient
+    private int sellCount;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getUseruu() {
+        return useruu;
+    }
+
+    public void setUseruu(Long useruu) {
+        this.useruu = useruu;
+    }
+
+    public String getOperateName() {
+        return operateName;
+    }
+
+    public void setOperateName(String operateName) {
+        this.operateName = operateName;
+    }
+
+    public Long getEnuu() {
+        return enuu;
+    }
+
+    public void setEnuu(Long enuu) {
+        this.enuu = enuu;
+    }
+
+    public String getBatchCode() {
+        return batchCode;
+    }
+
+    public void setBatchCode(String batchCode) {
+        this.batchCode = batchCode;
+    }
+
+    public List<ModifyInfo> getInfoList() {
+        return infoList;
+    }
+
+    public void setInfoList(List<ModifyInfo> infoList) {
+        this.infoList = infoList;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public String getAuditedName() {
+        return auditedName;
+    }
+
+    public void setAuditedName(String auditedName) {
+        this.auditedName = auditedName;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+
+    public int getBasicCount() {
+        return basicCount;
+    }
+
+    public void setBasicCount(int basicCount) {
+        this.basicCount = basicCount;
+    }
+
+    public int getSellCount() {
+        return sellCount;
+    }
+
+    public void setSellCount(int sellCount) {
+        this.sellCount = sellCount;
+    }
+
+    public Date getAuditedTime() {
+        return auditedTime;
+    }
+
+    public void setAuditedTime(Date auditedTime) {
+        this.auditedTime = auditedTime;
+    }
+}

+ 122 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/model/ModifyInfo.java

@@ -0,0 +1,122 @@
+package com.uas.platform.b2c.prod.commodity.model;
+
+import javax.persistence.*;
+
+/**
+ * 商品修改明细类
+ * @author hulh 2017年12月14日 11点22分
+ */
+@Entity
+@Table(name = "trade$goods_modify_info")
+public class ModifyInfo {
+
+    /**
+     * 基本信息
+     */
+    public static final Short TYPE_BASIC = 1;
+
+    /**
+     * 销售信息
+     */
+    public static final Short TYPE_SALE = 2;
+
+    /**
+     * 主键
+     */
+    @Id
+    @GeneratedValue
+    @Column(name = "id")
+    private Long id;
+
+    /**
+     * 关联的商品修改id
+     */
+    @Column(name = "mo_id")
+    private Long modifyid;
+
+    /**
+     * 关联的商品批次号,方便查询
+     */
+    @Column(name = "mo_batch")
+    private String batchCode;
+
+    /**
+     * 修改的字段
+     */
+    @Column(name = "info_field")
+    private String modifyField;
+
+    /**
+     * 修改前信息
+     */
+    @Column(name = "info_before")
+    private String before;
+
+    /**
+     * 修改后信息
+     */
+    @Column(name = "info_after")
+    private String after;
+
+    /**
+     * 修改信息类型
+     */
+    @Column(name = "info_type")
+    private Short type;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getModifyid() {
+        return modifyid;
+    }
+
+    public void setModifyid(Long modifyid) {
+        this.modifyid = modifyid;
+    }
+
+    public String getModifyField() {
+        return modifyField;
+    }
+
+    public void setModifyField(String modifyField) {
+        this.modifyField = modifyField;
+    }
+
+    public String getBefore() {
+        return before;
+    }
+
+    public void setBefore(String before) {
+        this.before = before;
+    }
+
+    public String getAfter() {
+        return after;
+    }
+
+    public void setAfter(String after) {
+        this.after = after;
+    }
+
+    public Short getType() {
+        return type;
+    }
+
+    public void setType(Short type) {
+        this.type = type;
+    }
+
+    public String getBatchCode() {
+        return batchCode;
+    }
+
+    public void setBatchCode(String batchCode) {
+        this.batchCode = batchCode;
+    }
+}

+ 115 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/model/Title.java

@@ -0,0 +1,115 @@
+package com.uas.platform.b2c.prod.commodity.model;
+
+import org.apache.commons.collections.CollectionUtils;
+
+import javax.persistence.*;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * 表头信息类
+ * @author hulh 2017年12月13日 10点03分
+ */
+@Entity
+@Table(name = "background$title")
+public class Title {
+
+    private static String[] nameArray = {"产品图片", "商家名称", "封装", "梯度", "单价", "交期(天)",
+            "在售状态", "在售数量", "库存总数", "销售方式"};
+    private static final Set<Title> defaultList = new HashSet<>();
+    static {
+        initDefaultList();
+    }
+
+    /**
+     * 主键
+     */
+    @Id
+    @GeneratedValue
+    @Column(name = "title_id")
+    private Long id;
+
+    /**
+     * 表头名
+     */
+    @Column(name = "title_name")
+    private String titleName;
+
+    /**
+     * 关联的后台记录主键
+     */
+    @Column(name = "re_id")
+    private Long recordid;
+
+    public Title() {
+
+    }
+
+    public Title(String titleName) {
+        this.titleName = titleName;
+    }
+
+    /**
+     * 初始化默认列表
+     */
+    private static void initDefaultList() {
+        if (CollectionUtils.isEmpty(defaultList)) {
+            synchronized (Title.class) {
+                if (CollectionUtils.isEmpty(defaultList)) {
+                    for (String name : nameArray) {
+                        Title title = new Title(name);
+                        defaultList.add(title);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 公有方法获取默认列表
+     * @return
+     */
+    public static Set<Title> getDefaultList(){
+        return defaultList;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+
+        Title title = (Title) o;
+
+        return titleName.equals(title.titleName);
+
+    }
+
+    @Override
+    public int hashCode() {
+        return titleName.hashCode();
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getTitleName() {
+        return titleName;
+    }
+
+    public void setTitleName(String titleName) {
+        this.titleName = titleName;
+    }
+
+    public Long getRecordid() {
+        return recordid;
+    }
+
+    public void setRecordid(Long recordid) {
+        this.recordid = recordid;
+    }
+}

+ 27 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/service/BackgroundRecordService.java

@@ -0,0 +1,27 @@
+package com.uas.platform.b2c.prod.commodity.service;
+
+import com.uas.platform.b2c.prod.commodity.model.Title;
+import com.uas.platform.b2c.trade.support.ResultMap;
+import java.util.Set;
+
+/**
+ * 表头记录的Service层
+ *
+ * @author hulh 2017年12月13日 10点03分
+ */
+public interface BackgroundRecordService {
+
+    /**
+     * 更新表头信息,如果没发生改变则不更新
+     *
+     * @param titleList 表头list
+     * @return
+     */
+    ResultMap updateTitleInfo(Set<Title> titleList);
+
+    /**
+     * 返回当前用户的表头记录信息
+     * @return
+     */
+    Set<Title> getTitleInfoByUseruu();
+}

+ 18 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/service/GoodsHistoryService.java

@@ -100,4 +100,22 @@ public interface GoodsHistoryService {
      * @return
      */
     String compareGoodsHistory(GoodsHistory goodsHistory);
+
+    /**
+     * 返回该批次号的上下架历史
+     * @param batchCode 批次号
+     * @return
+     */
+    List<GoodsHistory> findDataOfUpAndDown(String batchCode);
+
+    /**
+     * 通过批次号获取批次变更记录(卖家)
+     *
+     * @param info      the info 一页数据
+     * @param batchCode the batch code 批次信息
+     * @return page
+     */
+    Page<GoodsHistory> findPageByBatchCode(final PageInfo info, String batchCode, Long startDate,
+                                           Long endDate, String keyword);
+
 }

+ 54 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/service/GoodsModifyInfoService.java

@@ -0,0 +1,54 @@
+package com.uas.platform.b2c.prod.commodity.service;
+
+import com.uas.platform.b2c.prod.commodity.model.GoodsModifyInfo;
+import com.uas.platform.b2c.prod.commodity.model.ModifyInfo;
+import com.uas.platform.core.model.PageParams;
+import org.springframework.data.domain.Page;
+
+import java.util.List;
+
+/**
+ * 产品修改记录service类
+ * @author hulh
+ */
+public interface GoodsModifyInfoService {
+
+    /**
+     * 根据批次号分页获取该Goods指定类型的修改记录明细
+     * @param batchCode 批次号
+     * @param params    分页参数
+     * @param startDate 开始时间
+     * @param endDate   结束时间
+     * @param keyword   关键字
+     * @return
+     */
+    Page<GoodsModifyInfo> getPageModifyRecord(PageParams params, String batchCode, Long startDate,
+                                              Long endDate, String keyword);
+
+    /**
+     * 根据批次号分页获取该Goods指定类型的修改记录明细
+     * @param batchCode 批次号
+     * @param params    分页参数
+     * @param startDate 开始时间
+     * @param endDate   结束时间
+     * @param keyword   关键字
+     * @return
+     */
+    Page<GoodsModifyInfo> getPageModifyDetail(PageParams params, String batchCode, Long startDate,
+                                              Long endDate, String keyword);
+
+    /**
+     * 根据批次号获取该Goods的修改记录
+     * @param batchCode 批次号
+     * @return
+     */
+    List<GoodsModifyInfo> getModifyRecord(String batchCode);
+
+    /**
+     * 根据批次号审核商品
+     * @param batchCode 批次号
+     * @param pass      审核状态
+     * @param message   错误描述
+     */
+    void auditedGoods(String batchCode, Boolean pass, String message);
+}

+ 20 - 4
src/main/java/com/uas/platform/b2c/prod/commodity/service/GoodsService.java

@@ -418,9 +418,10 @@ public interface GoodsService {
      * 卖家下架已上架商品
      *
      * @param batchCodes 待下架商品批次号
+     * @param downMsg   下架原因
      * @return the result map
      */
-    ResultMap offShelfGoodsByProvider(String batchCodes,Boolean isERP);
+    ResultMap offShelfGoodsByProvider(String batchCodes, String downMsg, Boolean isERP);
 
     /**
      * 分页获取批次信息
@@ -678,14 +679,22 @@ public interface GoodsService {
      * @param batchCode
      * @return
      */
-    void addVisitCount(String batchCode);
+    public void addVisitCount(String batchCode);
+
+    /**
+     * 根据分页参数和过滤对象分页获取数据
+     *
+     * @param info 分页参数
+     * @param goodsFilter 过滤对象
+     * @return
+     */
+    Page<Goods> getPageDataOfBackground(PageInfo info, GoodsFilter goodsFilter);
 
     /**
      * 根据productid
      * @param productid
      */
-    ResultMap getDeleteProductMessage(Long
-                                              productid);
+    ResultMap getDeleteProductMessage(Long productid);
 
     /**
      * 修正测试的数据
@@ -693,4 +702,11 @@ public interface GoodsService {
      * @return
      */
     String modifyData();
+
+    /**
+     * 根据id返回一个Goods数据
+     * @param id
+     * @return
+     */
+    Goods getGoodsById(Long id);
 }

+ 88 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/service/impl/BackgroundRecordServiceImpl.java

@@ -0,0 +1,88 @@
+package com.uas.platform.b2c.prod.commodity.service.impl;
+
+import com.uas.platform.b2c.core.config.SysConf;
+import com.uas.platform.b2c.core.support.SystemSession;
+import com.uas.platform.b2c.prod.commodity.dao.BackgroundRecordDao;
+import com.uas.platform.b2c.prod.commodity.dao.TitleDao;
+import com.uas.platform.b2c.prod.commodity.model.BackgroundRecord;
+import com.uas.platform.b2c.prod.commodity.model.Title;
+import com.uas.platform.b2c.prod.commodity.service.BackgroundRecordService;
+import com.uas.platform.b2c.prod.commodity.util.SetUtil;
+import com.uas.platform.b2c.trade.support.CodeType;
+import com.uas.platform.b2c.trade.support.ResultMap;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Date;
+import java.util.Set;
+
+/**
+ * 表头记录服务的实现层
+ *
+ * @author hulh 2017年12月13日 11点34分
+ */
+@Service
+public class BackgroundRecordServiceImpl implements BackgroundRecordService {
+
+    @Autowired
+    private BackgroundRecordDao backgroundRecordDao;
+
+    @Autowired
+    private TitleDao titleDao;
+
+    @Autowired
+    private SysConf sysConf;
+
+    /**
+     * 判断表头Set是否修改,未修改则不操作(返回false)
+     * 修改则进行保存操作,并刷新页面 (返回true)
+     *
+     * @param titleList 表头list
+     * @return
+     */
+    @Transactional
+    @Override
+    public ResultMap updateTitleInfo(Set<Title> titleList) {
+        Long userUU = SystemSession.getUser().getUserUU();
+        BackgroundRecord record = backgroundRecordDao.findByUseruu(userUU);
+        if (record == null) {
+            return new ResultMap(CodeType.NOT_COMPLETE_INFO, "对应表头记录丢失,刷新后重试");
+        }
+        Set<Title> beforeSet = record.getTitleSet();
+        // 判断表头信息是否修改
+        boolean isEquals = SetUtil.compareSet(beforeSet, titleList);
+        if (isEquals) {
+            return ResultMap.success(false);
+        }
+        titleDao.deleteByRecordid(record.getId());
+        record.setTitleSet(titleList);
+        backgroundRecordDao.save(record);
+        return ResultMap.success(true);
+    }
+
+    @Override
+    public Set<Title> getTitleInfoByUseruu() {
+        Long userUU = SystemSession.getUser().getUserUU();
+        BackgroundRecord record = backgroundRecordDao.findByUseruu(userUU);
+        if (record == null) {
+            record = createOneRecord();
+            return record.getTitleSet();
+        }
+        return record.getTitleSet();
+    }
+
+    /**
+     * 新建一个表头记录类
+     * @return
+     */
+    private BackgroundRecord createOneRecord() {
+        BackgroundRecord record = new BackgroundRecord();
+        record.setUseruu(SystemSession.getUser().getUserUU());
+        record.setEnuu(sysConf.getEnUU());
+        record.setCreateTime(new Date());
+        record.setUpdateTime(new Date());
+        record.setTitleSet(Title.getDefaultList());
+        return backgroundRecordDao.save(record);
+    }
+}

+ 42 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/service/impl/GoodsHistoryServiceImpl.java

@@ -288,4 +288,46 @@ public class GoodsHistoryServiceImpl implements GoodsHistoryService {
 		}
 		return message;
 	}
+
+	@Override
+	public List<GoodsHistory> findDataOfUpAndDown(String batchCode) {
+		List<String> typeList = Arrays.asList("下架商品", "过期下架(存储过程下架)", "发布商品");
+		return goodsHistoryDao.findByBatchCodeInType(batchCode, typeList);
+	}
+
+	@Override
+	public Page<GoodsHistory> findPageByBatchCode(final PageInfo info, String batchCode, Long startDate,
+												  Long endDate, String keyword) {
+		Goods goods = goodsDao.findByBatchCode(batchCode);
+		if (goods == null) {
+			throw new IllegalOperatorException("批次:" + batchCode + "不存在");
+		}
+		if (startDate != null) {
+			info.expression(PredicateUtils.gte("operateDate", new Date(startDate), true));
+		}
+		if (endDate != null) {
+			info.expression(PredicateUtils.lte("operateDate", new Date(endDate), true));
+		}
+		if (StringUtils.hasText(keyword)) {
+			info.filter("operater.userName", keyword);
+		}
+
+		info.filter("batchCode", batchCode);
+
+		SimpleExpression[] simpArrs = new SimpleExpression[4];
+		simpArrs[0] = new SimpleExpression ("operateType", "上架", Operator.EQ);
+		simpArrs[1] = new SimpleExpression ("operateType", "发布商品", Operator.EQ);
+		simpArrs[2] = new SimpleExpression ("operateType", "下架商品", Operator.EQ);
+		simpArrs[3] = new SimpleExpression ("operateType", "批量下架公司产品", Operator.EQ);
+
+		LogicalExpression logical = new LogicalExpression(simpArrs, Operator.OR);
+		info.expression(logical);
+
+		return goodsHistoryDao.findAll(new Specification<GoodsHistory>() {
+			public Predicate toPredicate(Root<GoodsHistory> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
+				query.where(info.getPredicates(root, query, builder));
+				return null;
+			}
+		}, info);
+	}
 }

+ 153 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/service/impl/GoodsModifyInfoServiceImpl.java

@@ -0,0 +1,153 @@
+package com.uas.platform.b2c.prod.commodity.service.impl;
+
+import com.uas.platform.b2c.core.constant.ShortConstant;
+import com.uas.platform.b2c.core.support.SystemSession;
+import com.uas.platform.b2c.prod.commodity.dao.GoodsDao;
+import com.uas.platform.b2c.prod.commodity.dao.GoodsModifyInfoDao;
+import com.uas.platform.b2c.prod.commodity.dao.ModifyInfoDao;
+import com.uas.platform.b2c.prod.commodity.model.Goods;
+import com.uas.platform.b2c.prod.commodity.model.GoodsModifyInfo;
+import com.uas.platform.b2c.prod.commodity.model.ModifyInfo;
+import com.uas.platform.b2c.prod.commodity.service.GoodsModifyInfoService;
+import com.uas.platform.b2c.prod.commodity.service.GoodsService;
+import com.uas.platform.b2c.prod.commodity.status.ModifyInfoStatus;
+import com.uas.platform.core.exception.IllegalOperatorException;
+import com.uas.platform.core.model.PageInfo;
+import com.uas.platform.core.model.PageParams;
+import com.uas.platform.core.persistence.criteria.PredicateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.jpa.domain.Specification;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Predicate;
+import javax.persistence.criteria.Root;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 产品修改记录impl层
+ * @author hulh
+ */
+@Service
+public class GoodsModifyInfoServiceImpl implements GoodsModifyInfoService {
+
+    @Autowired
+    private GoodsModifyInfoDao goodsModifyInfoDao;
+
+    @Autowired
+    private GoodsDao goodsDao;
+
+    @Autowired
+    private GoodsService goodsService;
+
+    @Autowired
+    private ModifyInfoDao modifyInfoDao;
+
+    @Override
+    public Page<GoodsModifyInfo> getPageModifyRecord(PageParams params, String batchCode, Long startDate,
+                                                     Long endDate, String keyword) {
+        final PageInfo info = new PageInfo(params);
+        info.expression(PredicateUtils.eq("batchCode", batchCode, true));
+        info.expression(PredicateUtils.ne("status", ModifyInfoStatus.TO_BE_AUDITED.getCode(), true));
+        if (startDate != null) {
+            info.expression(PredicateUtils.gte("updateTime", new Date(startDate), true));
+        }
+        if (endDate != null) {
+            info.expression(PredicateUtils.lte("updateTime", new Date(endDate), true));
+        }
+        if (StringUtils.hasText(keyword)) {
+            info.filter("operateName", keyword);
+        }
+        return goodsModifyInfoDao.findAll(new Specification<GoodsModifyInfo>() {
+            @Override
+            public Predicate toPredicate(Root<GoodsModifyInfo> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
+                criteriaQuery.where(info.getPredicates(root, criteriaQuery, criteriaBuilder));
+                return null;
+            }
+        }, info);
+    }
+
+    @Override
+    public Page<GoodsModifyInfo> getPageModifyDetail(PageParams params, String batchCode, Long startDate,
+                                                     Long endDate, String keyword) {
+        final PageInfo info = new PageInfo(params);
+        info.expression(PredicateUtils.eq("batchCode", batchCode, true));
+        if (startDate != null) {
+            info.expression(PredicateUtils.gte("updateTime", new Date(startDate), true));
+        }
+        if (endDate != null) {
+            info.expression(PredicateUtils.lte("updateTime", new Date(endDate), true));
+        }
+        if (StringUtils.hasText(keyword)) {
+            info.filter("operateName", keyword);
+        }
+        Page<GoodsModifyInfo> page =  goodsModifyInfoDao.findAll(new Specification<GoodsModifyInfo>() {
+            @Override
+            public Predicate toPredicate(Root<GoodsModifyInfo> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
+                criteriaQuery.where(info.getPredicates(root, criteriaQuery, criteriaBuilder));
+                return null;
+            }
+        }, info);
+        for (GoodsModifyInfo aModify : page.getContent()) {
+            int basicCount = 0;
+            int sellCount = 0;
+            for (ModifyInfo aInfo : aModify.getInfoList()) {
+                if (ModifyInfo.TYPE_BASIC.equals(aInfo.getType())) {
+                    basicCount++;
+                } else if (ModifyInfo.TYPE_SALE.equals(aInfo.getType())) {
+                    sellCount++;
+                }
+            }
+            aModify.setBasicCount(basicCount);
+            aModify.setSellCount(sellCount);
+        }
+        return page;
+    }
+
+    @Override
+    public List<GoodsModifyInfo> getModifyRecord(String batchCode) {
+        if (StringUtils.isEmpty(batchCode)) {
+            throw new IllegalOperatorException("批次号丢失");
+        }
+        return goodsModifyInfoDao.findByBatchCodeAndStatus(batchCode, ModifyInfoStatus.TO_BE_AUDITED.getCode());
+    }
+
+    @Override
+    public void auditedGoods(String batchCode, Boolean pass, String message) {
+        if (pass == null) {
+            throw new IllegalOperatorException("审核是否通过状态丢失");
+        }
+        if (!pass && StringUtils.isEmpty(message)) {
+            throw new IllegalOperatorException("不通过原因不能为空");
+        }
+        if (StringUtils.isEmpty(batchCode)) {
+            throw new IllegalOperatorException("批次号丢失");
+        }
+        Goods goods = goodsDao.findByBatchCode(batchCode);
+        if (goods == null) {
+            throw new IllegalOperatorException("批次号对应商品信息丢失");
+        }
+        List<GoodsModifyInfo> modifyInfoList = getModifyRecord(batchCode);
+        Integer status = pass ? ModifyInfoStatus.AUDITED_PASS.getCode() : ModifyInfoStatus.AUDITED_NOT_PASS.getCode();
+        for (GoodsModifyInfo modifyInfo : modifyInfoList) {
+            modifyInfo.setStatus(status);
+            if (ModifyInfoStatus.AUDITED_NOT_PASS.getCode().equals(status)) {
+                modifyInfo.setMessage(message);
+            }
+            modifyInfo.setAuditedTime(new Date());
+            modifyInfo.setAuditedName(SystemSession.getUser().getUserName());
+        }
+        goodsModifyInfoDao.save(modifyInfoList);
+        goods.setAudited(ShortConstant.YES_SHORT);
+        goods.setAuditedTime(new Date());
+        goodsDao.save(goods);
+        if (!pass) {
+            // 不通过下架该商品
+            goodsService.offShelfGoodsByProvider(goods.getBatchCode(), message, false);
+        }
+    }
+}

+ 377 - 40
src/main/java/com/uas/platform/b2c/prod/commodity/service/impl/GoodsServiceImpl.java

@@ -12,12 +12,15 @@ import com.uas.platform.b2c.common.account.dao.EnterpriseDao;
 import com.uas.platform.b2c.common.account.model.Enterprise;
 import com.uas.platform.b2c.common.account.model.User;
 import com.uas.platform.b2c.core.config.SysConf;
+import com.uas.platform.b2c.core.constant.ShortConstant;
 import com.uas.platform.b2c.core.constant.SplitChar;
 import com.uas.platform.b2c.core.constant.Status;
 import com.uas.platform.b2c.core.support.SystemSession;
 import com.uas.platform.b2c.core.utils.DoubleArith;
 import com.uas.platform.b2c.core.utils.FastjsonUtils;
 import com.uas.platform.b2c.core.utils.NumberUtil;
+import com.uas.platform.b2c.core.utils.PatternUtil;
+import com.uas.platform.b2c.core.utils.RegexConstant;
 import com.uas.platform.b2c.external.erp.commodity.util.ModelConverter;
 import com.uas.platform.b2c.prod.commodity.constant.DoubleConstant;
 import com.uas.platform.b2c.prod.commodity.constant.IntegerConstant;
@@ -26,6 +29,8 @@ import com.uas.platform.b2c.prod.commodity.dao.*;
 import com.uas.platform.b2c.prod.commodity.model.*;
 import com.uas.platform.b2c.prod.commodity.model.GoodsHistory.OperateType;
 import com.uas.platform.b2c.prod.commodity.service.*;
+import com.uas.platform.b2c.prod.commodity.status.ModifyInfoStatus;
+import com.uas.platform.b2c.prod.commodity.type.ModifyConstant;
 import com.uas.platform.b2c.prod.commodity.util.GoodsUtil;
 import com.uas.platform.b2c.prod.product.common.service.CreateNumberService;
 import com.uas.platform.b2c.prod.product.component.dao.ComponentDao;
@@ -208,6 +213,9 @@ public class GoodsServiceImpl implements GoodsService {
     @Autowired
     private NamedParameterJdbcTemplate namedParameterJdbcTemplate;
 
+    @Autowired
+    private GoodsModifyInfoDao goodsModifyInfoDao;
+
     private final Logger logger = Logger.getLogger(getClass());
 
     @Autowired
@@ -495,7 +503,7 @@ public class GoodsServiceImpl implements GoodsService {
 		}
 		goodsDao.modifyReserve(goods.getBatchCode(), goods.getUuid(), goods.getReserve(), goods.getStatus().intValue());
 		// 每次批次保存同时保存一遍历史信息
-		GoodsHistory goodsHistory = goodsHistoryService.converTGoodsHist(goods, GoodsHistory.OperateType.DeductReserve.getPhrase(),false);
+		GoodsHistory goodsHistory = goodsHistoryService.converTGoodsHist(goods, GoodsHistory.OperateType.DeductReserve.getPhrase(), false);
 		goodsHistoryService.save(goodsHistory);
 		// 更新器件属性的库存
 		updateComponentTradeInfos(goods.getUuid());
@@ -533,7 +541,7 @@ public class GoodsServiceImpl implements GoodsService {
 
             goodsDao.modifyReserve(goods.getBatchCode(), goods.getUuid(), goods.getReserve(), goods.getStatus().intValue());
             // 每次批次保存同时保存一遍历史信息
-            GoodsHistory goodsHistory = goodsHistoryService.converTGoodsHist(goods, GoodsHistory.OperateType.ReleaseReserve.getPhrase(),false);
+            GoodsHistory goodsHistory = goodsHistoryService.converTGoodsHist(goods, GoodsHistory.OperateType.ReleaseReserve.getPhrase(), false);
             goodsHistoryService.save(goodsHistory);
             // 更新器件属性的库存
             updateComponentTradeInfos(goods.getUuid());
@@ -719,7 +727,7 @@ public class GoodsServiceImpl implements GoodsService {
             return null;
         }
 //		updateGoodTransactional(goods);
-        GoodsHistory goodsHistory = goodsHistoryService.converTGoodsHist(goods, GoodsHistory.OperateType.Publish.getPhrase(),false);
+        GoodsHistory goodsHistory = goodsHistoryService.converTGoodsHist(goods, GoodsHistory.OperateType.Publish.getPhrase(), false);
         //仅保存商品信息,不上架
         if (goods.getId() == null || goods.getSold() == null) {
             goods.setSold(IntegerConstant.NO_INT);
@@ -783,7 +791,7 @@ public class GoodsServiceImpl implements GoodsService {
             if (resultMap.getCode() != CodeType.OK.code()) {
                 continue;
             }
-            GoodsHistory g = goodsHistoryService.converTGoodsHist(goods, GoodsHistory.OperateType.Publish.getPhrase(),false);
+            GoodsHistory g = goodsHistoryService.converTGoodsHist(goods, GoodsHistory.OperateType.Publish.getPhrase(), false);
             goodsHistorys.add(g);
             list.add(goods);
             if (goods.getUuid() != null) {
@@ -816,7 +824,7 @@ public class GoodsServiceImpl implements GoodsService {
             if (resultMap.getCode() != CodeType.OK.code()) {
                 continue;
             }
-            GoodsHistory g = goodsHistoryService.converTGoodsHist(goods, GoodsHistory.OperateType.Publish.getPhrase(),false);
+            GoodsHistory g = goodsHistoryService.converTGoodsHist(goods, GoodsHistory.OperateType.Publish.getPhrase(), false);
             goodsHistorys.add(g);
             list.add(goods);
             if (goods.getUuid() != null) {
@@ -1257,6 +1265,7 @@ public class GoodsServiceImpl implements GoodsService {
             pageInfo.expression(logical);
         }
         Page<Goods> pageGoods = goodsDao.findAll(new Specification<Goods>() {
+            @Override
             public Predicate toPredicate(Root<Goods> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
                 query.where(pageInfo.getPredicates(root, query, builder));
                 return null;
@@ -1350,11 +1359,209 @@ public class GoodsServiceImpl implements GoodsService {
                 throw new IllegalOperatorException("该物料已存在(包装、日期、最小包装量、最小起订量、交期、单位、价格)相同的信息");
             }
         }
+        // 比较两个goods编辑信息
+        compareGoodsWithModify(nowGoods, goods);
         resultGoods = updateGoods(nowGoods, goods);
         updateComponentTradeInfos(nowGoods.getUuid());
         return ResultMap.success(resultGoods);
     }
 
+    /**
+     * 比较两个Goods,得出修改后的信息
+     * @param beforeGoods 原有的Goods
+     * @param afterGoods  修改的Goods
+     */
+    private void compareGoodsWithModify(Goods beforeGoods, Goods afterGoods) {
+        List<ModifyInfo> infoList = new ArrayList<>();
+        String beforeImg = beforeGoods.getImg();
+        String afterImg = afterGoods.getImg();
+        if (StringUtils.isEmpty(beforeImg) && StringUtils.hasText(afterImg)) {
+            ModifyInfo info = new ModifyInfo();
+            info.setModifyField(ModifyConstant.MODIFY_IMG.getPhrase());
+            info.setBefore(StringConstant.DEFAULT_IMG);
+            info.setAfter(StringConstant.NEW_IMG);
+            info.setType(ModifyInfo.TYPE_BASIC);
+            info.setBatchCode(beforeGoods.getBatchCode());
+            infoList.add(info);
+        }
+        if (StringUtils.hasText(beforeImg) && !beforeImg.equals(afterImg)) {
+            ModifyInfo info = new ModifyInfo();
+            info.setModifyField(ModifyConstant.MODIFY_IMG.getPhrase());
+            info.setBefore(StringConstant.OLD_IMG);
+            info.setAfter(StringConstant.NEW_IMG);
+            info.setType(ModifyInfo.TYPE_BASIC);
+            info.setBatchCode(beforeGoods.getBatchCode());
+            infoList.add(info);
+        }
+        String beforePackage = beforeGoods.getPackaging();
+        String afterPackage = afterGoods.getPackaging();
+        if (!beforePackage.equals(afterPackage)) {
+            ModifyInfo info = new ModifyInfo();
+            info.setModifyField(ModifyConstant.MODIFY_PACKAGE.getPhrase());
+            info.setBefore(beforePackage);
+            info.setAfter(afterPackage);
+            info.setType(ModifyInfo.TYPE_BASIC);
+            info.setBatchCode(beforeGoods.getBatchCode());
+            infoList.add(info);
+        }
+        String beforeProduce = beforeGoods.getProduceDate();
+        String afterProduce = afterGoods.getProduceDate();
+        if (!beforeProduce.equals(afterProduce)) {
+            ModifyInfo info = new ModifyInfo();
+            info.setModifyField(ModifyConstant.MODIFY_PRODUCE_DATE.getPhrase());
+            info.setBefore(beforeProduce);
+            info.setAfter(afterProduce);
+            info.setType(ModifyInfo.TYPE_BASIC);
+            info.setBatchCode(beforeGoods.getBatchCode());
+            infoList.add(info);
+        }
+        Boolean beforeBreak = beforeGoods.getBreakUp();
+        Boolean afterBreak = afterGoods.getBreakUp();
+        if (!beforeBreak.equals(afterBreak)) {
+            ModifyInfo info = new ModifyInfo();
+            info.setModifyField(ModifyConstant.MODIFY_BREAK_UP.getPhrase());
+            info.setBefore(beforeBreak.toString());
+            info.setAfter(afterBreak.toString());
+            info.setType(ModifyInfo.TYPE_SALE);
+            info.setBatchCode(beforeGoods.getBatchCode());
+            infoList.add(info);
+        }
+        Double beforeReserve = beforeGoods.getReserve();
+        Double afterReserve = afterGoods.getReserve();
+        if (!beforeReserve.equals(afterReserve)) {
+            ModifyInfo info = new ModifyInfo();
+            info.setModifyField(ModifyConstant.MODIFY_RESERVE.getPhrase());
+            info.setBefore(beforeReserve.toString());
+            info.setAfter(afterReserve.toString());
+//            info.setType(ModifyInfo.TYPE_SALE);
+            info.setBatchCode(beforeGoods.getBatchCode());
+            infoList.add(info);
+        }
+        Double beforePackQty = beforeGoods.getMinPackQty();
+        Double afterPackQty = afterGoods.getMinPackQty();
+        if (!beforePackQty.equals(afterPackQty)) {
+            ModifyInfo info = new ModifyInfo();
+            info.setModifyField(ModifyConstant.MODIFY_PACKAGE_QTY.getPhrase());
+            info.setBefore(beforePackQty.toString());
+            info.setAfter(afterPackQty.toString());
+            info.setType(ModifyInfo.TYPE_BASIC);
+            info.setBatchCode(beforeGoods.getBatchCode());
+            infoList.add(info);
+        }
+        Double beforeBuyQty = beforeGoods.getMinBuyQty();
+        Double afterBuyQty = afterGoods.getMinBuyQty();
+        if (!beforeBuyQty.equals(afterBuyQty)) {
+            ModifyInfo info = new ModifyInfo();
+            info.setModifyField(ModifyConstant.MODIFY_BUY_QTY.getPhrase());
+            info.setBefore(beforeBuyQty.toString());
+            info.setAfter(afterBuyQty.toString());
+            info.setType(ModifyInfo.TYPE_SALE);
+            info.setBatchCode(beforeGoods.getBatchCode());
+            infoList.add(info);
+        }
+        Short beforeMinDelivery = beforeGoods.getMinDelivery();
+        Short afterMinDelivery = afterGoods.getMinDelivery();
+        if (!beforeMinDelivery.equals(afterMinDelivery)) {
+            ModifyInfo info = new ModifyInfo();
+            info.setModifyField(ModifyConstant.MODIFY_MIN_DELIVERY.getPhrase());
+            info.setBefore(beforeMinDelivery.toString());
+            info.setAfter(afterMinDelivery.toString());
+            info.setType(ModifyInfo.TYPE_SALE);
+            info.setBatchCode(beforeGoods.getBatchCode());
+            infoList.add(info);
+        }
+        Short beforeMaxDelivery = beforeGoods.getMaxDelivery();
+        Short afterMaxDelivery = afterGoods.getMaxDelivery();
+        if (!beforeMaxDelivery.equals(afterMaxDelivery)) {
+            ModifyInfo info = new ModifyInfo();
+            info.setModifyField(ModifyConstant.MODIFY_MAX_DELIVERY.getPhrase());
+            info.setBefore(beforeMaxDelivery.toString());
+            info.setAfter(afterMaxDelivery.toString());
+            info.setType(ModifyInfo.TYPE_SALE);
+            info.setBatchCode(beforeGoods.getBatchCode());
+            infoList.add(info);
+        }
+        Integer beforeSale = sysConf.getStoreid().equals(beforeGoods.getStoreid()) ? IntegerConstant.B2C_SALE : IntegerConstant.SELF_SALE;
+        String beforeStore = beforeSale.toString();
+        String afterStore = afterGoods.getSelfSale();
+        if (!beforeStore.equals(afterStore)) {
+            ModifyInfo info = new ModifyInfo();
+            info.setModifyField(ModifyConstant.MODIFY_SALE_METHOD.getPhrase());
+            if (beforeStore.equals(IntegerConstant.B2C_SALE.toString())) {
+                info.setBefore(StringConstant.CONSIGNMENT);
+                info.setAfter(StringConstant.SALE_SELF);
+            } else {
+                info.setBefore(StringConstant.SALE_SELF);
+                info.setAfter(StringConstant.CONSIGNMENT);
+            }
+            info.setType(ModifyInfo.TYPE_SALE);
+            info.setBatchCode(beforeGoods.getBatchCode());
+            infoList.add(info);
+        }
+        if (beforeGoods.getCurrencyName().equals(afterGoods.getCurrencyName())) {
+            if (!GoodsUtil.compareWithQtyPrice(beforeGoods.getPrices(), afterGoods.getPrices(), beforeGoods.getCurrencyName())) {
+                // 生成分段数量修改记录
+                ModifyInfo qtyInfo = new ModifyInfo();
+                qtyInfo.setModifyField(ModifyConstant.MODIFY_QTY_NUMBER.getPhrase());
+                qtyInfo.setBefore(analyzeQtyNumber(beforeGoods.getPrices()));
+                qtyInfo.setAfter(analyzeQtyNumber(afterGoods.getPrices()));
+                qtyInfo.setType(ModifyInfo.TYPE_SALE);
+                qtyInfo.setBatchCode(beforeGoods.getBatchCode());
+                infoList.add(qtyInfo);
+                // 生成分段价格修改记录
+                ModifyInfo priceInfo = new ModifyInfo();
+                priceInfo.setModifyField(ModifyConstant.MODIFY_QTY_PRICE.getPhrase());
+                priceInfo.setBefore(analyzeQtyPrice(beforeGoods.getPrices()));
+                priceInfo.setAfter(analyzeQtyPrice(afterGoods.getPrices()));
+                priceInfo.setType(ModifyInfo.TYPE_SALE);
+                priceInfo.setBatchCode(beforeGoods.getBatchCode());
+                infoList.add(priceInfo);
+            }
+        }
+        if (!CollectionUtils.isEmpty(infoList)) {
+            beforeGoods.setAudited(ShortConstant.NO_SHORT);
+            GoodsModifyInfo modifyInfo = new GoodsModifyInfo();
+            modifyInfo.setEnuu(SystemSession.getUser().getEnterprise().getUu());
+            modifyInfo.setUseruu(SystemSession.getUser().getUserUU());
+            modifyInfo.setOperateName(SystemSession.getUser().getUserName());
+            modifyInfo.setBatchCode(beforeGoods.getBatchCode());
+            modifyInfo.setStatus(ModifyInfoStatus.TO_BE_AUDITED.getCode());
+            modifyInfo.setUpdateTime(new Date());
+            modifyInfo.setInfoList(infoList);
+            goodsModifyInfoDao.save(modifyInfo);
+        }
+    }
+
+    /**
+     * 分析分段价格获取数量字符串
+     * @param   qtyPriceList
+     * @return
+     */
+    private String analyzeQtyNumber(List<GoodsQtyPrice> qtyPriceList) {
+        StringBuilder builder = new StringBuilder();
+        for (GoodsQtyPrice qtyPrice : qtyPriceList) {
+            builder.append(SplitChar.SLASH);
+            builder.append(qtyPrice.getStart());
+        }
+        return builder.substring(1);
+    }
+
+    /**
+     * 分析分段价格获取价格字符串
+     * @param   qtyPriceList
+     * @return
+     */
+    private String analyzeQtyPrice(List<GoodsQtyPrice> qtyPriceList) {
+        StringBuilder builder = new StringBuilder();
+        Double price = null;
+        for (GoodsQtyPrice qtyPrice : qtyPriceList) {
+            builder.append(SplitChar.SLASH);
+            price = qtyPrice.getRMBPrice() != null ? qtyPrice.getRMBPrice() : qtyPrice.getUSDPrice();
+            builder.append(price);
+        }
+        return builder.substring(1);
+    }
+
     @Transactional
     @Override
     public ResultMap putOn(Long id) {
@@ -1383,7 +1590,7 @@ public class GoodsServiceImpl implements GoodsService {
                 return resultMap;
             }
             //	updateGoodTransactional(goods);
-            GoodsHistory goodsHistory = goodsHistoryService.converTGoodsHist(goods, OperateType.Publish.getPhrase(),false);
+            GoodsHistory goodsHistory = goodsHistoryService.converTGoodsHist(goods, OperateType.Publish.getPhrase(), false);
             Goods persistGoods = goodsDao.save(goods);
             goodsHistoryDao.save(goodsHistory);
             // TODO huxz 添加或修改商品价格信息
@@ -1397,7 +1604,6 @@ public class GoodsServiceImpl implements GoodsService {
         }
     }
 
-
     /**
      * 添加保存的产品信息
      * @param goods
@@ -1444,7 +1650,7 @@ public class GoodsServiceImpl implements GoodsService {
         }
         goods.setStatus(Status.NO_SHELVE.value());
         //	updateGoodTransactional(goods);
-        GoodsHistory goodsHistory = goodsHistoryService.converTGoodsHist(goods, OperateType.ADD_GOODS.getPhrase(),false);
+        GoodsHistory goodsHistory = goodsHistoryService.converTGoodsHist(goods, OperateType.ADD_GOODS.getPhrase(), false);
         Goods persistGoods = goodsDao.save(goods);
         if(product != null) {
             ProductPrivate productPrivate = releaseProductByBatchService.findByPrId(product.getId());
@@ -1756,7 +1962,7 @@ public class GoodsServiceImpl implements GoodsService {
                     goodsDao.deleteByBatchCode(batchCode);
 
                     GoodsHistory goodsHist = goodsHistoryService.converTGoodsHist(goods,
-                            GoodsHistory.OperateType.Down.getPhrase(),false);
+                            GoodsHistory.OperateType.Down.getPhrase(), false);
                     goodsHist.setMessage(goodsHist.getMessage() + "该批次下架");
                     goodsHistoryService.save(goodsHist);
                     uuids.add(goods.getUuid());
@@ -1942,7 +2148,7 @@ public class GoodsServiceImpl implements GoodsService {
         } else {
             goods.setStatus(Status.UNAVAILABLE.value());
         }
-        GoodsHistory converTGoodsHist = goodsHistoryService.converTGoodsHist(goods, OperateType.Update.getPhrase(),true);
+        GoodsHistory converTGoodsHist = goodsHistoryService.converTGoodsHist(goods, OperateType.Update.getPhrase(), true);
         goodsHistoryService.save(converTGoodsHist);
         Goods good = goodsDao.save(goods);
         if (good == null) {
@@ -1965,7 +2171,7 @@ public class GoodsServiceImpl implements GoodsService {
                 goods.setStatus(Status.UNAVAILABLE.value());
             }
             // 每次批次保存同时保存一遍历史信息
-            GoodsHistory goodsHist = goodsHistoryService.converTGoodsHist(goods, OperateType.OrderPaied.getPhrase(),true);
+            GoodsHistory goodsHist = goodsHistoryService.converTGoodsHist(goods, OperateType.OrderPaied.getPhrase(), true);
             goodsHist.setMessage(goodsHist.getMessage() + "接口变更库存之后,扣除意向采购单 和正式采购单的购买数量");
             goodsHistoryService.save(goodsHist);
             good = goodsDao.save(goods);
@@ -2131,7 +2337,7 @@ public class GoodsServiceImpl implements GoodsService {
 
                 } else {
                     goods.setStatus(Status.REMOVED.value());
-                    GoodsHistory goodsHist = goodsHistoryService.converTGoodsHist(goods, OperateType.Down.getPhrase(),false);
+                    GoodsHistory goodsHist = goodsHistoryService.converTGoodsHist(goods, OperateType.Down.getPhrase(), false);
                     goodsHist.setMessage(goodsHist.getMessage() + "该批次产品下架(UAS接口)");
                     goodsHistoryService.save(goodsHist);
                     goodsDao.delete(goods);
@@ -2384,7 +2590,7 @@ public class GoodsServiceImpl implements GoodsService {
     }
 
 	@Override
-	public ResultMap offShelfGoodsByProvider(String batchCodes, Boolean isERP) {
+	public ResultMap offShelfGoodsByProvider(String batchCodes, String downMsg, Boolean isERP) {
 		SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 		logger.info(String.format("%s 商城测试下架时间记录1", dateFormat.format(new Date())));
 		if (StringUtils.isEmpty(batchCodes)) {
@@ -2401,7 +2607,7 @@ public class GoodsServiceImpl implements GoodsService {
         logger.info(String.format("%s 商城测试下架时间记录2", dateFormat.format(new Date())));
         for (String batchCode : batchCodeArr) {
             logger.info(String.format("%s 商城测试下架时间记录 调用下架方法开始", dateFormat.format(new Date())));
-            ResultMap resultMap = offShelfOneGoodsByProvider(batchCode,isERP);
+            ResultMap resultMap = offShelfOneGoodsByProvider(batchCode, downMsg, isERP);
             logger.info(String.format("%s 商城测试下架时间记录  调用下架方法结束", dateFormat.format(new Date())));
             if (resultMap.isSuccess()) {
                 Goods goods = (Goods) resultMap.getData();
@@ -2438,9 +2644,10 @@ public class GoodsServiceImpl implements GoodsService {
      * 下架单个批次商品
      *
      * @param batchCode 商品批次号
+     * @param downMsg   下架信息
      */
     @Transactional
-    public ResultMap offShelfOneGoodsByProvider(String batchCode, Boolean isERP) {
+    public ResultMap offShelfOneGoodsByProvider(String batchCode, String downMsg, Boolean isERP) {
         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
         logger.info(String.format("%s 商城测试下架时间记录 进入下架方法", dateFormat.format(new Date())));
         if (StringUtils.isEmpty(batchCode)) {
@@ -2453,9 +2660,12 @@ public class GoodsServiceImpl implements GoodsService {
         if (goods == null) {
             return new ResultMap(CodeType.NOT_EXiST.code(), "对应的批次号" + batchCode + "不存在,请刷新界面再操作");
         }
-        if (!goods.getEnUU().equals(enUU)) {
-            return new ResultMap(CodeType.NOT_PERMIT.code(), "您提交的批次号不属于您当前登陆公司");
+        if (Status.AVAILABLE.value() != goods.getStatus() && Status.UNAVAILABLE.value() != goods.getStatus()) {
+            return new ResultMap(CodeType.NOT_EXiST.code(), "对应的批次号" + batchCode + "未上架,不要下架");
         }
+//        if (!goods.getEnUU().equals(enUU)) {
+//            return new ResultMap(CodeType.NOT_PERMIT.code(), "您提交的批次号不属于您当前登陆公司");
+//        }
         if (goods.getSourceId() != null) {
             return new ResultMap(CodeType.NOT_PERMIT.code(), "批次号" + batchCode + "来自接口,b2c不能进行操作");
         }
@@ -2472,6 +2682,9 @@ public class GoodsServiceImpl implements GoodsService {
                 GoodsHistory.OperateType.Down.getPhrase(), isERP);
         logger.info(String.format("%s 商城测试下架时间记录 转历史库存 结束", dateFormat.format(new Date())));
         goodsHist.setMessage(goodsHist.getMessage() + "该批次下架");
+        if (StringUtils.hasText(downMsg)) {
+            goodsHist.setDownMsg(downMsg);
+        }
         goodsHistoryService.save(goodsHist);
 
         Goods updateGoods = goodsDao.save(goods);
@@ -3486,6 +3699,26 @@ public class GoodsServiceImpl implements GoodsService {
         return ResultMap.success(null);
     }
 
+    @Override
+    public Goods getGoodsById(Long id) {
+        Goods goods = goodsDao.findOne(id);
+        if (goods != null) {
+            if (sysConf.getStoreid().equals(goods.getStoreid())) {
+                goods.setSelfSale("寄售");
+            } else {
+                goods.setSelfSale("自营");
+            }
+            goods.setFrozen(getFrozenCount(goods.getBatchCode()));
+        }
+        if (goods.getUuid() != null) {
+            Component component = componentDao.findByUuid(goods.getUuid());
+            if (component != null) {
+                goods.setAttach(component.getAttach());
+            }
+        }
+        return goods;
+    }
+
     /**
      * 修正测试的数据
      *
@@ -3532,35 +3765,139 @@ public class GoodsServiceImpl implements GoodsService {
         return String.valueOf(goodses.size());
     }
 
-    public ResultMap batchOnSale(List<Long> idList) {
-        Map<String, Object> result = new HashMap<>();
-        List<Integer> statusList = Arrays.asList(Status.AVAILABLE.value(), Status.UNAVAILABLE.value());
-        for (Long id : idList) {
-            Product aProduct = productDao.findOne(id);
-            if (aProduct == null) {
-                continue;
+	@Override
+	public Page<Goods> getPageDataOfBackground(final PageInfo info, GoodsFilter goodsFilter) {
+		if (info == null) {
+			throw new IllegalOperatorException("分页参数丢失");
+		}
+		if (goodsFilter != null) {
+			convertPageInfo(info, goodsFilter);
+		}
+        Page<Goods> page = goodsDao.findAll(new Specification<Goods>() {
+            @Override
+            public Predicate toPredicate(Root<Goods> root, CriteriaQuery<?> query,
+                                         CriteriaBuilder builder) {
+                query.where(info.getPredicates(root, query, builder));
+                return null;
             }
-            ProductDetail detail = productDetailDao.findByProductId(id);
-            if (detail != null) {
-                // 判断是否已有上架商品
-                List<Goods> goodsList = goodsDao.findByProductIdInStatus(id, statusList);
-                if (CollectionUtils.isEmpty(goodsList)) {
-                    // 生成Goods信息
-                    Goods goods = fillDataInGoods(detail);
-                    ResultMap resultMap = putOnGoods(goods);
-                }
+        }, info);
+        List<Goods> goodsList = page.getContent();
+        for (Goods goods : goodsList) {
+            if (sysConf.getStoreid().equals(goods.getStoreid())) {
+                goods.setSelfSale(StringConstant.CONSIGNMENT);
+            } else {
+                goods.setSelfSale(StringConstant.SALE_SELF);
             }
+            goods.setFrozen(getFrozenCount(goods.getBatchCode()));
         }
-        return ResultMap.success(result);
-    }
+		return page;
+	}
 
     /**
-     * 填充相应字段
-     * @param detail
+     * 获取未发货前订单的库存数
+     * @param batchCode
      * @return
      */
-    private Goods fillDataInGoods(ProductDetail detail) {
-        Goods goods = new Goods();
-        return goods;
+    private int getFrozenCount(String batchCode) {
+        String statusStr = OrderStatus.TOBEPAID.getCodes() + SplitChar.HYPHEN + OrderStatus.TOBEDELIVER.getCodes();
+        List<Integer> statusList = new ArrayList<>();
+        for (String str : statusStr.split(SplitChar.HYPHEN)) {
+            statusList.add(Integer.valueOf(str));
+        }
+        List<OrderDetail> detailList = orderDetailDao.findByBatchInStatus(batchCode, statusList);
+        int stock = 0;
+        for (OrderDetail detail : detailList) {
+            stock += detail.getNumber();
+        }
+        return stock;
     }
+
+	private void convertPageInfo(PageInfo info, GoodsFilter goodsFilter) {
+		if (!StringUtils.isEmpty(goodsFilter.getCode())) {
+			info.filter("code", goodsFilter.getCode());
+		}
+		if (!StringUtils.isEmpty(goodsFilter.getBrand())) {
+			SimpleExpression[] brandExpression = new SimpleExpression[2];
+			brandExpression[0] = PredicateUtils.like("brandNameCn", goodsFilter.getBrand(), false, true);
+			brandExpression[1] = PredicateUtils.like("brandNameEn", goodsFilter.getBrand(), false, true);
+			info.expression(PredicateUtils.or((CriterionExpression[]) brandExpression));
+		}
+		if (!StringUtils.isEmpty(goodsFilter.getStore())) {
+            if (RegexConstant.onlyHaveNumber(goodsFilter.getStore())) {
+                SimpleExpression[] storeExpression = new SimpleExpression[2];
+                storeExpression[0] = PredicateUtils.eq("enUU", goodsFilter.getStore(), true);
+                storeExpression[1] = PredicateUtils.like("storeName", goodsFilter.getStore(), false, true);
+                info.expression(PredicateUtils.or((CriterionExpression[]) storeExpression));
+            } else {
+                info.filter("storeName", goodsFilter.getStore());
+            }
+		}
+		if (!StringUtils.isEmpty(goodsFilter.getKindUuid())) {
+            // 如果包含多个叶子类目ID,则获取所有的叶子类目对应的商品信息
+            if (goodsFilter.getKindUuid().contains(SplitChar.COMMA)) {
+                String[] kindIds = goodsFilter.getKindUuid().split(SplitChar.COMMA);
+                info.expression(PredicateUtils.in("kindUuid", kindIds, false));
+            } else {
+                info.expression(PredicateUtils.eq("kindUuid", goodsFilter.getKindUuid(), false));
+            }
+        }
+		if (!StringUtils.isEmpty(goodsFilter.getCurrency())) {
+			info.expression(PredicateUtils.eq("currencyName", goodsFilter.getCurrency(), false));
+		}
+		if (goodsFilter.getSaleSelf() != null) {
+			if (goodsFilter.getSaleSelf()) {
+				info.expression(PredicateUtils.ne("storeid", sysConf.getStoreid(), false));
+			} else {
+				info.expression(PredicateUtils.eq("storeid", sysConf.getStoreid(), false));
+			}
+		}
+		if (goodsFilter.getBreakUp() != null) {
+            int breakUp = goodsFilter.getBreakUp() ? 1 : 0;
+			info.filter("breakUp", breakUp, false);
+		}
+		if (goodsFilter.getHaveImg() != null) {
+            if (goodsFilter.getHaveImg()) {
+                info.expression(PredicateUtils.isNotNull("img"));
+            } else {
+                info.expression(PredicateUtils.isNull("img"));
+            }
+        }
+        if (goodsFilter.getStandard() != null) {
+            if (goodsFilter.getStandard()) {
+                info.expression(PredicateUtils.isNotNull("uuid"));
+            } else {
+                info.expression(PredicateUtils.isNull("uuid"));
+            }
+        }
+        if (goodsFilter.getAudited() != null) {
+            info.expression(PredicateUtils.isNotNull("audited"));
+            info.expression(PredicateUtils.eq("audited", goodsFilter.getAudited(), true));
+        }
+        if (goodsFilter.getSaleStatus() != null || goodsFilter.getSaleNum() != null) {
+            Set<Integer> statusSet = new HashSet<>();
+            if (goodsFilter.getSaleStatus() != null) {
+                // 已上架状态
+                if (Status.AVAILABLE.value() == goodsFilter.getSaleStatus()) {
+                    statusSet.add(Status.AVAILABLE.value());
+                    statusSet.add(Status.UNAVAILABLE.value());
+                } else {
+                    statusSet.add(goodsFilter.getSaleStatus());
+                }
+            }
+            if (goodsFilter.getSaleNum() != null && 603 != goodsFilter.getSaleNum()) {
+                statusSet.add(goodsFilter.getSaleNum());
+            }
+            if (CollectionUtils.isNotEmpty(statusSet)) {
+                SimpleExpression[] statusExpression = new SimpleExpression[statusSet.size()];
+                int i = 0;
+                for (Integer status : statusSet) {
+                    statusExpression[i++] = PredicateUtils.eq("status", status, true);
+                }
+                info.expression(PredicateUtils.or((CriterionExpression[]) statusExpression));
+            }
+        }
+        if (goodsFilter.getSaleNum() != null && 603 == goodsFilter.getSaleNum()) {
+            info.expression(PredicateUtils.eq("reserve", 0, true));
+        }
+	}
 }

+ 54 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/status/ModifyInfoStatus.java

@@ -0,0 +1,54 @@
+package com.uas.platform.b2c.prod.commodity.status;
+
+/**
+ * 产品修改记录状态
+ * @author hulh
+ */
+public enum  ModifyInfoStatus {
+
+    /**
+     * 未审核
+     */
+    TO_BE_AUDITED(10, "未审核"),
+
+    /**
+     * 审核通过
+     */
+    AUDITED_PASS(11, "审核通过"),
+
+    /**
+     * 审核不通过
+     */
+    AUDITED_NOT_PASS(12, "审核不通过");
+
+    /**
+     * 状态码
+     */
+    private Integer code;
+
+    /**
+     * 状态描述
+     */
+    private String message;
+
+    ModifyInfoStatus(Integer code, String message) {
+        this.code = code;
+        this.message = message;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getMessage() {
+        return message;
+    }
+
+    public void setMessage(String message) {
+        this.message = message;
+    }
+}

+ 43 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/type/ModifyConstant.java

@@ -0,0 +1,43 @@
+package com.uas.platform.b2c.prod.commodity.type;
+
+/**
+ * 商品修改常量
+ * @author hulh 2017年12月14日 11点22分
+ */
+public enum  ModifyConstant {
+    MODIFY_IMG(10, "产品图片"),
+    MODIFY_PACKAGE(11, "包装"),
+    MODIFY_PRODUCE_DATE(12, "生产日期"),
+    MODIFY_BREAK_UP(13, "可拆卖"),
+    MODIFY_RESERVE(14, "库存"),
+    MODIFY_BUY_QTY(15, "最小起订量"),
+    MODIFY_PACKAGE_QTY(16, "最小包装量"),
+    MODIFY_MIN_DELIVERY(17, "最小交期"),
+    MODIFY_MAX_DELIVERY(18, "最大交期"),
+    MODIFY_SALE_METHOD(19, "销售方式"),
+    MODIFY_QTY_NUMBER(20, "分段数量"),
+    MODIFY_QTY_PRICE(21, "分段价格");
+
+    ModifyConstant(int value, String phrase) {
+        this.value = value;
+        this.phrase = phrase;
+    }
+
+    private final int value;
+
+    private final String phrase;
+
+    /**
+     * @return 状态的整型编码
+     */
+    public int value() {
+        return this.value;
+    }
+
+    /**
+     * @return 状态的描述
+     */
+    public String getPhrase() {
+        return this.phrase;
+    }
+}

+ 33 - 0
src/main/java/com/uas/platform/b2c/prod/commodity/util/SetUtil.java

@@ -0,0 +1,33 @@
+package com.uas.platform.b2c.prod.commodity.util;
+
+import java.util.Set;
+
+/**
+ * 针对Set集合的工具类
+ * @author hulh 2017年12月13日 10点03分
+ */
+public final class SetUtil {
+
+    private SetUtil() {
+
+    }
+
+    /**
+     * 比较两个Set集合中元素是否相等
+     * @param beforeSet 会改变的Set
+     * @param nowSet 不会改变的Set
+     * @param <E> 类型参数
+     * @return Boolean 是否相等
+     */
+    public static <E> Boolean compareSet(Set<? super E> beforeSet, Set<? extends E> nowSet) {
+        if (beforeSet.size() != nowSet.size()) {
+            return false;
+        }
+        int length = beforeSet.size();
+        for (E e : nowSet) {
+            beforeSet.add(e);
+        }
+        return length == beforeSet.size();
+    }
+
+}

+ 19 - 1
src/main/java/com/uas/platform/b2c/prod/store/controller/CommodityController.java

@@ -2,6 +2,8 @@ package com.uas.platform.b2c.prod.store.controller;
 
 import com.uas.platform.b2c.prod.commodity.model.Goods;
 import com.uas.platform.b2c.prod.commodity.service.GoodsService;
+import com.uas.platform.b2c.prod.product.kind.model.KindInfo;
+import com.uas.platform.b2c.prod.store.facade.CommodityFacade;
 import com.uas.platform.core.model.PageInfo;
 import com.uas.platform.core.model.PageParams;
 import org.slf4j.Logger;
@@ -13,6 +15,8 @@ import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RequestParam;
 import org.springframework.web.bind.annotation.RestController;
 
+import java.util.List;
+
 /**
  * 店铺商品操作接口类
  *
@@ -27,9 +31,12 @@ public class CommodityController {
 
 	private final GoodsService commodityService;
 
+	private final CommodityFacade commodityFacade;
+
 	@Autowired
-	public CommodityController(GoodsService commodityService) {
+	public CommodityController(GoodsService commodityService, CommodityFacade commodityFacade) {
 		this.commodityService = commodityService;
+		this.commodityFacade = commodityFacade;
 	}
 
 	/**
@@ -47,4 +54,15 @@ public class CommodityController {
 		PageInfo pageInfo = new PageInfo(params);
 		return commodityService.pageCommoditiesByEnInfos(storeid, kindUuid, code, pageInfo);
 	}
+
+	/**
+	 * 获取所有类目信息
+	 *
+	 * @return List<KindInfo>
+	 */
+	@RequestMapping(value = "/kinds", method = RequestMethod.GET)
+	public List<KindInfo> getAllKindsInfoByStoreUuid() {
+		logger.info("Get information of all kind");
+		return commodityFacade.getAllKindsInfoByGoods();
+	}
 }

+ 5 - 0
src/main/java/com/uas/platform/b2c/prod/store/facade/CommodityFacade.java

@@ -18,4 +18,9 @@ public interface CommodityFacade {
 	 * @param storeUuid		店铺UUID
 	 */
 	List<KindInfo> getAllKindsInfoByStoreUuid(String storeUuid);
+
+	/**
+	 * 获取店铺的所有类目信息
+	 */
+	List<KindInfo> getAllKindsInfoByGoods();
 }

+ 16 - 0
src/main/java/com/uas/platform/b2c/prod/store/facade/impl/CommodityFacadeImpl.java

@@ -52,4 +52,20 @@ public class CommodityFacadeImpl implements CommodityFacade {
 		allKind.setChildren(children);
 		return Collections.singletonList(allKind);
 	}
+
+	@Override
+	public List<KindInfo> getAllKindsInfoByGoods() {
+		// 外层所有类目包裹
+		final KindInfo allKind = KindInfo.getAllKind();
+		Set<KindInfo> children = new LinkedHashSet<>();
+
+		Set<Long> kindUuidSet = commodityService.findAllKinds();
+		if (!CollectionUtils.isEmpty(kindUuidSet)) {
+			List<KindInfo> kindList = kindService.getStructruingKindsByLeafKindIds(kindUuidSet);
+			children.addAll(kindList);
+		}
+
+		allKind.setChildren(children);
+		return Collections.singletonList(allKind);
+	}
 }

+ 5 - 0
src/main/java/com/uas/platform/b2c/prod/store/service/CommodityService.java

@@ -16,4 +16,9 @@ public interface CommodityService {
 	 * @param storeUuid		店铺UUID
 	 */
 	Set<Long> findAllKindsByStoreUuid(String storeUuid);
+
+	/**
+	 * 获取所有类目信息
+	 */
+	Set<Long> findAllKinds();
 }

+ 5 - 0
src/main/java/com/uas/platform/b2c/prod/store/service/impl/CommodityServiceImpl.java

@@ -27,4 +27,9 @@ public class CommodityServiceImpl implements CommodityService {
 	public Set<Long> findAllKindsByStoreUuid(String storeUuid) {
 		return goodsDao.findAllKindsByStoreUuid(storeUuid);
 	}
+
+	@Override
+	public Set<Long> findAllKinds() {
+		return goodsDao.findAllKinds();
+	}
 }

+ 10 - 0
src/main/java/com/uas/platform/b2c/trade/order/dao/OrderDetailDao.java

@@ -26,6 +26,16 @@ public interface OrderDetailDao extends JpaSpecificationExecutor<OrderDetail>, J
 	 */
 	List<OrderDetail> findByBatchCode(String batchCode);
 
+	/**
+	 * 根据batchCode返回指定状态的订单明细
+	 *
+	 * @param batchCode
+	 * @param statusList
+	 * @return
+	 */
+	@Query(value = "select d from OrderDetail d where d.batchCode =:batchCode and d.status in :statusList")
+	List<OrderDetail> findByBatchInStatus(@Param("batchCode") String batchCode, @Param("statusList") List<Integer> statusList);
+
 	/**
 	 * 根据订单明细号查找订单明细
 	 *

+ 5 - 5
src/main/resources/spring/context.xml

@@ -15,17 +15,17 @@
 		  class="com.uas.platform.b2c.core.support.EncryptablePropertyPlaceholderConfigurer">
 		<property name="locations">
 			<list>
-				<value>classpath*:${profile}/*.properties</value>
+				<value>classpath*:dev/*.properties</value>
 			</list>
 		</property>
 	</bean>
-	<!--<context:property-placeholder location="classpath*:${profile}/*.properties" />-->
+	<!--<context:property-placeholder location="classpath*:dev/*.properties" />-->
 	<!-- 系统运行参数注入 -->
 	<util:properties id="sys"
-		location="classpath:${profile}/sys.properties" />
+		location="classpath:dev/sys.properties" />
 	<!-- 消息参数 -->
 	<util:properties id="message"
-		location="classpath:${profile}/message.properties" />
+		location="classpath:dev/message.properties" />
 	<!-- 注册spring上下文对象 -->
 	<bean class="com.uas.platform.b2c.core.support.ApplicationContextRegister" />
 	<!-- 容器启动完成之后执行 -->
@@ -198,7 +198,7 @@
 	<!-- 账户中心配置 -->
 	<bean id="accountConfigurer" class="com.uas.sso.web.AccountConfigurer"
 		init-method="init">
-		<property name="configPath" value="classpath:${profile}/account.properties" />
+		<property name="configPath" value="classpath:dev/account.properties" />
 	</bean>
 
 	<import resource="classpath:spring/ehcache.xml"/>

+ 2 - 0
src/main/webapp/WEB-INF/views/normal/adminWithNav.html

@@ -158,6 +158,8 @@
 					class="fa fa-flag"></i><span> 品牌映射维护</span></a></li>
 			<li class="nav-node"><a href="#/store/company"><i
 					class="fa fa-flag"></i><span> 寄售管理</span></a></li>
+			<li class="nav-node"><a href="#/manage"><i
+					class="fa fa-flag"></i><span> 产品管理</span></a></li>
 			<li class="nav-node"><a href="#brandmaintenance"><i
 					class="fa fa-bullhorn"></i><span> 品牌维护</span></a></li>
 			<li class="nav-node"><a href="#/store/list"><i

BIN
src/main/webapp/resources/img/icon/icon-detail.png


+ 28 - 9
src/main/webapp/resources/js/admin/app.js

@@ -1,4 +1,4 @@
- define([ 'angularAMD', 'ui.router', 'ui-bootstrap', 'ui-form', 'ngLocal', 'ngTable', 'ngSanitize', 'ngDraggable', 'common/services', 'common/directives', 'common/query/brand', 'common/query/address', 'common/query/return' , 'common/query/change' ,'common/query/component', 'common/query/order', 'common/query/purchase', 'common/query/invoice', 'common/query/property', 'common/query/kind', 'common/query/property', 'common/query/receipt', 'common/query/logistics' ,'angular-toaster', 'ui-jquery', 'jquery-uploadify','common/query/dateParse' , 'common/query/bankTransfer' ,'common/query/bankInfo', 'common/query/urlencryption', 'common/query/bill', 'common/query/makerDemand', 'common/query/goods', 'common/query/validtime', 'file-upload','file-upload-shim', 'common/query/slideImage', 'common/query/kindAdvice', 'common/query/responseLogistics', 'common/query/search','common/directives/dynamicInput', 'common/query/auditorMail', 'common/query/tradeBasicProperties', 'common/query/exchangeRate', 'common/query/tradeDeliveryDelayTime', 'common/query/payment', 'common/query/kindContrast', 'common/query/crawlTask', 'common/query/afterSale', 'common/query/refund', 'common/query/messageBoard', 'common/query/logisticsPort', 'common/query/storeInfo', 'common/query/cms', 'common/query/help', 'common/query/commonCount', 'common/module/store_admin_violations_module', 'common/query/internalMessage','common/query/user','common/query/secQuestion','common/query/keyWord','common/query/logUsage','common/query/seekQualityBuyer','common/query/loanApply', 'common/query/supplier', 'common/query/seekSalesman', 'common/query/b2bManage'], function(angularAMD) {
+ define([ 'angularAMD', 'ui.router', 'ui-bootstrap', 'ui-form', 'ngLocal', 'ngTable', 'ngSanitize', 'ngDraggable', 'common/services', 'common/directives', 'common/query/brand', 'common/query/address', 'common/query/return' , 'common/query/change' ,'common/query/component', 'common/query/order', 'common/query/purchase', 'common/query/invoice', 'common/query/property', 'common/query/kind', 'common/query/property', 'common/query/commodity', 'common/query/receipt', 'common/query/logistics' ,'angular-toaster', 'ui-jquery', 'jquery-uploadify','common/query/dateParse' , 'common/query/bankTransfer' ,'common/query/bankInfo', 'common/query/urlencryption', 'common/query/bill', 'common/query/makerDemand', 'common/query/goods', 'common/query/validtime', 'file-upload','file-upload-shim', 'common/query/slideImage', 'common/query/kindAdvice', 'common/query/responseLogistics', 'common/query/search','common/directives/dynamicInput', 'common/query/auditorMail', 'common/query/tradeBasicProperties', 'common/query/exchangeRate', 'common/query/tradeDeliveryDelayTime', 'common/query/payment', 'common/query/kindContrast', 'common/query/crawlTask', 'common/query/afterSale', 'common/query/refund', 'common/query/messageBoard', 'common/query/logisticsPort', 'common/query/storeInfo', 'common/query/cms', 'common/query/help', 'common/query/commonCount', 'common/module/store_admin_violations_module', 'common/query/internalMessage','common/query/user','common/query/secQuestion','common/query/keyWord','common/query/logUsage','common/query/seekQualityBuyer','common/query/loanApply', 'common/query/supplier', 'common/query/seekSalesman', 'common/query/b2bManage'], function(angularAMD) {
 	'use strict';
 
 	 /**
@@ -8,7 +8,7 @@
 		 return this.length > 0 ? this[this.length - 1] : null;
 	 };
 
-	var app = angular.module('myApp', [ 'ui.router', 'ui.bootstrap', 'ui.form', 'ng.local', 'ngTable', 'ngSanitize', 'ngDraggable', 'common.services', 'common.directives', 'brandServices', 'addressServices', 'returnServices', 'changeServices', 'componentServices', 'orderServices', 'purchaseServices', 'invoiceServices', 'propertyServices', 'receiptServices', 'logisticsServices', 'common.query.kind', 'toaster','ui.jquery' ,'dateparseServices', 'bankInfo' , 'bankTransfer', 'urlencryptionServices', 'billServices', 'makerDemand', 'goodsServices', 'validtimeServices', 'angularFileUpload', 'slideImageService', 'common.query.kindAdvice', 'responseLogisticsService', 'searchService', 'ngDynamicInput', 'ReviewerEmailInfoService', 'tradeBasicPropertiesServices', 'exchangeRateModule', 'tradeDeliveryDelayTimeModule', 'PaymentService', 'kindContrastServices', 'crawlTaskServices', 'afterSaleService', 'refundModule', 'messageBoardServices', 'logisticsPortService', 'storeInfoServices', 'cmsService', 'helpServices', 'commonCountServices', 'tool.directives', 'StoreAdminViolationsModule', 'internalMessageServices','common.query.user','secQuestionServices','keyWordServices','logUsageServices','seekQualityBuyerServices', 'loanApplyService', 'supplierServices', 'seekSalesmanServices', 'b2bManageService']);
+	var app = angular.module('myApp', [ 'ui.router', 'ui.bootstrap', 'ui.form', 'ng.local', 'ngTable', 'ngSanitize', 'ngDraggable', 'common.services', 'common.directives', 'brandServices', 'addressServices', 'returnServices', 'changeServices', 'componentServices', 'orderServices', 'purchaseServices', 'invoiceServices', 'propertyServices', 'receiptServices', 'logisticsServices', 'common.query.kind', 'toaster','ui.jquery', 'commodityServices', 'dateparseServices', 'bankInfo' , 'bankTransfer', 'urlencryptionServices', 'billServices', 'makerDemand', 'goodsServices', 'validtimeServices', 'angularFileUpload', 'slideImageService', 'common.query.kindAdvice', 'responseLogisticsService', 'searchService', 'ngDynamicInput', 'ReviewerEmailInfoService', 'tradeBasicPropertiesServices', 'exchangeRateModule', 'tradeDeliveryDelayTimeModule', 'PaymentService', 'kindContrastServices', 'crawlTaskServices', 'afterSaleService', 'refundModule', 'messageBoardServices', 'logisticsPortService', 'storeInfoServices', 'cmsService', 'helpServices', 'commonCountServices', 'tool.directives', 'StoreAdminViolationsModule', 'internalMessageServices','common.query.user','secQuestionServices','keyWordServices','logUsageServices','seekQualityBuyerServices', 'loanApplyService', 'supplierServices', 'seekSalesmanServices', 'b2bManageService']);
 	app.init = function() {
 		angularAMD.bootstrap(app);
 	};
@@ -263,12 +263,24 @@
 			controller : 'BrandMaintenanceCtrl',
 			controllerUrl : 'app/controllers/BrandMaintenanceCtrl'
 		})).state('brand_map', angularAMD.route({
-			// 品牌映射维护
-			url: '/brand/map',
-			templateUrl : 'static/view/admin/product/brand_map.html',
-			controller : 'BrandMapCtrl',
-			controllerUrl : 'app/controllers/product/brandMapCtrl'
-		})).state('store_company_list', angularAMD.route({
+            // 品牌映射维护
+            url: '/brand/map',
+            templateUrl : 'static/view/admin/product/brand_map.html',
+            controller : 'BrandMapCtrl',
+            controllerUrl : 'app/controllers/product/brandMapCtrl'
+        })).state('manage', angularAMD.route({
+			// 产品管理
+			url: '/manage',
+			templateUrl : 'static/view/admin/product/productManage.html',
+			controller : 'productManageCtrl',
+			controllerUrl : 'app/controllers/product/productManageCtrl'
+		})).state('manage_detail', angularAMD.route({
+            // 产品详情列表
+            url: '/manage/:id',
+            templateUrl : 'static/view/admin/product/productManageDetail.html',
+            controller : 'productManageDetailCtrl',
+            controllerUrl : 'app/controllers/product/productManageDetailCtrl'
+        })).state('store_company_list', angularAMD.route({
 			// 寄售管理
 			url: '/store/company',
 			templateUrl : 'static/view/admin/store/store_company_list.html',
@@ -948,6 +960,13 @@
              }
          }
      });
-	
+
+     // 币别filter
+     app.filter('currencyStr', function () {
+         return function (str) {
+             return typeof str == 'string' && str != 'RMB' && str != 'USD' ? str.startsWith('RMB') ? '¥' + str.substring(3, str.length) : '$' + str.substring(3, str.length) : '-';
+         }
+     });
+
 	return app;
 });

+ 685 - 0
src/main/webapp/resources/js/admin/controllers/product/productManageCtrl.js

@@ -0,0 +1,685 @@
+define(['app/app'], function(app) {
+    'use strict';
+    app.register.controller('productManageCtrl', ['$scope', '$modal', 'toaster', 'ngTableParams', 'BaseService', '$http', 'Goods', 'BackgroundRecord', 'Commodity', 'GoodsModifyInfo', function($scope, $modal, toaster, ngTableParams, BaseService, $http, Goods, BackgroundRecord, Commodity, GoodsModifyInfo) {
+
+        $scope.goodsFilter = {};
+        $scope.kindPojo = {};
+        var initTitleInfo = function () {
+            BackgroundRecord.getUserTitle({}, function (data) {
+                $scope.tableTabs = data;
+                $scope.titleInShow = {};
+                angular.forEach($scope.tableTabs, function (item) {
+                    $scope.titleInShow[item.titleName] = true;
+                });
+            });
+        };
+        initTitleInfo();
+
+        $scope.saleStatus = {
+            601 : '已上架',
+            602 : '已上架',
+            612 : '已下架',
+            613 : '新品未上架'
+        };
+
+        // 获取分页Goods数据
+        $scope.manageTableParams = new ngTableParams({
+            page: 1,
+            count: 10,
+            sorting: {
+                createdDate : 'DESC'
+            }
+        }, {
+            total: 0,
+            counts: [],
+            getData: function ($defer, params) {
+                var param = BaseService.parseParams(params.url());
+                Goods.loadGoodsList(param, $scope.goodsFilter, function (data) {
+                    $scope.totalCount = data.totalElements;
+                    $scope.goodsList = data.content;
+                    angular.forEach($scope.goodsList, function (list) {
+                        list.isChoosed = false
+                    });
+                    params.total(data.totalElements);
+                    $defer.resolve(data.content);
+                }, function () {
+                    toaster.pop('error', '获取数据失败')
+                })
+            }
+        });
+
+        // 全选
+        $scope.chooseAll = function () {
+            $scope.isChooseAll = !$scope.isChooseAll;
+            angular.forEach($scope.goodsList, function (list) {
+                list.isChoosed = $scope.isChooseAll;
+            })
+        };
+
+        // 检查是否全选
+        var checkChoosedAll = function () {
+            $scope.isChooseAll = true;
+            angular.forEach($scope.goodsList, function (list) {
+                if(!list.isChoosed) {
+                    $scope.isChooseAll = false;
+                }
+            })
+        };
+
+        // 单选
+        $scope.chooseOne = function (list) {
+            (typeof list.isChoosed === 'undefined' || !list.isChoosed) ? list.isChoosed = true : list.isChoosed = false;
+            checkChoosedAll();
+        };
+
+        //获取选中之后的信息
+        var getChooseBatch = function () {
+            $scope.choosedBatch = [];
+            angular.forEach($scope.goodsList, function (goods) {
+                if (goods.isChoosed) {
+                    $scope.choosedBatch.push(goods.batchCode);
+                }
+            });
+        };
+
+        $scope.batchDown = function () {
+            getChooseBatch();
+            if (!$scope.choosedBatch || $scope.choosedBatch.length == 0) {
+                toaster.pop("info", "您尚未选中任何产品");
+                return ;
+            }
+            $scope.soldOutProduct($scope.choosedBatch);
+        };
+
+        var initKindDataInfo = function () {
+            Commodity.getAllKindInfo({}, function (data) {
+                $scope.kindInfo = data[0].children;
+            })
+        };
+        initKindDataInfo();
+
+        // 是否打开树型选择
+        $scope.showSecondList = function () {
+            $scope.selectDown = true;
+        };
+        $scope.selectDown = false;
+        $scope.treeOptions = {
+            nodeChildren: "children",
+            dirSelectable: false,
+            injectClasses: {
+                ul: "a1",
+                li: "a2",
+                liSelected: "a7",
+                iExpanded: "a3",
+                iCollapsed: "a4",
+                iLeaf: "a5",
+                label: "a6",
+                labelSelected: "a8"
+            }
+        };
+        $scope.showSelected = function(node) {
+            $scope.leaf = node.nameCn;
+            $scope.selectDown = false;
+        };
+
+        /**
+         * 获取根据当前类目的信息获取所有叶子节点的类目信息
+         *
+         * @param kind
+         */
+        function getAllLeafKindId(kind) {
+            if (!kind) {
+                return null;
+            }
+            if (kind.isLeaf == 1) {
+                return kind.id;
+            }
+            if (kind.isLeaf == 0) {
+                // 获取第一级类目的所有叶子类目ID
+                if (kind.level == 1) {
+                    var leafKindIds = [];
+                    angular.forEach(kind.children, function (kind) {
+                        // 获取第一级类目的直接子类目的所有叶子类目ID
+                        var childrenIds = getAllLeafKindId(kind);
+                        if (Array.isArray(childrenIds)) {
+                            angular.forEach(childrenIds, function (child) {
+                                leafKindIds.push(child);
+                            })
+                        } else {
+                            leafKindIds.push(childrenIds);
+                        }
+                    });
+                    return leafKindIds;
+                } else if (kind.level == 2) {
+                    // 获取第二级类目的所有叶子类目ID
+                    var kindIds = [];
+                    angular.forEach(kind.children, function (kind) {
+                        kindIds.push(kind.id);
+                    });
+                    return kindIds;
+                }
+            }
+        }
+
+        // 搜索事件
+        $scope.searchClick = function () {
+            if ($scope.kindPojo && $scope.kindPojo.first) {
+                if (!$scope.kindPojo.second) {
+                    var kind = $scope.kindInfo[$scope.kindPojo.first];
+                    var kindUuid = getAllLeafKindId(kind);
+                    $scope.goodsFilter.kindUuid = kindUuid.join(',')
+                } else if ($scope.kindPojo.second && $scope.kindPojo.third) {
+                    $scope.goodsFilter.kindUuid = getAllLeafKindId($scope.kindPojo.third);
+                } else {
+                    var kind = $scope.kindInfo[$scope.kindPojo.first].children[$scope.kindPojo.second];
+                    var kindUuid = getAllLeafKindId(kind);
+                    $scope.goodsFilter.kindUuid = kindUuid.join(',')
+                }
+            }
+            $scope.manageTableParams.page(1);
+            $scope.manageTableParams.reload();
+        };
+
+        // 产品导出事件
+        $scope.exportClick = function (data) {
+            var modalInstance = $modal.open({
+                templateUrl: 'static/view/admin/modal/manage/exportProduct_modal.html',
+                controller: 'exportProductCtrl',
+                resolve: {
+                    account: function () {
+                        return angular.copy(data);
+                    }
+                }
+            });
+            modalInstance.result.then(function (account) {
+
+            }, function () {
+
+            })
+        };
+
+        // 更多信息事件
+        $scope.moreInfo = function () {
+            var modalInstance = $modal.open({
+                templateUrl: 'static/view/admin/modal/manage/moreInfo_modal.html',
+                controller: 'moreInfoCtrl',
+                resolve: {
+                    titleInShow: function () {
+                        return angular.copy($scope.titleInShow);
+                    }
+                }
+            });
+            modalInstance.result.then(function (data) {
+                if (data) {
+                    BackgroundRecord.updateUserTitle({}, data, function (data) {
+                        if (data.success) {
+                            if (data.data) {
+                                initTitleInfo();
+                            }
+                        } else {
+                            toaster.pop("info", data.message);
+                        }
+                    })
+                }
+            })
+        };
+
+        // 审核事件
+        $scope.auditProduct = function (goods) {
+            // 分页获取修改历史记录
+            // $scope.modifyTableParams = new ngTableParams({
+            //     page: 1,
+            //     count: 3
+            // }, {
+            //     total: 0,
+            //     getData: function ($defer, params) {
+            //         var param = BaseService.parseParams(params.url());
+            //         param.batchCode = goods.batchCode;
+            //         GoodsModifyInfo.getPageModifyInfo(param, function (data) {
+            //             var modalInstance = $modal.open({
+            //                 templateUrl: 'static/view/admin/modal/manage/manageAudit.html',
+            //                 controller: 'AuditCtrl',
+            //                 resolve: {
+            //                     goods: function () {
+            //                         return angular.copy(goods);
+            //                     },
+            //                     info: function () {
+            //                         return angular.copy(data.content);
+            //                     }
+            //                 }
+            //             });
+            //             modalInstance.result.then(function (result) {
+            //
+            //             }, function () {
+            //
+            //             })
+            //             params.total(data.totalElements);
+            //             $defer.resolve(data.content);
+            //         }, function () {
+            //             toaster.pop('error', '获取数据失败')
+            //         })
+            //     }
+            // });
+            GoodsModifyInfo.getModifyInfoByBatchCode({batchCode:goods.batchCode}, function (data) {
+                if (data) {
+                    var modalInstance = $modal.open({
+                        templateUrl: 'static/view/admin/modal/manage/manageAudit.html',
+                        controller: 'AuditCtrl',
+                        resolve: {
+                            goods: function () {
+                                return angular.copy(goods);
+                            },
+                            info: function () {
+                                return angular.copy(data);
+                            }
+                        }
+                    });
+                    modalInstance.result.then(function () {
+                        $scope.manageTableParams.reload();
+                    }, function () {
+
+                    })
+                }
+            }, function (error) {
+                toaster.pop("error", error.data);
+            });
+
+        };
+        // 日志点击事件
+        $scope.journalProduct = function (goods) {
+            var modalInstance = $modal.open({
+                templateUrl: 'static/view/admin/modal/manage/journal_modal.html',
+                controller: 'journalCtrl',
+                resolve: {
+                    goods: function () {
+                        return angular.copy(goods);
+                    }
+                }
+            });
+            modalInstance.result.then(function (account) {
+
+            }, function () {
+
+            })
+        };
+
+        // 下架事件
+        $scope.soldOutProduct = function (batchArray) {
+            var modalInstance = $modal.open({
+                templateUrl: 'static/view/admin/modal/manage/ManageSoldOut.html',
+                controller: 'soleOutCtrl',
+                resolve: {
+                    batchArray: function () {
+                        return angular.copy(batchArray);
+                    }
+                }
+            });
+            modalInstance.result.then(function () {
+                $scope.manageTableParams.reload();
+            }, function () {
+
+            })
+        };
+        // 显示对比图片信息
+        $scope.showImg = function (data) {
+            var modalInstance = $modal.open({
+                templateUrl: 'static/view/admin/modal/manage/showContrastImg_modal.html',
+                controller: 'showContrastImgCtrl',
+                resolve: {
+                    img: function () {
+                        return angular.copy(data);
+                    }
+                }
+            })
+            modalInstance.result.then(function (account) {
+
+            }, function () {
+
+            })
+        }
+
+    }]);
+
+    app.register.controller('exportProductCtrl', ['$scope', '$modalInstance', 'account', function($scope, $modalInstance, account) {
+        $scope.cancel = function () {
+            $modalInstance.dismiss();
+        }
+    }]);
+
+    app.register.controller('moreInfoCtrl', ['$scope', '$modalInstance', 'titleInShow', function ($scope, $modalInstance, titleInShow) {
+
+        $scope.allTitle = [{titleName : '商家ID'}, {titleName : '商家名称'}, {titleName : '产品信息'}, {titleName : 'SKU编码'},
+            {titleName : '产品编号'}, {titleName : '封装'}, {titleName : '梯度'}, {titleName : '单价'}, {titleName : '交期(天)'},
+            {titleName : '包装'}, {titleName : '包装数量'}, {titleName : '起订量'}, {titleName : '拆包售卖'}, {titleName : '在售数量'},
+            {titleName : '锁库数'}, {titleName : '冻结数量'}, {titleName : '库存总数'}, {titleName : '在售状态'}, {titleName : '销售方式'},
+            {titleName : '创建人'}, {titleName : '创建时间'}, {titleName : '产品类型'}, {titleName : '图片类型'}, {titleName : '产品图片'}];
+
+        var initTitleInfo = function () {
+            angular.forEach($scope.allTitle, function (item) {
+                if (titleInShow[item.titleName]) {
+                    item.choosed = true;
+                }
+            })
+        };
+        initTitleInfo();
+
+        var getChooseInfo = function () {
+            $scope.titleSet = [];
+            angular.forEach($scope.allTitle, function (item) {
+                if (item.choosed) {
+                    $scope.titleSet.push(item);
+                }
+            })
+        };
+
+        $scope.ensureAddAccount = function () {
+            getChooseInfo();
+            $modalInstance.close($scope.titleSet);
+        };
+
+        $scope.cancel = function () {
+            $modalInstance.dismiss();
+        }
+    }]);
+
+    app.register.controller('AuditCtrl', ['$scope', 'goods', 'info', 'toaster', '$modalInstance', 'GoodsModifyInfo', function($scope, goods, info, toaster, $modalInstance, GoodsModifyInfo) {
+        $scope.auditGoods = goods;
+        $scope.modifyList = info;
+        $scope.hasAuditTwo = false;
+        $scope.errorMsg = '';
+        $scope.otherMessage = '';
+        $scope.errorArray = ['价格异常', '图片违规', '基本信息有误', '断缺货'];
+
+        $scope.cancel = function () {
+            $modalInstance.dismiss();
+        };
+
+        $scope.toggleAudit = function (type) {
+            $scope.hasAuditTwo = type
+        };
+        
+        $scope.changeType = function (type) {
+            $scope.errorType = type;
+        };
+
+        var countLength = function (string) {
+            return string.replace(/[^\x00-\xff]/g, '**').length;
+        };
+
+        var cutOutString = function (str, length) {
+            for (var i = 1; i <= str.length; i++) {
+                if (countLength(str.substr(0, i)) > length){
+                    str = str.substr(0, i-1);
+                    break;
+                }
+            }
+            return str;
+        };
+
+        $scope.inputMessage = function () {
+            if ($scope.otherMessage) {
+                $scope.otherMessage = cutOutString($scope.otherMessage, 30);
+            }
+        };
+
+        $scope.ensureAudit = function (pass) {
+            if (!pass) {
+                if (!$scope.errorType) {
+                    toaster.pop("info", "您尚未选择下架原因");
+                    return;
+                }
+                if ($scope.errorType == 5) {
+                    if (!$scope.otherMessage || countLength($scope.otherMessage) < 2) {
+                        toaster.pop("info", "原因至少要填写2个字");
+                        return;
+                    }
+                }
+                if ($scope.errorType == 5) {
+                    $scope.errorMsg = $scope.otherMessage;
+                } else {
+                    $scope.errorMsg = $scope.errorArray[$scope.errorType - 1];
+                }
+            }
+            GoodsModifyInfo.auditedGoods({batchCode:goods.batchCode,pass:pass,message:$scope.errorMsg}, {}, function () {
+                toaster.pop("info", "审核完毕");
+                $modalInstance.close();
+            })
+        };
+
+    }]);
+
+    app.register.controller('journalCtrl', ['$scope', 'goods', 'toaster', 'ngTableParams', 'BaseService', 'GoodsHistory', 'GoodsModifyInfo', '$modalInstance', function($scope, goods, toaster, ngTableParams, BaseService, GoodsHistory, GoodsModifyInfo, $modalInstance) {
+        $scope.tabs = 'basic';
+
+        // 日期选择框部分
+        $scope.condition = [{open: false},{open: false} ];
+        $scope.openDatePicker = function ($event, item, openParam) {
+            $event.preventDefault();
+            $event.stopPropagation();
+            openParam === 0 ? $scope.condition[1].open = false : $scope.condition[0].open = false;
+            item[openParam].open = !item[openParam].open;
+        };
+        $scope.onDateCondition = function (bool) {
+            if (bool === 1) {
+               if ($scope.startDate && !$scope.endDate) {
+                   var nowTime = new Date();
+                   $scope.endDate = new Date(nowTime.getFullYear(), nowTime.getMonth(), nowTime.getDate());
+                   if ($scope.endDate.getTime() == $scope.startDate.getTime()) {
+                       $scope.endDate = new Date($scope.endDate.getTime() + 86400000);
+                   }
+               }
+               if ($scope.startDate && $scope.endDate) {
+                   if($scope.startDate.getTime() > $scope.endDate) {
+                       $scope.endDate = new Date($scope.startDate.getTime() + 86400000)
+                   }
+               }
+            } else if (bool === 2) {
+                if ($scope.startDate && $scope.endDate) {
+                   $scope.startDate = new Date($scope.endDate.getTime() - 86400000);
+                }
+            }
+        };
+
+        $scope.convertTab = function (tab) {
+            $scope.tabs = tab;
+            $scope.startDate = null;
+            $scope.endDate = null;
+            $scope.keyword = null;
+        };
+
+        $scope.search = function (tab) {
+            switch (tab) {
+                case 'basic':
+                    $scope.ModifyDetailTableParams.page(1);
+                    $scope.ModifyDetailTableParams.reload();
+                    break;
+                case 'sell':
+                    $scope.ModifyDetailTableParams.page(1);
+                    $scope.ModifyDetailTableParams.reload();
+                    break;
+                case 'smt':
+                    $scope.historyTableParams.page(1);
+                    $scope.historyTableParams.reload();
+                    break;
+                case 'audit':
+                    $scope.auditedTableParams.page(1);
+                    $scope.auditedTableParams.reload();
+                    break;
+            }
+        };
+
+        $scope.historyStatus = {
+            '上架' : '上架',
+            '发布商品' : '上架',
+            '下架商品' : '下架',
+            '批量下架公司产品' : '下架'
+        };
+
+        var initQueryParams = function (param) {
+            if ($scope.startDate) {
+                param.startDate = $scope.startDate.getTime();
+            }
+            if ($scope.endDate) {
+                param.endDate = $scope.endDate.getTime();
+            }
+            if ($scope.keyword) {
+                param.keyword = $scope.keyword;
+            }
+        };
+
+        // 获取分页GoodsHistory数据
+        $scope.historyTableParams = new ngTableParams({
+            page: 1,
+            count: 3,
+            sorting: {
+                operateDate : 'DESC'
+            }
+        }, {
+            total: 0,
+            getData: function ($defer, params) {
+                var param = BaseService.parseParams(params.url());
+                param.batchCode = goods.batchCode;
+                initQueryParams(param);
+                GoodsHistory.findDataOfUpAndDown(param, function (data) {
+                    $scope.historyList = data.content;
+                    params.total(data.totalElements);
+                    $defer.resolve(data.content);
+                }, function () {
+                    toaster.pop('error', '获取数据失败')
+                })
+            }
+        });
+
+        $scope.auditedTableParams = new ngTableParams({
+            page: 1,
+            count: 3,
+            sorting: {
+                updateTime : 'DESC'
+            }
+        }, {
+            total: 0,
+            getData: function ($defer, params) {
+                var param = BaseService.parseParams(params.url());
+                param.batchCode = goods.batchCode;
+                initQueryParams(param);
+                GoodsModifyInfo.getPageModifyInfo(param, function (data) {
+                    $scope.auditedList = data.content;
+                    params.total(data.totalElements);
+                    $defer.resolve(data.content);
+                }, function () {
+                    toaster.pop('error', '获取数据失败')
+                })
+            }
+        });
+
+        $scope.ModifyDetailTableParams = new ngTableParams({
+            page: 1,
+            count: 3,
+            sorting: {
+                updateTime : 'DESC'
+            }
+        }, {
+            total: 0,
+            getData: function ($defer, params) {
+                var param = BaseService.parseParams(params.url());
+                param.batchCode = goods.batchCode;
+                initQueryParams(param);
+
+                GoodsModifyInfo.getPageModifyDetail(param, function (data) {
+                    $scope.detailList = data.content;
+                    params.total(data.totalElements);
+                    $defer.resolve(data.content);
+                }, function () {
+                    toaster.pop('error', '获取数据失败')
+                })
+            }
+        });
+
+        $scope.cancel = function () {
+            $modalInstance.dismiss();
+        }
+    }]);
+
+    app.register.controller('soleOutCtrl', ['$scope', 'batchArray', 'Goods', 'toaster', '$modalInstance', function($scope, batchArray, Goods, toaster, $modalInstance) {
+        $scope.errorMsg = '';
+        $scope.otherMessage = '';
+        $scope.errorArray = ['价格异常', '图片违规', '基本信息有误', '短缺货'];
+
+        var countLength = function (string) {
+            return string.replace(/[^\x00-\xff]/g, '**').length;
+        };
+
+        var cutOutString = function (str, length) {
+            for (var i = 1; i <= str.length; i++) {
+                if (countLength(str.substr(0, i)) > length){
+                    str = str.substr(0, i-1);
+                    break;
+                }
+            }
+            return str;
+        };
+
+        $scope.inputMessage = function () {
+            if ($scope.otherMessage) {
+                $scope.otherMessage = cutOutString($scope.otherMessage, 30);
+            }
+        };
+
+        $scope.cancel = function () {
+            $modalInstance.dismiss();
+        };
+
+        $scope.changeType = function (type) {
+            $scope.errorType = type;
+        };
+
+        $scope.ensureDown = function () {
+            if (!$scope.errorType) {
+                toaster.pop("info", "您尚未选择下架原因");
+                return;
+            }
+            if ($scope.errorType == 5) {
+                if (!$scope.otherMessage || countLength($scope.otherMessage) < 2) {
+                    toaster.pop("info", "原因至少要填写2个字");
+                    return;
+                }
+            }
+            if ($scope.errorType == 5) {
+                $scope.errorMsg = $scope.otherMessage;
+            } else {
+                $scope.errorMsg = $scope.errorArray[$scope.errorType - 1];
+            }
+
+            if (!$scope.errorMsg || $scope.errorMsg.length == 0) {
+                toaster.pop("info", "您尚未选择下架原因");
+                return;
+            }
+            var batchs = batchArray.join(",");
+            Goods.offShelfGoodsByProvider({batchCodes:batchs, downMsg:$scope.errorMsg}, {}, function(map){
+                if (map.success) {
+                    toaster.pop('success', '下架成功');
+                    $modalInstance.close();
+                } else {
+                    toaster.pop('error', map.message);
+                }
+            }, function() {
+                toaster.pop('error', '下架失败');
+            });
+        };
+
+    }]);
+    app.register.controller('showContrastImgCtrl', ['$scope', 'img', '$modalInstance', function ($scope, img, $modalInstance) {
+        $scope.showImgs = img;
+        $scope.cancel = function () {
+            $modalInstance.dismiss();
+        }
+    }]);
+
+    //器件选择功能方法
+    app.register.factory('TreeData', function() {
+        return function (tree) {
+            var me = this;
+            me.$data = tree;
+        }
+    })
+})

+ 291 - 0
src/main/webapp/resources/js/admin/controllers/product/productManageDetailCtrl.js

@@ -0,0 +1,291 @@
+define(['app/app'], function(app) {
+    'use strict';
+    app.register.controller('productManageDetailCtrl', ['$scope', '$stateParams', 'Goods', '$modal', function ($scope, $stateParams, Goods, $modal) {
+        $scope.goodId = $stateParams.id;
+        var initGoods = function () {
+            Goods.findOneById({goodsId:$scope.goodId}, function (data) {
+                $scope.goods = data;
+            })
+        };
+        initGoods();
+
+        $scope.getPrice = function (currencyName, price) {
+            if ("RMB" == currencyName) {
+                return '¥' + price.rMBPrice;
+            } else if ("USD" == currencyName) {
+                return '$' + price.uSDPrice;
+            } else {
+                return "-";
+            }
+        };
+
+        $scope.breakUpStr = function (breakUp) {
+            return breakUp ? "是" : "否";
+        };
+
+        $scope.saleStatus = {
+            601 : '已上架',
+            602 : '已上架',
+            612 : '已下架',
+            613 : '新品未上架'
+        };
+
+        // 下架事件
+        $scope.soldOutProduct = function (batchArray) {
+            var modalInstance = $modal.open({
+                templateUrl: 'static/view/admin/modal/manage/ManageSoldOut.html',
+                controller: 'soleOutDetailCtrl',
+                resolve: {
+                    batchArray: function () {
+                        return angular.copy(batchArray);
+                    }
+                }
+            });
+            modalInstance.result.then(function () {
+                $scope.manageTableParams.reload();
+            }, function () {
+
+            })
+        };
+
+        // 日志点击事件
+        $scope.journalProduct = function (goods) {
+            var modalInstance = $modal.open({
+                templateUrl: 'static/view/admin/modal/manage/journal_modal.html',
+                controller: 'journalDetailCtrl',
+                resolve: {
+                    goods: function () {
+                        return angular.copy(goods);
+                    }
+                }
+            });
+            modalInstance.result.then(function (account) {
+
+            }, function () {
+
+            })
+        };
+
+    }]);
+
+    app.register.controller('soleOutDetailCtrl', ['$scope', 'batchArray', 'Goods', 'toaster', '$modalInstance', function($scope, batchArray, Goods, toaster, $modalInstance) {
+        $scope.errorMsg = '';
+        $scope.otherMessage = '';
+        $scope.errorArray = ['价格异常', '图片违规', '基本信息有误', '短缺货'];
+
+        var countLength = function (string) {
+            return string.replace(/[^\x00-\xff]/g, '**').length;
+        };
+
+        var cutOutString = function (str, length) {
+            for (var i = 1; i <= str.length; i++) {
+                if (countLength(str.substr(0, i)) > length){
+                    str = str.substr(0, i-1);
+                    break;
+                }
+            }
+            return str;
+        };
+
+        $scope.inputMessage = function () {
+            if ($scope.otherMessage) {
+                $scope.otherMessage = cutOutString($scope.otherMessage, 30);
+            }
+        };
+
+        $scope.cancel = function () {
+            $modalInstance.dismiss();
+        };
+
+        $scope.changeType = function (type) {
+            $scope.errorType = type;
+        };
+
+        $scope.ensureDown = function () {
+            if (!$scope.errorType) {
+                toaster.pop("info", "您尚未选择下架原因");
+                return;
+            }
+            if ($scope.errorType == 5) {
+                if (!$scope.otherMessage || countLength($scope.otherMessage) < 2) {
+                    toaster.pop("info", "原因至少要填写2个字");
+                    return;
+                }
+            }
+            if ($scope.errorType == 5) {
+                $scope.errorMsg = $scope.otherMessage;
+            } else {
+                $scope.errorMsg = $scope.errorArray[$scope.errorType - 1];
+            }
+
+            if (!$scope.errorMsg || $scope.errorMsg.length == 0) {
+                toaster.pop("info", "您尚未选择下架原因");
+                return;
+            }
+            var batchs = batchArray.join(",");
+            Goods.offShelfGoodsByProvider({batchCodes:batchs, downMsg:$scope.errorMsg}, {}, function(map){
+                if (map.success) {
+                    toaster.pop('success', '下架成功');
+                    $modalInstance.close();
+                } else {
+                    toaster.pop('error', map.message);
+                }
+            }, function() {
+                toaster.pop('error', '下架失败');
+            });
+        };
+
+    }]);
+
+    app.register.controller('journalDetailCtrl', ['$scope', 'goods', 'toaster', 'ngTableParams', 'BaseService', 'GoodsHistory', 'GoodsModifyInfo', '$modalInstance', function($scope, goods, toaster, ngTableParams, BaseService, GoodsHistory, GoodsModifyInfo, $modalInstance) {
+        $scope.tabs = 'basic';
+
+        // 日期选择框部分
+        $scope.condition = [{open: false},{open: false} ];
+        $scope.openDatePicker = function ($event, item, openParam) {
+            $event.preventDefault();
+            $event.stopPropagation();
+            openParam === 0 ? $scope.condition[1].open = false : $scope.condition[0].open = false;
+            item[openParam].open = !item[openParam].open;
+        };
+        $scope.onDateCondition = function (bool) {
+            if (bool === 1) {
+                if($scope.startDate && !$scope.endDate) {
+                    var nowTime = new Date();
+                    $scope.endDate = new Date(nowTime.getFullYear(), nowTime.getMonth(), nowTime.getDate());
+                    if ($scope.endDate.getTime() == $scope.startDate.getTime()) {
+                        $scope.endDate = new Date($scope.endDate.getTime() + 86400000);
+                    }
+                }
+                if ($scope.startDate && $scope.endDate) {
+                    if($scope.startDate.getTime() > $scope.endDate) {
+                        $scope.endDate = new Date($scope.startDate.getTime() + 86400000)
+                    }
+                }
+            } else if (bool === 2) {
+                if ($scope.startDate && $scope.endDate) {
+                    $scope.startDate = new Date($scope.endDate.getTime() - 86400000);
+                }
+            }
+        };
+
+        $scope.convertTab = function (tab) {
+            $scope.tabs = tab;
+            $scope.startDate = null;
+            $scope.endDate = null;
+            $scope.keyword = null;
+        };
+
+        $scope.search = function (tab) {
+            switch (tab) {
+                case 'basic':
+                    $scope.ModifyDetailTableParams.page(1);
+                    $scope.ModifyDetailTableParams.reload();
+                    break;
+                case 'sell':
+                    $scope.ModifyDetailTableParams.page(1);
+                    $scope.ModifyDetailTableParams.reload();
+                    break;
+                case 'smt':
+                    $scope.historyTableParams.page(1);
+                    $scope.historyTableParams.reload();
+                    break;
+                case 'audit':
+                    $scope.auditedTableParams.page(1);
+                    $scope.auditedTableParams.reload();
+                    break;
+            }
+        };
+
+        $scope.historyStatus = {
+            '上架' : '上架',
+            '发布商品' : '上架',
+            '下架商品' : '下架',
+            '批量下架公司产品' : '下架'
+        };
+
+        var initQueryParams = function (param) {
+            if ($scope.startDate) {
+                param.startDate = $scope.startDate.getTime();
+            }
+            if ($scope.endDate) {
+                param.endDate = $scope.endDate.getTime();
+            }
+            if ($scope.keyword) {
+                param.keyword = $scope.keyword;
+            }
+        };
+
+        // 获取分页GoodsHistory数据
+        $scope.historyTableParams = new ngTableParams({
+            page: 1,
+            count: 3,
+            sorting: {
+                operateDate : 'DESC'
+            }
+        }, {
+            total: 0,
+            getData: function ($defer, params) {
+                var param = BaseService.parseParams(params.url());
+                param.batchCode = goods.batchCode;
+                initQueryParams(param);
+                GoodsHistory.findDataOfUpAndDown(param, function (data) {
+                    $scope.historyList = data.content;
+                    params.total(data.totalElements);
+                    $defer.resolve(data.content);
+                }, function () {
+                    toaster.pop('error', '获取数据失败')
+                })
+            }
+        });
+
+        $scope.auditedTableParams = new ngTableParams({
+            page: 1,
+            count: 3,
+            sorting: {
+                updateTime : 'DESC'
+            }
+        }, {
+            total: 0,
+            getData: function ($defer, params) {
+                var param = BaseService.parseParams(params.url());
+                param.batchCode = goods.batchCode;
+                initQueryParams(param);
+                GoodsModifyInfo.getPageModifyInfo(param, function (data) {
+                    $scope.auditedList = data.content;
+                    params.total(data.totalElements);
+                    $defer.resolve(data.content);
+                }, function () {
+                    toaster.pop('error', '获取数据失败')
+                })
+            }
+        });
+
+        $scope.ModifyDetailTableParams = new ngTableParams({
+            page: 1,
+            count: 3,
+            sorting: {
+                updateTime : 'DESC'
+            }
+        }, {
+            total: 0,
+            getData: function ($defer, params) {
+                var param = BaseService.parseParams(params.url());
+                param.batchCode = goods.batchCode;
+                initQueryParams(param);
+
+                GoodsModifyInfo.getPageModifyDetail(param, function (data) {
+                    $scope.detailList = data.content;
+                    params.total(data.totalElements);
+                    $defer.resolve(data.content);
+                }, function () {
+                    toaster.pop('error', '获取数据失败')
+                })
+            }
+        });
+
+        $scope.cancel = function () {
+            $modalInstance.dismiss();
+        }
+    }]);
+});

+ 2 - 0
src/main/webapp/resources/js/admin/main.js

@@ -6,6 +6,7 @@ require.config({
 		'lib' : 'lib',
 		'common' : 'js/common',
 		'angular' : 'lib/angular/angular.min',
+		'angular-tree' : 'lib/angular/angular-tree-control',
 		'ngResource' : 'lib/angular/angular-resource.min',
 		'angularAMD' : 'lib/angular/angularAMD',
 		'ui-bootstrap' : 'lib/angular/ui-bootstrap-tpls.min',
@@ -64,6 +65,7 @@ require.config({
 		'jquery-summernote-lang' : ['jquery-summernote'],
 		'ui-form' : ['angular', 'jquery-summernote', 'jquery-summernote-lang'],
 		'ui-jquery': ['jquery'],
+		'angular-tree': ['angular'],
 		'file-upload': ['angular', 'file-upload-shim'],
 		'angular-toaster' : ['angular', 'ngAnimate'],
 		'ngDraggable': [ 'jquery', 'angular' ],

+ 8 - 0
src/main/webapp/resources/js/common/query/commodity.js

@@ -37,6 +37,14 @@ define([ 'ngResource' ], function() {
 			findPageGoods: {
 				url : rootPath + '/api/commodity/goods/page',
 				method : 'GET'
+			},
+			/**
+			 * 返回所有类目信息
+			 */
+			getAllKindInfo: {
+				url : rootPath + '/commodity-service/kinds',
+				method: 'GET',
+				isArray: true
 			}
 		});
 	}]);

+ 46 - 8
src/main/webapp/resources/js/common/query/goods.js

@@ -3,6 +3,20 @@ define([ 'ngResource' ], function() {
 		var rootPath = BaseService.getRootPath();
 		//获取ComponentSubmit的分页数据
 		return $resource('trade/goods', {}, {
+			/**
+			* 获取分页面的GOODS数据(后台数据 产品管理部分)
+			 * start wangcz
+			* */
+			loadGoodsList: {
+				url: 'trade/goods/background/page',
+				method: 'POST'
+			},
+
+			/**
+			 * end  wangcz
+			 * */
+
+
 			//取得完整的消息
 			findAllByUuid : {
 				url : 'trade/goods/byUuid/:uuid',
@@ -20,6 +34,10 @@ define([ 'ngResource' ], function() {
 				method : 'GET',
 				isArray : true
 			},
+			findOneById : {
+				url : 'trade/goods/one',
+				method : 'GET'
+			},
 			//取得有效的简化的消息
 			findSimpleAvailableByUuid : {
 				url : 'trade/goods/simple/byUuidAndCurrency',
@@ -203,17 +221,10 @@ define([ 'ngResource' ], function() {
                 url : 'trade/goods/similarities/count',
                 method : 'GET'
             },
-            /**
-             * 获取类似的产品
-             */
-            getSimilarityProCount : {
-                url : 'trade/goods/similarities/count',
-                method : 'GET'
-            },
             /**
              * 批量获取类似的产品
              */
-            getSimilarityProCount : {
+            getSimilarityProCountBatch : {
                 url : 'trade/goods/similarities/count/batch',
                 method : 'POST'
             },
@@ -270,5 +281,32 @@ define([ 'ngResource' ], function() {
 				method : 'GET'
 			}
 		});
+	}]).factory('GoodsModifyInfo', ['$resource', function ($resource) {
+		return $resource('goods/modifyInfo', {}, {
+			getPageModifyInfo : {
+				url: 'goods/modifyInfo/page',
+				method: 'GET'
+			},
+			getPageModifyDetail : {
+				url: 'goods/modifyInfo/detail/page',
+				method: 'GET'
+			},
+			getModifyInfoByBatchCode : {
+				url: 'goods/modifyInfo/batchCode',
+				method: 'GET',
+				isArray: true
+			},
+			auditedGoods : {
+				url: 'goods/modifyInfo/audit/goods',
+				method: 'PUT'
+			}
+		})
+	}]).factory('GoodsHistory', ['$resource', function ($resource) {
+		return $resource('trade/goodsHistory', {}, {
+			findDataOfUpAndDown: {
+				url: 'trade/goodsHistory/page/batchCode',
+				method: 'GET'
+			}
+		})
 	}]);
 });

+ 12 - 0
src/main/webapp/resources/js/common/query/logisticsPort.js

@@ -141,5 +141,17 @@ define([ 'ngResource' ], function() {
 				method: 'PUT'
 			}
 		})
+	}]).factory('BackgroundRecord', ['$resource', function ($resource) {
+		return $resource('background/record', {}, {
+			getUserTitle : {
+				url: 'background/record/title',
+				method: 'GET',
+				isArray: true
+			},
+			updateUserTitle : {
+				url: 'background/record/update',
+				method: 'POST'
+			}
+		})
 	}]);
 });

+ 1 - 1
src/main/webapp/resources/js/vendor/controllers/forstore/vendor_materialCtrl.js

@@ -3031,7 +3031,7 @@ define([ 'app/app', 'jquery-uploadify' ], function(app) {
                     var idStr = $scope.ids.join(',');
                     Material.deleteBatch({ids : idStr}, function (data) {
                         toaster.pop('success', '删除成功');
-						$scope.deleteModal = false;
+                        $scope.deleteModal = false;
                         $modalInstance.close(data);
                     }, function (response) {
                         $scope.deleteModal = false;

+ 445 - 0
src/main/webapp/resources/lib/angular/angular-tree-control.js

@@ -0,0 +1,445 @@
+/* commonjs package manager support (eg componentjs) */
+if (typeof module !== "undefined" && typeof exports !== "undefined" && module.exports === exports){
+  module.exports = 'treeControl';
+}
+(function ( angular ) {
+    'use strict';
+
+    function createPath(startScope) {
+        return function path() {
+            var _path = [];
+            var scope = startScope;
+            var prevNode;
+            while (scope && scope.node !== startScope.synteticRoot) {
+                if (prevNode !== scope.node)
+                    _path.push(scope.node);
+                prevNode = scope.node;
+                scope = scope.$parent;
+            }
+            return _path;
+        }
+    }
+
+    function ensureDefault(obj, prop, value) {
+        if (!obj.hasOwnProperty(prop))
+            obj[prop] = value;
+    }
+
+    function defaultIsLeaf(node, $scope) {
+        return !node[$scope.options.nodeChildren] || node[$scope.options.nodeChildren].length === 0;
+    }
+
+    function shallowCopy(src, dst) {
+        if (angular.isArray(src)) {
+            dst = dst || [];
+
+            for (var i = 0; i < src.length; i++) {
+                dst[i] = src[i];
+            }
+        } else if (angular.isObject(src)) {
+            dst = dst || {};
+
+            for (var key in src) {
+                if (hasOwnProperty.call(src, key) && !(key.charAt(0) === '$' && key.charAt(1) === '$')) {
+                    dst[key] = src[key];
+                }
+            }
+        }
+
+        return dst || src;
+    }
+    function defaultEquality(a, b,$scope) {
+        if (!a || !b)
+            return false;
+        a = shallowCopy(a);
+        a[$scope.options.nodeChildren] = [];
+        b = shallowCopy(b);
+        b[$scope.options.nodeChildren] = [];
+        return angular.equals(a, b);
+    }
+
+    function defaultIsSelectable() {
+        return true;
+    }
+
+    function ensureAllDefaultOptions($scope) {
+        ensureDefault($scope.options, "multiSelection", false);
+        ensureDefault($scope.options, "nodeChildren", "children");
+        ensureDefault($scope.options, "dirSelectable", "true");
+        ensureDefault($scope.options, "injectClasses", {});
+        ensureDefault($scope.options.injectClasses, "ul", "");
+        ensureDefault($scope.options.injectClasses, "li", "");
+        ensureDefault($scope.options.injectClasses, "liSelected", "");
+        ensureDefault($scope.options.injectClasses, "iExpanded", "");
+        ensureDefault($scope.options.injectClasses, "iCollapsed", "");
+        ensureDefault($scope.options.injectClasses, "iLeaf", "");
+        ensureDefault($scope.options.injectClasses, "label", "");
+        ensureDefault($scope.options.injectClasses, "labelSelected", "");
+        ensureDefault($scope.options, "equality", defaultEquality);
+        ensureDefault($scope.options, "isLeaf", defaultIsLeaf);
+        ensureDefault($scope.options, "allowDeselect", true);
+        ensureDefault($scope.options, "isSelectable", defaultIsSelectable);
+    }
+    
+    angular.module( 'treeControl', [] )
+        .constant('treeConfig', {
+            templateUrl: null
+        })
+        .directive( 'treecontrol', ['$compile', function( $compile ) {
+            /**
+             * @param cssClass - the css class
+             * @param addClassProperty - should we wrap the class name with class=""
+             */
+            function classIfDefined(cssClass, addClassProperty) {
+                if (cssClass) {
+                    if (addClassProperty)
+                        return 'class="' + cssClass + '"';
+                    else
+                        return cssClass;
+                }
+                else
+                    return "";
+            }
+            
+            
+            
+            return {
+                restrict: 'EA',
+                require: "treecontrol",
+                transclude: true,
+                scope: {
+                    treeModel: "=",
+                    selectedNode: "=?",
+                    selectedNodes: "=?",
+                    expandedNodes: "=?",
+                    onSelection: "&",
+                    onNodeToggle: "&",
+                    options: "=?",
+                    orderBy: "=?",
+                    reverseOrder: "@",
+                    filterExpression: "=?",
+                    filterComparator: "=?"
+                },
+                controller: ['$scope', '$templateCache', '$interpolate', 'treeConfig', function ($scope, $templateCache, $interpolate, treeConfig) {
+                    
+                    $scope.options = $scope.options || {};
+                    
+                    ensureAllDefaultOptions($scope);
+                  
+                    $scope.selectedNodes = $scope.selectedNodes || [];
+                    $scope.expandedNodes = $scope.expandedNodes || [];
+                    $scope.expandedNodesMap = {};
+                    for (var i=0; i < $scope.expandedNodes.length; i++) {
+                        $scope.expandedNodesMap["a"+i] = $scope.expandedNodes[i];
+                    }
+                    $scope.parentScopeOfTree = $scope.$parent;
+
+
+                    function isSelectedNode(node) {
+                        if (!$scope.options.multiSelection && ($scope.options.equality(node, $scope.selectedNode , $scope)))
+                            return true;
+                        else if ($scope.options.multiSelection && $scope.selectedNodes) {
+                            for (var i = 0; (i < $scope.selectedNodes.length); i++) {
+                                if ($scope.options.equality(node, $scope.selectedNodes[i] , $scope)) {
+                                    return true;
+                                }
+                            }
+                            return false;
+                        }
+                    }
+
+                    $scope.headClass = function(node) {
+                        var liSelectionClass = classIfDefined($scope.options.injectClasses.liSelected, false);
+                        var injectSelectionClass = "";
+                        if (liSelectionClass && isSelectedNode(node))
+                            injectSelectionClass = " " + liSelectionClass;
+                        if ($scope.options.isLeaf(node, $scope))
+                            return "tree-leaf" + injectSelectionClass;
+                        if ($scope.expandedNodesMap[this.$id])
+                            return "tree-expanded" + injectSelectionClass;
+                        else
+                            return "tree-collapsed" + injectSelectionClass;
+                    };
+
+                    $scope.iBranchClass = function() {
+                        if ($scope.expandedNodesMap[this.$id])
+                            return classIfDefined($scope.options.injectClasses.iExpanded);
+                        else
+                            return classIfDefined($scope.options.injectClasses.iCollapsed);
+                    };
+
+                    $scope.nodeExpanded = function() {
+                        return !!$scope.expandedNodesMap[this.$id];
+                    };
+
+                    $scope.selectNodeHead = function() {
+                        var transcludedScope = this;
+                        var expanding = $scope.expandedNodesMap[transcludedScope.$id] === undefined;
+                        $scope.expandedNodesMap[transcludedScope.$id] = (expanding ? transcludedScope.node : undefined);
+                        if (expanding) {
+                            $scope.expandedNodes.push(transcludedScope.node);
+                        }
+                        else {
+                            var index;
+                            for (var i=0; (i < $scope.expandedNodes.length) && !index; i++) {
+                                if ($scope.options.equality($scope.expandedNodes[i], transcludedScope.node , $scope)) {
+                                    index = i;
+                                }
+                            }
+                            if (index !== undefined)
+                                $scope.expandedNodes.splice(index, 1);
+                        }
+                        if ($scope.onNodeToggle) {
+                            var parentNode = (transcludedScope.$parent.node === transcludedScope.synteticRoot)?null:transcludedScope.$parent.node;
+                            var path = createPath(transcludedScope);
+                            $scope.onNodeToggle({node: transcludedScope.node, $parentNode: parentNode, $path: path,
+                              $index: transcludedScope.$index, $first: transcludedScope.$first, $middle: transcludedScope.$middle,
+                              $last: transcludedScope.$last, $odd: transcludedScope.$odd, $even: transcludedScope.$even, expanded: expanding});
+
+                        }
+                    };
+
+                    $scope.selectNodeLabel = function( selectedNode){
+                        var transcludedScope = this;
+                        if(!$scope.options.isLeaf(selectedNode, $scope) && (!$scope.options.dirSelectable || !$scope.options.isSelectable(selectedNode))) {
+                            // Branch node is not selectable, expand
+                            this.selectNodeHead();
+                        }
+                        else if($scope.options.isLeaf(selectedNode, $scope) && (!$scope.options.isSelectable(selectedNode))) {
+                            // Leaf node is not selectable
+                            return;
+                        }
+                        else {
+                            var selected = false;
+                            if ($scope.options.multiSelection) {
+                                var pos = -1;
+                                for (var i=0; i < $scope.selectedNodes.length; i++) {
+                                    if($scope.options.equality(selectedNode, $scope.selectedNodes[i] , $scope)) {
+                                        pos = i;
+                                        break;
+                                    }
+                                }
+                                if (pos === -1) {
+                                    $scope.selectedNodes.push(selectedNode);
+                                    selected = true;
+                                } else {
+                                    $scope.selectedNodes.splice(pos, 1);
+                                }
+                            } else {
+                                if (!$scope.options.equality(selectedNode, $scope.selectedNode , $scope)) {
+                                    $scope.selectedNode = selectedNode;
+                                    selected = true;
+                                }
+                                else {
+                                    if ($scope.options.allowDeselect) {
+                                        $scope.selectedNode = undefined;
+                                    } else {
+                                        $scope.selectedNode = selectedNode;
+                                        selected = true;
+                                    }
+                                }
+                            }
+                            if ($scope.onSelection) {
+                                var parentNode = (transcludedScope.$parent.node === transcludedScope.synteticRoot)?null:transcludedScope.$parent.node;
+                                var path = createPath(transcludedScope)
+                                $scope.onSelection({node: selectedNode, selected: selected, $parentNode: parentNode, $path: path,
+                                  $index: transcludedScope.$index, $first: transcludedScope.$first, $middle: transcludedScope.$middle,
+                                  $last: transcludedScope.$last, $odd: transcludedScope.$odd, $even: transcludedScope.$even});
+                            }
+                        }
+                    };
+
+                    $scope.selectedClass = function() {
+                        var isThisNodeSelected = isSelectedNode(this.node);
+                        var labelSelectionClass = classIfDefined($scope.options.injectClasses.labelSelected, false);
+                        var injectSelectionClass = "";
+                        if (labelSelectionClass && isThisNodeSelected)
+                            injectSelectionClass = " " + labelSelectionClass;
+
+                        return isThisNodeSelected ? "tree-selected" + injectSelectionClass : "";
+                    };
+
+                    $scope.unselectableClass = function() {
+                        var isThisNodeUnselectable = !$scope.options.isSelectable(this.node);
+                        var labelUnselectableClass = classIfDefined($scope.options.injectClasses.labelUnselectable, false);
+                        return isThisNodeUnselectable ? "tree-unselectable " + labelUnselectableClass : "";
+                    };
+
+                    //tree template
+                    $scope.isReverse = function() {
+                      return !($scope.reverseOrder === 'false' || $scope.reverseOrder === 'False' || $scope.reverseOrder === '' || $scope.reverseOrder === false);
+                    };
+
+                    $scope.orderByFunc = function() {
+                      return $scope.orderBy;
+                    };
+//                    return "" + $scope.orderBy;
+
+                    var templateOptions = {
+                        orderBy: $scope.orderBy ? " | orderBy:orderByFunc():isReverse()" : '',
+                        ulClass: classIfDefined($scope.options.injectClasses.ul, true),
+                        nodeChildren:  $scope.options.nodeChildren,
+                        liClass: classIfDefined($scope.options.injectClasses.li, true),
+                        iLeafClass: classIfDefined($scope.options.injectClasses.iLeaf, false),
+                        labelClass: classIfDefined($scope.options.injectClasses.label, false)
+                    };
+
+                    var template;
+                    var templateUrl = $scope.options.templateUrl || treeConfig.templateUrl;
+
+                    if(templateUrl) {
+                        template = $templateCache.get(templateUrl);
+                    }
+
+                    if(!template) {
+                        template =
+                            '<ul {{options.ulClass}} >' +
+                            '<li ng-repeat="node in node.{{options.nodeChildren}} | filter:filterExpression:filterComparator {{options.orderBy}}" ng-class="headClass(node)" {{options.liClass}}' +
+                            'set-node-to-data>' +
+                            '<i class="tree-branch-head" ng-class="iBranchClass()" ng-click="selectNodeHead(node)"></i>' +
+                            '<i class="tree-leaf-head {{options.iLeafClass}}"></i>' +
+                            '<div class="tree-label {{options.labelClass}}" ng-class="[selectedClass(), unselectableClass()]" ng-click="selectNodeLabel(node)" tree-transclude></div>' +
+                            '<treeitem ng-if="nodeExpanded()"></treeitem>' +
+                            '</li>' +
+                            '</ul>';
+                    }
+
+                    this.template = $compile($interpolate(template)({options: templateOptions}));
+                }],
+                compile: function(element, attrs, childTranscludeFn) {
+                    return function ( scope, element, attrs, treemodelCntr ) {
+
+                        scope.$watch("treeModel", function updateNodeOnRootScope(newValue) {
+                            if (angular.isArray(newValue)) {
+                                if (angular.isDefined(scope.node) && angular.equals(scope.node[scope.options.nodeChildren], newValue))
+                                    return;
+                                scope.node = {};
+                                scope.synteticRoot = scope.node;
+                                scope.node[scope.options.nodeChildren] = newValue;
+                            }
+                            else {
+                                if (angular.equals(scope.node, newValue))
+                                    return;
+                                scope.node = newValue;
+                            }
+                        });
+
+                        scope.$watchCollection('expandedNodes', function(newValue, oldValue) {
+                            var notFoundIds = 0;
+                            var newExpandedNodesMap = {};
+                            var $liElements = element.find('li');
+                            var existingScopes = [];
+                            // find all nodes visible on the tree and the scope $id of the scopes including them
+                            angular.forEach($liElements, function(liElement) {
+                                var $liElement = angular.element(liElement);
+                                var liScope = {
+                                    $id: $liElement.data('scope-id'),
+                                    node: $liElement.data('node')
+                                };
+                                existingScopes.push(liScope);
+                            });
+                            // iterate over the newValue, the new expanded nodes, and for each find it in the existingNodesAndScopes
+                            // if found, add the mapping $id -> node into newExpandedNodesMap
+                            // if not found, add the mapping num -> node into newExpandedNodesMap
+                            angular.forEach(newValue, function(newExNode) {
+                                var found = false;
+                                for (var i=0; (i < existingScopes.length) && !found; i++) {
+                                    var existingScope = existingScopes[i];
+                                    if (scope.options.equality(newExNode, existingScope.node , scope)) {
+                                        newExpandedNodesMap[existingScope.$id] = existingScope.node;
+                                        found = true;
+                                    }
+                                }
+                                if (!found)
+                                    newExpandedNodesMap['a' + notFoundIds++] = newExNode;
+                            });
+                            scope.expandedNodesMap = newExpandedNodesMap;
+                        });
+
+//                        scope.$watch('expandedNodesMap', function(newValue) {
+//
+//                        });
+
+                        //Rendering template for a root node
+                        treemodelCntr.template( scope, function(clone) {
+                            element.html('').append( clone );
+                        });
+                        // save the transclude function from compile (which is not bound to a scope as apposed to the one from link)
+                        // we can fix this to work with the link transclude function with angular 1.2.6. as for angular 1.2.0 we need
+                        // to keep using the compile function
+                        scope.$treeTransclude = childTranscludeFn;
+                    };
+                }
+            };
+        }])
+        .directive("setNodeToData", ['$parse', function($parse) {
+            return {
+                restrict: 'A',
+                link: function($scope, $element, $attrs) {
+                    $element.data('node', $scope.node);
+                    $element.data('scope-id', $scope.$id);
+                }
+            };
+        }])
+        .directive("treeitem", function() {
+            return {
+                restrict: 'E',
+                require: "^treecontrol",
+                link: function( scope, element, attrs, treemodelCntr) {
+                    // Rendering template for the current node
+                    treemodelCntr.template(scope, function(clone) {
+                        element.html('').append(clone);
+                    });
+                }
+            };
+        })
+        .directive("treeTransclude", function () {
+            return {
+                controller: ['$scope',function ($scope) {
+                    ensureAllDefaultOptions($scope);
+                }],
+
+                link: function(scope, element, attrs, controller) {
+                    if (!scope.options.isLeaf(scope.node, scope)) {
+                        angular.forEach(scope.expandedNodesMap, function (node, id) {
+                            if (scope.options.equality(node, scope.node , scope)) {
+                                scope.expandedNodesMap[scope.$id] = scope.node;
+                                scope.expandedNodesMap[id] = undefined;
+                            }
+                        });
+                    }
+                    if (!scope.options.multiSelection && scope.options.equality(scope.node, scope.selectedNode , scope)) {
+                        scope.selectedNode = scope.node;
+                    } else if (scope.options.multiSelection) {
+                        var newSelectedNodes = [];
+                        for (var i = 0; (i < scope.selectedNodes.length); i++) {
+                            if (scope.options.equality(scope.node, scope.selectedNodes[i] , scope)) {
+                                newSelectedNodes.push(scope.node);
+                            }
+                        }
+                        scope.selectedNodes = newSelectedNodes;
+                    }
+
+                    // create a scope for the transclusion, whos parent is the parent of the tree control
+                    scope.transcludeScope = scope.parentScopeOfTree.$new();
+                    scope.transcludeScope.node = scope.node;
+                    scope.transcludeScope.$path = createPath(scope);
+                    scope.transcludeScope.$parentNode = (scope.$parent.node === scope.synteticRoot)?null:scope.$parent.node;
+                    scope.transcludeScope.$index = scope.$index;
+                    scope.transcludeScope.$first = scope.$first;
+                    scope.transcludeScope.$middle = scope.$middle;
+                    scope.transcludeScope.$last = scope.$last;
+                    scope.transcludeScope.$odd = scope.$odd;
+                    scope.transcludeScope.$even = scope.$even;
+                    scope.$on('$destroy', function() {
+                        scope.transcludeScope.$destroy();
+                    });
+
+                    scope.$treeTransclude(scope.transcludeScope, function(clone) {
+                        element.empty();
+                        element.append(clone);
+                    });
+                }
+            };
+        });
+})( angular );

+ 46 - 46
src/main/webapp/resources/view/admin/modal/billInfoModal.html

@@ -62,52 +62,52 @@ div.title {
 </div>
 <form class="form-horizontal " name="myForm" novalidate>
 	<div class="modal-body" id="body">
-			<div class="padding-bottom-10">
-				<div class="row-left text-right">开票抬头:</div>
-				<div class="row-right" ng-bind="bill.head"></div>
+		<div class="padding-bottom-10">
+			<div class="row-left text-right">开票抬头:</div>
+			<div class="row-right" ng-bind="bill.head"></div>
+		</div>
+		<div class="padding-bottom-10">
+			<div class="row-left text-right">发票类型:</div>
+			<div class="row-right" ng-bind="bill.kind==1206 ? '增值税(普通)发票': '增值税(专用)发票'"></div>
+		</div>
+		<div class="padding-bottom-10">
+			<div class="row-left text-right">收票人:</div>
+			<div class="row-right" ng-bind="bill.name"></div>
+		</div>
+		<div class="padding-bottom-10">
+			<div class="row-left text-right">收票人电话:</div>
+			<div class="row-right" ng-bind="bill.telephone"></div>
+		</div>
+		<div class="padding-bottom-10">
+			<div class="row-left text-right">收票人地址:</div>
+			<div class="row-right auto-br" title="{{address}}" ng-init="address= bill.area+ bill.detailAddress">
+				<span ng-bind="bill.area"></span>
+				<span ng-bind="bill.detailAddress"></span>
 			</div>
-			<div class="padding-bottom-10">
-				<div class="row-left text-right">发票类型:</div>
-				<div class="row-right" ng-bind="bill.kind==1206 ? '增值税(普通)发票': '增值税(专用)发票'"></div>
-			</div>
-			<div class="padding-bottom-10">
-		    	<div class="row-left text-right">收票人:</div>
-		    	<div class="row-right" ng-bind="bill.name"></div>
-		  	</div>
-		  	<div class="padding-bottom-10">
-		  		<div class="row-left text-right">收票人电话:</div>
-		  		<div class="row-right" ng-bind="bill.telephone"></div>
-		  	</div>
-		  	<div class="padding-bottom-10">
-		  		<div class="row-left text-right">收票人地址:</div>
-		  		<div class="row-right auto-br" title="{{address}}" ng-init="address= bill.area+ bill.detailAddress">
-		  			<span ng-bind="bill.area"></span>
-		  			<span ng-bind="bill.detailAddress"></span>
-		  		</div>
-		  	</div>
-		  	<div class="padding-bottom-10" ng-show="bill.companyAddress">
-		  		<div class="row-left text-right">企业地址:</div>
-		  		<div class="row-right" ng-bind="bill.companyAddress"></div>
-		  	</div>
-		  	<div class="padding-bottom-10" ng-show="bill.companyTaxNumber">
-		  		<div class="row-left text-right">税务登记号:</div>
-		  		<div class="row-right" ng-bind="bill.companyTaxNumber"></div>
-		  	</div>
-		  	<div class="padding-bottom-10" ng-show="bill.companyPhone">
-		  		<div class="row-left text-right">企业电话:</div>
-		  		<div class="row-right" ng-bind="bill.companyPhone"></div>
-		  	</div>
-		  	<div class="padding-bottom-10" ng-show="bill.bankName">
-		  		<div class="row-left text-right">开户银行:</div>
-		  		<div class="row-right" ng-bind="bill.bankName"></div>
-		  	</div>
-		  	<div class="padding-bottom-10" ng-show="bill.bankAccount">
-		  		<div class="row-left text-right">开户银行账户:</div>
-		  		<div class="row-right" ng-bind="bill.bankAccount"></div>
-		  	</div>
-		  	<div class="padding-bottom-10" ng-show="bill.attachUrl">
-		  		<div class="row-left text-right">发票资料:</div>
-		  		<div class="row-right"><a href="{{bill.attachUrl}}" target="_blank">点击查看</a></div>
-		  	</div>
+		</div>
+		<div class="padding-bottom-10" ng-show="bill.companyAddress">
+			<div class="row-left text-right">企业地址:</div>
+			<div class="row-right" ng-bind="bill.companyAddress"></div>
+		</div>
+		<div class="padding-bottom-10" ng-show="bill.companyTaxNumber">
+			<div class="row-left text-right">税务登记号:</div>
+			<div class="row-right" ng-bind="bill.companyTaxNumber"></div>
+		</div>
+		<div class="padding-bottom-10" ng-show="bill.companyPhone">
+			<div class="row-left text-right">企业电话:</div>
+			<div class="row-right" ng-bind="bill.companyPhone"></div>
+		</div>
+		<div class="padding-bottom-10" ng-show="bill.bankName">
+			<div class="row-left text-right">开户银行:</div>
+			<div class="row-right" ng-bind="bill.bankName"></div>
+		</div>
+		<div class="padding-bottom-10" ng-show="bill.bankAccount">
+			<div class="row-left text-right">开户银行账户:</div>
+			<div class="row-right" ng-bind="bill.bankAccount"></div>
+		</div>
+		<div class="padding-bottom-10" ng-show="bill.attachUrl">
+			<div class="row-left text-right">发票资料:</div>
+			<div class="row-right"><a href="{{bill.attachUrl}}" target="_blank">点击查看</a></div>
+		</div>
 	</div>
 </form>

+ 125 - 0
src/main/webapp/resources/view/admin/modal/manage/ManageSoldOut.html

@@ -0,0 +1,125 @@
+<div class="modal-header">
+    <button type="button" class="close" ng-click="cancel()"><span >×</span></button>
+</div>
+<div class="modal-body">
+    <div class="title">
+        <h3 class="modal-title">是否下架此产品</h3>
+        <!--<span><em>*</em>&nbsp;此产品已被推荐至店铺首页</span>-->
+    </div>
+    <div class="modal-center">
+        <div class="row">
+            <div class="col-xs-2 text-right">
+                <span>原因:</span>
+            </div>
+            <div class="col-xs-10">
+                <form class="form-inline" name="myForm">
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut" ng-model="errorType" ng-checked="errorType==1" ng-click="changeType(1)">价格异常
+                        </label>
+                    </div>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut" ng-model="errorType" ng-checked="errorType==2" ng-click="changeType(2)">图片违规
+                        </label>
+                    </div>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut" ng-model="errorType" ng-checked="errorType==3" ng-click="changeType(3)">基本信息有误
+                        </label>
+                    </div>
+                    <br/>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut" ng-model="errorType" ng-checked="errorType==4" ng-click="changeType(4)">断缺货&nbsp;&nbsp;&nbsp;
+                        </label>
+                    </div>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut" ng-model="errorType" ng-checked="errorType==5" ng-click="changeType(5)">其它
+                            <input type="text" ng-show="errorType==5" ng-model="otherMessage" ng-change="inputMessage()">
+                        </label>
+                    </div>
+                </form>
+            </div>
+        </div>
+    </div>
+    <div class="form-btn">
+        <button class="btn" ng-click="cancel()" value="close">取消</button>
+        <button class="btn" type="submit" ng-click="ensureDown()" value="success">确定</button>
+    </div>
+</div>
+<style>
+    .modal-content{
+        width:440px!important;
+    }
+    .modal-header{
+        height:22px;
+        line-height: 22px;
+        background: #2ca3e7;
+    }
+    .modal-header .close {
+        margin-top: -10px;
+        color: #fff;
+        opacity:1;
+    }
+    .modal-body{
+        padding-bottom:30px;
+    }
+    .modal-body .title{
+        margin-left:15px;
+        margin-bottom:15px;
+    }
+    .modal-body .title h3{
+        font-size: 16px;
+        color:#1d9ce5;
+        line-height: 32px;
+    }
+    .modal-body .title span{
+        font-size: 12px;
+        color:#666;
+    }
+    .modal-body .title span em{
+        color:#ff4242;
+        position:relative;
+        top:-3px;
+    }
+    .modal-body .modal-center{
+        background: #f3f3f3;
+        padding:15px 0;
+        font-size: 14px;
+        color:#333;
+    }
+    .modal-body .modal-center .row .col-xs-2{
+        padding:5px 0;
+    }
+    .modal-body .modal-center .row .checkbox{
+        margin:0 0 10px 10px;
+    }
+    .modal-body .modal-center .row .col-xs-10{
+        padding:0;
+    }
+    .modal-body .form-btn{
+        padding-top:25px;
+        margin:0 auto;
+        text-align: center;
+    }
+    .modal-body .form-btn button{
+        width:71px;
+        height:25px;
+        line-height: 23px;
+        padding:0 22px;
+        margin:0 11px;
+        border-radius:3px;
+    }
+    .modal-body .form-btn button[value=close]{
+        color:#999;
+        background: #fff;
+        border:1px solid #999;
+    }
+    .modal-body .form-btn button{
+        color:#fff;
+        background: #37a7e8;
+        border:1px solid #37a7e8;
+    }
+</style>

+ 125 - 0
src/main/webapp/resources/view/admin/modal/manage/detailsProduct_modal.html

@@ -0,0 +1,125 @@
+<div class="modal-header">
+    <button type="button" class="close" ng-click="cancel()"><span >×</span></button>
+</div>
+<div class="modal-body">
+    <div class="title">
+        <h3 class="modal-title">是否下架此产品</h3>
+        <span><em>*</em>&nbsp;此产品已被推荐至店铺首页</span>
+    </div>
+    <div class="modal-center">
+        <div class="row">
+            <div class="col-xs-2 text-right">
+                <span>原因:</span>
+            </div>
+            <div class="col-xs-10">
+                <form class="form-inline" name="myForm">
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut">价格异常
+                        </label>
+                    </div>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut">图片违规
+                        </label>
+                    </div>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut">基本信息有误
+                        </label>
+                    </div>
+                    <br/>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut">断缺货&nbsp;&nbsp;&nbsp;
+                        </label>
+                    </div>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut">其它
+                            <input type="text">
+                        </label>
+                    </div>
+                </form>
+            </div>
+        </div>
+    </div>
+    <div class="form-btn">
+        <button class="btn" ng-click="cancel()" value="close">取消</button>
+        <button class="btn" type="submit" ng-click="ensureAddAccount()" value="success">确定</button>
+    </div>
+</div>
+<style>
+    .modal-content{
+        width:440px!important;
+    }
+    .modal-header{
+        height:22px;
+        line-height: 22px;
+        background: #2ca3e7;
+    }
+    .modal-header .close {
+        margin-top: -10px;
+        color: #fff;
+        opacity:1;
+    }
+    .modal-body{
+        padding-bottom:30px;
+    }
+    .modal-body .title{
+        margin-left:15px;
+        margin-bottom:15px;
+    }
+    .modal-body .title h3{
+        font-size: 16px;
+        color:#1d9ce5;
+        line-height: 32px;
+    }
+    .modal-body .title span{
+        font-size: 12px;
+        color:#666;
+    }
+    .modal-body .title span em{
+        color:#ff4242;
+        position:relative;
+        top:-3px;
+    }
+    .modal-body .modal-center{
+        background: #f3f3f3;
+        padding:15px 0;
+        font-size: 14px;
+        color:#333;
+    }
+    .modal-body .modal-center .row .col-xs-2{
+        padding:5px 0;
+    }
+    .modal-body .modal-center .row .checkbox{
+        margin:0 0 10px 10px;
+    }
+    .modal-body .modal-center .row .col-xs-10{
+        padding:0;
+    }
+    .modal-body .form-btn{
+        padding-top:25px;
+        margin:0 auto;
+        text-align: center;
+    }
+    .modal-body .form-btn button{
+        width:71px;
+        height:25px;
+        line-height: 23px;
+        padding:0 22px;
+        margin:0 11px;
+        border-radius:3px;
+    }
+    .modal-body .form-btn button[value=close]{
+        color:#999;
+        background: #fff;
+        border:1px solid #999;
+    }
+    .modal-body .form-btn button{
+        color:#fff;
+        background: #37a7e8;
+        border:1px solid #37a7e8;
+    }
+</style>

+ 125 - 0
src/main/webapp/resources/view/admin/modal/manage/exportProduct_modal.html

@@ -0,0 +1,125 @@
+<div class="modal-header">
+    <button type="button" class="close" ng-click="cancel()"><span >×</span></button>
+</div>
+<div class="modal-body">
+    <div class="title">
+        <h3 class="modal-title">是否下架此产品</h3>
+        <span><em>*</em>&nbsp;此产品已被推荐至店铺首页</span>
+    </div>
+    <div class="modal-center">
+        <div class="row">
+            <div class="col-xs-2 text-right">
+                <span>原因:</span>
+            </div>
+            <div class="col-xs-10">
+                <form class="form-inline" name="myForm">
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut">价格异常
+                        </label>
+                    </div>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut">图片违规
+                        </label>
+                    </div>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut">基本信息有误
+                        </label>
+                    </div>
+                    <br/>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut">断缺货&nbsp;&nbsp;&nbsp;
+                        </label>
+                    </div>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut">其它
+                            <input type="text">
+                        </label>
+                    </div>
+                </form>
+            </div>
+        </div>
+    </div>
+    <div class="form-btn">
+        <button class="btn" ng-click="cancel()" value="close">取消</button>
+        <button class="btn" type="submit" ng-click="ensureAddAccount()" value="success">确定</button>
+    </div>
+</div>
+<style>
+    .modal-content{
+        width:440px!important;
+    }
+    .modal-header{
+        height:22px;
+        line-height: 22px;
+        background: #2ca3e7;
+    }
+    .modal-header .close {
+        margin-top: -10px;
+        color: #fff;
+        opacity:1;
+    }
+    .modal-body{
+        padding-bottom:30px;
+    }
+    .modal-body .title{
+        margin-left:15px;
+        margin-bottom:15px;
+    }
+    .modal-body .title h3{
+        font-size: 16px;
+        color:#1d9ce5;
+        line-height: 32px;
+    }
+    .modal-body .title span{
+        font-size: 12px;
+        color:#666;
+    }
+    .modal-body .title span em{
+        color:#ff4242;
+        position:relative;
+        top:-3px;
+    }
+    .modal-body .modal-center{
+        background: #f3f3f3;
+        padding:15px 0;
+        font-size: 14px;
+        color:#333;
+    }
+    .modal-body .modal-center .row .col-xs-2{
+        padding:5px 0;
+    }
+    .modal-body .modal-center .row .checkbox{
+        margin:0 0 10px 10px;
+    }
+    .modal-body .modal-center .row .col-xs-10{
+        padding:0;
+    }
+    .modal-body .form-btn{
+        padding-top:25px;
+        margin:0 auto;
+        text-align: center;
+    }
+    .modal-body .form-btn button{
+        width:71px;
+        height:25px;
+        line-height: 23px;
+        padding:0 22px;
+        margin:0 11px;
+        border-radius:3px;
+    }
+    .modal-body .form-btn button[value=close]{
+        color:#999;
+        background: #fff;
+        border:1px solid #999;
+    }
+    .modal-body .form-btn button{
+        color:#fff;
+        background: #37a7e8;
+        border:1px solid #37a7e8;
+    }
+</style>

+ 395 - 0
src/main/webapp/resources/view/admin/modal/manage/journal_modal.html

@@ -0,0 +1,395 @@
+<div class="modal-header">
+    <button type="button" class="close" ng-click="cancel()"><span >×</span></button>
+</div>
+<div class="modal-body">
+    <div class="title">
+        <h3 class="modal-title">查看日志</h3>
+    </div>
+    <div class="tab-list">
+        <ul class="list-inline">
+            <li ng-class="{active:tabs==='basic'}"><span ng-click="convertTab('basic')">基本信息</span></li>
+            <li ng-class="{active:tabs==='repertory'}" ng-if="false"><span ng-click="convertTab('repertory')">库存信息</span></li>
+            <li ng-class="{active:tabs==='frost'}" ng-if="false"><span ng-click="convertTab('frost')">冻结释放</span></li>
+            <li ng-class="{active:tabs==='sell'}"><span ng-click="convertTab('sell')">销售信息</span></li>
+            <li ng-class="{active:tabs==='correlation'}" ng-if="false"><span ng-click="convertTab('correlation')">相关产品</span></li>
+            <li ng-class="{active:tabs==='group'}" ng-if="false"><span ng-click="convertTab('group')">组合套餐</span></li>
+            <li ng-class="{active:tabs==='smt'}"><span ng-click="convertTab('smt')">上下架</span></li>
+            <li ng-class="{active:tabs==='audit'}"><span ng-click="convertTab('audit')">平台审核</span></li>
+        </ul>
+    </div>
+    <div class="modal-center">
+        <div class="time-search clearfix">
+            <div class="date pull-left">
+                <div class="data-input">
+                    <input id="start" type="text" ng-model="startDate" readonly="readonly"
+                           class="form-control select-adder" placeholder="起始时间"
+                           datepicker-popup="yyyy-MM-dd"
+                           is-open="condition[0].open"
+                           current-text="今天" clear-text="清除" close-text="关闭"
+                           datepicker-options="{formatDayTitle: 'yyyy年M月', formatMonth: 'M月', showWeeks: false}"
+                           ng-click="openDatePicker($event, condition, 0)"
+                           ng-change="onDateCondition(1)"/>
+                    <button class="open" ng-click="openDatePicker($event, condition, 0)"></button>
+                </div>
+                -----
+                <div class="data-input">
+                    <input id="end" type="text" ng-model="endDate" readonly="readonly"
+                           class="form-control select-adder" placeholder="结束时间"
+                           datepicker-popup="yyyy-MM-dd"
+                           is-open="condition[1].open"
+                           current-text="今天" clear-text="清除" close-text="关闭"
+                           datepicker-options="{formatDayTitle: 'yyyy年M月', formatMonth: 'M月', showWeeks: false}"
+                           ng-click="openDatePicker($event, condition, 1)"
+                           ng-change="onDateCondition(2)"/>
+                    <button class="open" ng-click="openDatePicker($event, condition, 1)"></button>
+                </div>
+            </div>
+            <div class="sreach-input pull-right">
+                <input type="search" placeholder="操作人" class="form-control" ng-model="keyword" ng-search="search()"/>
+                <a class="seek" href="javascript:void(0)" ng-click="search(tabs)">搜索</a>
+            </div>
+        </div>
+        <table ng-if="tabs==='basic'" ng-table="ModifyDetailTableParams">
+            <thead>
+            <tr>
+                <th>时间</th>
+                <th>操作人</th>
+                <th>修改前</th>
+                <th>修改后</th>
+            </tr>
+            </thead>
+            <tbody>
+                <tr ng-repeat="aModify in detailList" ng-if="aModify.basicCount != 0">
+                    <td><span ng-bind="aModify.updateTime | date : 'yyyy-MM-dd HH:mm:ss'">2017-77-77 00.00.00</span></td>
+                    <td><span ng-bind="aModify.operateName"></span></td>
+                    <td>
+                        <p ng-repeat="info in aModify.infoList" ng-if="info.type==1">
+                            <span ng-bind="info.modifyField">盘装</span>:
+                            <span ng-bind="info.before">盘装</span>
+                        </p>
+                    </td>
+                    <td>
+                        <p ng-repeat="info in aModify.infoList" ng-if="info.type==1">
+                            <span ng-bind="info.modifyField">盘装</span>:
+                            <span ng-bind="info.after">盘装</span>
+                        </p>
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+        <table ng-if="tabs==='repertory'">
+            <thead>
+            <tr>
+                <th>时间</th>
+                <th>操作人</th>
+                <th>操作</th>
+                <th>下架原因</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr>
+                <td>2017-07-02 21.21.21</td>
+                <td>张三</td>
+                <td>上架</td>
+                <td>图处有酷管家</td>
+            </tr>
+            </tbody>
+            <tbody>
+            <tr>
+                <td>2017-07-02 21.21.21</td>
+                <td>张三</td>
+                <td>上架</td>
+                <td>图处有酷管家</td>
+            </tr>
+            </tbody>
+        </table>
+        <table ng-if="tabs==='frost'">
+            <thead>
+            <tr>
+                <th>时间</th>
+                <th>操作人</th>
+                <th>操作</th>
+                <th>下架原因</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr>
+                <td>2017-07-02 21.21.21</td>
+                <td>张三</td>
+                <td>上架</td>
+                <td>图处有酷管家</td>
+            </tr>
+            </tbody>
+            <tbody>
+            <tr>
+                <td>2017-07-02 21.21.21</td>
+                <td>张三</td>
+                <td>上架</td>
+                <td>图处有酷管家</td>
+            </tr>
+            </tbody>
+        </table>
+        <table ng-if="tabs==='sell'">
+            <thead>
+            <tr>
+                <th>时间</th>
+                <th>操作人</th>
+                <th>修改前</th>
+                <th>修改后</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr ng-repeat="aModify in detailList" ng-if="aModify.sellCount != 0">
+                <td><span ng-bind="aModify.updateTime | date : 'yyyy-MM-dd HH:mm:ss'">2017-77-77 00.00.00</span></td>
+                <td><span ng-bind="aModify.operateName"></span></td>
+                <td>
+                    <p ng-repeat="info in aModify.infoList" ng-if="info.type==2">
+                        <span ng-bind="info.modifyField">盘装</span>:
+                        <span ng-if="info.modifyField != '可拆卖'" ng-bind="info.before">盘装</span>
+                        <span ng-if="info.modifyField == '可拆卖'" ng-bind="info.before =='true' ? '是' : '否'">盘装</span>
+                    </p>
+                </td>
+                <td>
+                    <p ng-repeat="info in aModify.infoList" ng-if="info.type==2">
+                        <span ng-bind="info.modifyField">盘装</span>:
+                        <span ng-if="info.modifyField != '可拆卖'" ng-bind="info.after">盘装</span>
+                        <span ng-if="info.modifyField == '可拆卖'" ng-bind="info.after =='true' ? '是' : '否'">盘装</span>
+                    </p>
+                </td>
+            </tr>
+            </tbody>
+        </table>
+        <table ng-if="tabs==='correlation'">
+            <thead>
+            <tr>
+                <th>时间</th>
+                <th>操作人</th>
+                <th>操作</th>
+                <th>下架原因</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr>
+                <td>2017-07-02 21.21.21</td>
+                <td>张三</td>
+                <td>上架</td>
+                <td>图处有酷管家</td>
+            </tr>
+            </tbody>
+            <tbody>
+            <tr>
+                <td>2017-07-02 21.21.21</td>
+                <td>张三</td>
+                <td>上架</td>
+                <td>图处有酷管家</td>
+            </tr>
+            </tbody>
+        </table>
+        <table ng-if="tabs==='group'">
+            <thead>
+            <tr>
+                <th>时间</th>
+                <th>操作人</th>
+                <th>操作</th>
+                <th>下架原因</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr>
+                <td>2017-07-02 21.21.21</td>
+                <td>张三</td>
+                <td>上架</td>
+                <td>图处有酷管家</td>
+            </tr>
+            </tbody>
+            <tbody>
+            <tr>
+                <td>2017-07-02 21.21.21</td>
+                <td>张三</td>
+                <td>上架</td>
+                <td>图处有酷管家</td>
+            </tr>
+            </tbody>
+        </table>
+        <table ng-if="tabs==='smt'" ng-table="historyTableParams">
+            <thead>
+            <tr>
+                <th>时间</th>
+                <th>操作人</th>
+                <th>操作</th>
+                <th>下架原因</th>
+            </tr>
+            </thead>
+            <tbody>
+            <tr ng-repeat="history in historyList">
+                <td ng-bind="history.operateDate | date: 'yyyy-MM-dd HH:mm:ss'">2017-07-02 21.21.21</td>
+                <td ng-bind="history.operater.userName">张三</td>
+                <td ng-bind="historyStatus[history.operateType]">上架</td>
+                <td ng-bind="history.downMsg || '-'">图处有酷管家</td>
+            </tr>
+            </tbody>
+        </table>
+        <table ng-if="tabs==='audit'" ng-table="auditedTableParams">
+            <thead>
+                <tr>
+                    <th>时间</th>
+                    <th>操作人</th>
+                    <th>操作</th>
+                    <th>原因</th>
+                </tr>
+            </thead>
+            <tbody>
+                <tr ng-repeat="record in auditedList">
+                    <td ng-bind="record.updateTime | date: 'yyyy-MM-dd HH:mm:ss'">2017-07-02 21.21.21</td>
+                    <td ng-bind="record.auditedName">张三</td>
+                    <td ng-bind="record.status == 11 ? '审核通过' : '审核不通过'">上架</td>
+                    <td ng-bind="record.message || '-'">图处有酷管家</td>
+                </tr>
+            </tbody>
+        </table>
+    </div>
+</div>
+<style>
+    .modal-content{
+        width:820px!important;
+    }
+    .modal-header{
+        height:22px;
+        line-height: 22px;
+        background: #2ca3e7;
+    }
+    .modal-header .close {
+        margin-top: -10px;
+        color: #fff;
+        opacity:1;
+    }
+    .modal-body{
+        padding:10px!important;
+    }
+    .modal-body .title h3{
+        font-size: 16px;
+        color:#1d9ce5;
+        line-height: 16px;
+        margin-bottom:10px;
+    }
+    .modal-body .tab-list{
+        border-bottom:1px solid #ddd;
+    }
+    .modal-body .tab-list ul{
+        margin:0;
+        width:798px;
+    }
+    .modal-body .tab-list ul li{
+        padding:0!important;
+        width:12.06%;
+    }
+    .modal-body .tab-list ul li span{
+        display:block;
+        height:38px;
+        line-height: 36px;
+        font-size: 14px;
+        color:#999;
+        text-align: center;
+        background: #eaeaea;
+        border:1px solid #ddd;
+        border-bottom:none;
+        border-radius:3px 3px 0 0 ;
+    }
+    .modal-body .tab-list ul li:hover span,.modal-body .tab-list ul li.active span{
+        height: 39px;
+        line-height: 38px;
+        position: relative;
+        top: 1px;
+        cursor:pointer;
+        background: #fff;
+        color:#333;
+    }
+    .modal-body .modal-center{
+        border:1px solid #ddd;
+        border-top:none;
+        padding:15px 0;
+    }
+    .modal-body .modal-center .time-search{
+        padding:8px 0;
+        border-top:2px solid #e9e9e9;
+        border-bottom:1px solid #e9e9e9;
+    }
+    .modal-body .modal-center .time-search .date .data-input{
+        display:inline-block;
+        margin: 0 10px;
+        position: relative;
+    }
+    .modal-body .modal-center .time-search .date .data-input .select-adder{
+        width:229px;
+        height:25px;
+        line-height: 25px;
+    }
+    .modal-body .modal-center .time-search .date .data-input button.open{
+        position: absolute;
+        right: 3px;
+        top: 1px;
+        width: 20px;
+        height: 23px;
+        background: url('static/img/user/images/xiala.png') right no-repeat #fff !important;
+        background-position-x: 100% !important;
+        border: none;
+    }
+    .modal-body .modal-center .time-search .sreach-input input{
+        display:inline-block;
+        width:90px;
+        height:25px;
+        line-height: 23px;
+        padding:0 0 0 3px;
+        font-size: 12px;
+        color:#999;
+        border-radius:3px;
+        margin-right:32px;
+    }
+    .modal-body .modal-center .time-search .sreach-input input:hover{
+        cursor:pointer;
+    }
+    .modal-body .modal-center .time-search .sreach-input a{
+        display:inline-block;
+        width:58px;
+        height:25px;
+        line-height: 25px;
+        text-align: center;
+        color:#fff;
+        background: #3caae8;
+        border-radius:3px;
+        margin:0 12px;
+    }
+    .modal-body .modal-center .time-search .sreach-input a:hover{
+        text-decoration:none;
+    }
+    .modal-body .modal-center>table{
+        border-top:1px solid #e9e9e9;
+        width:100%;
+        margin-bottom:15px;
+    }
+    .modal-body .modal-center>table thead tr{
+        border-bottom:1px dashed #e0e0e0;
+        height:40px;
+        line-height: 40px;
+    }
+    .modal-body .modal-center>table thead tr th{
+        text-align: center;
+        color:#333;
+        font-size: 14px;
+    }
+    .modal-body .modal-center>table tbody tr{
+        border-bottom:1px dashed #e0e0e0;
+        background: #fff;
+        height:80px;
+        vertical-align: middle;
+    }
+    .modal-body .modal-center>table tbody tr td{
+        text-align: center;
+        color:#999;
+        font-size: 14px;
+    }
+    .modal-body .modal-center>table tbody tr:hover{
+        background: #fbfcff;
+    }
+
+</style>

+ 193 - 0
src/main/webapp/resources/view/admin/modal/manage/manageAudit.html

@@ -0,0 +1,193 @@
+<div class="modal-header">
+    <button type="button" class="close" ng-click="cancel()"><span >×</span></button>
+</div>
+<div class="modal-body" ng-show="hasAuditTwo">
+    <div class="title">
+        <h3 class="modal-title">审核不通过的产品将会强制下架</h3>
+        <!--<span><em>*</em>&nbsp;此产品已被推荐至店铺首页</span>-->
+    </div>
+    <div class="modal-center">
+        <div class="row">
+            <div class="col-xs-2 text-right">
+                <span>原因:</span>
+            </div>
+            <div class="col-xs-10">
+                <form class="form-inline" name="myForm">
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut" ng-model="errorType" ng-checked="errorType==1" ng-click="changeType(1)">价格异常
+                        </label>
+                    </div>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut" ng-model="errorType" ng-checked="errorType==2" ng-click="changeType(2)">图片违规
+                        </label>
+                    </div>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut" ng-model="errorType" ng-checked="errorType==3" ng-click="changeType(3)">基本信息有误
+                        </label>
+                    </div>
+                    <br/>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut" ng-model="errorType" ng-checked="errorType==4" ng-click="changeType(4)">断缺货&nbsp;&nbsp;&nbsp;
+                        </label>
+                    </div>
+                    <div class="checkbox">
+                        <label class="control-label">
+                            <input type="radio" name="soldOut" ng-model="errorType" ng-checked="errorType==5" ng-click="changeType(5)">其它
+                            <input type="text" ng-show="errorType==5" ng-model="otherMessage" ng-change="inputMessage()">
+                        </label>
+                    </div>
+                </form>
+            </div>
+        </div>
+    </div>
+    <div class="form-btn">
+        <button class="btn" ng-click="toggleAudit(false)" value="close">上一步</button>
+        <button class="btn" type="submit" ng-click="ensureAudit(false)" value="success">确认</button>
+    </div>
+</div>
+<div class="modal-body" ng-show="!hasAuditTwo">
+    <div class="title">
+        <a style="font-size: 16px;" class="modal-title" target="_blank" href="admin#/manage/{{auditGoods.id}}">查看产品详情</a>
+        <span ng-if="auditGoods.auditedTime">上次审核通过的时间: <b ng-bind="auditGoods.auditedTime | date : 'yyyy-MM-dd HH:mm:ss'">2017-17-17  00.00.00</b></span>
+    </div>
+    <table>
+        <thead>
+        <tr>
+            <th>修改前</th>
+            <th>修改后</th>
+            <th>时间</th>
+        </tr>
+        </thead>
+        <tbody>
+        <tr ng-repeat="aModify in modifyList">
+            <td>
+                <p ng-repeat="info in aModify.infoList">
+                    <span ng-bind="info.modifyField">盘装</span>:
+                    <span ng-bind="info.before">盘装</span>
+                </p>
+            </td>
+            <td>
+                <p ng-repeat="info in aModify.infoList">
+                    <span ng-bind="info.modifyField">盘装</span>:
+                    <span ng-bind="info.after">盘装</span>
+                </p>
+            </td>
+            <td><span ng-bind="aModify.updateTime | date : 'yyyy-MM-dd HH:mm:ss'">2017-77-77 00.00.00</span></td>
+        </tr>
+        </tbody>
+    </table>
+    <div class="form-btn">
+        <button class="btn" ng-click="toggleAudit(true)" value="close">审核不通过</button>
+        <button class="btn" type="submit" ng-click="ensureAudit(true)" value="success">审核通过</button>
+    </div>
+</div>
+<style>
+    .modal-content{
+        width:542px!important;
+    }
+    .modal-header{
+        height:22px;
+        line-height: 22px;
+        background: #2ca3e7;
+    }
+    .modal-header .close {
+        margin-top: -10px;
+        color: #fff;
+        opacity:1;
+    }
+    .modal-body{
+        padding-bottom:30px;
+    }
+    .modal-body .title{
+        margin-bottom:15px;
+    }
+    .modal-body .title h3{
+        font-size: 16px;
+        color:#1d9ce5;
+        line-height: 32px;
+    }
+    .modal-body .title span{
+        font-size: 12px;
+        color:#666;
+    }
+    .modal-body table{
+        border:1px solid #d3d3d3;
+        border-radius:5px;
+        width:100%;
+    }
+    .modal-body table thead tr{
+        background: #f3f3f3;
+        height:28px;
+        line-height: 28px;
+    }
+    .modal-body table thead tr th{
+        width:33%;
+        text-align: center;
+    }
+    .modal-body table tbody tr{
+        height:60px;
+        border-bottom:1px solid #d3d3d3;
+    }
+    .modal-body table tbody tr:hover{
+        cursor:pointer;
+        background: #fbfcff;
+    }
+    .modal-body table tbody tr:last-child{
+        border:none;
+    }
+    .modal-body table tbody tr td{
+        text-align: center;
+        vertical-align: center;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+    }
+
+    .modal-body .form-btn{
+        padding-top:25px;
+        margin:0 auto;
+        text-align: center;
+    }
+    .modal-body .form-btn button{
+        height:25px;
+        line-height: 23px;
+        padding:0 22px;
+        margin:0 11px;
+        border-radius:3px;
+    }
+    .modal-body .form-btn button[value=close]{
+        color:#999;
+        background: #fff;
+        border:1px solid #999;
+    }
+    .modal-body .form-btn button{
+        color:#fff;
+        background: #37a7e8;
+        border:1px solid #37a7e8;
+    }
+
+
+    .modal-body .title span em{
+        color:#ff4242;
+        position:relative;
+        top:-3px;
+    }
+    .modal-body .modal-center{
+        background: #f3f3f3;
+        padding:15px 0;
+        font-size: 14px;
+        color:#333;
+    }
+    .modal-body .modal-center .row .col-xs-2{
+        padding:5px 0;
+    }
+    .modal-body .modal-center .row .checkbox{
+        margin:0 0 10px 10px;
+    }
+    .modal-body .modal-center .row .col-xs-10{
+        padding:0;
+    }
+</style>

+ 208 - 0
src/main/webapp/resources/view/admin/modal/manage/moreInfo_modal.html

@@ -0,0 +1,208 @@
+<div class="modal-header">
+    <button type="button" class="close" ng-click="cancel()"><span >×</span></button>
+</div>
+<div class="modal-body">
+    <div class="title">
+        <h3 class="modal-title">选择字段</h3>
+    </div>
+    <div class="modal-center">
+        <form class="form-inline" name="myForm">
+            <div class="checkbox" ng-repeat="item in allTitle" ng-if="item.titleName!=='产品信息'">
+                <label class="control-label">
+                    <input type="checkbox" ng-checked="item.choosed" ng-click="item.choosed = !item.choosed">{{item.titleName}}
+                </label>
+            </div>
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">商家名称-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox" style="display:none;">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">产品信息-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">SKU编码-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">产品编号-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">封装-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">梯度-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">单价-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">交期(天)-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">包装-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">包装数量-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">起订量-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">拆包售卖-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">在售数量-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">锁库数-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">冻结数量-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">库存总数-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">在售状态-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">销售方式-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">创建人-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">创建时间-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">产品类型-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">图片类型-->
+                <!--</label>-->
+            <!--</div>-->
+            <!--<div class="checkbox">-->
+                <!--<label class="control-label">-->
+                    <!--<input type="checkbox" name="moreinfo">产品图片-->
+                <!--</label>-->
+            <!--</div>-->
+        </form>
+    </div>
+    <div class="form-btn">
+        <button class="btn" ng-click="cancel()" value="close">取消</button>
+        <button class="btn" type="submit" ng-click="ensureAddAccount()" value="success">确定</button>
+    </div>
+</div>
+<style>
+    .modal-content{
+        width:550px!important;
+    }
+    .modal-header{
+        height:22px;
+        line-height: 22px;
+        background: #2ca3e7;
+    }
+    .modal-header .close {
+        margin-top: -10px;
+        color: #fff;
+        opacity:1;
+    }
+    .modal-body{
+        padding-bottom:30px;
+    }
+    .modal-body .title{
+        margin-left:15px;
+        margin-bottom:15px;
+    }
+    .modal-body .title h3{
+        font-size: 16px;
+        color:#1d9ce5;
+        line-height: 32px;
+    }
+    .modal-body .title span{
+        font-size: 12px;
+        color:#666;
+    }
+    .modal-body .title span em{
+        color:#ff4242;
+        position:relative;
+        top:-3px;
+    }
+    .modal-body .modal-center{
+        background: #f3f3f3;
+        padding:15px 0;
+        font-size: 14px;
+        color:#333;
+    }
+    .modal-body .modal-center .checkbox{
+        width:94px;
+        padding-left:10px;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space: nowrap;
+    }
+    .modal-body .form-btn{
+        padding-top:25px;
+        margin:0 auto;
+        text-align: center;
+    }
+    .modal-body .form-btn button{
+        width:71px;
+        height:25px;
+        line-height: 23px;
+        padding:0 22px;
+        margin:0 11px;
+        border-radius:3px;
+    }
+    .modal-body .form-btn button[value=close]{
+        color:#999;
+        background: #fff;
+        border:1px solid #999;
+    }
+    .modal-body .form-btn button{
+        color:#fff;
+        background: #37a7e8;
+        border:1px solid #37a7e8;
+    }
+</style>

+ 78 - 0
src/main/webapp/resources/view/admin/modal/manage/showContrastImg_modal.html

@@ -0,0 +1,78 @@
+<div class="modal-header">
+    <button type="button" class="close" ng-click="cancel()"><span >×</span></button>
+</div>
+<div class="modal-body">
+    <ul class="list-inline">
+        <li class="body-list body-left">
+            <div class="body-left">
+                <h3>用户自有图片</h3>
+                <div class="img">
+                    <img ng-src="{{showImgs || 'static/img/store/common/default.png'}}">
+                </div>
+            </div>
+        </li>
+        <li class="body-list body-right">
+            <div class="body-right">
+                <h3>平台默认图片</h3>
+                <div class="img">
+                    <img src="static/img/store/common/default.png">
+                </div>
+            </div>
+        </li>
+    </ul>
+</div>
+<style>
+    .modal-header{
+        height:22px;
+        line-height: 22px;
+        background: #2ca3e7;
+    }
+    .modal-header .close {
+        margin-top: -10px;
+        color: #fff;
+        opacity:1;
+    }
+    .modal-body{
+        padding:0!important;
+        text-align: center;
+    }
+    .modal-body ul{
+        margin: 0 !important;
+        padding:0!important;
+    }
+    .modal-body .body-list{
+        display:inline-block;
+        padding:25px 32px;
+    }
+    .modal-body .body-list h3{
+        font-size: 16px;
+        font-weight: bold;
+        text-align: center;
+        margin:0 0 25px 0!important;
+    }
+    .modal-body .body-list .img{
+        display: block;
+        width:232px;
+        height:232px;
+        border:1px solid #999;
+        margin:0 auto;
+        overflow: hidden;
+    }
+    .modal-body .body-list img{
+        width:100%;
+        height:100%;
+    }
+    .modal-body .body-left{
+        background: #fff;
+    }
+    .modal-body .body-right{
+        background: #eee;
+    }
+    .modal-body .body-left h3{
+        color:#333;
+    }
+    .modal-body .body-right h3{
+        color:#666;
+    }
+
+</style>

+ 594 - 0
src/main/webapp/resources/view/admin/product/productManage.html

@@ -0,0 +1,594 @@
+<div id="manage">
+    <div class="container-fluid">
+        <div class="manage-form">
+            <div class="form-top">
+                <div class="form-inline">
+                    <div class="form-group form-group-sm">
+                        <label class="control-label">
+                            型号:
+                            <input class="form-control width140" type="text" ng-model="goodsFilter.code" placeholder="型号">
+                        </label>
+                    </div>
+                    <div class="form-group form-group-sm">
+                        <label class="control-label">
+                            商家:
+                            <input class="form-control width140" type="text" ng-model="goodsFilter.store" placeholder="商家ID/商家名称">
+                        </label>
+                    </div>
+                    <div class="form-group form-group-sm">
+                        <label class="control-label">
+                            在售状态:
+                            <select name="" id="1" class="form-control width88" ng-model="goodsFilter.saleStatus">
+                                <option value="">全部</option>
+                                <option value="601">已上架</option>
+                                <option value="613">新品未上架</option>
+                                <option value="612">已下架</option>
+                            </select>
+                        </label>
+                    </div>
+                    <div class="form-group form-group-sm">
+                        <label class="control-label">
+                            &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;币种:
+                            <select id="2" class="form-control width60" ng-model="goodsFilter.currency">
+                                <option value="">全部</option>
+                                <option value="RMB">RMB</option>
+                                <option value="USD">USD</option>
+                            </select>
+                        </label>
+                    </div>
+                    <div class="form-group form-group-sm">
+                        <label class="control-label">
+                            拆包售卖:
+                            <select name="" id="3" ng-model="goodsFilter.breakUp" class="form-control width88">
+                                <option value="">全部</option>
+                                <option value="true">可拆卖</option>
+                                <option value="false">不可拆卖</option>
+                            </select>
+                        </label>
+                    </div>
+                    <div class="form-group form-group-sm">
+                        <label class="control-label">
+                            审核状态:
+                            <select name="" id="4" ng-model="goodsFilter.audited" class="form-control width60">
+                                <option value="">全部</option>
+                                <option value="1">已审核</option>
+                                <option value="0">未审核</option>
+                            </select>
+                        </label>
+                    </div>
+                </div>
+                <div class="form-inline">
+                    <div class="form-group form-group-sm">
+                        <label class="control-label">
+                            类目:
+                        </label>
+                        <div class="mar-rt0 row checkbox">
+                            <div class="col-md-3">
+                                <select class="form-control"
+                                        ng-model="kindPojo.first"
+                                        ng-options="key as value.nameCn for (key,value) in kindInfo"
+                                        ng-change="kindPojo.second='';kindPojo.third='';"
+                                        style="opacity: 1;">
+                                    <option value="">一级类目</option>
+                                </select>
+                            </div>
+                            <div class="col-md-3" style="margin-left: 10px;">
+                                <select class="form-control" ng-model="kindPojo.second"
+                                        ng-options="key as value.nameCn for (key,value) in kindInfo[kindPojo.first].children"
+                                        ng-change="kindPojo.third='';"
+                                        style="opacity: 1;">
+                                    <option value="">二级类目</option>
+                                </select>
+                            </div>
+                            <div class="col-md-3">
+                                <select class="form-control" ng-model="kindPojo.third" style="opacity: 1;"
+                                        ng-options="value as value.nameCn for value in kindInfo[kindPojo.first].children[kindPojo.second].children">
+                                    <option value="">三级类目</option>
+                                </select>
+                            </div>
+                        </div>
+                    </div>
+                    <div class="form-group form-group-sm">
+                        <label class="control-label">
+                            品牌:
+                            <input type="text" placeholder="品牌中英文名称" class="form-control width140" ng-model="goodsFilter.brand">
+                        </label>
+                    </div>
+                    <div class="form-group form-group-sm">
+                        <label class="control-label">
+                            在售数量:
+                            <select name="" id="6" class="form-control width88" ng-model="goodsFilter.saleNum">
+                                <option value="">全部</option>
+                                <option value="601">有货</option>
+                                <option value="602">不足起订量</option>
+                                <option value="603">无货</option>
+                            </select>
+                        </label>
+                    </div>
+                    <div class="form-group form-group-sm">
+                        <label class="control-label">
+                            销售方式:
+                            <select name="" id="7" ng-model="goodsFilter.saleSelf" class="form-control width60">
+                                <option value="">全部</option>
+                                <option value="true">自营</option>
+                                <option value="false">寄售</option>
+                            </select>
+                        </label>
+                    </div>
+                    <div class="form-group form-group-sm">
+                        <label class="control-label">
+                            产品类型:
+                            <select name="" id="8" ng-model="goodsFilter.standard" class="form-control width88">
+                                <option value="">全部</option>
+                                <option value="true">标准产品</option>
+                                <option value="false">非标准产品</option>
+                            </select>
+                        </label>
+                    </div>
+                    <div class="form-group form-group-sm">
+                        <label class="control-label">
+                            图片类型:
+                            <select name="" id="9" ng-model="goodsFilter.haveImg" class="form-control width88">
+                                <option value="">全部</option>
+                                <option value="true">自有图片</option>
+                                <option value="false">默认图片</option>
+                            </select>
+                        </label>
+                    </div>
+                    <div class="form-group form-group-sm">
+                        <button ng-click="searchClick()">搜索</button>
+                    </div>
+                    <div class="form-group form-group-sm">
+                        <button title="此功能没有开放">产品导出</button>
+                        <!--<button ng-click="exportClick()" >产品导出</button>-->
+                    </div>
+                </div>
+            </div>
+            <div class="form-bottom">
+                <button ng-click="batchDown()">批量下架</button>
+                <button ng-click="moreInfo()">更多信息</button>
+                <!--<label>-->
+                    <!--<input type="checkbox">合并相同产品-->
+                <!--</label>-->
+                <span style="float: right;font-size: 14px">共<span style="color: red;" ng-bind="totalCount">3424</span>个产品</span>
+            </div>
+        </div>
+        <div class="manage-table">
+           <table class="table" ng-table="manageTableParams">
+               <thead>
+               <tr>
+                   <th width="80">
+                       <label>
+                           <input id="AllChoose" type="checkbox" ng-checked="isChooseAll" ng-click="chooseAll()">全选
+                       </label>
+                   </th>
+                   <th width="120">操作</th>
+                   <th width="160" ng-if="titleInShow['商家ID']">商家ID</th>
+                   <th width="160" ng-if="titleInShow['商家名称']">商家名称</th>
+                   <th width="160">产品信息</th>
+                   <th width="160" ng-if="titleInShow['SKU编码']">SKU编码</th>
+                   <th width="160" ng-if="titleInShow['产品编号']">产品编号</th>
+                   <th width="160" ng-if="titleInShow['封装']">封装</th>
+                   <th width="160" ng-if="titleInShow['梯度']">梯度</th>
+                   <th width="160" ng-if="titleInShow['单价']">单价</th>
+                   <th width="160" ng-if="titleInShow['交期(天)']">交期(天)</th>
+                   <th width="160" ng-if="titleInShow['包装']">包装</th>
+                   <th width="160" ng-if="titleInShow['包装数量']">包装数量</th>
+                   <th width="160" ng-if="titleInShow['起订量']">起订量</th>
+                   <th width="160" ng-if="titleInShow['拆包售卖']">拆包售卖</th>
+                   <th width="160" ng-if="titleInShow['在售数量']">在售数量</th>
+                   <th width="160" ng-if="titleInShow['锁库数']">锁库数</th>
+                   <th width="160" ng-if="titleInShow['冻结数量']">冻结数量</th>
+                   <th width="160" ng-if="titleInShow['库存总数']">库存总数</th>
+                   <th width="160" ng-if="titleInShow['在售状态']">在售状态</th>
+                   <th width="160" ng-if="titleInShow['销售方式']">销售方式</th>
+                   <th width="160" ng-if="titleInShow['创建人']">创建人</th>
+                   <th width="160" ng-if="titleInShow['创建时间']">创建时间</th>
+                   <th width="160" ng-if="titleInShow['产品类型']">产品类型</th>
+                   <th width="160" ng-if="titleInShow['图片类型']">图片类型</th>
+                   <th width="160" ng-if="titleInShow['产品图片']">产品图片</th>
+               </tr>
+               </thead>
+               <tbody>
+               <tr ng-repeat="list in goodsList">
+                   <td>
+                       <input id="{{$index+1}}" type="checkbox" ng-checked="list.isChoosed" ng-click="chooseOne(list)">
+                   </td>
+                   <td>
+                       <a target="_blank" href="admin#/manage/{{list.id}}">详情</a>
+                       <a ng-if="list.audited == 0" ng-click="auditProduct(list)">审核</a>
+                       <br/>
+                       <a ng-click="journalProduct(list)" style="margin-left:-1px;">日志</a>
+                       <a ng-if="list.status == 601 || list.status == 602" ng-click="soldOutProduct([list.batchCode])">下架</a>
+                   </td>
+                   <td ng-if="titleInShow['商家ID']">
+                       <span ng-bind="list.enUU || '-'">商家ID</span>
+                   </td>
+                   <td ng-if="titleInShow['商家名称']">
+                       <span ng-bind="list.storeName || '-'">商家名称</span>
+                   </td>
+                   <td>
+                       <p>类目:<span ng-bind="list.kindNameCn || '-'">****</span></p>
+                       <p>型号:<span ng-bind="list.code || '-'">****</span></p>
+                       <p>品牌:<span ng-bind="list.brandNameEn || '-'">****</span></p>
+                   </td>
+                   <td ng-if="titleInShow['SKU编码']">
+                       <span ng-bind="list.batchCode || '-'">SKU编码</span>
+                   </td>
+                   <td ng-if="titleInShow['产品编号']">
+                       <span ng-bind="list.prodNum || '-'">产品编号</span>
+                   </td>
+                   <td ng-if="titleInShow['封装']">
+                       <span ng-bind="list.encapsulation || '-'">封装</span>
+                   </td>
+                   <td ng-if="titleInShow['梯度']">
+                      <div ng-repeat="qty in list.prices">
+                          <span ng-if="!$last">
+                              <span ng-bind="qty.start"></span>-<span ng-bind="qty.end"></span>
+                          </span>
+                          <span ng-if="$last">
+                              <span ng-bind="qty.start"></span>以上
+                          </span>
+                      </div>
+                   </td>
+                   <td ng-if="titleInShow['单价']">
+                      <div ng-repeat="price in list.prices">
+                          <span ng-bind="list.currencyName == 'RMB' ? '¥' : '$'"></span>
+                          <span ng-bind="list.currencyName == 'RMB' ? price.rMBPrice : price.uSDPrice"></span>
+                      </div>
+                   </td>
+                   <td ng-if="titleInShow['交期(天)']">
+                       <div ng-if="list.b2cMinDelivery != list.b2cMaxDelivery">
+                           <span ng-bind="list.b2cMinDelivery || '-'">交期(天)</span>-
+                           <span ng-bind="list.b2cMaxDelivery || '-'">交期(天)</span>
+                       </div>
+                       <span ng-if="list.b2cMinDelivery == list.b2cMaxDelivery" ng-bind="list.b2cMinDelivery || '-'">交期(天)</span>
+                   </td>
+                   <td ng-if="titleInShow['包装']">
+                       <span ng-bind="list.packaging || '-'">包装</span>
+                   </td>
+                   <td ng-if="titleInShow['包装数量']">
+                       <span ng-bind="list.minPackQty || '-'">包装</span>
+                   </td>
+                   <td ng-if="titleInShow['起订量']">
+                       <span ng-bind="list.minBuyQty || '-'">起订量</span>
+                   </td>
+                   <td ng-if="titleInShow['拆包售卖']">
+                       <span ng-if="list.breakUp">可拆卖</span>
+                       <span ng-if="!list.breakUp">不可拆卖</span>
+                   </td>
+                   <td ng-if="titleInShow['在售数量']">
+                       <span ng-bind="list.reserve">在售数量</span>
+                   </td>
+                   <td ng-if="titleInShow['锁库数']">
+                       <span ng-bind="'-'">锁库数</span>
+                   </td>
+                   <td ng-if="titleInShow['冻结数量']">
+                       <span ng-bind="list.frozen">冻结数量</span>
+                   </td>
+                   <td ng-if="titleInShow['库存总数']">
+                       <span ng-bind="list.reserve + list.frozen">库存总数</span>
+                   </td>
+                   <td ng-if="titleInShow['在售状态']">
+                       <span ng-bind="saleStatus[list.status] || '-'">在售状态</span>
+                   </td>
+                   <td ng-if="titleInShow['销售方式']">
+                       <span ng-bind="list.selfSale || '-'">销售方式</span>
+                   </td>
+                   <td ng-if="titleInShow['创建人']">
+                       <span ng-bind="list.publisherName || '-'">创建人</span>
+                   </td>
+                   <td ng-if="titleInShow['创建时间']">
+                       <span ng-bind="list.createdDate | date: 'yyyy-MM-dd HH:mm:ss' || '-'">创建时间</span>
+                   </td>
+                   <td ng-if="titleInShow['产品类型']">
+                       <span ng-if="list.uuid">标准</span>
+                       <span ng-if="!list.uuid">非标</span>
+                   </td>
+                   <td ng-if="titleInShow['图片类型']">
+                       <span ng-if="list.img">自有图片</span>
+                       <span ng-if="!list.img">默认图片</span>
+                   </td>
+                   <td ng-if="titleInShow['产品图片']">
+                       <img ng-src="{{list.img || 'static/img/store/common/default.png'}}" ng-click="showImg(list.img)" alt="产品图片">
+                   </td>
+               </tr>
+               </tbody>
+           </table>
+       </div>
+    </div>
+</div>
+<style>
+    #manage input[type=checkbox]{
+        position:relative;
+        top:3px;
+        left:-3px;
+    }
+
+    .manage-form{
+        height:158px;
+        background: #fff;
+        border-radius:5px;
+    }
+    .manage-form .form-top{
+        padding-top:15px;
+    }
+    .manage-form .form-top .form-inline{
+        display: inline-block;
+        width:1470px;
+        margin-bottom:10px;
+    }
+    .manage-form .form-top .form-group{
+        display: inline-block;
+        margin:0 18px;
+        vertical-align: middle;
+    }
+    .manage-form .form-top label{
+        text-align: right;
+        font-size: 14px;
+        color:#666;
+    }
+
+    .manage-form .form-top ul.tree{
+        position:absolute;
+        top:-4px;
+        left:46px;
+        z-index:100;
+        display:inline-block;
+        min-width:140px;
+        max-height: 473px;
+        overflow-y: auto;
+        line-height: 23px;
+        padding:0 5px;
+        margin:0;
+        color: #555555;
+        vertical-align: middle;
+        background-color: #ffffff;
+        border: 1px solid #cccccc;
+        border-radius: 4px;
+        -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
+        box-shadow: inset 0 1px 1px rgba(0,0,0,0.075);
+        -webkit-transition: border-color ease-in-out .15s,-webkit-box-shadow ease-in-out .15s;
+        -o-transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
+        transition: border-color ease-in-out .15s,box-shadow ease-in-out .15s;
+    }
+
+    .manage-form .form-top ul.tree li{
+        text-align: left;
+    }
+    .manage-form .form-top ul.tree li .icon-left {
+        position:absolute;
+        top:3px;
+        right:0px;
+        display:inline-block;
+        width:20px;
+        height:20px;
+        background: url("static/img/icon/opa-icons-color16.png") no-repeat -63px 1px;
+    }
+
+    .manage-form .form-top ul.tree li .icon-down {
+        position:absolute;
+        top:3px;
+        right:0px;
+        display:inline-block;
+        width:20px;
+        height:20px;
+        background: url("static/img/icon/opa-icons-color16.png") no-repeat -30px 1px;
+    }
+    .manage-form .form-top ul.tree li span{
+        color:#555;
+        font-size: 12px;
+        font-weight: normal;
+    }
+
+    .manage-form .form-top label input{
+        display: inline-block;
+        height:25px;
+        padding:0 2px;
+        margin:0;
+    }
+    .manage-form .form-top label select{
+        display: inline-block;
+        height:25px;
+        line-height: 25px;
+        padding:0 2px;
+        margin:0;
+    }
+    .manage-form .form-top label .width180{
+        padding:0 2px;
+        width:180px;
+    }
+    .manage-form .form-top label .width140{
+        padding:0 2px;
+        width:140px;
+    }
+    .manage-form .form-top label .width88{
+        width:88px;
+    }
+    .manage-form .form-top label .width60{
+        width:60px;
+    }
+    .manage-form .form-bottom{
+        margin-top:32px;
+    }
+    .manage-form  button{
+        border-radius:3px;
+        border:none;
+        line-height: 25px;
+        padding:0 15px;
+        font-size: 14px;
+        color:#fff;
+        background: #49afea;
+    }
+    .manage-form .form-bottom button{
+        margin:0 18px;
+    }
+    .manage-table table{
+        table-layout: fixed;
+        font-size: 14px;
+        color:#666;
+        border-collapse:separate;
+        border-spacing:0 5px;
+    }
+    .manage-table table thead tr{
+        height:50px;
+        line-height: 50px;
+        background: #f5f5f5;
+    }
+    .manage-table table thead tr label{
+        margin:0;
+    }
+    .form-control{
+        border-radius: 3px;
+    }
+    .manage-table table thead th{
+        text-align: center;
+        border:none;
+    }
+    .manage-table table thead th:first-child{
+        text-align: left;
+        padding-left:20px;
+    }
+    .manage-table table tbody{}
+    .manage-table table tbody tr{
+        height:72px;
+        margin-bottom:10px;
+        background: #fff;
+    }
+    .manage-table table tbody tr:hover{
+        position:relative;
+        top:2px;
+        left:2px;
+        cursor:pointer;
+        box-shadow:0 0 10px #e0e0e0;
+        background: #fff;
+    }
+    .manage-table table tbody td{
+        height:74px;
+        border:none;
+        vertical-align: middle;
+        text-align: center;
+    }
+    .manage-table table tbody td:first-child{
+        text-align: left;
+        padding-left:20px;
+    }
+    .manage-table table tbody td:nth-child(2){
+        padding:0;
+    }
+    .manage-table table tbody td p{
+        margin:0;
+        text-align: left;
+        font-size: 14px;
+        line-height: 18px;
+        width:100%;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        white-space:nowrap;
+    }
+    .select-adder{
+        background:url("static/img/user/images/xiala.png") right no-repeat ;
+        background-position-x: 180px;
+    }
+    .manage-table table tbody td img{
+        margin:0;
+        width:50%;
+    }
+    .manage-table table tbody td p span{
+        margin:0;
+        font-size: 14px;
+        line-height: 18px;
+    }
+    .manage-table table tbody td a{
+        display:inline-block;
+        padding:0 8px;
+        margin:2px;
+        line-height: 18px;
+        height:20px;
+        border:1px solid #35a6e8;
+        border-radius:3px;
+        font-size: 12px;
+        color:#666;
+        background: #fff;
+        text-decoration: none;
+    }
+    .manage-table table tbody td a:hover{
+        background: #35a6e8;
+        cursor:pointer;
+        color:#fff;
+    }
+
+    /* 树结构样式  */
+
+    [treecontrol] ul {
+        list-style: none;
+    }
+
+    [treecontrol] li {
+        position: relative;
+        padding: 0 0 0 20px;
+        line-height: 20px;
+    }
+
+    [treecontrol] li.tree-expanded i.tree-leaf-head, [treecontrol] li.tree-collapsed i.tree-leaf-head {display:none;}
+    [treecontrol] li.tree-expanded i.tree-branch-head, [treecontrol] li.tree-collapsed i.tree-branch-head {display:inline;}
+    [treecontrol] li.tree-leaf i.tree-branch-head {display:none;}
+    [treecontrol] li.tree-leaf i.tree-leaf-head {display:inline;}
+
+    [treecontrol] li i {
+        cursor: pointer;
+    }
+
+    [treecontrol] li .tree-label {
+        cursor: pointer;
+        display: inline;
+    }
+
+    [treecontrol].tree-boot > ul > li {
+        padding: 0;
+    }
+
+    [treecontrol].tree-boot li > .tree-label {
+        display: block;
+        padding: 3px 0;
+        border-radius: 4px;
+    }
+
+    [treecontrol].tree-boot i.tree-branch-head,
+    [treecontrol].tree-boot i.tree-leaf-head {
+        float: left;
+        height: 16px;
+        margin: 5px;
+    }
+
+    [treecontrol].tree-boot li.tree-expanded i.tree-branch-head {
+        padding: 1px 10px;
+        background: url("static/img/icon/opa-icons-color16.png") no-repeat -63px 1px;
+    }
+
+    [treecontrol].tree-boot li.tree-collapsed i.tree-branch-head {
+        padding: 1px 10px;
+        background: url("static/img/icon/opa-icons-color16.png") no-repeat -30px 1px;
+    }
+
+    [treecontrol].tree-boot li.tree-leaf i.tree-leaf-head {
+        padding: 1px 5px;
+    }
+
+    [treecontrol].tree-boot .tree-label.tree-selected,
+    [treecontrol].tree-boot .tree-label.tree-selected:hover{
+        background-color: #38a8e8;
+    }
+
+    [treecontrol].tree-boot .tree-label:hover{
+        background-color: #38a8e8;
+    }
+    [treecontrol].tree-boot .tree-label:hover span{
+        color:#fff;
+    }
+
+    #toast-container {
+        top: auto;
+        bottom: 40px;
+    }
+</style>

+ 330 - 0
src/main/webapp/resources/view/admin/product/productManageDetail.html

@@ -0,0 +1,330 @@
+<div class="manage-detail">
+    <div class="container">
+        <div class="detail-top clearfix">
+            <div class="top-left pull-left">
+                <span>产品详情</span>
+                <!--<a href="admin#/manage"><i class="fa fa-mail-reply "></i>&nbsp;&nbsp;  返回上一页</a>-->
+            </div>
+            <div class="top-right pull-right">
+                <span>在售状态:<em ng-bind="saleStatus[goods.status]">新品未上架</em></span>
+                <button class="btn" ng-if="goods.status == 601 || goods.status == 602" ng-click="soldOutProduct([goods.batchCode])">下架</button>
+                <button class="btn" ng-click="journalProduct(goods)">查看日志</button>
+            </div>
+        </div>
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                <h4 class="panel-title">基本信息</h4>
+            </div>
+            <div class="panel-body" style="padding:65px 50px 35px 50px;">
+                <div class="row">
+                    <div class="col-xs-4">
+                        <div class="img-info">
+                            <img ng-src="{{goods.img || 'static/img/store/common/default.png'}}">
+                            <i class="icon-fei" ng-if="!goods.uuid"></i>
+                            <i class="icon-biao" ng-if="goods.uuid"></i>
+                        </div>
+                    </div>
+                    <div class="col-xs-4">
+                        <div class="info-text">
+                            <p>型号:<span ng-bind="goods.code"></span></p>
+                            <p>产品名称(类目):<span ng-bind="goods.kindNameCn"></span></p>
+                            <p>品牌:<span ng-bind="goods.brandNameEn"></span></p>
+                            <p>封装:<span ng-bind="goods.encapsulation || '-'"></span></p>
+                        </div>
+                    </div>
+                    <div class="col-xs-4">
+                        <div class="info-text">
+                            <p>包装:<span ng-bind="goods.packaging || '-'"></span></p>
+                            <p>包装数量:<span ng-bind="goods.minPackQty || '-'"></span></p>
+                            <p>单位:<span ng-bind="goods.unit || '-'"></span></p>
+                            <p>生产日期:<span ng-bind="goods.produceDate || '-'"></span></p>
+                            <p>规格书:
+                                <a ng-if="goods.attach" target="_blank" href="{{goods.attach}}">点击查看</a>
+                                <span ng-if="!goods.attach">无</span>
+                            </p>
+                            <p>平台SKU编码:<span ng-bind="goods.batchCode"></span></p>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                <h4 class="panel-title">库存信息</h4>
+                <a data-toggle="collapse" data-target="#panel_one">
+                    <i class="fa fa-angle-double-down"></i>
+                    <i class="fa fa-angle-double-up"></i>
+                </a>
+            </div>
+            <div class="panel-body collapse in" id="panel_one">
+                <table class="table">
+                    <tr>
+                        <th>产品编号</th>
+                        <th>冻结数量</th>
+                        <!--<th>可上架数</th>-->
+                        <th>锁库数</th>
+                        <th>在售数量</th>
+                        <th>库存总数</th>
+                    </tr>
+                    <tr>
+                        <td ng-bind="goods.prodNum || '-'">111</td>
+                        <td ng-bind="goods.frozen">-</td>
+                        <!--<td>-</td>-->
+                        <td>-</td>
+                        <td ng-bind="goods.reserve">11</td>
+                        <td ng-bind="goods.reserve + goods.frozen">11</td>
+                    </tr>
+                </table>
+            </div>
+        </div>
+        <div class="panel panel-default">
+            <div class="panel-heading">
+                <h4 class="panel-title">销售信息</h4>
+                <a data-toggle="collapse" data-target="#panel_two">
+                    <i class="fa fa-angle-double-down"></i>
+                    <i class="fa fa-angle-double-up"></i>
+                </a>
+            </div>
+            <div class="panel-body collapse in" id="panel_two">
+                <table class="table">
+                    <tr>
+                        <th>梯度</th>
+                        <th>单价</th>
+                        <th>交期(天)</th>
+                        <th>起订量</th>
+                        <th>销售方式</th>
+                        <th>是否可拆卖</th>
+                    </tr>
+                    <tr ng-repeat="price in goods.prices">
+                        <td ng-bind="price.start + '+'">111</td>
+                        <td ng-bind="getPrice(goods.currencyName, price)">11</td>
+                        <td ng-if="$first" rowspan="{{goods.prices.length}}">
+                            <span ng-bind="goods.minDelivery"></span>-<span ng-bind="goods.maxDelivery"></span>
+                        </td>
+                        <td ng-if="$first" rowspan="{{goods.prices.length}}" ng-bind="goods.minBuyQty">11</td>
+                        <td ng-if="$first" rowspan="{{goods.prices.length}}" ng-bind="goods.selfSale">11</td>
+                        <td ng-if="$first" rowspan="{{goods.prices.length}}" ng-bind="breakUpStr(goods.breakUp)">11</td>
+                    </tr>
+                </table>
+            </div>
+        </div>
+        <div class="panel panel-default" ng-if="false">
+            <div class="panel-heading">
+                <h4 class="panel-title">相关产品</h4>
+                <a data-toggle="collapse" data-target="#panel_three">
+                    <i class="fa fa-angle-double-down"></i>
+                    <i class="fa fa-angle-double-up"></i>
+                </a>
+            </div>
+            <div class="panel-body collapse in" id="panel_three">
+                <table class="table">
+                    <tr>
+                        <th>产品编号</th>
+                        <th>产品名称(类目)</th>
+                        <th>型号</th>
+                        <th>封装</th>
+                        <th>品牌</th>
+                    </tr>
+                    <tr>
+                        <td>111</td>
+                        <td>11</td>
+                        <td>11</td>
+                        <td>11</td>
+                        <td>11</td>
+                    </tr>
+                </table>
+            </div>
+        </div>
+        <div class="panel panel-default" ng-if="false">
+            <div class="panel-heading">
+                <h4 class="panel-title">组合套餐</h4>
+                <a data-toggle="collapse" data-target="#panel_four"><i class="fa fa-angle-double-down"></i></a>
+            </div>
+            <div class="panel-body collapse in" id="panel_four">
+                <table class="table">
+                    <tr>
+                        <th>产品编号</th>
+                        <th>产品名称(类目)</th>
+                        <th>型号</th>
+                        <th>品牌</th>
+                        <th>封装</th>
+                        <th>套餐梯度</th>
+                        <th>套餐单价</th>
+                    </tr>
+                    <tr>
+                        <td>111</td>
+                        <td>11</td>
+                        <td>11</td>
+                        <td>11</td>
+                        <td>11</td>
+                        <td>11</td>
+                        <td>11</td>
+                    </tr>
+                    <tr>
+                        <td>111</td>
+                        <td>11</td>
+                        <td>11</td>
+                        <td>11</td>
+                        <td>11</td>
+                        <td>11</td>
+                        <td>11</td>
+                    </tr>
+                </table>
+            </div>
+        </div>
+    </div>
+</div>
+<style>
+    .manage-detail .container{
+        width:1190px;
+        margin:0 auto;
+    }
+    .detail-top{
+        margin-bottom:30px;
+    }
+    .detail-top .top-left span{
+        font-size: 24px;
+        color:#333;
+    }
+    .detail-top .top-left a{
+        display:inline-block;
+        width:120px;
+        height:24px;
+        margin-left:30px;
+        text-align: center;
+        line-height: 24px;
+        background: #34a6e8;
+        border-radius:3px;
+        color:#ffea00;
+    }
+    .detail-top .top-left a:hover{
+        text-decoration:none;
+        cursor:pointer;
+    }
+
+    .detail-top .top-right span{
+        font-size: 14px;
+        color:#333;
+    }
+    .detail-top .top-right span em{
+        font-style: normal;
+        background: none;
+        font-size: 14px;
+        font-family: "Microsoft Yahei","微软雅黑"!important;
+    }
+    .detail-top .top-right button{
+        padding:0 15px;
+        color:#fff;
+        font-size: 14px;
+        background: #34a6e8;
+        margin:0 15px;
+        height:25px;
+        line-height: 23px;
+        border:none;
+    }
+    .manage-detail .panel-default>.panel-heading{
+        position:relative;
+        background: #34a6e8;
+        line-height: 34px;
+        padding:6px 35px;
+    }
+    .manage-detail .panel-title{
+        font-size: 18px;
+        color:#fff;
+        font-weight: bold;
+    }
+    .manage-detail .panel-default>.panel-heading a{
+        position:absolute;
+        top:3px;
+        right:20px;
+    }
+    .manage-detail .panel-default>.panel-heading a i{
+        font-size: 28px;
+        color:#fff;
+    }
+    .manage-detail a i.fa-angle-double-down {
+        display: none;
+    }
+    .manage-detail a i.fa-angle-double-up {
+        display: inline;
+    }
+    .manage-detail .panel-default>.panel-heading a.collapsed i.fa-angle-double-down {
+        display: inline;
+    }
+    .manage-detail .panel-default>.panel-heading a.collapsed i.fa-angle-double-up {
+        display: none;
+    }
+    .manage-detail .img-info{
+        position:relative;
+        width:255px;
+        height:255px;
+        border:1px solid #d6d3ce;
+        overflow: hidden;
+    }
+    .manage-detail .img-info img{
+        height:100%;
+    }
+    .manage-detail .img-info i{
+        position:absolute;
+        top:0;
+        left:0;
+        display:block;
+        width:30px;
+        height:30px;
+    }
+    .manage-detail .img-info i.icon-fei{
+        background: url('static/img/icon/icon-detail.png')no-repeat 0px -38px;
+    }
+    .manage-detail .img-info i.icon-biao{
+        background: url('static/img/icon/icon-detail.png')no-repeat;
+    }
+    .manage-detail .info-text{
+        overflow: hidden;
+    }
+    .manage-detail .info-text p{
+        margin-bottom:25px;
+        font-size: 14px;
+        color:#333;
+        overflow: hidden;
+        white-space: nowrap;
+    }
+    .manage-detail .panel-body{
+        padding:0;
+    }
+    .manage-detail .panel-body table{
+        padding:0;
+        margin:0;
+    }
+    .manage-detail .panel-body table tr{
+        text-align: center;
+    }
+    .manage-detail .panel-body table tr th{
+        background: #ececec;
+        color:#333;
+        font-size: 12px;
+        text-align: center;
+        font-weight: normal;
+        padding:14px;
+        border-right:1px solid #999999;
+    }
+    .manage-detail .panel-body table tr th:last-child{
+        border:none;
+    }
+    .manage-detail .panel-body table tr td{
+        color:#666;
+        font-size: 14px;
+        padding:14px;
+        vertical-align: middle!important;
+        border-right:1px solid #cbcbcb;
+        border-top:1px solid #cbcbcb;
+    }
+    .manage-detail .panel-body table tr td:last-child{
+        border-right:none;
+    }
+    #toast-container {
+        top: auto;
+        bottom: 40px;
+    }
+
+</style>

+ 19 - 0
src/test/java/com/uas/platform/b2c/hulh/simple/StringTest.java

@@ -0,0 +1,19 @@
+package com.uas.platform.b2c.hulh.simple;
+
+import org.junit.Test;
+
+/**
+ * Created by hulh on 2017/12/12.
+ */
+public class StringTest {
+
+    @Test
+    public void testSplit(){
+        String str = "-1-2-3-4-5-6-7-8-9-12-";
+        String[] strings = str.split("-");
+        System.out.println(strings.length);
+        for (String s : strings){
+            System.out.print(s + " ");
+        }
+    }
+}