Quellcode durchsuchen

Merge branch 'dev' of 113.31.163.91:quanshu/mp-server into dev

dai xiaodan vor 3 Jahren
Ursprung
Commit
cb95c1b6d0
100 geänderte Dateien mit 6020 neuen und 763 gelöschten Zeilen
  1. 10 0
      mp-admin/src/main/java/com/qs/mp/handler/auth/SignInterceptor.java
  2. 0 10
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/AreaMgrController.java
  3. 88 27
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/ChannelMgrController.java
  4. 384 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/ChannelOrderMgrController.java
  5. 107 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/ChannelWithdrawMgrController.java
  6. 40 26
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/CouponMgrController.java
  7. 135 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/ExchangeBannerMgrController.java
  8. 164 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/GoodsCategoryMgrController.java
  9. 321 257
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/GoodsMgrController.java
  10. 163 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/GoodsTagMgrController.java
  11. 640 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/IndexMgrController.java
  12. 152 23
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/SaleSiteMgrController.java
  13. 182 21
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/TicketBoxMgrController.java
  14. 248 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/UserDeliverOrderMgrController.java
  15. 7 11
      mp-admin/src/main/java/com/qs/mp/web/controller/api/callback/PayCallBackController.java
  16. 136 30
      mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/ChannelController.java
  17. 165 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/ChannelCouponVerifyController.java
  18. 5 1
      mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/ChannelInviteController.java
  19. 24 2
      mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/ChannelMoneyController.java
  20. 24 7
      mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/ChannelWithdrawController.java
  21. 0 10
      mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/mall/ChannelCartController.java
  22. 61 18
      mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/mall/ChannelOrderController.java
  23. 0 10
      mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/mall/ChannelTicketController.java
  24. 0 10
      mp-admin/src/main/java/com/qs/mp/web/controller/api/common/AreaQueryController.java
  25. 40 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/common/DeliveryCompanyController.java
  26. 124 22
      mp-admin/src/main/java/com/qs/mp/web/controller/api/common/UserController.java
  27. 0 10
      mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserAddrController.java
  28. 78 12
      mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserDeliverOrderController.java
  29. 197 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserExchangeController.java
  30. 17 20
      mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserMineController.java
  31. 54 0
      mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserShareController.java
  32. 159 41
      mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserTicketController.java
  33. 62 35
      mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserTicketOrderController.java
  34. 94 7
      mp-admin/src/main/java/com/qs/mp/web/controller/common/FileUploadController.java
  35. 1 1
      mp-admin/src/main/java/com/qs/mp/web/controller/common/WxServerController.java
  36. 17 0
      mp-admin/src/main/java/com/qs/mp/web/controller/system/SysLoginController.java
  37. 29 8
      mp-admin/src/main/resources/application-8100.yml
  38. 30 9
      mp-admin/src/main/resources/application-8200.yml
  39. 14 1
      mp-admin/src/main/resources/application-dev.yml
  40. 19 7
      mp-admin/src/main/resources/application-test.yml
  41. 2 4
      mp-admin/src/main/resources/application.yml
  42. 2 2
      mp-admin/src/main/resources/logback-8100.xml
  43. 2 2
      mp-admin/src/main/resources/logback-8200.xml
  44. 2 2
      mp-admin/src/main/resources/logback-spring.xml
  45. 42 0
      mp-admin/src/test/java/com/qs/mp/api/UserDeliverOrderMgrControllerTest.java
  46. 1 1
      mp-admin/src/test/java/com/qs/mp/common/BaseControllerTest.java
  47. 50 1
      mp-admin/src/test/java/com/qs/mp/service/ServiceImplTest.java
  48. 51 0
      mp-common/src/main/java/com/qs/mp/common/enums/BannerLocationEnum.java
  49. 4 2
      mp-common/src/main/java/com/qs/mp/common/enums/ChannelMoneyEnum.java
  50. 4 0
      mp-common/src/main/java/com/qs/mp/common/enums/ChannelOrderStatusEnum.java
  51. 54 0
      mp-common/src/main/java/com/qs/mp/common/enums/ChannelWithdrawStatusEnum.java
  52. 1 1
      mp-common/src/main/java/com/qs/mp/common/enums/CoinLogTypeEnum.java
  53. 43 0
      mp-common/src/main/java/com/qs/mp/common/enums/CommStatusEnum.java
  54. 40 0
      mp-common/src/main/java/com/qs/mp/common/enums/CouponSettleStatusEnum.java
  55. 6 1
      mp-common/src/main/java/com/qs/mp/common/enums/CouponUseAreaEnum.java
  56. 7 2
      mp-common/src/main/java/com/qs/mp/common/enums/DeliverOrderStatusEnum.java
  57. 6 0
      mp-common/src/main/java/com/qs/mp/common/enums/ErrorCodeEnum.java
  58. 9 0
      mp-common/src/main/java/com/qs/mp/common/enums/GoodsStatusEnum.java
  59. 41 0
      mp-common/src/main/java/com/qs/mp/common/enums/PayOrderStatusEnum.java
  60. 31 0
      mp-common/src/main/java/com/qs/mp/common/enums/PicHandlerTypeEnum.java
  61. 3 0
      mp-common/src/main/java/com/qs/mp/common/enums/SiteTypeEnum.java
  62. 4 0
      mp-common/src/main/java/com/qs/mp/common/enums/TicketTypeEnum.java
  63. 3 0
      mp-common/src/main/java/com/qs/mp/common/enums/UserCouponStatusEnum.java
  64. 2 2
      mp-common/src/main/java/com/qs/mp/common/enums/UserIdentityEnum.java
  65. 25 0
      mp-common/src/main/java/com/qs/mp/common/filter/ThumbnailsImgFilter.java
  66. 6 9
      mp-common/src/main/java/com/qs/mp/common/jsms/JSMSUtils.java
  67. 4 2
      mp-common/src/main/java/com/qs/mp/common/pulsar/PulsarClientService.java
  68. 34 8
      mp-common/src/main/java/com/qs/mp/common/qcloud/QcloudFileUtils.java
  69. 336 0
      mp-common/src/main/java/com/qs/mp/common/utils/DateUtils.java
  70. 20 10
      mp-common/src/main/java/com/qs/mp/common/utils/WebhookService.java
  71. 2 1
      mp-common/src/main/java/com/qs/mp/common/utils/http/HttpUtils.java
  72. 24 12
      mp-framework/src/main/java/com/qs/mp/framework/config/SecurityConfig.java
  73. 9 1
      mp-framework/src/main/java/com/qs/mp/framework/security/filter/JwtAuthenticationTokenFilter.java
  74. 2 2
      mp-framework/src/main/java/com/qs/mp/framework/security/handle/AuthenticationEntryPointImpl.java
  75. 8 3
      mp-framework/src/main/java/com/qs/mp/framework/web/exception/GlobalExceptionHandler.java
  76. 2 2
      mp-quartz/pom.xml
  77. 58 0
      mp-quartz/src/main/java/com/qs/mp/quartz/task/ChannelCommTask.java
  78. 53 0
      mp-quartz/src/main/java/com/qs/mp/quartz/task/ChannelOrderTask.java
  79. 167 0
      mp-quartz/src/main/java/com/qs/mp/quartz/task/CosTask.java
  80. 254 0
      mp-quartz/src/main/java/com/qs/mp/quartz/task/DayStatTask.java
  81. 167 0
      mp-quartz/src/main/java/com/qs/mp/quartz/task/TicketBoxTask.java
  82. 77 0
      mp-quartz/src/main/java/com/qs/mp/quartz/task/TicketOrderTask.java
  83. 4 4
      mp-service/src/main/java/com/qs/mp/admin/domain/Coupon.java
  84. 1 1
      mp-service/src/main/java/com/qs/mp/admin/domain/CouponTicket.java
  85. 87 0
      mp-service/src/main/java/com/qs/mp/admin/domain/ExchangeBanner.java
  86. 17 4
      mp-service/src/main/java/com/qs/mp/admin/domain/Goods.java
  87. 13 1
      mp-service/src/main/java/com/qs/mp/admin/domain/GoodsCategory.java
  88. 3 3
      mp-service/src/main/java/com/qs/mp/admin/domain/GoodsSku.java
  89. 59 0
      mp-service/src/main/java/com/qs/mp/admin/domain/GoodsTag.java
  90. 11 23
      mp-service/src/main/java/com/qs/mp/admin/domain/GoodsTagRel.java
  91. 4 4
      mp-service/src/main/java/com/qs/mp/admin/domain/Ticket.java
  92. 28 0
      mp-service/src/main/java/com/qs/mp/admin/domain/param/ChannelOrderPkgParam.java
  93. 46 0
      mp-service/src/main/java/com/qs/mp/admin/domain/param/ChannelOrderQueryParam.java
  94. 49 0
      mp-service/src/main/java/com/qs/mp/admin/domain/param/ChannelOrderShipParam.java
  95. 0 11
      mp-service/src/main/java/com/qs/mp/admin/domain/param/CouponParam.java
  96. 7 4
      mp-service/src/main/java/com/qs/mp/admin/domain/param/GoodsParam.java
  97. 13 1
      mp-service/src/main/java/com/qs/mp/admin/domain/param/GoodsQueryParam.java
  98. 24 0
      mp-service/src/main/java/com/qs/mp/admin/domain/param/IndexQueryParam.java
  99. 2 1
      mp-service/src/main/java/com/qs/mp/admin/domain/param/TicketBoxCreateParam.java
  100. 3 0
      mp-service/src/main/java/com/qs/mp/admin/domain/param/TicketParam.java

+ 10 - 0
mp-admin/src/main/java/com/qs/mp/handler/auth/SignInterceptor.java

@@ -1,6 +1,7 @@
 package com.qs.mp.handler.auth;
 
 import com.alibaba.fastjson.JSONObject;
+import com.qs.mp.common.enums.ServerEnvEnum;
 import com.qs.mp.common.utils.LogUtil;
 import com.qs.mp.common.utils.http.HttpHelper;
 import com.qs.mp.core.domain.LoginUser;
@@ -13,6 +14,7 @@ import org.apache.commons.lang.StringUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
 import org.springframework.lang.Nullable;
 import org.springframework.stereotype.Component;
 import org.springframework.web.method.HandlerMethod;
@@ -36,6 +38,11 @@ public class SignInterceptor implements HandlerInterceptor {
     @Autowired
     private HostHolder hostHolder;
 
+    @Value(value = "${server.env}")
+    private String env;
+
+
+
 
     @Override
     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
@@ -43,6 +50,9 @@ public class SignInterceptor implements HandlerInterceptor {
         if (!(handler instanceof HandlerMethod)) {
             return true;
         }
+        if (ServerEnvEnum.DEV.getCode().equals(env)) {
+            return true;
+        }
         String method = request.getMethod();
         if ("post".equalsIgnoreCase(method)) {
             // 最后用RequestBody中获取token

+ 0 - 10
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/AreaMgrController.java

@@ -1,13 +1,3 @@
-/*
- * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
- *
- * https://www.mall4j.com/
- *
- * 未经允许,不可做商业用途!
- *
- * 版权所有,侵权必究!
- */
-
 package com.qs.mp.web.controller.api.admin;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

+ 88 - 27
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/ChannelMgrController.java

@@ -4,20 +4,21 @@ import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.qs.mp.channel.domain.Channel;
-import com.qs.mp.channel.domain.ChannelOrder;
 import com.qs.mp.channel.domain.param.ChannelParam;
 import com.qs.mp.channel.domain.vo.ChannelOperDataVO;
 import com.qs.mp.channel.domain.vo.ChannelVO;
 import com.qs.mp.channel.service.IChannelOrderService;
 import com.qs.mp.channel.service.IChannelService;
 import com.qs.mp.channel.service.IChannelUserRelService;
+import com.qs.mp.common.annotation.Log;
 import com.qs.mp.common.constant.UserConstants;
 import com.qs.mp.common.core.domain.AjaxResult;
 import com.qs.mp.common.core.page.TableDataInfo;
+import com.qs.mp.common.enums.BusinessType;
 import com.qs.mp.common.enums.ChannelRoleEnum;
 import com.qs.mp.common.enums.ErrorCodeEnum;
-import com.qs.mp.system.domain.SysUser;
 import com.qs.mp.system.service.ISysUserService;
+import com.qs.mp.user.service.IUserTicketOrderService;
 import com.qs.mp.web.controller.common.BaseApiController;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -27,10 +28,11 @@ import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 import org.apache.commons.lang3.StringUtils;
-import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -51,16 +53,19 @@ public class ChannelMgrController extends BaseApiController {
 
 	@Autowired
 	private IChannelService channelService;
-	
+
 	@Autowired
 	private IChannelUserRelService channelUserRelService;
-	
+
 	@Autowired
 	private IChannelOrderService channelOrderService;
 	
+	@Autowired
+	private IUserTicketOrderService userTicketOrderService;
+
 	@Autowired
 	private ISysUserService userService;
-	
+
 	@Autowired
 	private MapperFacade mapperFacade;
 
@@ -70,6 +75,7 @@ public class ChannelMgrController extends BaseApiController {
 	 * @return
 	 */
 	@PostMapping("/tree")
+	@PreAuthorize("@ss.hasPermi('business:channel:list')")
 	public AjaxResult treeChannel(@RequestBody Channel channel) {
 		List<ChannelVO> list = new ArrayList<ChannelVO>();
 		QueryWrapper<Channel> queryWrapper = new QueryWrapper<>();
@@ -77,7 +83,7 @@ public class ChannelMgrController extends BaseApiController {
 		queryWrapper.gt("t1.level", 0);
 		queryWrapper.likeRight(null != channel && StringUtils.isNotBlank(channel.getMobile()), "t1.mobile", channel.getMobile());
 		queryWrapper.likeRight(null != channel && StringUtils.isNotBlank(channel.getName()), "t1.name", channel.getName());
-		queryWrapper.orderByAsc("t1.channel_id");
+		queryWrapper.orderByAsc("t1.level").orderByDesc("t1.channel_id");
 		queryWrapper.last("limit 50");
 		list = channelService.selectChannelVoList(queryWrapper);
 		if(null != list && list.size() > 0) {
@@ -97,31 +103,33 @@ public class ChannelMgrController extends BaseApiController {
 		}
 		return AjaxResult.success(list);
 	}
-	
-	
+
+
 	/**
 	 * 查询所有渠道列表
 	 *
 	 * @return
 	 */
 	@PostMapping("/listAll")
+	@PreAuthorize("@ss.hasPermi('business:channel:list')")
 	public AjaxResult listAllChannel() {
 		List<Channel> list = new ArrayList<Channel>();
 		LambdaQueryWrapper<Channel> queryWrapper = new LambdaQueryWrapper<Channel>();
 		queryWrapper.gt(Channel::getLevel, 0);
-		queryWrapper.orderByAsc(Channel::getCreatedTime);
+		queryWrapper.orderByAsc(Channel::getLevel).orderByDesc(Channel::getChannelId);
 		list = channelService.list(queryWrapper);
 		return AjaxResult.success(list);
 	}
-	
-	
+
+
 	/**
 	 * 获取我的下级渠道列表信息,支持翻页
 	 *
 	 * @return
 	 */
 	@PostMapping("/list")
-	public TableDataInfo listChannel(@RequestBody Channel channel) {
+	@PreAuthorize("@ss.hasPermi('business:channel:list')")
+	public TableDataInfo listChannel(@RequestBody ChannelVO channel) {
 		List<ChannelVO> list = new ArrayList<ChannelVO>();
 		startPage();
 		QueryWrapper<Channel> queryWrapper = new QueryWrapper<>();
@@ -129,12 +137,14 @@ public class ChannelMgrController extends BaseApiController {
 			queryWrapper.eq("t1.parent_id", channel.getParentId());
 		}
 		queryWrapper.gt("t1.level", 0);
+		queryWrapper.eq(null != channel && null != channel.getLevel(),"t1.level", channel.getLevel());
 		queryWrapper.likeRight(null != channel && StringUtils.isNotBlank(channel.getMobile()), "t1.mobile", channel.getMobile());
 		queryWrapper.likeRight(null != channel && StringUtils.isNotBlank(channel.getName()), "t1.name", channel.getName());
+		queryWrapper.likeRight(null != channel && StringUtils.isNotBlank(channel.getParentName()), "t2.name", channel.getParentName());
 		queryWrapper.eq(null != channel && null != channel.getProvinceId(), "t1.province_id", channel.getProvinceId());
 		queryWrapper.eq(null != channel && null != channel.getCityId(), "t1.city_id", channel.getCityId());
 		queryWrapper.eq(null != channel && null != channel.getAreaId(), "t1.area_id", channel.getAreaId());
-		queryWrapper.orderByAsc("t1.channel_id");
+		queryWrapper.orderByAsc("t1.level").orderByDesc("t1.channel_id");
 		list = channelService.selectChannelVoList(queryWrapper);
 		if(null != list && list.size() > 0) {
 			for(ChannelVO channelVO : list) {
@@ -146,20 +156,27 @@ public class ChannelMgrController extends BaseApiController {
 					// 查询用户信息
 					// SysUser sysUser = userService.selectUserById(channelVO.getUserId());
 					// channelVO.setSysUser(sysUser);
+					// 查询子渠道数量
+					int childCnt = channelService.count(
+							new LambdaQueryWrapper<Channel>().eq(Channel::getParentId, channelVO.getChannelId())
+							.gt(Channel::getLevel, 0));
+					channelVO.setChildCnt(childCnt);
  				}
 			}
 		}
 		return getDataTable(list);
 	}
-	
-	
+
+
 	/**
 	 * 渠道管理新增一级渠道信息
 	 * @param
 	 * @return
 	 */
+	@Log(title = "新增渠道", businessType = BusinessType.INSERT)
 	@ApiOperation(value = "新增子渠道信息", notes = "渠道端新增子渠道")
 	@PostMapping("/create")
+	@PreAuthorize("@ss.hasPermi('business:channel:add')")
 	public AjaxResult channelCreate(@Validated @RequestBody ChannelParam channelParam) {
 		if (channelParam.getChannelId() != null && channelParam.getChannelId() != 0) {
 			return AjaxResult.error("该渠道已存在");
@@ -182,7 +199,7 @@ public class ChannelMgrController extends BaseApiController {
 //		if(null != channel.getParentId() && channel.getParentId() != 0) {
 //			Channel parentChannel = channelService.getById(channel.getParentId());
 //			if(null != parentChannel) {
-//				 if(null != parentChannel.getCommRate() 
+//				 if(null != parentChannel.getCommRate()
 //						 && channel.getCommRate().compareTo(parentChannel.getCommRate()) > 0) {
 //					 return AjaxResult.error("佣金比例不能高于父渠道的佣金比例");
 //				 }
@@ -204,7 +221,7 @@ public class ChannelMgrController extends BaseApiController {
 		} catch (Exception e) {
 			return AjaxResult.error("渠道'" + channel.getName() + "'新增失败" + e.getMessage());
 		}
-		
+
 		return AjaxResult.success("渠道'" + channel.getName() + "'新增成功");
 	}
 
@@ -213,8 +230,10 @@ public class ChannelMgrController extends BaseApiController {
 	 * @param
 	 * @return
 	 */
+	@Log(title = "修改渠道", businessType = BusinessType.UPDATE)
 	@ApiOperation(value = "编辑子渠道信息", notes = "渠道端编辑子渠道")
 	@PostMapping("/update")
+	@PreAuthorize("@ss.hasPermi('business:channel:edit')")
 	public AjaxResult channelUpdate(@Validated @RequestBody ChannelParam channelParam) {
 		if (null == channelParam || null == channelParam.getChannelId()) {
 			return error(ErrorCodeEnum.ERROR_CODE_1001);
@@ -237,6 +256,7 @@ public class ChannelMgrController extends BaseApiController {
 		}
 		boolean mobileChange = false;  // 手机号码是否有变更
 		if(!channel.getMobile().equals(oldChannel.getMobile())) {
+			
 			int mobileCount = channelService.count(
 			        new LambdaQueryWrapper<Channel>().eq(Channel::getMobile, channel.getMobile()));
 			if(mobileCount > 0) {
@@ -250,7 +270,7 @@ public class ChannelMgrController extends BaseApiController {
 		// 3.校验佣金比例,不能高于其父渠道的佣金比例,不能低于其子渠道的最大佣金比例
 //		Channel parentChannel = channelService.getById(oldChannel.getParentId());
 //		if(null != parentChannel) {
-//			 if(null != parentChannel.getCommRate() 
+//			 if(null != parentChannel.getCommRate()
 //					 && channel.getCommRate().compareTo(parentChannel.getCommRate()) > 0) {
 //				 return AjaxResult.error("佣金比例不能高于父渠道的佣金比例");
 //			 }
@@ -271,21 +291,24 @@ public class ChannelMgrController extends BaseApiController {
 			}
 		}
 		try {
+			channel.setUserId(oldChannel.getUserId());
 			channelService.updateChannel(channel, mobileChange);
 		} catch (Exception e) {
 			return AjaxResult.error(e.getMessage());
 		}
 		return AjaxResult.success("渠道'" + channel.getName() + "'编辑成功");
 	}
-	
-	
+
+
 	/**
 	 * 停用、启用渠道
 	 * @param
 	 * @return
 	 */
+	@Log(title = "启停渠道", businessType = BusinessType.UPDATE)
 	@ApiOperation(value = "停用、启用渠道信息", notes = "渠道管理编辑子渠道")
 	@PostMapping("/status")
+	@PreAuthorize("@ss.hasPermi('business:channel:edit')")
 	public AjaxResult channelStatus(@RequestBody JSONObject jsonObject) {
 		String channelId = jsonObject.containsKey("channelId")?jsonObject.get("channelId").toString():"";
 		String status = jsonObject.containsKey("status")?jsonObject.get("status").toString():"";
@@ -300,8 +323,8 @@ public class ChannelMgrController extends BaseApiController {
 		}
 		return AjaxResult.success("操作成功");
 	}
-	
-	
+
+
 	/**
 	 * 查询渠道详情
 	 * @param
@@ -309,6 +332,7 @@ public class ChannelMgrController extends BaseApiController {
 	 */
 	@ApiOperation(value = "查询渠道详情信息", notes = "渠道管理编辑子渠道查询渠道详情")
 	@PostMapping("/detail")
+	@PreAuthorize("@ss.hasPermi('business:channel:query')")
 	public AjaxResult getChannelDetail(@RequestBody JSONObject jsonObject) {
 		String channelId = (null != jsonObject && jsonObject.containsKey("channelId"))?jsonObject.getString("channelId"):"";
 		if (StringUtils.isBlank(channelId)) {
@@ -323,15 +347,52 @@ public class ChannelMgrController extends BaseApiController {
 			int userCnt = channelUserRelService.getChannelTotalUserCnt(channelVO.getChannelNo());
 			channelVO.setSiteCnt(siteCnt);
 			channelVO.setUserCnt(userCnt);
+			channelVO.setParentsName(getParentsName(channelVO.getChannelNo()));
 		}
 	    // 查询渠道销售额、佣金收入、订单数等
 	    ChannelOperDataVO channelOperDataVO = channelService.getChannelTotalOperData(channelVO.getChannelNo());
-		LambdaQueryWrapper<ChannelOrder> queryWrapper = new LambdaQueryWrapper<ChannelOrder>();
-		queryWrapper.eq(ChannelOrder::getChannelId, channelId);
-		int orderCnt = channelOrderService.count(queryWrapper);
-		channelOperDataVO.setOrderCnt(orderCnt);
+		// LambdaQueryWrapper<ChannelOrder> queryWrapper = new LambdaQueryWrapper<ChannelOrder>();
+		//queryWrapper.eq(ChannelOrder::getChannelId, channelId);
+		//int orderCnt = channelOrderService.count(queryWrapper);
+		//channelOperDataVO.setOrderCnt(orderCnt);
+		
+		// 盲票销量
+		int ticketSaleCnt = userTicketOrderService.getChannelTotalTicketNumCnt(channelVO.getChannelNo());
+		channelOperDataVO.setTicketSaleCnt(ticketSaleCnt);
 	    channelVO.setOperData(channelOperDataVO);
 		return AjaxResult.success(channelVO);
 	}
 	
+	
+	// 获取上级渠道迭代
+	private String getParentsName(String channelNo) {
+		if(StringUtils.isNotBlank(channelNo)) {
+			String[] noArray = channelNo.split("\\.");
+			if(null != noArray && noArray.length > 0) {
+				List<String> noList = new ArrayList<String>();
+				String parentNo = "";
+				for (int i = 0; i < noArray.length; i++) {
+					if(null != noArray[i] && StringUtils.isNotBlank(noArray[i])) {
+						parentNo += (i>0?".":"")+noArray[i];
+						if(StringUtils.isNotBlank(parentNo) && !parentNo.equals(channelNo)) {
+							noList.add(parentNo);
+						}
+					}
+				}
+				if(noList.size() > 0 ) {
+					LambdaQueryWrapper<Channel> queryWrapper = new LambdaQueryWrapper<Channel>();
+					queryWrapper.gt(Channel::getLevel, 0);
+					queryWrapper.in(Channel::getChannelNo,noList);
+					queryWrapper.orderByAsc(Channel::getLevel);
+					List<Channel> list = channelService.list(queryWrapper);
+					if(null != list && list.size() >0) {
+						String names = list.stream().map(Channel::getName).collect(Collectors.joining(" > "));
+						return names;
+					}
+				}
+			}
+		}
+		return "";
+	}
+
 }

+ 384 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/ChannelOrderMgrController.java

@@ -0,0 +1,384 @@
+package com.qs.mp.web.controller.api.admin;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.qs.mp.admin.domain.TicketPackage;
+import com.qs.mp.admin.domain.param.ChannelOrderPkgParam;
+import com.qs.mp.admin.domain.param.ChannelOrderQueryParam;
+import com.qs.mp.admin.domain.param.ChannelOrderShipParam;
+import com.qs.mp.admin.domain.param.UserDeliverOrderQueryParam;
+import com.qs.mp.admin.domain.vo.TicketPackageVO;
+import com.qs.mp.admin.service.ITicketPackageService;
+import com.qs.mp.channel.domain.Channel;
+import com.qs.mp.channel.domain.ChannelOrder;
+import com.qs.mp.channel.domain.ChannelOrderDetail;
+import com.qs.mp.channel.domain.ChannelOrderItem;
+import com.qs.mp.channel.domain.excel.ChannelOrderExcel;
+import com.qs.mp.channel.domain.vo.ChannelOrderInfoVO;
+import com.qs.mp.channel.domain.vo.ChannelOrderItemVO;
+import com.qs.mp.channel.domain.vo.ChannelOrderVO;
+import com.qs.mp.channel.domain.vo.ChannelVO;
+import com.qs.mp.channel.service.IChannelOrderDetailService;
+import com.qs.mp.channel.service.IChannelOrderItemService;
+import com.qs.mp.channel.service.IChannelOrderService;
+import com.qs.mp.channel.service.IChannelService;
+import com.qs.mp.common.annotation.Log;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.core.page.TableDataInfo;
+import com.qs.mp.common.domain.DeliveryCompany;
+import com.qs.mp.common.enums.BusinessType;
+import com.qs.mp.common.enums.ErrorCodeEnum;
+import com.qs.mp.common.enums.TicketPkgStatusEnum;
+import com.qs.mp.common.service.IDeliveryCompanyService;
+import com.qs.mp.user.domain.UserDeliverOrder;
+import com.qs.mp.user.domain.UserDeliverOrderItem;
+import com.qs.mp.user.domain.excel.DeliverOrderExcel;
+import com.qs.mp.user.domain.vo.UserDeliverOrderItemVO;
+import com.qs.mp.user.domain.vo.UserDeliverOrderVO;
+import com.qs.mp.utils.ExcelUtil;
+import com.qs.mp.web.controller.common.BaseApiController;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import ma.glasnost.orika.MapperFacade;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@RestController
+@RequestMapping("/api/v1/mp/admin/channel/order")
+@Api(tags = "渠道订单管理接口")
+@AllArgsConstructor
+public class ChannelOrderMgrController extends BaseApiController {
+
+  @Autowired
+  private IChannelOrderService channelOrderService;
+
+  @Autowired
+  private IChannelOrderItemService channelOrderItemService;
+
+  @Autowired
+  private IChannelOrderDetailService channelOrderDetailService;
+
+  @Autowired
+  private IChannelService channelService;
+
+  @Autowired
+  private IDeliveryCompanyService deliveryCompanyService;
+
+  @Autowired
+  private ITicketPackageService ticketPackageService;
+
+  @Autowired
+  private MapperFacade mapperFacade;
+
+  /**
+   * 订单列表
+   */
+  @PostMapping("/list")
+  @ApiOperation(value = "订单列表" , notes = "获取所有订单信息")
+  @PreAuthorize("@ss.hasPermi('order:channel:list')")
+  public TableDataInfo list(@RequestBody ChannelOrderQueryParam queryParam) {
+    startPage();
+    QueryWrapper<ChannelOrder> queryWrapper = new QueryWrapper<ChannelOrder>();
+    queryWrapper.eq(null != queryParam && null != queryParam.getChannelId(), "t1.channel_id" ,queryParam.getChannelId());
+    queryWrapper.eq(null != queryParam && StringUtils.isNotBlank(queryParam.getOrderId()), "t1.order_id" ,queryParam.getOrderId());
+	queryWrapper.eq(null != queryParam && null != queryParam.getStatus(), "t1.`status`" ,queryParam.getStatus());
+	queryWrapper.ge(null != queryParam && null != queryParam.getStartTime(),  "t1.created_time", queryParam.getStartTime());
+	queryWrapper.le(null != queryParam && null != queryParam.getEndTime(), "t1.created_time", queryParam.getEndTime());
+	queryWrapper.like(null != queryParam && StringUtils.isNotBlank(queryParam.getTitle()), "t1.title", queryParam.getTitle());
+    queryWrapper.orderByDesc("t1.order_id");
+    List<ChannelOrderVO> channelOrderVOList = channelOrderService.selectChannelOrderVoList(queryWrapper);
+    for (ChannelOrderVO channelOrderVO : channelOrderVOList) {
+    	List<ChannelOrderItem> itemList = channelOrderItemService.list(new LambdaQueryWrapper<ChannelOrderItem>()
+   	          .eq(ChannelOrderItem::getOrderId, channelOrderVO.getOrderId()));
+
+   	    List<ChannelOrderItemVO> itemVOList = mapperFacade.mapAsList(itemList, ChannelOrderItemVO.class);
+        channelOrderVO.setItems(itemVOList);
+    }
+    return getDataTable(channelOrderVOList);
+  }
+
+  /**
+   * 订单详情
+   */
+  @PostMapping("/detail")
+  @ApiOperation(value = "订单详情" , notes = "在订单列表页面查看详情")
+  @PreAuthorize("@ss.hasPermi('order:channel:query')")
+  public AjaxResult query(@RequestBody ChannelOrder order) {
+    if(null == order || StringUtils.isBlank(order.getOrderId())) {
+    	return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    ChannelOrder channelOrder = channelOrderService.getById(order.getOrderId());
+    if(null == channelOrder || StringUtils.isBlank(channelOrder.getOrderId())) {
+    	return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    ChannelOrderInfoVO channelOrderInfoVO = mapperFacade.map(channelOrder, ChannelOrderInfoVO.class);
+
+    if(null != channelOrderInfoVO && null != channelOrderInfoVO.getChannelId()) {
+    	ChannelVO channel = channelService.getChannelVoById(channelOrderInfoVO.getChannelId());
+    	channelOrderInfoVO.setChannel(channel);
+    }
+    if(null != channelOrderInfoVO && null != channelOrderInfoVO.getDeliveryId()) {
+    	DeliveryCompany deliveryCompany = deliveryCompanyService.getById(channelOrderInfoVO.getDeliveryId());
+    	channelOrderInfoVO.setDeliveryCompany(deliveryCompany);
+    }
+    List<ChannelOrderItem> itemList = channelOrderItemService.list(new LambdaQueryWrapper<ChannelOrderItem>()
+	          .eq(ChannelOrderItem::getOrderId, channelOrderInfoVO.getOrderId()));
+
+	List<ChannelOrderItemVO> itemVOList = mapperFacade.mapAsList(itemList, ChannelOrderItemVO.class);
+	if(null != itemVOList && itemVOList.size() > 0) {
+		for(ChannelOrderItemVO itemVO : itemVOList) {
+			if(null != itemVO && StringUtils.isNotBlank(itemVO.getBoxId())
+					&& StringUtils.isNotBlank(itemVO.getOrderId())) {
+				LambdaQueryWrapper<ChannelOrderDetail> detailQueryWrapper = new LambdaQueryWrapper<ChannelOrderDetail>();
+				detailQueryWrapper.eq(ChannelOrderDetail::getOrderId, itemVO.getOrderId());
+				detailQueryWrapper.eq(ChannelOrderDetail::getBoxId, itemVO.getBoxId());
+				List<ChannelOrderDetail> detailList = channelOrderDetailService.list(detailQueryWrapper);
+				itemVO.setDetailList(detailList);
+			}
+		}
+	}
+	channelOrderInfoVO.setItems(itemVOList);
+    return AjaxResult.success(channelOrderInfoVO);
+  }
+
+
+  /**
+   * 订单发货
+   */
+  @Log(title = "经销商订单发货", businessType = BusinessType.UPDATE)
+  @PostMapping("/ship")
+  @ApiOperation(value = "订单发货" , notes = "在订单发货页面提交")
+  @PreAuthorize("@ss.hasPermi('order:channel:ship')")
+  public AjaxResult ship(@RequestBody ChannelOrderShipParam shipParam) {
+		if(null == shipParam || StringUtils.isBlank(shipParam.getOrderId())) {
+			return error(ErrorCodeEnum.ERROR_CODE_1001);
+		}
+
+		ChannelOrder order  = channelOrderService.getById(shipParam.getOrderId());
+		if(null == order || StringUtils.isBlank(order.getOrderId())
+				|| null == order.getChannelId()) {
+			return error(ErrorCodeEnum.ERROR_CODE_1001);
+		}
+
+		if(null != shipParam && null != shipParam.getPkgIds()
+				&& shipParam.getPkgIds().size() > 0) {
+			ChannelOrder channelOrder = new ChannelOrder();
+			channelOrder.setOrderId(shipParam.getOrderId());
+			channelOrder.setChannelId(order.getChannelId());
+			channelOrder.setDeliveryId(shipParam.getDeliveryId());
+			channelOrder.setDeliveryFlowId(shipParam.getDeliveryFlowId());
+			channelOrder.setDeliveryTime(new Date());
+			boolean rtn = channelOrderService.channelOrderShip(channelOrder, shipParam.getPkgIds());
+			return rtn ? AjaxResult.success() : AjaxResult.error("发货失败");
+		}
+		return AjaxResult.error("发货失败");
+  }
+
+	/**
+	 * 订单发货单号修改
+	 */
+	@Log(title = "经销商订单发货单号修改", businessType = BusinessType.UPDATE)
+	@PostMapping("/ship/update")
+	@ApiOperation(value = "订单发货单号修改" , notes = "在订单发货页面提交")
+	@PreAuthorize("@ss.hasPermi('order:channel:ship')")
+	public AjaxResult updateShipInfo(@RequestBody ChannelOrderShipParam shipParam) {
+		if(null == shipParam || StringUtils.isBlank(shipParam.getOrderId())
+			|| null == shipParam.getDeliveryId() || StringUtils.isBlank(shipParam.getDeliveryFlowId())) {
+			return error(ErrorCodeEnum.ERROR_CODE_1001);
+		}
+
+		ChannelOrder order  = channelOrderService.getById(shipParam.getOrderId());
+		if(null == order || StringUtils.isBlank(order.getOrderId())
+				|| null == order.getChannelId()) {
+			return error(ErrorCodeEnum.ERROR_CODE_1001);
+		}
+
+		boolean rtn = channelOrderService.update(new LambdaUpdateWrapper<ChannelOrder>()
+				.set(ChannelOrder::getDeliveryId, shipParam.getDeliveryId())
+				.set(ChannelOrder::getDeliveryFlowId, shipParam.getDeliveryFlowId())
+				.eq(ChannelOrder::getOrderId, shipParam.getOrderId()));
+		return rtn ? AjaxResult.success() : AjaxResult.error("修改失败");
+
+	}
+
+	@PostMapping("/item/list")
+	@ApiOperation(value = "获取经销商订单盲票组列表", notes = "")
+	public AjaxResult list(@RequestBody ChannelOrder order) {
+		List<ChannelOrderItemVO> list = new ArrayList<ChannelOrderItemVO>();
+		if (null != order && StringUtils.isNotBlank(order.getOrderId())) {
+			QueryWrapper<ChannelOrderItem> queryWrapper = new QueryWrapper<ChannelOrderItem>();
+			queryWrapper.eq("t1.order_id", order.getOrderId());
+			list = channelOrderItemService.listChannelOrderItemVO(queryWrapper);
+		}
+		return AjaxResult.success(list);
+	}
+
+	@PostMapping("/ticket/pkg/list")
+	@ApiOperation(value = "经销商订单发货筛选盲票包列表", notes = "")
+	public AjaxResult list(@RequestBody ChannelOrderPkgParam orderPkgParam) {
+		List<TicketPackageVO> list = new ArrayList<TicketPackageVO>();
+		QueryWrapper<TicketPackage> queryWrapper = new QueryWrapper<TicketPackage>();
+		queryWrapper.eq("t1.`status`", TicketPkgStatusEnum.FOR_SALE); // 筛选待售
+		if (null != orderPkgParam && StringUtils.isNotBlank(orderPkgParam.getPkgNo())) {
+			queryWrapper.like("t1.pkg_no", orderPkgParam.getPkgNo());
+		}
+		if (null != orderPkgParam && StringUtils.isNotBlank(orderPkgParam.getBoxId())) {
+			queryWrapper.eq("t1.box_id", orderPkgParam.getBoxId());
+			list = ticketPackageService.listTicketPackageVO(queryWrapper);
+		} else {
+			if (null != orderPkgParam && StringUtils.isNotBlank(orderPkgParam.getOrderId())) {
+				// 查询订单明细
+				List<ChannelOrderItem> itemList = channelOrderItemService
+						.list(new LambdaQueryWrapper<ChannelOrderItem>().eq(ChannelOrderItem::getOrderId,
+								orderPkgParam.getOrderId()));
+				if (null != itemList && itemList.size() > 0) {
+					List<String> boxIds = new ArrayList<String>();
+					for (ChannelOrderItem item : itemList) {
+						if (null != item && StringUtils.isNotBlank(item.getBoxId())) {
+							boxIds.add(item.getBoxId());
+						}
+					}
+					if (null != boxIds && boxIds.size() > 0) {
+						queryWrapper.in("t1.box_id", boxIds);
+						list = ticketPackageService.listTicketPackageVO(queryWrapper);
+					}
+				}
+			}
+		}
+		return AjaxResult.success(list);
+	}
+	
+	
+	
+	@Log(title = "提货订单导出", businessType = BusinessType.EXPORT)
+	@PostMapping("/export")
+	@PreAuthorize("@ss.hasPermi('order:channel:export')")
+	public AjaxResult export(@RequestBody ChannelOrderQueryParam queryParam) {
+
+		List<ChannelOrderExcel> excelList = new ArrayList<ChannelOrderExcel>();
+		List<ChannelOrderVO> listAll = new ArrayList<ChannelOrderVO>();
+		// 首先查询要导出的数据总数
+		QueryWrapper<ChannelOrder> queryWrapper = new QueryWrapper<ChannelOrder>();
+	    queryWrapper.eq(null != queryParam && null != queryParam.getChannelId(), "t1.channel_id" ,queryParam.getChannelId());
+	    queryWrapper.eq(null != queryParam && StringUtils.isNotBlank(queryParam.getOrderId()), "t1.order_id" ,queryParam.getOrderId());
+		queryWrapper.eq(null != queryParam && null != queryParam.getStatus(), "t1.`status`" ,queryParam.getStatus());
+		queryWrapper.ge(null != queryParam && null != queryParam.getStartTime(),  "t1.created_time", queryParam.getStartTime());
+		queryWrapper.le(null != queryParam && null != queryParam.getEndTime(), "t1.created_time", queryParam.getEndTime());
+		queryWrapper.like(null != queryParam && StringUtils.isNotBlank(queryParam.getTitle()), "t1.title", queryParam.getTitle());
+	    queryWrapper.orderByDesc("t1.order_id");
+	    
+	    int totalSize = channelOrderService.selectChannelOrderCount(queryWrapper);
+		if (totalSize == 0) {
+			return AjaxResult.error("没有符合条件的经销商订单");
+		}
+	    
+		int pageSize = 2000;
+		if (totalSize > pageSize) {
+			int totalPage = totalSize % pageSize == 0 ? totalSize / pageSize : totalSize / pageSize + 1;
+			for (int i = 0; i < totalPage; i++) {
+				queryWrapper.last("limit " + (i * pageSize) + ", " + pageSize);
+			    List<ChannelOrderVO> channelOrderVOList = channelOrderService.selectChannelOrderVoList(queryWrapper);
+			    for (ChannelOrderVO channelOrderVO : channelOrderVOList) {
+			    	List<ChannelOrderItem> itemList = channelOrderItemService.list(new LambdaQueryWrapper<ChannelOrderItem>()
+			     	          .eq(ChannelOrderItem::getOrderId, channelOrderVO.getOrderId()));
+				  	List<ChannelOrderItemVO> itemVOList = mapperFacade.mapAsList(itemList, ChannelOrderItemVO.class);
+				  	if(null != itemVOList && itemVOList.size() > 0) {
+				  		for(ChannelOrderItemVO itemVO : itemVOList) {
+				  			if(null != itemVO && StringUtils.isNotBlank(itemVO.getBoxId())
+				  					&& StringUtils.isNotBlank(itemVO.getOrderId())) {
+				  				LambdaQueryWrapper<ChannelOrderDetail> detailQueryWrapper = new LambdaQueryWrapper<ChannelOrderDetail>();
+				  				detailQueryWrapper.eq(ChannelOrderDetail::getOrderId, itemVO.getOrderId());
+				  				detailQueryWrapper.eq(ChannelOrderDetail::getBoxId, itemVO.getBoxId());
+				  				List<ChannelOrderDetail> detailList = channelOrderDetailService.list(detailQueryWrapper);
+				  				itemVO.setDetailList(detailList);
+				  			}
+				  		}
+				  	}
+				  	channelOrderVO.setItems(itemVOList);
+			    }
+				if (null != channelOrderVOList && channelOrderVOList.size() > 0) {
+					listAll.addAll(channelOrderVOList);
+				}
+			}
+		} else {
+			listAll = channelOrderService.selectChannelOrderVoList(queryWrapper);
+		    for (ChannelOrderVO channelOrderVO : listAll) {
+		    	List<ChannelOrderItem> itemList = channelOrderItemService.list(new LambdaQueryWrapper<ChannelOrderItem>()
+		     	          .eq(ChannelOrderItem::getOrderId, channelOrderVO.getOrderId()));
+			  	List<ChannelOrderItemVO> itemVOList = mapperFacade.mapAsList(itemList, ChannelOrderItemVO.class);
+			  	if(null != itemVOList && itemVOList.size() > 0) {
+			  		for(ChannelOrderItemVO itemVO : itemVOList) {
+			  			if(null != itemVO && StringUtils.isNotBlank(itemVO.getBoxId())
+			  					&& StringUtils.isNotBlank(itemVO.getOrderId())) {
+			  				LambdaQueryWrapper<ChannelOrderDetail> detailQueryWrapper = new LambdaQueryWrapper<ChannelOrderDetail>();
+			  				detailQueryWrapper.eq(ChannelOrderDetail::getOrderId, itemVO.getOrderId());
+			  				detailQueryWrapper.eq(ChannelOrderDetail::getBoxId, itemVO.getBoxId());
+			  				List<ChannelOrderDetail> detailList = channelOrderDetailService.list(detailQueryWrapper);
+			  				itemVO.setDetailList(detailList);
+			  			}
+			  		}
+			  	}
+			  	channelOrderVO.setItems(itemVOList);
+		    }
+		}
+	    
+		if (null != listAll && listAll.size() > 0) {
+			// listAll.sort(Comparator.comparing(UserDeliverOrderVO::getOrderId));
+			for (ChannelOrderVO channelOrder : listAll) {
+				if (null != channelOrder && StringUtils.isNotBlank(channelOrder.getOrderId())
+						&& StringUtils.isNotBlank(channelOrder.getReceiver())
+						&& StringUtils.isNotBlank(channelOrder.getTel())
+						&& StringUtils.isNotBlank(channelOrder.getProvince())
+						&& StringUtils.isNotBlank(channelOrder.getCity())
+						&& StringUtils.isNotBlank(channelOrder.getArea())
+						&& StringUtils.isNotBlank(channelOrder.getAddress()) && null != channelOrder.getItems()
+						&& channelOrder.getItems().size() > 0) {
+					for (ChannelOrderItemVO channelOrderItem : channelOrder.getItems()) {
+						if (null != channelOrderItem) {
+							ChannelOrderExcel channelOrderExcel = new ChannelOrderExcel();
+							channelOrderExcel.setTitle(channelOrderItem.getTitle());
+							channelOrderExcel.setOrderNum(channelOrderItem.getOrderNum());
+							if(null != channelOrderItem.getDetailList() && channelOrderItem.getDetailList().size() > 0) {
+								StringBuffer buff = new StringBuffer();
+								for(ChannelOrderDetail orderDetail: channelOrderItem.getDetailList()) {
+									if(null != orderDetail && StringUtils.isNotBlank(orderDetail.getStartSn())
+											&& StringUtils.isNotBlank(orderDetail.getEndSn())) {
+										buff.append("("+orderDetail.getStartSn()+"-"+orderDetail.getEndSn()+")");
+									}
+								}
+								channelOrderExcel.setSnRrange(buff.toString());
+							}
+							channelOrderExcel.setCreatedTime(channelOrder.getCreatedTime());
+							channelOrderExcel.setItemStatus(channelOrder.getStatus().getValue() > 1 ? "已发货" : "未发货");
+							channelOrderExcel.setOrderId(channelOrder.getOrderId());
+							channelOrderExcel.setStatus(channelOrder.getStatus().getDesc());
+							channelOrderExcel.setChannelName(channelOrder.getChannelName());
+							channelOrderExcel.setParentName(channelOrder.getParentName());
+							channelOrderExcel.setReceiver(channelOrder.getReceiver());
+							channelOrderExcel.setTel(channelOrder.getTel());
+							String address = channelOrder.getProvince() + channelOrder.getCity()
+									+ channelOrder.getArea() + channelOrder.getAddress();
+							channelOrderExcel.setAddress(address);
+							excelList.add(channelOrderExcel);
+						}
+					}
+				}
+			}
+		}
+		ExcelUtil<ChannelOrderExcel> util = new ExcelUtil<ChannelOrderExcel>(ChannelOrderExcel.class);
+		return util.exportExcel(excelList, "经销商订单导出", false);
+	}
+}

+ 107 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/ChannelWithdrawMgrController.java

@@ -0,0 +1,107 @@
+package com.qs.mp.web.controller.api.admin;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qs.mp.channel.domain.ChannelOrder;
+import com.qs.mp.channel.domain.ChannelOrderItem;
+import com.qs.mp.channel.domain.ChannelWithdraw;
+import com.qs.mp.channel.domain.vo.ChannelOrderVO;
+import com.qs.mp.channel.domain.vo.ChannelWithdrawVO;
+import com.qs.mp.channel.service.IChannelOrderItemService;
+import com.qs.mp.channel.service.IChannelOrderService;
+import com.qs.mp.channel.service.IChannelWithdrawService;
+import com.qs.mp.common.annotation.Log;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.core.page.TableDataInfo;
+import com.qs.mp.common.core.redis.RedisCache;
+import com.qs.mp.common.enums.BusinessType;
+import com.qs.mp.common.enums.ChannelWithdrawStatusEnum;
+import com.qs.mp.common.enums.ErrorCodeEnum;
+import com.qs.mp.common.utils.DateUtils;
+import com.qs.mp.web.controller.common.BaseApiController;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import java.util.Date;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import ma.glasnost.orika.MapperFacade;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@RestController
+@RequestMapping("/api/v1/mp/admin/channel/withdraw")
+@Api(tags = "渠道提现申请管理接口")
+@AllArgsConstructor
+public class ChannelWithdrawMgrController extends BaseApiController {
+
+  @Autowired
+  private IChannelWithdrawService channelWithdrawService;
+
+  @Autowired
+  private MapperFacade mapperFacade;
+
+  /**
+   * 提现申请列表
+   */
+  @PostMapping("/list")
+  @ApiOperation(value = "提现申请列表" , notes = "获取所有提现信息")
+  @PreAuthorize("@ss.hasPermi('finance:withdraw:list')")
+  public TableDataInfo list(@RequestBody JSONObject param) {
+    Integer status = param.getInteger("status");
+    String name = param.getString("name");
+    Date startDay = param.getDate("startDay");
+    Date endDay = param.getDate("endDay");
+
+    startPage();
+    List<ChannelWithdrawVO> withdrawList = channelWithdrawService.listWithdrawVO(new QueryWrapper<ChannelWithdraw>()
+        .eq(null != status && status != 0, "t1.status", status)
+        .like(StringUtils.isNotBlank(name), "t2.name", name)
+        .ge(null != startDay, "t1.create_time", startDay)
+        .lt(null != endDay, "t1.create_time", endDay)
+        .orderByDesc("t1.create_time"));
+    return getDataTable(withdrawList);
+  }
+
+  /**
+   * 提现申请详情
+   */
+  @PostMapping("/detail")
+  @PreAuthorize("@ss.hasPermi('finance:withdraw:query')")
+  @ApiOperation(value = "申请详情" , notes = "在提现列表页面查看详情")
+  public AjaxResult query(@RequestBody JSONObject param) {
+    Long id = param.getLong("id");
+    if (null == id || 0 == id) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    List<ChannelWithdrawVO> withdrawList = channelWithdrawService.listWithdrawVO(new QueryWrapper<ChannelWithdraw>()
+        .eq("t1.id", id));
+    return AjaxResult.success(withdrawList.get(0));
+  }
+
+  /**
+   * 提现申请审核结果
+   */
+  @Log(title = "提现申请审核", businessType = BusinessType.UPDATE)
+  @PostMapping("/verify")
+  @ApiOperation(value = "申请审核" , notes = "在提现详情页面审核")
+  @PreAuthorize("@ss.hasPermi('finance:withdraw:verify')")
+  public AjaxResult verify(@RequestBody ChannelWithdraw withdraw) {
+    if (null == withdraw.getId() || null == withdraw.getStatus()) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    ChannelWithdraw channelWithdraw = channelWithdrawService.getById(withdraw.getId());
+    if (channelWithdraw.getStatus() != ChannelWithdrawStatusEnum.WITHDRAWING) {
+      return error("提现申请状态异常,不是提现中");
+    }
+    channelWithdrawService.verify(channelWithdraw, withdraw.getStatus(), withdraw.getVerifyContent());
+    return AjaxResult.success("操作成功");
+  }
+
+}

+ 40 - 26
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/CouponMgrController.java

@@ -20,9 +20,11 @@ import com.qs.mp.admin.service.ICouponTicketService;
 import com.qs.mp.admin.service.ITicketBoxService;
 import com.qs.mp.channel.domain.Channel;
 import com.qs.mp.channel.service.IChannelService;
+import com.qs.mp.common.annotation.Log;
 import com.qs.mp.common.constant.UserConstants;
 import com.qs.mp.common.core.domain.AjaxResult;
 import com.qs.mp.common.core.page.TableDataInfo;
+import com.qs.mp.common.enums.BusinessType;
 import com.qs.mp.common.enums.CouponStatusEnum;
 import com.qs.mp.common.enums.CouponUseAreaEnum;
 import com.qs.mp.common.enums.ErrorCodeEnum;
@@ -44,6 +46,7 @@ import java.util.stream.Collectors;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -67,13 +70,13 @@ public class CouponMgrController extends BaseApiController {
 
 	@Autowired
 	private ICouponTicketService couponTicketService;
-	
+
 	@Autowired
 	private ITicketBoxService ticketBoxService;
-	
+
 	@Autowired
 	private ICouponChannelService couponChannelService;
-	
+
 	@Autowired
 	private IChannelService channelService;
 
@@ -89,20 +92,22 @@ public class CouponMgrController extends BaseApiController {
 	 * @return
 	 */
 	@PostMapping("/list")
+	@PreAuthorize("@ss.hasPermi('business:coupon:list')")
 	public TableDataInfo listCoupon(@RequestBody Coupon coupon) {
 		List<Coupon> list = new ArrayList<Coupon>();
 		startPage();
-		LambdaQueryWrapper<Coupon> queryWrapper = new LambdaQueryWrapper<Coupon>();
-		queryWrapper.like(null != coupon && StringUtils.isNotBlank(coupon.getTitle()), Coupon::getTitle, coupon.getTitle());
-		queryWrapper.eq(null != coupon && null != coupon.getStatus(), Coupon::getStatus, coupon.getStatus());
-		queryWrapper.eq(null != coupon && null != coupon.getType(), Coupon::getType, coupon.getType());
-		queryWrapper.eq(Coupon::getIsDeleted, 0);
-		queryWrapper.orderByAsc(Coupon::getCreatedTime);
+		QueryWrapper<Coupon> queryWrapper = new QueryWrapper<Coupon>();
+		queryWrapper.lambda().like(null != coupon && StringUtils.isNotBlank(coupon.getTitle()), Coupon::getTitle, coupon.getTitle());
+		queryWrapper.lambda().eq(null != coupon && null != coupon.getStatus(), Coupon::getStatus, coupon.getStatus());
+		queryWrapper.lambda().eq(null != coupon && null != coupon.getType(), Coupon::getType, coupon.getType());
+		queryWrapper.lambda().eq(Coupon::getIsDeleted, 0);
+		queryWrapper.orderByAsc("FIELD(`status`, 'init', 'on', 'off')");
+		queryWrapper.lambda().orderByDesc(Coupon::getCouponId);
 		list = couponService.list(queryWrapper);
 		return getDataTable(list);
 	}
-	
-	
+
+
 	/**
 	 * 获取代金券详情信息
 	 *
@@ -110,13 +115,14 @@ public class CouponMgrController extends BaseApiController {
 	 * @return
 	 */
 	@PostMapping(value = "/detail")
+	@PreAuthorize("@ss.hasPermi('business:coupon:query')")
 	public AjaxResult getCouponDetail(@RequestBody JSONObject jsonObject) {
 		String couponId = jsonObject.getString("couponId");
-	    if (StringUtils.isBlank(couponId)){
-	      return error(ErrorCodeEnum.ERROR_CODE_1001);
-	    }
-	    Coupon coupon = couponService.getById(couponId);
-		if(null == coupon || StringUtils.isBlank(coupon.getCouponId())) {
+		if (StringUtils.isBlank(couponId)){
+			return error(ErrorCodeEnum.ERROR_CODE_1001);
+		}
+		Coupon coupon = couponService.getById(Long.valueOf(couponId));
+		if(null == coupon) {
 			 return error(ErrorCodeEnum.ERROR_CODE_1001);
 		}
 		CouponVO couponVO = new CouponVO();
@@ -159,12 +165,14 @@ public class CouponMgrController extends BaseApiController {
 	}
 
 	/**
-	 * 新增代金券信息
+	 * 新增优惠券信息
 	 * @param
 	 * @return
 	 */
-	@ApiOperation(value = "新增代金券信息", notes = "代金券端新增代金券")
+	@Log(title = "新增优惠券", businessType = BusinessType.INSERT)
+	@ApiOperation(value = "新增优惠券信息", notes = "新增优惠券")
 	@PostMapping("/create")
+	@PreAuthorize("@ss.hasPermi('business:coupon:add')")
 	public AjaxResult couponCreate(@Validated @RequestBody CouponParam couponParam) {
 		if (StringUtils.isNotBlank(couponParam.getCouponId())) {
 			return AjaxResult.error("该代金券已存在");
@@ -189,7 +197,7 @@ public class CouponMgrController extends BaseApiController {
 	        	ticketList.add(couponTicket);
 	        }
 		}
-//		if(coupon.getUseArea() != CouponUseAreaEnum.COMMON 
+//		if(coupon.getUseArea() != CouponUseAreaEnum.COMMON
 //				&& ticketList.size() == 0) {
 //			return AjaxResult.error("使用范围为指定盲票时需要至少选择一种盲票");
 //		}
@@ -211,8 +219,10 @@ public class CouponMgrController extends BaseApiController {
 	 * @param
 	 * @return
 	 */
+	@Log(title = "修改优惠券", businessType = BusinessType.UPDATE)
 	@ApiOperation(value = "编辑代金券信息", notes = "代金券端编辑代金券")
 	@PostMapping("/update")
+	@PreAuthorize("@ss.hasPermi('business:coupon:edit')")
 	public AjaxResult couponUpdate(@Validated @RequestBody CouponParam couponParam) {
 		if (null == couponParam || StringUtils.isBlank(couponParam.getCouponId())) {
 			return error(ErrorCodeEnum.ERROR_CODE_1001);
@@ -254,11 +264,13 @@ public class CouponMgrController extends BaseApiController {
 
 
 	/**
-	 * 停用、启用代金
+	 * 上下架优惠
 	 * @param
 	 * @return
 	 */
-	@ApiOperation(value = "停用、启用代金券信息", notes = "代金券管理编辑代金券")
+	@Log(title = "上下架优惠券", businessType = BusinessType.UPDATE)
+	@PreAuthorize("@ss.hasPermi('business:coupon:on')")
+	@ApiOperation(value = "上下架优惠券信息", notes = "优惠券管理编辑代金券")
 	@PostMapping("/status")
 	public AjaxResult couponStatus(@RequestBody JSONObject jsonObject) {
 		String couponId = jsonObject.getString("couponId");
@@ -267,29 +279,31 @@ public class CouponMgrController extends BaseApiController {
 			return error(ErrorCodeEnum.ERROR_CODE_1001);
 		}
 		try {
-			couponService.lambdaUpdate().set(Coupon::getStatus, CouponStatusEnum.PUT_ON.getValue().equals(status)?CouponStatusEnum.PUT_ON:CouponStatusEnum.PUT_OFF).eq(Coupon::getCouponId, couponId).update();
+			couponService.lambdaUpdate().set(Coupon::getStatus, CouponStatusEnum.PUT_ON.getValue().equals(status)?CouponStatusEnum.PUT_ON:CouponStatusEnum.PUT_OFF).eq(Coupon::getCouponId, Long.valueOf(couponId)).update();
 			// 查询代金券信息
 		} catch (Exception e) {
 			return AjaxResult.error("操作失败");
 		}
 		return AjaxResult.success("操作成功");
 	}
-	
-	
+
+
 	/**
 	 * 删除代金券商品(假删)
 	 *
 	 * @param
 	 * @return
 	 */
+	@Log(title = "删除优惠券", businessType = BusinessType.DELETE)
 	@PostMapping(value = "/remove")
+	@PreAuthorize("@ss.hasPermi('business:coupon:remove')")
 	public AjaxResult removeCoupon(@RequestBody JSONObject jsonObject) {
 		String couponId = jsonObject.getString("couponId");
 	    if (StringUtils.isBlank(couponId)){
 	      return error(ErrorCodeEnum.ERROR_CODE_1001);
 	    }
-	    Coupon coupon = couponService.getById(couponId);
-		if(null == coupon || StringUtils.isBlank(coupon.getCouponId())) {
+	    Coupon coupon = couponService.getById(Long.valueOf(couponId));
+		if(null == coupon) {
 			 return error(ErrorCodeEnum.ERROR_CODE_1001);
 		}
 		// 商品未下架, 不允许删除

+ 135 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/ExchangeBannerMgrController.java

@@ -0,0 +1,135 @@
+package com.qs.mp.web.controller.api.admin;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.qs.mp.admin.domain.ExchangeBanner;
+import com.qs.mp.admin.service.IExchangeBannerService;
+import com.qs.mp.common.annotation.Log;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.core.page.TableDataInfo;
+import com.qs.mp.common.enums.BusinessType;
+import com.qs.mp.common.enums.ErrorCodeEnum;
+import com.qs.mp.common.utils.StringUtils;
+import com.qs.mp.web.controller.common.BaseApiController;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @auther zhongcp
+ * @create 2022-04-07 23:45:48
+ * @describe 商品banner管理前端控制器
+ */
+@Api("商品banner管理API")
+@RestController
+@RequestMapping("/api/v1/mp/admin/goods/banner/*")
+@Component
+public class ExchangeBannerMgrController extends BaseApiController {
+
+  @Autowired
+  private IExchangeBannerService exchangeBannerService;
+
+
+  /**
+   * 查询商品banner列表, 支持翻页
+   *
+   * @return
+   */
+  @PostMapping("/list")
+  @PreAuthorize("@ss.hasPermi('business:banner:list')")
+  public TableDataInfo list(@RequestBody JSONObject param) {
+    startPage();
+    List<ExchangeBanner> bannerList = exchangeBannerService.list(
+        new LambdaQueryWrapper<ExchangeBanner>().orderByDesc(ExchangeBanner::getSort));
+    return getDataTable(bannerList);
+  }
+
+  /**
+   * 获取商品banner详情信息
+   *
+   * @param
+   * @return
+   */
+  @PostMapping(value = "/detail")
+  @PreAuthorize("@ss.hasPermi('business:banner:query')")
+  public AjaxResult info(@RequestBody JSONObject jsonObject) {
+    Long bannerId = jsonObject.getLong("bannerId");
+    if (null == bannerId || 0 == bannerId) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    ExchangeBanner banner = exchangeBannerService.getById(bannerId);
+    return AjaxResult.success(banner);
+  }
+
+
+  /**
+   * 新增商品banner信息
+   *
+   * @param
+   * @return
+   */
+  @Log(title = "新增商品banner", businessType = BusinessType.INSERT)
+  @ApiOperation(value = "新增商品banner", notes = "后台商品管理新增banner")
+  @PostMapping("/create")
+  @PreAuthorize("@ss.hasPermi('business:banner:add')")
+  public AjaxResult create(@RequestBody ExchangeBanner exchangeBanner) {
+    if (StringUtils.isBlank(exchangeBanner.getName()) || StringUtils.isBlank(
+        exchangeBanner.getPicUrl())
+        || StringUtils.isBlank(exchangeBanner.getType()) || null == exchangeBanner.getLocation()) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    // 2.保存
+    exchangeBannerService.save(exchangeBanner);
+    return AjaxResult.success("保存成功");
+  }
+
+  /**
+   * 编辑商品banner信息
+   *
+   * @param
+   * @return
+   */
+  @Log(title = "修改商品banner", businessType = BusinessType.UPDATE)
+  @ApiOperation(value = "编辑商品banner信息", notes = "后台商品管理修改商品banner信息")
+  @PostMapping("/update")
+  @PreAuthorize("@ss.hasPermi('business:banner:edit')")
+  public AjaxResult update(@Validated @RequestBody ExchangeBanner exchangeBanner) {
+    if (null == exchangeBanner || null == exchangeBanner.getBannerId()
+        || 0 == exchangeBanner.getBannerId()) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    // 保存数据
+    boolean rst = exchangeBannerService.updateById(exchangeBanner);
+    return rst ? AjaxResult.success("更新成功") : AjaxResult.error("更新失败");
+  }
+
+
+  /**
+   * 删除商品banner
+   *
+   * @param
+   * @return
+   */
+  @Log(title = "删除商品banner", businessType = BusinessType.DELETE)
+  @PostMapping(value = "/remove")
+  @PreAuthorize("@ss.hasPermi('business:banner:remove')")
+  public AjaxResult remove(@RequestBody ExchangeBanner exchangeBanner) {
+
+    if (null == exchangeBanner || null == exchangeBanner.getBannerId()
+        || 0 == exchangeBanner.getBannerId()) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+
+    boolean res = exchangeBannerService.removeById(exchangeBanner.getBannerId());
+    return res ? AjaxResult.success("删除成功") : AjaxResult.error("删除失败");
+  }
+
+}

+ 164 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/GoodsCategoryMgrController.java

@@ -0,0 +1,164 @@
+package com.qs.mp.web.controller.api.admin;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.qs.mp.admin.domain.Goods;
+import com.qs.mp.admin.domain.GoodsCategory;
+import com.qs.mp.admin.service.IGoodsCategoryService;
+import com.qs.mp.admin.service.IGoodsService;
+import com.qs.mp.common.annotation.Log;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.core.page.TableDataInfo;
+import com.qs.mp.common.enums.BusinessType;
+import com.qs.mp.common.enums.ErrorCodeEnum;
+import com.qs.mp.web.controller.common.BaseApiController;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import java.util.Arrays;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @auther zhongcp
+ * @create 2022-04-07 23:45:48
+ * @describe 商品分类管理前端控制器
+ */
+@Api("商品分类管理API")
+@RestController
+@RequestMapping("/api/v1/mp/admin/goods/category/*")
+@Component
+public class GoodsCategoryMgrController extends BaseApiController {
+
+  @Autowired
+  private IGoodsCategoryService goodsCategoryService;
+
+  @Autowired
+  private IGoodsService goodsService;
+
+
+  /**
+   * 查询商品分类列表, 支持翻页
+   *
+   * @return
+   */
+  @PostMapping("/list")
+  @PreAuthorize("@ss.hasPermi('business:category:list')")
+  public TableDataInfo list(@RequestBody JSONObject param) {
+    startPage();
+    List<GoodsCategory> categoryList = goodsCategoryService.list(
+        new LambdaQueryWrapper<GoodsCategory>().orderByDesc(GoodsCategory::getSort));
+    return getDataTable(categoryList);
+  }
+
+  /**
+   * 查询商品分类列表, 支持翻页
+   *
+   * @return
+   */
+  @PostMapping("/items")
+  public AjaxResult items(@RequestBody JSONObject param) {
+    List<GoodsCategory> categoryList = goodsCategoryService.list(
+        new LambdaQueryWrapper<GoodsCategory>().orderByDesc(GoodsCategory::getSort));
+    return AjaxResult.success(categoryList);
+  }
+
+  /**
+   * 获取商品分类详情信息
+   *
+   * @param
+   * @return
+   */
+  @PostMapping(value = "/detail")
+  @PreAuthorize("@ss.hasPermi('business:category:query')")
+  public AjaxResult info(@RequestBody JSONObject jsonObject) {
+    Long categoryId = jsonObject.getLong("categoryId");
+    if (null == categoryId || 0 == categoryId) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    GoodsCategory category = goodsCategoryService.getById(categoryId);
+    return AjaxResult.success(category);
+  }
+
+
+  /**
+   * 新增商品分类信息
+   *
+   * @param
+   * @return
+   */
+  @Log(title = "新增商品分类", businessType = BusinessType.INSERT)
+  @ApiOperation(value = "新增商品分类", notes = "后台商品管理新增分类")
+  @PostMapping("/create")
+  @PreAuthorize("@ss.hasPermi('business:category:add')")
+  public AjaxResult create(@Validated @RequestBody GoodsCategory goodsCategory) {
+    // 1、校验名称是否重复
+    int cnt = goodsCategoryService.count(new LambdaQueryWrapper<GoodsCategory>()
+        .eq(GoodsCategory::getName, goodsCategory.getName()));
+    if (cnt > 0) {
+      return AjaxResult.error("分类名称已存在!");
+    }
+    // 2.保存
+    goodsCategory.setParentId(0L);
+    goodsCategoryService.save(goodsCategory);
+    return AjaxResult.success("保存成功");
+  }
+
+  /**
+   * 编辑商品分类信息
+   *
+   * @param
+   * @return
+   */
+  @Log(title = "修改商品分类", businessType = BusinessType.UPDATE)
+  @ApiOperation(value = "编辑商品分类信息", notes = "后台商品管理修改商品分类信息")
+  @PostMapping("/update")
+  @PreAuthorize("@ss.hasPermi('business:category:edit')")
+  public AjaxResult update(@Validated @RequestBody GoodsCategory goodsCategory) {
+    if (null == goodsCategory || null == goodsCategory.getCategoryId()
+        || 0 == goodsCategory.getCategoryId()) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    int cnt = goodsCategoryService.count(new LambdaQueryWrapper<GoodsCategory>()
+        .eq(GoodsCategory::getName, goodsCategory.getName()).notIn(GoodsCategory::getCategoryId,
+            Arrays.asList(goodsCategory.getCategoryId())));
+    if (cnt > 0) {
+      return AjaxResult.error("分类名称已存在!");
+    }
+    // 保存数据
+    boolean rst = goodsCategoryService.updateById(goodsCategory);
+    return rst ? AjaxResult.success("更新成功") : AjaxResult.error("更新失败");
+  }
+
+
+  /**
+   * 删除商品分类
+   *
+   * @param
+   * @return
+   */
+  @Log(title = "删除商品分类", businessType = BusinessType.DELETE)
+  @PostMapping(value = "/remove")
+  @PreAuthorize("@ss.hasPermi('business:category:remove')")
+  public AjaxResult remove(@RequestBody GoodsCategory goodsCategory) {
+
+    if (null == goodsCategory.getCategoryId() || 0 == goodsCategory.getCategoryId()) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    int cnt = goodsService.count(new LambdaQueryWrapper<Goods>()
+        .eq(Goods::getCategoryId, goodsCategory.getCategoryId()).eq(Goods::getIsDeleted, 0));
+    if (cnt > 0) {
+      return error(ErrorCodeEnum.ERROR_CODE_1024);
+    }
+
+    boolean res = goodsCategoryService.removeById(goodsCategory.getCategoryId());
+    return res ? AjaxResult.success("删除成功") : AjaxResult.error("删除失败");
+  }
+
+}

+ 321 - 257
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/GoodsMgrController.java

@@ -4,55 +4,38 @@ import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
-import com.baomidou.mybatisplus.extension.service.IService;
-import com.google.common.html.HtmlEscapers;
-import com.qs.mp.admin.domain.Coupon;
 import com.qs.mp.admin.domain.Goods;
-import com.qs.mp.admin.domain.GoodsCategory;
 import com.qs.mp.admin.domain.GoodsSku;
-import com.qs.mp.admin.domain.param.CouponParam;
+import com.qs.mp.admin.domain.GoodsTagRel;
 import com.qs.mp.admin.domain.param.GoodsParam;
 import com.qs.mp.admin.domain.param.GoodsQueryParam;
-import com.qs.mp.admin.domain.vo.GoodsListVO;
 import com.qs.mp.admin.domain.vo.GoodsVO;
-import com.qs.mp.admin.service.IGoodsCategoryService;
 import com.qs.mp.admin.service.IGoodsService;
 import com.qs.mp.admin.service.IGoodsSkuService;
-import com.qs.mp.channel.domain.Channel;
-import com.qs.mp.channel.domain.param.ChannelParam;
-import com.qs.mp.channel.domain.vo.ChannelOperDataVO;
-import com.qs.mp.channel.domain.vo.ChannelVO;
-import com.qs.mp.channel.service.IChannelService;
-import com.qs.mp.channel.service.IChannelUserRelService;
-import com.qs.mp.common.constant.UserConstants;
+import com.qs.mp.admin.service.IGoodsTagRelService;
+import com.qs.mp.common.annotation.Log;
 import com.qs.mp.common.core.domain.AjaxResult;
 import com.qs.mp.common.core.page.TableDataInfo;
-import com.qs.mp.common.enums.ChannelRoleEnum;
-import com.qs.mp.common.enums.CouponStatusEnum;
+import com.qs.mp.common.enums.BusinessType;
 import com.qs.mp.common.enums.ErrorCodeEnum;
 import com.qs.mp.common.enums.GoodsStatusEnum;
-import com.qs.mp.common.utils.html.EscapeUtil;
-import com.qs.mp.system.domain.SysUser;
-import com.qs.mp.system.service.ISysUserService;
-import com.qs.mp.utils.SecurityUtils;
+import com.qs.mp.common.utils.LogUtil;
 import com.qs.mp.web.controller.common.BaseApiController;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import ma.glasnost.orika.MapperFacade;
-
-import java.math.BigDecimal;
-import java.net.URI;
 import java.net.URLDecoder;
 import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
 import java.util.List;
-import java.util.Map;
-
-import org.apache.commons.codec.Decoder;
-import org.apache.commons.lang3.StringEscapeUtils;
+import java.util.stream.Collectors;
+import ma.glasnost.orika.MapperFacade;
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
@@ -70,241 +53,322 @@ import org.springframework.web.bind.annotation.RestController;
 @Component
 public class GoodsMgrController extends BaseApiController {
 
-	@Autowired
-	private IGoodsService goodsService;
-	
-	@Autowired
-	private IGoodsSkuService goodsSkuService;
-	
-	@Autowired
-	private IGoodsCategoryService goodsCategoryService;
-	
-	@Autowired
-	private ISysUserService sysUserService;
+  @Autowired
+  private IGoodsService goodsService;
+
+  @Autowired
+  private IGoodsSkuService goodsSkuService;
+
+  @Autowired
+  private IGoodsTagRelService goodsTagRelService;
+
+  @Autowired
+  private MapperFacade mapperFacade;
+
+
+  /**
+   * 查询商品列表, 支持翻页
+   *
+   * @return
+   */
+  @PostMapping("/list")
+  @PreAuthorize("@ss.hasPermi('business:goods:list')")
+  public TableDataInfo list(@RequestBody GoodsQueryParam queryParam) {
+    // 商品标签
+    List<Long> goodsIds = new ArrayList<>();
+    if (null != queryParam.getTagId()) {
+      List<GoodsTagRel> goodsTagRelList = goodsTagRelService.list(
+          new LambdaQueryWrapper<GoodsTagRel>().eq(GoodsTagRel::getTagId, queryParam.getTagId()));
+      goodsIds = goodsTagRelList.stream().map(GoodsTagRel::getGoodsId)
+          .collect(Collectors.toList());
+      if (CollectionUtils.isEmpty(goodsIds)) {
+        return getDataTable(new ArrayList<>());
+      }
+    }
+    startPage();
+    QueryWrapper<Goods> queryWrapper = new QueryWrapper<Goods>();
+    queryWrapper.lambda()
+        .like(null != queryParam && StringUtils.isNotBlank(queryParam.getTitle()), Goods::getTitle,
+            queryParam.getTitle());
+    queryWrapper.lambda()
+        .eq(null != queryParam.getGoodsId() && 0 != queryParam.getGoodsId(),
+            Goods::getGoodsId, queryParam.getGoodsId());
+    // 成本
+    queryWrapper.lambda()
+        .ge(null != queryParam.getMinCost(), Goods::getCost, queryParam.getMinCost());
+    queryWrapper.lambda()
+        .le(null != queryParam.getMaxCost(), Goods::getCost, queryParam.getMaxCost());
+    // 价格
+    queryWrapper.lambda()
+        .ge(null != queryParam.getMinValue(), Goods::getValue, queryParam.getMinValue());
+    queryWrapper.lambda()
+        .le(null != queryParam.getMaxValue(), Goods::getValue, queryParam.getMaxValue());
+    // 状态
+    queryWrapper.lambda()
+        .eq(null != queryParam.getStatus(), Goods::getStatus, queryParam.getStatus());
+    // 是否支持兑换
+    queryWrapper.lambda().eq(null != queryParam.getExchangeShow(), Goods::getExchangeShow,
+        queryParam.getExchangeShow());
+    // 商品分类
+    queryWrapper.lambda()
+        .eq(null != queryParam.getCategoryId(), Goods::getCategoryId, queryParam.getCategoryId());
+    // 标签过滤的商品ID
+    queryWrapper.lambda().in(null != queryParam.getTagId(), Goods::getGoodsId, goodsIds);
+    queryWrapper.lambda().eq(Goods::getIsDeleted, 0);
+    queryWrapper.orderByAsc("FIELD(`status`, 'init', 'on', 'off')");
+    queryWrapper.lambda().orderByDesc(Goods::getGoodsId);
+    List<Goods> goodsList = goodsService.list(queryWrapper);
+    TableDataInfo res = getDataTable(goodsList);
+    res.setRows(goodsList);
+    return res;
+  }
+
+  /**
+   * 获取商品详情信息
+   *
+   * @param
+   * @return
+   */
+  @PostMapping(value = "/detail")
+  @PreAuthorize("@ss.hasPermi('business:goods:query')")
+  public AjaxResult getGoodsDetail(@RequestBody JSONObject jsonObject) {
+    Long goodsId = jsonObject.getLong("goodsId");
+    if (null == goodsId || 0 == goodsId) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    Goods goods = goodsService.getById(goodsId);
+    if (null == goods) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    GoodsVO goodsVo = new GoodsVO();
+    BeanUtils.copyProperties(goods, goodsVo);
+    // 查询SKU列表
+    List<GoodsSku> skuList = new ArrayList<>();
+    LambdaQueryWrapper<GoodsSku> queryWrapper = new LambdaQueryWrapper<>();
+    queryWrapper.eq(GoodsSku::getGoodsId, goods.getGoodsId());
+    queryWrapper.orderByDesc(GoodsSku::getCreatedTime);
+    skuList = goodsSkuService.list(queryWrapper);
+    if (null != skuList && skuList.size() > 0) {
+      goodsVo.setSkuList(skuList);
+    }
+    // 查询标签ID列表
+    List<GoodsTagRel> goodsTagRelList = goodsTagRelService.list(
+        new LambdaQueryWrapper<GoodsTagRel>().eq(GoodsTagRel::getGoodsId, goods.getGoodsId()));
+    List<Long> tagIds = goodsTagRelList.stream().map(GoodsTagRel::getTagId)
+        .collect(Collectors.toList());
+    goodsVo.setTagIds(tagIds);
+
+    return AjaxResult.success(goodsVo);
+  }
+
+
+  /**
+   * 新增商品信息
+   *
+   * @param
+   * @return
+   */
+  @Log(title = "新增商品", businessType = BusinessType.INSERT)
+  @ApiOperation(value = "新增商品信息", notes = "后台商品管理新增商品")
+  @PostMapping("/create")
+  @PreAuthorize("@ss.hasPermi('business:goods:add')")
+  public AjaxResult goodsCreate(@Validated @RequestBody GoodsParam goodsParam) {
+    Goods goods = mapperFacade.map(goodsParam, Goods.class);
+    // 1、校验名称是否重复(商品表)
+    LambdaQueryWrapper<Goods> queryWrapper = new LambdaQueryWrapper<>();
+    queryWrapper.eq(Goods::getTitle, goods.getTitle());
+    queryWrapper.eq(Goods::getIsDeleted, 0);
+    int titleCount = goodsService.count(queryWrapper);
+    if (titleCount > 0) {
+      return AjaxResult.error("商品名称" + goods.getTitle() + "已存在!");
+    }
+    String description = URLDecoder.decode(goodsParam.getDescription());
+    goods.setDescription(description);
+    goods.setStatus(GoodsStatusEnum.PUT_INIT);
+    // 多SKU
+    List<GoodsSku> skuList = goodsParam.getSkuList();
+    if (goods.getMultiSku() == 1) { //
+      if ((null == skuList || skuList.size() == 0)) {
+        return AjaxResult.error("商品" + goods.getTitle() + "不满足多SKU条件!");
+      } else {
+        GoodsSku firstGoodsSku = skuList.get(0);
+        goods.setOriginPrice(firstGoodsSku.getOriginPrice());
+        goods.setExchangePrice(firstGoodsSku.getExchangePrice());
+        goods.setValue(firstGoodsSku.getValue());
+        goods.setCost(firstGoodsSku.getCost());
+        // 累计库存
+        int totalQuantity = skuList.stream().mapToInt(GoodsSku::getQuantity).sum();
+        goods.setQuantity(totalQuantity);
+      }
+    }
+    if (null == goods.getOriginPrice()) {
+      goods.setOriginPrice(goods.getExchangePrice());
+    }
+    // 3.插入数据
+    try {
+      goods.setSkuProp(getSkuProp(skuList));
+      goodsService.saveGoods(goods, skuList, goodsParam.getTagIds());
+    } catch (Exception e) {
+      LogUtil.error(logger, e, "商品新增失败。");
+      return AjaxResult.error("商品'" + goods.getTitle() + "'新增失败");
+    }
+    return AjaxResult.success("商品'" + goods.getTitle() + "'新增成功");
+  }
 
-	@Autowired
-	private MapperFacade mapperFacade;
+  /**
+   * 编辑商品信息
+   *
+   * @param
+   * @return
+   */
+  @Log(title = "修改商品", businessType = BusinessType.UPDATE)
+  @ApiOperation(value = "编辑商品信息", notes = "后台商品管理修改商品信息")
+  @PostMapping("/update")
+  @PreAuthorize("@ss.hasPermi('business:goods:edit')")
+  public AjaxResult goodsUpdate(@Validated @RequestBody GoodsParam goodsParam) {
+    if (null == goodsParam || null == goodsParam.getGoodsId() || 0 == goodsParam.getGoodsId()) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    Goods oldGoods = goodsService.getById(goodsParam.getGoodsId());
+    if (null == oldGoods || null == oldGoods.getGoodsId()) {
+      return AjaxResult.error("商品'" + oldGoods.getTitle() + "'编辑失败,商品ID异常");
+    }
+    Goods goods = mapperFacade.map(goodsParam, Goods.class);
+    // 1、校验名称是否重复(商品表)
+    if (!goods.getTitle().equals(oldGoods.getTitle())) {
+      LambdaQueryWrapper<Goods> queryWrapper = new LambdaQueryWrapper<>();
+      queryWrapper.eq(Goods::getTitle, goods.getTitle());
+      queryWrapper.eq(Goods::getIsDeleted, 0);
+      int titleCount = goodsService.count(queryWrapper);
+      if (titleCount > 0) {
+        return AjaxResult.error("商品名称" + goods.getTitle() + "已存在!");
+      }
+    }
+    String description = URLDecoder.decode(goodsParam.getDescription());
+    goods.setDescription(description);
+    // 多SKU
+    List<GoodsSku> skuList = goodsParam.getSkuList();
+    if (goods.getMultiSku() == 1) {
+      if ((null == skuList || skuList.size() == 0)) {
+        return AjaxResult.error("商品" + goods.getTitle() + "不满足多SKU条件!");
+      } else {
+        GoodsSku firstGoodsSku = skuList.get(0);
+        goods.setExchangePrice(firstGoodsSku.getExchangePrice());
+        goods.setValue(firstGoodsSku.getValue());
+        goods.setCost(firstGoodsSku.getCost());
+        if (null == firstGoodsSku.getOriginPrice()) {
+          goods.setOriginPrice(firstGoodsSku.getExchangePrice());
+        } else {
+          goods.setOriginPrice(firstGoodsSku.getOriginPrice());
+        }
+        // 累计库存
+        int totalQuantity = skuList.stream().mapToInt(GoodsSku::getQuantity).sum();
+        goods.setQuantity(totalQuantity);
+      }
+    }
+    // 3.插入数据
+    try {
+      goods.setSkuProp(getSkuProp(skuList));
+      goodsService.updateGoods(goods, skuList, goodsParam.getTagIds());
+    } catch (Exception e) {
+      LogUtil.error(logger, e, "商品更新失败。");
+      return AjaxResult.error("商品'" + goods.getTitle() + "'更新失败");
+    }
+    return AjaxResult.success("商品'" + goods.getTitle() + "'更新成功");
+  }
 
+  // 获取商品的sku
+  public String getSkuProp(List<GoodsSku> skuList) {
+    if (CollectionUtils.isEmpty(skuList)) {
+      return null;
+    }
+    LinkedHashMap<String, HashSet<String>> skuProp = new LinkedHashMap<>();
+    for (GoodsSku sku : skuList) {
+      if (StringUtils.isNotBlank(sku.getProperties())) {
+        String[] skuAry = sku.getProperties().split(";");
+        for (int i = 0; i < skuAry.length; i++) {
+          String item = skuAry[i];
+          String[] itemAry = item.split(":");
+          String key = itemAry[0];
+          String value = itemAry[1];
+          HashSet<String> valueSet = skuProp.get(key);
+          if (null == valueSet) {
+            valueSet = new HashSet<>();
+            skuProp.put(key, valueSet);
+          }
+          valueSet.add(value);
+        }
+      }
+    }
+    List<JSONObject> skuPropList = new ArrayList<>();
+    for (String key : skuProp.keySet()) {
+      JSONObject jsonObject = new JSONObject();
+      jsonObject.put("name", key);
+      jsonObject.put("value", skuProp.get(key));
+      skuPropList.add(jsonObject);
+    }
+    return JSONObject.toJSONString(skuPropList);
+  }
 
-	/**
-	 * 查询商品列表, 支持翻页
-	 *
-	 * @return
-	 */
-	@PostMapping("/list")
-	public TableDataInfo list(@RequestBody GoodsQueryParam queryParam) {
-		startPage();
-		LambdaQueryWrapper<Goods> queryWrapper = new LambdaQueryWrapper<Goods>();
-		queryWrapper.like(null != queryParam && StringUtils.isNotBlank(queryParam.getTitle()), Goods::getTitle, queryParam.getTitle());
-		queryWrapper.eq(null != queryParam && StringUtils.isNotBlank(queryParam.getGoodsId()), Goods::getGoodsId, queryParam.getGoodsId());
-		// 成本
-		queryWrapper.ge(null != queryParam && null != queryParam.getMinCost(), Goods::getCost, queryParam.getMinCost());
-		queryWrapper.le(null != queryParam && null != queryParam.getMaxCost(), Goods::getCost, queryParam.getMaxCost());
-		// 价格
-		queryWrapper.ge(null != queryParam && null != queryParam.getMinValue(), Goods::getValue, queryParam.getMinValue());
-		queryWrapper.le(null != queryParam && null != queryParam.getMaxValue(), Goods::getValue, queryParam.getMaxValue());
-		// 状态
-		queryWrapper.eq(null != queryParam && null != queryParam.getStatus(), Goods::getStatus, queryParam.getStatus());
-		queryWrapper.eq(Goods::getIsDeleted, 0);
-		List<Goods> goodsList = goodsService.list(queryWrapper);
-		TableDataInfo res = getDataTable(goodsList);
-		res.setRows(goodsList);
-		return res;
-	}
-	
-	/**
-	 * 获取商品详情信息
-	 *
-	 * @param
-	 * @return
-	 */
-	@PostMapping(value = "/detail")
-	public AjaxResult getGoodsDetail(@RequestBody JSONObject jsonObject) {
-		String goodsId = jsonObject.getString("goodsId");
-	    if (StringUtils.isBlank(goodsId)){
-	      return error(ErrorCodeEnum.ERROR_CODE_1001);
-	    }
-		Goods goods = goodsService.getById(goodsId);
-		if(null == goods || StringUtils.isBlank(goods.getGoodsId())) {
-			 return error(ErrorCodeEnum.ERROR_CODE_1001);
-		}
-		GoodsVO goodsVo = new GoodsVO();
-		BeanUtils.copyProperties(goods, goodsVo);
-		// 查询SKU列表
-		List<GoodsSku> skuList = new ArrayList<>();
-		LambdaQueryWrapper<GoodsSku> queryWrapper = new LambdaQueryWrapper<>();
-		queryWrapper.eq(GoodsSku::getGoodsId, goods.getGoodsId());
-		queryWrapper.orderByDesc(GoodsSku::getCreatedTime);
-		skuList = goodsSkuService.list(queryWrapper);
-		if(null != skuList && skuList.size() > 0) {
-			goodsVo.setSkuList(skuList);
-		}
-		return AjaxResult.success(goodsVo);
-	}
 
+  /**
+   * 上下架商品
+   *
+   * @param
+   * @return
+   */
+  @Log(title = "上下架商品", businessType = BusinessType.UPDATE)
+  @ApiOperation(value = "上下架商品", notes = "上下架商品")
+  @PostMapping("/status")
+  @PreAuthorize("@ss.hasPermi('business:goods:on')")
+  public AjaxResult goodsStatus(@RequestBody JSONObject jsonObject) {
+    String goodsId = jsonObject.getString("goodsId");
 
-	/**
-	 * 新增商品信息
-	 * @param
-	 * @return
-	 */
-	@ApiOperation(value = "新增商品信息", notes = "后台商品管理新增商品")
-	@PostMapping("/create")
-	public AjaxResult goodsCreate(@Validated @RequestBody GoodsParam goodsParam) {
-		if (StringUtils.isNotBlank(goodsParam.getGoodsId())) {
-			return AjaxResult.error("该商品已存在");
-		}
-		Goods goods = mapperFacade.map(goodsParam, Goods.class);
-		// 1、校验名称是否重复(商品表)
-		LambdaQueryWrapper<Goods> queryWrapper = new LambdaQueryWrapper<>();
-		queryWrapper.eq(Goods::getTitle, goods.getTitle());
-		queryWrapper.eq(Goods::getIsDeleted, 0);
-		int titleCount = goodsService.count(queryWrapper);
-		if(titleCount > 0) {
-			return AjaxResult.error("商品名称" + goods.getTitle() + "已存在!");
-		}
-		String description = URLDecoder.decode(goodsParam.getDescription());
-		goods.setDescription(description);
-		goods.setStatus(GoodsStatusEnum.PUT_INIT);
-		// 多SKU
-		List<GoodsSku> skuList = goodsParam.getSkuList();
-		if(goods.getMultiSku() == 1) { // 
-			if((null == skuList || skuList.size() == 0)) {
-				return AjaxResult.error("商品" + goods.getTitle() + "不满足多SKU条件!");
-			}else {
-				GoodsSku firstGoodsSku = skuList.get(0);
-				goods.setOriginPrice(firstGoodsSku.getOriginPrice());
-				goods.setExchangePrice(firstGoodsSku.getExchangePrice());
-				goods.setValue(firstGoodsSku.getValue());
-				goods.setCost(firstGoodsSku.getCost());
-				// 累计库存
-				int totalQuantity = skuList.stream().mapToInt(GoodsSku::getQuantity).sum();
-				goods.setQuantity(totalQuantity);
-			}
-		}
-		if(null == goods.getOriginPrice()) {
-			goods.setOriginPrice(goods.getExchangePrice());
-		}
-		// 3.插入数据
-		try {
-			goodsService.saveGoods(goods, skuList);
-		} catch (Exception e) {
-			return AjaxResult.error("商品'" + goods.getTitle() + "'新增失败" + e.getMessage());
-		}
-		return AjaxResult.success("商品'" + goods.getTitle() + "'新增成功");
-	}
+    GoodsStatusEnum status = GoodsStatusEnum.getStatusEnum(jsonObject.getString("status"));
+    if (StringUtils.isBlank(goodsId) || null == status) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    try {
+      goodsService.lambdaUpdate().set(Goods::getStatus, status).eq(Goods::getGoodsId, goodsId)
+          .update();
+      // 查询代金券信息
+    } catch (Exception e) {
+      return AjaxResult.error("操作失败");
+    }
+    return AjaxResult.success("操作成功");
+  }
 
-	/**
-	 * 编辑商品信息
-	 * @param
-	 * @return
-	 */
-	@ApiOperation(value = "编辑商品信息", notes = "后台商品管理修改商品信息")
-	@PostMapping("/update")
-	public AjaxResult goodsUpdate(@Validated @RequestBody GoodsParam goodsParam) {
-		if (null == goodsParam || StringUtils.isBlank(goodsParam.getGoodsId())) {
-			return error(ErrorCodeEnum.ERROR_CODE_1001);
-		}
-		Goods oldGoods = goodsService.getById(goodsParam.getGoodsId());
-		if(null == oldGoods || null == oldGoods.getGoodsId()) {
-			return AjaxResult.error("商品'" + oldGoods.getTitle() + "'编辑失败,商品ID异常");
-		}
-		Goods goods = mapperFacade.map(goodsParam, Goods.class);
-		// 1、校验名称是否重复(商品表)
-		if(!goods.getTitle().equals(oldGoods.getTitle())) {
-			LambdaQueryWrapper<Goods> queryWrapper = new LambdaQueryWrapper<>();
-			queryWrapper.eq(Goods::getTitle, goods.getTitle());
-			queryWrapper.eq(Goods::getIsDeleted, 0);
-			int titleCount = goodsService.count(queryWrapper);
-			if(titleCount > 0) {
-				return AjaxResult.error("商品名称" + goods.getTitle() + "已存在!");
-			}
-		}
-		String description = URLDecoder.decode(goodsParam.getDescription());
-		goods.setDescription(description);
-		// 多SKU
-		List<GoodsSku> skuList = goodsParam.getSkuList();
-		if(goods.getMultiSku() == 1) {
-			if((null == skuList || skuList.size() == 0)) {
-				return AjaxResult.error("商品" + goods.getTitle() + "不满足多SKU条件!");
-			}else {
-				GoodsSku firstGoodsSku = skuList.get(0);
-				goods.setExchangePrice(firstGoodsSku.getExchangePrice());
-				goods.setValue(firstGoodsSku.getValue());
-				goods.setCost(firstGoodsSku.getCost());
-				if(null == firstGoodsSku.getOriginPrice()) {
-					goods.setOriginPrice(firstGoodsSku.getExchangePrice());
-				}else {
-					goods.setOriginPrice(firstGoodsSku.getOriginPrice());
-				}
-				// 累计库存
-				int totalQuantity = skuList.stream().mapToInt(GoodsSku::getQuantity).sum();
-				goods.setQuantity(totalQuantity);
-			}
-		}
-		// 3.插入数据
-		try {
-			goodsService.updateGoods(goods, skuList);
-		} catch (Exception e) {
-			return AjaxResult.error("商品'" + goods.getTitle() + "'新增失败" + e.getMessage());
-		}
-		return AjaxResult.success("商品'" + goods.getTitle() + "'新增成功");
-	}
 
-	
-	
-	/**
-	 * 停用、启用商品
-	 * @param
-	 * @return
-	 */
-	@ApiOperation(value = "停用、启用代金券信息", notes = "代金券管理编辑代金券")
-	@PostMapping("/status")
-	public AjaxResult goodsStatus(@RequestBody Goods goods) {
-		String goodsId = (null != goods && StringUtils.isNotBlank(goods.getGoodsId()))?goods.getGoodsId():"";
-		GoodsStatusEnum status = (null != goods && null != goods.getStatus())?goods.getStatus():null;
-		if (StringUtils.isBlank(goodsId)
-				|| null == status) {
-			return error(ErrorCodeEnum.ERROR_CODE_1001);
-		}
-		try {
-			goodsService.lambdaUpdate().set(Goods::getStatus, goods.getStatus()).eq(Goods::getGoodsId, goodsId).update();
-			// 查询代金券信息
-		} catch (Exception e) {
-			return AjaxResult.error("操作失败");
-		}
-		return AjaxResult.success("操作成功");
-	}
-	
-	
-	/**
-	 * 删除商品(假删)
-	 *
-	 * @param
-	 * @return
-	 */
-	@PostMapping(value = "/remove")
-	public AjaxResult removeGoods(@RequestBody JSONObject jsonObject) {
-		String goodsId = jsonObject.getString("goodsId");
-	    if (StringUtils.isBlank(goodsId)){
-	      return error(ErrorCodeEnum.ERROR_CODE_1001);
-	    }
-		Goods goods = goodsService.getById(goodsId);
-		if(null == goods || StringUtils.isBlank(goods.getGoodsId())) {
-			 return error(ErrorCodeEnum.ERROR_CODE_1001);
-		}
-		// 商品未下架, 不允许删除
-		if(goods.getStatus().equals("on")) {
-			return AjaxResult.error("商品未下架,不允许删除");
-		}
-		LambdaUpdateWrapper<Goods> updateWrapper = new LambdaUpdateWrapper<>();
-		updateWrapper.set(Goods::getIsDeleted, 1);
-		updateWrapper.eq(Goods::getGoodsId, goods.getGoodsId());
-		boolean res = goodsService.update(updateWrapper);
-		if(!res) {
-			return AjaxResult.error("商品删除失败");
-		}
-		return AjaxResult.success("商品删除成功");
-	}
+  /**
+   * 删除商品(假删)
+   *
+   * @param
+   * @return
+   */
+  @Log(title = "删除商品", businessType = BusinessType.DELETE)
+  @PostMapping(value = "/remove")
+  @PreAuthorize("@ss.hasPermi('business:goods:remove')")
+  public AjaxResult removeGoods(@RequestBody JSONObject jsonObject) {
+    Long goodsId = jsonObject.getLong("goodsId");
+    if (null == goodsId || 0 == goodsId) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    Goods goods = goodsService.getById(goodsId);
+    if (null == goods || null == goods.getGoodsId() || 0 == goods.getGoodsId()) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    // 商品未下架, 不允许删除
+    if (goods.getStatus().equals("on")) {
+      return AjaxResult.error("商品未下架,不允许删除");
+    }
+    LambdaUpdateWrapper<Goods> updateWrapper = new LambdaUpdateWrapper<>();
+    updateWrapper.set(Goods::getIsDeleted, 1);
+    updateWrapper.eq(Goods::getGoodsId, goods.getGoodsId());
+    boolean res = goodsService.update(updateWrapper);
+    if (!res) {
+      return AjaxResult.error("商品删除失败");
+    }
+    return AjaxResult.success("商品删除成功");
+  }
 
 }

+ 163 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/GoodsTagMgrController.java

@@ -0,0 +1,163 @@
+package com.qs.mp.web.controller.api.admin;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.qs.mp.admin.domain.Goods;
+import com.qs.mp.admin.domain.GoodsCategory;
+import com.qs.mp.admin.domain.GoodsTag;
+import com.qs.mp.admin.domain.GoodsTagRel;
+import com.qs.mp.admin.service.IGoodsCategoryService;
+import com.qs.mp.admin.service.IGoodsService;
+import com.qs.mp.admin.service.IGoodsTagRelService;
+import com.qs.mp.admin.service.IGoodsTagService;
+import com.qs.mp.common.annotation.Log;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.core.page.TableDataInfo;
+import com.qs.mp.common.enums.BusinessType;
+import com.qs.mp.common.enums.ErrorCodeEnum;
+import com.qs.mp.web.controller.common.BaseApiController;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import java.util.Arrays;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @auther zhongcp
+ * @create 2022-04-07 23:45:48
+ * @describe 商品标签管理前端控制器
+ */
+@Api("商品标签管理API")
+@RestController
+@RequestMapping("/api/v1/mp/admin/goods/tag/*")
+@Component
+public class GoodsTagMgrController extends BaseApiController {
+
+  @Autowired
+  private IGoodsTagService goodsTagService;
+
+  @Autowired
+  private IGoodsTagRelService goodsTagRelService;
+
+
+  /**
+   * 查询商品标签列表, 支持翻页
+   *
+   * @return
+   */
+  @PostMapping("/list")
+  @PreAuthorize("@ss.hasPermi('business:tag:list')")
+  public TableDataInfo list(@RequestBody JSONObject param) {
+    startPage();
+    List<GoodsTag> tagList = goodsTagService.list(new LambdaQueryWrapper<GoodsTag>().orderByDesc(GoodsTag::getSort));
+    return getDataTable(tagList);
+  }
+
+  /**
+   * 查询商品标签列表
+   *
+   * @return
+   */
+  @PostMapping("/items")
+  public AjaxResult items(@RequestBody JSONObject param) {
+    List<GoodsTag> tagList = goodsTagService.list(new LambdaQueryWrapper<GoodsTag>().orderByDesc(GoodsTag::getSort));
+    return AjaxResult.success(tagList);
+  }
+
+  /**
+   * 获取商品标签详情信息
+   *
+   * @param
+   * @return
+   */
+  @PostMapping(value = "/detail")
+  @PreAuthorize("@ss.hasPermi('business:tag:query')")
+  public AjaxResult info(@RequestBody JSONObject jsonObject) {
+    Long tagId = jsonObject.getLong("tagId");
+    if (null == tagId || 0 == tagId) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    GoodsTag goodsTag = goodsTagService.getById(tagId);
+    return AjaxResult.success(goodsTag);
+  }
+
+
+  /**
+   * 新增商品标签信息
+   *
+   * @param
+   * @return
+   */
+  @Log(title = "新增商品标签", businessType = BusinessType.INSERT)
+  @ApiOperation(value = "新增商品标签", notes = "后台商品管理新增标签")
+  @PostMapping("/create")
+  @PreAuthorize("@ss.hasPermi('business:tag:add')")
+  public AjaxResult create(@Validated @RequestBody GoodsTag goodsTag) {
+    // 1、校验名称是否重复
+    int cnt = goodsTagService.count(new LambdaQueryWrapper<GoodsTag>()
+        .eq(GoodsTag::getName, goodsTag.getName()));
+    if (cnt > 0) {
+      return AjaxResult.error("标签名称已存在!");
+    }
+    // 2.保存
+    goodsTagService.save(goodsTag);
+    return AjaxResult.success("保存成功");
+  }
+
+  /**
+   * 编辑商品标签信息
+   *
+   * @param
+   * @return
+   */
+  @Log(title = "修改商品标签", businessType = BusinessType.UPDATE)
+  @ApiOperation(value = "编辑商品标签信息", notes = "后台商品管理修改商品标签信息")
+  @PostMapping("/update")
+  @PreAuthorize("@ss.hasPermi('business:tag:edit')")
+  public AjaxResult update(@Validated @RequestBody GoodsTag goodsTag) {
+    if (null == goodsTag || null == goodsTag.getTagId()
+        || 0 == goodsTag.getTagId()) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    int cnt = goodsTagService.count(new LambdaQueryWrapper<GoodsTag>()
+        .eq(GoodsTag::getName, goodsTag.getName()).notIn(GoodsTag::getTagId,
+            Arrays.asList(goodsTag.getTagId())));
+    if (cnt > 0) {
+      return AjaxResult.error("标签名称已存在!");
+    }
+    // 保存数据
+    boolean rst = goodsTagService.updateById(goodsTag);
+    return rst ? AjaxResult.success("更新成功") : AjaxResult.error("更新失败");
+  }
+
+
+  /**
+   * 删除商品标签
+   *
+   * @param
+   * @return
+   */
+  @Log(title = "删除商品标签", businessType = BusinessType.DELETE)
+  @PostMapping(value = "/remove")
+  @PreAuthorize("@ss.hasPermi('business:tag:remove')")
+  public AjaxResult remove(@RequestBody GoodsTag goodsTag) {
+
+    if (null == goodsTag || null == goodsTag.getTagId()
+        || 0 == goodsTag.getTagId()) {
+      return error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    goodsTagRelService.remove(new LambdaQueryWrapper<GoodsTagRel>()
+        .eq(GoodsTagRel::getTagId, goodsTag.getTagId()));
+
+    boolean res = goodsTagService.removeById(goodsTag.getTagId());
+    return res ? AjaxResult.success("删除成功") : AjaxResult.error("删除失败");
+  }
+
+}

+ 640 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/IndexMgrController.java

@@ -0,0 +1,640 @@
+package com.qs.mp.web.controller.api.admin;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qs.mp.admin.domain.param.IndexQueryParam;
+import com.qs.mp.admin.domain.vo.IndexVO;
+import com.qs.mp.channel.domain.Channel;
+import com.qs.mp.channel.service.IChannelService;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.utils.DateUtils;
+import com.qs.mp.user.domain.UserTicketOrder;
+import com.qs.mp.user.service.IUserTicketOrderService;
+import com.qs.mp.utils.SecurityUtils;
+import com.qs.mp.web.controller.common.BaseApiController;
+import io.swagger.annotations.Api;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @auther quanshu
+ * @create 2022-03-31 16:17:48
+ * @describe 首页渠道管理前端控制器
+ */
+@Api("首页管理API")
+@RestController
+@RequestMapping("/api/v1/mp/admin/index/*")
+@Component
+public class IndexMgrController extends BaseApiController {
+
+	@Autowired
+	private IChannelService channelService;
+
+    @Autowired
+    private IUserTicketOrderService userTicketOrderService;
+
+
+
+	/**
+	 * 查询统计交易金额
+	 * @return
+	 */
+	@PostMapping("/pay/amt")
+	// @PreAuthorize("@ss.hasPermi('business:channel:list')")
+	public AjaxResult listPayAmtData(@RequestBody IndexQueryParam indeQueryParam) {
+		
+		IndexQueryParam queryParam = getQueryParam(indeQueryParam);
+		
+		List<IndexVO> list = new ArrayList<IndexVO>();
+		QueryWrapper<UserTicketOrder> queryWrapper = new QueryWrapper<>();
+		queryWrapper.ge(null != queryParam && null != queryParam.getStartTime(), "t1.created_time", queryParam.getStartTime());
+		queryWrapper.le(null != queryParam && null != queryParam.getEndTime(), "t1.created_time", queryParam.getEndTime());
+		queryWrapper.gt("t1.`status`", 0);
+//		Long channelId = SecurityUtils.getLoginUser().getChannelId();
+//		if(null != channelId && 0 != channelId) {
+//			Channel channel = channelService.getById(channelId);
+//			if(null!=channel && StringUtils.isNotBlank(channel.getChannelNo())) {
+//				queryWrapper.and(wrapper -> wrapper.likeRight("t2.channel_no", channel.getChannelNo())
+//						.or().eq("t2.channel_no", channel.getChannelNo()));
+//			}
+//		}
+	
+		list = userTicketOrderService.selectIndexPayAmtList(queryWrapper);
+		return  AjaxResult.success(getPayAmtList(list, queryParam));
+	}
+	
+	private List<Map<String,Object>> getPayAmtList(List<IndexVO> list, IndexQueryParam queryParam){
+		List<Map<String,Object>> mapList = new ArrayList<>();
+		if(null != queryParam && queryParam.getLevel().equals("month")) {  // 月粒度
+			List<String> monthList = DateUtils.addMonths(queryParam.getStartTime(), queryParam.getEndTime());
+			if(null != monthList && monthList.size() > 0) {
+				for(String month : monthList) {
+					if(StringUtils.isNotBlank(month)) {
+						Map<String,Object> map = new HashMap<String,Object>();
+						map.put("x", month);
+						map.put("y", getMonthPayAmt(month, list));
+						mapList.add(map);
+					}
+				}
+			}
+		}else if(null != queryParam && queryParam.getLevel().equals("week")) {  // 周粒度
+			List<Map<String,Object>> weekList = DateUtils.getDateOfWeek(queryParam.getStartTime(), queryParam.getEndTime());
+			if(null != weekList && weekList.size() > 0) {
+				for(Map<String,Object> weekMap : weekList) {
+					if(null != weekMap && weekMap.containsKey("start")
+							&& weekMap.containsKey("end")
+							&& weekMap.containsKey("dayList")) {
+						String start = weekMap.get("start").toString();
+						String end = weekMap.get("end").toString();
+						List<String> dayList = (List<String>) weekMap.get("dayList");
+						Map<String,Object> map = new HashMap<String,Object>();
+						map.put("x", start +"-"+end);
+						map.put("y", getWeekPayAmt(dayList, list));
+						mapList.add(map);
+					}
+				}
+			}
+		}else {  // 日粒度
+			List<String> dayList = DateUtils.addDates(DateUtils.dateTime(queryParam.getStartTime()), DateUtils.dateTime(queryParam.getEndTime()));
+			if(null != dayList && dayList.size() > 0) {
+				for(String day : dayList) {
+					int payAmt = 0;
+					if(null != list && list.size() > 0) {
+						if(StringUtils.isNotBlank(day)) {
+							for(IndexVO indexVo : list) {
+								if(null != indexVo 
+										&& null != indexVo.getPayAmt()
+										&& StringUtils.isNotBlank(indexVo.getTime())
+										&& indexVo.getTime().equals(day)) {
+									payAmt = indexVo.getPayAmt();
+									break;
+								}
+							}
+						}
+					}
+					Map<String,Object> map = new HashMap<String,Object>();
+					map.put("x", day);
+					map.put("y", payAmt);
+					mapList.add(map);
+				}
+			}
+		}
+		return mapList;
+	} 
+	
+	
+	private int getWeekPayAmt(List<String> dayList, List<IndexVO> list) {
+		BigDecimal payAmt = new BigDecimal(0);
+		if(null != list && list.size() > 0
+				&& null != dayList && dayList.size() > 0) {
+			for(IndexVO indexVo : list) {
+				if(null != indexVo 
+						&& null != indexVo.getPayAmt()
+						&& StringUtils.isNotBlank(indexVo.getTime())
+						&& dayList.contains(indexVo.getTime())) {
+					payAmt = payAmt.add(new BigDecimal(indexVo.getPayAmt()));
+				}
+			}
+			return payAmt.intValue();
+		}
+		return 0;
+	}
+	
+	private int getMonthPayAmt(String month, List<IndexVO> list) {
+		BigDecimal payAmt = new BigDecimal(0);
+		if(null != list && list.size() > 0
+				&& StringUtils.isNotBlank(month)) {
+			for(IndexVO indexVo : list) {
+				if(null != indexVo 
+						&& null != indexVo.getPayAmt()
+						&& StringUtils.isNotBlank(indexVo.getTime())
+						&& indexVo.getTime().indexOf(month) >= 0) {
+					payAmt = payAmt.add(new BigDecimal(indexVo.getPayAmt()));
+				}
+			}
+			return payAmt.intValue();
+		}
+		return 0;
+	}
+	
+	
+	/**
+	 * 查询统计交易用户数
+	 * @return
+	 */
+	@PostMapping("/pay/user")
+	// @PreAuthorize("@ss.hasPermi('business:channel:list')")
+	public AjaxResult listPayUserData(@RequestBody IndexQueryParam indeQueryParam) {
+		
+		IndexQueryParam queryParam = getQueryParam(indeQueryParam);
+		
+		List<IndexVO> list = new ArrayList<IndexVO>();
+		QueryWrapper<UserTicketOrder> queryWrapper = new QueryWrapper<>();
+		queryWrapper.ge(null != queryParam && null != queryParam.getStartTime(), "t1.created_time", queryParam.getStartTime());
+		queryWrapper.le(null != queryParam && null != queryParam.getEndTime(), "t1.created_time", queryParam.getEndTime());
+		queryWrapper.gt("t1.`status`", 0);
+//		Long channelId = SecurityUtils.getLoginUser().getChannelId();
+//		if(null != channelId && 0 != channelId) {
+//			Channel channel = channelService.getById(channelId);
+//			if(null!=channel && StringUtils.isNotBlank(channel.getChannelNo())) {
+//				queryWrapper.and(wrapper -> wrapper.likeRight("t2.channel_no", channel.getChannelNo())
+//						.or().eq("t2.channel_no", channel.getChannelNo()));
+//			}
+//		}
+	
+		list = userTicketOrderService.selectIndexPayUserCntList(queryWrapper);
+		return  AjaxResult.success(getPayUserList(list, queryParam));
+	}
+	
+	private List<Map<String,Object>> getPayUserList(List<IndexVO> list, IndexQueryParam queryParam){
+		List<Map<String,Object>> mapList = new ArrayList<>();
+		if(null != queryParam && queryParam.getLevel().equals("month")) {  // 月粒度
+			List<String> monthList = DateUtils.addMonths(queryParam.getStartTime(), queryParam.getEndTime());
+			if(null != monthList && monthList.size() > 0) {
+				for(String month : monthList) {
+					if(StringUtils.isNotBlank(month)) {
+						Map<String,Object> map = new HashMap<String,Object>();
+						map.put("x", month);
+						map.put("y", getMonthPayUser(month, list));
+						mapList.add(map);
+					}
+				}
+			}
+		}else if(null != queryParam && queryParam.getLevel().equals("week")) {  // 周粒度
+			List<Map<String,Object>> weekList = DateUtils.getDateOfWeek(queryParam.getStartTime(), queryParam.getEndTime());
+			if(null != weekList && weekList.size() > 0) {
+				for(Map<String,Object> weekMap : weekList) {
+					if(null != weekMap && weekMap.containsKey("start")
+							&& weekMap.containsKey("end")
+							&& weekMap.containsKey("dayList")) {
+						String start = weekMap.get("start").toString();
+						String end = weekMap.get("end").toString();
+						List<String> dayList = (List<String>) weekMap.get("dayList");
+						Map<String,Object> map = new HashMap<String,Object>();
+						map.put("x", start +"-"+end);
+						map.put("y", getWeekPayUser(dayList, list));
+						mapList.add(map);
+					}
+				}
+			}
+		}else {  // 日粒度
+			List<String> dayList = DateUtils.addDates(DateUtils.dateTime(queryParam.getStartTime()), DateUtils.dateTime(queryParam.getEndTime()));
+			if(null != dayList && dayList.size() > 0) {
+				for(String day : dayList) {
+					int payUser = 0;
+					if(null != list && list.size() > 0) {
+						if(StringUtils.isNotBlank(day)) {
+							for(IndexVO indexVo : list) {
+								if(null != indexVo 
+										&& null != indexVo.getPayUserCnt()
+										&& StringUtils.isNotBlank(indexVo.getTime())
+										&& indexVo.getTime().equals(day)) {
+									payUser = indexVo.getPayUserCnt();
+									break;
+								}
+							}
+						}
+					}
+					Map<String,Object> map = new HashMap<String,Object>();
+					map.put("x", day);
+					map.put("y", payUser);
+					mapList.add(map);
+				}
+			}
+		}
+		return mapList;
+	} 
+	
+	
+	private int getWeekPayUser(List<String> dayList, List<IndexVO> list) {
+		int payUserCnt = 0;
+		if(null != list && list.size() > 0
+				&& null != dayList && dayList.size() > 0) {
+			for(IndexVO indexVo : list) {
+				if(null != indexVo 
+						&& null != indexVo.getPayUserCnt()
+						&& StringUtils.isNotBlank(indexVo.getTime())
+						&& dayList.contains(indexVo.getTime())) {
+					payUserCnt = payUserCnt + indexVo.getPayUserCnt();
+				}
+			}
+			return payUserCnt;
+		}
+		return 0;
+	}
+	
+	private int getMonthPayUser(String month, List<IndexVO> list) {
+		int payUserCnt = 0;
+		if(null != list && list.size() > 0
+				&& StringUtils.isNotBlank(month)) {
+			for(IndexVO indexVo : list) {
+				if(null != indexVo 
+						&& null != indexVo.getPayUserCnt()
+						&& StringUtils.isNotBlank(indexVo.getTime())
+						&& indexVo.getTime().indexOf(month) >= 0) {
+					payUserCnt = payUserCnt + indexVo.getPayUserCnt();
+				}
+			}
+			return payUserCnt;
+		}
+		return 0;
+	}
+	
+	
+	/**
+	 * 初始化查询参数
+	 * @param indeQueryParam
+	 * @return
+	 */
+	private IndexQueryParam getQueryParam(IndexQueryParam indeQueryParam) {
+		IndexQueryParam queryParam = new IndexQueryParam();
+		queryParam.setDays(null != indeQueryParam && null != indeQueryParam.getDays()?indeQueryParam.getDays(): 7);
+		queryParam.setLevel(null != indeQueryParam && StringUtils.isNotBlank(indeQueryParam.getLevel())?indeQueryParam.getLevel():"day");
+		if(queryParam.getDays() == 0) { // 自定义
+			if(null != indeQueryParam.getStartTime() && null != indeQueryParam.getEndTime()) {
+				queryParam.setStartTime(indeQueryParam.getStartTime());
+				queryParam.setEndTime(DateUtils.getEndTimeOfNow(indeQueryParam.getEndTime()));
+			}else {
+				queryParam.setStartTime(DateUtils.getPreDayOfNowZero(6));
+				queryParam.setEndTime(new Date());
+			}
+		}else {
+			queryParam.setStartTime(DateUtils.getPreDayOfNowZero(queryParam.getDays() - 1));
+			queryParam.setEndTime(new Date());
+		}
+		return queryParam;
+	}
+	
+	
+	/**
+	 * 查询统计新增经销商数量
+	 * @return
+	 */
+	@PostMapping("/site/increase")
+	// @PreAuthorize("@ss.hasPermi('business:channel:list')")
+	public AjaxResult listSiteIncreaseData(@RequestBody IndexQueryParam indeQueryParam) {
+		
+		IndexQueryParam queryParam = getQueryParam(indeQueryParam);
+		
+		List<IndexVO> list = new ArrayList<IndexVO>();
+		QueryWrapper<Channel> queryWrapper = new QueryWrapper<>();
+		queryWrapper.ge(null != queryParam && null != queryParam.getStartTime(), "t1.created_time", queryParam.getStartTime());
+		queryWrapper.le(null != queryParam && null != queryParam.getEndTime(), "t1.created_time", queryParam.getEndTime());
+		queryWrapper.eq("t1.`level`", 0);
+//		Long channelId = SecurityUtils.getLoginUser().getChannelId();
+//		if(null != channelId && 0 != channelId) {
+//			Channel channel = channelService.getById(channelId);
+//			if(null!=channel && StringUtils.isNotBlank(channel.getChannelNo())) {
+//				queryWrapper.and(wrapper -> wrapper.likeRight("t2.channel_no", channel.getChannelNo())
+//						.or().eq("t2.channel_no", channel.getChannelNo()));
+//			}
+//		}
+	
+		list = channelService.selectIndexSiteIncreaseList(queryWrapper);
+		return  AjaxResult.success(getSiteIncreaseList(list, queryParam));
+	}
+	
+	private List<Map<String,Object>> getSiteIncreaseList(List<IndexVO> list, IndexQueryParam queryParam){
+		List<Map<String,Object>> mapList = new ArrayList<>();
+		if(null != queryParam && queryParam.getLevel().equals("month")) {  // 月粒度
+			List<String> monthList = DateUtils.addMonths(queryParam.getStartTime(), queryParam.getEndTime());
+			if(null != monthList && monthList.size() > 0) {
+				for(String month : monthList) {
+					if(StringUtils.isNotBlank(month)) {
+						Map<String,Object> map = new HashMap<String,Object>();
+						map.put("x", month);
+						map.put("y", getMonthSiteIncrease(month, list));
+						mapList.add(map);
+					}
+				}
+			}
+		}else if(null != queryParam && queryParam.getLevel().equals("week")) {  // 周粒度
+			List<Map<String,Object>> weekList = DateUtils.getDateOfWeek(queryParam.getStartTime(), queryParam.getEndTime());
+			if(null != weekList && weekList.size() > 0) {
+				for(Map<String,Object> weekMap : weekList) {
+					if(null != weekMap && weekMap.containsKey("start")
+							&& weekMap.containsKey("end")
+							&& weekMap.containsKey("dayList")) {
+						String start = weekMap.get("start").toString();
+						String end = weekMap.get("end").toString();
+						List<String> dayList = (List<String>) weekMap.get("dayList");
+						Map<String,Object> map = new HashMap<String,Object>();
+						map.put("x", start +"-"+end);
+						map.put("y", getWeekSiteIncrease(dayList, list));
+						mapList.add(map);
+					}
+				}
+			}
+		}else {  // 日粒度
+			List<String> dayList = DateUtils.addDates(DateUtils.dateTime(queryParam.getStartTime()), DateUtils.dateTime(queryParam.getEndTime()));
+			if(null != dayList && dayList.size() > 0) {
+				for(String day : dayList) {
+					int newSiteCnt = 0;
+					if(null != list && list.size() > 0) {
+						if(StringUtils.isNotBlank(day)) {
+							for(IndexVO indexVo : list) {
+								if(null != indexVo 
+										&& null != indexVo.getNewSiteCnt()
+										&& StringUtils.isNotBlank(indexVo.getTime())
+										&& indexVo.getTime().equals(day)) {
+									newSiteCnt = indexVo.getNewSiteCnt();
+									break;
+								}
+							}
+						}
+					}
+					
+					Map<String,Object> map = new HashMap<String,Object>();
+					map.put("x", day);
+					map.put("y", newSiteCnt);
+					mapList.add(map);
+				}
+			}
+		}
+		return mapList;
+	} 
+	
+	
+	private int getWeekSiteIncrease(List<String> dayList, List<IndexVO> list) {
+		int newSiteCnt = 0;
+		if(null != list && list.size() > 0
+				&& null != dayList && dayList.size() > 0) {
+			for(IndexVO indexVo : list) {
+				if(null != indexVo 
+						&& null != indexVo.getNewSiteCnt()
+						&& StringUtils.isNotBlank(indexVo.getTime())
+						&& dayList.contains(indexVo.getTime())) {
+					newSiteCnt = newSiteCnt + indexVo.getNewSiteCnt();
+				}
+			}
+			return newSiteCnt;
+		}
+		return 0;
+	}
+	
+	private int getMonthSiteIncrease(String month, List<IndexVO> list) {
+		int newSiteCnt = 0;
+		if(null != list && list.size() > 0
+				&& StringUtils.isNotBlank(month)) {
+			for(IndexVO indexVo : list) {
+				if(null != indexVo 
+						&& null != indexVo.getNewSiteCnt()
+						&& StringUtils.isNotBlank(indexVo.getTime())
+						&& indexVo.getTime().indexOf(month) >= 0) {
+					newSiteCnt = newSiteCnt + indexVo.getNewSiteCnt();
+				}
+			}
+			return newSiteCnt;
+		}
+		return 0;
+	}
+	
+	
+	/**
+	 * 查询统计交易金额
+	 * @return
+	 */
+	@PostMapping("/daily")
+	// @PreAuthorize("@ss.hasPermi('business:channel:list')")
+	public AjaxResult listDailyData(@RequestBody IndexQueryParam indeQueryParam) {
+		
+		IndexQueryParam queryParam = new IndexQueryParam();
+		queryParam.setStartTime(DateUtils.getPreDayOfNowZero(1));  // 昨天
+		queryParam.setEndTime(new Date());  // 今天
+		
+		List<IndexVO> list = new ArrayList<IndexVO>();
+		List<IndexVO> siteList = new ArrayList<IndexVO>();
+		
+		QueryWrapper<UserTicketOrder> queryWrapper = new QueryWrapper<>();
+		queryWrapper.ge(null != queryParam && null != queryParam.getStartTime(), "t1.created_time", queryParam.getStartTime());
+		queryWrapper.le(null != queryParam && null != queryParam.getEndTime(), "t1.created_time", queryParam.getEndTime());
+		queryWrapper.gt("t1.`status`", 0);
+		
+
+		QueryWrapper<Channel> siteQueryWrapper = new QueryWrapper<>();
+		siteQueryWrapper.ge(null != queryParam && null != queryParam.getStartTime(), "t1.created_time", queryParam.getStartTime());
+		siteQueryWrapper.le(null != queryParam && null != queryParam.getEndTime(), "t1.created_time", queryParam.getEndTime());
+		siteQueryWrapper.eq("t1.`level`", 0);
+		
+//		Long channelId = SecurityUtils.getLoginUser().getChannelId();
+//		if(null != channelId && 0 != channelId) {
+//			Channel channel = channelService.getById(channelId);
+//			if(null!=channel && StringUtils.isNotBlank(channel.getChannelNo())) {
+//				queryWrapper.and(wrapper -> wrapper.likeRight("t2.channel_no", channel.getChannelNo())
+//						.or().eq("t2.channel_no", channel.getChannelNo()));
+//				
+//				siteQueryWrapper.and(wrapper -> wrapper.likeRight("t2.channel_no", channel.getChannelNo())
+//						.or().eq("t2.channel_no", channel.getChannelNo()));
+//			}
+//		}
+	
+		list = userTicketOrderService.selectIndexDailyInfoList(queryWrapper);
+	
+		siteList = channelService.selectIndexSiteIncreaseList(siteQueryWrapper);
+		
+		return  AjaxResult.success(getDailyInfoData(list, siteList));
+	}
+	
+	
+	private Map<String,Object> getDailyInfoData(List<IndexVO> list,List<IndexVO> siteList){
+		Map<String,Object> payAmt = new HashMap<String,Object>();
+		Map<String,Object> payUser = new HashMap<String,Object>();
+		Map<String,Object> ticketNum = new HashMap<String,Object>();
+		Map<String,Object> newSite = new HashMap<String,Object>();
+		String today = DateUtils.parseDateToStr(DateUtils.YYYYMMDD,new Date());
+		
+		int todayPayAmt = 0;
+		int todayPayUserCnt = 0;
+		int todayTicketNum = 0;
+		int todayNewSiteCnt = 0;
+		
+		int yesterdayPayAmt = 0;
+		int yesterdayPayUserCnt = 0;
+		int yesterdayTicketNum = 0;
+		int yesterdayNewSiteCnt = 0;
+		
+		if(null != list && list.size() > 0) {
+			for(IndexVO indexVo : list) {
+				if(null != indexVo 
+						&& StringUtils.isNotBlank(indexVo.getTime())) {
+					if(today.equals(indexVo.getTime())) {
+						todayPayAmt =  null != indexVo.getPayAmt()?indexVo.getPayAmt():0;
+						todayPayUserCnt =  null != indexVo.getPayUserCnt()?indexVo.getPayUserCnt():0;
+						todayTicketNum = null != indexVo.getTicketNum()?indexVo.getTicketNum():0;
+					}else {
+						yesterdayPayAmt = null != indexVo.getPayAmt()?indexVo.getPayAmt():0;
+						yesterdayPayUserCnt = null != indexVo.getPayUserCnt()?indexVo.getPayUserCnt():0;
+						yesterdayTicketNum =  null != indexVo.getTicketNum()?indexVo.getTicketNum():0;
+					}
+				}
+			}
+		}
+		if(null != siteList && siteList.size() > 0) {
+			for(IndexVO indexVo : siteList) {
+				if(null != indexVo 
+						&& null != indexVo.getNewSiteCnt()
+						&& StringUtils.isNotBlank(indexVo.getTime())) {
+					if(today.equals(indexVo.getTime())) {
+						todayNewSiteCnt = null != indexVo.getNewSiteCnt()?indexVo.getNewSiteCnt():0;
+					}else {
+						yesterdayNewSiteCnt = null != indexVo.getNewSiteCnt()?indexVo.getNewSiteCnt():0;
+					}
+				}
+			}
+		}
+		payAmt.put("today", todayPayAmt);
+		payAmt.put("yesterday", yesterdayPayAmt);
+		payUser.put("today", todayPayUserCnt);
+		payUser.put("yesterday", yesterdayPayUserCnt);
+		ticketNum.put("today", todayTicketNum);
+		ticketNum.put("yesterday", yesterdayTicketNum);
+		newSite.put("today", todayNewSiteCnt);
+		newSite.put("yesterday", yesterdayNewSiteCnt);
+		
+		Map<String,Object> map = new HashMap<String,Object>();
+		map.put("payAmt", payAmt);
+		map.put("payUser", payUser);
+		map.put("ticketNum", ticketNum);
+		map.put("newSite", newSite);
+		return map;
+	} 
+	
+	/**
+	 * 查询统计统计票组销售TOP10
+	 * @return
+	 */
+	@PostMapping("/ticket/box/top")
+	// @PreAuthorize("@ss.hasPermi('business:channel:list')")
+	public AjaxResult ticketBoxTopData(@RequestBody IndexQueryParam indeQueryParam) {
+		
+		IndexQueryParam queryParam = getQueryParam(indeQueryParam);
+		List<IndexVO> list = new ArrayList<IndexVO>();
+		QueryWrapper<UserTicketOrder> queryWrapper = new QueryWrapper<>();
+		queryWrapper.ge(null != queryParam && null != queryParam.getStartTime(), "t1.created_time", queryParam.getStartTime());
+		queryWrapper.le(null != queryParam && null != queryParam.getEndTime(), "t1.created_time", queryParam.getEndTime());
+		queryWrapper.gt("t1.`status`", 0);
+		
+//		Long channelId = SecurityUtils.getLoginUser().getChannelId();
+//		if(null != channelId && 0 != channelId) {
+//			Channel channel = channelService.getById(channelId);
+//			if(null!=channel && StringUtils.isNotBlank(channel.getChannelNo())) {
+//				queryWrapper.and(wrapper -> wrapper.likeRight("t2.channel_no", channel.getChannelNo())
+//						.or().eq("t2.channel_no", channel.getChannelNo()));
+//				
+//			}
+//		}
+	
+		list = userTicketOrderService.selectIndexTicketBoxTop(queryWrapper);
+		List<Map<String,Object>> mapList = new ArrayList<>();
+		if(null != list && list.size() > 0) {
+			for(IndexVO indexVo : list) {
+				if(null != indexVo 
+						&& StringUtils.isNotBlank(indexVo.getTitle())
+						&& null != indexVo.getPayAmt()) {
+					Map<String,Object> map = new HashMap<String,Object>();
+					map.put("x", indexVo.getTitle());
+					map.put("y", indexVo.getPayAmt());
+					mapList.add(map);
+				}
+			}
+		}
+		return  AjaxResult.success(mapList);
+	}
+	
+	
+	/**
+	 * 统计经销商交易额TOP10
+	 * @return
+	 */
+	@PostMapping("/ticket/site/top")
+	// @PreAuthorize("@ss.hasPermi('business:channel:list')")
+	public AjaxResult ticketSiteTopData(@RequestBody IndexQueryParam indeQueryParam) {
+		
+		IndexQueryParam queryParam = getQueryParam(indeQueryParam);
+		List<IndexVO> list = new ArrayList<IndexVO>();
+		QueryWrapper<UserTicketOrder> queryWrapper = new QueryWrapper<>();
+		queryWrapper.ge(null != queryParam && null != queryParam.getStartTime(), "t1.created_time", queryParam.getStartTime());
+		queryWrapper.le(null != queryParam && null != queryParam.getEndTime(), "t1.created_time", queryParam.getEndTime());
+		queryWrapper.gt("t1.`status`", 0);
+		
+//		Long channelId = SecurityUtils.getLoginUser().getChannelId();
+//		if(null != channelId && 0 != channelId) {
+//			Channel channel = channelService.getById(channelId);
+//			if(null!=channel && StringUtils.isNotBlank(channel.getChannelNo())) {
+//				queryWrapper.and(wrapper -> wrapper.likeRight("t2.channel_no", channel.getChannelNo())
+//						.or().eq("t2.channel_no", channel.getChannelNo()));
+//				
+//			}
+//		}
+	
+		list = userTicketOrderService.selectIndexTicketSiteTop(queryWrapper);
+		List<Map<String,Object>> mapList = new ArrayList<>();
+		if(null != list && list.size() > 0) {
+			for(IndexVO indexVo : list) {
+				if(null != indexVo 
+						&& StringUtils.isNotBlank(indexVo.getName())
+						&& null != indexVo.getPayAmt()) {
+					Map<String,Object> map = new HashMap<String,Object>();
+					map.put("x", indexVo.getName());
+					map.put("y", indexVo.getPayAmt());
+					mapList.add(map);
+				}
+			}
+		}
+		return  AjaxResult.success(mapList);
+	}
+
+
+}

+ 152 - 23
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/SaleSiteMgrController.java

@@ -3,8 +3,11 @@ package com.qs.mp.web.controller.api.admin;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qs.mp.admin.domain.vo.TicketCntVO;
+import com.qs.mp.admin.service.ITicketService;
 import com.qs.mp.channel.domain.Channel;
 import com.qs.mp.channel.domain.ChannelOrder;
+import com.qs.mp.channel.domain.ChannelOrderDetail;
 import com.qs.mp.channel.domain.ChannelUserRel;
 import com.qs.mp.channel.domain.param.ChannelParam;
 import com.qs.mp.channel.domain.param.SaleSiteParam;
@@ -13,13 +16,18 @@ import com.qs.mp.channel.domain.vo.ChannelVO;
 import com.qs.mp.channel.service.IChannelOrderService;
 import com.qs.mp.channel.service.IChannelService;
 import com.qs.mp.channel.service.IChannelUserRelService;
+import com.qs.mp.common.annotation.Log;
 import com.qs.mp.common.constant.UserConstants;
 import com.qs.mp.common.core.domain.AjaxResult;
 import com.qs.mp.common.core.page.TableDataInfo;
+import com.qs.mp.common.enums.BusinessType;
 import com.qs.mp.common.enums.ChannelRoleEnum;
 import com.qs.mp.common.enums.ErrorCodeEnum;
+import com.qs.mp.common.enums.UserTicketOrderStatusEnum;
 import com.qs.mp.system.domain.SysUser;
 import com.qs.mp.system.service.ISysUserService;
+import com.qs.mp.user.domain.UserTicketOrder;
+import com.qs.mp.user.service.IUserTicketOrderService;
 import com.qs.mp.web.controller.common.BaseApiController;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -29,9 +37,11 @@ import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.stereotype.Component;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.PostMapping;
@@ -52,16 +62,22 @@ public class SaleSiteMgrController extends BaseApiController {
 
 	@Autowired
 	private IChannelService channelService;
-	
+
 	@Autowired
 	private IChannelUserRelService channelUserRelService;
-	
+
 	@Autowired
 	private IChannelOrderService channelOrderService;
 	
+	@Autowired
+	private IUserTicketOrderService userTicketOrderService;
+
 	@Autowired
 	private ISysUserService userService;
 	
+	@Autowired
+	private ITicketService ticketService;
+
 	@Autowired
 	private MapperFacade mapperFacade;
 
@@ -72,7 +88,8 @@ public class SaleSiteMgrController extends BaseApiController {
 	 * @return
 	 */
 	@PostMapping("/list")
-	public TableDataInfo listChannel(@RequestBody Channel channel) {
+	@PreAuthorize("@ss.hasPermi('business:salesite:list')")
+	public TableDataInfo listSite(@RequestBody Channel channel) {
 		List<ChannelVO> list = new ArrayList<ChannelVO>();
 		startPage();
 		QueryWrapper<Channel> queryWrapper = new QueryWrapper<>();
@@ -85,11 +102,34 @@ public class SaleSiteMgrController extends BaseApiController {
 		queryWrapper.eq(null != channel && null != channel.getProvinceId(), "t1.province_id", channel.getProvinceId());
 		queryWrapper.eq(null != channel && null != channel.getCityId(), "t1.city_id", channel.getCityId());
 		queryWrapper.eq(null != channel && null != channel.getAreaId(), "t1.area_id", channel.getAreaId());
-		queryWrapper.orderByAsc("t1.channel_id");
+		queryWrapper.orderByDesc("t1.channel_id");
 		list = channelService.selectChannelVoList(queryWrapper);
+		List<Long> channelIds = new ArrayList<Long>();
 		if(null != list && list.size() > 0) {
 			for(ChannelVO channelVO : list) {
-				if(null != channelVO && StringUtils.isNotBlank(channelVO.getChannelNo())) {
+				if(null != channelVO && null != channelVO.getChannelId()
+						&& StringUtils.isNotBlank(channelVO.getChannelNo())) {
+					channelIds.add(channelVO.getChannelId());
+ 				}
+			}
+		}
+		List<TicketCntVO>  qtyCntList = new ArrayList<TicketCntVO>();
+		List<TicketCntVO>  saleCntList = new ArrayList<TicketCntVO>();
+		if(null != channelIds && channelIds.size() > 0) {
+			QueryWrapper<ChannelOrderDetail> ticketQtyCntQueryWrapper = new QueryWrapper<ChannelOrderDetail>();
+			ticketQtyCntQueryWrapper.in("t1.channel_id", channelIds);
+			qtyCntList = ticketService.listTicketQtyCnt(ticketQtyCntQueryWrapper);
+			
+	    	QueryWrapper<UserTicketOrder> ticketSaleCntQueryWrapper = new QueryWrapper<UserTicketOrder>();
+	    	ticketSaleCntQueryWrapper.in("t1.channel_id", channelIds);
+	    	ticketSaleCntQueryWrapper.eq("t1.`status`", 1);
+	    	saleCntList = userTicketOrderService.listTicketSaleCnt(ticketSaleCntQueryWrapper);
+		}
+		
+		if(null != list && list.size() > 0) {
+			for(ChannelVO channelVO : list) {
+				if(null != channelVO && null != channelVO.getChannelId()
+						&& StringUtils.isNotBlank(channelVO.getChannelNo())) {
 					// int siteCnt = channelService.getChannelSiteCnt(channelVO.getChannelNo());
 					LambdaQueryWrapper<ChannelUserRel> userCntQueryWrapper = new LambdaQueryWrapper<ChannelUserRel>();
 					userCntQueryWrapper.eq(ChannelUserRel::getChannelId, channelVO.getChannelId());
@@ -98,21 +138,88 @@ public class SaleSiteMgrController extends BaseApiController {
 					// 查询用户信息
 					//SysUser sysUser = userService.selectUserById(channelVO.getUserId());
 					// channelVO.setSysUser(sysUser);
+					channelVO.setParentsName(getParentsName(channelVO.getChannelNo()));
+					// 统计盲票库存, 销量
+					if(null != qtyCntList && qtyCntList.size() > 0) {
+						List<TicketCntVO> voList =  qtyCntList.stream().filter(item  -> item.getChannelId().equals(channelVO.getChannelId()))
+				                .collect(Collectors.toList());
+						if(null != voList && voList.size() > 0) {
+							TicketCntVO ticketQtyCnt =  voList.get(0);
+							channelVO.setOffLineQtyCnt(null != ticketQtyCnt?ticketQtyCnt.getOffLineQtyCnt():0);
+						}
+					}
+					if(null != saleCntList && saleCntList.size() > 0) {
+						List<TicketCntVO> voList =  saleCntList.stream().filter(item  -> item.getChannelId().equals(channelVO.getChannelId()))
+				                .collect(Collectors.toList());
+						if(null != voList && voList.size() > 0) {
+							TicketCntVO ticketSaleCnt =  voList.get(0);
+							channelVO.setOffLineSaleCnt(null != ticketSaleCnt?ticketSaleCnt.getOffLineSaleCnt():0);
+							channelVO.setOnLineSaleCnt(null != ticketSaleCnt?ticketSaleCnt.getOnLineSaleCnt():0);
+						}
+					}
  				}
 			}
 		}
 		return getDataTable(list);
 	}
 	
-	
+	// 获取上级渠道迭代
+	private String getParentsName(String channelNo) {
+		if(StringUtils.isNotBlank(channelNo)) {
+			String[] noArray = channelNo.split("\\.");
+			if(null != noArray && noArray.length > 0) {
+				List<String> noList = new ArrayList<String>();
+				String parentNo = "";
+				for (int i = 0; i < noArray.length; i++) {
+					if(null != noArray[i] && StringUtils.isNotBlank(noArray[i])) {
+						parentNo += (i>0?".":"")+noArray[i];
+						if(StringUtils.isNotBlank(parentNo) && !parentNo.equals(channelNo)) {
+							noList.add(parentNo);
+						}
+					}
+				}
+				if(noList.size() > 0 ) {
+					LambdaQueryWrapper<Channel> queryWrapper = new LambdaQueryWrapper<Channel>();
+					queryWrapper.gt(Channel::getLevel, 0);
+					queryWrapper.in(Channel::getChannelNo,noList);
+					queryWrapper.orderByAsc(Channel::getLevel);
+					List<Channel> list = channelService.list(queryWrapper);
+					if(null != list && list.size() >0) {
+						String names = list.stream().map(Channel::getName).collect(Collectors.joining(" > "));
+						return names;
+					}
+				}
+			}
+		}
+		return "";
+	}
+
+	/**
+	 * 查询所有渠道列表
+	 *
+	 * @return
+	 */
+	@PostMapping("/listAll")
+	// @PreAuthorize("@ss.hasPermi('business:salesite:list')")
+	public AjaxResult listAllSite() {
+		List<Channel> list = new ArrayList<Channel>();
+		LambdaQueryWrapper<Channel> queryWrapper = new LambdaQueryWrapper<Channel>();
+		queryWrapper.eq(Channel::getLevel, 0);
+		queryWrapper.orderByDesc(Channel::getChannelId);
+		list = channelService.list(queryWrapper);
+		return AjaxResult.success(list);
+	}
+
 	/**
 	 * 新增经销商信息
 	 * @param
 	 * @return
 	 */
+	@Log(title = "新增经销商", businessType = BusinessType.INSERT)
 	@ApiOperation(value = "新增经销商信息", notes = "经销商端新增经销商")
 	@PostMapping("/create")
-	public AjaxResult channelCreate(@Validated @RequestBody SaleSiteParam channelParam) {
+	@PreAuthorize("@ss.hasPermi('business:salesite:add')")
+	public AjaxResult siteCreate(@Validated @RequestBody SaleSiteParam channelParam) {
 		if (channelParam.getChannelId() != null && channelParam.getChannelId() != 0) {
 			return AjaxResult.error("该经销商已存在");
 		}
@@ -134,7 +241,7 @@ public class SaleSiteMgrController extends BaseApiController {
 		if(null != channel.getParentId() && channel.getParentId() != 0) {
 			Channel parentChannel = channelService.getById(channel.getParentId());
 			if(null != parentChannel) {
-				 if(null != parentChannel.getCommRate() 
+				 if(null != parentChannel.getCommRate()
 						 && channel.getCommRate().compareTo(parentChannel.getCommRate()) > 0) {
 					 return AjaxResult.error("佣金比例不能高于父经销商的佣金比例");
 				 }
@@ -143,7 +250,7 @@ public class SaleSiteMgrController extends BaseApiController {
 			}else {
 				return AjaxResult.error("父经销商不存在");
 			}
-			
+
 		}else {
 			channel.setLevel(1);
 			channel.setChannelNo("");
@@ -154,7 +261,7 @@ public class SaleSiteMgrController extends BaseApiController {
 		} catch (Exception e) {
 			return AjaxResult.error("经销商'" + channel.getName() + "'新增失败" + e.getMessage());
 		}
-		
+
 		return AjaxResult.success("经销商'" + channel.getName() + "'新增成功");
 	}
 
@@ -163,9 +270,11 @@ public class SaleSiteMgrController extends BaseApiController {
 	 * @param
 	 * @return
 	 */
+	@Log(title = "修改经销商", businessType = BusinessType.UPDATE)
 	@ApiOperation(value = "编辑经销商信息", notes = "经销商端编辑经销商")
 	@PostMapping("/update")
-	public AjaxResult channelUpdate(@Validated @RequestBody ChannelParam channelParam) {
+	@PreAuthorize("@ss.hasPermi('business:salesite:edit')")
+	public AjaxResult siteUpdate(@Validated @RequestBody ChannelParam channelParam) {
 		if (null == channelParam || null == channelParam.getChannelId()) {
 			return error(ErrorCodeEnum.ERROR_CODE_1001);
 		}
@@ -200,7 +309,7 @@ public class SaleSiteMgrController extends BaseApiController {
 		// 3.校验佣金比例,不能高于其父经销商的佣金比例,不能低于其子经销商的最大佣金比例
 		Channel parentChannel = channelService.getById(oldChannel.getParentId());
 		if(null != parentChannel) {
-			 if(null != parentChannel.getCommRate() 
+			 if(null != parentChannel.getCommRate()
 					 && channel.getCommRate().compareTo(parentChannel.getCommRate()) > 0) {
 				 return AjaxResult.error("佣金比例不能高于父经销商的佣金比例");
 			 }
@@ -210,22 +319,25 @@ public class SaleSiteMgrController extends BaseApiController {
 			return AjaxResult.error("父经销商不存在");
 		}
 		try {
+			channel.setUserId(oldChannel.getUserId());
 			channelService.updateChannel(channel, mobileChange);
 		} catch (Exception e) {
 			return AjaxResult.error(e.getMessage());
 		}
 		return AjaxResult.success("经销商'" + channel.getName() + "'编辑成功");
 	}
-	
-	
+
+
 	/**
 	 * 停用、启用经销商
 	 * @param
 	 * @return
 	 */
+	@Log(title = "经销商启用停用", businessType = BusinessType.UPDATE)
 	@ApiOperation(value = "停用、启用经销商信息", notes = "经销商管理编辑经销商")
 	@PostMapping("/status")
-	public AjaxResult channelStatus(@RequestBody JSONObject jsonObject) {
+	@PreAuthorize("@ss.hasPermi('business:salesite:edit')")
+	public AjaxResult siteStatus(@RequestBody JSONObject jsonObject) {
 		String channelId = jsonObject.containsKey("channelId")?jsonObject.get("channelId").toString():"";
 		String status = jsonObject.containsKey("status")?jsonObject.get("status").toString():"";
 		if (null == jsonObject || StringUtils.isBlank(channelId)
@@ -247,8 +359,8 @@ public class SaleSiteMgrController extends BaseApiController {
 		}
 		return AjaxResult.success("操作成功");
 	}
-	
-	
+
+
 	/**
 	 * 查询经销商详情
 	 * @param
@@ -256,7 +368,8 @@ public class SaleSiteMgrController extends BaseApiController {
 	 */
 	@ApiOperation(value = "查询经销商详情信息", notes = "经销商管理编辑子经销商查询经销商详情")
 	@PostMapping("/detail")
-	public AjaxResult getChannelDetail(@RequestBody JSONObject jsonObject) {
+	@PreAuthorize("@ss.hasPermi('business:salesite:query')")
+	public AjaxResult getSiteDetail(@RequestBody JSONObject jsonObject) {
 		String channelId = (null != jsonObject && jsonObject.containsKey("channelId"))?jsonObject.getString("channelId"):"";
 		if (StringUtils.isBlank(channelId)) {
 			return error(ErrorCodeEnum.ERROR_CODE_1001);
@@ -271,15 +384,31 @@ public class SaleSiteMgrController extends BaseApiController {
 			userCntQueryWrapper.eq(ChannelUserRel::getChannelId, channelVO.getChannelId());
 			int userCnt = channelUserRelService.count(userCntQueryWrapper);
 			channelVO.setUserCnt(userCnt);
+			channelVO.setParentsName(getParentsName(channelVO.getChannelNo()));
 		}
 	    // 查询经销商销售额、佣金收入、订单数等
 	    ChannelOperDataVO channelOperDataVO = channelService.getChannelTotalOperData(channelVO.getChannelNo());
-		LambdaQueryWrapper<ChannelOrder> queryWrapper = new LambdaQueryWrapper<ChannelOrder>();
-		queryWrapper.eq(ChannelOrder::getChannelId, channelId);
-		int orderCnt = channelOrderService.count(queryWrapper);
-		channelOperDataVO.setOrderCnt(orderCnt);
+		
+		// 盲票销售张数
+		int ticketSaleCnt = userTicketOrderService.getSaleSiteTotalTicketNumCnt(channelVO.getChannelId());
+		channelOperDataVO.setTicketSaleCnt(ticketSaleCnt);
 	    channelVO.setOperData(channelOperDataVO);
+	    
+        if(null != channelVO && null != channelVO.getChannelId()) {
+	    	LambdaQueryWrapper<ChannelUserRel> userCntQueryWrapper = new LambdaQueryWrapper<ChannelUserRel>();
+			userCntQueryWrapper.eq(ChannelUserRel::getChannelId, channelVO.getChannelId());
+			int userCnt = channelUserRelService.count(userCntQueryWrapper);
+			channelVO.setUserCnt(userCnt);
+	    	
+	    	int ticketQtyCnt = ticketService.getTicketQtyCnt(channelVO.getChannelId());
+	    	channelVO.setOffLineQtyCnt(ticketQtyCnt);
+	    	
+	    	TicketCntVO ticketCnt = userTicketOrderService.getTicketSaleCnt(channelVO.getChannelId());
+			channelVO.setOffLineSaleCnt(null != ticketCnt?ticketCnt.getOffLineSaleCnt():0);
+			channelVO.setOnLineSaleCnt(null != ticketCnt?ticketCnt.getOnLineSaleCnt():0);
+	    }
+	    
 		return AjaxResult.success(channelVO);
 	}
-	
+
 }

+ 182 - 21
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/TicketBoxMgrController.java

@@ -1,14 +1,22 @@
 package com.qs.mp.web.controller.api.admin;
 
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
 import com.qs.mp.admin.domain.Ticket;
+import com.qs.mp.admin.domain.TicketAwards;
+import com.qs.mp.admin.domain.TicketAwardsPrize;
 import com.qs.mp.admin.domain.TicketBox;
 import com.qs.mp.admin.domain.excel.TicketExcel;
 import com.qs.mp.admin.domain.param.BathIdParam;
 import com.qs.mp.admin.domain.param.TicketBoxCreateParam;
+import com.qs.mp.admin.domain.param.TicketBoxParam;
+import com.qs.mp.admin.domain.vo.TicketAwardsVO;
+import com.qs.mp.admin.domain.vo.TicketBoxVO;
+import com.qs.mp.admin.service.ITicketAwardsPrizeService;
+import com.qs.mp.admin.service.ITicketAwardsService;
 import com.qs.mp.admin.service.ITicketBoxService;
 import com.qs.mp.admin.service.ITicketService;
 import com.qs.mp.channel.domain.Channel;
@@ -23,9 +31,13 @@ import com.qs.mp.common.core.page.TableDataInfo;
 import com.qs.mp.common.enums.BusinessType;
 import com.qs.mp.common.enums.ChannelRoleEnum;
 import com.qs.mp.common.enums.ErrorCodeEnum;
+import com.qs.mp.common.enums.MqTopicType;
+import com.qs.mp.common.enums.ServerEnvEnum;
 import com.qs.mp.common.enums.TicketBoxStatusEnum;
 import com.qs.mp.common.enums.TicketTypeEnum;
+import com.qs.mp.common.pulsar.PulsarClientService;
 import com.qs.mp.common.utils.LogUtil;
+import com.qs.mp.common.utils.RSAUtil;
 import com.qs.mp.system.domain.SysUser;
 import com.qs.mp.system.service.ISysUserService;
 import com.qs.mp.utils.ExcelUtil;
@@ -34,10 +46,13 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import java.math.BigDecimal;
 import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import ma.glasnost.orika.MapperFacade;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.pulsar.client.api.PulsarClientException;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.security.access.prepost.PreAuthorize;
@@ -65,45 +80,80 @@ public class TicketBoxMgrController extends BaseApiController {
 	private ITicketBoxService ticketBoxService;
 
 	@Autowired
-	private IChannelUserRelService channelUserRelService;
+	private ITicketService ticketService;
 
 	@Autowired
-	private ISysUserService userService;
+	private ITicketAwardsPrizeService ticketAwardsPrizeService;
 
 	@Autowired
-	private ITicketService ticketService;
+	private ITicketAwardsService ticketAwardsService;
 
 	@Autowired
-	private MapperFacade mapperFacade;
-
-
-	@Value("${wx-channel.appId}")
-	private String channelAppId;
+	private PulsarClientService pulsarClientService;
 
+	@Autowired
+	private MapperFacade mapperFacade;
 
 	@Value("${mp.exportUrl}")
 	private String exportUrl;
 
+	@Value("${export.page-size}")
+	private int pageSize;
+
+	@Value("${server.env}")
+	private String env;
+
 	/**
 	 * 查询所有盲票组列表
 	 *
 	 * @return
 	 */
 	@PostMapping("/list")
+	@PreAuthorize("@ss.hasPermi('business:ticket:list')")
 	public TableDataInfo list(@RequestBody TicketBox ticketBox) {
 		startPage();
-		List<TicketBox> list = ticketBoxService.list(new QueryWrapper<>());
+		QueryWrapper<TicketBox> queryWrapper = new QueryWrapper<TicketBox>();
+		queryWrapper.like(null != ticketBox && StringUtils.isNotBlank(ticketBox.getTitle()), "title", ticketBox.getTitle());
+		queryWrapper.eq(null != ticketBox && null != ticketBox.getType(), "type", ticketBox.getType());
+		queryWrapper.eq(null != ticketBox && null != ticketBox.getStatus(), "status", ticketBox.getStatus());
+		queryWrapper.orderByAsc("FIELD(`status`, 'wait', 'doing', 'done', 'on', 'off')").orderByDesc("box_id");
+		List<TicketBox> list = ticketBoxService.list(queryWrapper);
 		return getDataTable(list);
 	}
 
+	/**
+	 * 查看盲票详情
+	 */
+	@PostMapping("/detail")
+	@PreAuthorize("@ss.hasPermi('business:ticket:query')")
+	@ApiOperation(value = "查看盲票详情" , notes = "根据盲票组ID,获取盲票信息")
+	public AjaxResult getInfo(@RequestBody TicketBoxParam param) {
+		if (com.qs.mp.common.utils.StringUtils.isBlank(param.getBoxId())) {
+			return AjaxResult.error("参数异常,盲票组ID缺失");
+		}
+		TicketBox ticketBox = ticketBoxService.getById(param.getBoxId());
+		TicketBoxVO ticketBoxVO = mapperFacade.map(ticketBox, TicketBoxVO.class);
+		List<TicketAwards> ticketAwardsList = ticketAwardsService.list(new LambdaQueryWrapper<TicketAwards>()
+				.eq(TicketAwards::getBoxId, ticketBox.getBoxId()).orderByAsc(TicketAwards::getSort));
+		List<TicketAwardsVO> ticketAwardsVOS = mapperFacade.mapAsList(ticketAwardsList, TicketAwardsVO.class);
+		for (TicketAwardsVO ticketAwardsVO : ticketAwardsVOS) {
+			ticketAwardsVO.setPrizeList(ticketAwardsPrizeService.list(new LambdaQueryWrapper<TicketAwardsPrize>()
+					.eq(TicketAwardsPrize::getAwardsId, ticketAwardsVO.getAwardsId())));
+		}
+		ticketBoxVO.setAwardsList(ticketAwardsVOS);
+		return AjaxResult.success(ticketBoxVO);
+	}
+
 	/**
 	 * 新增盲票
 	 *
 	 * @param
 	 * @return
 	 */
+	@Log(title = "盲票新增", businessType = BusinessType.INSERT)
 	@ApiOperation(value = "新增盲票", notes = "管理端创建盲票")
 	@PostMapping("/create")
+	@PreAuthorize("@ss.hasPermi('business:ticket:add')")
 	public AjaxResult create(@Validated @RequestBody TicketBoxCreateParam param) {
 		if (param.getType() == TicketTypeEnum.OFFLINE) {
 			if (param.getPkgSalePrice() == null || param.getPkgSalePrice() == 0) {
@@ -113,8 +163,16 @@ public class TicketBoxMgrController extends BaseApiController {
 				return AjaxResult.error("每包张数必须大于0");
 			}
 		}
-		boolean rtn = ticketBoxService.createTicketBox(param);
-		return rtn ? AjaxResult.success() : AjaxResult.error("创建失败");
+		String boxId = ticketBoxService.createTicketBox(param);
+		if (StringUtils.isNotBlank(boxId)) {
+			try {
+				pulsarClientService.producer(MqTopicType.ticket_generate, boxId);
+			} catch (PulsarClientException e) {
+				LogUtil.error(logger, e, "盲票组保存成功,发送异步消息失败. {0}", boxId);
+			}
+			return AjaxResult.success();
+		}
+		return AjaxResult.error("创建失败");
 	}
 
 	/**
@@ -123,8 +181,10 @@ public class TicketBoxMgrController extends BaseApiController {
 	 * @param
 	 * @return
 	 */
+	@Log(title = "盲票上下架", businessType = BusinessType.UPDATE)
 	@ApiOperation(value = "盲票上下架", notes = "管理端盲票上下架")
 	@PostMapping("/put")
+	@PreAuthorize("@ss.hasPermi('business:ticket:on')")
 	public AjaxResult putOnOff(@RequestBody TicketBox param) {
 		if (StringUtils.isBlank(param.getBoxId()) || param.getStatus() == null) {
 				return AjaxResult.error("参数缺失");
@@ -134,7 +194,9 @@ public class TicketBoxMgrController extends BaseApiController {
 			if (ticketBox.getStatus() != TicketBoxStatusEnum.PUT_ON) {
 				return AjaxResult.error("当前状态不是已上架,不能下架");
 			}
-			ticketBoxService.update(new LambdaUpdateWrapper<TicketBox>().set(TicketBox::getStatus, TicketBoxStatusEnum.PUT_OFF)
+			ticketBoxService.update(new LambdaUpdateWrapper<TicketBox>()
+					.set(TicketBox::getStatus, TicketBoxStatusEnum.PUT_OFF)
+					.set(TicketBox::getManualOff, 1)
 					.eq(TicketBox::getBoxId, ticketBox.getBoxId()));
 		} else if (param.getStatus() == TicketBoxStatusEnum.PUT_ON) {
 			if (ticketBox.getStatus() != TicketBoxStatusEnum.PUT_OFF && ticketBox.getStatus() != TicketBoxStatusEnum.DONE) {
@@ -153,8 +215,10 @@ public class TicketBoxMgrController extends BaseApiController {
 	 * @param
 	 * @return
 	 */
+	@Log(title = "盲票删除", businessType = BusinessType.DELETE)
 	@ApiOperation(value = "盲票删除", notes = "管理端盲票删除")
 	@PostMapping("/remove")
+	@PreAuthorize("@ss.hasPermi('business:ticket:remove')")
 	public AjaxResult remove(@RequestBody TicketBox param) {
 		if (StringUtils.isBlank(param.getBoxId())) {
 			return AjaxResult.error("参数缺失");
@@ -167,12 +231,17 @@ public class TicketBoxMgrController extends BaseApiController {
 		return AjaxResult.success("删除成功");
 	}
 
-	@Log(title = "盲票导出", businessType = BusinessType.EXPORT)
+	/*@Log(title = "盲票导出", businessType = BusinessType.EXPORT)
 	@PostMapping("/export")
+	@PreAuthorize("@ss.hasPermi('business:ticket:export')")
 	public AjaxResult exportTicket(@RequestBody BathIdParam ids) {
 		if (null == ids || null == ids.getIds() || ids.getIds().size() == 0) {
 			return AjaxResult.error("请选择需要导出的盲票组");
 		}
+		TicketBox ticketBox = ticketBoxService.getById(ids.getIds().get(0));
+		if (null == ticketBox || StringUtils.isBlank(ticketBox.getBoxId())) {
+			return AjaxResult.error("选择的盲票组数据异常, 请联系管理员或重试");
+		}
 		List<TicketExcel> excelList = new ArrayList<TicketExcel>();
 		List<Ticket> listAll = new ArrayList<Ticket>();
 		// 首先查询要导出的数据总数
@@ -182,26 +251,25 @@ public class TicketBoxMgrController extends BaseApiController {
 		if (totalSize == 0) {
 			return AjaxResult.error("选择的盲票组中没有可导出的数据");
 		}
-		int pageSize = 2000;
+
 		if(totalSize > pageSize) {
 			int totalPage = totalSize%pageSize == 0 ? totalSize/pageSize : totalSize/pageSize+1;
 			for (int i = 0; i < totalPage; i++) {
 				LambdaQueryWrapper<Ticket> pageQueryWrapper = new LambdaQueryWrapper<Ticket>();
+				pageQueryWrapper.select(Ticket::getSerialNo, Ticket::getDrawNum, Ticket::getCipherLuckyNum);
 				pageQueryWrapper.eq(Ticket::getBoxId, ids.getIds().get(0));
-				pageQueryWrapper.orderByAsc(Ticket::getSerialNo);
-				//pageQueryWrapper.last("limit "+ (i*pageSize) +", " + pageSize);
-				pageQueryWrapper.last("limit " + pageSize);
+				pageQueryWrapper.last("limit "+ (i*pageSize) +", " + pageSize);
 				List<Ticket> list = ticketService.list(pageQueryWrapper);
 				if(null != list && list.size() > 0 ) {
 					listAll.addAll(list);
 				}
 			}
 		}else {
-			queryWrapper.orderByAsc(Ticket::getSerialNo);
 			listAll = ticketService.list(queryWrapper);
 		}
 
 		if(null != listAll && listAll.size() > 0 ) {
+			listAll.sort(Comparator.comparing(Ticket::getSerialNo));
 			for (Ticket ticket : listAll) {
 				if (null != ticket && StringUtils.isNotBlank(ticket.getSerialNo())
 						&& StringUtils.isNotBlank(ticket.getDrawNum())
@@ -210,14 +278,16 @@ public class TicketBoxMgrController extends BaseApiController {
 					ticketExcel.setSerialNo(ticket.getSerialNo());
 					ticketExcel.setUrl(exportUrl + ticket.getSerialNo());
 					ticketExcel.setDrawNum(ticket.getDrawNum());
-					ticketExcel.setCipherLuckyNum(ticket.getCipherLuckyNum());
+					if (!ServerEnvEnum.PROD.getCode().equals(env)) {
+						ticketExcel.setCipherLuckyNum(RSAUtil.decrypt(ticket.getCipherLuckyNum()));
+					}
 					excelList.add(ticketExcel);
 				}
 			}
 		}
 
 		ExcelUtil<TicketExcel> util = new ExcelUtil<TicketExcel>(TicketExcel.class);
-		return util.exportExcel(excelList, "盲票导出数据", true);
+		return util.exportExcel(excelList, ticketBox.getTitle(), false);
 	}
 
 
@@ -225,7 +295,7 @@ public class TicketBoxMgrController extends BaseApiController {
     public AjaxResult importTemplate()
     {
         ExcelUtil<TicketExcel> util = new ExcelUtil<TicketExcel>(TicketExcel.class);
-        return util.importTemplateExcel("盲票导出数据",true);
+        return util.importTemplateExcel("盲票导出数据",false);
     }
 
 	@Log(title = "盲票导入", businessType = BusinessType.IMPORT)
@@ -247,6 +317,97 @@ public class TicketBoxMgrController extends BaseApiController {
 		} catch (Exception e) {
 			return AjaxResult.error("导入失败,请联系管理员");
 		}
+	}*/
+
+
+	@Log(title = "导出印刷", businessType = BusinessType.EXPORT)
+	@PostMapping("/exportDraw")
+	@PreAuthorize("@ss.hasPermi('business:ticket:export')")
+	public AjaxResult exportDraw(@RequestBody BathIdParam ids) {
+		if (null == ids || null == ids.getIds() || ids.getIds().size() == 0) {
+			return AjaxResult.error("请选择需要导出的盲票组");
+		}
+		TicketBox ticketBox = ticketBoxService.getById(ids.getIds().get(0));
+		if (null == ticketBox || StringUtils.isBlank(ticketBox.getBoxId())) {
+			return AjaxResult.error("选择的盲票组数据异常, 请联系管理员或重试");
+		}
+		List<TicketExcel> excelList = new ArrayList<TicketExcel>();
+		List<Ticket> listAll = new ArrayList<Ticket>();
+		// 首先查询要导出的数据总数
+		LambdaQueryWrapper<Ticket> queryWrapper = new LambdaQueryWrapper<Ticket>();
+		queryWrapper.eq(Ticket::getBoxId, ids.getIds().get(0));
+		int totalSize = ticketService.count(queryWrapper);
+		if (totalSize == 0) {
+			return AjaxResult.error("选择的盲票组中没有可导出的数据");
+		}
+
+		if(totalSize > pageSize) {
+			int totalPage = totalSize%pageSize == 0 ? totalSize/pageSize : totalSize/pageSize+1;
+			for (int i = 0; i < totalPage; i++) {
+				LambdaQueryWrapper<Ticket> pageQueryWrapper = new LambdaQueryWrapper<Ticket>();
+				pageQueryWrapper.select(Ticket::getSerialNo, Ticket::getDrawNum, Ticket::getCipherLuckyNum);
+				pageQueryWrapper.eq(Ticket::getBoxId, ids.getIds().get(0));
+				pageQueryWrapper.last("limit "+ (i*pageSize) +", " + pageSize);
+				List<Ticket> list = ticketService.list(pageQueryWrapper);
+				if(null != list && list.size() > 0 ) {
+					listAll.addAll(list);
+				}
+			}
+		}else {
+			listAll = ticketService.list(queryWrapper);
+		}
+
+		if(null != listAll && listAll.size() > 0 ) {
+			listAll.sort(Comparator.comparing(Ticket::getSerialNo));
+			for (Ticket ticket : listAll) {
+				if (null != ticket && StringUtils.isNotBlank(ticket.getSerialNo())
+						&& StringUtils.isNotBlank(ticket.getDrawNum())
+						&& StringUtils.isNotBlank(ticket.getCipherLuckyNum())) {
+					TicketExcel ticketExcel = new TicketExcel();
+					ticketExcel.setSerialNo(ticket.getSerialNo());
+					ticketExcel.setUrl(exportUrl + ticket.getSerialNo());
+					ticketExcel.setDrawNum(formatDraw(ticket.getDrawNum()));
+					if (!ServerEnvEnum.PROD.getCode().equals(env)) {
+						ticketExcel.setCipherLuckyNum(RSAUtil.decrypt(ticket.getCipherLuckyNum()));
+					}
+					excelList.add(ticketExcel);
+				}
+			}
+		}
+
+		ExcelUtil<TicketExcel> util = new ExcelUtil<TicketExcel>(TicketExcel.class);
+		return util.exportExcel(excelList, ticketBox.getTitle(), false);
+	}
+
+
+	/**
+	 * 导出印刷格式化
+	 * @param drawNum
+	 * @return
+	 */
+	private String formatDraw(String drawNum) {
+		if(StringUtils.isNotBlank(drawNum)) {
+			try {
+				List<String> drawList = new ArrayList<String>();
+				JSONArray jsonArray = JSONArray.parseArray(drawNum);
+				if(null != jsonArray && jsonArray.size() > 0) {
+					for (int i = 0; i < jsonArray.size(); i++) {
+						JSONObject jo = jsonArray.getJSONObject(i);
+						if(null != jo && jo.containsKey("name")
+								&& jo.containsKey("num")) {
+							drawList.add(jo.getString("name")+jo.getString("num"));
+						}
+					}
+				}
+				if(null != drawList && drawList.size() >0) {
+					return StringUtils.join(drawList.toArray(), ",");
+				}
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
+		return "";
+
 	}
 
 

+ 248 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/admin/UserDeliverOrderMgrController.java

@@ -0,0 +1,248 @@
+package com.qs.mp.web.controller.api.admin;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.qs.mp.admin.domain.param.UserDeliverOrderQueryParam;
+import com.qs.mp.admin.domain.param.UserDeliverOrderShipParam;
+import com.qs.mp.common.annotation.Log;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.core.page.TableDataInfo;
+import com.qs.mp.common.enums.BusinessType;
+import com.qs.mp.common.enums.ErrorCodeEnum;
+import com.qs.mp.user.domain.UserDeliverOrder;
+import com.qs.mp.user.domain.UserDeliverOrderItem;
+import com.qs.mp.user.domain.excel.DeliverOrderExcel;
+import com.qs.mp.user.domain.vo.OrderDeliverItemVO;
+import com.qs.mp.user.domain.vo.UserDeliverOrderItemVO;
+import com.qs.mp.user.domain.vo.UserDeliverOrderVO;
+import com.qs.mp.user.service.IUserDeliverOrderItemService;
+import com.qs.mp.user.service.IUserDeliverOrderService;
+import com.qs.mp.utils.ExcelUtil;
+import com.qs.mp.web.controller.common.BaseApiController;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.List;
+import lombok.AllArgsConstructor;
+import ma.glasnost.orika.MapperFacade;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/v1/mp/admin/deliver/order")
+@Api(tags = "用户提货订单接口")
+@AllArgsConstructor
+public class UserDeliverOrderMgrController extends BaseApiController {
+
+	@Autowired
+	private IUserDeliverOrderService userDeliverOrderService;
+
+	@Autowired
+	private IUserDeliverOrderItemService userDeliverOrderItemService;
+
+//	@Autowired
+//	private IUserPrizeStorageService userPrizeStorageService;
+//
+//	@Autowired
+//	private IUserAddrService userAddrService;
+//
+//	@Autowired
+//	private IWalletService walletService;
+
+	@Autowired
+	private MapperFacade mapperFacade;
+
+//	@Autowired
+//	private RedisCache redisCache;
+
+	/**
+	 * 用户提货订单列表
+	 */
+	@PostMapping("/list")
+	@ApiOperation(value = "用户提货订单列表", notes = "获取用户提货订单列表")
+	@PreAuthorize("@ss.hasPermi('order:deliver:list')")
+	public TableDataInfo list(@RequestBody UserDeliverOrderQueryParam queryParam) {
+		startPage();
+		QueryWrapper<UserDeliverOrder> queryWrapper = new QueryWrapper<UserDeliverOrder>();
+		queryWrapper.eq(null != queryParam && StringUtils.isNotBlank(queryParam.getOrderId()), "t1.order_id", queryParam.getOrderId());
+		queryWrapper.eq(null != queryParam && null != queryParam.getStatus(), "t1.`status`", queryParam.getStatus());
+		queryWrapper.ge(null != queryParam && null != queryParam.getStartTime(), "t1.created_time", queryParam.getStartTime());
+		queryWrapper.le(null != queryParam && null != queryParam.getEndTime(), "t1.created_time", queryParam.getEndTime());
+		queryWrapper.like(null != queryParam && StringUtils.isNotBlank(queryParam.getNickName()), "t2.nick_name", queryParam.getNickName());
+		queryWrapper.like(null != queryParam && StringUtils.isNotBlank(queryParam.getTitle()), "t3.title", queryParam.getTitle());
+		queryWrapper.orderByDesc("t1.order_id");
+		List<UserDeliverOrderVO> userDeliverOrderVOList = userDeliverOrderService.selectUserDeliverOrderVoList(queryWrapper);
+		for (UserDeliverOrderVO userDeliverOrderVO : userDeliverOrderVOList) {
+			List<UserDeliverOrderItemVO> orderItems = userDeliverOrderItemService.selectUserDeliverOrderItemVOList(userDeliverOrderVO.getOrderId());
+			userDeliverOrderVO.setItems(orderItems);
+		}
+		TableDataInfo rspData = getDataTable(userDeliverOrderVOList);
+		return rspData;
+	}
+
+	/**
+	 * 订单详情
+	 */
+	@PostMapping("/detail")
+	@ApiOperation(value = "订单详情", notes = "在订单列表页面查看详情")
+	@PreAuthorize("@ss.hasPermi('order:deliver:query')")
+	public AjaxResult query(@RequestBody UserDeliverOrder order) {
+		if (null == order || StringUtils.isBlank(order.getOrderId())) {
+			return error(ErrorCodeEnum.ERROR_CODE_1001);
+		}
+		UserDeliverOrderVO userDeliverOrderVO = userDeliverOrderService.selectUserDeliverOrderVo(order.getOrderId());
+		if (null == userDeliverOrderVO || StringUtils.isBlank(userDeliverOrderVO.getOrderId())) {
+			return error(ErrorCodeEnum.ERROR_CODE_1001);
+		}
+		List<UserDeliverOrderItemVO> orderItems = userDeliverOrderItemService.selectUserDeliverOrderItemVOList(userDeliverOrderVO.getOrderId());
+		userDeliverOrderVO.setItems(orderItems);
+		// 获取物流详情
+		userDeliverOrderVO.setDeliverList(userDeliverOrderItemService.getDeliverItemList(order.getOrderId(), orderItems));
+		return AjaxResult.success(userDeliverOrderVO);
+	}
+
+
+
+	/**
+	 * 订单发货
+	 */
+	@Log(title = "用户提货订单发货", businessType = BusinessType.UPDATE)
+	@PostMapping("/ship")
+	@ApiOperation(value = "订单发货", notes = "在订单发货页面提交")
+	@PreAuthorize("@ss.hasPermi('order:deliver:ship')")
+	public AjaxResult ship(@RequestBody UserDeliverOrderShipParam shipParam) {
+		if (null == shipParam || StringUtils.isBlank(shipParam.getOrderId())) {
+			return error(ErrorCodeEnum.ERROR_CODE_1001);
+		}
+		List<UserDeliverOrderItem> itemList = new ArrayList<UserDeliverOrderItem>();
+		if (null != shipParam && null != shipParam.getItemIds() && shipParam.getItemIds().size() > 0) {
+			Date deliveryTime = new Date();
+			for (String itemId : shipParam.getItemIds()) {
+				if (StringUtils.isNotBlank(itemId)) {
+					UserDeliverOrderItem item = new UserDeliverOrderItem();
+					item.setItemId(itemId);
+					item.setDeliveryId(shipParam.getDeliveryId());
+					item.setDeliveryFlowId(shipParam.getDeliveryFlowId());
+					item.setDeliveryTime(deliveryTime);
+					itemList.add(item);
+				}
+			}
+		}
+		if (null != itemList && itemList.size() > 0) {
+			boolean rtn = userDeliverOrderService.userDeliverOrderShip(shipParam.getOrderId(), itemList);
+			return rtn ? AjaxResult.success() : AjaxResult.error("发货失败");
+		}
+		return AjaxResult.error("发货失败");
+	}
+
+	/**
+	 * 订单发货修改
+	 */
+	@Log(title = "用户提货订单发货单号修改", businessType = BusinessType.UPDATE)
+	@PostMapping("/ship/update")
+	@ApiOperation(value = "订单发货修改", notes = "在订单发货页面提交")
+	@PreAuthorize("@ss.hasPermi('order:deliver:ship')")
+	public AjaxResult updateShipInfo(@RequestBody UserDeliverOrderShipParam shipParam) {
+		if (null == shipParam || StringUtils.isBlank(shipParam.getOrderId())
+				|| null == shipParam.getDeliveryId() || StringUtils.isBlank(shipParam.getDeliveryFlowId())
+				|| CollectionUtils.isEmpty(shipParam.getItemIds())) {
+			return error(ErrorCodeEnum.ERROR_CODE_1001);
+		}
+
+		for (String itemId : shipParam.getItemIds()) {
+			userDeliverOrderItemService.update(new LambdaUpdateWrapper<UserDeliverOrderItem>()
+					.set(UserDeliverOrderItem::getDeliveryId, shipParam.getDeliveryId())
+					.set(UserDeliverOrderItem::getDeliveryFlowId, shipParam.getDeliveryFlowId())
+					.eq(UserDeliverOrderItem::getItemId, itemId));
+		}
+		return AjaxResult.success();
+	}
+
+	@Log(title = "提货订单导出", businessType = BusinessType.EXPORT)
+	@PostMapping("/export")
+	@PreAuthorize("@ss.hasPermi('order:deliver:export')")
+	public AjaxResult export(@RequestBody UserDeliverOrderQueryParam queryParam) {
+
+		List<DeliverOrderExcel> excelList = new ArrayList<DeliverOrderExcel>();
+		List<UserDeliverOrderVO> listAll = new ArrayList<UserDeliverOrderVO>();
+		// 首先查询要导出的数据总数
+		QueryWrapper<UserDeliverOrder> queryWrapper = new QueryWrapper<UserDeliverOrder>();
+		queryWrapper.eq(null != queryParam && StringUtils.isNotBlank(queryParam.getOrderId()), "t1.order_id", queryParam.getOrderId());
+		queryWrapper.eq(null != queryParam && null != queryParam.getStatus(), "t1.`status`", queryParam.getStatus());
+		queryWrapper.ge(null != queryParam && null != queryParam.getStartTime(), "t1.created_time", queryParam.getStartTime());
+		queryWrapper.le(null != queryParam && null != queryParam.getEndTime(), "t1.created_time", queryParam.getEndTime());
+		queryWrapper.like(null != queryParam && StringUtils.isNotBlank(queryParam.getNickName()), "t2.nick_name", queryParam.getNickName());
+		queryWrapper.like(null != queryParam && StringUtils.isNotBlank(queryParam.getTitle()), "t3.title", queryParam.getTitle());
+		queryWrapper.orderByDesc("t1.order_id");
+		int totalSize = userDeliverOrderService.selectUserDeliverOrderCount(queryWrapper);
+		if (totalSize == 0) {
+			return AjaxResult.error("没有符合条件的用户提货订单");
+		}
+		int pageSize = 2000;
+		if (totalSize > pageSize) {
+			int totalPage = totalSize % pageSize == 0 ? totalSize / pageSize : totalSize / pageSize + 1;
+			for (int i = 0; i < totalPage; i++) {
+				queryWrapper.last("limit " + (i * pageSize) + ", " + pageSize);
+				List<UserDeliverOrderVO> userDeliverOrderVOList = userDeliverOrderService.selectUserDeliverOrderVoList(queryWrapper);
+				for (UserDeliverOrderVO userDeliverOrderVO : userDeliverOrderVOList) {
+					List<UserDeliverOrderItemVO> orderItems = userDeliverOrderItemService.selectUserDeliverOrderItemVOList(userDeliverOrderVO.getOrderId());
+					userDeliverOrderVO.setItems(orderItems);
+				}
+				if (null != userDeliverOrderVOList && userDeliverOrderVOList.size() > 0) {
+					listAll.addAll(userDeliverOrderVOList);
+				}
+			}
+		} else {
+			listAll = userDeliverOrderService.selectUserDeliverOrderVoList(queryWrapper);
+			for (UserDeliverOrderVO userDeliverOrderVO : listAll) {
+				List<UserDeliverOrderItemVO> orderItems = userDeliverOrderItemService.selectUserDeliverOrderItemVOList(userDeliverOrderVO.getOrderId());
+				userDeliverOrderVO.setItems(orderItems);
+			}
+		}
+
+		if (null != listAll && listAll.size() > 0) {
+			// listAll.sort(Comparator.comparing(UserDeliverOrderVO::getOrderId));
+			for (UserDeliverOrderVO deliverOrder : listAll) {
+				if (null != deliverOrder && StringUtils.isNotBlank(deliverOrder.getOrderId())
+						&& StringUtils.isNotBlank(deliverOrder.getReceiver())
+						&& StringUtils.isNotBlank(deliverOrder.getTel())
+						&& StringUtils.isNotBlank(deliverOrder.getProvince())
+						&& StringUtils.isNotBlank(deliverOrder.getCity())
+						&& StringUtils.isNotBlank(deliverOrder.getArea())
+						&& StringUtils.isNotBlank(deliverOrder.getAddress()) && null != deliverOrder.getItems()
+						&& deliverOrder.getItems().size() > 0) {
+					for (UserDeliverOrderItem userDeliverOrderItem : deliverOrder.getItems()) {
+						if (null != userDeliverOrderItem) {
+							DeliverOrderExcel deliverOrderExcel = new DeliverOrderExcel();
+							deliverOrderExcel.setTitle(userDeliverOrderItem.getTitle());
+							deliverOrderExcel.setProperties(userDeliverOrderItem.getProperties());
+							deliverOrderExcel.setGoodsNum(userDeliverOrderItem.getGoodsNum());
+							deliverOrderExcel.setCreatedTime(deliverOrder.getCreatedTime());
+							deliverOrderExcel.setOrderId(deliverOrder.getOrderId());
+							deliverOrderExcel.setReceiver(deliverOrder.getReceiver());
+							deliverOrderExcel.setTel(deliverOrder.getTel());
+							String address = deliverOrder.getProvince() + deliverOrder.getCity()
+									+ deliverOrder.getArea() + deliverOrder.getAddress();
+							deliverOrderExcel.setAddress(address);
+							deliverOrderExcel.setStatus(deliverOrder.getStatus().getDesc());
+							deliverOrderExcel.setItemStatus(
+									StringUtils.isNotBlank(userDeliverOrderItem.getDeliveryFlowId()) ? "已发货" : "未发货");
+							excelList.add(deliverOrderExcel);
+						}
+					}
+				}
+			}
+		}
+		ExcelUtil<DeliverOrderExcel> util = new ExcelUtil<DeliverOrderExcel>(DeliverOrderExcel.class);
+		return util.exportExcel(excelList, "用户提货订单导出", false);
+	}
+}

+ 7 - 11
mp-admin/src/main/java/com/qs/mp/web/controller/api/callback/PayCallBackController.java

@@ -45,7 +45,7 @@ public class PayCallBackController {
     String orderNo =  request.getParameter("orderNo");
     if(!"121.196.180.137".equalsIgnoreCase(ipAddress)){
       //暂时增加机器人告警,防止三方服务器ip变更信息同步不到位,导致支付故障
-      WebhookService.sendMonitorData("【三方支付请求IP异常】{"+ipAddress+"} 订单号:"+orderNo);
+      WebhookService.sendLogAlertMsg("【三方支付请求IP异常】{"+ipAddress+"} 订单号:"+orderNo);
     }
     String orderStatus =  request.getParameter("orderStatus");
     String shopOrderNo =  request.getParameter("shopOrderNo");
@@ -77,18 +77,14 @@ public class PayCallBackController {
     payOrder.setCompleteDate(completeDate);
     payOrder.setChannelNo(channelNo);
     payOrder.setOrderStatus(orderStatus);
-    // 订单支付状态单独保存
-    LambdaUpdateWrapper<PayOrder> updateWrapper = new LambdaUpdateWrapper<>();
-    updateWrapper.eq(PayOrder::getOrderStatus,2);
-    updateWrapper.eq(PayOrder::getOrderId,shopOrderNo);
-    boolean ret = payOrderService.update(payOrder,updateWrapper);
-    if(ret){
-      // 更新订单,单独封装一个事物接口服务
+
+    try {
+      // 更新订单,单个事务处理
       logger.info("支付回调消息更新成功 shopOrderNo:"+shopOrderNo);
-      walletService.payOrderStatusHandle(shopOrderNo);
+      walletService.payOrderStatusHandle(payOrder);
       responseWrite(response,"success");
-    }else{
-      LogUtil.error(logger,"支付回调消息更新失败 shopOrderNo:"+shopOrderNo);
+    } catch (Exception e){
+      LogUtil.error(logger, e, "支付回调消息更新失败 shopOrderNo:"+shopOrderNo);
       responseWrite(response,"error");
     }
   }

+ 136 - 30
mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/ChannelController.java

@@ -3,8 +3,12 @@ package com.qs.mp.web.controller.api.channel;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qs.mp.admin.domain.vo.TicketCntVO;
+import com.qs.mp.admin.service.ITicketService;
 import com.qs.mp.channel.domain.Channel;
 import com.qs.mp.channel.domain.ChannelCommission;
+import com.qs.mp.channel.domain.ChannelOrderDetail;
+import com.qs.mp.channel.domain.ChannelUserRel;
 import com.qs.mp.channel.domain.param.ChannelParam;
 import com.qs.mp.channel.domain.param.SiteQueryParam;
 import com.qs.mp.channel.domain.param.VerifyParam;
@@ -23,6 +27,8 @@ import com.qs.mp.common.enums.ErrorCodeEnum;
 import com.qs.mp.common.exception.ServiceException;
 import com.qs.mp.common.utils.DateUtils;
 import com.qs.mp.system.service.ISysUserService;
+import com.qs.mp.user.domain.UserTicketOrder;
+import com.qs.mp.user.service.IUserTicketOrderService;
 import com.qs.mp.utils.SecurityUtils;
 import com.qs.mp.web.controller.common.BaseApiController;
 import io.swagger.annotations.Api;
@@ -33,8 +39,10 @@ import java.math.BigDecimal;
 import java.util.ArrayList;
 import java.util.Calendar;
 import java.util.Date;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
@@ -69,6 +77,12 @@ public class ChannelController extends BaseApiController {
 
     @Autowired
     private ISysUserService userService;
+    
+	@Autowired
+	private IUserTicketOrderService userTicketOrderService;
+    
+	@Autowired
+	private ITicketService ticketService;
 
 	@Autowired
 	private MapperFacade mapperFacade;
@@ -122,7 +136,7 @@ public class ChannelController extends BaseApiController {
 			return error(ErrorCodeEnum.ERROR_CODE_1001);
 		}
 		if(!parentlId.equals(queryChannel.getParentId())) {
-			return AjaxResult.error("非当前用户的子渠道,查询失败");
+			return AjaxResult.error("非当前用户的下级,查询失败");
 		}
 	    BeanUtils.copyProperties(queryChannel, channelVO);
 	    // 查询今日的销售额、佣金收入、新增用户数
@@ -140,7 +154,7 @@ public class ChannelController extends BaseApiController {
 	@PostMapping("subchannel/create")
 	public AjaxResult channelCreate(@Validated @RequestBody ChannelParam channelParam) {
 		if (channelParam.getChannelId() != null && channelParam.getChannelId() != 0) {
-			return AjaxResult.error("该渠道已存在");
+			return AjaxResult.error("该代理已存在");
 		}
 		Long channelId = SecurityUtils.getLoginUser().getChannelId();
 		Channel channel = mapperFacade.map(channelParam, Channel.class);
@@ -151,7 +165,7 @@ public class ChannelController extends BaseApiController {
 		queryWrapper.gt(Channel::getLevel, 0);
 		int nameCount = channelService.count(queryWrapper);
 		if(nameCount > 0) {
-			return AjaxResult.error("渠道名称" + channel.getName() + "已存在!");
+			return AjaxResult.error("代理名称" + channel.getName() + "已存在!");
 		}
 		int mobileCount = channelService.count(
 		        new LambdaQueryWrapper<Channel>().eq(Channel::getMobile, channel.getMobile()));
@@ -162,7 +176,7 @@ public class ChannelController extends BaseApiController {
 		Channel parentChannel = channelService.getById(channel.getParentId());
 		if(null != parentChannel && null != parentChannel.getCommRate()) {
 			 if(channel.getCommRate().compareTo(parentChannel.getCommRate()) > 0) {
-				 return AjaxResult.error("佣金比例不能高于父渠道的佣金比例");
+				 return AjaxResult.error("佣金比例不能高于上级代理的佣金比例");
 			 }
 		}
 		channel.setLevel(parentChannel.getLevel()+1);
@@ -171,10 +185,10 @@ public class ChannelController extends BaseApiController {
 		try {
 			channelService.saveChannel(channel, ChannelRoleEnum.CHANNEL);
 		} catch (Exception e) {
-			return AjaxResult.error("渠道'" + channel.getName() + "'新增失败" + e.getMessage());
+			return AjaxResult.error("代理'" + channel.getName() + "'新增失败" + e.getMessage());
 		}
 
-		return AjaxResult.success("渠道'" + channel.getName() + "'新增成功");
+		return AjaxResult.success("代理'" + channel.getName() + "'新增成功");
 	}
 
 	/**
@@ -193,11 +207,11 @@ public class ChannelController extends BaseApiController {
 		// 1、校验修改子渠道是否为当前用户的子渠道
 		Channel oldChannel = channelService.getById(channel.getChannelId());
 		if(null == oldChannel || null == oldChannel.getChannelId()) {
-			return AjaxResult.error("渠道'" + oldChannel.getName() + "'编辑失败,渠道ID异常");
+			return AjaxResult.error("代理'" + oldChannel.getName() + "'编辑失败");
 		}
 		Long channelId = SecurityUtils.getLoginUser().getChannelId();
 		if(!oldChannel.getParentId().equals(channelId)) {
-			return AjaxResult.error("渠道'" + oldChannel.getName() + "'编辑失败,非当前用户子渠道");
+			return AjaxResult.error("代理'" + oldChannel.getName() + "'编辑失败");
 		}
 		// 2.校验名称是否重复、手机号是否存在(渠道表);
 		if(!channel.getName().equals(oldChannel.getName())) {
@@ -206,7 +220,7 @@ public class ChannelController extends BaseApiController {
 			queryWrapper.gt(Channel::getLevel, 0);
 			int nameCount = channelService.count(queryWrapper);
 			if(nameCount > 0) {
-				return AjaxResult.error("渠道名称" + channel.getName() + "已存在!");
+				return AjaxResult.error("代理名称" + channel.getName() + "已存在!");
 			}
 		}
 		boolean mobileChange = false;  // 手机号码是否有变更
@@ -225,7 +239,7 @@ public class ChannelController extends BaseApiController {
 		Channel parentChannel = channelService.getById(oldChannel.getParentId());
 		if(null != parentChannel && null != parentChannel.getCommRate()) {
 			 if(channel.getCommRate().compareTo(parentChannel.getCommRate()) > 0) {
-				 return AjaxResult.error("佣金比例不能高于父渠道的佣金比例");
+				 return AjaxResult.error("佣金比例不能高于上级代理的佣金比例");
 			 }
 		}
 		// 查询子渠道的最大佣金比例
@@ -236,7 +250,7 @@ public class ChannelController extends BaseApiController {
 		if(null != map && map.containsKey("commRate")) {
 			BigDecimal commRate = new BigDecimal(map.get("commRate").toString());
 			if(!commRate.equals(BigDecimal.ZERO) && channel.getCommRate().compareTo(commRate) < 0) {
-				return AjaxResult.error("不能低于其子渠道的最大佣金比例");
+				return AjaxResult.error("不能低于其下级的最大佣金比例");
 			}
 		}
 		try {
@@ -245,7 +259,7 @@ public class ChannelController extends BaseApiController {
 		} catch (Exception e) {
 			return AjaxResult.error(e.getMessage());
 		}
-		return AjaxResult.success("渠道'" + channel.getName() + "'编辑成功");
+		return AjaxResult.success("代理'" + channel.getName() + "'编辑成功");
 	}
 
 
@@ -269,7 +283,7 @@ public class ChannelController extends BaseApiController {
 				return error(ErrorCodeEnum.ERROR_CODE_1001);
 			}
 			if(!channelId.equals(queryChannel.getParentId())) {
-				return AjaxResult.error("非当前用户的子渠道,查询失败");
+				return AjaxResult.error("非当前用户的下级,查询失败");
 			}
 			channelId = _channelId;
 		}
@@ -340,6 +354,60 @@ public class ChannelController extends BaseApiController {
 				queryWrapper.eq("t1.certify_status", siteParam.getCertifyStatus());
 			}
 			list = channelService.selectChannelVoList(queryWrapper);
+			
+			List<Long> channelIds = new ArrayList<Long>();
+			if(null != list && list.size() > 0) {
+				for(ChannelVO channelVO : list) {
+					if(null != channelVO && null != channelVO.getChannelId()
+							&& StringUtils.isNotBlank(channelVO.getChannelNo())) {
+						channelIds.add(channelVO.getChannelId());
+	 				}
+				}
+			}
+			List<TicketCntVO>  qtyCntList = new ArrayList<TicketCntVO>();
+			List<TicketCntVO>  saleCntList = new ArrayList<TicketCntVO>();
+			if(null != channelIds && channelIds.size() > 0) {
+				QueryWrapper<ChannelOrderDetail> ticketQtyCntQueryWrapper = new QueryWrapper<ChannelOrderDetail>();
+				ticketQtyCntQueryWrapper.in("t1.channel_id", channelIds);
+				qtyCntList = ticketService.listTicketQtyCnt(ticketQtyCntQueryWrapper);
+				
+		    	QueryWrapper<UserTicketOrder> ticketSaleCntQueryWrapper = new QueryWrapper<UserTicketOrder>();
+		    	ticketSaleCntQueryWrapper.in("t1.channel_id", channelIds);
+		    	ticketSaleCntQueryWrapper.eq("t1.`status`", 1);
+		    	saleCntList = userTicketOrderService.listTicketSaleCnt(ticketSaleCntQueryWrapper);
+			}
+			
+			if(null != list && list.size() > 0) {
+				for(ChannelVO channelVO : list) {
+					if(null != channelVO && null != channelVO.getChannelId()
+							&& StringUtils.isNotBlank(channelVO.getChannelNo())) {
+						// int siteCnt = channelService.getChannelSiteCnt(channelVO.getChannelNo());
+						LambdaQueryWrapper<ChannelUserRel> userCntQueryWrapper = new LambdaQueryWrapper<ChannelUserRel>();
+						userCntQueryWrapper.eq(ChannelUserRel::getChannelId, channelVO.getChannelId());
+						int userCnt = channelUserRelService.count(userCntQueryWrapper);
+						channelVO.setUserCnt(userCnt);
+						// 统计盲票库存, 销量
+						if(null != qtyCntList && qtyCntList.size() > 0) {
+							List<TicketCntVO> voList =  qtyCntList.stream().filter(item  -> item.getChannelId().equals(channelVO.getChannelId()))
+					                .collect(Collectors.toList());
+							if(null != voList && voList.size() > 0) {
+								TicketCntVO ticketQtyCnt =  voList.get(0);
+								channelVO.setOffLineQtyCnt(null != ticketQtyCnt?ticketQtyCnt.getOffLineQtyCnt():0);
+							}
+						}
+						if(null != saleCntList && saleCntList.size() > 0) {
+							List<TicketCntVO> voList =  saleCntList.stream().filter(item  -> item.getChannelId().equals(channelVO.getChannelId()))
+					                .collect(Collectors.toList());
+							if(null != voList && voList.size() > 0) {
+								TicketCntVO ticketSaleCnt =  voList.get(0);
+								channelVO.setOffLineSaleCnt(null != ticketSaleCnt?ticketSaleCnt.getOffLineSaleCnt():0);
+								channelVO.setOnLineSaleCnt(null != ticketSaleCnt?ticketSaleCnt.getOnLineSaleCnt():0);
+							}
+						}
+	 				}
+				}
+			}
+			
 		}
 		return getDataTable(list);
 	}
@@ -362,12 +430,27 @@ public class ChannelController extends BaseApiController {
 			return error(ErrorCodeEnum.ERROR_CODE_1001);
 		}
 		if(!parentlId.equals(queryChannel.getParentId())) {
-			return AjaxResult.error("非当前用户的经销商,查询失败");
+			return AjaxResult.error("非当前用户的门店,查询失败");
 		}
 	    BeanUtils.copyProperties(queryChannel, channelVO);
 	    // 查询今日的销售额、佣金收入、新增用户数
 	    ChannelOperDataVO channelOperDataVO = channelService.getChannelOperData(channelVO.getChannelNo(), 1);
 	    channelVO.setOperData(channelOperDataVO);
+	    if(null != channelVO && null != channelVO.getChannelId()) {
+	    	
+	    	LambdaQueryWrapper<ChannelUserRel> userCntQueryWrapper = new LambdaQueryWrapper<ChannelUserRel>();
+			userCntQueryWrapper.eq(ChannelUserRel::getChannelId, channelVO.getChannelId());
+			int userCnt = channelUserRelService.count(userCntQueryWrapper);
+			channelVO.setUserCnt(userCnt);
+	    	
+	    	int ticketQtyCnt = ticketService.getTicketQtyCnt(channelVO.getChannelId());
+	    	channelVO.setOffLineQtyCnt(ticketQtyCnt);
+	    	
+	    	TicketCntVO ticketSaleCnt = userTicketOrderService.getTicketSaleCnt(channelVO.getChannelId());
+			channelVO.setOffLineSaleCnt(null != ticketSaleCnt?ticketSaleCnt.getOffLineSaleCnt():0);
+			channelVO.setOnLineSaleCnt(null != ticketSaleCnt?ticketSaleCnt.getOnLineSaleCnt():0);
+	    }
+	   
 		return AjaxResult.success(channelVO);
 	}
 
@@ -380,7 +463,7 @@ public class ChannelController extends BaseApiController {
 	@PostMapping("site/create")
 	public AjaxResult siteCreate(@Validated @RequestBody ChannelParam channelParam) {
 		if (channelParam.getChannelId() != null && channelParam.getChannelId() != 0) {
-			return AjaxResult.error("该经销商已存在");
+			return AjaxResult.error("该门店已存在");
 		}
 		Long channelId = SecurityUtils.getLoginUser().getChannelId();
 
@@ -392,7 +475,7 @@ public class ChannelController extends BaseApiController {
 		queryWrapper.eq(Channel::getLevel, 0);
 		int nameCount = channelService.count(queryWrapper);
 		if(nameCount > 0) {
-			return AjaxResult.error("经销商名称" + channel.getName() + "已存在!");
+			return AjaxResult.error("门店名称" + channel.getName() + "已存在!");
 		}
 		int mobileCount = channelService.count(
 		        new LambdaQueryWrapper<Channel>().eq(Channel::getMobile, channel.getMobile()));
@@ -403,7 +486,7 @@ public class ChannelController extends BaseApiController {
 		Channel parentChannel = channelService.getById(channel.getParentId());
 		if(null != parentChannel && null != parentChannel.getCommRate()) {
 			 if(channel.getCommRate().compareTo(parentChannel.getCommRate()) > 0) {
-				 return AjaxResult.error("佣金比例不能高于父渠道的佣金比例");
+				 return AjaxResult.error("佣金比例不能高于上级代理的佣金比例");
 			 }
 		}
 		channel.setLevel(0);
@@ -412,9 +495,9 @@ public class ChannelController extends BaseApiController {
 		try {
 			channelService.saveChannel(channel,ChannelRoleEnum.SALESITE);
 		} catch (Exception e) {
-			return AjaxResult.error("经销商'" + channel.getName() + "'新增失败"+e.getMessage());
+			return AjaxResult.error("门店'" + channel.getName() + "'新增失败"+e.getMessage());
 		}
-		return AjaxResult.success("经销商'" + channel.getName() + "'新增成功");
+		return AjaxResult.success("门店'" + channel.getName() + "'新增成功");
 	}
 
 	/**
@@ -434,11 +517,11 @@ public class ChannelController extends BaseApiController {
 		// 1、校验修改子渠道是否为当前用户的子渠道
 		Channel oldChannel = channelService.getById(channel.getChannelId());
 		if(null == oldChannel || null == oldChannel.getChannelId()) {
-			return AjaxResult.error("经销商'" + oldChannel.getName() + "'编辑失败,渠道ID异常");
+			return AjaxResult.error("门店'" + oldChannel.getName() + "'编辑失败");
 		}
 		Long channelId = SecurityUtils.getLoginUser().getChannelId();
 		if(!oldChannel.getParentId().equals(channelId)) {
-			return AjaxResult.error("经销商'" + oldChannel.getName() + "'编辑失败,非当前用户子渠道");
+			return AjaxResult.error("门店'" + oldChannel.getName() + "'编辑失败");
 		}
 		// 2.校验名称是否重复、手机号是否存在(渠道表);
 		if(!channel.getName().equals(oldChannel.getName())) {
@@ -448,7 +531,7 @@ public class ChannelController extends BaseApiController {
 			queryWrapper.eq(Channel::getLevel, 0);
 			int nameCount = channelService.count(queryWrapper);
 			if(nameCount > 0) {
-				return AjaxResult.error("经销商名称" + channel.getName() + "已存在!");
+				return AjaxResult.error("门店名称" + channel.getName() + "已存在!");
 			}
 		}
 		boolean mobileChange = false;  // 手机号码是否有变更
@@ -467,16 +550,16 @@ public class ChannelController extends BaseApiController {
 		Channel parentChannel = channelService.getById(oldChannel.getParentId());
 		if(null != parentChannel && null != parentChannel.getCommRate()) {
 			 if(channel.getCommRate().compareTo(parentChannel.getCommRate()) > 0) {
-				 return AjaxResult.error("佣金比例不能高于父渠道的佣金比例");
+				 return AjaxResult.error("佣金比例不能高于上级代理的佣金比例");
 			 }
 		}
 		try {
 			channel.setUserId(oldChannel.getUserId());
 			channelService.updateChannel(channel, mobileChange);
 		} catch (Exception e) {
-			return AjaxResult.error("经销商'" + channel.getName() + "'编辑失败");
+			return AjaxResult.error("门店'" + channel.getName() + "'编辑失败");
 		}
-		return AjaxResult.success("经销商'" + channel.getName() + "'编辑成功");
+		return AjaxResult.success("门店'" + channel.getName() + "'编辑成功");
 	}
 
 
@@ -499,7 +582,7 @@ public class ChannelController extends BaseApiController {
 			return error(ErrorCodeEnum.ERROR_CODE_1001);
 		}
 		if(!parentlId.equals(queryChannel.getParentId())) {
-			return AjaxResult.error(queryChannel.getName() + "非当前用户的经销商, 认证审核失败");
+			return AjaxResult.error(queryChannel.getName() + "非当前用户的门店, 认证审核失败");
 		}
 		try {
 			if(channel.getVerifyStatus() == ChannelVerifyStatusEnum.ACCEPT) {
@@ -509,9 +592,9 @@ public class ChannelController extends BaseApiController {
 			}
 			channelService.updateById(channel);
 		} catch (Exception e) {
-			return AjaxResult.error("经销商'" + channel.getName() + "'认证审核失败");
+			return AjaxResult.error("门店'" + channel.getName() + "'认证审核失败");
 		}
-		return AjaxResult.success("经销商'" + channel.getName() + "'认证审核成功");
+		return AjaxResult.success("门店'" + channel.getName() + "'认证审核成功");
 	}
 
 	/**
@@ -531,9 +614,9 @@ public class ChannelController extends BaseApiController {
 			channel.setVerifyStatus(ChannelVerifyStatusEnum.WAIT);
 			channelService.updateById(channel);
 		} catch (Exception e) {
-			return AjaxResult.error("经销商'" + channel.getName() + "'提交认证信息失败");
+			return AjaxResult.error("门店'" + channel.getName() + "'提交认证信息失败");
 		}
-		return AjaxResult.success("经销商'" + channel.getName() + "'提交认证信息成功");
+		return AjaxResult.success("门店'" + channel.getName() + "'提交认证信息成功");
 	}
 
 
@@ -595,4 +678,27 @@ public class ChannelController extends BaseApiController {
 		}
 		return AjaxResult.success(channelVO);
 	}
+
+
+	/**
+	 * 场景是这里要显示待审核数量
+	 *
+	 * @param
+	 * @return
+	 */
+	@PostMapping(value = "subchannel/index")
+	public AjaxResult getChannelIndex() {
+		int waitVerifyNum = 0;
+		Long channelId = SecurityUtils.getLoginUser().getChannelId();
+		if(null != channelId && 0 != channelId) {
+			LambdaQueryWrapper<Channel> queryWrapper = new LambdaQueryWrapper<Channel>();
+			queryWrapper.eq(Channel::getParentId, channelId);
+			queryWrapper.eq(Channel::getVerifyStatus, ChannelVerifyStatusEnum.WAIT);
+			queryWrapper.eq(Channel::getLevel, 0);
+			waitVerifyNum = channelService.count(queryWrapper);
+		}
+	    Map<String,Object> map = new HashMap<String,Object>();
+	    map.put("waitVerifyNum", waitVerifyNum);
+		return AjaxResult.success(map);
+	}
 }

+ 165 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/ChannelCouponVerifyController.java

@@ -0,0 +1,165 @@
+package com.qs.mp.web.controller.api.channel;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qs.mp.channel.domain.ChannelCouponVerifyLog;
+import com.qs.mp.channel.service.IChannelCouponVerifyLogService;
+import com.qs.mp.channel.service.IChannelService;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.core.page.TableDataInfo;
+import com.qs.mp.common.enums.ErrorCodeEnum;
+import com.qs.mp.common.enums.UserCouponStatusEnum;
+import com.qs.mp.user.domain.UserCoupon;
+import com.qs.mp.user.domain.UserCouponChannel;
+import com.qs.mp.user.domain.vo.UserCouponVO;
+import com.qs.mp.user.service.IUserCouponChannelService;
+import com.qs.mp.user.service.IUserCouponService;
+import com.qs.mp.utils.SecurityUtils;
+import com.qs.mp.web.controller.common.BaseApiController;
+import io.swagger.annotations.Api;
+import java.util.Date;
+import java.util.List;
+import ma.glasnost.orika.MapperFacade;
+import org.apache.catalina.User;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @auther zhongcp
+ * @create 2022-02-28 16:17:48
+ * @describe 渠道优惠券核销前端控制器
+ */
+@Api("渠道管理API")
+@RestController
+@RequestMapping("/api/v1/mp/channel/*")
+@Component
+public class ChannelCouponVerifyController extends BaseApiController {
+
+  @Autowired
+  private IChannelService channelService;
+
+  @Autowired
+  private IUserCouponService userCouponService;
+
+  @Autowired
+  private IUserCouponChannelService userCouponChannelService;
+
+  @Autowired
+  private IChannelCouponVerifyLogService channelCouponVerifyLogService;
+
+  @Autowired
+  private MapperFacade mapperFacade;
+
+  /**
+   * 优惠券查询
+   *
+   * @param
+   * @return
+   */
+  @PostMapping(value = "coupon/query")
+  public AjaxResult query(@RequestBody JSONObject param) {
+    String verifyCode = param.getString("verifyCode");
+    Long channelId = SecurityUtils.getLoginUser().getChannelId();
+    UserCoupon userCoupon = userCouponService.getOne(new LambdaQueryWrapper<UserCoupon>()
+        .eq(UserCoupon::getVerifyCode, verifyCode));
+    if (null == userCoupon) {
+      return error("券码非法");
+    }
+    AjaxResult result = checkCoupon(verifyCode, channelId, userCoupon);
+    if (null != result) {
+      return result;
+    }
+    List<UserCouponVO> userCouponVOList = userCouponService.listUserCouponVO(
+        new QueryWrapper<UserCoupon>()
+            .eq("t1.verify_code", verifyCode));
+
+    return AjaxResult.success(userCouponVOList.get(0));
+  }
+
+  private AjaxResult checkCoupon(String verifyCode, Long channelId, UserCoupon userCoupon) {
+    AjaxResult result = null;
+
+    if (StringUtils.isBlank(verifyCode)) {
+      result = error(ErrorCodeEnum.ERROR_CODE_1001);
+    }
+    if (null == userCoupon) {
+      result = error("该券不存在!");
+    }
+    if (userCoupon.getStatus() == UserCouponStatusEnum.USED) {
+      result = error("该券已使用!");
+    }
+    if (userCoupon.getValidEnd().before(new Date())) {
+      result = error("该券已过期!");
+    }
+    UserCouponChannel couponChannel = userCouponChannelService.getOne(
+        new LambdaQueryWrapper<UserCouponChannel>()
+            .eq(UserCouponChannel::getUserCouponId, userCoupon.getId())
+            .eq(UserCouponChannel::getChannelId, channelId));
+    if (null == couponChannel) {
+      result = error("无权核销该券");
+    }
+    return result;
+  }
+
+  /**
+   * 优惠券核销
+   *
+   * @param
+   * @return
+   */
+  @PostMapping(value = "coupon/verify")
+  public AjaxResult verify(@RequestBody JSONObject param) {
+    String verifyCode = param.getString("verifyCode");
+    Long channelId = SecurityUtils.getLoginUser().getChannelId();
+    UserCoupon userCoupon = userCouponService.getOne(new LambdaQueryWrapper<UserCoupon>()
+        .eq(UserCoupon::getVerifyCode, verifyCode));
+    if (null == userCoupon) {
+      return error("券码非法");
+    }
+    AjaxResult result = checkCoupon(verifyCode, channelId, userCoupon);
+    if (null != result) {
+      return result;
+    }
+    channelCouponVerifyLogService.verify(channelId, userCoupon);
+    return AjaxResult.success("核销成功");
+  }
+
+  /**
+   * 获取我的核销记录
+   *
+   * @return
+   */
+  @PostMapping("coupon/verify/log/list")
+  public TableDataInfo list(@RequestBody JSONObject jsonObject) {
+    Long channelId = SecurityUtils.getLoginUser().getChannelId();
+    startPage();
+    List<ChannelCouponVerifyLog> verifyLogList = channelCouponVerifyLogService.list(
+        new LambdaQueryWrapper<ChannelCouponVerifyLog>()
+            .eq(ChannelCouponVerifyLog::getChannelId, channelId)
+            .orderByDesc(ChannelCouponVerifyLog::getVerifyTime));
+    return getDataTable(verifyLogList);
+  }
+
+	/**
+	 * 优惠券核销记录详情
+	 *
+	 * @param
+	 * @return
+	 */
+	@PostMapping(value = "coupon/verify/log/detail")
+	public AjaxResult detail(@RequestBody JSONObject param) {
+		Long logId = param.getLong("logId");
+		if (null == logId || 0 == logId) {
+			return error(ErrorCodeEnum.ERROR_CODE_1001);
+		}
+		ChannelCouponVerifyLog verifyLog = channelCouponVerifyLogService.getById(logId);
+		return AjaxResult.success(verifyLog);
+	}
+
+}

+ 5 - 1
mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/ChannelInviteController.java

@@ -2,6 +2,7 @@ package com.qs.mp.web.controller.api.channel;
 
 import cn.jsms.api.ValidSMSResult;
 import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.qs.mp.channel.domain.Channel;
 import com.qs.mp.channel.domain.param.ChannelInviteParam;
 import com.qs.mp.channel.service.IChannelService;
@@ -82,7 +83,10 @@ public class ChannelInviteController extends BaseApiController {
 		if (res == null || !res.getIsValid()) {
 			return error("短信验证码错误");
 		}
-
+		int cnt = channelService.count(new LambdaQueryWrapper<Channel>().eq(Channel::getMobile, param.getMobile()));
+		if (cnt > 0) {
+			return error("手机号已存在");
+		}
 		// 创建经销商
 		Channel channel = new Channel();
 		channel.setChannelNo(parent.getChannelNo() + ".");

+ 24 - 2
mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/ChannelMoneyController.java

@@ -12,13 +12,18 @@ package com.qs.mp.web.controller.api.channel;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.qs.mp.channel.domain.ChannelMoneyLog;
+import com.qs.mp.channel.domain.ChannelWithdraw;
+import com.qs.mp.channel.domain.vo.ChannelMoneyLogVO;
 import com.qs.mp.channel.service.IChannelMoneyLogService;
+import com.qs.mp.channel.service.IChannelWithdrawService;
 import com.qs.mp.common.core.page.TableDataInfo;
+import com.qs.mp.common.enums.ChannelMoneyEnum;
 import com.qs.mp.utils.SecurityUtils;
 import com.qs.mp.web.controller.common.BaseApiController;
 import io.swagger.annotations.Api;
 import java.util.List;
 import lombok.AllArgsConstructor;
+import ma.glasnost.orika.MapperFacade;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -36,15 +41,32 @@ public class ChannelMoneyController extends BaseApiController {
   @Autowired
   private IChannelMoneyLogService channelMoneyLogService;
 
+  @Autowired
+  private IChannelWithdrawService channelWithdrawService;
+
+  @Autowired
+  private MapperFacade mapperFacade;
+
   @RequestMapping(value = "/money/log", method = RequestMethod.POST)
   @ResponseBody
   public TableDataInfo listMoneyLog(@RequestBody ChannelMoneyLog channelMoneyLog) {
     Long channelId = SecurityUtils.getLoginUser().getChannelId();
     QueryWrapper<ChannelMoneyLog> queryWrapper = new QueryWrapper();
     queryWrapper.lambda().eq(ChannelMoneyLog::getChannelId, channelId);
-    queryWrapper.lambda().orderByDesc(ChannelMoneyLog::getBizTime);
+    queryWrapper.lambda().orderByDesc(ChannelMoneyLog::getCreatedTime);
     startPage();
     List<ChannelMoneyLog> list = channelMoneyLogService.list(queryWrapper);
-    return getDataTable(list);
+    List<ChannelMoneyLogVO> channelMoneyLogVOS = mapperFacade.mapAsList(list, ChannelMoneyLogVO.class);
+    for (ChannelMoneyLogVO logVO : channelMoneyLogVOS) {
+      if (logVO.getType() == ChannelMoneyEnum.WITHDRAW) {
+        ChannelWithdraw channelWithdraw = channelWithdrawService.getById(logVO.getRefId());
+        if (null != channelWithdraw) {
+          logVO.setWithdrawStatus(channelWithdraw.getStatus());
+        }
+      }
+    }
+    TableDataInfo resp = getDataTable(list);
+    resp.setRows(channelMoneyLogVOS);
+    return resp;
   }
 }

+ 24 - 7
mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/ChannelWithdrawController.java

@@ -79,7 +79,7 @@ public class ChannelWithdrawController extends BaseApiController {
   /**
    * 提现费率默认值
    */
-  private final String FEE_RATE_DEFAULT_VALUE = "8";
+  private final String FEE_RATE_DEFAULT_VALUE = "0.8";
 
   /**
    * 渠道提现计算手续费
@@ -88,21 +88,38 @@ public class ChannelWithdrawController extends BaseApiController {
   @ApiOperation(value = "提现" , notes = "提现计费")
   public AjaxResult settle(@Valid @RequestBody ChannelWithdrawParam param) {
     String feeRateValue = configService.selectConfigByKey(FEE_RATE_CONFIG_KEY);
-    BigDecimal feeRate = new BigDecimal(StringUtils.isNotBlank(feeRateValue) ? feeRateValue : FEE_RATE_DEFAULT_VALUE);
+    BigDecimal feeRate = new BigDecimal(
+        StringUtils.isNotBlank(feeRateValue) ? feeRateValue : FEE_RATE_DEFAULT_VALUE);
     Long channelId = SecurityUtils.getLoginUser().getChannelId();
+    Channel channel = channelService.getById(channelId);
+    /*if (channel.getMoney() < 50000) {
+      return AjaxResult.error("账户余额不足500元");
+    }*/
+    if (param.getMoney() > channel.getMoney() ) {
+      return AjaxResult.error("提现金额超出了余额");
+    }
+    int feeAmt = new BigDecimal(param.getMoney()).multiply(feeRate)
+        .divide(new BigDecimal(100), 0, RoundingMode.HALF_UP).intValue();
     ChannelWithdraw channelWithdraw = new ChannelWithdraw();
-    channelWithdraw.setMoney(param.getMoney());
-    BigDecimal feeAmt = new BigDecimal(param.getMoney()).multiply(feeRate).divide(new BigDecimal(1000), 2, RoundingMode.DOWN);
-    channelWithdraw.setChargeAmt(feeAmt.intValue());
+    if (param.getMoney() + feeAmt > channel.getMoney()) {
+      channelWithdraw.setMoney(new BigDecimal(channel.getMoney()).divide(new BigDecimal(1).add(feeRate.divide(new BigDecimal(100), 4, RoundingMode.HALF_UP)), 0, RoundingMode.HALF_UP).intValue());
+      channelWithdraw.setChargeAmt(channel.getMoney() - channelWithdraw.getMoney());
+    } else {
+      channelWithdraw.setMoney(param.getMoney());
+      channelWithdraw.setChargeAmt(feeAmt);
+  }
     channelWithdraw.setUserName(param.getUserName());
     channelWithdraw.setCardNo(param.getCardNo());
+    channelWithdraw.setBankName(param.getBankName());
     channelWithdraw.setBranchName(param.getBranchName());
 
     // 缓存订单结算对象
     redisCache.setCacheObject(CHANNEL_WITHDRAW_CACHE_KEY + channelId, channelWithdraw, 1, TimeUnit.MINUTES);
 
     JSONObject jsonObject = new JSONObject();
+    jsonObject.put("withdrawAmt", channelWithdraw.getMoney());
     jsonObject.put("chargeAmt", channelWithdraw.getChargeAmt());
+    jsonObject.put("chargeRate", feeRate);
     return AjaxResult.success(jsonObject);
   }
 
@@ -118,12 +135,12 @@ public class ChannelWithdrawController extends BaseApiController {
       return AjaxResult.error("申请已过期,请重新提交");
     }
     Channel channel = channelService.getById(channelId);
-    if (channelWithdraw.getMoney() > channel.getMoney() ) {
+    if (channelWithdraw.getMoney() + channelWithdraw.getChargeAmt() > channel.getMoney() ) {
       return AjaxResult.error("提现金额超出账户余额");
     }
 
     channelWithdraw.setChannelId(channelId);
-    channelWithdraw.setLogMoney(channel.getMoney());
+    channelWithdraw.setAvailableMoney(channel.getMoney());
 
     channelWithdrawService.apply(channel, channelWithdraw);
 

+ 0 - 10
mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/mall/ChannelCartController.java

@@ -1,13 +1,3 @@
-/*
- * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
- *
- * https://www.mall4j.com/
- *
- * 未经允许,不可做商业用途!
- *
- * 版权所有,侵权必究!
- */
-
 package com.qs.mp.web.controller.api.channel.mall;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

+ 61 - 18
mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/mall/ChannelOrderController.java

@@ -1,13 +1,3 @@
-/*
- * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
- *
- * https://www.mall4j.com/
- *
- * 未经允许,不可做商业用途!
- *
- * 版权所有,侵权必究!
- */
-
 package com.qs.mp.web.controller.api.channel.mall;
 
 import com.alibaba.fastjson.JSONObject;
@@ -15,6 +5,15 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.qs.mp.admin.domain.TicketBox;
 import com.qs.mp.admin.service.ITicketBoxService;
 import com.qs.mp.channel.domain.Channel;
+import com.qs.mp.channel.domain.ChannelOrderDetail;
+import com.qs.mp.channel.domain.vo.ChannelOrderInfoVO;
+import com.qs.mp.channel.domain.vo.ChannelOrderItemVO;
+import com.qs.mp.channel.service.IChannelOrderDetailService;
+import com.qs.mp.common.domain.DeliveryCompany;
+import com.qs.mp.common.service.IDeliveryCompanyService;
+import com.qs.mp.common.utils.StringUtils;
+import com.qs.mp.system.domain.SysUser;
+import com.qs.mp.system.service.ISysUserService;
 import com.qs.mp.user.domain.UserAddr;
 import com.qs.mp.channel.domain.ChannelCart;
 import com.qs.mp.channel.domain.ChannelOrder;
@@ -87,6 +86,15 @@ public class ChannelOrderController extends BaseApiController {
   @Autowired
   private IChannelService channelService;
 
+  @Autowired
+  private IDeliveryCompanyService deliveryCompanyService;
+
+  @Autowired
+  private IChannelOrderDetailService channelOrderDetailService;
+
+  @Autowired
+  private ISysUserService sysUserService;
+
   @Autowired
   private RedisCache redisCache;
 
@@ -107,8 +115,11 @@ public class ChannelOrderController extends BaseApiController {
             .orderByDesc(ChannelOrder::getCreatedTime));
     List<ChannelOrderVO> channelOrderVOList = mapperFacade.mapAsList(channelOrders, ChannelOrderVO.class);
     for (ChannelOrderVO channelOrderVO : channelOrderVOList) {
-      channelOrderVO.setItems(channelOrderItemService.list(new LambdaQueryWrapper<ChannelOrderItem>()
-          .eq(ChannelOrderItem::getOrderId, channelOrderVO.getOrderId())));
+    	List<ChannelOrderItem> itemList = channelOrderItemService.list(new LambdaQueryWrapper<ChannelOrderItem>()
+     	          .eq(ChannelOrderItem::getOrderId, channelOrderVO.getOrderId()));
+
+     	 List<ChannelOrderItemVO> itemVOList = mapperFacade.mapAsList(itemList, ChannelOrderItemVO.class);
+         channelOrderVO.setItems(itemVOList);
     }
     TableDataInfo rspData = getDataTable(channelOrders);
     rspData.setRows(channelOrderVOList);
@@ -124,9 +135,29 @@ public class ChannelOrderController extends BaseApiController {
     Long channelId = SecurityUtils.getLoginUser().getChannelId();
     ChannelOrder channelOrder = channelOrderService.getOne(new LambdaQueryWrapper<ChannelOrder>()
         .eq(ChannelOrder::getOrderId, order.getOrderId()).eq(ChannelOrder::getChannelId, channelId));
-    ChannelOrderVO channelOrderVO = mapperFacade.map(channelOrder, ChannelOrderVO.class);
-    channelOrderVO.setItems(channelOrderItemService.list(new LambdaQueryWrapper<ChannelOrderItem>()
-        .eq(ChannelOrderItem::getOrderId, channelOrderVO.getOrderId())));
+    ChannelOrderInfoVO channelOrderVO = mapperFacade.map(channelOrder, ChannelOrderInfoVO.class);
+
+    if(null != channelOrderVO && null != channelOrderVO.getDeliveryId()) {
+      DeliveryCompany deliveryCompany = deliveryCompanyService.getById(channelOrderVO.getDeliveryId());
+      channelOrderVO.setDeliveryCompany(deliveryCompany);
+    }
+    List<ChannelOrderItem> itemList = channelOrderItemService.list(new LambdaQueryWrapper<ChannelOrderItem>()
+        .eq(ChannelOrderItem::getOrderId, channelOrderVO.getOrderId()));
+
+    List<ChannelOrderItemVO> itemVOList = mapperFacade.mapAsList(itemList, ChannelOrderItemVO.class);
+    if(null != itemVOList && itemVOList.size() > 0) {
+      for(ChannelOrderItemVO itemVO : itemVOList) {
+        if(null != itemVO && org.apache.commons.lang3.StringUtils.isNotBlank(itemVO.getBoxId())
+            && org.apache.commons.lang3.StringUtils.isNotBlank(itemVO.getOrderId())) {
+          LambdaQueryWrapper<ChannelOrderDetail> detailQueryWrapper = new LambdaQueryWrapper<ChannelOrderDetail>();
+          detailQueryWrapper.eq(ChannelOrderDetail::getOrderId, itemVO.getOrderId());
+          detailQueryWrapper.eq(ChannelOrderDetail::getBoxId, itemVO.getBoxId());
+          List<ChannelOrderDetail> detailList = channelOrderDetailService.list(detailQueryWrapper);
+          itemVO.setDetailList(detailList);
+        }
+      }
+    }
+    channelOrderVO.setItems(itemVOList);
     return AjaxResult.success(channelOrderVO);
   }
 
@@ -137,6 +168,7 @@ public class ChannelOrderController extends BaseApiController {
   @ApiOperation(value = "订单结算" , notes = "购物车里点结算或者单个盲票组商品上点立即购买")
   public AjaxResult settle(@Valid @RequestBody ChannelOrderParam param) {
     Long userId = SecurityUtils.getLoginUser().getUserId();
+    Long channelId = SecurityUtils.getLoginUser().getChannelId();
 
     ChannelOrderSettleVO orderSettleVO = new ChannelOrderSettleVO();
 
@@ -178,7 +210,7 @@ public class ChannelOrderController extends BaseApiController {
     orderSettleVO.setPkgNum(pkgNum);
 
     // 缓存订单结算对象
-    redisCache.setCacheObject(RedisKey.build(RedisKey.CHANNEL_ORDER_KEY, userId), orderSettleVO, 10, TimeUnit.MINUTES);
+    redisCache.setCacheObject(RedisKey.build(RedisKey.CHANNEL_ORDER_KEY, channelId), orderSettleVO, 10, TimeUnit.MINUTES);
     return AjaxResult.success(orderSettleVO);
   }
 
@@ -227,12 +259,23 @@ public class ChannelOrderController extends BaseApiController {
   @PostMapping("/order/pay")
   @ApiOperation(value = "订单支付" , notes = "在订单列表页面支付")
   public AjaxResult pay(@Valid @RequestBody OrderPayParam param) {
-    String openId = SecurityUtils.getLoginUser().getUser().getChannelOpenId();
+    Long userId = SecurityUtils.getLoginUser().getUserId();
+    SysUser sysUser = sysUserService.selectUserById(userId);
+    String channelOpenId = "";
+    if (StringUtils.isNotBlank(param.getOpenId())) {
+      channelOpenId = param.getOpenId();
+    } else {
+      channelOpenId = sysUser.getChannelOpenId();
+    }
+    if (StringUtils.isBlank(channelOpenId)) {
+      return AjaxResult.error(ErrorCodeEnum.ERROR_CODE_1005);
+    }
     ChannelOrder channelOrder = channelOrderService.getById(param.getOrderId());
     JSONObject jsonObject;
     try {
-      jsonObject = walletService.pay(BizTypeEnum.CHANNEL_ORDER, param.getOrderId(), openId, channelOrder.getPayAmt());
+      jsonObject = walletService.pay(BizTypeEnum.CHANNEL_ORDER, param.getOrderId(), channelOpenId, channelOrder.getPayAmt());
     }catch (ServiceException e) {
+      LogUtil.error(logger, e, "根据经销商采购订单创建支付单失败。userId:{0},orderId:{1}", new Object[]{userId, param.getOrderId()});
       return AjaxResult.error(e.getMessage());
     }
     return AjaxResult.success(jsonObject);

+ 0 - 10
mp-admin/src/main/java/com/qs/mp/web/controller/api/channel/mall/ChannelTicketController.java

@@ -1,13 +1,3 @@
-/*
- * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
- *
- * https://www.mall4j.com/
- *
- * 未经允许,不可做商业用途!
- *
- * 版权所有,侵权必究!
- */
-
 package com.qs.mp.web.controller.api.channel.mall;
 
 import com.baomidou.mybatisplus.core.conditions.Wrapper;

+ 0 - 10
mp-admin/src/main/java/com/qs/mp/web/controller/api/common/AreaQueryController.java

@@ -1,13 +1,3 @@
-/*
- * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
- *
- * https://www.mall4j.com/
- *
- * 未经允许,不可做商业用途!
- *
- * 版权所有,侵权必究!
- */
-
 package com.qs.mp.web.controller.api.common;
 
 import com.alibaba.fastjson.JSONObject;

+ 40 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/common/DeliveryCompanyController.java

@@ -0,0 +1,40 @@
+package com.qs.mp.web.controller.api.common;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.domain.Area;
+import com.qs.mp.common.domain.DeliveryCompany;
+import com.qs.mp.common.service.IAreaService;
+import com.qs.mp.common.service.IDeliveryCompanyService;
+import com.qs.mp.web.controller.common.BaseApiController;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 快递公司
+ * @author zhongcp on 2022/3/2.
+ */
+@RestController
+@RequestMapping("/api/v1/mp/delivery")
+@Api(tags="快递公司接口")
+public class DeliveryCompanyController extends BaseApiController {
+
+    @Autowired
+    private IDeliveryCompanyService deliveryCompanyService;
+
+    @PostMapping("/company/list")
+    @ApiOperation(value="获取快递公司列表", notes="")
+	public AjaxResult list(@RequestBody JSONObject jsonObject){
+		  List<DeliveryCompany> list = deliveryCompanyService.list(new LambdaQueryWrapper<DeliveryCompany>()
+          .orderByAsc(DeliveryCompany::getCreatedTime));
+		  return AjaxResult.success(list);
+	}
+
+}

+ 124 - 22
mp-admin/src/main/java/com/qs/mp/web/controller/api/common/UserController.java

@@ -1,9 +1,12 @@
 package com.qs.mp.web.controller.api.common;
 
 import cn.jsms.api.ValidSMSResult;
+import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.qs.mp.channel.domain.Channel;
+import com.qs.mp.channel.service.IChannelService;
 import com.qs.mp.common.constant.Constants;
 import com.qs.mp.common.core.domain.AjaxResult;
 import com.qs.mp.common.enums.UserIdentityEnum;
@@ -29,10 +32,14 @@ import io.swagger.annotations.Api;
 import java.io.File;
 import java.net.HttpURLConnection;
 import java.net.URL;
+import java.nio.charset.StandardCharsets;
 import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
 import org.apache.commons.io.FileUtils;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
@@ -42,6 +49,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.ResponseBody;
 import org.springframework.web.bind.annotation.RestController;
+import sun.misc.BASE64Decoder;
+import sun.misc.BASE64Encoder;
 
 /**
  * @auther duota
@@ -64,6 +73,9 @@ public class UserController extends BaseApiController {
   @Autowired
   private IWxAccountService wxAccountService;
 
+  @Autowired
+  private IChannelService channelService;
+
   @Value("${wx-channel.appId}")
   private String channelAppId;
   @Value("${wx-channel.appSecret}")
@@ -92,6 +104,10 @@ public class UserController extends BaseApiController {
   @Autowired
   private SysLoginService sysLoginService;
 
+  private static final String CBC_CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
+  private static final String KEY_ALGORITHM = "AES";
+  private static final String UTF8 = "UTF-8";
+
 
   @RequestMapping(value = "/user/wxauth", method = RequestMethod.POST)
   @ResponseBody
@@ -103,7 +119,7 @@ public class UserController extends BaseApiController {
       appSecret = userAppSecret;
     }
     //调用微信后台接口获取openId
-    String res = wxLoginCheck(wxLoginParams, appId, appSecret);
+    String res = wxLoginCheck(wxLoginParams.getCode(), appId, appSecret);
     JSONObject jsonObject = JSONObject.parseObject(res);
     String openId = jsonObject.getString("openid");
     String sessionKey = jsonObject.getString("session_key");
@@ -114,7 +130,7 @@ public class UserController extends BaseApiController {
       return error("登录失败");
     }
     //更新数据库用户授权信息
-    LoginUser loginUser = hostHolder.getUser();
+    LoginUser loginUser = SecurityUtils.getLoginUser();
     SysUser user = new SysUser();
     user.setUserId(loginUser.getUserId());
     if (wxLoginParams.getIdentity() == UserIdentityEnum.USER.ordinal()) {
@@ -126,6 +142,7 @@ public class UserController extends BaseApiController {
     user.setSessionKey(sessionKey);
     user.setUnionId(unionId);
     user.setLoginDate(new Date());
+    user.setNickName(wxLoginParams.getNickName());
     //如果用户头像字段为空,则默认获取用户微信头像
     String avatarUrl = wxLoginParams.getAvatarUrl();
 
@@ -154,7 +171,9 @@ public class UserController extends BaseApiController {
       LogUtil.error(logger,"用户微信授权异常");
       return error("用户微信授权异常");
     }
-    return success("微信授权成功");
+    JSONObject rst = new JSONObject();
+    rst.put("openId", openId);
+    return success(rst);
   }
 
 
@@ -163,23 +182,60 @@ public class UserController extends BaseApiController {
   public AjaxResult wxauthMobile(@RequestBody WxLoginParams wxLoginParams) {
     String appId = userAppId;
     String appSecret = userAppSecret;
-    if (UserIdentityEnum.isChannel(wxLoginParams.getIdentity())) {
+    /*if (UserIdentityEnum.isChannel(wxLoginParams.getIdentity())) {
       appId = channelAppId;
       appSecret = channelAppSecret;
+    }*/
+    JSONObject phoneInfo;
+    if (StringUtils.isNotBlank(wxLoginParams.getCode())) {
+      //调用微信后台接口获取openId
+      String res = getWxMobile(wxLoginParams, appId);
+      JSONObject jsonObject = JSONObject.parseObject(res);
+      int errcode = jsonObject.getIntValue("errcode");
+      if (errcode != 0) {
+        LogUtil.error(logger, "手机号获取失败:" + res);
+        return error("手机号获取失败");
+      }
+      phoneInfo = jsonObject.getJSONObject("phone_info");
+    } else {
+      //调用微信后台接口获取openId
+      String rtn = wxLoginCheck(wxLoginParams.getLoginCode(), appId, appSecret);
+      JSONObject jsonObject = JSONObject.parseObject(rtn);
+      String openId = jsonObject.getString("openid");
+      String sessionKey = jsonObject.getString("session_key");
+
+      if (StringUtils.isBlank(openId) || StringUtils.isBlank(sessionKey)) {
+        LogUtil.error(logger, "微信登录失败:" + jsonObject.toJSONString());
+        return error("登录失败");
+      }
+
+      String res = weixinDecrypt(wxLoginParams.getEncryptedData(), sessionKey, wxLoginParams.getIv());
+      if (StringUtils.isBlank(res)) {
+        return error("手机号获取失败");
+      }
+      /**
+       * {
+       *     "phoneNumber": "13580006666",
+       *     "purePhoneNumber": "13580006666",
+       *     "countryCode": "86",
+       *     "watermark":
+       *     {
+       *         "appid":"APPID",
+       *         "timestamp": TIMESTAMP
+       *     }
+       * }
+       */
+      phoneInfo = JSON.parseObject(res);
+      JSONObject watermark = phoneInfo.getJSONObject("watermark");
+      if (!appId.equals(watermark.getString("appid"))) {
+        LogUtil.error(logger, "手机号解密appid不符,appid:{0}",  watermark.getString("appid"));
+        return error("手机号获取失败");
+      }
     }
-    //调用微信后台接口获取openId
-    String res = getWxMobile(wxLoginParams, appId);
-    JSONObject jsonObject = JSONObject.parseObject(res);
-    int errcode = jsonObject.getIntValue("errcode");
-    if (errcode != 0 ) {
-      LogUtil.error(logger, "手机号获取失败:" + res);
-      return error("手机号获取失败");
-    }
-    JSONObject phoneInfo = jsonObject.getJSONObject("phone_info");
     String phoneNumber = phoneInfo.getString("phoneNumber");
 
     if (StringUtils.isBlank(phoneNumber)) {
-      LogUtil.error(logger, "微信手机号不存在:" + res);
+      LogUtil.error(logger, "微信手机号不存在:" + phoneInfo);
       return error("手机号获取失败");
     }
     AjaxResult ajax = AjaxResult.success();
@@ -228,18 +284,26 @@ public class UserController extends BaseApiController {
    */
   @RequestMapping(value = "/user/getLoginUserinfo", method = RequestMethod.POST)
   public AjaxResult getLoginUserinfo(@RequestBody JSONObject params) {
-    LoginUser loginUser = hostHolder.getUser();
+    LoginUser loginUser = SecurityUtils.getLoginUser();
+    SysUser sysUser = sysUserService.selectUserById(SecurityUtils.getUserId());
+
     JSONObject jsonObject = new JSONObject();
-    jsonObject.put("userName", loginUser.getUsername());
-    jsonObject.put("avatar", loginUser.getUser().getAvatar());
-    jsonObject.put("nickName", loginUser.getUser().getNickName());
-    jsonObject.put("openId", loginUser.getUser().getOpenId());
-    jsonObject.put("channelOpenId", loginUser.getUser().getChannelOpenId());
+    jsonObject.put("userName", sysUser.getUserName());
+    jsonObject.put("avatar", sysUser.getAvatar());
+    if(loginUser.getIdentity() == UserIdentityEnum.CHANNEL) {
+      Channel channel = channelService.getById(loginUser.getChannelId());
+      jsonObject.put("nickName", channel.getName());
+    } else {
+      jsonObject.put("nickName", sysUser.getNickName());
+    }
+    jsonObject.put("openId", sysUser.getOpenId());
+    jsonObject.put("channelOpenId", sysUser.getChannelOpenId());
     JSONArray roleKeys = new JSONArray();
     JSONArray roles = new JSONArray();
     loginUser.getUser().getRoles().forEach(sysRole -> roles.add(sysRole.getRoleName()));
     jsonObject.put("roleKeys", roleKeys);
     jsonObject.put("roles", roles);
+    jsonObject.put("userId", SecurityUtils.getUserId());
 
     return success(jsonObject);
   }
@@ -252,8 +316,8 @@ public class UserController extends BaseApiController {
    * @param
    * @return
    */
-  private String wxLoginCheck(WxLoginParams params, String appId, String appSecret) {
-    String param = "appid=" + appId + "&secret=" + appSecret + "&js_code=" + params.getCode()
+  private String wxLoginCheck(String code, String appId, String appSecret) {
+    String param = "appid=" + appId + "&secret=" + appSecret + "&js_code=" + code
         + "&grant_type=authorization_code";
     String res = HttpUtils.sendGet("https://api.weixin.qq.com/sns/jscode2session", param);
     return res;
@@ -336,4 +400,42 @@ public class UserController extends BaseApiController {
     return result;
   }
 
+  /**
+   * 带有初始变量的解密(微信用)
+   *
+   * @param content     密文
+   * @param skey        密钥
+   * @param ivParameter 初始向量
+   * @return
+   * @throws Exception
+   */
+  public String weixinDecrypt(String content, String skey, String ivParameter) {
+    try {
+      BASE64Decoder decoder = new BASE64Decoder();
+      // 根据微信文档要求需要把 密文、密钥、iv 使用BASE64进行解码
+      byte[] keyByte = decoder.decodeBuffer(skey);
+      byte[] contentByte = decoder.decodeBuffer(content);
+      byte[] ivByte = decoder.decodeBuffer(ivParameter);
+      // 生成密码
+      SecretKeySpec keySpec = new SecretKeySpec(keyByte, KEY_ALGORITHM);
+      // 生成IvParameterSpec
+      IvParameterSpec iv = new IvParameterSpec(ivByte);
+      // 初始化解密 指定模式 AES/CBC/PKCS5Padding
+      Cipher cipher = Cipher.getInstance(CBC_CIPHER_ALGORITHM);
+      // 指定解密模式 传入密码 iv
+      cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
+      // 解密
+      byte[] result = cipher.doFinal(contentByte);
+      return new String(result, UTF8);
+    } catch (Exception e) {
+      LogUtil.error(logger, e, "【解密错误】content:{0},ivParameter:{1}", new Object[]{content, ivParameter});
+      return null;
+    }
+  }
+
+  public static void main(String[] args) {
+    UserController userController = new UserController();
+    System.out.println(userController.weixinDecrypt("qvNE+SHdiP2GTbmNaqahrhhLw7EZetcMhUMV9yPXHxBbWOMcZ5gFxOGliXC9uojyC0NDUXCUi1xvFVDKMYREQ7rLXXrZIkB1jEleJNuUb9kO3LCDRucvbGAbVwm2EsTNsd5VbqI3fKdu0IOxmmSAWCLZNGXZBlki4ke62lI+ASg6dPohQmmCux8jwD2Js3ZnDQN2mb0JPRT68Qj716gYvA==", "QJ/WdeFANTIfIErOCJ2jNg==", "60YJmIckq4kaXp88wAGGHA=="));
+  }
+
 }

+ 0 - 10
mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserAddrController.java

@@ -1,13 +1,3 @@
-/*
- * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
- *
- * https://www.mall4j.com/
- *
- * 未经允许,不可做商业用途!
- *
- * 版权所有,侵权必究!
- */
-
 package com.qs.mp.web.controller.api.user;
 
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

+ 78 - 12
mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserDeliverOrderController.java

@@ -1,44 +1,51 @@
-/*
- * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
- *
- * https://www.mall4j.com/
- *
- * 未经允许,不可做商业用途!
- *
- * 版权所有,侵权必究!
- */
-
 package com.qs.mp.web.controller.api.user;
 
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.serializer.SerializerFeature;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.qs.mp.channel.domain.ChannelOrder;
+import com.qs.mp.channel.domain.ChannelOrderItem;
 import com.qs.mp.channel.domain.param.OrderPayParam;
+import com.qs.mp.channel.domain.vo.ChannelOrderVO;
 import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.core.page.TableDataInfo;
 import com.qs.mp.common.core.redis.RedisCache;
 import com.qs.mp.common.enums.BizTypeEnum;
+import com.qs.mp.common.enums.ErrorCodeEnum;
 import com.qs.mp.common.enums.PrizeStorageStatusEnum;
 import com.qs.mp.common.exception.ServiceException;
+import com.qs.mp.common.service.IDeliveryCompanyService;
+import com.qs.mp.common.utils.LogUtil;
+import com.qs.mp.common.utils.StringUtils;
 import com.qs.mp.framework.redis.RedisKey;
 import com.qs.mp.pay.service.IWalletService;
+import com.qs.mp.system.domain.SysUser;
+import com.qs.mp.system.service.ISysUserService;
 import com.qs.mp.user.domain.UserAddr;
 import com.qs.mp.user.domain.UserDeliverOrder;
+import com.qs.mp.user.domain.UserDeliverOrderItem;
 import com.qs.mp.user.domain.UserPrizeStorage;
 import com.qs.mp.user.domain.param.DeliverOrderParam;
 import com.qs.mp.user.domain.vo.DeliverOrderSettleVO;
+import com.qs.mp.user.domain.vo.DeliverOrderVO;
 import com.qs.mp.user.service.IUserAddrService;
+import com.qs.mp.user.service.IUserDeliverOrderItemService;
 import com.qs.mp.user.service.IUserDeliverOrderService;
 import com.qs.mp.user.service.IUserPrizeStorageService;
 import com.qs.mp.utils.SecurityUtils;
 import com.qs.mp.web.controller.common.BaseApiController;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 import javax.validation.Valid;
 import lombok.AllArgsConstructor;
 import ma.glasnost.orika.MapperFacade;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.CollectionUtils;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -60,15 +67,64 @@ public class UserDeliverOrderController extends BaseApiController {
   @Autowired
   private IUserDeliverOrderService userDeliverOrderService;
 
+  @Autowired
+  private IUserDeliverOrderItemService userDeliverOrderItemService;
+
   @Autowired
   private IWalletService walletService;
 
   @Autowired
   private MapperFacade mapperFacade;
 
+  @Autowired
+  private ISysUserService sysUserService;
+
   @Autowired
   private RedisCache redisCache;
 
+  /**
+   * 订单列表
+   */
+  @PostMapping("/order/list")
+  @ApiOperation(value = "订单列表" , notes = "获取所有订单信息")
+  public TableDataInfo list(@RequestBody JSONObject param) {
+    Long userId = SecurityUtils.getLoginUser().getUserId();
+    String status = param.getString("status");
+    List<Integer> statusList = new ArrayList<>();
+    if (StringUtils.isNotBlank(status)) {
+      String[] arr = status.split(",");
+      for (int i = 0; i < arr.length; i++) {
+        statusList.add(Integer.valueOf(arr[i]));
+      }
+    }
+    startPage();
+    List<UserDeliverOrder> deliverOrders = userDeliverOrderService.list(
+        new LambdaQueryWrapper<UserDeliverOrder>().eq(UserDeliverOrder::getUserId, userId)
+            .in(!CollectionUtils.isEmpty(statusList), UserDeliverOrder::getStatus, statusList)
+            .orderByDesc(UserDeliverOrder::getCreatedTime));
+    List<DeliverOrderVO> deliverOrderVOList = mapperFacade.mapAsList(deliverOrders, DeliverOrderVO.class);
+    for (DeliverOrderVO deliverOrderVO : deliverOrderVOList) {
+      deliverOrderVO.setItems(userDeliverOrderItemService.selectUserDeliverOrderItemVOList(deliverOrderVO.getOrderId()));
+    }
+    TableDataInfo rspData = getDataTable(deliverOrders);
+    rspData.setRows(deliverOrderVOList);
+    return rspData;
+  }
+
+  /**
+   * 订单详情
+   */
+  @PostMapping("/order/detail")
+  @ApiOperation(value = "订单详情" , notes = "在订单列表页面查看详情")
+  public AjaxResult query(@RequestBody UserDeliverOrder order) {
+    Long userId = SecurityUtils.getLoginUser().getUserId();
+    UserDeliverOrder deliverOrder = userDeliverOrderService.getOne(new LambdaQueryWrapper<UserDeliverOrder>()
+        .eq(UserDeliverOrder::getOrderId, order.getOrderId()).eq(UserDeliverOrder::getUserId, userId));
+    DeliverOrderVO deliverOrderVO = mapperFacade.map(deliverOrder, DeliverOrderVO.class);
+    deliverOrderVO.setItems(userDeliverOrderItemService.selectUserDeliverOrderItemVOList(deliverOrder.getOrderId()));
+    deliverOrderVO.setDeliverList(userDeliverOrderItemService.getDeliverItemList(order.getOrderId(), deliverOrderVO.getItems()));
+    return AjaxResult.success(deliverOrderVO);
+  }
 
   /**
    * 订单结算,每次更换地址时需重新请求此接口
@@ -119,11 +175,16 @@ public class UserDeliverOrderController extends BaseApiController {
     if (null == orderSettleVO) {
       return AjaxResult.error("订单已过期,请重新下单");
     }
+    if (null == orderSettleVO.getAddr()) {
+      return AjaxResult.error("请填写收货地址");
+    }
     String orderId = userDeliverOrderService.submitOrder(userId, orderSettleVO);
     JSONObject jsonObject = new JSONObject();
     jsonObject.put("orderId", orderId);
     if (orderSettleVO.getPayAmt() > 0) {
       jsonObject.put("needPay", 1);
+    } else {
+      jsonObject.put("needPay", 0);
     }
     // 清除缓存的订单
     redisCache.deleteObject(RedisKey.build(RedisKey.USER_TICKET_ORDER_KEY, userId));
@@ -148,12 +209,17 @@ public class UserDeliverOrderController extends BaseApiController {
   @PostMapping("/order/pay")
   @ApiOperation(value = "订单支付" , notes = "订单支付")
   public AjaxResult pay(@Valid @RequestBody OrderPayParam param) {
-    String openId = SecurityUtils.getLoginUser().getUser().getOpenId();
+    Long userId = SecurityUtils.getLoginUser().getUserId();
+    SysUser sysUser = sysUserService.selectUserById(userId);
+    if (StringUtils.isBlank(sysUser.getOpenId())) {
+      return AjaxResult.error(ErrorCodeEnum.ERROR_CODE_1005);
+    }
     UserDeliverOrder deliverOrder = userDeliverOrderService.getById(param.getOrderId());
     JSONObject jsonObject;
     try {
-      jsonObject = walletService.pay(BizTypeEnum.DELIVER_ORDER, param.getOrderId(), openId, deliverOrder.getPayAmt());
+      jsonObject = walletService.pay(BizTypeEnum.DELIVER_ORDER, param.getOrderId(), sysUser.getOpenId(), deliverOrder.getPayAmt());
     }catch (ServiceException e) {
+      LogUtil.error(logger, e, "根据提货单创建支付单失败。userId:{0},orderId:{1}", new Object[]{userId, param.getOrderId()});
       return AjaxResult.error(e.getMessage());
     }
     return AjaxResult.success(jsonObject);

+ 197 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserExchangeController.java

@@ -0,0 +1,197 @@
+package com.qs.mp.web.controller.api.user;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.qs.mp.admin.domain.ExchangeBanner;
+import com.qs.mp.admin.domain.Goods;
+import com.qs.mp.admin.domain.GoodsCategory;
+import com.qs.mp.admin.domain.GoodsSku;
+import com.qs.mp.admin.domain.GoodsTag;
+import com.qs.mp.admin.domain.GoodsTagRel;
+import com.qs.mp.admin.domain.vo.GoodsListVO;
+import com.qs.mp.admin.domain.vo.GoodsVO;
+import com.qs.mp.admin.service.IExchangeBannerService;
+import com.qs.mp.admin.service.IGoodsCategoryService;
+import com.qs.mp.admin.service.IGoodsService;
+import com.qs.mp.admin.service.IGoodsSkuService;
+import com.qs.mp.admin.service.IGoodsTagRelService;
+import com.qs.mp.admin.service.IGoodsTagService;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.core.page.TableDataInfo;
+import com.qs.mp.common.enums.ErrorCodeEnum;
+import com.qs.mp.common.enums.GoodsStatusEnum;
+import com.qs.mp.common.utils.StringUtils;
+import com.qs.mp.user.domain.param.ExchangeOrderParam;
+import com.qs.mp.user.service.IUserExchangeOrderService;
+import com.qs.mp.utils.SecurityUtils;
+import com.qs.mp.web.controller.common.BaseApiController;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Collectors;
+import lombok.AllArgsConstructor;
+import ma.glasnost.orika.MapperFacade;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+
+@RestController
+@RequestMapping("/api/v1/mp/user/exchange")
+@Api(tags = "盲票商城接口")
+@AllArgsConstructor
+public class UserExchangeController extends BaseApiController {
+
+
+  @Autowired
+  private IGoodsService goodsService;
+
+  @Autowired
+  private IGoodsSkuService goodsSkuService;
+
+  @Autowired
+  private IUserExchangeOrderService userExchangeOrderService;
+
+  @Autowired
+  private IGoodsTagRelService goodsTagRelService;
+
+  @Autowired
+  private IExchangeBannerService exchangeBannerService;
+
+  @Autowired
+  private IGoodsCategoryService goodsCategoryService;
+
+  @Autowired
+  private IGoodsTagService goodsTagService;
+
+  @Autowired
+  private MapperFacade mapperFacade;
+
+  /**
+   * 商品列表
+   */
+  @PostMapping("/goods/list")
+  @ApiOperation(value = "商品列表", notes = "获取所有可兑换商品")
+  public TableDataInfo list(@RequestBody JSONObject param) {
+    Long categoryId = param.getLong("categoryId");
+    String tagIds = param.getString("tagIds");
+    Integer startPrice = param.getInteger("startPrice");
+    Integer endPrice = param.getInteger("endPrice");
+
+    List<Long> goodsIds = new ArrayList<>();
+    if (StringUtils.isNotBlank(tagIds)) {
+      List<GoodsTagRel> goodsTagRelList = goodsTagRelService.list(
+          new LambdaQueryWrapper<GoodsTagRel>()
+              .in(GoodsTagRel::getTagId, Arrays.asList(tagIds.split(","))));
+      goodsIds = goodsTagRelList.stream().map(GoodsTagRel::getGoodsId).collect(Collectors.toList());
+    }
+    startPage();
+    List<Goods> goodsList = goodsService.list(new LambdaQueryWrapper<Goods>()
+        .eq(null != categoryId && 0 != categoryId, Goods::getCategoryId, categoryId)
+        .ge(null != startPrice && 0 != startPrice, Goods::getExchangePrice, startPrice)
+        .le(null != endPrice && 0 != endPrice, Goods::getExchangePrice, endPrice)
+        .eq(Goods::getStatus, GoodsStatusEnum.PUT_ON)
+        .eq(Goods::getExchangeShow, 1)
+        .in(!CollectionUtils.isEmpty(goodsIds), Goods::getGoodsId, goodsIds));
+    List<GoodsListVO> goodsListVOList = mapperFacade.mapAsList(goodsList, GoodsListVO.class);
+    TableDataInfo rspData = getDataTable(goodsList);
+    rspData.setRows(goodsListVOList);
+    return rspData;
+  }
+
+
+  /**
+   * 查看商品详情
+   */
+  @PostMapping("/goods/detail")
+  @ApiOperation(value = "查看商品详情", notes = "根据商品ID,获取商品信息")
+  public AjaxResult getInfo(@RequestBody Goods param) {
+    if (null == param.getGoodsId() || 0 == param.getGoodsId()) {
+      return AjaxResult.error("参数异常,商品ID缺失");
+    }
+    Goods goods = goodsService.getById(param.getGoodsId());
+    GoodsVO goodsVo = new GoodsVO();
+    BeanUtils.copyProperties(goods, goodsVo);
+    // 查询SKU列表
+    LambdaQueryWrapper<GoodsSku> queryWrapper = new LambdaQueryWrapper<>();
+    queryWrapper.eq(GoodsSku::getGoodsId, goods.getGoodsId());
+    queryWrapper.orderByDesc(GoodsSku::getCreatedTime);
+    List<GoodsSku> skuList = goodsSkuService.list(queryWrapper);
+    if (null != skuList && skuList.size() > 0) {
+      goodsVo.setSkuList(skuList);
+    }
+    return AjaxResult.success(goodsVo);
+  }
+
+  /**
+   * 提交兑换订单
+   */
+  @PostMapping("/submit")
+  @ApiOperation(value = "提交兑换订单", notes = "提交兑换订单")
+  public AjaxResult submit(@RequestBody ExchangeOrderParam param) {
+    Long userId = SecurityUtils.getUserId();
+    if (null == param.getGoodsId() || 0 == param.getGoodsId() || null == param.getOrderNum()
+        || param.getOrderNum() == 0) {
+      return AjaxResult.error("参数缺失");
+    }
+    boolean result = userExchangeOrderService.exchange(userId, param.getGoodsId(), param.getSkuId(),
+        param.getOrderNum());
+    if (!result) {
+      return AjaxResult.error(ErrorCodeEnum.ERROR_CODE_1021);
+    }
+    return AjaxResult.success();
+  }
+
+  /**
+   * 查询banner列表
+   */
+  @PostMapping("/banner/list")
+  @ApiOperation(value = "查询banner列表", notes = "banner列表")
+  public AjaxResult listBanner(@RequestBody JSONObject param) {
+    String location = param.getString("location");
+    List<ExchangeBanner> bannerList = exchangeBannerService.list(
+        new LambdaQueryWrapper<ExchangeBanner>()
+            .eq(ExchangeBanner::getLocation, location).orderByDesc(ExchangeBanner::getSort));
+    return AjaxResult.success(bannerList);
+  }
+
+  /**
+   * 查询分类列表
+   */
+  @PostMapping("/category/list")
+  @ApiOperation(value = "查询分类列表", notes = "分类列表")
+  public AjaxResult listCategory(@RequestBody JSONObject param) {
+    List<GoodsCategory> categoryList = goodsCategoryService.list(
+        new LambdaQueryWrapper<GoodsCategory>()
+            .eq(GoodsCategory::getIsShow, 1).orderByDesc(GoodsCategory::getSort));
+    return AjaxResult.success(categoryList);
+  }
+
+  /**
+   * 查询标签列表
+   */
+  @PostMapping("/activity/list")
+  @ApiOperation(value = "查询标签列表", notes = "标签列表")
+  public AjaxResult listActivity(@RequestBody JSONObject param) {
+    List<GoodsTag> tagList = goodsTagService.list(new LambdaQueryWrapper<GoodsTag>()
+        .eq(GoodsTag::getIsShow, 1).orderByDesc(GoodsTag::getSort));
+    Iterator<GoodsTag> iterator = tagList.iterator();
+    while (iterator.hasNext()) {
+      GoodsTag next = iterator.next();
+      int cnt = goodsTagRelService.count(
+          new LambdaQueryWrapper<GoodsTagRel>().eq(GoodsTagRel::getTagId, next.getTagId()));
+      if (cnt < 2) {
+        iterator.remove();
+      }
+    }
+    return AjaxResult.success(tagList);
+  }
+
+}

+ 17 - 20
mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserMineController.java

@@ -1,13 +1,3 @@
-/*
- * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
- *
- * https://www.mall4j.com/
- *
- * 未经允许,不可做商业用途!
- *
- * 版权所有,侵权必究!
- */
-
 package com.qs.mp.web.controller.api.user;
 
 import com.alibaba.fastjson.JSONObject;
@@ -19,6 +9,8 @@ import com.qs.mp.common.core.domain.AjaxResult;
 import com.qs.mp.common.core.page.TableDataInfo;
 import com.qs.mp.common.enums.PrizeStorageStatusEnum;
 import com.qs.mp.common.enums.TicketStatusEnum;
+import com.qs.mp.common.enums.UserCouponStatusEnum;
+import com.qs.mp.common.utils.DateUtils;
 import com.qs.mp.user.domain.UserCoin;
 import com.qs.mp.user.domain.UserCoinLog;
 import com.qs.mp.user.domain.UserCoupon;
@@ -45,7 +37,7 @@ import org.springframework.web.bind.annotation.RestController;
 
 
 @RestController
-@RequestMapping("/api/v1/mp/user")
+@RequestMapping("/api/v1/mp/user/mine")
 @Api(tags = "我的接口")
 @AllArgsConstructor
 public class UserMineController extends BaseApiController {
@@ -72,7 +64,7 @@ public class UserMineController extends BaseApiController {
   /**
    * 我的票包
    */
-  @PostMapping("/mine/ticket/list")
+  @PostMapping("/ticket/list")
   @ApiOperation(value = "我的盲票列表", notes = "获取我的盲票列表")
   public TableDataInfo listTicket(@RequestBody Ticket param) {
     Long userId = SecurityUtils.getLoginUser().getUserId();
@@ -85,7 +77,7 @@ public class UserMineController extends BaseApiController {
   /**
    * 我的优惠券
    */
-  @PostMapping("/mine/coupon/list")
+  @PostMapping("/coupon/list")
   @ApiOperation(value = "我的优惠券列表", notes = "获取我的优惠券列表")
   public TableDataInfo listCoupon(@RequestBody UserCoupon param) {
     Long userId = SecurityUtils.getLoginUser().getUserId();
@@ -97,7 +89,7 @@ public class UserMineController extends BaseApiController {
   /**
    * 我的盲豆
    */
-  @PostMapping("/mine/coin/log/list")
+  @PostMapping("/coin/log/list")
   @ApiOperation(value = "我的盲豆记录", notes = "获取我的盲豆记录")
   public TableDataInfo listCoinLog(@RequestBody JSONObject param) {
     Long userId = SecurityUtils.getLoginUser().getUserId();
@@ -111,7 +103,7 @@ public class UserMineController extends BaseApiController {
   /**
    * 我的实物奖品库
    */
-  @PostMapping("/mine/prize/list")
+  @PostMapping("/prize/list")
   @ApiOperation(value = "我的实物奖品库", notes = "获取我的实物奖品库")
   public TableDataInfo listPrize(@RequestBody JSONObject param) {
     Long userId = SecurityUtils.getLoginUser().getUserId();
@@ -128,18 +120,23 @@ public class UserMineController extends BaseApiController {
   /**
    * 我的
    */
-  @PostMapping("/mine/init")
+  @PostMapping("/init")
   @ApiOperation(value = "查看我的", notes = "查看我的")
   public AjaxResult getInfo(@RequestBody JSONObject param) {
     Long userId = SecurityUtils.getLoginUser().getUserId();
     Map<String, Object> storageMap = userPrizeStorageService.getMap(
         new QueryWrapper<UserPrizeStorage>()
-            .select("IFNULL(goods_num,0) as total")
-            .eq("userId", userId).eq("status", PrizeStorageStatusEnum.NOT_DISTRIBUTED));
+            .select("count(IFNULL(goods_num,0)) as total")
+            .eq("user_id", userId).eq("status", PrizeStorageStatusEnum.NOT_DISTRIBUTED));
+    int couponCnt = userCouponService.count(new LambdaQueryWrapper<UserCoupon>()
+            .eq(UserCoupon::getUserId, userId)
+        .eq(UserCoupon::getStatus, UserCouponStatusEnum.UNUSED)
+        .le(UserCoupon::getValidStart, DateUtils.getToday())
+        .ge(UserCoupon::getValidEnd, DateUtils.getToday()));
     JSONObject result = new JSONObject();
-    result.put("prizeNum", Integer.valueOf(String.valueOf(storageMap.get("total"))));
+    result.put("prizeNum", Integer.valueOf(String.valueOf(null != storageMap ? storageMap.get("total") : 0)) + couponCnt);
 
-    int ticketNum = userTicketOrderItemService.countMyTicket(userId, TicketStatusEnum.ACTIVATED);
+    int ticketNum = userTicketOrderItemService.countMyTicket(userId, null);
     result.put("ticketNum", ticketNum);
 
     UserCoin userCoin = userCoinService.getById(userId);

+ 54 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserShareController.java

@@ -0,0 +1,54 @@
+package com.qs.mp.web.controller.api.user;
+
+import com.alibaba.fastjson.JSONObject;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.core.domain.AjaxResult.Type;
+import com.qs.mp.framework.service.IWxUrlLinkService;
+import com.qs.mp.user.domain.vo.UserShareVO;
+import com.qs.mp.utils.SecurityUtils;
+import com.qs.mp.web.controller.common.BaseApiController;
+import io.swagger.annotations.Api;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @auther zhongcp
+ * @create 2022-02-28 16:17:48
+ * @describe 用户分享前端控制器
+ */
+@Api("用户分享调用API")
+@RestController
+@RequestMapping("/api/v1/mp/user/share")
+@Component
+public class UserShareController extends BaseApiController {
+
+	@Autowired
+	private IWxUrlLinkService wxUrlLinkService;
+
+	@Value("${wx-user.appId}")
+	private String userAppId;
+
+	/**
+	 * 生成盲票详情小程序码
+	 *
+	 * @return
+	 */
+	@PostMapping("/code/generate")
+	public AjaxResult generateInviteCode(@RequestBody  JSONObject jsonObject) {
+		String boxId = jsonObject.getString("boxId"); // 票组ID
+		String type = jsonObject.getString("type"); // 分享类型,1/2
+		Long userId = SecurityUtils.getUserId();
+		if (UserShareVO.SHARE_TYPE_SITE.equals(type)) {
+			// 经销商分享,默认到盲票小程序首页
+			String rst = wxUrlLinkService.generateUnlimitCode("", userId + "&" + type, userAppId);
+			return new AjaxResult(Type.SUCCESS, "", rst);
+		}
+		String rst = wxUrlLinkService.generateUnlimitCode("pages/ticketBox/detail", boxId + "&" + userId + "&" + type, userAppId);
+		return new AjaxResult(Type.SUCCESS, "", rst);
+	}
+}

+ 159 - 41
mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserTicketController.java

@@ -1,49 +1,50 @@
-/*
- * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
- *
- * https://www.mall4j.com/
- *
- * 未经允许,不可做商业用途!
- *
- * 版权所有,侵权必究!
- */
-
 package com.qs.mp.web.controller.api.user;
 
+import com.alibaba.fastjson.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
 import com.qs.mp.admin.domain.Ticket;
 import com.qs.mp.admin.domain.TicketAwardsPrize;
 import com.qs.mp.admin.domain.TicketBox;
+import com.qs.mp.admin.domain.TicketPackage;
 import com.qs.mp.admin.domain.param.TicketBoxParam;
 import com.qs.mp.admin.domain.param.TicketParam;
 import com.qs.mp.admin.domain.vo.TicketBoxListVO;
 import com.qs.mp.admin.domain.vo.TicketBoxVO;
+import com.qs.mp.admin.domain.vo.TicketListVO;
 import com.qs.mp.admin.domain.vo.TicketVO;
 import com.qs.mp.admin.service.ITicketAwardsPrizeService;
 import com.qs.mp.admin.service.ITicketBoxService;
+import com.qs.mp.admin.service.ITicketPackageService;
 import com.qs.mp.admin.service.ITicketService;
 import com.qs.mp.common.core.domain.AjaxResult;
 import com.qs.mp.common.core.page.TableDataInfo;
-import com.qs.mp.common.enums.ErrorCodeEnum;
-import com.qs.mp.common.enums.TicketBoxStatusEnum;
-import com.qs.mp.common.enums.TicketStatusEnum;
+import com.qs.mp.common.enums.*;
+import com.qs.mp.common.utils.LogUtil;
 import com.qs.mp.common.utils.StringUtils;
+import com.qs.mp.framework.security.handle.HostHolder;
+import com.qs.mp.user.domain.UserHitPrize;
 import com.qs.mp.user.domain.UserTicketOrderItem;
+import com.qs.mp.user.domain.vo.TicketHitPrizeBarrageVO;
 import com.qs.mp.user.service.IUserHitPrizeService;
 import com.qs.mp.user.service.IUserTicketOrderItemService;
 import com.qs.mp.utils.SecurityUtils;
 import com.qs.mp.web.controller.common.BaseApiController;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+
 import lombok.AllArgsConstructor;
 import ma.glasnost.orika.MapperFacade;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
+
+import javax.ws.rs.POST;
 
 
 @RestController
@@ -68,22 +69,31 @@ public class UserTicketController extends BaseApiController {
   @Autowired
   private IUserHitPrizeService userHitPrizeService;
 
+  @Autowired
+  private ITicketPackageService ticketPackageService;
+
   @Autowired
   private MapperFacade mapperFacade;
 
+
+  @Autowired
+  private HostHolder hostHolder;
+
   /**
    * 盲票进货列表
    */
   @PostMapping("/mall/ticket/list")
-  @ApiOperation(value = "盲票组列表" , notes = "获取所有盲票信息")
+  @ApiOperation(value = "盲票组列表", notes = "获取所有盲票信息")
   public TableDataInfo list(@RequestBody TicketBoxParam param) {
     // TODO 根据标签过滤
     startPage();
     List<TicketBox> ticketBoxes = ticketBoxService.list(
         new LambdaQueryWrapper<TicketBox>().eq(TicketBox::getType, param.getType())
-            .eq(null != param.getCategoryId() && 0 != param.getCategoryId(), TicketBox::getCategoryId, param.getCategoryId())
+            .eq(null != param.getCategoryId() && 0 != param.getCategoryId(),
+                TicketBox::getCategoryId, param.getCategoryId())
             .eq(TicketBox::getStatus, TicketBoxStatusEnum.PUT_ON));
-    List<TicketBoxListVO> ticketBoxListVOList = mapperFacade.mapAsList(ticketBoxes, TicketBoxListVO.class);
+    List<TicketBoxListVO> ticketBoxListVOList = mapperFacade.mapAsList(ticketBoxes,
+        TicketBoxListVO.class);
     TableDataInfo rspData = getDataTable(ticketBoxes);
     rspData.setRows(ticketBoxListVOList);
     return rspData;
@@ -94,15 +104,16 @@ public class UserTicketController extends BaseApiController {
    * 查看盲票详情
    */
   @PostMapping("/mall/ticket/detail")
-  @ApiOperation(value = "查看盲票详情" , notes = "根据盲票组ID,获取盲票信息")
+  @ApiOperation(value = "查看盲票详情", notes = "根据盲票组ID,获取盲票信息")
   public AjaxResult getInfo(@RequestBody TicketBoxParam param) {
     if (StringUtils.isBlank(param.getBoxId())) {
       return AjaxResult.error("参数异常,盲票组ID缺失");
     }
     TicketBox ticketBox = ticketBoxService.getById(param.getBoxId());
     TicketBoxVO ticketBoxVO = mapperFacade.map(ticketBox, TicketBoxVO.class);
-    ticketBoxVO.setPrizeList(ticketAwardsPrizeService.listPrizeVO(new QueryWrapper<TicketAwardsPrize>()
-        .eq("t1.box_id", ticketBox.getBoxId()).orderByAsc("t1.sort").orderByDesc("t2.value")));
+    ticketBoxVO.setPrizeList(
+        ticketAwardsPrizeService.listPrizeVO(new QueryWrapper<TicketAwardsPrize>()
+            .eq("t1.box_id", ticketBox.getBoxId()).orderByAsc("t1.sort").orderByDesc("t2.value")));
     return AjaxResult.success(ticketBoxVO);
   }
 
@@ -110,28 +121,26 @@ public class UserTicketController extends BaseApiController {
    * 扫码查看盲票幸运数字
    */
   @PostMapping("/ticket/queryLuckyNum")
-  @ApiOperation(value = "查看盲票幸运数字" , notes = "根据盲票组ID,获取盲票幸运数字")
+  @ApiOperation(value = "查看盲票幸运数字", notes = "根据盲票组ID,获取盲票幸运数字")
   public AjaxResult queryLuckyNum(@RequestBody TicketParam param) {
-    Long userId = SecurityUtils.getLoginUser().getUserId();
+
     if (StringUtils.isBlank(param.getSerialNo())) {
       return AjaxResult.error("参数异常,盲票序列号缺失");
     }
 
-    Ticket ticket = ticketService.getOne(new LambdaQueryWrapper<Ticket>().eq(Ticket::getSerialNo, param.getSerialNo()));
+    Ticket ticket = ticketService.getOne(
+        new LambdaQueryWrapper<Ticket>().eq(Ticket::getSerialNo, param.getSerialNo()));
     if (null == ticket) {
       return AjaxResult.error("参数异常,盲票不存在");
     }
 
-    if (ticket.getStatus() == TicketStatusEnum.CASHED) {
+    /*if (ticket.getStatus() == TicketStatusEnum.CASHED) {
       return AjaxResult.error(ErrorCodeEnum.ERROR_CODE_1017);
-    }
-
-    // 已付款的盲票,需要校验当前用户是否有权限查看
-    if (ticket.getStatus() == TicketStatusEnum.ACTIVATED) {
-      UserTicketOrderItem orderItem = userTicketOrderItemService.queryFinishedOrderItem(userId, ticket.getTicketId());
-      if (null == orderItem) {
-        return AjaxResult.error(ErrorCodeEnum.ERROR_CODE_1018);
-      }
+    }*/
+    TicketPackage ticketPackage = ticketPackageService.getById(ticket.getPkgId());
+    if (ticketPackage.getStatus() != TicketPkgStatusEnum.SOLD) {
+      LogUtil.error(logger, "盲票未激活。sn:{0},pkgId:{1}", new Object[]{ticket.getSerialNo(), ticket.getPkgId()});
+      return AjaxResult.error(ErrorCodeEnum.ERROR_CODE_1023);
     }
 
     TicketBox ticketBox = ticketBoxService.getById(ticket.getBoxId());
@@ -147,22 +156,39 @@ public class UserTicketController extends BaseApiController {
     ticketVO.setSalePrice(ticketBox.getSalePrice());
     ticketVO.setPlainLuckyNum(ticket.getPlainLuckyNum());
     ticketVO.setStatus(ticket.getStatus().getValue());
+    ticketVO.setPicUrl(ticketBox.getPicUrl());
 
     return AjaxResult.success(ticketVO);
   }
 
+  /**
+   * 根据盲票购买订单号查看盲票详情
+   */
+  @PostMapping("/ticket/query")
+  @ApiOperation(value = "查看盲票详情", notes = "根据盲票购买订单号,查看盲票详情")
+  public AjaxResult queryTicket(@RequestBody TicketParam param) {
+    Long userId = SecurityUtils.getLoginUser().getUserId();
+    if (StringUtils.isBlank(param.getOrderId())) {
+      return AjaxResult.error("参数缺失");
+    }
+
+    TicketListVO ticketListVO = userTicketOrderItemService.queryTicketVO(userId,
+        param.getOrderId());
+    return AjaxResult.success(ticketListVO);
+  }
+
   /**
    * 查看能兑奖的奖品
    */
   @PostMapping("/ticket/queryHitPrizeList")
-  @ApiOperation(value = "查看兑奖奖品" , notes = "根据盲票ID,查看兑奖奖品")
+  @ApiOperation(value = "查看兑奖奖品", notes = "根据盲票ID,查看兑奖奖品")
   public AjaxResult queryHitPrizeList(@RequestBody TicketParam param) {
     Long userId = SecurityUtils.getLoginUser().getUserId();
     if (StringUtils.isBlank(param.getTicketId())) {
-      return AjaxResult.error("参数异常,盲票ID缺失");
+      return AjaxResult.error("参数缺失");
     }
-
     Ticket ticket = ticketService.getById(param.getTicketId());
+
     if (null == ticket) {
       return AjaxResult.error("参数异常,盲票不存在");
     }
@@ -172,20 +198,30 @@ public class UserTicketController extends BaseApiController {
     if (ticket.getStatus() != TicketStatusEnum.ACTIVATED) {
       return AjaxResult.error(ErrorCodeEnum.ERROR_CODE_1019);
     }
+    // 已付款的盲票,需要校验当前用户是否有权限查看
+    UserTicketOrderItem orderItem = userTicketOrderItemService.queryFinishedOrderItem(userId,
+        ticket.getTicketId());
+    if (null == orderItem) {
+      return AjaxResult.error(ErrorCodeEnum.ERROR_CODE_1018);
+    }
 
     List<TicketAwardsPrize> ticketAwardsPrizes = userHitPrizeService.listPrize(ticket, userId);
-    return AjaxResult.success(ticketAwardsPrizes);
+    JSONObject jsonObject = new JSONObject();
+    jsonObject.put("prizeList", ticketAwardsPrizes);
+    jsonObject.put("ticketId", ticket.getTicketId());
+    jsonObject.put("boxId", ticket.getBoxId());
+    return AjaxResult.success(jsonObject);
   }
 
   /**
    * 兑奖
    */
   @PostMapping("/ticket/cashPrize")
-  @ApiOperation(value = "兑奖" , notes = "选择奖品兑奖")
+  @ApiOperation(value = "兑奖", notes = "选择奖品兑奖")
   public AjaxResult cashPrize(@RequestBody TicketParam param) {
     Long userId = SecurityUtils.getLoginUser().getUserId();
     if (StringUtils.isBlank(param.getTicketId()) || StringUtils.isBlank(param.getAwardsId())
-    || StringUtils.isBlank(param.getPrizeId())) {
+        || StringUtils.isBlank(param.getPrizeId())) {
       return AjaxResult.error("参数缺失");
     }
 
@@ -204,4 +240,86 @@ public class UserTicketController extends BaseApiController {
     return AjaxResult.success();
   }
 
+  @PostMapping("/ticket/hitPrizeBarrage")
+  @ApiOperation(value = "中奖弹幕", notes = "获取最近中奖的 20-22 条信息")
+  public AjaxResult hitPrizeBarrage() {
+
+    // 获取用户 id
+    Long userId = 0L;
+
+    if (hostHolder.getUser() != null) {
+      userId = hostHolder.getUser().getUserId();
+    }
+
+    // 弹幕列表
+    List<TicketHitPrizeBarrageVO> listOne = new ArrayList<>();
+    List<TicketHitPrizeBarrageVO> listTwo = new ArrayList<>();
+
+    // 获取用户当天中奖的 2 条弹幕
+    if (userId != 0L) {
+      List<TicketHitPrizeBarrageVO> ticketHitPrizeBarrageVOList = userHitPrizeService.hitPrizeBarrageByUserId(userId);
+      if (CollectionUtils.isNotEmpty(ticketHitPrizeBarrageVOList)) {
+        for (int i = 0; i < ticketHitPrizeBarrageVOList.size(); i++) {
+          // 类型为盲豆则拼接数量
+          if(TicketPrizeTypeEnum.COIN.getValue().equals(ticketHitPrizeBarrageVOList.get(i).getPrizeType())){
+            ticketHitPrizeBarrageVOList.get(i).setPrizeInfo(ticketHitPrizeBarrageVOList.get(i).getPrizeInfo() + ticketHitPrizeBarrageVOList.get(i).getValue() + "颗");
+          }
+
+          if (i % 2 == 0) {
+            listOne.add(ticketHitPrizeBarrageVOList.get(i));
+          }else {
+            listTwo.add(ticketHitPrizeBarrageVOList.get(i));
+          }
+        }
+      }
+    }
+    // 获取除该用户外,最近中奖的 40 条弹幕信息
+    List<TicketHitPrizeBarrageVO> ticketHitPrizeBarrageVOList = userHitPrizeService.hitPrizeBarrage(userId);
+
+    // 获取除该用户外,近 6 个月,8 条高级中奖弹幕信息
+    List<TicketHitPrizeBarrageVO> expensiveHitPrizeBarrageList = userHitPrizeService.expensiveHitPrizeBarrage(userId);
+    int count = 0;
+    int index = 0;
+    if (CollectionUtils.isNotEmpty(expensiveHitPrizeBarrageList)) {
+      count = expensiveHitPrizeBarrageList.size();
+      // 去重
+      ticketHitPrizeBarrageVOList.removeAll(expensiveHitPrizeBarrageList);
+    }
+
+
+    for (int i = 0; i < ticketHitPrizeBarrageVOList.size(); i++) {
+      // 类型为盲豆则拼接数量
+      if(TicketPrizeTypeEnum.COIN.getValue().equals(ticketHitPrizeBarrageVOList.get(i).getPrizeType())){
+        ticketHitPrizeBarrageVOList.get(i).setPrizeInfo(ticketHitPrizeBarrageVOList.get(i).getPrizeInfo() + ticketHitPrizeBarrageVOList.get(i).getValue() + "颗");
+      }
+
+      // 插入大奖弹幕
+      if (count != 0 && i % 5 == 0) {
+        if (index % 2 == 0) {
+          listOne.add(expensiveHitPrizeBarrageList.get(index));
+        }else {
+          listTwo.add(expensiveHitPrizeBarrageList.get(index));
+        }
+        count--;
+        index++;
+      }
+
+      if (i % 2 == 0) {
+        listOne.add(ticketHitPrizeBarrageVOList.get(i));
+      }else {
+        listTwo.add(ticketHitPrizeBarrageVOList.get(i));
+      }
+    }
+    Map<String,List<TicketHitPrizeBarrageVO>> ticketHitPrizeBarrageMap = new HashMap<>();
+    ticketHitPrizeBarrageMap.put("listOne",listOne);
+    ticketHitPrizeBarrageMap.put("listTwo",listTwo);
+
+    return AjaxResult.success(ticketHitPrizeBarrageMap);
+  }
+
+
+
+
+
+
 }

+ 62 - 35
mp-admin/src/main/java/com/qs/mp/web/controller/api/user/UserTicketOrderController.java

@@ -1,13 +1,3 @@
-/*
- * Copyright (c) 2018-2999 广州市蓝海创新科技有限公司 All rights reserved.
- *
- * https://www.mall4j.com/
- *
- * 未经允许,不可做商业用途!
- *
- * 版权所有,侵权必究!
- */
-
 package com.qs.mp.web.controller.api.user;
 
 import com.alibaba.fastjson.JSONObject;
@@ -24,20 +14,28 @@ import com.qs.mp.common.core.domain.AjaxResult;
 import com.qs.mp.common.core.redis.RedisCache;
 import com.qs.mp.common.enums.BizTypeEnum;
 import com.qs.mp.common.enums.CouponUseAreaEnum;
+import com.qs.mp.common.enums.ErrorCodeEnum;
+import com.qs.mp.common.enums.TicketTypeEnum;
 import com.qs.mp.common.exception.ServiceException;
+import com.qs.mp.common.utils.LogUtil;
 import com.qs.mp.common.utils.StringUtils;
 import com.qs.mp.framework.redis.RedisKey;
 import com.qs.mp.pay.service.IWalletService;
+import com.qs.mp.system.domain.SysUser;
+import com.qs.mp.system.service.ISysUserService;
 import com.qs.mp.user.domain.UserTicketOrder;
 import com.qs.mp.user.domain.param.TicketOrderParam;
 import com.qs.mp.user.domain.vo.TicketOrderSettleVO;
+import com.qs.mp.user.domain.vo.UserCoupon4OrderVO;
 import com.qs.mp.user.domain.vo.UserCouponVO;
+import com.qs.mp.user.domain.vo.UserShareVO;
 import com.qs.mp.user.service.IUserCouponService;
 import com.qs.mp.user.service.IUserTicketOrderService;
 import com.qs.mp.utils.SecurityUtils;
 import com.qs.mp.web.controller.common.BaseApiController;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import java.util.Iterator;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
 import javax.validation.Valid;
@@ -71,10 +69,10 @@ public class UserTicketOrderController extends BaseApiController {
   private IUserCouponService userCouponService;
 
   @Autowired
-  private ICouponTicketService couponTicketService;
+  private IWalletService walletService;
 
   @Autowired
-  private IWalletService walletService;
+  private ISysUserService sysUserService;
 
   @Autowired
   private MapperFacade mapperFacade;
@@ -113,25 +111,20 @@ public class UserTicketOrderController extends BaseApiController {
     }
 
     if (param.getAutoCoupon() == 1) {
-      // 系统自动选择优惠券,按照金额从大到小排序
-      List<UserCouponVO> userCouponList = userCouponService.listTicketOrderCoupon(userId);
-      for (UserCouponVO userCouponVO : userCouponList) {
-        if (orderAmt >= userCouponVO.getMinOrderAmt() && orderAmt >= userCouponVO.getDiscount()) {
-          if (userCouponVO.getUseArea() == CouponUseAreaEnum.PRE_SCOPE) {
-            // 使用范围验证
-            List<CouponTicket> couponTicketList = couponTicketService.list(new LambdaQueryWrapper<CouponTicket>()
-                .eq(CouponTicket::getCouponId, userCouponVO.getCouponId()).eq(CouponTicket::getBoxId, ticketBox.getBoxId()));
-            if (CollectionUtils.isEmpty(couponTicketList)) {
-              continue;
-            }
-          }
-          orderSettleVO.getCouponList().add(userCouponVO);
-          discountAmt = userCouponVO.getDiscount();
-        }
+      List<UserCouponVO> userCouponVOList = userCouponService.queryUserCouponList(userId, orderAmt, ticketBox);
+      if (!CollectionUtils.isEmpty(userCouponVOList)) {
+        // 只考虑使用单张券
+        orderSettleVO.getCouponList().add(mapperFacade.map(userCouponVOList.get(0), UserCoupon4OrderVO.class));
+        discountAmt = userCouponVOList.get(0).getDiscount();
       }
     } else if (!CollectionUtils.isEmpty(param.getUserCouponIds())){
       // 查询指定券
-      orderSettleVO.setCouponList(userCouponService.listTicketOrderCouponByIds(param.getUserCouponIds()));
+      List<UserCouponVO> userCouponVOList = userCouponService.listTicketOrderCouponByIds(param.getUserCouponIds());
+      if (!CollectionUtils.isEmpty(userCouponVOList)) {
+        // 只考虑使用单张券
+        orderSettleVO.getCouponList().add(mapperFacade.map(userCouponVOList.get(0), UserCoupon4OrderVO.class));
+        discountAmt = userCouponVOList.get(0).getDiscount();
+      }
     }
 
     orderSettleVO.setOrderAmt(orderAmt);
@@ -139,32 +132,33 @@ public class UserTicketOrderController extends BaseApiController {
     // 当前没有运费和优惠,实付金额=订单金额
     orderSettleVO.setPayAmt(orderAmt - discountAmt);
     orderSettleVO.setOrderNum(param.getOrderNum());
-    orderSettleVO.setBoxId(param.getBoxId());
+    orderSettleVO.setBoxId(ticketBox.getBoxId());
     orderSettleVO.setTicketId(param.getTicketId());
     orderSettleVO.setPicUrl(ticketBox.getPicUrl());
-
+    orderSettleVO.setTitle(ticketBox.getTitle());
     // 缓存订单结算对象
     redisCache.setCacheObject(RedisKey.build(RedisKey.USER_TICKET_ORDER_KEY, userId), orderSettleVO, 10, TimeUnit.MINUTES);
     return AjaxResult.success(orderSettleVO);
   }
 
-
   /**
    * 提交订单
    */
   @PostMapping("/order/submit")
   @ApiOperation(value = "提交订单" , notes = "在订单确认页面提交")
-  public AjaxResult submit(@RequestBody UserTicketOrder order) {
+  public AjaxResult submit(@RequestBody UserShareVO userShareVO) {
     Long userId = SecurityUtils.getLoginUser().getUserId();
     TicketOrderSettleVO orderSettleVO = redisCache.getCacheObject(RedisKey.build(RedisKey.USER_TICKET_ORDER_KEY, userId));
     if (null == orderSettleVO) {
       return AjaxResult.error("订单已过期,请重新下单");
     }
-    String orderId = userTicketOrderService.submitOrder(userId, orderSettleVO);
+    String orderId = userTicketOrderService.submitOrder(userId, orderSettleVO, userShareVO);
     JSONObject jsonObject = new JSONObject();
     jsonObject.put("orderId", orderId);
     if (orderSettleVO.getPayAmt() > 0) {
       jsonObject.put("needPay", 1);
+    } else {
+      jsonObject.put("needPay", 0);
     }
     // 清除缓存的订单
     redisCache.deleteObject(RedisKey.build(RedisKey.USER_TICKET_ORDER_KEY, userId));
@@ -189,15 +183,48 @@ public class UserTicketOrderController extends BaseApiController {
   @PostMapping("/order/pay")
   @ApiOperation(value = "订单支付" , notes = "在盲票页面支付")
   public AjaxResult pay(@Valid @RequestBody OrderPayParam param) {
-    String openId = SecurityUtils.getLoginUser().getUser().getOpenId();
+    Long userId = SecurityUtils.getLoginUser().getUserId();
+    SysUser sysUser = sysUserService.selectUserById(userId);
+    if (StringUtils.isBlank(sysUser.getOpenId())) {
+      return AjaxResult.error(ErrorCodeEnum.ERROR_CODE_1005);
+    }
     UserTicketOrder ticketOrder = userTicketOrderService.getById(param.getOrderId());
     JSONObject jsonObject;
     try {
-      jsonObject = walletService.pay(BizTypeEnum.TICKET_ORDER, param.getOrderId(), openId, ticketOrder.getPayAmt());
+      jsonObject = walletService.pay(BizTypeEnum.TICKET_ORDER, param.getOrderId(), sysUser.getOpenId(), ticketOrder.getPayAmt());
     }catch (ServiceException e) {
+      LogUtil.error(logger, e, "根据盲票购买订单创建支付单失败。userId:{0},orderId:{1}", new Object[]{userId, param.getOrderId()});
       return AjaxResult.error(e.getMessage());
     }
     return AjaxResult.success(jsonObject);
   }
 
+  /**
+   * 可用优惠券列表
+   */
+  @PostMapping("/order/coupon/list")
+  @ApiOperation(value = "查询可用优惠券" , notes = "在下单页面选择")
+  public AjaxResult listCoupon(@RequestBody TicketOrderParam param) {
+    Long userId = SecurityUtils.getUserId();
+    TicketOrderSettleVO orderSettleVO = redisCache.getCacheObject(RedisKey.build(RedisKey.USER_TICKET_ORDER_KEY, userId));
+    if (null == orderSettleVO) {
+      return AjaxResult.error("订单已过期,请重新下单");
+    }
+    TicketBox ticketBox = ticketBoxService.getById(orderSettleVO.getBoxId());
+    List<UserCouponVO> userCouponVOList = userCouponService.queryUserCouponList(userId, orderSettleVO.getOrderAmt(), ticketBox);
+
+    // 设置选中状态
+    for (UserCouponVO userCouponVO : userCouponVOList) {
+      if (!CollectionUtils.isEmpty(orderSettleVO.getCouponList())) {
+        for (UserCoupon4OrderVO userCoupon4OrderVO : orderSettleVO.getCouponList()) {
+          if (userCoupon4OrderVO.getId().equals(userCouponVO.getId())) {
+            userCouponVO.setChecked(true);
+            break;
+          }
+        }
+      }
+    }
+    return AjaxResult.success(userCouponVOList);
+  }
+
 }

+ 94 - 7
mp-admin/src/main/java/com/qs/mp/web/controller/common/FileUploadController.java

@@ -1,7 +1,10 @@
 package com.qs.mp.web.controller.common;
 
 
+import com.alibaba.druid.sql.visitor.functions.If;
 import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.enums.PicHandlerTypeEnum;
+import com.qs.mp.common.filter.ThumbnailsImgFilter;
 import com.qs.mp.common.qcloud.QcloudFileUtils;
 import com.qs.mp.common.utils.LogUtil;
 import com.qs.mp.common.utils.StringUtils;
@@ -99,12 +102,25 @@ public class FileUploadController extends BaseApiController {
      */
     @PostMapping("image/remote/upload/post/{auth}")
     public AjaxResult postImage(@PathVariable("auth") int auth, @RequestParam("file") MultipartFile file)  {
-        return uploadImageFile(auth, file);
+        return uploadImageFile(auth, file, PicHandlerTypeEnum.CROP.getValue());
     }
 
+    @PutMapping("image/remote/upload/commpress/{auth}")
+    public AjaxResult postCommpressImage(@PathVariable("auth") int auth, @RequestParam("file") MultipartFile file)  {
+        return uploadImageFile(auth, file, PicHandlerTypeEnum.COMPRESSION.getValue());
+    }
+
+    /**
+     * 上传图形方法
+     * @param auth  认证
+     * @param file  文件信息
+     * @param handlerType   处理类型,1 裁剪,2 压缩
+     * @return
+     */
     private AjaxResult uploadImageFile(
         @PathVariable("auth") int auth,
-        @RequestParam("file") MultipartFile file) {
+        @RequestParam("file") MultipartFile file,
+        int handlerType) {
         try {
             if (null == file) {
                 return AjaxResult.error("上传文件参数为空.");
@@ -122,7 +138,14 @@ public class FileUploadController extends BaseApiController {
                 mimeType = "image/jpg";
             }
             LogUtil.info(logger," mimeType:" + mimeType + " fileName:" + file.getOriginalFilename());
-            String name = commpressPicAndUpLoadOSS(file, mimeType, 480, 480, bucketName);
+            String name = "";
+            if (PicHandlerTypeEnum.CROP.getValue().equals(handlerType)) {
+                // 裁剪并上传图片
+                name = cropPicAndUpLoadOSS(file, mimeType, 480, 480, bucketName);
+            }else if (PicHandlerTypeEnum.COMPRESSION.getValue().equals(handlerType)) {
+                // 压缩并上传图片
+                name = commpressPicAndUpLoadOSS(file, mimeType, bucketName);
+            }
             if (StringUtils.isBlank(name)) {
                 LogUtil.error(logger, "图片上传失败.");
                 return AjaxResult.error("图片上传失败.");
@@ -143,12 +166,19 @@ public class FileUploadController extends BaseApiController {
      */
     @PutMapping("image/remote/upload/{auth}")
     public AjaxResult uploadImage(@PathVariable("auth") int auth, @RequestParam("file") MultipartFile file)  {
-        return uploadImageFile(auth, file);
+        return uploadImageFile(auth, file, PicHandlerTypeEnum.CROP.getValue());
     }
 
-
-
-    private String commpressPicAndUpLoadOSS(MultipartFile file,String mimeType,int width,int height,String bucketName) {
+    /**
+     * 裁剪图片并上传
+     * @param file
+     * @param mimeType
+     * @param width
+     * @param height
+     * @param bucketName
+     * @return
+     */
+    private String cropPicAndUpLoadOSS(MultipartFile file,String mimeType,int width,int height,String bucketName) {
         String fileName = file.getOriginalFilename();
         int idx = fileName.lastIndexOf('.');
         String suffix = "";
@@ -191,4 +221,61 @@ public class FileUploadController extends BaseApiController {
         }
         return name;
     }
+
+
+    /**
+     * 压缩并上传图片
+     * @param file
+     * @param mimeType
+     * @param bucketName
+     * @return
+     */
+    private String commpressPicAndUpLoadOSS(MultipartFile file, String mimeType, String bucketName){
+        String fileName = file.getOriginalFilename();
+        int idx = fileName.lastIndexOf('.');
+        String suffix = "";
+        if (idx > 0) {
+            suffix = fileName.substring(idx);
+        }
+        String name = UUIDUtils.newId() + suffix;
+        try {
+            QcloudFileUtils.putStream(file.getInputStream(), name, bucketName, mimeType );
+            BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
+            Builder<BufferedImage> builder = Thumbnails.of(bufferedImage);
+
+
+            int pWidth = bufferedImage.getWidth();
+            int pHeight = bufferedImage.getHeight();
+            builder.size(pWidth, pHeight);
+
+            String outFileDir = filePath+"/thumb";
+            File tempFile = new File(outFileDir);
+            if(!tempFile.exists()) {
+                tempFile.mkdirs();
+            }
+            String thumbName = name +"_s";
+            String outFilePath = filePath+"/thumb/"+thumbName+"."+mimeType.substring(mimeType.lastIndexOf("/")+1);
+            builder.toFile(outFilePath);
+
+            // 压缩图片
+            if (pWidth > 500) {
+                float scale = 500f / pWidth;
+                Thumbnails.of(outFilePath).scale(scale).outputQuality(0.8f).toFile(outFilePath);
+            }else {
+                Thumbnails.of(outFilePath).scale(1f).outputQuality(0.8f).toFile(outFilePath);
+            }
+
+
+            File outFile = new File(outFilePath);
+            QcloudFileUtils.putFile(outFile, thumbName, bucketName, mimeType);
+            if(outFile.exists()) {
+                LogUtil.info(log, "delete file..."+outFilePath);
+                outFile.delete();
+            }
+        }  catch (Exception e) {
+            LogUtil.error(log, e, "");
+            return null;
+        }
+        return name;
+    }
 }

+ 1 - 1
mp-admin/src/main/java/com/qs/mp/web/controller/common/WxServerController.java

@@ -54,7 +54,7 @@ public class WxServerController extends BaseApiController {
 	@PostMapping("code/generate")
 	public AjaxResult generateInviteCode(@RequestBody  JSONObject jsonObject) {
 		String id = jsonObject.getString("id");
-		String rst = wxUrlLinkService.generateCode("pages/index/index", "id=" + id, userAppId);
+		String rst = wxUrlLinkService.generateCode("pages/lucky/index", "id=" + id, userAppId);
 		return new AjaxResult(Type.SUCCESS, "", rst);
 	}
 }

+ 17 - 0
mp-admin/src/main/java/com/qs/mp/web/controller/system/SysLoginController.java

@@ -4,6 +4,7 @@ package com.qs.mp.web.controller.system;
 import com.qs.mp.common.constant.Constants;
 import com.qs.mp.common.core.domain.AjaxResult;
 import com.qs.mp.common.core.domain.model.LoginBody;
+import com.qs.mp.common.enums.UserIdentityEnum;
 import com.qs.mp.framework.security.handle.HostHolder;
 import com.qs.mp.framework.web.service.SysLoginService;
 import com.qs.mp.framework.web.service.SysPermissionService;
@@ -11,6 +12,7 @@ import com.qs.mp.sms.domain.SmsCode;
 import com.qs.mp.system.domain.SysMenu;
 import com.qs.mp.system.domain.SysUser;
 import com.qs.mp.system.service.ISysMenuService;
+import com.qs.mp.system.service.ISysUserService;
 import com.qs.mp.utils.SecurityUtils;
 import java.util.HashMap;
 import java.util.Iterator;
@@ -41,6 +43,9 @@ public class SysLoginController
     @Autowired
     private SysPermissionService permissionService;
 
+    @Autowired
+    private ISysUserService sysUserService;
+
     @Autowired
     private HostHolder hostHolder;
 
@@ -87,6 +92,18 @@ public class SysLoginController
         if (!codePattern.matcher(smsCode.getCode()).matches()) {
             return AjaxResult.error("请输入6位验证码");
         }
+        SysUser sysUser = sysUserService.selectUserByUserName(smsCode.getMobile());
+        if (null == sysUser) {
+            if (smsCode.getIdentity() != UserIdentityEnum.USER.ordinal()) {
+                return AjaxResult.error("账号不存在");
+            }
+            // C端直接注册新用户
+            sysUser = new SysUser();
+            sysUser.setUserName(smsCode.getMobile());
+            sysUser.setNickName(smsCode.getMobile());
+            sysUserService.registerUser(sysUser);
+        }
+
         AjaxResult ajax = AjaxResult.success();
         Map<String, String> result = loginService.login(smsCode);
         for (String key : result.keySet()) {

+ 29 - 8
mp-admin/src/main/resources/application-8100.yml

@@ -1,6 +1,10 @@
+mp:
+  # 文件路径 示例( Windows配置D:/ygp/uploadPath,Linux配置 /home/ygp/uploadPath)
+  profile: /home/mangpiao/mp-server
+
 #三方支付配置
 pay:
-  callbackUrl: https://api.quanshu123.com/service/notify/payCallback
+  callbackUrl: https://mp-api.51jiazhu.com/service/notify/payCallback
 
 # 日志配置
 logging:
@@ -12,12 +16,13 @@ logging:
     io.lettuce.core: warn
     org.quartz.core: warn
     com.qs.mp.framework.interceptor: warn
+    ma.glasnost.orika: warn
 # 数据源配置
 spring:
     redis:
-      host: 172.17.0.17
+      host: 172.17.16.10
       port: 6379
-      password: SD232@%Gwwer1ds0(SS323
+      password: 5YgEx,%5crw!9x0F2Em26Gx
       # 连接超时时间(毫秒)
       timeout: 10000
       jedis:
@@ -36,9 +41,9 @@ spring:
         druid:
             # 主库数据源
             master:
-                url: jdbc:mysql://172.17.0.3:3306/ygpdb-prod?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
-                username: ygp_prod
-                password: x23W%s2PcW23)vw23Csaw234)3
+                url: jdbc:mysql://172.17.32.4:3306/mpdb-prod?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
+                username: mp_prod
+                password: x2xs@S3W%s2PcW23)vw23Csaw234)3
             # 从库数据源
             slave:
                 # 从数据源开关/默认关闭
@@ -109,11 +114,27 @@ client:
 # cloud
 cloud:
   # 存储对象公开可访问
-  public-bucket-name: mp-public-1307117429
+  public-bucket-name: mp-public-1310078123
   # 存储对象公开不可访问,需要通过应用下载
-  private-bucket-name: mp-auth-1307117429
+  private-bucket-name: mp-auth-1310078123
+
+  accessKey: AKIDSnvoRovmOkqfGbfT1JL6bssd9OTJsBE1
+  secretKey: auxkHXWFhtpX0C7lCMFrDJ8g39zY8Yic
+  region: ap-shanghai
+
+mq:
+  consumer-conn: true
+  service-url: http://pulsar-rd94exwe9rmq.tdmq-pulsar.ap-sh.qcloud.tencenttdmq.com:5039
+  auth-token: eyJrZXlJZCI6InB1bHNhci1yZDk0ZXh3ZTlybXEiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJwdWxzYXItcmQ5NGV4d2U5cm1xX21wLXNlcnZlci1wcm9kIn0.lV__rvUtTdNxcFI9qq50s81YZxw9V-7vDxK0_tDJHNo
+  topic-ticket-generate: pulsar-rd94exwe9rmq/prod-share/topic-ticket-generate
+  topic-ticket-pay: pulsar-rd94exwe9rmq/prod-share/topic-ticket-pay
+  consumer-topics: pulsar-rd94exwe9rmq/prod-share/topic-ticket-generate,pulsar-rd94exwe9rmq/prod-share/topic-ticket-pay
 
 # 小程序
 miniprogram:
   # 接收通知的状态
   state: formal
+
+# 盲票导出每页查询数量
+export:
+  page-size: 1000

+ 30 - 9
mp-admin/src/main/resources/application-8200.yml

@@ -1,6 +1,10 @@
+mp:
+  # 文件路径 示例( Windows配置D:/ygp/uploadPath,Linux配置 /home/ygp/uploadPath)
+  profile: /home/mangpiao/mp-server
+
 #三方支付配置
 pay:
-  callbackUrl: https://api.quanshu123.com/service/notify/payCallback
+  callbackUrl: https://mp-api.51jiazhu.com/service/notify/payCallback
 
 # 日志配置
 logging:
@@ -12,12 +16,13 @@ logging:
     io.lettuce.core: warn
     org.quartz.core: warn
     com.qs.mp.framework.interceptor: warn
+    ma.glasnost.orika: warn
 # 数据源配置
 spring:
     redis:
-      host: 172.17.0.17
+      host: 172.17.16.10
       port: 6379
-      password: SD232@%Gwwer1ds0(SS323
+      password: 5YgEx,%5crw!9x0F2Em26Gx
       # 连接超时时间(毫秒)
       timeout: 10000
       jedis:
@@ -36,9 +41,9 @@ spring:
         druid:
             # 主库数据源
             master:
-                url: jdbc:mysql://172.17.0.3:3306/ygpdb-prod?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
-                username: ygp_prod
-                password: x23W%s2PcW23)vw23Csaw234)3
+                url: jdbc:mysql://172.17.32.4:3306/mpdb-prod?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false
+                username: mp_prod
+                password: x2xs@S3W%s2PcW23)vw23Csaw234)3
             # 从库数据源
             slave:
                 # 从数据源开关/默认关闭
@@ -92,7 +97,7 @@ server:
     context-path: /
   session-timeout: 1800
   # 生成唯一ID的,同一Mac地址多应用的部署方式,用这个进行区分
-  datacenterId: 1
+  datacenterId: 2
   # 环境标识
   env: prod
 
@@ -109,11 +114,27 @@ client:
 # cloud
 cloud:
   # 存储对象公开可访问
-  public-bucket-name: mp-public-1307117429
+  public-bucket-name: mp-public-1310078123
   # 存储对象公开不可访问,需要通过应用下载
-  private-bucket-name: mp-auth-1307117429
+  private-bucket-name: mp-auth-1310078123
+
+  accessKey: AKIDSnvoRovmOkqfGbfT1JL6bssd9OTJsBE1
+  secretKey: auxkHXWFhtpX0C7lCMFrDJ8g39zY8Yic
+  region: ap-shanghai
+
+mq:
+  consumer-conn: false
+  service-url: http://pulsar-rd94exwe9rmq.tdmq-pulsar.ap-sh.qcloud.tencenttdmq.com:5039
+  auth-token: eyJrZXlJZCI6InB1bHNhci1yZDk0ZXh3ZTlybXEiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJwdWxzYXItcmQ5NGV4d2U5cm1xX21wLXNlcnZlci1wcm9kIn0.lV__rvUtTdNxcFI9qq50s81YZxw9V-7vDxK0_tDJHNo
+  topic-ticket-generate: pulsar-rd94exwe9rmq/prod-share/topic-ticket-generate
+  topic-ticket-pay: pulsar-rd94exwe9rmq/prod-share/topic-ticket-pay
+  consumer-topics: pulsar-rd94exwe9rmq/prod-share/topic-ticket-generate,pulsar-rd94exwe9rmq/prod-share/topic-ticket-pay
 
 # 小程序
 miniprogram:
   # 接收通知的状态
   state: formal
+
+# 盲票导出每页查询数量
+export:
+  page-size: 1000

+ 14 - 1
mp-admin/src/main/resources/application-dev.yml

@@ -1,3 +1,7 @@
+mp:
+    # 文件路径 示例( Windows配置D:/ygp/uploadPath,Linux配置 /home/ygp/uploadPath)
+    profile: /Users/Steven/Documents/logs
+
 pay:
     callbackUrl: https://test-mp.quanshu123.com/service/notify/payCallback
 
@@ -25,7 +29,7 @@ spring:
         druid:
             # 主库数据源
             master:
-                url: jdbc:mysql://110.40.236.236:3306/mpdb_test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=UTC
+                url: jdbc:mysql://110.40.236.236:3306/mpdb_test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
                 username: mptest
                 password: wan789*@dfhzHu518!dr2xosn
                 # 从库数据源
@@ -83,6 +87,7 @@ logging:
         org.apache: warn
         io.lettuce.core: warn
         com.qs.mp.framework.interceptor: warn
+        ma.glasnost.orika: warn
 
 # 开发环境配置
 server:
@@ -106,6 +111,10 @@ cloud:
     # 存储对象公开不可访问,需要通过应用下载
     private-bucket-name: mp-auth-test-1307117429
 
+    accessKey: AKIDDF4dwzlGVTAmCMGvLVP4UfbHiuqVzFEw
+    secretKey: TgbFcjZ8HDse9ToujIabLo1yf5YqtfBX
+    region: ap-shanghai
+
 mq:
     consumer-conn: false
     service-url: http://pulsar-rkrxw2wx8zeo.tdmq-pulsar.ap-sh.public.tencenttdmq.com:8080
@@ -119,3 +128,7 @@ miniprogram:
     # 接收通知的状态
     state: developer
 
+# 盲票导出每页查询数量
+export:
+    page-size: 200
+

+ 19 - 7
mp-admin/src/main/resources/application-test.yml

@@ -1,3 +1,6 @@
+mp:
+  # 文件路径 示例( Windows配置D:/ygp/uploadPath,Linux配置 /home/ygp/uploadPath)
+  profile: /home/quanshu/mp-server
 pay:
   callbackUrl: https://test-mp.quanshu123.com/service/notify/payCallback
 
@@ -11,10 +14,11 @@ logging:
     io.lettuce.core: warn
     org.quartz.core: warn
     com.qs.mp.framework.interceptor: warn
+    ma.glasnost.orika: warn
 # 数据源配置
 spring:
     redis:
-      host: 110.40.236.236
+      host: 172.17.16.14
       port: 6379
       password: '@9(s2sWppxkess'
       # 连接超时时间(毫秒)
@@ -35,7 +39,7 @@ spring:
         druid:
             # 主库数据源
             master:
-                url: jdbc:mysql://110.40.236.236:3306/mpdb_test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=UTC
+                url: jdbc:mysql://172.17.16.14:3306/mpdb_test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
                 username: mptest
                 password: wan789*@dfhzHu518!dr2xosn
             # 从库数据源
@@ -111,16 +115,24 @@ cloud:
   # 存储对象公开不可访问,需要通过应用下载
   private-bucket-name: mp-auth-test-1307117429
 
+  accessKey: AKIDDF4dwzlGVTAmCMGvLVP4UfbHiuqVzFEw
+  secretKey: TgbFcjZ8HDse9ToujIabLo1yf5YqtfBX
+  region: ap-shanghai
+
 mq:
   consumer-conn: true
-  service-url: http://pulsar-rkrxw2wx8zeo.tdmq-pulsar.ap-sh.public.tencenttdmq.com:8080
-  auth-token: eyJrZXlJZCI6InB1bHNhci1ya3J4dzJ3eDh6ZW8iLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJwdWxzYXItcmtyeHcyd3g4emVvX21wLXNlcnZlci10ZXN0In0.12cemXSqXGn9beDFnB-uUe477G6pP9bNbDUA4fIRsgk
-  topic-ticket-generate: pulsar-rkrxw2wx8zeo/test-share/topic-ticket-generate
-  topic-ticket-pay: pulsar-rkrxw2wx8zeo/test-share/topic-ticket-pay
-  consumer-topics: pulsar-rkrxw2wx8zeo/test-share/topic-ticket-generate,pulsar-rkrxw2wx8zeo/test-share/topic-ticket-pay
+  service-url: http://pulsar-op4bzppa37m4.tdmq-pulsar.ap-sh.public.tencenttdmq.com:8080
+  auth-token: eyJrZXlJZCI6InB1bHNhci1vcDRienBwYTM3bTQiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJwdWxzYXItb3A0YnpwcGEzN200X21wLXNlcnZlci10ZXN0In0.GVeFHHSqIYqTeOtXItWOT-NfydCSNvvVVS2FlpFZNKY
+  topic-ticket-generate: pulsar-op4bzppa37m4/test-share/topic-ticket-generate
+  topic-ticket-pay: pulsar-op4bzppa37m4/test-share/topic-ticket-pay
+  consumer-topics: pulsar-op4bzppa37m4/test-share/topic-ticket-generate,pulsar-op4bzppa37m4/test-share/topic-ticket-pay
 
 
 # 小程序
 miniprogram:
   # 接收通知的状态
   state: developer
+
+# 盲票导出每页查询数量
+export:
+  page-size: 200

+ 2 - 4
mp-admin/src/main/resources/application.yml

@@ -8,8 +8,6 @@ mp:
   copyrightYear: 2022
   # 实例演示开关
   demoEnabled: true
-  # 文件路径 示例( Windows配置D:/ygp/uploadPath,Linux配置 /home/ygp/uploadPath)
-  profile: /home/quanshu/mp-server
   # 获取ip地址开关
   addressEnabled: false
   # 验证码类型 math 数组计算 char 字符验证
@@ -145,8 +143,8 @@ pay:
   baseUrl: https://jlpays.kakapaypay.com
   user-shopNo: 1646882813774
   user-sign: 614140724fb74085be8aef8bebc538ed
-  channel-shopNo: 1646882813774
-  channel-sign: 614140724fb74085be8aef8bebc538ed
+  channel-shopNo: 1647504328218
+  channel-sign: 0e0c00555fee4549b1a88af4d988415b
 
 #幸运数字加密密钥对
 rsa:

+ 2 - 2
mp-admin/src/main/resources/logback-8100.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <configuration>
     <!-- 日志存放路径 -->
-	<property name="log.path" value="/home/quanshu/mp-server/logs/8100" />
+	<property name="log.path" value="/home/mangpiao/mp-server/logs/8100" />
     <!-- 日志输出格式 -->
     <!-- You can override this to have a custom pattern -->
 	<property name="CONSOLE_LOG_PATTERN" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
@@ -67,4 +67,4 @@
         <appender-ref ref="SendErrorMsgAppender"/>
     </root>
 
-</configuration> 
+</configuration>

+ 2 - 2
mp-admin/src/main/resources/logback-8200.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <configuration>
     <!-- 日志存放路径 -->
-	<property name="log.path" value="/home/quanshu/mp-server/logs/8200" />
+	<property name="log.path" value="/home/mangpiao/mp-server/logs/8200" />
     <!-- 日志输出格式 -->
     <!-- You can override this to have a custom pattern -->
 	<property name="CONSOLE_LOG_PATTERN" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
@@ -67,4 +67,4 @@
         <appender-ref ref="SendErrorMsgAppender"/>
     </root>
 
-</configuration> 
+</configuration>

+ 2 - 2
mp-admin/src/main/resources/logback-spring.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <configuration>
     <!-- 日志存放路径 -->
-	<property name="log.path" value="/Users/daixiaodan/Documents/logs" />
+	<property name="log.path" value="/Users/Steven/Documents/logs" />
     <!-- 日志输出格式 -->
     <!-- You can override this to have a custom pattern -->
 	<property name="CONSOLE_LOG_PATTERN" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
@@ -63,4 +63,4 @@
         <appender-ref ref="DEBUG"/>
         <appender-ref ref="ERROR" />
     </root>
-</configuration> 
+</configuration>

+ 42 - 0
mp-admin/src/test/java/com/qs/mp/api/UserDeliverOrderMgrControllerTest.java

@@ -0,0 +1,42 @@
+package com.qs.mp.api;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.jupiter.api.Test;
+
+import com.alibaba.fastjson.JSON;
+import com.qs.mp.common.BaseControllerTest;
+
+/**
+ * @auther duota
+ * @create 2021 2021/9/7 6:36 下午
+ * @describe
+ */
+public class UserDeliverOrderMgrControllerTest extends BaseControllerTest {
+
+  /**
+   * 发送短信验证码接口
+   */
+  @Test
+  public void testList(){
+    Map<String, Object> map = new HashMap<String, Object>();
+	int pageNum = 1;
+	int pageSize = 10;
+	map.put("pageNum", pageNum);
+	map.put("pageSize", pageSize);
+	String params = JSON.toJSONString(map);
+    String url = "http://localhost:8080/api/v1/mp/admin/deliver/order/list?";
+    System.out.println(request(url, params));
+  }
+  
+  
+  @Test
+  public void testQuery(){
+    Map<String, Object> map = new HashMap<String, Object>();
+	map.put("orderId", "95588124524032822218");
+	String params = JSON.toJSONString(map);
+    String url = "http://localhost:8080/api/v1/mp/admin/deliver/order/detail?";
+    System.out.println(request(url, params));
+  }
+}

+ 1 - 1
mp-admin/src/test/java/com/qs/mp/common/BaseControllerTest.java

@@ -31,7 +31,7 @@ public class BaseControllerTest {
     headers.put("content-type", "application/json; charset=UTF-8");
     headers.put("x-zz-timestamp", timestamp);
     // 本地登录状态
-    String token = "eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6IjEyY2NjMzUyLTZmZWQtNDVlNC04NzIzLWJlNjliOWM0Zjg0NCJ9.GAYmA8UEM3Tt97rAGl6PHSAC1wMqrxIlsbmBIpDXdmOACyYcYBgatAxLArovIJlEs1kYDVw_Z64nkE46I6Im2g";
+    String token = "eyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6Ijg3ZWM0OGMwLWQ4ZWYtNDcwYS05ZTQ5LThhOWI0NWMzOWM3MSJ9.q3l1Q0xoWBvXY6eZKfEAKXHZclb2ssMdGO4xd5IjvSNnIRdOLT8kA9jsGo8iR2KZOXjaEfN_DBxPfD6vGZpemg";
 
     if (!StringUtils.isBlank(token)) {
       headers.put("Authorization", "Bearer "+token);

+ 50 - 1
mp-admin/src/test/java/com/qs/mp/service/ServiceImplTest.java

@@ -3,6 +3,10 @@ package com.qs.mp.service;
 import com.qs.mp.MpApplication;
 import com.qs.mp.admin.service.ITicketBoxSerialService;
 import com.qs.mp.framework.service.IWxUrlLinkService;
+import com.qs.mp.quartz.task.CosTask;
+import com.qs.mp.quartz.task.DayStatTask;
+import com.qs.mp.quartz.task.TicketBoxTask;
+import java.io.IOException;
 import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -30,9 +34,30 @@ public class ServiceImplTest {
   @Autowired
   private ITicketBoxSerialService ticketBoxSerialService;
 
+  @Autowired
+  private TicketBoxTask ticketBoxTask;
+
+  @Autowired
+  private DayStatTask dayStatTask;
+
+  @Autowired
+  private CosTask cosTask;
+
   @Test
   public void testGenerateQrCode() {
-    System.out.println(wxUrlLinkService.generateCode("pages/index/index", "id=1", "wx8533800e393dbd6b"));
+    System.out.println(wxUrlLinkService.generateCode("pages/index/index", "id=1", "wxc3a684f1196f6e15"));
+
+  }
+
+  @Test
+  public void testGenerateUnlimitCode() {
+    System.out.println(wxUrlLinkService.generateUnlimitCode("pages/ticketBox/detail", "boxId=1&suid=2&type=user", "wx8533800e393dbd6b"));
+
+  }
+
+  @Test
+  public void testGenerateShortUrl() {
+    System.out.println(wxUrlLinkService.generate("", "", "wxc3a684f1196f6e15"));
 
   }
 
@@ -49,6 +74,30 @@ public class ServiceImplTest {
   }
 
 
+  @Test
+  public void testCheckTicketBox() {
+    ticketBoxTask.checkPrize("954112676047486977");
+
+  }
+
+  @Test
+  public void testDayStat() {
+    dayStatTask.stat(null);
+  }
+
+  @Test
+  public void testCosCompress() {
+    try {
+      cosTask.compressPicture();
+    } catch (IOException e) {
+      e.printStackTrace();
+    } catch (InterruptedException e) {
+      e.printStackTrace();
+    }
+  }
+
+
+
 
   public static void main(String[] args) {
     /*int n = 500;

+ 51 - 0
mp-common/src/main/java/com/qs/mp/common/enums/BannerLocationEnum.java

@@ -0,0 +1,51 @@
+package com.qs.mp.common.enums;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.annotation.JSONType;
+import com.baomidou.mybatisplus.annotation.IEnum;
+import com.qs.mp.common.json.EnumValueDeserializer;
+
+/**
+ *
+ * banner位置
+ *
+ */
+@JSONType(deserializer = EnumValueDeserializer.class)
+public enum BannerLocationEnum implements IEnum<String> {
+
+  PUT_ON("top", "顶部轮播"),;
+
+  private final String value;
+  private final String desc;
+
+  public static BannerLocationEnum getStatusEnum(String value) {
+    for (BannerLocationEnum statusEnum : BannerLocationEnum.values()) {
+      if (statusEnum.getValue().equals(value)) {
+        return statusEnum;
+      }
+    }
+    return null;
+  }
+
+  BannerLocationEnum(final String value, final String desc) {
+    this.value = value;
+    this.desc = desc;
+  }
+
+  @Override
+  public String getValue() {
+    return value;
+  }
+
+  /**
+   * 重写toString,单个转化成json
+   * @return
+   */
+  @Override
+  public String toString() {
+    JSONObject object = new JSONObject();
+    object.put("value",value);
+    object.put("desc", desc);
+    return object.toString();
+  }
+}

+ 4 - 2
mp-common/src/main/java/com/qs/mp/common/enums/ChannelMoneyEnum.java

@@ -11,9 +11,11 @@ import com.baomidou.mybatisplus.annotation.IEnum;
 public enum ChannelMoneyEnum implements IEnum<Integer> {
 
   COMMISSION(1, "佣金收入"),
-  WITHDRAW(2, "提现"),
+  WITHDRAW(2, "余额提现"),
   WITHDRAW_FEE(3, "提现手续费"),
-  PURCHASE(4, "进票");
+  PURCHASE(4, "进票"),
+  COUPON(5, "优惠券核销结算"),
+  WITHDRAW_BACK(6, "余额提现退回");
 
 
   private final int value;

+ 4 - 0
mp-common/src/main/java/com/qs/mp/common/enums/ChannelOrderStatusEnum.java

@@ -30,6 +30,10 @@ public enum ChannelOrderStatusEnum implements IEnum<Integer> {
   public Integer getValue() {
     return value;
   }
+  
+  public String getDesc() {
+	return desc;
+  }
 
   /**
    * 重写toString,单个转化成json

+ 54 - 0
mp-common/src/main/java/com/qs/mp/common/enums/ChannelWithdrawStatusEnum.java

@@ -0,0 +1,54 @@
+package com.qs.mp.common.enums;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.annotation.JSONType;
+import com.baomidou.mybatisplus.annotation.IEnum;
+import com.qs.mp.common.json.EnumValueDeserializer;
+
+/**
+ * @auther zhongcp
+ * @create 2022 2022/3/7 2:30 下午
+ * @describe
+ */
+@JSONType(deserializer = EnumValueDeserializer.class)
+public enum ChannelWithdrawStatusEnum implements IEnum<Integer> {
+
+  WITHDRAWING(1, "提现中"),
+  FINISHED(2, "已完成"),
+  FAILED(3, "提现失败");
+
+
+  private final int value;
+  private final String desc;
+
+  ChannelWithdrawStatusEnum(int value, String desc) {
+    this.value = value;
+    this.desc = desc;
+  }
+
+  public static ChannelWithdrawStatusEnum getChannelWithdrawStatusEnum(int value) {
+    for (ChannelWithdrawStatusEnum channelMoneyTypeEnum : ChannelWithdrawStatusEnum.values()) {
+      if (channelMoneyTypeEnum.getValue() == value) {
+        return channelMoneyTypeEnum;
+      }
+    }
+    return null;
+  }
+
+  @Override
+  public Integer getValue() {
+    return value;
+  }
+
+  public String getDesc() {
+    return desc;
+  }
+
+  @Override
+  public String toString() {
+    JSONObject object = new JSONObject();
+    object.put("value", value);
+    object.put("desc", desc);
+    return object.toString();
+  }
+}

+ 1 - 1
mp-common/src/main/java/com/qs/mp/common/enums/CoinLogTypeEnum.java

@@ -11,7 +11,7 @@ import com.baomidou.mybatisplus.annotation.IEnum;
 public enum CoinLogTypeEnum implements IEnum<Integer> {
 
   PRIZE(1, "盲票奖品"),
-  CASHED(2, "商品兑换");
+  EXCHANGE(2, "商品兑换");
 
 
   private final int value;

+ 43 - 0
mp-common/src/main/java/com/qs/mp/common/enums/CommStatusEnum.java

@@ -0,0 +1,43 @@
+package com.qs.mp.common.enums;
+
+import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.annotation.JSONType;
+import com.baomidou.mybatisplus.annotation.IEnum;
+import com.qs.mp.common.json.EnumValueDeserializer;
+
+/**
+ *
+ * 渠道结佣状态
+ *
+ */
+@JSONType(deserializer = EnumValueDeserializer.class)
+public enum CommStatusEnum implements IEnum<Integer> {
+  NO(0, "未结佣"),
+  YES(1, "已结佣"),
+  DOING(2, "结佣中");
+
+  private final int value;
+  private final String desc;
+
+  CommStatusEnum(final int value, final String desc) {
+    this.value = value;
+    this.desc = desc;
+  }
+
+  @Override
+  public Integer getValue() {
+    return value;
+  }
+
+  /**
+   * 重写toString,单个转化成json
+   * @return
+   */
+  @Override
+  public String toString() {
+    JSONObject object = new JSONObject();
+    object.put("value",value);
+    object.put("desc", desc);
+    return object.toString();
+  }
+}

+ 40 - 0
mp-common/src/main/java/com/qs/mp/common/enums/CouponSettleStatusEnum.java

@@ -0,0 +1,40 @@
+package com.qs.mp.common.enums;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.annotation.IEnum;
+
+/**
+ *
+ * 用户卡券使用状态
+ *
+ */
+public enum CouponSettleStatusEnum implements IEnum<Integer> {
+
+  INIT(1, "待结算"),
+  FINISHED(2, "已结算"),;
+
+  private final Integer value;
+  private final String desc;
+
+  CouponSettleStatusEnum(final Integer value, final String desc) {
+    this.value = value;
+    this.desc = desc;
+  }
+
+  @Override
+  public Integer getValue() {
+    return value;
+  }
+
+  /**
+   * 重写toString,单个转化成json
+   * @return
+   */
+  @Override
+  public String toString() {
+    JSONObject object = new JSONObject();
+    object.put("value",value);
+    object.put("desc", desc);
+    return object.toString();
+  }
+}

+ 6 - 1
mp-common/src/main/java/com/qs/mp/common/enums/CouponUseAreaEnum.java

@@ -15,7 +15,9 @@ public enum CouponUseAreaEnum implements IEnum<Integer> {
 
   COMMON(0, "通用"),
   PRE_SCOPE(1, "指定范围"), // 生成优惠券的时候设定使用范围
-  POST_SCOPE(2, "指定范围"); // 发放的时候动态设定使用范围
+  POST_SCOPE(2, "指定范围"), // 门店消费类优惠券,发放的时候动态设定使用范围
+  ONLINE_SCOPE(3, "所有线上盲票"), // 盲票购买类优惠券,仅限线上盲票
+  OFFLINE_SCOPE(4, "所有线下盲票"); // 盲票购买类优惠券,仅限线下盲票
 
 
   private final int value;
@@ -31,6 +33,9 @@ public enum CouponUseAreaEnum implements IEnum<Integer> {
     return value;
   }
 
+  public String getDesc() {
+    return desc;
+  }
 
   @Override
   public String toString() {

+ 7 - 2
mp-common/src/main/java/com/qs/mp/common/enums/DeliverOrderStatusEnum.java

@@ -16,7 +16,8 @@ public enum DeliverOrderStatusEnum implements IEnum<Integer> {
   NOT_PAY(0, "待付款"),
   NOT_DELIVER(1, "待发货"),
   NOT_CONFIRM(2, "待收货"),
-  FINISHED(3, "已完成");
+  FINISHED(3, "已完成"),
+  PART_DELIVER(4, "部分发货");
 
   private final int value;
   private final String desc;
@@ -30,8 +31,12 @@ public enum DeliverOrderStatusEnum implements IEnum<Integer> {
   public Integer getValue() {
     return value;
   }
+  
+  public String getDesc() {
+	return desc;
+}
 
-  /**
+/**
    * 重写toString,单个转化成json
    * @return
    */

+ 6 - 0
mp-common/src/main/java/com/qs/mp/common/enums/ErrorCodeEnum.java

@@ -26,6 +26,12 @@ public enum ErrorCodeEnum {
   ERROR_CODE_1017(1017, "盲票已兑奖"),
   ERROR_CODE_1018(1018, "无权限查看"),
   ERROR_CODE_1019(1019, "盲票未付款"),
+  ERROR_CODE_1020(1020, "库存不足"),
+  ERROR_CODE_1021(1021, "盲豆余额不足"),
+  ERROR_CODE_1022(1022, "订单支付中"),
+  ERROR_CODE_1023(1023, "盲票未激活"),
+  ERROR_CODE_1024(1024, "删除失败,分类下存在商品"),
+  ERROR_CODE_1025(1025, "删除失败,标签下存在商品"),
   ;
   private int code;
   private String msg;

+ 9 - 0
mp-common/src/main/java/com/qs/mp/common/enums/GoodsStatusEnum.java

@@ -20,6 +20,15 @@ public enum GoodsStatusEnum implements IEnum<String> {
   private final String value;
   private final String desc;
 
+  public static GoodsStatusEnum getStatusEnum(String value) {
+    for (GoodsStatusEnum statusEnum : GoodsStatusEnum.values()) {
+      if (statusEnum.getValue().equals(value)) {
+        return statusEnum;
+      }
+    }
+    return null;
+  }
+
   GoodsStatusEnum(final String value, final String desc) {
     this.value = value;
     this.desc = desc;

+ 41 - 0
mp-common/src/main/java/com/qs/mp/common/enums/PayOrderStatusEnum.java

@@ -0,0 +1,41 @@
+package com.qs.mp.common.enums;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.annotation.IEnum;
+
+/**
+ *
+ * 支付订单状态类型
+ *
+ */
+public enum PayOrderStatusEnum implements IEnum<String> {
+
+  SUCCESS("1", "支付成功"),
+  WAIT("2", "待支付");
+
+
+  private final String value;
+  private final String desc;
+
+  PayOrderStatusEnum(final String value, final String desc) {
+    this.value = value;
+    this.desc = desc;
+  }
+
+  @Override
+  public String getValue() {
+    return value;
+  }
+
+  /**
+   * 重写toString,单个转化成json
+   * @return
+   */
+  @Override
+  public String toString() {
+    JSONObject object = new JSONObject();
+    object.put("value",value);
+    object.put("desc", desc);
+    return object.toString();
+  }
+}

+ 31 - 0
mp-common/src/main/java/com/qs/mp/common/enums/PicHandlerTypeEnum.java

@@ -0,0 +1,31 @@
+package com.qs.mp.common.enums;
+
+import com.baomidou.mybatisplus.annotation.IEnum;
+import io.swagger.annotations.ApiModel;
+
+/**
+ * 图片处理类型枚举
+ * @author Cup
+ * @date 2022/4/15
+ */
+@ApiModel(value = "图片处理类型枚举")
+public enum PicHandlerTypeEnum implements IEnum<Integer> {
+
+    CROP(1, "裁剪"),
+    COMPRESSION(2, "压缩");
+
+
+    private final int value;
+    private final String desc;
+
+    PicHandlerTypeEnum(int value, String desc) {
+        this.value = value;
+        this.desc = desc;
+    }
+
+    @Override
+    public Integer getValue() {
+        return value;
+    }
+
+}

+ 3 - 0
mp-common/src/main/java/com/qs/mp/common/enums/SiteTypeEnum.java

@@ -1,13 +1,16 @@
 package com.qs.mp.common.enums;
 
 import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.annotation.JSONType;
 import com.baomidou.mybatisplus.annotation.IEnum;
+import com.qs.mp.common.json.EnumValueDeserializer;
 
 /**
  *
  * 经销商门店类型
  *
  */
+@JSONType(deserializer = EnumValueDeserializer.class)
 public enum SiteTypeEnum implements IEnum<Integer> {
 
   STREET_STORE(1, "临街门店"),

+ 4 - 0
mp-common/src/main/java/com/qs/mp/common/enums/TicketTypeEnum.java

@@ -29,6 +29,10 @@ public enum TicketTypeEnum implements IEnum<String> {
     return value;
   }
 
+  public String getDesc() {
+    return desc;
+  }
+
   /**
    * 重写toString,单个转化成json
    * @return

+ 3 - 0
mp-common/src/main/java/com/qs/mp/common/enums/UserCouponStatusEnum.java

@@ -1,13 +1,16 @@
 package com.qs.mp.common.enums;
 
 import com.alibaba.fastjson.JSONObject;
+import com.alibaba.fastjson.annotation.JSONType;
 import com.baomidou.mybatisplus.annotation.IEnum;
+import com.qs.mp.common.json.EnumValueDeserializer;
 
 /**
  *
  * 用户卡券使用状态
  *
  */
+@JSONType(deserializer = EnumValueDeserializer.class)
 public enum UserCouponStatusEnum implements IEnum<Integer> {
 
   UNUSED(1, "未使用"),

+ 2 - 2
mp-common/src/main/java/com/qs/mp/common/enums/UserIdentityEnum.java

@@ -8,9 +8,9 @@ package com.qs.mp.common.enums;
  */
 public enum UserIdentityEnum {
 
-	CHANNEL, // 渠道端
+	ADMIN, // 管理后台
 	USER, // 用户
-	ADMIN // 管理后台
+	CHANNEL // 渠道端
 	;
 	public static boolean isChannel(int identity) {
 		return identity == CHANNEL.ordinal();

+ 25 - 0
mp-common/src/main/java/com/qs/mp/common/filter/ThumbnailsImgFilter.java

@@ -0,0 +1,25 @@
+package com.qs.mp.common.filter;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import net.coobird.thumbnailator.filters.ImageFilter;
+
+/**
+ * @author zhongcp
+ * @Date 2022/4/16
+ */
+public class ThumbnailsImgFilter implements ImageFilter {
+  @Override
+  public BufferedImage apply(BufferedImage img) {
+    int w = img.getWidth();
+    int h = img.getHeight();
+    BufferedImage newImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+    Graphics2D graphic = newImage.createGraphics();
+    graphic.setColor(Color.white);//背景设置为白色
+    graphic.fillRect(0, 0, w, h);
+    graphic.drawRenderedImage(img, null);
+    graphic.dispose();
+    return newImage;
+  }
+}

+ 6 - 9
mp-common/src/main/java/com/qs/mp/common/jsms/JSMSUtils.java

@@ -36,11 +36,8 @@ public class JSMSUtils {
 
     protected static final Logger logger = LoggerFactory.getLogger(JSMSUtils.class);
 
-    private static final String appkey = "2f17e0698d004ca7411a9ef6";
-    private static final String masterSecret = "a6446a6b8bf8a4be72bf86d4";
-/*
-    private static final String devKey = "242780bfdd7315dc1989fedb";
-    private static final String devSecret = "2f5ced2bef64167950e63d13";*/
+    private static final String appkey = "07abbc24df161327ea51d311";
+    private static final String masterSecret = "a7710786463881179a3d5b22";
     private static String env;
 
     @Value("${server.env}")
@@ -79,7 +76,7 @@ public class JSMSUtils {
     }
 
     public static SendSMSResult sendChannelActNotify(String mobile) {
-        return sendSMSResult(mobile, 206374);
+        return sendSMSResult(mobile, 206810);
     }
 
 
@@ -90,7 +87,7 @@ public class JSMSUtils {
         try {
             if (ServerEnvEnum.PROD.getCode().equals(env)) {
                 SendSMSResult res = client.sendTemplateSMS(payload);
-                LogUtil.info(logger, "账单支付失败短信发送,mobile:{0}, res:{1}", new Object[]{mobile, JSON.toJSONString(res)});
+                LogUtil.info(logger, "短信发送,mobile:{0}, res:{1}", new Object[]{mobile, JSON.toJSONString(res)});
                 return res;
             } else {
                 logger.info("非生产环境,不发送短信!" + mobile + "," + tempId);
@@ -98,9 +95,9 @@ public class JSMSUtils {
 
             }
         } catch (APIConnectionException e) {
-            LogUtil.error(logger, e, "账单支付失败短信发送失败,mobile:{0}", mobile);
+            LogUtil.error(logger, e, "短信发送失败,mobile:{0}", mobile);
         } catch (APIRequestException e) {
-            LogUtil.error(logger, e, "账单支付失败短信发送失败,mobile:{0}", mobile);
+            LogUtil.error(logger, e, "短信发送失败,mobile:{0}", mobile);
         }
         return null;
     }

+ 4 - 2
mp-common/src/main/java/com/qs/mp/common/pulsar/PulsarClientService.java

@@ -1,6 +1,7 @@
 package com.qs.mp.common.pulsar;
 
 import com.qs.mp.common.enums.MqTopicType;
+import com.qs.mp.common.utils.LogUtil;
 import com.qs.mp.common.utils.StringUtils;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
@@ -94,11 +95,12 @@ public class PulsarClientService {
         try {
           pulsarConsumer.wsConsumer(key, jsons);
           logger.info("receive data>>>>>>" + jsons);
+          consumer.acknowledge(message);
         } catch (Exception e) {
-          logger.error("消费Pulsar数据异常,key【{}】,json【{}】:", message.getKey(), jsons, e);
+          LogUtil.error(logger, e, "消费Pulsar数据异常,key【{0}】,json【{1}】:", new Object[]{message.getKey(), jsons});
         }
       }
-      consumer.acknowledge(message);
+
     }
   }
 

+ 34 - 8
mp-common/src/main/java/com/qs/mp/common/qcloud/QcloudFileUtils.java

@@ -14,25 +14,51 @@ import java.io.File;
 import java.io.InputStream;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
 
 /**
  * @author zhongcp
  * @Date 2021/9/18
  */
+@Component
 public class QcloudFileUtils {
 
   private static final Logger logger = LoggerFactory.getLogger(QcloudFileUtils.class);
 
-  static COSClient cosClient = createCli();
+  private static COSClient cosClient;
 
-  static COSClient createCli() {
-    return createCli("ap-shanghai");
+  private static String accessKey;
+
+  @Value("${cloud.accessKey}")
+  public void setAccessKey(String accessKeyParam) {
+    accessKey = accessKeyParam;
+  }
+
+  private static String secretKey;
+
+  @Value("${cloud.secretKey}")
+  public void setSecretKey(String secretKeyParam) {
+    secretKey = secretKeyParam;
+  }
+
+  private static String region;
+
+  @Value("${cloud.region}")
+  public void setRegion(String regionParam) {
+    region = regionParam;
+  }
+
+  public static COSClient getCosClient() {
+    if (null == cosClient) {
+      cosClient = createCli(region);
+    }
+    return cosClient;
   }
 
   static COSClient createCli(String region) {
     // 初始化用户身份信息(secretId, secretKey)
-    COSCredentials cred = new BasicCOSCredentials("AKIDDF4dwzlGVTAmCMGvLVP4UfbHiuqVzFEw",
-        "TgbFcjZ8HDse9ToujIabLo1yf5YqtfBX");
+    COSCredentials cred = new BasicCOSCredentials(accessKey, secretKey);
     // 设置bucket的区域, COS地域的简称请参照 https://www.qcloud.com/document/product/436/6224
     ClientConfig clientConfig = new ClientConfig(new Region(region));
     // 生成cos客户端
@@ -47,7 +73,7 @@ public class QcloudFileUtils {
     PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, file);
     putObjectRequest.withMetadata(objectMetadata);
 
-    PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
+    PutObjectResult putObjectResult = getCosClient().putObject(putObjectRequest);
 
     LogUtil.info(logger, "put file reqId: " + putObjectResult.getRequestId());
   }
@@ -61,7 +87,7 @@ public class QcloudFileUtils {
     PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, stream, objectMetadata);
 //    putObjectRequest.withMetadata(objectMetadata);
 
-    PutObjectResult putObjectResult = cosClient.putObject(putObjectRequest);
+    PutObjectResult putObjectResult = getCosClient().putObject(putObjectRequest);
 
     LogUtil.info(logger, "put file reqId: " + putObjectResult.getRequestId());
 
@@ -90,7 +116,7 @@ public class QcloudFileUtils {
   public static void downloadFile(String key, String bucketName, String localDir, String saveName) {
     GetObjectRequest getObjectRequest = new GetObjectRequest(bucketName, key);
     File localFile = new File(localDir + saveName);
-    ObjectMetadata objectMetadata = cosClient.getObject(getObjectRequest, localFile);
+    ObjectMetadata objectMetadata = getCosClient().getObject(getObjectRequest, localFile);
 
     LogUtil.info(logger, "download file content length:" + objectMetadata.getContentLength());
   }

+ 336 - 0
mp-common/src/main/java/com/qs/mp/common/utils/DateUtils.java

@@ -1,10 +1,18 @@
 package com.qs.mp.common.utils;
 
 import java.lang.management.ManagementFactory;
+import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.SimpleDateFormat;
+import java.util.ArrayList;
 import java.util.Calendar;
+import java.util.Collections;
 import java.util.Date;
+import java.util.GregorianCalendar;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
 import org.apache.commons.lang3.time.DateFormatUtils;
 import org.joda.time.DateTime;
 import org.joda.time.Days;
@@ -12,6 +20,8 @@ import org.joda.time.Months;
 import org.joda.time.format.DateTimeFormat;
 import org.joda.time.format.DateTimeFormatter;
 
+import com.alibaba.fastjson.JSON;
+
 /**
  * 时间工具类
  *
@@ -235,4 +245,330 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
         }
         return null;
     }
+    
+    // 首页统计日期处理
+ 	 /** 
+ 	 * 取得指定日期的前面几天日期
+ 	 */ 
+ 	 public static Date getPreDayOfNow(int days) { 
+ 		try {
+			Calendar c = Calendar.getInstance();
+		   	c.setFirstDayOfWeek(Calendar.MONDAY); 
+		   	c.add(Calendar.DATE, - days);
+		   	return c.getTime(); 
+		} catch (Exception e) {
+			e.printStackTrace();
+			return null;
+		}
+ 	 }
+    
+    
+  	 /** 
+  	 * 取得指定日期的前面几天日期0点
+  	 */ 
+  	 public static Date getPreDayOfNowZero(int days) { 
+  		try {
+			Calendar c = Calendar.getInstance();
+		   	c.setFirstDayOfWeek(Calendar.MONDAY); 
+		   	c.add(Calendar.DATE, - days);
+		   	c.set(Calendar.HOUR_OF_DAY, 0);
+		   	c.set(Calendar.MINUTE, 0);
+		   	c.set(Calendar.SECOND, 0);
+		   	return c.getTime(); 
+		} catch (Exception e) {
+			e.printStackTrace();
+			return null;
+		}
+  	 }
+  	 
+  	/** 
+   	 * 取得指定日期的最晚时间
+   	 */ 
+   	 public static Date getEndTimeOfNow(Date endDate) { 
+   		try {
+ 			Calendar c = Calendar.getInstance();
+ 		   	c.setTime(endDate);
+ 		   	c.set(Calendar.HOUR_OF_DAY, 23);
+ 		   	c.set(Calendar.MINUTE, 59);
+ 		   	c.set(Calendar.SECOND, 59);
+ 		    c.set(Calendar.MILLISECOND, 59);
+ 		   	return c.getTime(); 
+ 		} catch (Exception e) {
+ 			e.printStackTrace();
+ 			return null;
+ 		}
+   	 }
+    
+    /** 
+     * @Title: getDateOfWeek 
+     * @Description: 获取两个时间内所有周之间的时间段,并且获得是今年第几周
+     * @param start_time    开始时间 
+     * @param end_time      结束时间 
+     */  
+    public static List<Map<String,Object>> getDateOfWeek(Date startTime, Date endTime) {
+    	List<Map<String,Object>> rtnList = new ArrayList<Map<String,Object>>();
+    	try {  
+            SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");  
+            
+            Calendar startCalendar = Calendar.getInstance();  
+            startCalendar.setTime(startTime);  
+            
+            Calendar endCalendar = Calendar.getInstance();  
+            endCalendar.setTime(endTime);  
+            
+            String firstWeekDay = getFirstDayOfWeek(startTime);  // 取得开始日期指定日期所在周的第一天
+	        String lastWeekDay = getLastDayOfWeek(endTime);      // 取得结束日期指定日期所在周的最后一天
+	        
+            // 开始日期所在的周
+            int startWeekOfYear = startCalendar.get(Calendar.WEEK_OF_YEAR);  
+            System.out.println("startWeekOfYear == " +startWeekOfYear);
+            
+            // 截止日期所在的周
+            int endWeekOfYear = endCalendar.get(Calendar.WEEK_OF_YEAR);  
+            System.out.println("currentWeekOfYear_e == " +endWeekOfYear);
+              
+            int j = 12;  
+            for (int i=0; i < endWeekOfYear + 53; i++) {  
+            	
+            	 //只取两个日期之间的周  
+//                if(startWeekOfYear > endWeekOfYear - i){  
+//                    break;  
+//                }  
+                int dayOfWeek = endCalendar.get(Calendar.DAY_OF_WEEK) - 2;  
+                
+                System.out.println("dayOfWeek == " +dayOfWeek);
+            	List<String> list = new ArrayList<>();
+                
+                endCalendar.add(Calendar.DATE, - dayOfWeek); //得到本周的第一天  
+                String s_date = sdf.format(endCalendar.getTime());  
+                
+                Long startTIme = endCalendar.getTimeInMillis();   
+                
+                endCalendar.add(Calendar.DATE, 6);  //得到本周的最后一天  
+                String e_date = sdf.format(endCalendar.getTime());  
+               
+                //结束时间转换成时间戳
+                Long endTIme = endCalendar.getTimeInMillis();
+               
+                //定义一个一天的时间戳时长
+                Long oneDay = 1000 * 60 * 60 * 24L;
+                Long time = startTIme;
+                //循环得出
+                while (time <= endTIme) {
+                    list.add(new SimpleDateFormat("yyyyMMdd").format(new Date(time)));
+                    time += oneDay;
+                }
+                endCalendar.add(Calendar.DATE, -j); //减去增加的日期  
+                System.out.println("");
+                //只取两个日期之间的周
+	            if(compareDate(firstWeekDay, s_date) && compareDate(s_date, lastWeekDay)
+	            		&& compareDate(firstWeekDay, e_date) && compareDate(e_date, lastWeekDay)){
+	            	//超过选择的日期,按选择日期来算
+	            	if(!compareDate(sdf.format(startTime), s_date)){
+	 	            	s_date = sdf.format(startTime);
+	 	            }
+	            	if(!compareDate(e_date, sdf.format(endTime))){
+	 	            	e_date = sdf.format(endTime);
+	 	            }
+	            	 Calendar yearCalendar = Calendar.getInstance();  
+	            	 yearCalendar.setTime(startTime);  
+	            	int year = yearCalendar.get(Calendar.YEAR);  
+	            	String s = year+ "年的第" + (endWeekOfYear - i) + "周" + "(" + s_date + "至" + e_date + ")";     
+	                System.out.println(s);  
+	               // System.out.println("包含的日期 = " +list.toString());
+	                Map<String,Object> map = new HashMap<String,Object>();
+	                map.put("start", s_date);
+	                map.put("end", e_date);
+	                map.put("year", year);
+	                map.put("week", endWeekOfYear - i);
+	                map.put("dayList", list);
+	                rtnList.add(map);
+	            }
+               
+            }  
+              
+        } catch (Exception e) {  
+            e.printStackTrace();  
+        }
+    	Collections.reverse(rtnList);
+    	return rtnList;
+    }
+    
+    
+    /** 
+   	 * 取得指定日期所在周的第一天 
+   	 */ 
+   	 public static String getFirstDayOfWeek(Date date) { 
+		try {
+			SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+			Calendar c = new GregorianCalendar(); 
+		   	c.setFirstDayOfWeek(Calendar.MONDAY); 
+		   	c.setTime(date); 
+		   	c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek()); // Monday 
+		   	return sdf.format(c.getTime()); 
+		} catch (Exception e) {
+			e.printStackTrace();
+			return "";
+		}
+        
+	   	
+   	 }
+ 
+   	 /** 
+   	 * 取得指定日期所在周的最后一天 
+   	 */ 
+   	 public static String getLastDayOfWeek(Date date) { 
+   		try {
+			SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
+			Calendar c = new GregorianCalendar(); 
+		   	c.setFirstDayOfWeek(Calendar.MONDAY); 
+		   	c.setTime(date); 
+		   	c.set(Calendar.DAY_OF_WEEK, c.getFirstDayOfWeek() + 6); // Sunday 
+		   	return sdf.format(c.getTime()); 
+		} catch (Exception e) {
+			e.printStackTrace();
+			return "";
+		}
+   	 }
+   	 
+   	/**
+ 	 * compareDate方法
+ 	 * <p>方法说明:
+ 	 * 		比较endDate是否是晚于startDate;
+ 	 * 			如果是,返回true, 否则返回false
+ 	 * </p>
+ 	 */
+  	public static boolean compareDate(String startDate, String endDate) {
+ 		try {
+ 			DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
+ 			java.util.Date date1 = dateFormat.parse(startDate);
+ 			java.util.Date date2 = dateFormat.parse(endDate);
+ 			if (date1.getTime() > date2.getTime())
+ 				return false;
+ 			return true; //startDate时间上早于endDate
+ 			
+ 		} catch (Exception e) {
+ 			return false; 
+ 		}
+ 	}
+
+
+    /**
+     * @param cntDateBeg 开始时间
+     * @param cntDateEnd 结束时间
+     * @return
+     */
+    public static List<String> addDates(String cntDateBeg, String cntDateEnd) {
+        List<String> list = new ArrayList<>();
+        //拆分成数组
+        String[] dateBegs = cntDateBeg.split("-");
+        String[] dateEnds = cntDateEnd.split("-");
+        //开始时间转换成时间戳
+        Calendar start = Calendar.getInstance();
+        start.set(Integer.valueOf(dateBegs[0]), Integer.valueOf(dateBegs[1]) - 1, Integer.valueOf(dateBegs[2]));
+        Long startTIme = start.getTimeInMillis();
+        //结束时间转换成时间戳
+        Calendar end = Calendar.getInstance();
+        end.set(Integer.valueOf(dateEnds[0]), Integer.valueOf(dateEnds[1]) - 1, Integer.valueOf(dateEnds[2]));
+        Long endTime = end.getTimeInMillis();
+        //定义一个一天的时间戳时长
+        Long oneDay = 1000 * 60 * 60 * 24L;
+        Long time = startTIme;
+        //循环得出
+        while (time <= endTime) {
+            list.add(new SimpleDateFormat("yyyyMMdd").format(new Date(time)));
+            time += oneDay;
+        }
+        return list;
+    }
+    
+    
+    /** 
+     * @Title: getDateOfWeek 
+     * @Description: 获取两个时间内所有周之间的时间段,并且获得是今年第几周
+     * @param start_time    开始时间 
+     * @param end_time      结束时间 
+     */  
+    public static List<String> addMonths(Date startTime, Date endTime) {
+    	List<String> list = new ArrayList<String>();
+    	try {  
+            Calendar calendar = Calendar.getInstance();
+            calendar.setTime(startTime);
+            // 获取开始年份和开始月份
+            int startYear = calendar.get(Calendar.YEAR);
+            int startMonth = calendar.get(Calendar.MONTH);
+            // 获取结束年份和结束月份
+            calendar.setTime(endTime);
+            int endYear = calendar.get(Calendar.YEAR);
+            int endMonth = calendar.get(Calendar.MONTH);
+            //
+            
+            for (int i = startYear; i <= endYear; i++) {
+                String date = "";
+                if (startYear == endYear) {
+                    for (int j = startMonth; j <= endMonth; j++) {
+                        if (j < 9) {
+                            date = i + "0" + (j + 1);
+                        } else {
+                            date = i + "" + (j + 1);
+                        }
+                        list.add(date);
+                    }
+                } else {
+                    if (i == startYear) {
+                        for (int j = startMonth; j < 12; j++) {
+                            if (j < 9) {
+                                date = i + "0" + (j + 1);
+                            } else {
+                                date = i + "" + (j + 1);
+                            }
+                            list.add(date);
+                        }
+                    } else if (i == endYear) {
+                        for (int j = 0; j <= endMonth; j++) {
+                            if (j < 9) {
+                                date = i + "0" + (j + 1);
+                            } else {
+                                date = i + "" + (j + 1);
+                            }
+                            list.add(date);
+                        }
+                    } else {
+                        for (int j = 0; j < 12; j++) {
+                            if (j < 9) {
+                                date = i + "0" + (j + 1);
+                            } else {
+                                date = i + "" + (j + 1);
+                            }
+                            list.add(date);
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {  
+            e.printStackTrace();  
+        }
+    	return list;
+    }
+    
+    
+    public static void main(String[] args) throws Exception {
+//      List<String> list = addDates("2022-02-01", "2022-03-31");
+//      list.forEach(i ->
+//              System.out.println(i)
+//      );
+    	DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
+//        String start_time = "2021-01-01";
+//		String end_time = "2022-01-30";
+//		List<Map<String,Object>> lsit = getDateOfWeek(dateFormat.parse(start_time), dateFormat.parse(end_time));  
+//		System.out.println(JSON.toJSONString(lsit));
+		
+		System.out.println(dateFormat.format(getPreDayOfNowZero(1)));
+		
+//		List<String> monthList = addMonths(dateFormat.parse(start_time), dateFormat.parse(end_time));
+//		System.out.println(JSON.toJSONString(monthList));
+//       
+//		
+//		System.out.println(start_time.indexOf("2022-01"));
+  }
 }

+ 20 - 10
mp-common/src/main/java/com/qs/mp/common/utils/WebhookService.java

@@ -10,14 +10,14 @@ import org.springframework.stereotype.Component;
 
 @Component
 public class WebhookService {
-    
+
     private static Logger logger = LoggerFactory.getLogger(WebhookService.class);
     //private String dingToken = "https://oapi.dingtalk.com/robot/send?access_token=a2f955b2c685e4449ac98fd4a41b9ba1238a6badb58aba4da9c6fc50714fc43d";
     //final static String alertUrl = "https://oapi.dingtalk.com/robot/send?access_token=79bd929c6cdec2150dbd2d5fdb5b4a499c9ad8137da511eab85bc7d381af9d7a";
     //final static String url = "https://oapi.dingtalk.com/robot/send?access_token=a2f955b2c685e4449ac98fd4a41b9ba1238a6badb58aba4da9c6fc50714fc43d";
-    final static String wxLogMonitorUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=ab1d9a09-2425-410e-b3ef-be8ee681146f";
+    final static String wxLogMonitorUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=4275487c-8706-4676-ae21-e74db900fcb6";
 
-    private static String  wxRobotUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=1433d0df-6def-4077-b466-e8f79f2fc60c";
+    private static String  wxRobotUrl = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=dd8d3a48-01f2-44b0-b4bb-406e2f466050";
     private static String env;
 
     @Value("${server.env}")
@@ -44,7 +44,7 @@ public class WebhookService {
         if (mobiles != null) {
             at.setAtMobiles(Arrays.asList(mobiles));
         }
-        
+
         request.setAt(at);
         try {
             OapiRobotSendResponse response = client.execute(request);
@@ -58,22 +58,32 @@ public class WebhookService {
 
     public static String sendWXRobot(String url , String msg) {
         //System.out.println("企业微信机器人告警发送:" + msg);
-        String jsonStr = "{\n" + 
-                "        \"msgtype\": \"text\",\n" + 
-                "        \"text\": {\n" + 
+        String jsonStr = "{\n" +
+                "        \"msgtype\": \"text\",\n" +
+                "        \"text\": {\n" +
                 "            \"content\": "+ JSON.toJSONString(msg)+"\n" +
-                "        }\n" + 
+                "        }\n" +
                 "   }";
         //System.out.println(jsonStr);
         return OkHttpUtil.post(url, jsonStr, null);
     }
-    
+
+    /**
+     * 系统监控
+     * @param msg
+     * @return
+     */
     public static String sendLogAlertMsg(String msg) {
 
         return sendWXRobot(wxLogMonitorUrl,msg);
     }
 
-    public static String sendMonitorData(String msg){
+    /**
+     * 业务通知
+     * @param msg
+     * @return
+     */
+    public static String sendBizData(String msg){
         if (ServerEnvEnum.PROD.getCode().equals(env)){
             return sendWXRobot(wxRobotUrl,msg);
         }

+ 2 - 1
mp-common/src/main/java/com/qs/mp/common/utils/http/HttpUtils.java

@@ -1,6 +1,7 @@
 package com.qs.mp.common.utils.http;
 
 import cn.hutool.http.ssl.TrustAnyHostnameVerifier;
+import com.qs.mp.common.utils.LogUtil;
 import java.io.BufferedReader;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
@@ -195,7 +196,7 @@ public class HttpUtils
         try
         {
             String urlNameString = url;
-            log.info("sendPost - {}", urlNameString, param);
+            LogUtil.info(log, "sendImagePost - url:{0},param:{1}", new Object[]{urlNameString, param});
             URL realUrl = new URL(urlNameString);
             URLConnection conn = realUrl.openConnection();
             conn.setRequestProperty("accept", "*/*");

+ 24 - 12
mp-framework/src/main/java/com/qs/mp/framework/config/SecurityConfig.java

@@ -109,8 +109,15 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                     "/api/v1/mp/sms/sendSmsCode",
                     "/api/v1/mp/user/wxauth/mobile",
                     "/api/v1/mp/channel/invite/register",
-                    "/api/v1/mp/wx/urlschema/generate",
-                    "/api/v1/mp/wx/code/generate").anonymous()
+                    "/common/download**",
+                    "/common/download/resource**",
+                    "/swagger-ui.html",
+                    "/swagger-resources/**",
+                    "/webjars/**",
+                    "/*/api-docs",
+                    "/druid/**",
+                    "/service/notify/**"
+                    ).anonymous()
                 .antMatchers(
                         HttpMethod.GET,
                         "/",
@@ -120,16 +127,21 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter
                         "/**/*.js",
                         "/profile/**"
                 ).permitAll()
-                .antMatchers("/common/download**").anonymous()
-                .antMatchers("/common/download/resource**").anonymous()
-                .antMatchers("/swagger-ui.html").anonymous()
-                .antMatchers("/swagger-resources/**").anonymous()
-                .antMatchers("/webjars/**").anonymous()
-                .antMatchers("/*/api-docs").anonymous()
-                .antMatchers("/druid/**").anonymous()
-                .antMatchers("/service/notify/**").anonymous()
-                .antMatchers("/api/v1/mp/user/mall/**").anonymous()
-
+                // 匹配放行 POST 请求,如果携带了 token 也不会进行拦截
+                .antMatchers(
+                        HttpMethod.POST,
+                    "/api/v1/mp/wx/urlschema/generate",
+                    "/api/v1/mp/wx/code/generate",
+                    "/api/v1/mp/user/ticket/queryLuckyNum",
+                    "/api/v1/mp/user/ticket/hitPrizeBarrage",
+                    "/api/v1/mp/user/mall/ticket/detail",
+                    "/api/v1/mp/user/mall/ticket/list",
+                    "/api/v1/mp/user/exchange/goods/list",
+                    "/api/v1/mp/user/exchange/goods/detail",
+                    "/api/v1/mp/user/exchange/banner/list",
+                    "/api/v1/mp/user/exchange/category/list",
+                    "/api/v1/mp/user/exchange/activity/list"
+                ).permitAll()
                 // 除上面外的所有请求全部需要鉴权认证
                 .anyRequest().authenticated()
                 .and()

+ 9 - 1
mp-framework/src/main/java/com/qs/mp/framework/security/filter/JwtAuthenticationTokenFilter.java

@@ -21,7 +21,7 @@ import org.springframework.web.filter.OncePerRequestFilter;
 
 /**
  * token过滤器 验证token有效性
- * 
+ *
  * @author ygp
  */
 @Component
@@ -47,7 +47,15 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
             UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
             authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
             SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+        } else {
+            hostHolder.setUser(null);
         }
         chain.doFilter(request, response);
     }
+
+    @Override
+    public void destroy() {
+        hostHolder.clear();
+        super.destroy();
+    }
 }

+ 2 - 2
mp-framework/src/main/java/com/qs/mp/framework/security/handle/AuthenticationEntryPointImpl.java

@@ -17,7 +17,7 @@ import org.springframework.stereotype.Component;
 
 /**
  * 认证失败处理类 返回未授权
- * 
+ *
  * @author ygp
  */
 @Component
@@ -31,7 +31,7 @@ public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, S
     {
         int code = HttpStatus.UNAUTHORIZED;
         String msg = StringUtils.format("请求访问:{},认证失败,无法访问系统资源", request.getRequestURI());
-        logger.warn("权限验证失败:"+e.getMessage(),e);
+        logger.warn("权限验证失败:"+e.getMessage());
         ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg)));
     }
 }

+ 8 - 3
mp-framework/src/main/java/com/qs/mp/framework/web/exception/GlobalExceptionHandler.java

@@ -1,5 +1,7 @@
 package com.qs.mp.framework.web.exception;
 
+import com.qs.mp.common.utils.LogUtil;
+import com.qs.mp.common.utils.http.HttpHelper;
 import javax.servlet.http.HttpServletRequest;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -17,7 +19,7 @@ import com.qs.mp.common.utils.StringUtils;
 
 /**
  * 全局异常处理器
- * 
+ *
  * @author ygp
  */
 @RestControllerAdvice
@@ -66,7 +68,10 @@ public class GlobalExceptionHandler
     public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)
     {
         String requestURI = request.getRequestURI();
-        log.error("请求地址'{}',发生未知异常.", requestURI, e);
+        if (!"用户不存在/密码错误".equals(e.getMessage()) && !"验证码已失效".equals(e.getMessage())) {
+            LogUtil.error(log, e, "请求地址:{0},请求参数:{1}发生未知异常.",
+                new Object[]{requestURI, HttpHelper.getBodyString(request)});
+        }
         return AjaxResult.error(e.getMessage());
     }
 
@@ -77,7 +82,7 @@ public class GlobalExceptionHandler
     public AjaxResult handleException(Exception e, HttpServletRequest request)
     {
         String requestURI = request.getRequestURI();
-        log.error("请求地址'{}',发生系统异常.", requestURI, e);
+        LogUtil.error(log, e, "请求地址'{0}',发生系统异常.", requestURI);
         return AjaxResult.error(e.getMessage());
     }
 

+ 2 - 2
mp-quartz/pom.xml

@@ -32,9 +32,9 @@
         <!-- 通用工具-->
         <dependency>
             <groupId>com.qs.mp</groupId>
-            <artifactId>mp-common</artifactId>
+            <artifactId>mp-service</artifactId>
         </dependency>
 
     </dependencies>
 
-</project>
+</project>

+ 58 - 0
mp-quartz/src/main/java/com/qs/mp/quartz/task/ChannelCommTask.java

@@ -0,0 +1,58 @@
+package com.qs.mp.quartz.task;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qs.mp.channel.domain.ChannelCommission;
+import com.qs.mp.channel.service.IChannelCommissionService;
+import com.qs.mp.common.utils.DateUtils;
+import com.qs.mp.common.utils.LogUtil;
+import com.qs.mp.common.utils.StringUtils;
+import java.util.Date;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * 渠道佣金按天汇总入账
+ *
+ * @author zhongcp
+ * @Date 2022/3/17
+ */
+@Component("channelCommTask")
+public class ChannelCommTask {
+
+  protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
+
+  @Autowired
+  private IChannelCommissionService channelCommissionService;
+
+  /**
+   * 渠道佣金汇总记账任务
+   */
+  public void sumComm(String executeDay) {
+    LogUtil.info(logger, "...渠道佣金汇总入账定时任务开始...");
+    Date bizDay;
+    if (StringUtils.isNotBlank(executeDay)) {
+      bizDay = DateUtils.parseStrToDate(executeDay, DateUtils.YYYYMMDD);
+    } else {
+      bizDay = DateUtils.addDays(DateUtils.getToday(), -1);
+    }
+
+    // 捞取前一天有分佣的渠道ID
+    List<ChannelCommission> channelList = channelCommissionService.getChannelList(
+        new QueryWrapper<ChannelCommission>()
+            .gt("t2.level", 0)
+            .ge("t1.created_time", bizDay)
+            .lt("t1.created_time", DateUtils.addDays(bizDay, 1)));
+    for (ChannelCommission channelCommission : channelList) {
+      try {
+        channelCommissionService.commEntry(channelCommission.getChannelId(), bizDay);
+      } catch (Exception e) {
+        LogUtil.error(logger, e, "渠道佣金汇总入账异常。channelId:{0}", channelCommission.getChannelId());
+      }
+    }
+
+    LogUtil.info(logger, "...渠道佣金汇总入账定时任务结束...");
+  }
+}

+ 53 - 0
mp-quartz/src/main/java/com/qs/mp/quartz/task/ChannelOrderTask.java

@@ -0,0 +1,53 @@
+package com.qs.mp.quartz.task;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.qs.mp.channel.domain.ChannelOrder;
+import com.qs.mp.channel.service.IChannelOrderService;
+import com.qs.mp.common.enums.ChannelOrderStatusEnum;
+import com.qs.mp.common.utils.DateUtils;
+import com.qs.mp.common.utils.LogUtil;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author zhongcp
+ * @Date 2022/3/17
+ */
+@Component("channelOrderTask")
+public class ChannelOrderTask {
+
+  protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
+
+  @Autowired
+  private IChannelOrderService channelOrderService;
+
+  private final int PAGE_SIZE = 500;
+
+  /**
+   * 订单取消到期任务
+   */
+  public void cancel() {
+    LogUtil.info(logger, "...渠道未支付订单定时取消任务开始...");
+    int total = PAGE_SIZE;
+    while (total == PAGE_SIZE) {
+      // 捞取30分钟前未支付订单
+      List<ChannelOrder> channelOrderList = channelOrderService.list(
+          new LambdaQueryWrapper<ChannelOrder>()
+              .eq(ChannelOrder::getStatus, ChannelOrderStatusEnum.NOT_PAY)
+              .lt(ChannelOrder::getCreatedTime, DateUtils.addMinutes(DateUtils.getNowDate(), -30))
+              .last("limit " + PAGE_SIZE));
+      total = channelOrderList.size();
+      for (ChannelOrder channelOrder : channelOrderList) {
+        try {
+          channelOrderService.cancelOrder(channelOrder.getChannelId(), channelOrder.getOrderId());
+        } catch (Exception e) {
+          LogUtil.error(logger, e, "定时取消未支付渠道订单异常。orderId:{0}", channelOrder.getOrderId());
+        }
+      }
+    }
+    LogUtil.info(logger, "...渠道未支付订单定时取消任务结束...");
+  }
+}

+ 167 - 0
mp-quartz/src/main/java/com/qs/mp/quartz/task/CosTask.java

@@ -0,0 +1,167 @@
+package com.qs.mp.quartz.task;
+
+import cn.hutool.core.img.Img;
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.exception.CosClientException;
+import com.qcloud.cos.exception.CosServiceException;
+import com.qcloud.cos.model.*;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.enums.PicHandlerTypeEnum;
+import com.qs.mp.common.filter.ThumbnailsImgFilter;
+import com.qs.mp.common.qcloud.QcloudFileUtils;
+import com.qs.mp.common.utils.LogUtil;
+import com.qs.mp.common.utils.StringUtils;
+import com.qs.mp.common.utils.UUIDUtils;
+import com.qs.mp.core.domain.LoginUser;
+import com.qs.mp.core.domain.UploadAttachment;
+import net.coobird.thumbnailator.Thumbnails;
+import net.coobird.thumbnailator.geometry.Positions;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * 腾讯 COS 操作任务
+ *
+ * @author Cup
+ * @date 2022/4/15
+ */
+@Component("cosTask")
+public class CosTask {
+
+    protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
+
+
+    /**
+     * 文件上传路径
+     */
+    @Value("${mp.profile}")
+    public String filePath;
+
+    /**
+     * 公开
+     */
+    @Value("${cloud.public-bucket-name}")
+    private String publicBucketName;
+
+
+    /**
+     * 腾讯COS图片压缩替换任务
+     */
+    public void compressPicture() throws IOException, InterruptedException {
+        LogUtil.info(logger, "...图片压缩替换任务开始...");
+
+        ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
+        // 设置bucket名称
+        listObjectsRequest.setBucketName(publicBucketName);
+        // prefix表示列出的object的key以prefix开始
+        listObjectsRequest.setPrefix("/");
+        // deliter表示分隔符, 设置为/表示列出当前目录下的object, 设置为空表示列出所有的object
+        listObjectsRequest.setDelimiter("/");
+        // 设置最大遍历出多少个对象, 一次listobject最大支持1000
+        listObjectsRequest.setMaxKeys(500);
+        ObjectListing objectListing = null;
+        do {
+            try {
+                COSClient cosClient = QcloudFileUtils.getCosClient();
+                objectListing = cosClient.listObjects(listObjectsRequest);
+            } catch (CosServiceException e) {
+                e.printStackTrace();
+                return;
+            } catch (CosClientException e) {
+                e.printStackTrace();
+                return;
+            }
+            // common prefix表示表示被delimiter截断的路径, 如delimter设置为/, common prefix则表示所有子目录的路径
+            List<String> commonPrefixs = objectListing.getCommonPrefixes();
+
+            // object summary表示所有列出的object列表
+            List<COSObjectSummary> cosObjectSummaries = objectListing.getObjectSummaries();
+
+            for (COSObjectSummary cosObjectSummary : cosObjectSummaries) {
+                // 文件的路径key
+                String key = cosObjectSummary.getKey();
+
+                if (key.length() < 2) {
+                    continue;
+                }
+
+                if ("_s".equals(key.substring(key.length() - 2))) {
+              //  if("EJU6PLW0GUARR4EWIHZA.jpg_s".equals(key)) {
+                    // 获取原图文件名
+                    String picName = key.substring(0, key.length() - 2);
+                    System.err.println("key = " + picName);
+                    try {
+                        uploadAndCommpressImg(picName);
+                    } catch (Exception e) {
+                        System.err.println(e);
+                    }
+                }
+            }
+            String nextMarker = objectListing.getNextMarker();
+            listObjectsRequest.setMarker(nextMarker);
+        } while (objectListing.isTruncated());
+
+        LogUtil.info(logger, "...图片压缩替换完成!!...");
+    }
+
+    private void uploadAndCommpressImg(String key) throws IOException, InterruptedException {
+        String path = filePath + "/thumb/" + key;
+        File downFile = new File(path);
+        GetObjectRequest getObjectRequest = new GetObjectRequest(publicBucketName, key);
+        COSClient cosClient = QcloudFileUtils.getCosClient();
+        ObjectMetadata downObjectMeta = cosClient.getObject(getObjectRequest, downFile);
+//        FileInputStream fileInputStream = new FileInputStream(path);
+        String mimeType = "image/jpg";
+//        QcloudFileUtils.putStream(fileInputStream, key, publicBucketName, mimeType);
+
+        // 压缩图片
+        BufferedImage bufferedImage = ImageIO.read(downFile);
+        Thumbnails.Builder<BufferedImage> builder = Thumbnails.of(bufferedImage);
+        int pWidth = bufferedImage.getWidth();
+        int pHeight = bufferedImage.getHeight();
+        builder.size(pWidth, pHeight);
+
+        String outFileDir = filePath + "/thumb";
+        File tempFile = new File(outFileDir);
+        if (!tempFile.exists()) {
+            tempFile.mkdirs();
+        }
+        String thumbName = key + "_s";
+        String outFilePath = filePath + "/thumb/" + thumbName + "." + mimeType.substring(mimeType.lastIndexOf("/") + 1);
+        builder.toFile(outFilePath);
+
+        // 压缩图片
+        if (pWidth > 500) {
+
+            float scale = 500f / pWidth;
+
+            Thumbnails.of(outFilePath).scale(scale).outputQuality(0.8f).toFile(outFilePath);
+        }else {
+            Thumbnails.of(outFilePath).scale(1f).outputQuality(0.8f).toFile(outFilePath);
+        }
+
+
+        File outFile = new File(outFilePath);
+        QcloudFileUtils.putFile(outFile, thumbName, publicBucketName, mimeType);
+
+        downFile.delete();
+        outFile.delete();
+
+
+    }
+
+
+}

+ 254 - 0
mp-quartz/src/main/java/com/qs/mp/quartz/task/DayStatTask.java

@@ -0,0 +1,254 @@
+package com.qs.mp.quartz.task;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qs.mp.admin.domain.TicketBox;
+import com.qs.mp.admin.service.ITicketBoxService;
+import com.qs.mp.channel.domain.Channel;
+import com.qs.mp.channel.domain.ChannelCommission;
+import com.qs.mp.channel.domain.ChannelCouponVerifyLog;
+import com.qs.mp.channel.domain.ChannelWithdraw;
+import com.qs.mp.channel.service.IChannelCommissionService;
+import com.qs.mp.channel.service.IChannelCouponVerifyLogService;
+import com.qs.mp.channel.service.IChannelService;
+import com.qs.mp.channel.service.IChannelWithdrawService;
+import com.qs.mp.common.enums.ChannelWithdrawStatusEnum;
+import com.qs.mp.common.enums.CoinLogTypeEnum;
+import com.qs.mp.common.enums.CouponDiscountTypeEnum;
+import com.qs.mp.common.enums.TicketBoxStatusEnum;
+import com.qs.mp.common.enums.TicketTypeEnum;
+import com.qs.mp.common.enums.UserTicketOrderStatusEnum;
+import com.qs.mp.common.utils.DateUtils;
+import com.qs.mp.common.utils.LogUtil;
+import com.qs.mp.common.utils.StringUtils;
+import com.qs.mp.common.utils.WebhookService;
+import com.qs.mp.system.domain.SysUser;
+import com.qs.mp.system.service.ISysUserService;
+import com.qs.mp.user.domain.UserCoinLog;
+import com.qs.mp.user.domain.UserExchangeOrder;
+import com.qs.mp.user.domain.UserTicketOrder;
+import com.qs.mp.user.service.IUserCoinLogService;
+import com.qs.mp.user.service.IUserExchangeOrderService;
+import com.qs.mp.user.service.IUserTicketOrderService;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ * 日统计任务
+ *
+ * @author zhongcp
+ * @Date 2022/3/17
+ */
+@Component("dayStatTask")
+public class DayStatTask {
+
+  protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
+
+  @Autowired
+  private ISysUserService sysUserService;
+
+  @Autowired
+  private IChannelService channelService;
+
+  @Autowired
+  private ITicketBoxService ticketBoxService;
+
+  @Autowired
+  private IUserTicketOrderService userTicketOrderService;
+
+  @Autowired
+  private IChannelCommissionService channelCommissionService;
+
+  @Autowired
+  private IChannelWithdrawService channelWithdrawService;
+
+  @Autowired
+  private IUserExchangeOrderService userExchangeOrderService;
+
+  @Autowired
+  private IUserCoinLogService userCoinLogService;
+
+  @Autowired
+  private IChannelCouponVerifyLogService channelCouponVerifyLogService;
+
+  @Value("${export.page-size}")
+  private int pageSize;
+
+  /**
+   * 日统计任务 2022.04.02 代理:xxx 门店:xxx 用户:xxx =============== 票组名字|线上(面值),销售:¥0.00 票组名字|线上(面值),销售:¥0.00
+   * 总销售额:¥0.00 累计分佣:¥0.00 累计提现:¥0.00 兑换订单:5689 派发盲豆:8880 兑换盲豆:6666
+   */
+  public void stat(String executeDay) {
+    LogUtil.info(logger, "...日统计定时任务开始...");
+    Date bizDay;
+    if (StringUtils.isNotBlank(executeDay)) {
+      bizDay = DateUtils.parseStrToDate(executeDay, DateUtils.YYYYMMDD);
+    } else {
+      bizDay = DateUtils.addDays(DateUtils.getToday(), -1);
+    }
+    StringBuilder sb = new StringBuilder();
+    sb.append(DateUtils.dateTime(bizDay)).append("\n");
+    int allChannelCnt = channelService.count(new LambdaQueryWrapper<Channel>().gt(Channel::getLevel, 0));
+    int channelCnt = channelService.count(new LambdaQueryWrapper<Channel>().gt(Channel::getLevel, 0)
+        .ge(Channel::getCreatedTime, bizDay)
+        .lt(Channel::getCreatedTime, DateUtils.addDays(bizDay, 1)));
+    sb.append("累计代理:").append(allChannelCnt).append(",当日新增:").append(channelCnt).append("\n");
+    int siteCnt = channelService.count(new LambdaQueryWrapper<Channel>().eq(Channel::getLevel, 0)
+        .ge(Channel::getCreatedTime, bizDay)
+        .lt(Channel::getCreatedTime, DateUtils.addDays(bizDay, 1)));
+    int allSiteCnt = channelService.count(new LambdaQueryWrapper<Channel>().eq(Channel::getLevel, 0));
+    sb.append("累计门店:").append(allSiteCnt).append(",当日新增:").append(siteCnt).append("\n");
+    int userCnt = sysUserService.count(new LambdaQueryWrapper<SysUser>()
+        .ge(SysUser::getCreateTime, bizDay)
+        .lt(SysUser::getCreateTime, DateUtils.addDays(bizDay, 1)));
+    int allUserCnt = sysUserService.count(new LambdaQueryWrapper<SysUser>());
+    sb.append("累计用户:").append(allUserCnt - allSiteCnt - allChannelCnt).append(",当日新增:").append(userCnt - siteCnt - channelCnt).append("\n");
+    sb.append("===================\n");
+
+    LambdaQueryWrapper<TicketBox> queryWrapper = new LambdaQueryWrapper<TicketBox>()
+        .nested(wrapper -> {
+          wrapper.eq(TicketBox::getType, TicketTypeEnum.ONLINE).eq(TicketBox::getStatus,
+              TicketBoxStatusEnum.PUT_ON).or().eq(TicketBox::getType, TicketTypeEnum.OFFLINE);
+        })
+        .notLike(TicketBox::getTitle, "测试票")
+        .eq(TicketBox::getIsDeleted, 0);
+
+    int totalSize = ticketBoxService.count(queryWrapper);
+    int totalPage = 1;
+    if (totalSize > pageSize) {
+      totalPage = totalSize % pageSize == 0 ? totalSize / pageSize : totalSize / pageSize + 1;
+    }
+    BigDecimal sumSaleAmt = BigDecimal.ZERO;
+    BigDecimal sumAllSaleAmt = BigDecimal.ZERO;
+    for (int i = 0; i < totalPage; i++) {
+      queryWrapper.orderByAsc(TicketBox::getBoxNo);
+      queryWrapper.last("limit " + (i * pageSize) + ", " + pageSize);
+      List<TicketBox> ticketBoxList = ticketBoxService.list(queryWrapper);
+      for (TicketBox ticketBox : ticketBoxList) {
+        Map<String, Object> orderMap = userTicketOrderService.getMap(
+            new QueryWrapper<UserTicketOrder>()
+                .select("IFNULL(sum(pay_amt) ,0) as orderAmt")
+                .lambda().eq(UserTicketOrder::getBoxId, ticketBox.getBoxId())
+                .eq(UserTicketOrder::getStatus, UserTicketOrderStatusEnum.FINISHED)
+                .ge(UserTicketOrder::getCreatedTime, bizDay)
+                .lt(UserTicketOrder::getCreatedTime, DateUtils.addDays(bizDay, 1)));
+        if (null != orderMap) {
+          BigDecimal orderAmt = new BigDecimal(
+              Integer.valueOf(String.valueOf(orderMap.get("orderAmt")))).divide(new BigDecimal(100),
+              2, RoundingMode.DOWN);
+          sumSaleAmt = sumSaleAmt.add(orderAmt);
+          BigDecimal allOrderAmt = new BigDecimal(ticketBox.getSalePrice() * ticketBox.getSaleQty()).divide(new BigDecimal(100),
+              2, RoundingMode.DOWN);
+          sumAllSaleAmt = sumAllSaleAmt.add(allOrderAmt);
+
+          sb.append(ticketBox.getTitle()).append("|").append(ticketBox.getType().getDesc())
+              .append("(").append(
+                  new BigDecimal(ticketBox.getSalePrice()).divide(new BigDecimal(100), 2,
+                      RoundingMode.DOWN)).append("元),累计销售额:")
+              .append(allOrderAmt).append("元,当日:")
+              .append(orderAmt).append("元\n");
+        }
+      }
+    }
+    sb.append("累计销售额:").append(sumAllSaleAmt).append("元,当日:").append(sumSaleAmt).append("元\n");
+
+    Map<String, Object> commMap = channelCommissionService.getMap(
+        new QueryWrapper<ChannelCommission>()
+            .select("IFNULL(sum(comm_amt) ,0) as commAmt")
+            .lambda().ge(ChannelCommission::getCreatedTime, bizDay)
+            .lt(ChannelCommission::getCreatedTime, DateUtils.addDays(bizDay, 1)));
+    Map<String, Object> allCommMap = channelCommissionService.getMap(
+        new QueryWrapper<ChannelCommission>()
+            .select("IFNULL(sum(comm_amt) ,0) as commAmt"));
+    if (null != commMap) {
+      sb.append("累计分佣:").append(
+          new BigDecimal(Integer.valueOf(String.valueOf(allCommMap.get("commAmt")))).divide(
+              new BigDecimal(100), 2, RoundingMode.DOWN))
+          .append("元,当日:").append(
+          new BigDecimal(Integer.valueOf(String.valueOf(commMap.get("commAmt")))).divide(
+              new BigDecimal(100), 2, RoundingMode.DOWN)).append("元\n");
+    }
+
+    Map<String, Object> couponMap = channelCouponVerifyLogService.getMap(
+        new QueryWrapper<ChannelCouponVerifyLog>()
+            .select("IFNULL(sum(discount) ,0) as discount")
+            .lambda().ge(ChannelCouponVerifyLog::getCreatedTime, bizDay)
+            .lt(ChannelCouponVerifyLog::getCreatedTime, DateUtils.addDays(bizDay, 1))
+            .eq(ChannelCouponVerifyLog::getDiscountType, CouponDiscountTypeEnum.MONEY_OFF));
+    Map<String, Object> allCouponMap = channelCouponVerifyLogService.getMap(
+        new QueryWrapper<ChannelCouponVerifyLog>()
+            .select("IFNULL(sum(discount) ,0) as discount")
+            .lambda().eq(ChannelCouponVerifyLog::getDiscountType, CouponDiscountTypeEnum.MONEY_OFF));
+    if (null != commMap) {
+      sb.append("累计核销:").append(
+              new BigDecimal(Integer.valueOf(String.valueOf(allCouponMap.get("discount")))).divide(
+                  new BigDecimal(100), 2, RoundingMode.DOWN))
+          .append("元,当日:").append(
+              new BigDecimal(Integer.valueOf(String.valueOf(couponMap.get("discount")))).divide(
+                  new BigDecimal(100), 2, RoundingMode.DOWN)).append("元\n");
+    }
+
+    Map<String, Object> withdrawMap = channelWithdrawService.getMap(
+        new QueryWrapper<ChannelWithdraw>()
+            .select("IFNULL(sum(money) ,0) as withdrawAmt")
+            .lambda().ge(ChannelWithdraw::getCreateTime, bizDay)
+            .lt(ChannelWithdraw::getCreateTime, DateUtils.addDays(bizDay, 1))
+            .eq(ChannelWithdraw::getStatus, ChannelWithdrawStatusEnum.FINISHED));
+    Map<String, Object> allWithdrawMap = channelWithdrawService.getMap(
+        new QueryWrapper<ChannelWithdraw>()
+            .select("IFNULL(sum(money) ,0) as withdrawAmt")
+            .lambda().eq(ChannelWithdraw::getStatus, ChannelWithdrawStatusEnum.FINISHED));
+    if (null != withdrawMap) {
+      sb.append("累计提现:").append(
+          new BigDecimal(Integer.valueOf(String.valueOf(allWithdrawMap.get("withdrawAmt")))).divide(
+              new BigDecimal(100), 2, RoundingMode.DOWN))
+          .append("元,当日:").append(
+          new BigDecimal(Integer.valueOf(String.valueOf(withdrawMap.get("withdrawAmt")))).divide(
+              new BigDecimal(100), 2, RoundingMode.DOWN)).append("元\n");
+    }
+
+    int exCnt = userExchangeOrderService.count(new LambdaQueryWrapper<UserExchangeOrder>()
+        .ge(UserExchangeOrder::getCreatedTime, bizDay)
+        .lt(UserExchangeOrder::getCreatedTime, DateUtils.addDays(bizDay, 1)));
+    int allExCnt = userExchangeOrderService.count(new LambdaQueryWrapper<UserExchangeOrder>());
+    sb.append("累计兑换订单:").append(allExCnt).append("个,当日:").append(exCnt).append("个\n");
+
+    Map<String, Object> deliverMap = userCoinLogService.getMap(new QueryWrapper<UserCoinLog>()
+        .select("IFNULL(sum(log_money) ,0) as deliverAmt")
+        .lambda().eq(UserCoinLog::getType, CoinLogTypeEnum.PRIZE)
+        .ge(UserCoinLog::getCreatedTime, bizDay)
+        .lt(UserCoinLog::getCreatedTime, DateUtils.addDays(bizDay, 1)));
+    Map<String, Object> allDeliverMap = userCoinLogService.getMap(new QueryWrapper<UserCoinLog>()
+        .select("IFNULL(sum(log_money) ,0) as deliverAmt")
+        .lambda().eq(UserCoinLog::getType, CoinLogTypeEnum.PRIZE));
+    if (null != deliverMap) {
+      sb.append("累计派发盲豆:").append(Integer.valueOf(String.valueOf(allDeliverMap.get("deliverAmt"))))
+          .append("颗,当日:").append(Integer.valueOf(String.valueOf(deliverMap.get("deliverAmt"))))
+          .append("颗\n");
+    }
+
+    Map<String, Object> exchangeMap = userCoinLogService.getMap(new QueryWrapper<UserCoinLog>()
+        .select("IFNULL(sum(log_money) ,0) as exchangeAmt")
+        .lambda().eq(UserCoinLog::getType, CoinLogTypeEnum.EXCHANGE)
+        .ge(UserCoinLog::getCreatedTime, bizDay)
+        .lt(UserCoinLog::getCreatedTime, DateUtils.addDays(bizDay, 1)));
+    Map<String, Object> allExchangeMap = userCoinLogService.getMap(new QueryWrapper<UserCoinLog>()
+        .select("IFNULL(sum(log_money) ,0) as exchangeAmt")
+        .lambda().eq(UserCoinLog::getType, CoinLogTypeEnum.EXCHANGE));
+    if (null != withdrawMap) {
+      sb.append("累计兑换盲豆:").append(0 - Integer.valueOf(String.valueOf(allExchangeMap.get("exchangeAmt"))))
+          .append("颗,当日:").append(0 - Integer.valueOf(String.valueOf(exchangeMap.get("exchangeAmt"))))
+          .append("颗\n");
+    }
+    WebhookService.sendBizData(sb.toString());
+    LogUtil.info(logger, "...日统计任务结束..." );
+  }
+}

+ 167 - 0
mp-quartz/src/main/java/com/qs/mp/quartz/task/TicketBoxTask.java

@@ -0,0 +1,167 @@
+package com.qs.mp.quartz.task;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qs.mp.admin.domain.Ticket;
+import com.qs.mp.admin.domain.TicketAwards;
+import com.qs.mp.admin.domain.TicketBox;
+import com.qs.mp.admin.service.ITicketAwardsService;
+import com.qs.mp.admin.service.ITicketBoxService;
+import com.qs.mp.admin.service.ITicketService;
+import com.qs.mp.common.annotation.Log;
+import com.qs.mp.common.core.domain.AjaxResult;
+import com.qs.mp.common.enums.TicketTypeEnum;
+import com.qs.mp.common.enums.UserTicketOrderStatusEnum;
+import com.qs.mp.common.utils.DateUtils;
+import com.qs.mp.common.utils.LogUtil;
+import com.qs.mp.common.utils.RSAUtil;
+import com.qs.mp.user.domain.UserTicketOrder;
+import com.qs.mp.user.service.IUserTicketOrderService;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.ArrayList;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+import java.util.stream.Collectors;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.util.Assert;
+
+/**
+ * 检查票组出奖率
+ * @author zhongcp
+ * @Date 2022/3/17
+ */
+@Component("ticketBoxTask")
+public class TicketBoxTask {
+
+  protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
+
+  @Autowired
+  private ITicketService ticketService;
+
+  @Autowired
+  private ITicketAwardsService ticketAwardsService;
+
+  @Autowired
+  private ITicketBoxService ticketBoxService;
+
+  @Value("${export.page-size}")
+  private int pageSize;
+
+  /**
+   * 检查票组中奖分布任务
+   */
+  public void checkPrize(String boxId) {
+    LogUtil.info(logger, "...票组奖品分布检测任务开始..." + boxId);
+
+    TicketBox ticketBox = ticketBoxService.getById(boxId);
+    List<TicketAwards> ticketAwardsList = ticketAwardsService.list(new LambdaQueryWrapper<TicketAwards>().eq(TicketAwards::getBoxId, boxId));
+    Map<String, TicketAwards> ticketAwardsMap = new HashMap<>();
+    for (TicketAwards ticketAward : ticketAwardsList) {
+      ticketAwardsMap.put(ticketAward.getName(), ticketAward);
+    }
+
+    List<Ticket> listAll = new ArrayList<Ticket>();
+    // 首先查询要导出的数据总数
+    LambdaQueryWrapper<Ticket> queryWrapper = new LambdaQueryWrapper<Ticket>();
+    queryWrapper.eq(Ticket::getBoxId, boxId);
+    int totalSize = ticketService.count(queryWrapper);
+    if (totalSize == 0) {
+      LogUtil.info(logger, "票组票数为0,boxId:{0}", boxId);
+    }
+
+    if(totalSize > pageSize) {
+      int totalPage = totalSize%pageSize == 0 ? totalSize/pageSize : totalSize/pageSize+1;
+      for (int i = 0; i < totalPage; i++) {
+        LambdaQueryWrapper<Ticket> pageQueryWrapper = new LambdaQueryWrapper<Ticket>();
+        pageQueryWrapper.select(Ticket::getSerialNo, Ticket::getDrawNum, Ticket::getCipherLuckyNum, Ticket::getPkgId);
+        pageQueryWrapper.eq(Ticket::getBoxId, boxId);
+        pageQueryWrapper.last("limit "+ (i*pageSize) +", " + pageSize);
+        List<Ticket> list = ticketService.list(pageQueryWrapper);
+        if(null != list && list.size() > 0 ) {
+          listAll.addAll(list);
+        }
+      }
+    }else {
+      listAll = ticketService.list(queryWrapper);
+    }
+
+    HashMap<String, HashMap<String, Integer>> pkgAwardsMap = new HashMap<>();
+    if(null != listAll && listAll.size() > 0 ) {
+//      listAll.sort(Comparator.comparing(Ticket::getSerialNo));
+      for (Ticket ticket : listAll) {
+        LogUtil.info(logger, "ticketid:{0}", ticket.getTicketId());
+        JSONArray jsonArray = JSONArray.parseArray(ticket.getDrawNum());
+        for (int i = 0; i < jsonArray.size(); i++) {
+          JSONObject jo = jsonArray.getJSONObject(i);
+          String luckyNum = RSAUtil.decrypt(ticket.getCipherLuckyNum());
+//          LogUtil.info(logger, "num:{0},luckyNum:{1}", new Object[]{jo.get("num"), luckyNum});
+          if (jo.get("num") == Integer.valueOf(luckyNum)) {
+            HashMap<String, Integer> awardsMap = pkgAwardsMap.get(ticket.getPkgId());
+            if (awardsMap == null) {
+              awardsMap = new HashMap<>();
+              pkgAwardsMap.put(ticket.getPkgId(), awardsMap);
+            }
+            Integer awardsNum = awardsMap.get(jo.getString("name"));
+            if (null == awardsNum) {
+              awardsNum = 0;
+            }
+            awardsNum += 1;
+            awardsMap.put(jo.getString("name"), awardsNum);
+          }
+        }
+      }
+    }
+    LogUtil.info(logger, "票包奖品分布:{0}", JSONObject.toJSONString(pkgAwardsMap));
+    // 奖级累计中奖数量
+    Map<String, Integer> totalAwardsMap = new HashMap<>();
+    for (String key : pkgAwardsMap.keySet()) {
+      HashMap<String, Integer> awardsMap = pkgAwardsMap.get(key);
+
+      int sumAwardsNum = 0;
+      for (String subKey : awardsMap.keySet()) {
+        sumAwardsNum += awardsMap.get(subKey);
+        Integer totalAwardsNum = totalAwardsMap.get(subKey);
+        if (totalAwardsNum == null) {
+          totalAwardsNum = 0;
+        }
+        totalAwardsNum += awardsMap.get(subKey);
+        totalAwardsMap.put(subKey, totalAwardsNum);
+      }
+      Assert.isTrue(sumAwardsNum == ticketBox.getPkgUnit(), "票包的中奖数和票包张数不匹配。总中奖数:" + sumAwardsNum + ",票包张数:" + ticketBox.getPkgUnit());
+      // 检查票包每个奖项的中奖率是否和整体票组中奖率一致
+      for (String subKey : awardsMap.keySet()) {
+        BigDecimal hitRate = new BigDecimal(awardsMap.get(subKey) * 100).divide(new BigDecimal(sumAwardsNum), 4, RoundingMode.DOWN);
+        // 误差率
+        BigDecimal misRate = ticketAwardsMap.get(subKey).getHitRate().subtract(hitRate).divide(hitRate, 2, RoundingMode.HALF_UP);
+        if (misRate.abs().compareTo(new BigDecimal(1)) > 0) {
+          LogUtil.error(logger, "中奖率与整个票组的中奖率误差大于1,pkgId:{0},票包奖项:{1},数量:{2},票包中奖率:{3},票组中奖率:{4}",
+              new Object[]{key, subKey, awardsMap.get(subKey), hitRate, ticketAwardsMap.get(subKey).getHitRate()});
+        }
+      }
+      Map<String, Integer> treeMap = new TreeMap<>((str1, str2) -> str1.compareTo(str2));
+      treeMap.putAll(awardsMap);
+      LogUtil.info(logger, "票包{0}奖级分布情况:{1}", new Object[]{key, treeMap});
+    }
+    // 排序
+    Map<String, Integer> resultMap = new TreeMap<>((str1, str2) -> str1.compareTo(str2));
+    resultMap.putAll(totalAwardsMap);
+    for (String key : resultMap.keySet()) {
+      int realNum = resultMap.get(key);
+      LogUtil.info(logger, "奖级{0}数量为{1}", new Object[]{key, realNum});
+      if(realNum != ticketAwardsMap.get(key).getQuantity()) {
+        LogUtil.error(logger, "实际中奖数(" + realNum + ")和票组中奖数(" + ticketAwardsMap.get(key).getQuantity() + ")不等" );
+      }
+    }
+    LogUtil.info(logger, "...票组奖品分布检测任务结束...");
+  }
+}

+ 77 - 0
mp-quartz/src/main/java/com/qs/mp/quartz/task/TicketOrderTask.java

@@ -0,0 +1,77 @@
+package com.qs.mp.quartz.task;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.qs.mp.common.enums.TicketTypeEnum;
+import com.qs.mp.common.enums.UserTicketOrderStatusEnum;
+import com.qs.mp.common.utils.DateUtils;
+import com.qs.mp.common.utils.LogUtil;
+import com.qs.mp.user.domain.UserTicketOrder;
+import com.qs.mp.user.service.IUserTicketOrderService;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * @author zhongcp
+ * @Date 2022/3/17
+ */
+@Component("ticketOrderTask")
+public class TicketOrderTask {
+
+  protected final Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
+
+  @Autowired
+  private IUserTicketOrderService userTicketOrderService;
+
+  private final int PAGE_SIZE = 500;
+
+  /**
+   * 订单取消到期任务
+   */
+  public void cancel() {
+    LogUtil.info(logger, "...盲票购买未支付订单定时取消任务开始...");
+    int total = PAGE_SIZE;
+    while (total == PAGE_SIZE) {
+      // 捞取30分钟前未支付在线盲票购买订单
+      List<UserTicketOrder> ticketOrderList = userTicketOrderService.list(
+          new QueryWrapper<UserTicketOrder>()
+              .select("distinct box_id")
+              .lambda().eq(UserTicketOrder::getResource, TicketTypeEnum.ONLINE)
+              .eq(UserTicketOrder::getStatus, UserTicketOrderStatusEnum.NOT_PAY)
+              .lt(UserTicketOrder::getCreatedTime,
+                  DateUtils.addMinutes(DateUtils.getNowDate(), -30))
+              .last("limit " + PAGE_SIZE));
+      total = ticketOrderList.size();
+      // 按票组分批次取消
+      for (UserTicketOrder ticketOrder : ticketOrderList) {
+        int boxTotal = 10;
+        while (boxTotal == 10) {
+          List<UserTicketOrder> orderList = userTicketOrderService.list(
+              new QueryWrapper<UserTicketOrder>()
+                  .select("order_id")
+                  .lambda().eq(UserTicketOrder::getBoxId, ticketOrder.getBoxId())
+                  .eq(UserTicketOrder::getStatus, UserTicketOrderStatusEnum.NOT_PAY)
+                  .lt(UserTicketOrder::getCreatedTime,
+                      DateUtils.addMinutes(DateUtils.getNowDate(), -30))
+                  .last("limit " + 10));
+          boxTotal = orderList.size();
+          try {
+            userTicketOrderService.batchCancelOrder(ticketOrder.getBoxId(),
+                orderList.stream().map(UserTicketOrder::getOrderId).collect(
+                    Collectors.toList()));
+          } catch (Exception e) {
+            LogUtil.error(logger, e, "定时取消未支付盲票购买订单异常。boxId:{0}, orderList:{1}",
+                ticketOrder.getBoxId(),
+                JSONObject.toJSONString(orderList));
+          }
+
+        }
+      }
+    }
+    LogUtil.info(logger, "...盲票购买未支付订单定时取消任务结束...");
+  }
+}

+ 4 - 4
mp-service/src/main/java/com/qs/mp/admin/domain/Coupon.java

@@ -30,8 +30,8 @@ public class Coupon implements Serializable {
   /**
    * 主键
    */
-  @TableId(value = "coupon_id", type = IdType.INPUT)
-  private String couponId;
+  @TableId(value = "coupon_id", type = IdType.AUTO)
+  private Long couponId;
 
   /**
    * 标题
@@ -94,7 +94,7 @@ public class Coupon implements Serializable {
   /**
    * 使用范围;0通用 1生成券时指定范围 2发放时动态指定范围
    *         0:进票门店  1、指定盲票  2:所有门票
-   *         
+   *
    */
   @TableField("use_area")
   @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
@@ -149,7 +149,7 @@ public class Coupon implements Serializable {
   @TableField("is_deleted")
   @TableLogic
   private Integer isDeleted;
-  
+
   /**
    * 创建时间
    */

+ 1 - 1
mp-service/src/main/java/com/qs/mp/admin/domain/CouponTicket.java

@@ -29,7 +29,7 @@ public class CouponTicket implements Serializable {
    * 优惠券ID
    */
   @TableField("coupon_id")
-  private String couponId;
+  private Long couponId;
 
   /**
    * 盲票组ID

+ 87 - 0
mp-service/src/main/java/com/qs/mp/admin/domain/ExchangeBanner.java

@@ -0,0 +1,87 @@
+package com.qs.mp.admin.domain;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.qs.mp.common.enums.BannerLocationEnum;
+import java.io.Serializable;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * @describe 兑换大厅推广区设置实体类
+ * @auther quanshu
+ * @create 2022-04-07 11:42:42
+ */
+@TableName("mp_exchange_banner")
+@Data
+public class ExchangeBanner implements Serializable {
+
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * 主键
+   */
+  @TableId(value = "banner_id", type = IdType.AUTO)
+  private Long bannerId;
+
+  /**
+   * banner名
+   */
+  @TableField("name")
+  private String name;
+
+  /**
+   * 图片
+   */
+  @TableField("pic_url")
+  private String picUrl;
+
+  /**
+   * 位置
+   */
+  @TableField("location")
+  @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
+  private BannerLocationEnum location;
+
+  /**
+   * 顺序
+   */
+  @TableField("sort")
+  private Integer sort;
+
+  /**
+   * 类型,链接link,标签tag
+   */
+  @TableField("type")
+  private String type;
+
+  /**
+   * 链接url
+   */
+  @TableField("link_url")
+  private String linkUrl;
+
+  /**
+   * 标签列表,逗号隔开
+   */
+  @TableField("goods_tags")
+  private String goodsTags;
+
+  /**
+   * 创建时间
+   */
+  @TableField("created_time")
+  private Date createdTime;
+
+  /**
+   * 更新时间
+   */
+  @TableField("updated_time")
+  private Date updatedTime;
+
+
+}

+ 17 - 4
mp-service/src/main/java/com/qs/mp/admin/domain/Goods.java

@@ -1,5 +1,6 @@
 package com.qs.mp.admin.domain;
 
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.annotation.JSONField;
 import com.alibaba.fastjson.serializer.SerializerFeature;
 import com.baomidou.mybatisplus.annotation.IdType;
@@ -9,8 +10,16 @@ import com.baomidou.mybatisplus.annotation.TableLogic;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.qs.mp.common.enums.GoodsStatusEnum;
 
+
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.*;
+
 import lombok.Data;
 
 /**
@@ -27,8 +36,8 @@ public class Goods implements Serializable {
   /**
    * 主键
    */
-  @TableId(value = "goods_id", type = IdType.INPUT)
-  private String goodsId;
+  @TableId(value = "goods_id", type = IdType.AUTO)
+  private Long goodsId;
 
   /**
    * 商品标题
@@ -102,6 +111,12 @@ public class Goods implements Serializable {
   @TableField("multi_sku")
   private Integer multiSku;
 
+  /**
+   * 规格描述
+   */
+  @TableField("sku_prop")
+  private String skuProp;
+
 
   /**
    * 上架状态;上架/下架
@@ -128,6 +143,4 @@ public class Goods implements Serializable {
    */
   @TableField("updated_time")
   private Date updatedTime;
-
-
 }

+ 13 - 1
mp-service/src/main/java/com/qs/mp/admin/domain/GoodsCategory.java

@@ -31,11 +31,17 @@ public class GoodsCategory implements Serializable {
   @TableField("name")
   private String name;
 
+  /**
+   * 图片
+   */
+  @TableField("pic_url")
+  private String picUrl;
+
   /**
    * 父级类目ID
    */
   @TableField("parent_id")
-  private String parentId;
+  private Long parentId;
 
   /**
    * 排序
@@ -43,6 +49,12 @@ public class GoodsCategory implements Serializable {
   @TableField("sort")
   private Integer sort;
 
+  /**
+   * 是否显示
+   */
+  @TableField("is_show")
+  private Integer isShow;
+
   /**
    * 创建时间
    */

+ 3 - 3
mp-service/src/main/java/com/qs/mp/admin/domain/GoodsSku.java

@@ -22,14 +22,14 @@ public class GoodsSku implements Serializable {
   /**
    * 主键
    */
-  @TableId(value = "sku_id", type = IdType.INPUT)
-  private String skuId;
+  @TableId(value = "sku_id", type = IdType.AUTO)
+  private Long skuId;
 
   /**
    * 商品ID
    */
   @TableField("goods_id")
-  private String goodsId;
+  private Long goodsId;
 
   /**
    * sku名称

+ 59 - 0
mp-service/src/main/java/com/qs/mp/admin/domain/GoodsTag.java

@@ -0,0 +1,59 @@
+package com.qs.mp.admin.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import java.io.Serializable;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * @describe 商品标签实体类
+ * @auther quanshu
+ * @create 2022-04-07 11:42:42
+ */
+@TableName("mp_goods_tag")
+@Data
+public class GoodsTag implements Serializable {
+
+  private static final long serialVersionUID = 1L;
+
+  /**
+   * 主键
+   */
+  @TableId(value = "tag_id", type = IdType.AUTO)
+  private Long tagId;
+
+  /**
+   * 标签名
+   */
+  @TableField("name")
+  private String name;
+
+  /**
+   * 顺序
+   */
+  @TableField("sort")
+  private Integer sort;
+
+  /**
+   * 是否在兑换大厅里显示
+   */
+  @TableField("is_show")
+  private Integer isShow;
+
+  /**
+   * 创建时间
+   */
+  @TableField("created_time")
+  private Date createdTime;
+
+  /**
+   * 更新时间
+   */
+  @TableField("updated_time")
+  private Date updatedTime;
+
+
+}

+ 11 - 23
mp-service/src/main/java/com/qs/mp/user/domain/UserCouponVerifyLog.java → mp-service/src/main/java/com/qs/mp/admin/domain/GoodsTagRel.java

@@ -1,4 +1,4 @@
-package com.qs.mp.user.domain;
+package com.qs.mp.admin.domain;
 
 import com.baomidou.mybatisplus.annotation.IdType;
 import com.baomidou.mybatisplus.annotation.TableField;
@@ -9,13 +9,13 @@ import java.util.Date;
 import lombok.Data;
 
 /**
- * @describe 优惠券核销记录实体类
+ * @describe 商品和标签的关系实体类
  * @auther quanshu
- * @create 2022-03-07 20:45:43
+ * @create 2022-04-07 11:42:42
  */
-@TableName("mp_user_coupon_verify_log")
+@TableName("mp_goods_tag_rel")
 @Data
-public class UserCouponVerifyLog implements Serializable {
+public class GoodsTagRel implements Serializable {
 
   private static final long serialVersionUID = 1L;
 
@@ -26,28 +26,16 @@ public class UserCouponVerifyLog implements Serializable {
   private Long id;
 
   /**
-   * 用户优惠券ID
+   * 商品ID
    */
-  @TableField("user_coupon_id")
-  private Long userCouponId;
+  @TableField("goods_id")
+  private Long goodsId;
 
   /**
-   * 优惠券ID
+   * 标签ID
    */
-  @TableField("coupon_id")
-  private String couponId;
-
-  /**
-   * 核销时间
-   */
-  @TableField("verify_time")
-  private Date verifyTime;
-
-  /**
-   * 核销用户
-   */
-  @TableField("verify_user")
-  private String verifyUser;
+  @TableField("tag_id")
+  private Long tagId;
 
   /**
    * 创建时间

+ 4 - 4
mp-service/src/main/java/com/qs/mp/admin/domain/Ticket.java

@@ -80,26 +80,26 @@ public class Ticket implements Serializable {
   /**
    * 是否实体纸质票(0否1是)
    */
-  @TableField("IS_PHYSICAL")
+  @TableField("is_physical")
   private Integer isPhysical;
 
   /**
    * 盲票状态;1未付款、2已激活、3已兑奖、4付款中
    */
-  @TableField("STATUS")
+  @TableField("status")
   @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
   private TicketStatusEnum status;
 
   /**
    * 创建时间
    */
-  @TableField("CREATED_TIME")
+  @TableField("created_time")
   private Date createdTime;
 
   /**
    * 更新时间
    */
-  @TableField("UPDATED_TIME")
+  @TableField("updated_time")
   @Version
   private Date updatedTime;
 

+ 28 - 0
mp-service/src/main/java/com/qs/mp/admin/domain/param/ChannelOrderPkgParam.java

@@ -0,0 +1,28 @@
+package com.qs.mp.admin.domain.param;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import lombok.Data;
+
+/**
+ * @describe 道发货订单可选择的票包列表筛选参数
+ * @auther quanshu
+ * @create 2022-03-022 20:43:44
+ */
+@ApiModel(value = "渠道发货订单可选择的票包列表筛选参数")
+@Data
+public class ChannelOrderPkgParam {
+
+	@ApiModelProperty(value = "订单编号", required = false)
+	private String orderId;
+
+
+	@ApiModelProperty(value = "盲票组ID", required = false)
+	private String boxId;
+	
+	
+	@ApiModelProperty(value = "盲票包编号", required = false)
+	private String pkgNo;
+
+}

+ 46 - 0
mp-service/src/main/java/com/qs/mp/admin/domain/param/ChannelOrderQueryParam.java

@@ -0,0 +1,46 @@
+package com.qs.mp.admin.domain.param;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.Date;
+
+import lombok.Data;
+
+/**
+ * @describe 经销商订单列表查询参数
+ * @auther quanshu
+ * @create 2022-03-07 20:43:44
+ */
+@ApiModel(value = "经销商订单列表查询参数")
+@Data
+public class ChannelOrderQueryParam {
+
+
+
+	@ApiModelProperty(value = "商品名称", required = false)
+	private String title;
+
+	@ApiModelProperty(value = "订单编号", required = false)
+	private String orderId;
+	
+	@ApiModelProperty(value = "经销商ID", required = false)
+	private Long channelId;
+
+	@ApiModelProperty(value = "订单状态", required = false)
+	private Integer status;
+	
+	/**
+	 * 下单区间-开始时间
+	 */
+	@ApiModelProperty(value = "开始时间", required = false)
+	private Date startTime;
+
+	/**
+	 * 下单区间-截止时间
+	 */
+	@ApiModelProperty(value = "截止时间", required = false)
+	private Date endTime;
+
+
+}

+ 49 - 0
mp-service/src/main/java/com/qs/mp/admin/domain/param/ChannelOrderShipParam.java

@@ -0,0 +1,49 @@
+package com.qs.mp.admin.domain.param;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import javax.validation.constraints.NotNull;
+
+import com.alibaba.fastjson.annotation.JSONField;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.qs.mp.admin.domain.TicketPackage;
+import com.qs.mp.common.enums.DeliverOrderStatusEnum;
+import lombok.Data;
+
+/**
+ * @describe 用户提货订单发货
+ * @auther quanshu
+ * @create 2022-03-07 20:43:44
+ */
+@ApiModel(value = "用户提货订单发货参数")
+@Data
+public class ChannelOrderShipParam {
+
+	@ApiModelProperty(value = "订单编号", required = false)
+	private String orderId;
+
+	/**
+	 * 物流公司ID
+	 */
+	@NotNull(message = "快递公司不能为空")
+	@ApiModelProperty(value = "物流公司", required = false)
+	private Long deliveryId;
+
+	/**
+	 * 物流单号ID
+	 */
+	@NotNull(message = "物流单号不能为空")
+	@ApiModelProperty(value = "物流单号", required = false)
+	private String deliveryFlowId;
+	
+	
+	@NotNull(message = "票包列表不能为空")
+	@ApiModelProperty(value = "票包ID列表", required = false)
+	private List<String> pkgIds;
+}

+ 0 - 11
mp-service/src/main/java/com/qs/mp/admin/domain/param/CouponParam.java

@@ -1,18 +1,13 @@
 package com.qs.mp.admin.domain.param;
 
-import com.alibaba.fastjson.annotation.JSONField;
-import com.alibaba.fastjson.serializer.SerializerFeature;
 import com.qs.mp.common.enums.CouponDiscountTypeEnum;
 import com.qs.mp.common.enums.CouponDistributeTypeEnum;
 import com.qs.mp.common.enums.CouponStatusEnum;
 import com.qs.mp.common.enums.CouponTypeEnum;
 import com.qs.mp.common.enums.CouponUseAreaEnum;
-
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
-
 import javax.validation.constraints.NotNull;
-
 import lombok.Data;
 
 /**
@@ -41,7 +36,6 @@ public class CouponParam {
    * 类型;1用户盲票购买优惠券、2用户门店消费优惠券、3经销商盲票采购优惠券
    */
   @ApiModelProperty(value = "代金券类型", required = false)
-  @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
   private CouponTypeEnum type;
 
   /**
@@ -60,7 +54,6 @@ public class CouponParam {
    * 优惠类型;1代金券(默认)、2折扣券、3兑换券
    */
   @ApiModelProperty(value = "优惠类型;1代金券、2折扣券、3兑换券", required = false)
-  @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
   private CouponDiscountTypeEnum discountType;
 
   /**
@@ -80,7 +73,6 @@ public class CouponParam {
    * 渠道代金券,渠道承担比例
    */
   @ApiModelProperty(value = "渠道代金券,渠道承担比例", required = true)
-  @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
   private Integer channelSharedRate;
 
 
@@ -88,21 +80,18 @@ public class CouponParam {
    * 状态;off下架 on正常
    */
   @ApiModelProperty(value = "状态", required = false)
-  @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
   private CouponStatusEnum status;
 
   /**
    * 使用范围;0通用 1生成券时指定范围 2发放时动态指定范围
    */
   @ApiModelProperty(value = "使用范围", required = true)
-  @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
   private CouponUseAreaEnum useArea;
 
   /**
    * 发放方式;1系统发放(默认) 2用户主动领取
    */
   @ApiModelProperty(value = "发放方式", required = false)
-  @JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
   private CouponDistributeTypeEnum distributeType;
 
   /**

+ 7 - 4
mp-service/src/main/java/com/qs/mp/admin/domain/param/GoodsParam.java

@@ -24,7 +24,7 @@ import lombok.Data;
 public class GoodsParam {
 
 	@ApiModelProperty(value = "商品ID", required = false)
-	private String goodsId;
+	private Long goodsId;
 
 	@NotNull(message = "商品名称不能为空")
 	@ApiModelProperty(value = "商品名称", required = true)
@@ -64,7 +64,7 @@ public class GoodsParam {
 	 */
 	@ApiModelProperty(value = "商品价值", required = false)
 	private Integer value;
-	
+
 
 	/**
 	 * 商品成本
@@ -83,7 +83,7 @@ public class GoodsParam {
 	 */
 	@ApiModelProperty(value = "已兑换量", required = false)
 	private Integer exchangedQty;
-	
+
 	  /**
 	   * 兑换大厅是否展示,0不展示,1展示
 	   */
@@ -105,8 +105,11 @@ public class GoodsParam {
 	@JSONField(serialzeFeatures = SerializerFeature.WriteEnumUsingToString)
 	private GoodsStatusEnum status;
 
-	
+
 	@ApiModelProperty(value = "商品多SKU列表", required = false)
 	private List<GoodsSku> skuList;
 
+	@ApiModelProperty(value = "商品标签ID列表", required = false)
+	private List<Long> tagIds;
+
 }

+ 13 - 1
mp-service/src/main/java/com/qs/mp/admin/domain/param/GoodsQueryParam.java

@@ -21,7 +21,13 @@ import lombok.Data;
 public class GoodsQueryParam {
 
 	@ApiModelProperty(value = "商品ID", required = false)
-	private String goodsId;
+	private Long goodsId;
+
+	@ApiModelProperty(value = "分类ID", required = false)
+	private Long categoryId;
+
+	@ApiModelProperty(value = "标签ID", required = false)
+	private Long tagId;
 
 	@NotNull(message = "商品名称不能为空")
 	@ApiModelProperty(value = "商品名称", required = true)
@@ -51,6 +57,12 @@ public class GoodsQueryParam {
 	@ApiModelProperty(value = "最高价格", required = false)
 	private Integer maxValue;
 
+	/**
+	 * 兑换大厅是否展示,0不展示,1展示
+	 */
+	@ApiModelProperty(value = "兑换大厅是否展示", required = false)
+	private Integer exchangeShow;
+
 	/**
 	 * 上架状态;上架/下架
 	 */

+ 24 - 0
mp-service/src/main/java/com/qs/mp/admin/domain/param/IndexQueryParam.java

@@ -0,0 +1,24 @@
+package com.qs.mp.admin.domain.param;
+
+import java.util.Date;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+@ApiModel(value= "首页统计参数")
+@Data
+public class IndexQueryParam {
+
+	@ApiModelProperty(value = "统计最近几天",required=false)
+	private Integer days;
+
+	@ApiModelProperty(value = "自定义开始时间",required=false)
+	private Date startTime;
+
+	@ApiModelProperty(value = "自定义截止时间",required=false)
+	private Date endTime;
+
+	@ApiModelProperty(value = "统计粒度",required=false)
+	private String level;
+}

+ 2 - 1
mp-service/src/main/java/com/qs/mp/admin/domain/param/TicketBoxCreateParam.java

@@ -3,6 +3,7 @@ package com.qs.mp.admin.domain.param;
 import com.qs.mp.common.enums.TicketTypeEnum;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
+import java.math.BigDecimal;
 import java.util.List;
 import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
@@ -44,7 +45,7 @@ public class TicketBoxCreateParam {
 
 	@NotNull(message = "分佣基数不能为空")
 	@ApiModelProperty(value = "分佣基数",required=true)
-	private Integer saleCommRate;
+	private BigDecimal saleCommRate;
 
 	@NotEmpty(message = "奖级列表不能为空")
 	@ApiModelProperty(value = "奖级列表",required=true)

+ 3 - 0
mp-service/src/main/java/com/qs/mp/admin/domain/param/TicketParam.java

@@ -16,6 +16,9 @@ public class TicketParam {
 	@ApiModelProperty(value = "盲票ID",required=false)
 	private String ticketId;
 
+	@ApiModelProperty(value = "盲票购买订单ID",required=false)
+	private String orderId;
+
 	@ApiModelProperty(value = "奖项ID",required=false)
 	private String awardsId;
 

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.