chenbiao преди 3 години
родител
ревизия
fe261a8246
променени са 100 файла, в които са добавени 4526 реда и са изтрити 71 реда
  1. 1 1
      netflix-common/src/main/java/com/cyksj/common/constant/WeChatTemplateConst.java
  2. 53 0
      netflix-common/src/main/java/com/cyksj/common/exception/AesException.java
  3. 32 0
      netflix-common/src/main/java/com/cyksj/common/util/ListsUtil.java
  4. 34 0
      netflix-common/src/main/java/com/cyksj/common/util/SmsUtil.java
  5. 26 0
      netflix-common/src/main/java/com/cyksj/common/util/corp/ByteGroup.java
  6. 65 0
      netflix-common/src/main/java/com/cyksj/common/util/corp/PKCS7Encoder.java
  7. 64 0
      netflix-common/src/main/java/com/cyksj/common/util/corp/SHA1.java
  8. 218 0
      netflix-common/src/main/java/com/cyksj/common/util/corp/WxCryptUtil.java
  9. 41 0
      netflix-common/src/main/java/com/cyksj/dto/CorpJsSdkTicket.java
  10. 26 0
      netflix-common/src/main/java/com/cyksj/dto/CorpOauth2UserInfo.java
  11. 6 0
      netflix-dao/src/main/java/com/cyksj/mapper/AccountMapper.java
  12. 11 0
      netflix-dao/src/main/java/com/cyksj/mapper/AddressMapper.java
  13. 3 0
      netflix-dao/src/main/java/com/cyksj/mapper/OrderDonMapper.java
  14. 11 0
      netflix-dao/src/main/java/com/cyksj/mapper/OrderDonTransportMapper.java
  15. 11 0
      netflix-dao/src/main/java/com/cyksj/mapper/OrderDonWaybillMapper.java
  16. 11 0
      netflix-dao/src/main/java/com/cyksj/mapper/SysConfigMapper.java
  17. 12 0
      netflix-dao/src/main/java/com/cyksj/mapper/corp/CorpFollowMapper.java
  18. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/corp/CorpTagGroupMapper.java
  19. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/corp/CorpTagMapper.java
  20. 11 0
      netflix-dao/src/main/java/com/cyksj/mapper/corp/CorpUserFollowRelationMapper.java
  21. 12 0
      netflix-dao/src/main/java/com/cyksj/mapper/corp/CorpUserMapper.java
  22. 12 0
      netflix-dao/src/main/java/com/cyksj/mapper/corp/CorpUserTagMapper.java
  23. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/statistics/AppleOneDataMapper.java
  24. 13 0
      netflix-dao/src/main/java/com/cyksj/mapper/manage/statistics/StreamingAccountDataMapper.java
  25. 5 0
      netflix-dao/src/main/java/com/cyksj/model/dto/AuthRedirect.java
  26. 33 0
      netflix-dao/src/main/java/com/cyksj/model/dto/WxCorpEncryptDto.java
  27. 71 0
      netflix-dao/src/main/java/com/cyksj/model/entity/AbstractBackData.java
  28. 4 3
      netflix-dao/src/main/java/com/cyksj/model/entity/Account.java
  29. 56 0
      netflix-dao/src/main/java/com/cyksj/model/entity/Address.java
  30. 19 0
      netflix-dao/src/main/java/com/cyksj/model/entity/AppleOneData.java
  31. 66 0
      netflix-dao/src/main/java/com/cyksj/model/entity/CorpFollow.java
  32. 33 0
      netflix-dao/src/main/java/com/cyksj/model/entity/CorpTag.java
  33. 33 0
      netflix-dao/src/main/java/com/cyksj/model/entity/CorpTagGroup.java
  34. 50 0
      netflix-dao/src/main/java/com/cyksj/model/entity/CorpUser.java
  35. 99 0
      netflix-dao/src/main/java/com/cyksj/model/entity/CorpUserFollowRelation.java
  36. 56 0
      netflix-dao/src/main/java/com/cyksj/model/entity/CorpUserTag.java
  37. 20 0
      netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDon.java
  38. 8 0
      netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDonSku.java
  39. 4 0
      netflix-dao/src/main/java/com/cyksj/model/entity/GroupsRelation.java
  40. 57 6
      netflix-dao/src/main/java/com/cyksj/model/entity/GroupsTrips.java
  41. 31 0
      netflix-dao/src/main/java/com/cyksj/model/entity/HomeGroup.java
  42. 4 0
      netflix-dao/src/main/java/com/cyksj/model/entity/OrderDon.java
  43. 47 0
      netflix-dao/src/main/java/com/cyksj/model/entity/OrderDonTransport.java
  44. 92 0
      netflix-dao/src/main/java/com/cyksj/model/entity/OrderDonWaybill.java
  45. 0 15
      netflix-dao/src/main/java/com/cyksj/model/entity/Platform.java
  46. 19 0
      netflix-dao/src/main/java/com/cyksj/model/entity/StreamingAccountData.java
  47. 18 0
      netflix-dao/src/main/java/com/cyksj/model/entity/SysConfig.java
  48. 19 0
      netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqAccountIncrExpiryTime.java
  49. 18 4
      netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqGoodsSkuInsert.java
  50. 4 0
      netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqGoodsSpecSingle.java
  51. 27 12
      netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqGoodsSpuInsert.java
  52. 17 0
      netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqRenewal.java
  53. 37 0
      netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqSetLogisticsPost.java
  54. 10 2
      netflix-dao/src/main/java/com/cyksj/model/manage/views/AccountView.java
  55. 23 0
      netflix-dao/src/main/java/com/cyksj/model/manage/views/GoodsDonViewer.java
  56. 18 5
      netflix-dao/src/main/java/com/cyksj/model/manage/views/GroupsRelationView.java
  57. 3 3
      netflix-dao/src/main/java/com/cyksj/model/manage/views/HomeGroupView.java
  58. 43 0
      netflix-dao/src/main/java/com/cyksj/model/manage/views/HomeUserView.java
  59. 34 5
      netflix-dao/src/main/java/com/cyksj/model/manage/views/OrderDonView.java
  60. 1 1
      netflix-dao/src/main/java/com/cyksj/model/manage/views/UserView.java
  61. 10 0
      netflix-dao/src/main/java/com/cyksj/model/request/OrderPayRequest.java
  62. 258 0
      netflix-dao/src/main/java/com/cyksj/model/request/corp/CorpXmlMessage.java
  63. 55 0
      netflix-dao/src/main/java/com/cyksj/model/request/corp/CorpXmlOutMessage.java
  64. 89 0
      netflix-dao/src/main/java/com/cyksj/model/response/Callback.java
  65. 23 0
      netflix-dao/src/main/java/com/cyksj/model/response/CorpExternalContactInfo.java
  66. 66 0
      netflix-dao/src/main/java/com/cyksj/model/response/CorpUserExternalTagGroupList.java
  67. 69 0
      netflix-dao/src/main/java/com/cyksj/model/response/CorpUserInfo.java
  68. 122 0
      netflix-dao/src/main/java/com/cyksj/model/response/ExternalContact.java
  69. 80 0
      netflix-dao/src/main/java/com/cyksj/model/response/FollowedUser.java
  70. 26 0
      netflix-dao/src/main/java/com/cyksj/model/response/UserExternalContactList.java
  71. 25 0
      netflix-dao/src/main/java/com/cyksj/model/response/UserWithExternalPermission.java
  72. 61 0
      netflix-dao/src/main/java/com/cyksj/model/views/BackgroundDataView.java
  73. 9 3
      netflix-dao/src/main/java/com/cyksj/model/views/GroupsView.java
  74. 25 4
      netflix-dao/src/main/java/com/cyksj/model/views/RenewalView.java
  75. 15 0
      netflix-dao/src/main/resources/mapper/AccountMapper.xml
  76. 19 0
      netflix-dao/src/main/resources/mapper/OrderDonMapper.xml
  77. 39 0
      netflix-service/src/main/java/com/cyksj/config/corp/BaseWxCorpConfig.java
  78. 32 0
      netflix-service/src/main/java/com/cyksj/config/corp/WxCorpFactory.java
  79. 22 0
      netflix-service/src/main/java/com/cyksj/config/corp/YHLXWxCorpConfig.java
  80. 27 0
      netflix-service/src/main/java/com/cyksj/redis/RedisService.java
  81. 28 0
      netflix-service/src/main/java/com/cyksj/service/corp/CorpService.java
  82. 77 0
      netflix-service/src/main/java/com/cyksj/service/corp/WxCorpOps.java
  83. 245 0
      netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpEventActionServiceImpl.java
  84. 272 0
      netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpServiceImpl.java
  85. 255 0
      netflix-service/src/main/java/com/cyksj/service/corp/impl/WxCorpOpsImpl.java
  86. 26 0
      netflix-service/src/main/java/com/cyksj/service/corp/msg/CorpEventActionService.java
  87. 25 0
      netflix-service/src/main/java/com/cyksj/service/corp/msg/CorpMessageHandler.java
  88. 26 0
      netflix-service/src/main/java/com/cyksj/service/corp/msg/CorpMessageInterceptor.java
  89. 20 0
      netflix-service/src/main/java/com/cyksj/service/corp/msg/CorpMessageMatcher.java
  90. 105 0
      netflix-service/src/main/java/com/cyksj/service/corp/msg/CorpMessageRouter.java
  91. 265 0
      netflix-service/src/main/java/com/cyksj/service/corp/msg/CorpMessageRouterRule.java
  92. 5 5
      netflix-service/src/main/java/com/cyksj/service/mange/CmsAccountService.java
  93. 6 0
      netflix-service/src/main/java/com/cyksj/service/mange/CmsGroupService.java
  94. 6 0
      netflix-service/src/main/java/com/cyksj/service/mange/CmsOrderDonService.java
  95. 9 0
      netflix-service/src/main/java/com/cyksj/service/mange/account/CmsAccountServiceImpl.java
  96. 87 0
      netflix-service/src/main/java/com/cyksj/service/mange/group/CmsGroupServiceImpl.java
  97. 38 0
      netflix-service/src/main/java/com/cyksj/service/mange/impl/CmsOrderDonServiceImpl.java
  98. 14 0
      netflix-service/src/main/java/com/cyksj/service/mange/statistics/StatisticsDataService.java
  99. 145 0
      netflix-service/src/main/java/com/cyksj/service/mange/statistics/impl/StatisticsDataServiceImpl.java
  100. 9 2
      netflix-service/src/main/java/com/cyksj/service/order/OrderDonService.java

+ 1 - 1
netflix-common/src/main/java/com/cyksj/common/constant/WeChatTemplateConst.java

@@ -6,5 +6,5 @@ package com.cyksj.common.constant;
  */
 public interface WeChatTemplateConst {
 
-    String EXPIRY_TEMPLATE = "g2_1-GzOU5RXj2IC9-ttmpSxd1FcDS_3fOe2w0MiH6Y";
+    String EXPIRY_TEMPLATE = "pNGASpViLNO9QsVm6nkg7P6XwwzULgdBCgytWlgsrYo";
 }

+ 53 - 0
netflix-common/src/main/java/com/cyksj/common/exception/AesException.java

@@ -0,0 +1,53 @@
+package com.cyksj.common.exception;
+
+/**
+ * @author chan
+ * @date 2022/3/15 下午2:03
+ */
+public class AesException extends Exception {
+
+    public final static int OK = 0;
+    public final static int ValidateSignatureError = -40001;
+    public final static int ParseXmlError = -40002;
+    public final static int ComputeSignatureError = -40003;
+    public final static int IllegalAesKey = -40004;
+    public final static int ValidateCorpidError = -40005;
+    public final static int EncryptAESError = -40006;
+    public final static int DecryptAESError = -40007;
+    public final static int IllegalBuffer = -40008;
+
+    private int code;
+
+    private static String getMessage(int code) {
+        switch (code) {
+            case ValidateSignatureError:
+                return "签名验证错误";
+            case ParseXmlError:
+                return "xml解析失败";
+            case ComputeSignatureError:
+                return "sha加密生成签名失败";
+            case IllegalAesKey:
+                return "SymmetricKey非法";
+            case ValidateCorpidError:
+                return "corpid校验失败";
+            case EncryptAESError:
+                return "aes加密失败";
+            case DecryptAESError:
+                return "aes解密失败";
+            case IllegalBuffer:
+                return "解密后得到的buffer非法";
+            default:
+                return null; // cannot be
+        }
+    }
+
+    public int getCode() {
+        return code;
+    }
+
+    public AesException(int code) {
+        super(getMessage(code));
+        this.code = code;
+    }
+
+}

+ 32 - 0
netflix-common/src/main/java/com/cyksj/common/util/ListsUtil.java

@@ -0,0 +1,32 @@
+package com.cyksj.common.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: ListUtil
+ *创建者: JavaZou
+ *创建时间:2022/10/14 11:52
+ */
+public class ListsUtil {
+
+	public static <T> List<List<T>> averageAssign(List<T> source, int n) {
+		List<List<T>> result = new ArrayList<List<T>>();
+		int remainder = source.size() % n;  //(先计算出余数)
+		int number = source.size() / n;  //然后是商
+		int offset = 0;//偏移量
+		for (int i = 0; i < n; i++) {
+			List<T> value = null;
+			if (remainder > 0) {
+				value = source.subList(i * number + offset, (i + 1) * number + offset + 1);
+				remainder--;
+				offset++;
+			} else {
+				value = source.subList(i * number + offset, (i + 1) * number + offset);
+			}
+			result.add(value);
+		}
+		return result;
+	}
+}

+ 34 - 0
netflix-common/src/main/java/com/cyksj/common/util/SmsUtil.java

@@ -0,0 +1,34 @@
+package com.cyksj.common.util;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import cn.hutool.http.HttpUtil;
+import cn.hutool.http.Method;
+import cn.hutool.json.JSONObject;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * @author chan
+ * @date 2022/10/13 11:29 AM
+ */
+public class SmsUtil {
+
+    private static final String URL =  "http://sms-api.luosimao.com/v1/send.json";
+
+    private static final String PASSWORD = "key-1bf2a2f243e18be640b2428ddf03ded9";
+
+    public static void main(String[] args) {
+        send("15720916464","尊敬的用户,您的验证码为123456,此验证码仅用于银河录像。【银河录像局】");
+    }
+
+    public static void send(String mobile, String msg){
+        HttpRequest request = new HttpRequest(URL);
+        request.setMethod(Method.POST);
+        request.basicAuth("api",PASSWORD);
+        request.form("mobile",mobile);
+        request.form("message",msg);
+        HttpResponse execute = request.execute();
+        System.out.println(execute.body());
+    }
+}

+ 26 - 0
netflix-common/src/main/java/com/cyksj/common/util/corp/ByteGroup.java

@@ -0,0 +1,26 @@
+package com.cyksj.common.util.corp;
+
+import java.util.ArrayList;
+
+public class ByteGroup {
+	ArrayList<Byte> byteContainer = new ArrayList<>();
+
+	public byte[] toBytes() {
+		byte[] bytes = new byte[this.byteContainer.size()];
+		for (int i = 0; i < this.byteContainer.size(); i++) {
+			bytes[i] = this.byteContainer.get(i);
+		}
+		return bytes;
+	}
+
+	public ByteGroup addBytes(byte[] bytes) {
+		for (byte b : bytes) {
+			this.byteContainer.add(b);
+		}
+		return this;
+	}
+
+	public int size() {
+		return this.byteContainer.size();
+	}
+}

+ 65 - 0
netflix-common/src/main/java/com/cyksj/common/util/corp/PKCS7Encoder.java

@@ -0,0 +1,65 @@
+/*
+ * 对公众平台发送给公众账号的消息加解密示例代码.
+ *
+ * @copyright Copyright (c) 1998-2014 Tencent Inc.
+ */
+
+package com.cyksj.common.util.corp;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+/**
+ * 提供基于PKCS7算法的加解.
+ *
+ * @author tencent
+ */
+public class PKCS7Encoder {
+	private static final Charset CHARSET = StandardCharsets.UTF_8;
+	private static final int BLOCK_SIZE = 32;
+
+	/**
+	 * 获得对明文进行补位填充的字节.
+	 *
+	 * @param count 需要进行填充补位操作的明文字节个数
+	 * @return 补齐用的字节数组
+	 */
+	public static byte[] encode(int count) {
+		// 计算需要填充的位数
+		int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
+		// 获得补位所用的字符
+		char padChr = chr(amountToPad);
+		StringBuilder tmp = new StringBuilder();
+		for (int index = 0; index < amountToPad; index++) {
+			tmp.append(padChr);
+		}
+		return tmp.toString().getBytes(CHARSET);
+	}
+
+	/**
+	 * 删除解密后明文的补位字符.
+	 *
+	 * @param decrypted 解密后的明文
+	 * @return 删除补位字符后的明文
+	 */
+	public static byte[] decode(byte[] decrypted) {
+		int pad = decrypted[decrypted.length - 1];
+		if (pad < 1 || pad > 32) {
+			pad = 0;
+		}
+		return Arrays.copyOfRange(decrypted, 0, decrypted.length - pad);
+	}
+
+	/**
+	 * 将数字转化成ASCII码对应的字符,用于对明文进行补码.
+	 *
+	 * @param a 需要转化的数字
+	 * @return 转化得到的字符
+	 */
+	private static char chr(int a) {
+		byte target = (byte) (a & 0xFF);
+		return (char) target;
+	}
+
+}

+ 64 - 0
netflix-common/src/main/java/com/cyksj/common/util/corp/SHA1.java

@@ -0,0 +1,64 @@
+package com.cyksj.common.util.corp;
+
+import com.cyksj.common.exception.AesException;
+import com.cyksj.common.util.Codec;
+
+import java.security.MessageDigest;
+import java.util.Arrays;
+
+/**
+ * @author chan
+ * @date 2022-03-14 上午10:31
+ */
+public class SHA1 {
+
+  /**
+   * 用&串接arr参数,生成sha1 digest.
+   */
+  public static String genWithAmple(String... arr) throws Exception {
+    Arrays.sort(arr);
+    StringBuilder sb = new StringBuilder();
+    for (int i = 0; i < arr.length; i++) {
+      String a = arr[i];
+      sb.append(a);
+      if (i != arr.length - 1) {
+        sb.append('&');
+      }
+    }
+    return Codec.DoDigest.custom().setAlgorithm(Codec.DoDigest.Algorithm.SHA1).setStringData(sb.toString()).toHexString();
+  }
+
+
+  /**
+   * 用SHA1算法生成安全签名
+   */
+  public static String getSHA1(String token, String timestamp, String nonce, String encrypt) throws AesException {
+    try {
+      String[] array = new String[] { token, timestamp, nonce, encrypt };
+      StringBuffer sb = new StringBuffer();
+      // 字符串排序
+      Arrays.sort(array);
+      for (int i = 0; i < 4; i++) {
+        sb.append(array[i]);
+      }
+      String str = sb.toString();
+      // SHA1签名生成
+      MessageDigest md = MessageDigest.getInstance("SHA-1");
+      md.update(str.getBytes());
+      byte[] digest = md.digest();
+
+      StringBuffer hexstr = new StringBuffer();
+      String shaHex = "";
+      for (int i = 0; i < digest.length; i++) {
+        shaHex = Integer.toHexString(digest[i] & 0xFF);
+        if (shaHex.length() < 2) {
+          hexstr.append(0);
+        }
+        hexstr.append(shaHex);
+      }
+      return hexstr.toString();
+    } catch (Exception e) {
+      throw new AesException(AesException.ComputeSignatureError);
+    }
+  }
+}

+ 218 - 0
netflix-common/src/main/java/com/cyksj/common/util/corp/WxCryptUtil.java

@@ -0,0 +1,218 @@
+package com.cyksj.common.util.corp;
+
+import cn.hutool.core.codec.Base64;
+import com.cyksj.common.exception.AesException;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Random;
+
+/**
+ * <pre>
+ * 对公众平台发送给公众账号的消息加解密示例代码.
+ * Copyright (c) 1998-2014 Tencent Inc.
+ * 针对org.apache.commons.codec.binary.Base64,
+ * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本)
+ * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi
+ * </pre>
+ *
+ * @author Tencent
+ */
+public class WxCryptUtil {
+
+	private static final Charset CHARSET = StandardCharsets.UTF_8;
+
+	private static final ThreadLocal<DocumentBuilder> BUILDER_LOCAL = ThreadLocal.withInitial(() -> {
+		try {
+			final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+			factory.setExpandEntityReferences(false);
+			factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+			return factory.newDocumentBuilder();
+		} catch (ParserConfigurationException exc) {
+			throw new IllegalArgumentException(exc);
+		}
+	});
+
+	protected byte[] aesKey;
+	protected String token;
+	protected String appidOrCorpid;
+
+	public WxCryptUtil() {
+	}
+
+	/**
+	 * 构造函数.
+	 *
+	 * @param token          公众平台上,开发者设置的token
+	 * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey
+	 * @param appidOrCorpid  公众平台appid/corpid
+	 */
+	public WxCryptUtil(String token, String encodingAesKey, String appidOrCorpid) {
+		this.token = token;
+		this.appidOrCorpid = appidOrCorpid;
+		this.aesKey = Base64.decode(encodingAesKey);
+	}
+
+
+	/**
+	 * 将一个数字转换成生成4个字节的网络字节序bytes数组.
+	 */
+	private static byte[] number2BytesInNetworkOrder(int number) {
+		byte[] orderBytes = new byte[4];
+		orderBytes[3] = (byte) (number & 0xFF);
+		orderBytes[2] = (byte) (number >> 8 & 0xFF);
+		orderBytes[1] = (byte) (number >> 16 & 0xFF);
+		orderBytes[0] = (byte) (number >> 24 & 0xFF);
+		return orderBytes;
+	}
+
+	/**
+	 * 4个字节的网络字节序bytes数组还原成一个数字.
+	 */
+	private static int bytesNetworkOrder2Number(byte[] bytesInNetworkOrder) {
+		int sourceNumber = 0;
+		for (int i = 0; i < 4; i++) {
+			sourceNumber <<= 8;
+			sourceNumber |= bytesInNetworkOrder[i] & 0xff;
+		}
+		return sourceNumber;
+	}
+
+	/**
+	 * 随机生成16位字符串.
+	 */
+	private static String genRandomStr() {
+		String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
+		Random random = new Random();
+		StringBuilder sb = new StringBuilder();
+		for (int i = 0; i < 16; i++) {
+			int number = random.nextInt(base.length());
+			sb.append(base.charAt(number));
+		}
+		return sb.toString();
+	}
+
+	/**
+	 * 生成xml消息.
+	 *
+	 * @param encrypt   加密后的消息密文
+	 * @param signature 安全签名
+	 * @param timestamp 时间戳
+	 * @param nonce     随机字符串
+	 * @return 生成的xml字符串
+	 */
+	private static String generateXml(String encrypt, String signature, String timestamp, String nonce) {
+		String format = "<xml>\n" + "<Encrypt><![CDATA[%1$s]]></Encrypt>\n"
+				+ "<MsgSignature><![CDATA[%2$s]]></MsgSignature>\n"
+				+ "<TimeStamp>%3$s</TimeStamp>\n" + "<Nonce><![CDATA[%4$s]]></Nonce>\n"
+				+ "</xml>";
+		return String.format(format, encrypt, signature, timestamp, nonce);
+	}
+
+	/**
+	 * 将公众平台回复用户的消息加密打包.
+	 * <ol>
+	 * <li>对要发送的消息进行AES-CBC加密</li>
+	 * <li>生成安全签名</li>
+	 * <li>将消息密文和安全签名打包成xml格式</li>
+	 * </ol>
+	 *
+	 * @param plainText 公众平台待回复用户的消息,xml格式的字符串
+	 * @return 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串
+	 */
+	public String encrypt(String plainText) throws AesException {
+		// 加密
+		String encryptedXml = encrypt(genRandomStr(), plainText);
+
+		// 生成安全签名
+		String timeStamp = Long.toString(System.currentTimeMillis() / 1000L);
+		String nonce = genRandomStr();
+
+		String signature = SHA1.getSHA1(this.token, timeStamp, nonce, encryptedXml);
+		return generateXml(encryptedXml, signature, timeStamp, nonce);
+	}
+
+	/**
+	 * 将公众平台回复用户的消息加密打包.
+	 * <ol>
+	 * <li>对要发送的消息进行AES-CBC加密</li>
+	 * <li>生成安全签名</li>
+	 * <li>将消息密文和安全签名打包成xml格式</li>
+	 * </ol>
+	 *
+	 * @param plainText 公众平台待回复用户的消息,xml格式的字符串
+	 * @return 加密消息所需的值对象
+	 */
+	public EncryptContext encryptContext(String plainText) throws AesException {
+		// 加密
+		String encryptedXml = encrypt(genRandomStr(), plainText);
+
+		// 生成安全签名
+		String timeStamp = Long.toString(System.currentTimeMillis() / 1000L);
+		String nonce = genRandomStr();
+
+		String signature = SHA1.getSHA1(this.token, timeStamp, nonce, encryptedXml);
+		return new EncryptContext(encryptedXml, signature, timeStamp, nonce);
+	}
+
+	/**
+	 * 对明文进行加密.
+	 *
+	 * @param plainText 需要加密的明文
+	 * @return 加密后base64编码的字符串
+	 */
+	public String encrypt(String randomStr, String plainText) {
+		ByteGroup byteCollector = new ByteGroup();
+		byte[] randomStringBytes = randomStr.getBytes(CHARSET);
+		byte[] plainTextBytes = plainText.getBytes(CHARSET);
+		byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder(plainTextBytes.length);
+		byte[] appIdBytes = this.appidOrCorpid.getBytes(CHARSET);
+
+		// randomStr + networkBytesOrder + text + appid
+		byteCollector.addBytes(randomStringBytes);
+		byteCollector.addBytes(bytesOfSizeInNetworkOrder);
+		byteCollector.addBytes(plainTextBytes);
+		byteCollector.addBytes(appIdBytes);
+
+		// ... + pad: 使用自定义的填充方式对明文进行补位填充
+		byte[] padBytes = PKCS7Encoder.encode(byteCollector.size());
+		byteCollector.addBytes(padBytes);
+
+		// 获得最终的字节流, 未加密
+		byte[] unencrypted = byteCollector.toBytes();
+
+		try {
+			// 设置加密模式为AES的CBC模式
+			Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+			SecretKeySpec keySpec = new SecretKeySpec(this.aesKey, "AES");
+			IvParameterSpec iv = new IvParameterSpec(this.aesKey, 0, 16);
+			cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
+
+			// 加密
+			byte[] encrypted = cipher.doFinal(unencrypted);
+
+			// 使用BASE64对加密后的字符串进行编码
+			return Base64.encode(encrypted);
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+
+	}
+
+	@Data
+	@AllArgsConstructor
+	public static class EncryptContext {
+		private String encrypt;
+		private String signature;
+		private String timeStamp;
+		private String nonce;
+	}
+}

+ 41 - 0
netflix-common/src/main/java/com/cyksj/dto/CorpJsSdkTicket.java

@@ -0,0 +1,41 @@
+package com.cyksj.dto;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * @author chan
+ * @date 2022/3/17 上午10:24
+ */
+@Getter
+@Setter
+public class CorpJsSdkTicket implements Serializable {
+
+    /**
+     * 企业微信的唯一标识
+     */
+    private String corpId;
+
+    /**
+     * 应用agentId
+     */
+    private String agentId;
+
+    /**
+     * 生成签名的时间戳
+     */
+    private Long timestamp;
+
+    /**
+     * 生成签名的随机串
+     */
+    private String nonceStr;
+
+    /**
+     * 签名
+     */
+    private String signature;
+
+}

+ 26 - 0
netflix-common/src/main/java/com/cyksj/dto/CorpOauth2UserInfo.java

@@ -0,0 +1,26 @@
+package com.cyksj.dto;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author chan
+ * @date 2022/3/17 下午4:40
+ */
+@Data
+public class CorpOauth2UserInfo implements Serializable {
+
+    /**
+     *  手机设备号
+     */
+    @JsonProperty("DeviceId")
+    private String deviceId;
+
+    /**
+     * 成员userId
+     */
+    @JsonProperty("UserId")
+    private String userId;
+}

+ 6 - 0
netflix-dao/src/main/java/com/cyksj/mapper/AccountMapper.java

@@ -2,10 +2,16 @@ package com.cyksj.mapper;
 
 import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.cyksj.model.entity.Account;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Date;
+import java.util.List;
 
 /**
  * @author chan
  * @date 2022/9/27 6:22 PM
  */
 public interface AccountMapper extends BaseMapper<Account> {
+
+	List<Integer> getNumOfUser(@Param("list") List<Long> accountIds, @Param("yesZeroDate") Date yesZeroDate, @Param("thisZeroDate") Date thisZeroDate);
 }

+ 11 - 0
netflix-dao/src/main/java/com/cyksj/mapper/AddressMapper.java

@@ -0,0 +1,11 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.Address;
+
+/**
+ * @author chan
+ * @date 2022/10/13 3:06 PM
+ */
+public interface AddressMapper extends BaseMapper<Address> {
+}

+ 3 - 0
netflix-dao/src/main/java/com/cyksj/mapper/OrderDonMapper.java

@@ -5,6 +5,7 @@ import com.cyksj.model.entity.OrderDon;
 import com.cyksj.model.excel.ExcelOrderDonInfo;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.Date;
 import java.util.List;
 
 /**
@@ -15,4 +16,6 @@ public interface OrderDonMapper extends BaseMapper<OrderDon> {
 
 
     List<ExcelOrderDonInfo> exportOrderInfo(@Param("promotionId") Long promotionId, @Param("start") String start, @Param("end") String end);
+
+    List<OrderDon> getAppleOneOrderDons(@Param("appleOne") String appleOne, @Param("skuIds") List<Long> skuIds, @Param("noOrderStatus") List<String> noOrderStatus, @Param("yesZeroDate") Date yesZeroDate, @Param("thisZeroDate") Date thisZeroDate);
 }

+ 11 - 0
netflix-dao/src/main/java/com/cyksj/mapper/OrderDonTransportMapper.java

@@ -0,0 +1,11 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.OrderDonTransport;
+
+/**
+ * @author chan
+ * @date 2022/10/17 7:09 PM
+ */
+public interface OrderDonTransportMapper extends BaseMapper<OrderDonTransport> {
+}

+ 11 - 0
netflix-dao/src/main/java/com/cyksj/mapper/OrderDonWaybillMapper.java

@@ -0,0 +1,11 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.OrderDonWaybill;
+
+/**
+ * @author chan
+ * @date 2022/10/18 10:13 AM
+ */
+public interface OrderDonWaybillMapper extends BaseMapper<OrderDonWaybill> {
+}

+ 11 - 0
netflix-dao/src/main/java/com/cyksj/mapper/SysConfigMapper.java

@@ -0,0 +1,11 @@
+package com.cyksj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.SysConfig;
+
+/**
+ * @author chan
+ * @date 2022/10/20 10:06 AM
+ */
+public interface SysConfigMapper extends BaseMapper<SysConfig> {
+}

+ 12 - 0
netflix-dao/src/main/java/com/cyksj/mapper/corp/CorpFollowMapper.java

@@ -0,0 +1,12 @@
+package com.cyksj.mapper.corp;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.CorpFollow;
+
+
+/**
+ * @author chan
+ * @date 2022/3/15 上午9:49
+ */
+public interface CorpFollowMapper extends BaseMapper<CorpFollow> {
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/corp/CorpTagGroupMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.corp;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.CorpTagGroup;
+
+/*
+ *项目名: netflix
+ *文件名: CorpTagGroupMapper
+ *创建者: JavaZou
+ *创建时间:2022/10/13 18:01
+ */
+public interface CorpTagGroupMapper extends BaseMapper<CorpTagGroup> {
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/corp/CorpTagMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.corp;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.CorpTag;
+
+/*
+ *项目名: netflix
+ *文件名: CorpTagMapper
+ *创建者: JavaZou
+ *创建时间:2022/10/13 18:07
+ */
+public interface CorpTagMapper extends BaseMapper<CorpTag> {
+}

+ 11 - 0
netflix-dao/src/main/java/com/cyksj/mapper/corp/CorpUserFollowRelationMapper.java

@@ -0,0 +1,11 @@
+package com.cyksj.mapper.corp;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.CorpUserFollowRelation;
+
+/**
+ * @author chan
+ * @date 2022/3/15 上午9:49
+ */
+public interface CorpUserFollowRelationMapper extends BaseMapper<CorpUserFollowRelation> {
+}

+ 12 - 0
netflix-dao/src/main/java/com/cyksj/mapper/corp/CorpUserMapper.java

@@ -0,0 +1,12 @@
+package com.cyksj.mapper.corp;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.CorpUser;
+
+
+/**
+ * @author chan
+ * @date 2022/3/15 上午9:49
+ */
+public interface CorpUserMapper extends BaseMapper<CorpUser> {
+}

+ 12 - 0
netflix-dao/src/main/java/com/cyksj/mapper/corp/CorpUserTagMapper.java

@@ -0,0 +1,12 @@
+package com.cyksj.mapper.corp;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.CorpUserTag;
+
+
+/**
+ * @author chan
+ * @date 2022/3/15 上午11:20
+ */
+public interface CorpUserTagMapper extends BaseMapper<CorpUserTag> {
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/statistics/AppleOneDataMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.manage.statistics;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.AppleOneData;
+
+/*
+ *项目名: netflix
+ *文件名: AppleOneDataMapper
+ *创建者: JavaZou
+ *创建时间:2022/10/18 14:54
+ */
+public interface AppleOneDataMapper extends BaseMapper<AppleOneData> {
+}

+ 13 - 0
netflix-dao/src/main/java/com/cyksj/mapper/manage/statistics/StreamingAccountDataMapper.java

@@ -0,0 +1,13 @@
+package com.cyksj.mapper.manage.statistics;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.cyksj.model.entity.StreamingAccountData;
+
+/*
+ *项目名: netflix
+ *文件名: StreamingAccountDataMapper
+ *创建者: JavaZou
+ *创建时间:2022/10/18 14:53
+ */
+public interface StreamingAccountDataMapper extends BaseMapper<StreamingAccountData> {
+}

+ 5 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/AuthRedirect.java

@@ -18,4 +18,9 @@ public class AuthRedirect {
 
     private Long sharedId;
 
+    /**
+     * corpId
+     */
+    private String corpId;
+
 }

+ 33 - 0
netflix-dao/src/main/java/com/cyksj/model/dto/WxCorpEncryptDto.java

@@ -0,0 +1,33 @@
+package com.cyksj.model.dto;
+
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlCData;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.experimental.Accessors;
+
+/**
+ * @author chan
+ * @date 2022/3/11 下午3:06
+ */
+
+@Getter
+@Setter
+@Accessors(chain = true)
+@JacksonXmlRootElement(localName = "xml")
+public class WxCorpEncryptDto {
+
+	@JacksonXmlProperty(localName = "ToUserName")
+	@JacksonXmlCData
+	private String toUserName;
+
+	@JacksonXmlProperty(localName = "AgentID")
+	@JacksonXmlCData
+	private String agentId;
+
+	@JacksonXmlProperty(localName = "Encrypt")
+	@JacksonXmlCData
+	private String encrypt;
+
+}

+ 71 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/AbstractBackData.java

@@ -0,0 +1,71 @@
+package com.cyksj.model.entity;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/*
+ *项目名: netflix
+ *文件名: AbstractBackData
+ *创建者: JavaZou
+ *创建时间:2022/10/18 14:34
+ */
+@Getter
+@Setter
+public abstract class AbstractBackData {
+	@TableId(value = "id", type = IdType.AUTO)
+	private Long id;
+
+	/**
+	 * 展示数据时使用
+	 */
+	private Long showId;
+
+	/**
+	 * 用户数
+	 */
+	private Integer numOfUser;
+
+	/**
+	 * 订单数
+	 */
+	private Integer numOfOrder;
+
+	/**
+	 * 金额
+	 */
+	private BigDecimal money;
+
+	/**
+	 * 月付单数
+	 */
+	private Integer numOfMonthOrder;
+
+	/**
+	 * 季付单数
+	 */
+	private Integer numOfSeasonOrder;
+
+	/**
+	 * 年付单数
+	 */
+	private Integer numOfYearOrder;
+
+	/**
+	 * 创建时间
+	 */
+	@TableField(fill = FieldFill.INSERT)
+	private Date createdTime;
+
+	/**
+	 * 修改时间
+	 */
+	@TableField(fill = FieldFill.INSERT_UPDATE)
+	private Date updateTime;
+}

+ 4 - 3
netflix-dao/src/main/java/com/cyksj/model/entity/Account.java

@@ -3,6 +3,7 @@ package com.cyksj.model.entity;
 import lombok.Getter;
 import lombok.Setter;
 
+import java.math.BigDecimal;
 import java.util.Date;
 
 /**
@@ -19,14 +20,14 @@ public class Account extends BaseEntity {
 
     private String password;
 
-    private Long platformId;
-
-    private String platform;
+    private Long goodsId;
 
     private Date startTime;
 
     private Date expiryTime;
 
+    private BigDecimal amount;
+
     /**
      * 国区id
      */

+ 56 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/Address.java

@@ -0,0 +1,56 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author chan
+ * @date 2022-10-13 3:04 PM
+ */
+@Getter
+@Setter
+public class Address extends BaseEntity {
+
+    private Long userId;
+
+    /**
+     * 收货人
+     */
+    private String receiver;
+
+    /**
+     * 手机号
+     */
+    private String phone;
+
+    /**
+     * 省份
+     */
+    private String province;
+
+    /**
+     * 城市
+     */
+    private String city;
+
+    /**
+     * 区/县
+     */
+    private String district;
+
+    /**
+     * 详细地址
+     */
+    private String address;
+
+    /**
+     * 地区代号
+     */
+    private String code;
+
+    /**
+     * 是否为默认地址
+     */
+    private Boolean isDefault;
+
+}

+ 19 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/AppleOneData.java

@@ -0,0 +1,19 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: AppleOne
+ *创建者: JavaZou
+ *创建时间:2022/10/18 11:44
+ */
+@Getter
+@Setter
+public class AppleOneData extends AbstractBackData{
+	/**
+	 * 区域名称
+	 */
+	private String areaName;
+}

+ 66 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CorpFollow.java

@@ -0,0 +1,66 @@
+package com.cyksj.model.entity;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author chan
+ * @date 2022/3/14 下午7:23
+ */
+@Data
+public class CorpFollow extends BaseEntity implements Serializable {
+
+    private String corpId;
+
+    /**
+     * 成员UserID
+     */
+    private String userid;
+
+    /**
+     * 成员名称
+     */
+    private String name;
+
+    /**
+     * 手机号
+     */
+    private String mobile;
+
+    /**
+     * 职位
+     */
+    private String position;
+
+    /**
+     * 头像地址
+     */
+    private String avatar;
+
+    /**
+     * 头像缩略图
+     */
+    private String thumbAvatar;
+
+    /**
+     * 地址。长度最大128个字符
+     */
+    private String address;
+
+
+    /**
+     * 激活状态: 1=已激活,2=已禁用,4=未激活,5=退出企业。
+     */
+    private Integer status;
+
+    /**
+     * 员工个人二维码,扫描可添加为外部联系人(注意返回的是一个url,可在浏览器上打开该url以展示二维码);第三方仅通讯录应用可获取;
+     */
+    private String qrCode;
+
+    /**
+     * 全局唯一。对于同一个服务商,不同应用获取到企业内同一个成员的open_userid是相同的
+     */
+    private String open_userid;
+}

+ 33 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CorpTag.java

@@ -0,0 +1,33 @@
+package com.cyksj.model.entity;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author chan
+ * @date 2022/3/24 上午11:01
+ */
+@Data
+public class CorpTag extends BaseEntity implements Serializable {
+
+    /**
+     * 标签组id
+     */
+    private String groupId;
+
+    /**
+     * 标签组名称
+     */
+    private String groupName;
+
+    /**
+     * 标签名称
+     */
+    private String name;
+
+    /**
+     * 标签id
+     */
+    private String tagId;
+}

+ 33 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CorpTagGroup.java

@@ -0,0 +1,33 @@
+package com.cyksj.model.entity;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author chan
+ * @date 2022/3/24 上午11:04
+ */
+@Data
+public class CorpTagGroup extends BaseEntity implements Serializable {
+
+    /**
+     * 标签组id
+     */
+    private String groupId;
+
+    /**
+     * 标签组名称
+     */
+    private String groupName;
+
+    /**
+     * 排序
+     */
+    private Integer order;
+
+    /**
+     * 是否删除
+     */
+    private Boolean deleted;
+}

+ 50 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CorpUser.java

@@ -0,0 +1,50 @@
+package com.cyksj.model.entity;
+
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+
+/**
+ * @author chan
+ * @date 2022/3/14 下午7:23
+ */
+@Accessors(chain = true)
+@Data
+public class CorpUser extends BaseEntity implements Serializable {
+
+	/**
+	 * 外部联系人的userid
+	 */
+	private String externalUserid;
+
+	/**
+	 * 外部联系人的名称
+	 */
+	private String name;
+
+	/**
+	 * 外部联系人头像,代开发自建应用需要管理员授权才可以获取,第三方不可获取,上游企业不可获取下游企业客户该字段
+	 */
+	private String avatar;
+
+	/**
+	 * 外部联系人的类型,1表示该外部联系人是微信用户,2表示该外部联系人是企业微信用户
+	 */
+	private Integer type;
+
+	/**
+	 * 外部联系人性别 0-未知 1-男性 2-女性。第三方不可获取,上游企业不可获取下游企业客户该字段,返回值为0,表示未定义
+	 */
+	private Integer gender;
+
+	/**
+	 * 外部联系人在微信开放平台的唯一身份标识(微信unionid),通过此字段企业可将外部联系人与公众号/小程序用户关联起来。仅当联系人类型是微信用户,且企业绑定了微信开发者ID有此字段。
+	 */
+	private String unionid;
+
+	/**
+	 * user表 关联用户id
+	 */
+	private Long userId;
+}

+ 99 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CorpUserFollowRelation.java

@@ -0,0 +1,99 @@
+package com.cyksj.model.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.Getter;
+import lombok.experimental.Accessors;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.stream.Stream;
+
+/**
+ * @author chan
+ * @date 2022/3/14 下午7:23
+ */
+@Accessors(chain = true)
+@Data
+public class CorpUserFollowRelation extends BaseEntity implements Serializable {
+
+	/**
+	 * corp_user 客户id
+	 */
+	private String corpUserId;
+
+	/**
+	 * corp_follow 成员id
+	 */
+	private String followId;
+
+	/**
+	 * 该成员对此外部联系人的备注
+	 */
+	private String remark;
+
+	/**
+	 * 该成员对此外部联系人的描述
+	 */
+	private String description;
+
+	/**
+	 * 该成员添加此外部联系人的时间
+	 */
+	private Date addCreatedTime;
+
+	/**
+	 * 该成员对此客户备注的手机号码
+	 */
+	private String remarkMobiles;
+
+	/**
+	 * 该成员添加此客户的来源
+	 */
+	private String addWay;
+
+	/**
+	 * 关联关系
+	 * 0删除 1未删除
+	 */
+	private Integer status;
+
+	/**
+	 * 发起添加的userid,如果成员主动添加,为成员的userid;如果是客户主动添加,则为客户的外部联系人userid;如果是内部成员共享/管理员分配,则为对应的成员/管理员userid
+	 */
+	private String operUserid;
+
+
+	/**
+	 * 发起删除的userid
+	 */
+	private String delUserid;
+
+	@AllArgsConstructor
+	@Getter
+	public enum Way {
+		way0("0", "未知来源"),
+		way1("1", "扫描二维码"),
+		way2("2", "搜索手机号"),
+		way3("3", "名片分享"),
+		way4("4", "群聊"),
+		way5("5", "手机通讯录"),
+		way6("6", "微信联系人"),
+		way8("8", "安装第三方应用时自动添加的客服人员"),
+		way9("9", "搜索邮箱"),
+		way10("10", "视频号添加"),
+		way201("201", "内部成员共享"),
+		way202("202", "管理员/负责人分配");
+
+		private String code;
+
+		private String desc;
+
+		@SuppressWarnings("rawtypes")
+		public static String getDesc(String code) {
+			return Stream.of(Way.values())
+					.filter(enums -> enums.getCode().equals(code)).findFirst().orElse(way0).getDesc();
+		}
+
+	}
+}

+ 56 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/CorpUserTag.java

@@ -0,0 +1,56 @@
+package com.cyksj.model.entity;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * @author chan
+ * @date 2022/3/15 上午11:17
+ */
+@Data
+public class CorpUserTag extends BaseEntity implements Serializable {
+
+	/**
+	 * corp_user_follow_relation_id 关联id
+	 */
+	private Long relationId;
+
+	/**
+	 * 该成员添加此外部联系人所打标签的分组名称
+	 */
+	private String groupName;
+
+	/**
+	 * 该成员添加此外部联系人所打标签名称
+	 */
+	private String tagName;
+
+	/**
+	 * 该成员添加此外部联系人所打企业标签的id,仅企业设置(type为1)的标签返回
+	 */
+	private String tagId;
+
+	/**
+	 * 该成员添加此外部联系人所打标签类型, 1-企业设置, 2-用户自定义
+	 */
+	private int type;
+
+	@Override
+	public boolean equals(Object o) {
+		if (this == o) return true;
+		if (o == null || getClass() != o.getClass()) return false;
+		CorpUserTag that = (CorpUserTag) o;
+		return type == that.type &&
+				relationId.equals(that.relationId) &&
+				groupName.equals(that.groupName) &&
+				tagName.equals(that.tagName) &&
+				tagId.equals(that.tagId);
+	}
+
+	@Override
+	public int hashCode() {
+		return Objects.hash(relationId, groupName, tagName, tagId, type);
+	}
+}

+ 20 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDon.java

@@ -1,5 +1,6 @@
 package com.cyksj.model.entity;
 
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.ejlchina.searcher.bean.SearchBean;
 import lombok.Getter;
 import lombok.Setter;
@@ -13,6 +14,7 @@ import lombok.Setter;
 @SearchBean(tables = "goods_don")
 public class GoodsDon extends BaseEntity {
 
+
     /**
      * 商品录入人
      */
@@ -53,4 +55,22 @@ public class GoodsDon extends BaseEntity {
      * 详情
      */
     private String detail;
+
+    /**
+     * 描述
+     */
+    private String remark;
+
+    private Integer type;
+
+    /**
+     * 二级分类
+     * 虚物品 1邀请制 2非邀请制
+     */
+    private Integer secondType;
+
+    private String banner;
+
+    @TableField(exist = false)
+    private Integer accountCount;
 }

+ 8 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GoodsDonSku.java

@@ -15,6 +15,9 @@ public class GoodsDonSku extends BaseEntity {
 
     private Long goodsId;
 
+
+    private String subTitle;
+
     /**
      * 商品规格 ids
      */
@@ -35,6 +38,11 @@ public class GoodsDonSku extends BaseEntity {
      */
     private String picture;
 
+    /**
+     * 标签
+     */
+    private String tag;
+
 
     /**
      * true 上架 / false 下架

+ 4 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/GroupsRelation.java

@@ -32,6 +32,10 @@ public class GroupsRelation extends BaseEntity {
      */
     private Status status;
 
+    /**
+     * 账号
+     */
+    private String account;
 
 
     @AllArgsConstructor

+ 57 - 6
netflix-dao/src/main/java/com/cyksj/model/entity/GroupsTrips.java

@@ -1,5 +1,8 @@
 package com.cyksj.model.entity;
 
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 import lombok.Setter;
@@ -12,52 +15,100 @@ import java.util.Date;
  */
 @Getter
 @Setter
+@SearchBean(tables = "groups_trips gt left join goods_don_sku sku on gt.sku_id = sku.id " +
+        "left join goods_don g on g.id = sku.goods_id " +
+        "left join account a on a.id = gt.account_id ")
 public class GroupsTrips extends BaseEntity {
 
+
+    @DbField("gt.id")
+    @TableField(exist = false)
+    private Long groupId;
+
     /**
      * 商品skuid
      */
+    @DbField("gt.sku_id")
     private Long skuId;
 
     /**
      * 账号id
      */
+    @DbField("gt.account_id")
     private Long accountId;
 
+
+    /**
+     * 账号
+     */
+    @DbField("a.account")
+    @TableField(exist = false)
+    private String account;
+
+    /**
+     * 密码
+     */
+    @DbField("a.password")
+    @TableField(exist = false)
+    private String password;
+
+    /**
+     * 标题
+     */
+    @DbField("g.title")
+    @TableField(exist = false)
+    private String title;
+
+    /**
+     * 商品规格
+     */
+    @DbField("sku.spec_val")
+    @TableField(exist = false)
+    private String seecVal;
     /**
      * 录入人
      */
+    @DbField("gt.writer")
     private Long writer;
 
     /**
      * 车位数量
      */
+    @DbField("gt.num")
     private Integer num;
 
     /**
      * 可用车位数
      */
+    @DbField("gt.available_num")
     private Integer availableNum;
 
     /**
      * 状态
      */
+    @DbField("gt.status")
     private Status status;
 
     /**
      * 备注
      */
+    @DbField("gt.remark")
     private String remark;
 
     /**
-     * 修改价格时间
+     * 时间
      */
-    private Date upValTime;
+    @DbField("gt.start_time")
+    private Date startTime;
+
+    @DbField("gt.created_time")
+    @TableField(exist = false)
+    private Date createTime;
+
+    @DbField("a.expiry_time")
+    @TableField(exist = false)
+    private Date expiryTime;
 
-    /**
-     * 续费时间
-     */
-    private Date renewalTime;
 
 
     @AllArgsConstructor

+ 31 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/HomeGroup.java

@@ -1,21 +1,52 @@
 package com.cyksj.model.entity;
 
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
 import lombok.Data;
 
+import java.util.Date;
+
 /**
  * @author chan
  * @date 2022/10/12 10:46 AM
  */
 @Data
+@SearchBean(tables = "home_group h left join groups_relation gr on h.relation_id gr.id")
 public class HomeGroup extends BaseEntity{
 
+    @DbField("h.id")
+    private Long homeGroupId;
+
+    @DbField("gr.account_id")
     private Long accountId;
 
+    @DbField("gr.relation_id")
     private Long relationId;
 
+    @DbField("gr.user_id")
+    private Long userId;
+
     /**
      * invited
      * uninvited
      */
+    @DbField("h.status")
     private String status;
+
+    /**
+     * 用户填写账号
+     */
+    @DbField("gr.account")
+    @TableField(exist = false)
+    private String account;
+
+    @DbField("gr.start_time")
+    @TableField(exist = false)
+    private Date startTime;
+
+    @TableField(exist = false)
+    @DbField("gr.expiry_time")
+    private Date expiryTime;
+
 }

+ 4 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/OrderDon.java

@@ -44,6 +44,10 @@ public class OrderDon extends BaseEntity implements Serializable {
     /** 金额 */
     private BigDecimal money ;
 
+    /**
+     * 购买数量
+     */
+    private Integer num;
 
     /** 支付状态 */
     private Status status ;

+ 47 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/OrderDonTransport.java

@@ -0,0 +1,47 @@
+package com.cyksj.model.entity;
+
+import lombok.Data;
+
+/**
+ * @author chan
+ * @date 2022/10/17 7:08 PM
+ */
+@Data
+public class OrderDonTransport extends BaseEntity{
+
+    /**
+     * 订单id
+     */
+    private Long orderId;
+
+    /**
+     * 收货人
+     */
+    private String receiver;
+
+    /**
+     * 手机号
+     */
+    private String phone;
+
+    /**
+     * 省份
+     */
+    private String province;
+
+    /**
+     * 城市
+     */
+    private String city;
+
+    /**
+     * 区/县
+     */
+    private String district;
+
+    /**
+     * 详细地址
+     */
+    private String address;
+
+}

+ 92 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/OrderDonWaybill.java

@@ -0,0 +1,92 @@
+package com.cyksj.model.entity;
+
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * @author chan
+ * @date 2022/10/18 10:13 AM
+ */
+@Data
+public class OrderDonWaybill extends BaseEntity{
+
+    /**
+     * 订单id
+     */
+    private Integer orderId;
+
+    /**
+     * 物流公司简码
+     */
+    private String code;
+
+    /**
+     * 物流公司名称
+     */
+    private String codeCn;
+
+    /**
+     * 物流运单号
+     */
+    private String trackingNumber;
+
+
+    public void setCodeCn(String codeCn) {
+        if (StringUtils.equals("中国 EMS",codeCn)){
+            this.code = "china-ems";
+        }
+        if (StringUtils.equals("顺丰速运",codeCn)){
+            this.code = "sf-express";
+        }
+        if (StringUtils.equals("申通快递",codeCn)){
+            this.code = "sto";
+        }
+        if (StringUtils.equals("圆通快递",codeCn)){
+            this.code = "yto";
+        }
+        if (StringUtils.equals("天天快递",codeCn)){
+            this.code = "ttkd";
+        }
+        if (StringUtils.equals("中通快递",codeCn)){
+            this.code = "zto";
+        }
+        if (StringUtils.equals("宅急送快递",codeCn)){
+            this.code = "zjs-express";
+        }
+        if (StringUtils.equals("韵达快递",codeCn)){
+            this.code = "yunda";
+        }
+        if (StringUtils.equals("全峰快递",codeCn)){
+            this.code = "qfkd";
+        }
+        if (StringUtils.equals("国通快递",codeCn)){
+            this.code = "cess";
+        }
+        if (StringUtils.equals("百世快递",codeCn)){
+            this.code = "bestex";
+        }
+        if (StringUtils.equals("速尔快递",codeCn)){
+            this.code = "sure56";
+        }
+        if (StringUtils.equals("快捷快递",codeCn)){
+            this.code = "kjkd";
+        }
+        if (StringUtils.equals("优速快递",codeCn)){
+            this.code = "uc-express";
+        }
+        if (StringUtils.equals("中国邮政",codeCn)){
+            this.code = "china-post";
+        }
+        if (StringUtils.equals("德邦物流",codeCn)){
+            this.code = "deppon";
+        }
+        if (StringUtils.equals("龙邦物流",codeCn)){
+            this.code = "lbex";
+        }
+        if (StringUtils.equals("极兔速递",codeCn)){
+            this.code = "jtexpress";
+        }
+        this.codeCn = codeCn;
+    }
+
+}

+ 0 - 15
netflix-dao/src/main/java/com/cyksj/model/entity/Platform.java

@@ -1,15 +0,0 @@
-package com.cyksj.model.entity;
-
-import lombok.Getter;
-import lombok.Setter;
-
-/**
- * @author chan
- * @date 2022/9/26 5:31 PM
- */
-@Getter
-@Setter
-public class Platform extends BaseEntity {
-
-
-}

+ 19 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/StreamingAccountData.java

@@ -0,0 +1,19 @@
+package com.cyksj.model.entity;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: StreamingAccount
+ *创建者: JavaZou
+ *创建时间:2022/10/18 11:45
+ */
+@Getter
+@Setter
+public class StreamingAccountData extends AbstractBackData {
+	/**
+	 * 账户名称
+	 */
+	private String accountName;
+}

+ 18 - 0
netflix-dao/src/main/java/com/cyksj/model/entity/SysConfig.java

@@ -0,0 +1,18 @@
+package com.cyksj.model.entity;
+
+import lombok.Data;
+
+/**
+ * @author chan
+ * @date 2022/10/20 10:02 AM
+ */
+@Data
+public class SysConfig extends BaseEntity {
+
+    private String sysKey;
+
+    private String sysValue;
+
+    private String remark;
+
+}

+ 19 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqAccountIncrExpiryTime.java

@@ -0,0 +1,19 @@
+package com.cyksj.model.manage.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.List;
+
+/**
+ * @author chan
+ * @date 2022/10/25 6:54 PM
+ */
+@Getter
+@Setter
+public class ReqAccountIncrExpiryTime {
+
+    private List<Long> accounts;
+
+    private Integer days;
+}

+ 18 - 4
netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqGoodsSkuInsert.java

@@ -29,20 +29,34 @@ public class ReqGoodsSkuInsert {
          */
         private String specIds;
 
+        /**
+         * 副标题
+         */
+        private String subTitle;
+
         /**
          * 商品预览图
          */
         private String picture;
 
+        private String tags;
+
+        private BigDecimal price;
+
         /**
-         * 原价 单位分
+         * 数量
          */
-        private BigDecimal price;
+        private Integer num;
+
+        /**
+         * 月份
+         */
+        private Integer months;
 
         /**
-         * 成本 单位分
+         * 状态
          */
-        private Integer cost;
+        private Boolean status;
 
     }
 

+ 4 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqGoodsSpecSingle.java

@@ -1,5 +1,6 @@
 package com.cyksj.model.manage.request;
 
+import com.fasterxml.jackson.annotation.JsonInclude;
 import lombok.Getter;
 import lombok.Setter;
 
@@ -12,6 +13,7 @@ import javax.validation.constraints.NotNull;
  */
 @Getter
 @Setter
+@JsonInclude(JsonInclude.Include.NON_NULL)
 public class ReqGoodsSpecSingle {
 
     @NotNull(message = "请指定商品spu")
@@ -25,4 +27,6 @@ public class ReqGoodsSpecSingle {
 
     @NotBlank(message = "缺少属性名.")
     private String name;
+
+    private Integer maxId;
 }

+ 27 - 12
netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqGoodsSpuInsert.java

@@ -26,39 +26,54 @@ public class ReqGoodsSpuInsert {
     @NotBlank(message = "请填写标题")
     private String title;
 
+
+    private String logo;
+
+    private String img;
+
+    private String tags;
+
     /**
      * 缩略图
      */
     private String thumbnail;
 
+
     /**
-     * 轮播视频
+     * 详情
      */
-    private String video;
-
+    private String detail;
 
     /**
-     * 商品描述
+     * 描述
      */
-    private String desc;
-
+    private String remark;
 
     /**
-     * 轮播图
+     * true 上架 / false 下架
      */
-    private String carousel;
+    private Boolean status;
 
     /**
-     * 详情图
+     * true 存在 / false 删除
      */
-    private String details;
+    private Boolean deleted;
 
     /**
-     * 详情
+     * 分类 1账号 2.实物
      */
-    private String detail;
+    private Integer type;
 
+    /**
+     *  轮播图
+     */
+    private String banner;
 
+    /**
+     * 二级分类
+     * 虚物品 1邀请制 2非邀请制
+     */
+    private Integer secondType;
 
 
 }

+ 17 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqRenewal.java

@@ -0,0 +1,17 @@
+package com.cyksj.model.manage.request;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * @author chan
+ * @date 2022/10/18 2:27 PM
+ */
+@Getter
+@Setter
+public class ReqRenewal {
+
+    private Long skuId;
+
+    private Integer months;
+}

+ 37 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/request/ReqSetLogisticsPost.java

@@ -0,0 +1,37 @@
+package com.cyksj.model.manage.request;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.List;
+
+/**
+ * @author chan
+ * @date 2022/10/18 10:16 AM
+ */
+@Getter
+@Setter
+public class ReqSetLogisticsPost {
+
+    /**
+     * 订单id
+     */
+    private Integer orderId;
+
+    /**
+     * 物流公司简码
+     */
+    private String code;
+
+    /**
+     * 物流公司名称
+     */
+    private String codeCn;
+
+    /**
+     * 物流运单号
+     */
+    private String trackingNumber;
+
+}

+ 10 - 2
netflix-dao/src/main/java/com/cyksj/model/manage/views/AccountView.java

@@ -6,6 +6,7 @@ import com.ejlchina.searcher.bean.SearchBean;
 import lombok.Getter;
 import lombok.Setter;
 
+import java.math.BigDecimal;
 import java.util.Date;
 
 /**
@@ -14,13 +15,14 @@ import java.util.Date;
  */
 @Getter
 @Setter
-@SearchBean(tables = "account a")
+@SearchBean(tables = "account a left join goods_don g on a.goods_id = g.id " +
+        "left join groups_trips gt on gt.account_id = a.id")
 public class AccountView {
 
     @DbField("a.id")
     private Long id;
 
-    @DbField("a.platform")
+    @DbField("g.title")
     private String title;
 
     @DbField("a.account")
@@ -35,6 +37,9 @@ public class AccountView {
     @DbField("a.expiry_time")
     private Date expiryTime;
 
+    @DbField("a.amount")
+    private BigDecimal amount;
+
     /**
      * 国区id
      */
@@ -53,4 +58,7 @@ public class AccountView {
     @DbIgnore
     private Integer total;
 
+    @DbField("gt.id")
+    private Long groupsId;
+
 }

+ 23 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/views/GoodsDonViewer.java

@@ -50,6 +50,9 @@ public class GoodsDonViewer {
     @DbField("g.logo")
     private String logo;
 
+    @DbField("img")
+    private String img;
+
 
     /**
      * true 上架 / false 下架
@@ -96,6 +99,26 @@ public class GoodsDonViewer {
     @DbField("g.detail")
     private String detail;
 
+    /**
+     * 类型
+     */
+    @DbField("g.type")
+    private Integer type;
+
+    /**
+     * banner
+     */
+    @DbField("g.banner")
+    private String banner;
+
+    /**
+     * 二级分类
+     * 虚物品 1邀请制 2非邀请制
+     */
+    @DbField("g.second_type")
+    private Integer secondType;
+
+
     @DbIgnore
     private List<GoodsDonSku> skus;
 

+ 18 - 5
netflix-dao/src/main/java/com/cyksj/model/manage/views/GroupsRelationView.java

@@ -1,5 +1,6 @@
 package com.cyksj.model.manage.views;
 
+import com.cyksj.model.entity.GroupsRelation;
 import com.ejlchina.searcher.bean.DbField;
 import com.ejlchina.searcher.bean.SearchBean;
 import lombok.Getter;
@@ -13,15 +14,22 @@ import java.util.Date;
  */
 @Getter
 @Setter
-@SearchBean(tables = "groups_relation gr left join groups_trips g on gr.groups_id = g.id " +
-        "left join account a on a.id = g.account_id left join user u on gr.user_id = u.id")
+@SearchBean(tables = "groups_relation gr left join groups_trips gt on gr.groups_id = gt.id " +
+        "left join account a on a.id = gt.account_id left join user u on gr.user_id = u.id " +
+        "left join goods_don g on a.goods_id = g.id ")
 public class GroupsRelationView {
 
+    @DbField("gr.id")
+    private Long id;
+
+    @DbField("g.id")
+    private Long goodsId;
+
     @DbField("gr.groups_id")
     private Long groupsId;
 
-    @DbField("a.platform")
-    private String platform;
+    @DbField("g.title")
+    private String title;
 
     @DbField("u.nickname")
     private String nickname;
@@ -48,7 +56,7 @@ public class GroupsRelationView {
      * none 无人
      */
     @DbField("gr.status")
-    private String status;
+    private GroupsRelation.Status status;
 
     /**
      * 创建时间
@@ -56,5 +64,10 @@ public class GroupsRelationView {
     @DbField("gr.created_time")
     private Date createdTime;
 
+    /**
+     * 账号
+     */
+    @DbField("gr.account")
+    private String account;
 
 }

+ 3 - 3
netflix-dao/src/main/java/com/cyksj/model/manage/views/HomeGroupView.java

@@ -25,11 +25,11 @@ public class HomeGroupView {
     @DbField("hp.account_id")
     private Long accountId;
 
-    @DbField("sku.sepc_val")
-    private String title;
+    @DbField("sku.spec_val")
+    private String specVal;
 
     @DbField("gr.start_time")
-    private String startTime;
+    private Date startTime;
 
     @DbField("gr.user_id")
     private Long userId;

+ 43 - 0
netflix-dao/src/main/java/com/cyksj/model/manage/views/HomeUserView.java

@@ -0,0 +1,43 @@
+package com.cyksj.model.manage.views;
+
+import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.SearchBean;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * @author chan
+ * @date 2022/10/24 3:51 PM
+ */
+@Data
+@SearchBean(tables = "groups_relation gr left join groups_trips gt on gr.groups_id = gt.id " +
+        "left join goods_don_sku sku on gt.sku_id = sku.id  " +
+        "left join user u on u.id = gr.user_id " +
+        "left join home_group hp on hp.relation_id = gr.id",
+        where = "gr.status = 'validity' and  hp.id is null and sku.goods_id = 2 and gr.user_id > 0"
+)
+public class HomeUserView {
+
+    @DbField("gr.id")
+    private Long relationId;
+
+    @DbField("u.id")
+    private Long userId;
+
+    @DbField("u.nickname")
+    private String nickname;
+
+    @DbField("u.headimgurl")
+    private String headimgurl;
+
+    @DbField("gr.account")
+    private String account;
+
+    @DbField("sku.spec_val")
+    private String specVal;
+
+    @DbField("gr.expiry_time")
+    private Date expiryTime;
+
+}

+ 34 - 5
netflix-dao/src/main/java/com/cyksj/model/manage/views/OrderDonView.java

@@ -1,6 +1,9 @@
 package com.cyksj.model.manage.views;
 
+import com.cyksj.model.entity.OrderDonTransport;
+import com.cyksj.model.entity.OrderDonWaybill;
 import com.ejlchina.searcher.bean.DbField;
+import com.ejlchina.searcher.bean.DbIgnore;
 import com.ejlchina.searcher.bean.SearchBean;
 import lombok.Getter;
 import lombok.Setter;
@@ -14,23 +17,40 @@ import java.util.Date;
  */
 @Getter
 @Setter
-@SearchBean(tables = "order_don o,goods_don g,goods_don_sku sku,platform p,user u"
-        ,where = "o.sku_id = sku.id and g.id = sku.id and p.id = g.platform_id and o.user_id = u.id"
+@SearchBean(tables = "order_don o left join goods_don_sku sku on o.sku_id = sku.id " +
+        "left join goods_don g on g.id = sku.goods_id " +
+        "left join user u on o.user_id = u.id " +
+        "left join groups_relation gr on gr.id = o.relation_id "
 )
 public class OrderDonView {
 
     @DbField("o.id")
     private Long id;
 
+    @DbField("o.relation_id")
+    private Long relationId;
+
+    @DbField("gr.account")
+    private String account;
+
+    @DbField("g.type")
+    private Integer goodsDonType;
+
     @DbField("o.order_no")
     private String orderNo;
 
-    @DbField("p.title")
-    private String platform;
+    @DbField("o.transaction_id")
+    private String transactionId;
+
+    @DbField("g.logo")
+    private String logo;
 
-    @DbField("sku.title")
+    @DbField("g.title")
     private String title;
 
+    @DbField("sku.spec_val")
+    private String specVal;
+
     @DbField("u.id")
     private Long userId;
 
@@ -43,6 +63,15 @@ public class OrderDonView {
     @DbField("o.status")
     private String status;
 
+    @DbField("o.num")
+    private Integer num;
+
     @DbField("o.created_time")
     private Date createdTime;
+
+    @DbIgnore
+    private OrderDonWaybill waybill;
+
+    @DbIgnore
+    private OrderDonTransport transport;
 }

+ 1 - 1
netflix-dao/src/main/java/com/cyksj/model/manage/views/UserView.java

@@ -14,7 +14,7 @@ import lombok.Setter;
 @Getter
 @Setter
 @SearchBean(tables = "user u")
-public class UserView extends BaseEntity {
+public class UserView {
 
     /**
      * id

+ 10 - 0
netflix-dao/src/main/java/com/cyksj/model/request/OrderPayRequest.java

@@ -45,4 +45,14 @@ public class OrderPayRequest {
      * 数量
      */
     private Integer num;
+
+    /**
+     * 提交账号
+     */
+    private String account;
+
+    /**
+     * 收获地址id
+     */
+    private Long addressId;
 }

+ 258 - 0
netflix-dao/src/main/java/com/cyksj/model/request/corp/CorpXmlMessage.java

@@ -0,0 +1,258 @@
+package com.cyksj.model.request.corp;
+
+import com.cyksj.common.util.Xmls;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import lombok.Getter;
+import lombok.Setter;
+import lombok.ToString;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.Serializable;
+
+/**
+ * @author chan
+ * @date 2022/3/14 上午10:57
+ */
+@Slf4j
+@Getter
+@Setter
+@ToString
+public class CorpXmlMessage implements Serializable {
+
+	///////////////////////
+	// 以下都是微信推送过来的消息的xml的element所对应的属性
+	///////////////////////
+
+	@JacksonXmlProperty(localName = "AgentID")
+	private String agentId;
+
+	@JacksonXmlProperty(localName = "ToUserName")
+	private String toUserName;
+
+	@JacksonXmlProperty(localName = "FromUserName")
+	private String fromUserName;
+
+	@JacksonXmlProperty(localName = "CreateTime")
+	private Long createTime;
+
+	/**
+	 * <pre>
+	 * 当接受用户消息时,可能会获得以下值:
+	 * {@link WxConsts.XmlMsgType#TEXT}
+	 * {@link WxConsts.XmlMsgType#IMAGE}
+	 * {@link WxConsts.XmlMsgType#VOICE}
+	 * {@link WxConsts.XmlMsgType#VIDEO}
+	 * {@link WxConsts.XmlMsgType#LOCATION}
+	 * {@link WxConsts.XmlMsgType#LINK}
+	 * {@link WxConsts.XmlMsgType#EVENT}
+	 * 当发送消息的时候使用:
+	 * {@link WxConsts.XmlMsgType#TEXT}
+	 * {@link WxConsts.XmlMsgType#IMAGE}
+	 * {@link WxConsts.XmlMsgType#VOICE}
+	 * {@link WxConsts.XmlMsgType#VIDEO}
+	 * {@link WxConsts.XmlMsgType#NEWS}
+	 * </pre>
+	 */
+	@JacksonXmlProperty(localName = "MsgType")
+	private String msgType;
+
+	@JacksonXmlProperty(localName = "Content")
+	private String content;
+
+	@JacksonXmlProperty(localName = "MsgId")
+	private Long msgId;
+
+	@JacksonXmlProperty(localName = "PicUrl")
+	private String picUrl;
+
+	@JacksonXmlProperty(localName = "MediaId")
+	private String mediaId;
+
+	@JacksonXmlProperty(localName = "Format")
+	private String format;
+
+	@JacksonXmlProperty(localName = "ThumbMediaId")
+	private String thumbMediaId;
+
+	@JacksonXmlProperty(localName = "Location_X")
+	private Double locationX;
+
+	@JacksonXmlProperty(localName = "Location_Y")
+	private Double locationY;
+
+	@JacksonXmlProperty(localName = "Scale")
+	private Double scale;
+
+	@JacksonXmlProperty(localName = "Label")
+	private String label;
+
+	@JacksonXmlProperty(localName = "Title")
+	private String title;
+
+	@JacksonXmlProperty(localName = "Description")
+	private String description;
+
+	@JacksonXmlProperty(localName = "Url")
+	private String url;
+
+	@JacksonXmlProperty(localName = "Event")
+	private String event;
+
+	@JacksonXmlProperty(localName = "UpdateDetail")
+	private String updateDetail;
+
+	@JacksonXmlProperty(localName = "JoinScene")
+	private String joinScene;
+
+	@JacksonXmlProperty(localName = "QuitScene")
+	private String quitScene;
+
+	@JacksonXmlProperty(localName = "MemChangeCnt")
+	private String memChangeCnt;
+
+	@JacksonXmlProperty(localName = "Source")
+	private String source;
+
+	@JacksonXmlProperty(localName = "StrategyId")
+	private String strategyId;
+
+	@JacksonXmlProperty(localName = "EventKey")
+	private String eventKey;
+
+	@JacksonXmlProperty(localName = "Ticket")
+	private String ticket;
+
+	@JacksonXmlProperty(localName = "Latitude")
+	private Double latitude;
+
+	@JacksonXmlProperty(localName = "Longitude")
+	private Double longitude;
+
+	@JacksonXmlProperty(localName = "Precision")
+	private Double precision;
+
+	@JacksonXmlProperty(localName = "Recognition")
+	private String recognition;
+
+	@JacksonXmlProperty(localName = "TaskId")
+	private String taskId;
+
+	/**
+	 * 通讯录变更事件.
+	 * 请参考常量 me.chanjar.weixin.cp.constant.WxCpConsts.ContactChangeType
+	 */
+	@JacksonXmlProperty(localName = "ChangeType")
+	private String changeType;
+
+	/**
+	 * 变更信息的成员UserID.
+	 */
+	@JacksonXmlProperty(localName = "UserID")
+	private String userId;
+
+	/**
+	 * 变更信息的外部联系人的userid,注意不是企业成员的帐号.
+	 */
+	@JacksonXmlProperty(localName = "ExternalUserID")
+	private String externalUserId;
+
+	/**
+	 * 添加此用户的「联系我」方式配置的state参数,可用于识别添加此用户的渠道.
+	 */
+	@JacksonXmlProperty(localName = "State")
+	private String state;
+
+	/**
+	 * 欢迎语code,可用于发送欢迎语.
+	 */
+	@JacksonXmlProperty(localName = "WelcomeCode")
+	private String welcomeCode;
+
+	/**
+	 * 新的UserID,变更时推送(userid由系统生成时可更改一次).
+	 */
+	@JacksonXmlProperty(localName = "NewUserID")
+	private String newUserId;
+
+	/**
+	 * 客户联系回调: 客户接替失败的原因
+	 */
+	@JacksonXmlProperty(localName = "FailReason")
+	private String failReason;
+
+	/**
+	 * 客户联系回调: 标签类型
+	 */
+	@JacksonXmlProperty(localName = "TagType")
+	private String tagType;
+
+	/**
+	 * 客户联系回调 标签id
+	 */
+	@JacksonXmlProperty(localName = "Id")
+	private String id;
+
+
+	///////////////////////////////////////
+	// 群发消息返回的结果
+	///////////////////////////////////////
+	/**
+	 * 多个时间共用字段.
+	 * 1. 群发的结果.
+	 * 2. 通讯录变更事件
+	 * 激活状态:1=已激活 2=已禁用 4=未激活 已激活代表已激活企业微信或已关注微工作台(原企业号).
+	 */
+	@JacksonXmlProperty(localName = "Status")
+	private String status;
+
+	/**
+	 * group_id下粉丝数;或者openid_list中的粉丝数.
+	 */
+	@JacksonXmlProperty(localName = "TotalCount")
+	private Integer totalCount;
+
+	/**
+	 * 过滤.
+	 * (过滤是指特定地区、性别的过滤、用户设置拒收的过滤,用户接收已超4条的过滤)后,准备发送的粉丝数,原则上,filterCount = sentCount + errorCount
+	 */
+	@JacksonXmlProperty(localName = "FilterCount")
+	private Integer filterCount;
+
+	/**
+	 * 发送成功的粉丝数.
+	 */
+	@JacksonXmlProperty(localName = "SentCount")
+	private Integer sentCount;
+
+	/**
+	 * 发送失败的粉丝数.
+	 */
+	@JacksonXmlProperty(localName = "ErrorCount")
+	private Integer errorCount;
+
+
+	public static CorpXmlMessage fromXml(String xml) {
+		//修改微信变态的消息内容格式,方便解析
+		xml = xml.replace("</PicList><PicList>", "");
+		final CorpXmlMessage xmlMessage;
+		try {
+			xmlMessage = Xmls.parseObject(xml, CorpXmlMessage.class);
+			return xmlMessage;
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+
+	public static CorpXmlMessage fromXml(String xml, String agentId) {
+		//修改微信变态的消息内容格式,方便解析
+		xml = xml.replace("</PicList><PicList>", "");
+		final CorpXmlMessage xmlMessage;
+		try {
+			xmlMessage = Xmls.parseObject(xml, CorpXmlMessage.class);
+			xmlMessage.setAgentId(agentId);
+			return xmlMessage;
+		} catch (Exception e) {
+			throw new RuntimeException(e);
+		}
+	}
+}

+ 55 - 0
netflix-dao/src/main/java/com/cyksj/model/request/corp/CorpXmlOutMessage.java

@@ -0,0 +1,55 @@
+package com.cyksj.model.request.corp;
+
+import com.cyksj.common.exception.AesException;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.StringUtil;
+import com.cyksj.common.util.Xmls;
+import com.cyksj.common.util.corp.WxCryptUtil;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlCData;
+import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+
+/**
+ * @author chan
+ * @date 2022/3/14 上午10:38
+ */
+@Getter
+@Setter
+public class CorpXmlOutMessage implements Serializable {
+
+	@JacksonXmlCData
+	@JacksonXmlProperty(localName = "ToUserName")
+	protected String toUserName;
+
+	@JacksonXmlCData
+	@JacksonXmlProperty(localName = "FromUserName")
+	protected String fromUserName;
+
+	@JacksonXmlCData
+	@JacksonXmlProperty(localName = "CreateTime")
+	protected Long createTime;
+
+	@JacksonXmlCData
+	@JacksonXmlProperty(localName = "MsgType")
+	protected String msgType;
+
+	protected String toXml() {
+		try {
+			return Xmls.toXml(this);
+		} catch (JsonProcessingException e) {
+			throw BusinessRuntimeException.getInstance("企业微信 xml转换error:" + StringUtil.getErrorText(e));
+		}
+	}
+
+	/**
+	 * 转换成加密的xml格式.
+	 */
+	public String toEncryptedXml(WxCryptUtil wxCryptUtil) throws AesException {
+		String plainXml = toXml();
+		return wxCryptUtil.encrypt(plainXml);
+	}
+}

+ 89 - 0
netflix-dao/src/main/java/com/cyksj/model/response/Callback.java

@@ -0,0 +1,89 @@
+package com.cyksj.model.response;
+
+import lombok.Getter;
+
+/**
+ * @author valor.
+ * @date 2019-07-23 14:56
+ */
+@Getter
+public class Callback<T> {
+
+    /**
+     * 请求是否成功
+     */
+    private boolean success;
+
+    /**
+     * 页面转跳参数
+     */
+    private int code;
+
+    /**
+     * 返回的消息
+     */
+    private String message;
+
+    /**
+     * 返回的数据
+     */
+    private T value;
+
+
+    /**
+     * 返回subCode
+     */
+    private Integer subCode;
+
+    /**
+     * 返回信息
+     */
+    private String subMsg;
+
+
+    public Callback() { }
+
+    private Callback(boolean result) {
+        this.success = result;
+        this.message = "";
+        this.code = result ? 1 : 0;
+    }
+
+    public static <T> Callback<T> success() {
+        return new Callback<>(true);
+    }
+
+    public static <T> Callback<T> fail() {
+        return new Callback<>(false);
+    }
+
+    public Callback<T> setCode(int code) {
+        this.code = code;
+        return this;
+    }
+
+    public Callback<T> setSuccess(Boolean success){
+        this.success = success;
+        return this;
+    }
+
+    public Callback<T> setMsg(String msg) {
+        this.message = msg;
+        return this;
+    }
+
+    public Callback<T> setData(T data) {
+        this.value = data;
+        return this;
+    }
+
+    public Callback<T> setSubCode(int subCode) {
+        this.subCode = subCode;
+        return this;
+    }
+
+    public Callback<T> setSubMsg(String subMsg) {
+        this.subMsg = subMsg;
+        return this;
+    }
+}

+ 23 - 0
netflix-dao/src/main/java/com/cyksj/model/response/CorpExternalContactInfo.java

@@ -0,0 +1,23 @@
+package com.cyksj.model.response;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author chan
+ * @date 2022/3/14 下午4:33
+ */
+@Data
+public class CorpExternalContactInfo implements Serializable {
+    @JsonProperty("external_contact")
+    private ExternalContact externalContact;
+
+    @JsonProperty("follow_user")
+    private List<FollowedUser> followedUsers;
+
+    @JsonProperty("next_cursor")
+    private String nextCursor;
+}

+ 66 - 0
netflix-dao/src/main/java/com/cyksj/model/response/CorpUserExternalTagGroupList.java

@@ -0,0 +1,66 @@
+package com.cyksj.model.response;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author chan
+ * @date 2022/3/24 下午2:29
+ */
+@Data
+public class CorpUserExternalTagGroupList implements Serializable {
+    @JsonProperty("tag_group")
+    private List<TagGroup> tagGroupList;
+
+    @Getter
+    @Setter
+    public static class TagGroup implements Serializable {
+        private static final long serialVersionUID = -4301684507150486556L;
+
+        @JsonProperty("group_id")
+        private String groupId;
+
+        @JsonProperty("group_name")
+        private String groupName;
+
+        @JsonProperty("create_time")
+        private Long createTime;
+
+        @JsonProperty("order")
+        private Long order;
+
+        @JsonProperty("deleted")
+        private Boolean deleted;
+
+
+        @JsonProperty("tag")
+        private List<Tag> tag;
+
+        @Getter
+        @Setter
+        public static class Tag implements Serializable {
+            private static final long serialVersionUID = -4301684507150486556L;
+
+            @JsonProperty("id")
+            private String id;
+
+            @JsonProperty("name")
+            private String name;
+
+            @JsonProperty("create_time")
+            private Long createTime;
+
+            @JsonProperty("order")
+            private Long order;
+
+            @JsonProperty("deleted")
+            private Boolean deleted;
+
+        }
+    }
+}

+ 69 - 0
netflix-dao/src/main/java/com/cyksj/model/response/CorpUserInfo.java

@@ -0,0 +1,69 @@
+package com.cyksj.model.response;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author chan
+ * @date 2022/3/16 下午1:44
+ */
+@Data
+public class CorpUserInfo implements Serializable {
+
+
+    private String userid;
+
+    /**
+     * 名称
+     */
+    private String name;
+
+    /**
+     * 职位
+     */
+    private String position;
+    /**
+     * 手机
+     */
+    private String mobile;
+
+    /**
+     * 性别
+     */
+    private String gender;
+
+    /**
+     * 邮箱
+     */
+    private String email;
+
+    /**
+     * 企业邮箱
+     */
+    @JsonProperty(value = "biz_mail")
+    private String bizMail;
+    /**
+     * 头像
+     */
+    private String avatar;
+
+    /**
+     * 头像缩略图
+     */
+    private String thumbAvatar;
+
+    /**
+     * 地址。长度最大128个字符
+     */
+    private String address;
+
+    /**
+     * 激活状态: 1=已激活,2=已禁用,4=未激活,5=退出企业。
+     */
+    private Integer status;
+
+
+
+}

+ 122 - 0
netflix-dao/src/main/java/com/cyksj/model/response/ExternalContact.java

@@ -0,0 +1,122 @@
+package com.cyksj.model.response;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.*;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author chan
+ * @date 2022/3/14 下午4:34
+ */
+@Getter
+@Setter
+public class ExternalContact {
+    @JsonProperty("external_userid")
+    private String externalUserId;
+
+    @JsonProperty("position")
+    private String position;
+
+    @JsonProperty("name")
+    private String name;
+
+    @JsonProperty("nickname")
+    private String nickname;
+
+    @JsonProperty("avatar")
+    private String avatar;
+
+    @JsonProperty("corp_name")
+    private String corpName;
+
+    @JsonProperty("corp_full_name")
+    private String corpFullName;
+
+    @JsonProperty("type")
+    private Integer type;
+
+    @JsonProperty("gender")
+    private Integer gender;
+
+    @JsonProperty("unionid")
+    private String unionId;
+
+    @JsonProperty("external_profile")
+    private ExternalProfile externalProfile;
+
+    @Data
+    public static class ExternalProfile implements Serializable {
+        private static final long serialVersionUID = -2899906589789022765L;
+
+        @JsonProperty("external_corp_name")
+        private String externalCorpName;
+
+        @JsonProperty("wechat_channels")
+        private WechatChannel wechatChannels;
+
+        @JsonProperty("external_attr")
+        private List<ExternalAttribute> externalAttrs;
+    }
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class WechatChannel implements Serializable {
+
+        @JsonProperty("nickname")
+        private String nickname;
+
+        @JsonProperty("status")
+        private Integer status;
+
+    }
+
+    @Data
+    @Builder
+    @NoArgsConstructor
+    @AllArgsConstructor
+    public static class ExternalAttribute implements Serializable {
+        private static final long serialVersionUID = -1262278808286421085L;
+
+        private int type;
+
+        private String name;
+
+        private Text text;
+
+        private Web web;
+
+        @JsonProperty("miniprogram")
+        private MiniProgram miniProgram;
+
+        @Data
+        public static class Text implements Serializable {
+            private static final long serialVersionUID = -8161579335600269094L;
+
+            private String value;
+        }
+
+        @Data
+        public static class Web implements Serializable {
+            private static final long serialVersionUID = 3664557135411521862L;
+
+            private String title;
+            private String url;
+        }
+
+        @Data
+        public static class MiniProgram implements Serializable {
+            private static final long serialVersionUID = -5329210594501835796L;
+
+            @JsonProperty("pagepath")
+            private String pagePath;
+
+            private String appid;
+
+            private String title;
+        }
+    }
+}

+ 80 - 0
netflix-dao/src/main/java/com/cyksj/model/response/FollowedUser.java

@@ -0,0 +1,80 @@
+package com.cyksj.model.response;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author chan
+ * @date 2022/3/14 下午5:48
+ */
+@Data
+public class FollowedUser implements Serializable {
+
+    @JsonProperty("userid")
+    private String userId;
+
+    private String remark;
+
+    private String description;
+
+    @JsonProperty("createtime")
+    private Long createTime;
+
+    private String state;
+
+    @JsonProperty("remark_company")
+    private String remarkCompany;
+
+    @JsonProperty("remark_mobiles")
+    private String[] remarkMobiles;
+
+    /**
+     * 批量获取客户详情 接口专用
+     */
+    @JsonProperty("tag_id")
+    private String[] tagIds;
+
+    /**
+     * 获取客户详情  接口专用
+     */
+    private Tag[] tags;
+
+    @JsonProperty("remark_corp_name")
+    private String remarkCorpName;
+
+    @JsonProperty("add_way")
+    private String addWay;
+
+    @JsonProperty("oper_userid")
+    private String operatorUserId;
+
+    @Data
+    public static class Tag implements Serializable {
+        private static final long serialVersionUID = -7556237053703295482L;
+
+        /**
+         * 该成员添加此外部联系人所打标签的分组名称(标签功能需要企业微信升级到2.7.5及以上版本)
+         */
+        @JsonProperty("group_name")
+        private String groupName;
+
+        /**
+         * 该成员添加此外部联系人所打标签名称
+         */
+        @JsonProperty("tag_name")
+        private String tagName;
+
+        /**
+         * 该成员添加此外部联系人所打企业标签的id,仅企业设置(type为1)的标签返回
+         */
+        @JsonProperty("tag_id")
+        private String tagId;
+
+        /**
+         * 该成员添加此外部联系人所打标签类型, 1-企业设置, 2-用户自定义
+         */
+        private int type;
+    }
+}

+ 26 - 0
netflix-dao/src/main/java/com/cyksj/model/response/UserExternalContactList.java

@@ -0,0 +1,26 @@
+package com.cyksj.model.response;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author chan
+ * @date 2022/3/16 下午2:20
+ */
+@Data
+public class UserExternalContactList implements Serializable {
+
+    @JsonProperty("errcode")
+    private Long errCode;
+    @JsonProperty("errmsg")
+
+    private String errMsg;
+
+    @JsonProperty("external_userid")
+    private List<String> externalUserId = null;
+
+
+}

+ 25 - 0
netflix-dao/src/main/java/com/cyksj/model/response/UserWithExternalPermission.java

@@ -0,0 +1,25 @@
+package com.cyksj.model.response;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author chan
+ * @date 2022/3/16 下午12:24
+ */
+@Data
+public class UserWithExternalPermission implements Serializable {
+
+	@JsonProperty("errcode")
+	private Long errCode;
+	@JsonProperty("errmsg")
+
+	private String errMsg;
+
+	@JsonProperty("follow_user")
+	private List<String> followers = null;
+
+}

+ 61 - 0
netflix-dao/src/main/java/com/cyksj/model/views/BackgroundDataView.java

@@ -0,0 +1,61 @@
+package com.cyksj.model.views;
+
+import com.cyksj.model.entity.AppleOneData;
+import com.cyksj.model.entity.StreamingAccountData;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: NetflixDataViews
+ *创建者: JavaZou
+ *创建时间:2022/10/17 14:09
+ * 数据统计展示类
+ */
+@Setter
+@Getter
+public class BackgroundDataView {
+	/**
+	 * 总用户数
+	 */
+	private Integer totalNumOfUser;
+
+	/**
+	 * 总订单数
+	 */
+	private Integer totalNumOfOrder;
+
+	/**
+	 * 总订单金额
+	 */
+	private BigDecimal totalOrderAmount;
+
+	/**
+	 * 近5天将要到期的主账号总数
+	 */
+	private Integer totalNumOfWillExpireAccount;
+
+	/**
+	 * 已到期主账号总数
+	 */
+	private Integer totalExpiredAccountNum;
+
+	/**
+	 * 到期子账号总数
+	 */
+	private Integer totalNumOfExpiredSubAccount;
+
+	/**
+	 * apple one数据
+	 */
+	private List<AppleOneData> appleOneDataViews;
+
+	/**
+	 * 流媒体账号数据
+	 */
+	private List<StreamingAccountData> streamAccountDataViews;
+
+}

+ 9 - 3
netflix-dao/src/main/java/com/cyksj/model/views/GroupsView.java

@@ -1,6 +1,6 @@
 package com.cyksj.model.views;
 
-import com.cyksj.model.entity.GroupsRelation;
+import com.cyksj.model.manage.views.GroupsRelationView;
 import com.ejlchina.searcher.bean.DbField;
 import com.ejlchina.searcher.bean.DbIgnore;
 import com.ejlchina.searcher.bean.SearchBean;
@@ -15,7 +15,7 @@ import java.util.List;
  */
 @Getter
 @Setter
-@SearchBean(tables = "groups_trips g")
+@SearchBean(tables = "groups_trips g ")
 public class GroupsView {
 
     @DbField("g.id")
@@ -30,6 +30,12 @@ public class GroupsView {
     @DbField("g.num")
     private Integer num;
 
+    /**
+     * 可用车位数
+     */
+    @DbField("g.available_num")
+    private Integer availableNum;
+
     /**
      * 状态
      */
@@ -46,6 +52,6 @@ public class GroupsView {
      * 关系
      */
     @DbIgnore
-    private List<GroupsRelation> relations;
+    private List<GroupsRelationView> relations;
 
 }

+ 25 - 4
netflix-dao/src/main/java/com/cyksj/model/views/RenewalView.java

@@ -11,15 +11,28 @@ import java.util.Date;
  * @author chan
  * @date 2022/9/27 11:54 AM
  */
-@SearchBean(tables = "groups_relation gr left join groups_trips g on g.id = gr.groups_id" +
-        "left join goods_don_sku sku on g.sku_id = sku.id " +
-        "left join goods_don g on g.id = sku.goods_id")
+@SearchBean(tables = "groups_relation gr left join groups_trips gt on gt.id = gr.groups_id " +
+        "left join account a on a.id = gt.account_id " +
+        "left join goods_don_sku sku on gt.sku_id = sku.id " +
+        "left join goods_don g on g.id = sku.goods_id " )
 @Getter
 @Setter
 public class RenewalView {
 
+    @DbField("g.id")
+    private Long goodsId;
+
+    @DbField("sku.id")
+    private Long skuId;
+
+    @DbField("gr.id")
+    private Long relationId;
+
+    @DbField("gr.num")
+    private Integer num;
+
     @DbField("gr.groups_id")
-    private String groupId;
+    private Long groupId;
 
     @DbField("g.title")
     private String title;
@@ -27,6 +40,9 @@ public class RenewalView {
     @DbField("g.logo")
     private String logo;
 
+    @DbField("g.img")
+    private String img;
+
     @DbField("gr.user_id")
     private Long userId;
 
@@ -36,4 +52,9 @@ public class RenewalView {
     @DbField("gr.status")
     private String status;
 
+    @DbField("a.account")
+    private String account;
+
+    @DbField("a.password")
+    private String password;
 }

+ 15 - 0
netflix-dao/src/main/resources/mapper/AccountMapper.xml

@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.cyksj.mapper.AccountMapper">
+
+    <select id="getNumOfUser" resultType="java.lang.Integer">
+        select distinct u.id from `groups_trips` gt inner join `groups_relation` gr on gr.groups_id = gt.id
+        inner join `user` u on u.id = gr.user_id
+        where gt.account_id in
+        <foreach collection="list" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+        and gt.status = 'validity'
+        and u.created_time between #{yesZeroDate} and #{thisZeroDate}
+    </select>
+</mapper>

+ 19 - 0
netflix-dao/src/main/resources/mapper/OrderDonMapper.xml

@@ -17,4 +17,23 @@
         </if>
 
     </select>
+
+    <select id="getAppleOneOrderDons" resultType="com.cyksj.model.entity.OrderDon">
+        select distinct s.* from (select id,user_id,money from `order_don`
+        where sku_id in
+        <foreach collection="skuIds" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+        and status not in
+        <foreach collection="noOrderStatus" item="item" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+        and pay_time between #{yesZeroDate} and #{thisZeroDate})s
+        inner join `groups_relation` gr
+        on gr.user_id = s.user_id
+        inner join `groups_trips` gt
+        on gt.id = gr.groups_id
+        inner join `account` a on a.id = gt.account_id
+        where a.title = #{appleOne} and gr.status = 'validity'
+    </select>
 </mapper>

+ 39 - 0
netflix-service/src/main/java/com/cyksj/config/corp/BaseWxCorpConfig.java

@@ -0,0 +1,39 @@
+package com.cyksj.config.corp;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/*
+ *项目名: netflix
+ *文件名: BaseWxCorpConfig
+ *创建者: JavaZou
+ *创建时间:2022/10/13 15:06
+ */
+@Setter
+@Getter
+public abstract class BaseWxCorpConfig {
+	/**
+	 * 企业微信应用唯一标识
+	 */
+	private String corpId;
+
+	/**
+	 * 企业微信应用唯一标识 对应key
+	 */
+	private String corpSecret;
+
+	/**
+	 *
+	 */
+	private String token;
+
+	/**
+	 *
+	 */
+	private String encodingAESKey;
+
+	/**
+	 * 公众号授权域名
+	 */
+	private String domain;
+}

+ 32 - 0
netflix-service/src/main/java/com/cyksj/config/corp/WxCorpFactory.java

@@ -0,0 +1,32 @@
+package com.cyksj.config.corp;
+
+import cn.hutool.core.util.StrUtil;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+
+/*
+ *项目名: netflix
+ *文件名: WxCorpFactory
+ *创建者: JavaZou
+ *创建时间:2022/10/13 15:18
+ */
+public class WxCorpFactory {
+
+	private static Map<String, BaseWxCorpConfig> wxCorpBean = new ConcurrentHashMap<>();
+
+	/**
+	 * 获取企业微信
+	 */
+	public static BaseWxCorpConfig getBaseWxCorpConfig(String corpId) {
+		if (StrUtil.isEmpty(corpId)) {
+			return null;
+		}
+		return Optional.ofNullable(wxCorpBean.get(corpId)).orElse(null);
+	}
+
+	public static void add(BaseWxCorpConfig baseWxCorpConfig) {
+		wxCorpBean.put(baseWxCorpConfig.getCorpId(), baseWxCorpConfig);
+	}
+}

+ 22 - 0
netflix-service/src/main/java/com/cyksj/config/corp/YHLXWxCorpConfig.java

@@ -0,0 +1,22 @@
+package com.cyksj.config.corp;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.PostConstruct;
+
+/*
+ *项目名: netflix
+ *文件名: A
+ *创建者: JavaZou
+ *创建时间:2022/10/13 15:04
+ */
+@Configuration
+@ConfigurationProperties(prefix = "yhlx")
+public class YHLXWxCorpConfig extends BaseWxCorpConfig {
+
+	@PostConstruct
+	public void add() {
+		WxCorpFactory.add(this);
+	}
+}

+ 27 - 0
netflix-service/src/main/java/com/cyksj/redis/RedisService.java

@@ -1,6 +1,8 @@
 package com.cyksj.redis;
 
 import com.cyksj.common.util.StringUtil;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
 import org.springframework.data.redis.core.RedisTemplate;
 import org.springframework.stereotype.Service;
 
@@ -571,4 +573,29 @@ public class RedisService {
             return 0L;
         }
     }
+
+    @AllArgsConstructor
+    @Getter
+    public enum key {
+
+	    CORP_AUTH_MAPPING_KEY("mapping:corp:", "企业微信授权跳转", 60 * 60 * 24L),
+	    CORP_ACCESSO_TOKEN_KEY("corp:access_token:", "corp_access_token", 60 * 30L),
+	    CORP_JS_TICKET_KEY("corp_wechat:js_ticket:", "js_ticket", 60 * 30L),
+	    CORP_AGENT_JS_TICKET_KEY("corp_wechat:js_ticket:agent:", "js_ticket", 60 * 30L),
+	    MAPPING_INDEX_KEY("mapper:index:", "授权跳转", 60 * 10L),
+	    CACHE_HEAR_DATA_KEY("cache:head:data:%s", "缓存头部数据", 60 * 60 * 24l)
+        ;
+
+        private String name;
+
+        private String desc;
+
+        private long timeout;
+
+
+        public String getNameFormat(Object str) {
+            return String.format(this.getName(), str);
+        }
+
+    }
 }

+ 28 - 0
netflix-service/src/main/java/com/cyksj/service/corp/CorpService.java

@@ -0,0 +1,28 @@
+package com.cyksj.service.corp;
+
+import com.cyksj.dto.CorpOauth2UserInfo;
+import com.cyksj.model.entity.CorpFollow;
+
+/*
+ *项目名: netflix
+ *文件名: CorpService
+ *创建者: JavaZou
+ *创建时间:2022/10/13 14:58
+ */
+public interface CorpService {
+	String VerifyURL(String msgSignature, String timestamp, String nonce, String echoStr) throws Exception;
+
+	String corpMsg(String msgSignature, String timestamp, String nonce, String content) throws Exception;
+
+	String dataInitByCorpId(String corpId) throws Exception;
+
+	String createUrl(String corpId, String state);
+
+	CorpOauth2UserInfo getUserInfo(String corpId, String code) throws Exception;
+
+	CorpFollow saveFollowUser(String corpId, CorpOauth2UserInfo corpOauth2UserInfo) throws Exception;
+
+	String getJsTicket(String corpId) throws Exception;
+
+	String getAgentJsTicket(String corpId, String agentId) throws Exception;
+}

+ 77 - 0
netflix-service/src/main/java/com/cyksj/service/corp/WxCorpOps.java

@@ -0,0 +1,77 @@
+package com.cyksj.service.corp;
+
+import com.cyksj.dto.CorpOauth2UserInfo;
+import com.cyksj.model.response.CorpExternalContactInfo;
+import com.cyksj.model.response.CorpUserExternalTagGroupList;
+import com.cyksj.model.response.CorpUserInfo;
+
+import java.util.List;
+
+/*
+ *项目名: netflix
+ *文件名: WxCorpOps
+ *创建者: JavaZou
+ *创建时间:2022/10/13 16:27
+ */
+public interface WxCorpOps {
+	/**
+	 * 获取客户详情
+	 *
+	 * @param corpId
+	 * @param userId
+	 * @return
+	 */
+	CorpExternalContactInfo getExternalContact(String corpId, String userId) throws Exception;
+
+	/**
+	 * 通过企业微信id 获取access_token
+	 *
+	 * @param corpId
+	 * @return
+	 * @throws Exception
+	 */
+	String getAccessToken(String corpId) throws Exception;
+
+	/**
+	 * 获取企业标签库
+	 *
+	 * @author chan
+	 * @date 2022-03-24 下午2:30
+	 */
+	CorpUserExternalTagGroupList getCorpTagList(String corpId, List<String> tagIds, List<String> groupIds) throws Exception;
+
+	/**
+	 * 获取配置客户功能成员列表
+	 */
+	List<String> getFollowUserList(String corpId) throws Exception;
+
+	/**
+	 * 客户联系功能的成员列表
+	 */
+	CorpUserInfo getFollowUser(String corpId, String userId) throws Exception;
+
+	/**
+	 * 获取客户列表
+	 */
+	List<String> listExternalContacts(String corpId, String userId) throws Exception;
+
+	/**
+	 * 获取授权链接
+	 */
+	String createUrl(String corpId, String state);
+
+	/**
+	 * 获取成员信息
+	 */
+	CorpOauth2UserInfo getUserInfo(String corpId, String code) throws Exception;
+
+	/**
+	 * 企业微信获取js_ticket
+	 */
+	String getJsTicket(String corpId) throws Exception;
+
+	/**
+	 * 企业微信获取应用js_ticket
+	 */
+	String getAgentJsTicket(String corpId, String agentId) throws Exception;
+}

+ 245 - 0
netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpEventActionServiceImpl.java

@@ -0,0 +1,245 @@
+package com.cyksj.service.corp.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.mapper.UserMapper;
+import com.cyksj.mapper.corp.*;
+import com.cyksj.model.entity.*;
+import com.cyksj.model.request.corp.CorpXmlMessage;
+import com.cyksj.model.request.corp.CorpXmlOutMessage;
+import com.cyksj.model.response.CorpExternalContactInfo;
+import com.cyksj.model.response.CorpUserExternalTagGroupList;
+import com.cyksj.model.response.ExternalContact;
+import com.cyksj.model.response.FollowedUser;
+import com.cyksj.service.corp.WxCorpOps;
+import com.cyksj.service.corp.msg.CorpEventActionService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/*
+ *项目名: netflix
+ *文件名: CorpEventActionServiceImpl
+ *创建者: JavaZou
+ *创建时间:2022/10/13 16:11
+ */
+@Service
+@RequiredArgsConstructor
+public class CorpEventActionServiceImpl implements CorpEventActionService {
+
+	private final WxCorpOps wxCorpOps;
+
+	private final CorpUserMapper corpUserMapper;
+
+	private final CorpUserTagMapper corpUserTagMapper;
+
+	private final CorpUserFollowRelationMapper relationMapper;
+
+	private final UserMapper userMapper;
+
+	private final CorpTagGroupMapper corpTagGroupMapper;
+
+	private final CorpTagMapper corpTagMapper;
+
+	/**
+	 * 客户添加成员
+	 */
+	@Override
+	public CorpXmlOutMessage addExternalContact(String corpId, String userId, String externalUserId, String welcomeCode, Map<String, Object> context) throws Exception {
+		//1.从企业微信获取客户信息
+		CorpExternalContactInfo externalContact = wxCorpOps.getExternalContact(corpId, externalUserId);
+		ExternalContact corpUserInfo = externalContact.getExternalContact();
+		//查询客户是否存在
+		CorpUser corpUser = Optional.ofNullable(
+				corpUserMapper.selectOne(Wrappers.lambdaQuery(CorpUser.class)
+						.eq(CorpUser::getUnionid, corpUserInfo.getUnionId())))
+				.orElseGet(() -> new CorpUser()
+						.setUnionid(corpUserInfo.getUnionId()));
+
+		corpUser.setName(corpUserInfo.getName());
+		corpUser.setGender(corpUserInfo.getGender());
+		corpUser.setAvatar(corpUserInfo.getAvatar());
+		corpUser.setExternalUserid(corpUserInfo.getExternalUserId());
+		corpUser.setType(corpUserInfo.getType());
+
+		//新增修改客户信息
+		if (corpUser.getId() == null) {
+			//查询是否已微信授权,关联user表id
+			User user = userMapper.selectOne(Wrappers.lambdaQuery(User.class).eq(User::getUnionid, corpUser.getUnionid()));
+			if (user != null) {
+				corpUser.setUserId(user.getId());
+			}
+			corpUserMapper.insert(corpUser);
+		} else {
+			corpUserMapper.updateById(corpUser);
+		}
+		//2.客户添加成员信息
+		List<FollowedUser> followedUsers = externalContact.getFollowedUsers();
+
+		Set<String> relationFollowUserIds = relationMapper.selectList(Wrappers.lambdaQuery(CorpUserFollowRelation.class)
+				.select(CorpUserFollowRelation::getFollowId)
+				.eq(CorpUserFollowRelation::getCorpUserId, corpUserInfo.getExternalUserId())).stream().map(CorpUserFollowRelation::getFollowId).collect(Collectors.toSet());
+
+		followedUsers.stream()
+				.filter((followedUser) -> !relationFollowUserIds.contains(followedUser.getUserId()))
+				.forEach(followedUser -> updateUserFollowRelation(followedUser, corpUser.getExternalUserid()));
+
+		return null;
+	}
+
+	/**
+	 * 修改外部联系人的备注、手机号或标签
+	 */
+	@Override
+	public CorpXmlOutMessage editExternalContact(CorpXmlMessage message, Map<String, Object> context) throws Exception {
+		//客户id
+		String externalUserId = message.getExternalUserId();
+		//成员id
+		String userId = message.getUserId();
+		CorpExternalContactInfo externalContact = wxCorpOps.getExternalContact(message.getToUserName(), externalUserId);
+		Map<String, List<FollowedUser>> followedUserMap = externalContact.getFollowedUsers().stream().collect(Collectors.groupingBy(FollowedUser::getUserId));
+		FollowedUser followedUser = followedUserMap.get(userId).get(0);
+		//修改客户关系
+		updateUserFollowRelation(followedUser, externalUserId);
+		return null;
+	}
+
+	/**
+	 * 删除企业客户事件
+	 */
+	@Override
+	public CorpXmlOutMessage delExternalContact(CorpXmlMessage message, Map<String, Object> context) {
+		//客户id
+		String externalUserId = message.getExternalUserId();
+		//成员id
+		String userId = message.getUserId();
+		corpUnfriend(externalUserId, userId, userId);
+		return null;
+	}
+
+	/**
+	 * 删除跟进成员事件
+	 */
+	@Override
+	public CorpXmlOutMessage delFollowUser(CorpXmlMessage message, Map<String, Object> context) {
+		//客户id
+		String externalUserId = message.getExternalUserId();
+		//成员id
+		String userId = message.getUserId();
+		corpUnfriend(externalUserId, userId, externalUserId);
+		return null;
+	}
+
+	/**
+	 * 企业微信客户标签创建事件
+	 */
+	@Override
+	public CorpXmlOutMessage saveCorpTag(CorpXmlMessage message, Map<String, Object> context) throws Exception {
+		CorpUserExternalTagGroupList tagInfo = null;
+		if (message.getTagType().equals("tag")) {
+			tagInfo = wxCorpOps.getCorpTagList(message.getToUserName(), List.of(message.getId()), Collections.emptyList());
+		} else if (message.getTagType().equals("tag_group")) {
+			tagInfo = wxCorpOps.getCorpTagList(message.getToUserName(), Collections.emptyList(), List.of(message.getId()));
+		}
+		//落库
+		if (tagInfo != null) {
+			updateCorpTagGroup(tagInfo);
+		}
+		return null;
+	}
+
+	/**
+	 * 企业微信客户标签删除事件
+	 */
+	@Override
+	public CorpXmlOutMessage delCorpTag(CorpXmlMessage message, Map<String, Object> context) {
+		if (message.getTagType().equals("tag")) {
+			corpTagMapper.deleteById(message.getId());
+		} else if (message.getTagType().equals("tag_group")) {
+			corpTagGroupMapper.deleteById(message.getId());
+			corpTagMapper.deleteById(message.getId());
+		}
+		return null;
+	}
+
+	/**
+	 * 修改客户成员关系,客户标签
+	 */
+	@Transactional(rollbackFor = Throwable.class)
+	public void updateUserFollowRelation(FollowedUser followedUser, String externalUserid) {
+		CorpUserFollowRelation relation = Optional.ofNullable(relationMapper
+				.selectOne(Wrappers.lambdaQuery(CorpUserFollowRelation.class)
+						.eq(CorpUserFollowRelation::getCorpUserId, externalUserid)
+						.eq(CorpUserFollowRelation::getFollowId, followedUser.getUserId())
+						.last("limit 1"))).orElse(new CorpUserFollowRelation().setFollowId(followedUser.getUserId()).setCorpUserId(externalUserid));
+		//存储关系表
+		relation.setRemark(followedUser.getRemark());
+		relation.setDescription(followedUser.getDescription());
+		relation.setAddCreatedTime(new Date(followedUser.getCreateTime() * 1000));
+		relation.setRemarkMobiles(Arrays.toString(followedUser.getRemarkMobiles()));
+		relation.setAddWay(CorpUserFollowRelation.Way.getDesc(followedUser.getAddWay()));
+		relation.setOperUserid(followedUser.getOperatorUserId());
+		if (relation.getId() == null) relationMapper.insert(relation);
+		else relationMapper.updateById(relation);
+		corpUserTagMapper.delete(Wrappers.lambdaQuery(CorpUserTag.class).eq(CorpUserTag::getRelationId, relation.getId()));
+
+		//存储用户标签
+		Stream.of(followedUser.getTags()).forEach((tag) -> {
+			CorpUserTag corpUserTag = new CorpUserTag();
+			corpUserTag.setRelationId(relation.getId());
+			corpUserTag.setGroupName(tag.getGroupName());
+			corpUserTag.setTagName(tag.getTagName());
+			corpUserTag.setTagId(tag.getTagId());
+			corpUserTag.setType(tag.getType());
+			corpUserTagMapper.insert(corpUserTag);
+		});
+	}
+
+	/**
+	 * 取消好友关系
+	 */
+	public void corpUnfriend(String externalUserId, String userId, String delUserId) {
+
+		CorpUserFollowRelation relation = relationMapper
+				.selectOne(Wrappers.lambdaQuery(CorpUserFollowRelation.class)
+						.eq(CorpUserFollowRelation::getCorpUserId, externalUserId)
+						.eq(CorpUserFollowRelation::getFollowId, userId)
+						.last("limit 1"));
+		if (relation == null) {
+			return;
+		}
+		relation.setStatus(0);
+		relation.setDelUserid(delUserId);
+		relationMapper.updateById(relation);
+	}
+
+	public void updateCorpTagGroup(CorpUserExternalTagGroupList tagInfo) {
+		tagInfo.getTagGroupList().forEach((tagGroup) -> {
+			CorpTagGroup corpTagGroup = Optional.ofNullable(corpTagGroupMapper.selectOne(Wrappers.lambdaQuery(CorpTagGroup.class).eq(CorpTagGroup::getGroupId, tagGroup.getGroupId()))).orElseGet(() -> {
+				CorpTagGroup cor = new CorpTagGroup();
+				cor.setGroupId(tagGroup.getGroupId());
+				return cor;
+			});
+			BeanUtil.copyProperties(tagGroup, corpTagGroup);
+			if (corpTagGroup.getId() == null) corpTagGroupMapper.insert(corpTagGroup);
+			else corpTagGroupMapper.updateById(corpTagGroup);
+			List<CorpUserExternalTagGroupList.TagGroup.Tag> tagList = tagGroup.getTag();
+			tagList.forEach((tag) -> {
+				CorpTag corpTag = Optional.ofNullable(corpTagMapper.selectOne(Wrappers.lambdaQuery(CorpTag.class).eq(CorpTag::getTagId, tag.getId()))).orElseGet(() -> {
+					CorpTag cTag = new CorpTag();
+					cTag.setTagId(tag.getId());
+					return cTag;
+				});
+				corpTag.setGroupId(corpTagGroup.getGroupId());
+				corpTag.setGroupName(corpTagGroup.getGroupName());
+				corpTag.setName(tag.getName());
+				if (corpTag.getId() == null) corpTagMapper.insert(corpTag);
+				else corpTagMapper.updateById(corpTag);
+			});
+		});
+	}
+}

+ 272 - 0
netflix-service/src/main/java/com/cyksj/service/corp/impl/CorpServiceImpl.java

@@ -0,0 +1,272 @@
+package com.cyksj.service.corp.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
+import com.cyksj.common.util.ListsUtil;
+import com.cyksj.common.util.Xmls;
+import com.cyksj.common.util.corp.WxCryptUtil;
+import com.cyksj.config.corp.BaseWxCorpConfig;
+import com.cyksj.config.corp.WxCorpFactory;
+import com.cyksj.config.corp.YHLXWxCorpConfig;
+import com.cyksj.dto.CorpOauth2UserInfo;
+import com.cyksj.mapper.corp.CorpFollowMapper;
+import com.cyksj.model.dto.WxCorpEncryptDto;
+import com.cyksj.model.entity.CorpFollow;
+import com.cyksj.model.request.corp.CorpXmlMessage;
+import com.cyksj.model.request.corp.CorpXmlOutMessage;
+import com.cyksj.model.response.CorpUserInfo;
+import com.cyksj.redis.RedisService;
+import com.cyksj.service.corp.CorpService;
+import com.cyksj.service.corp.WxCorpOps;
+import com.cyksj.service.corp.msg.CorpEventActionService;
+import com.cyksj.service.corp.msg.CorpMessageHandler;
+import com.cyksj.service.corp.msg.CorpMessageRouter;
+import com.cyksj.util.WxCorpUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.PostConstruct;
+import java.util.List;
+import java.util.Map;
+
+/*
+ *项目名: netflix
+ *文件名: CorpServiceImpl
+ *创建者: JavaZou
+ *创建时间:2022/10/13 14:59
+ */
+@Slf4j
+@Service
+public class CorpServiceImpl implements CorpService {
+	@Autowired
+	private YHLXWxCorpConfig yhlXWxCorpConfig;
+
+	private CorpMessageRouter corpMessageRouter;
+
+	@Autowired
+	private CorpEventActionService corpEventActionService;
+
+	@Autowired
+	private WxCorpOps wxCorpOps;
+
+	@Autowired
+	private CorpFollowMapper corpFollowMapper;
+
+	@Autowired
+	private GlobalThreadPoolTaskExecutor THREAD_POOL;
+
+	@Autowired
+	private RedisService redisService;
+
+	@PostConstruct
+	private void init() {
+		corpMessageRouter = new CorpMessageRouter(this)
+				//添加企业客户事件
+				.rule().async(false).changeType("add_external_contact")
+				.handler(new CorpMessageHandler() {
+					@Override
+					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
+						return corpEventActionService.addExternalContact(message.getToUserName(), message.getUserId(), message.getExternalUserId(), message.getWelcomeCode(), context);
+					}
+				})
+				.end()
+				//编辑企业客户事件
+				.rule().async(false).changeType("edit_external_contact")
+				.handler(new CorpMessageHandler() {
+					@Override
+					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
+						return corpEventActionService.editExternalContact(message, context);
+					}
+				})
+				.end()
+				//外部联系人免验证添加成员事件
+				.rule().async(false).changeType("add_half_external_contact")
+				.handler(new CorpMessageHandler() {
+					@Override
+					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
+						return corpEventActionService.addExternalContact(message.getToUserName(), message.getUserId(), message.getExternalUserId(), message.getWelcomeCode(), context);
+					}
+				})
+				.end()
+				//删除企业客户事件
+				.rule().async(false).changeType("del_external_contact")
+				.handler(new CorpMessageHandler() {
+					@Override
+					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
+						return corpEventActionService.delExternalContact(message, context);
+					}
+				})
+				.end()
+				//删除跟进人员
+				.rule().async(false).changeType("del_follow_user")
+				.handler(new CorpMessageHandler() {
+					@Override
+					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
+						return corpEventActionService.delFollowUser(message, context);
+					}
+				})
+				.end()
+				//企业客户标签创建事件
+				.rule().async(false).changeType("create").event("change_external_tag")
+				.handler(new CorpMessageHandler() {
+					@Override
+					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
+						return corpEventActionService.saveCorpTag(message, context);
+					}
+				})
+				.end()
+				//企业客户标签变更事件
+				.rule().async(false).changeType("update").event("change_external_tag")
+				.handler(new CorpMessageHandler() {
+					@Override
+					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
+						return corpEventActionService.saveCorpTag(message, context);
+					}
+				})
+				.end()
+				//企业客户标签删除事件
+				.rule().async(false).changeType("delete").event("change_external_tag")
+				.handler(new CorpMessageHandler() {
+					@Override
+					public CorpXmlOutMessage handle(CorpXmlMessage message, Map<String, Object> context, CorpService corpService) throws Exception {
+						return corpEventActionService.delCorpTag(message, context);
+					}
+				})
+				.end();
+
+	}
+
+	@Override
+	public String VerifyURL(String msgSignature, String timestamp, String nonce, String echoStr) throws Exception {
+		WxCorpUtil wxCorpMsgUtil = new WxCorpUtil(yhlXWxCorpConfig.getToken(), yhlXWxCorpConfig.getEncodingAESKey(), yhlXWxCorpConfig.getCorpId());
+		return wxCorpMsgUtil.VerifyURL(msgSignature, timestamp, nonce, echoStr);
+	}
+
+	@Override
+	public String corpMsg(String msgSignature, String timestamp, String nonce, String content) throws Exception {
+		WxCorpEncryptDto corpEncryptDto = Xmls.parseObject(content, WxCorpEncryptDto.class);
+		BaseWxCorpConfig corpConfig = WxCorpFactory.getBaseWxCorpConfig(corpEncryptDto.getToUserName());
+
+		WxCorpUtil wxCorpUtil = new WxCorpUtil(corpConfig.getToken(), corpConfig.getEncodingAESKey(), corpConfig.getCorpId());
+
+		String msg = wxCorpUtil.DecryptMsg(msgSignature, timestamp, nonce, corpEncryptDto);
+		log.info("企业微信 解密 msg:\n{}", msg);
+
+		CorpXmlMessage inMessage = Xmls.parseObject(msg, CorpXmlMessage.class);
+
+		//事件路由
+		CorpXmlOutMessage outMessage = corpMessageRouter.route(inMessage);
+
+		if (outMessage != null) {
+			return outMessage.toEncryptedXml(new WxCryptUtil(yhlXWxCorpConfig.getToken(), yhlXWxCorpConfig.getEncodingAESKey(), yhlXWxCorpConfig.getCorpId()));
+		}
+		return "";
+	}
+
+	@Override
+	public String dataInitByCorpId(String corpId) throws Exception {
+		//获取成员列表
+		List<String> followUserList = wxCorpOps.getFollowUserList(corpId);
+		for (String userId : followUserList) {
+			THREAD_POOL.execute(() -> {
+				CorpUserInfo userInfo = null;
+				try {
+					userInfo = wxCorpOps.getFollowUser(corpId, userId);
+				} catch (Exception e) {
+					e.printStackTrace();
+					return;
+				}
+				CorpFollow corpFollow = new CorpFollow();
+				BeanUtil.copyProperties(userInfo, corpFollow);
+				CorpFollow follow = corpFollowMapper.selectOne(Wrappers.lambdaQuery(CorpFollow.class).eq(CorpFollow::getUserid, corpFollow.getUserid()).eq(CorpFollow::getCorpId, corpId));
+				if (follow == null) {
+					corpFollow.setCorpId(corpId);
+					corpFollowMapper.insert(corpFollow);
+				} else {
+					corpFollow.setId(follow.getId());
+					corpFollowMapper.updateById(corpFollow);
+				}
+
+				List<String> externalList = null;
+				try {
+					externalList = wxCorpOps.listExternalContacts(corpId, userId);
+				} catch (Exception e) {
+					e.printStackTrace();
+					return;
+				}
+				if (externalList.size() > 1000) {
+					List<List<String>> lists = ListsUtil.averageAssign(externalList, 5);
+					for (List<String> list : lists) {
+						THREAD_POOL.execute(() -> {
+							for (String externalUserid : list) {
+								try {
+									corpEventActionService.addExternalContact(corpId, null, externalUserid, null, null);
+								} catch (Exception e) {
+									e.printStackTrace();
+								}
+							}
+						});
+					}
+				} else {
+					for (String externalUserid : externalList) {
+						try {
+							corpEventActionService.addExternalContact(corpId, null, externalUserid, null, null);
+						} catch (Exception e) {
+							e.printStackTrace();
+						}
+					}
+				}
+			});
+		}
+		return "";
+	}
+
+	@Override
+	public String createUrl(String corpId, String state) {
+		return wxCorpOps.createUrl(corpId, state);
+	}
+
+	@Override
+	public CorpOauth2UserInfo getUserInfo(String corpId, String code) throws Exception {
+		return wxCorpOps.getUserInfo(corpId, code);
+	}
+
+	@Override
+	@Transactional(rollbackFor = Throwable.class)
+	public CorpFollow saveFollowUser(String corpId, CorpOauth2UserInfo corpOauth2UserInfo) throws Exception {
+		CorpFollow corpFollow = corpFollowMapper.selectOne(Wrappers.lambdaQuery(CorpFollow.class).eq(CorpFollow::getCorpId, corpId).eq(CorpFollow::getUserid, corpOauth2UserInfo.getUserId()));
+		if (corpFollow == null) {
+			CorpUserInfo userInfo = wxCorpOps.getFollowUser(corpId, corpOauth2UserInfo.getUserId());
+			corpFollow = new CorpFollow();
+			BeanUtil.copyProperties(userInfo, corpFollow);
+			corpFollow.setCorpId(corpId);
+			corpFollowMapper.insert(corpFollow);
+		}
+
+		return corpFollow;
+	}
+
+	@Override
+	public String getJsTicket(String corpId) throws Exception {
+		String jsTicket = redisService.getStr(RedisService.key.CORP_JS_TICKET_KEY.getName() + corpId);
+		if (StrUtil.isBlank(jsTicket)) {
+			return wxCorpOps.getJsTicket(corpId);
+		}
+		return jsTicket;
+	}
+
+	@Override
+	public String getAgentJsTicket(String corpId, String agentId) throws Exception {
+		String jsTicket = redisService.getStr(RedisService.key.CORP_AGENT_JS_TICKET_KEY.getName() + corpId);
+		if (StrUtil.isBlank(jsTicket)) {
+			return wxCorpOps.getAgentJsTicket(corpId, agentId);
+		} else {
+			return jsTicket;
+		}
+	}
+
+}

+ 255 - 0
netflix-service/src/main/java/com/cyksj/service/corp/impl/WxCorpOpsImpl.java

@@ -0,0 +1,255 @@
+package com.cyksj.service.corp.impl;
+
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONObject;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.common.util.IoKit;
+import com.cyksj.common.util.J11HttpC;
+import com.cyksj.common.util.Jsons;
+import com.cyksj.config.corp.BaseWxCorpConfig;
+import com.cyksj.config.corp.WxCorpFactory;
+import com.cyksj.config.corp.YHLXWxCorpConfig;
+import com.cyksj.dto.CorpOauth2UserInfo;
+import com.cyksj.dto.RedisKey;
+import com.cyksj.model.response.*;
+import com.cyksj.redis.RedisService;
+import com.cyksj.service.corp.WxCorpOps;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.net.URLEncoder;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.util.List;
+import java.util.Optional;
+
+/*
+ *项目名: netflix
+ *文件名: WxCorpOpsImpl
+ *创建者: JavaZou
+ *创建时间:2022/10/13 16:46
+ */
+@Service
+@Slf4j
+public class WxCorpOpsImpl implements WxCorpOps {
+	@Autowired
+	private YHLXWxCorpConfig yhlXWxCorpConfig;
+
+	@Autowired
+	private RedisService redisService;
+
+	private final static String remoteUrl = "wx-ops.liuliangbang.vip";
+
+	@Override
+	public CorpExternalContactInfo getExternalContact(String corpId, String userId) throws Exception {
+		String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get?access_token=" + getAccessToken(corpId) + "&external_userid=" + userId;
+		HttpResponse<String> res =
+				J11HttpC.custom()
+						.ofGet()
+						.url(url)
+						.headers(J11HttpC.ReqType.raw_json)
+						.send(HttpResponse.BodyHandlers.ofString());
+		if (200 != res.statusCode()) {
+			throw BusinessRuntimeException.getInstance("企业微信获取客户详情错误: " + res.body());
+		}
+
+		return Jsons.parseObject(res.body(), CorpExternalContactInfo.class);
+	}
+
+	@Override
+	public String getAccessToken(String corpId) throws Exception {
+		String accessToken = redisService.getStr(RedisKey.ACCESS_TOKEN_KEY + corpId);
+		if (StringUtils.isNotBlank(accessToken)) {
+			return accessToken;
+		}
+		return access_token(corpId);
+	}
+
+	@Override
+	public CorpUserExternalTagGroupList getCorpTagList(String corpId, List<String> tagIds, List<String> groupIds) throws Exception {
+		JSONObject params = new JSONObject();
+		if (!tagIds.isEmpty()) {
+			params.putOpt("tag_id", tagIds);
+		}
+		if (!groupIds.isEmpty()) {
+			params.putOpt("group_id", groupIds);
+		}
+
+		String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_corp_tag_list?access_token=" + getAccessToken(corpId);
+		HttpResponse<String> res =
+				J11HttpC.custom()
+						.ofPost()
+						.url(url)
+						.headers(J11HttpC.ReqType.raw_json)
+						.body(HttpRequest.BodyPublishers.ofString(params.toString(), IoKit.Charsets.UTF_8.getCharset()))
+						.send(HttpResponse.BodyHandlers.ofString());
+		if (200 != res.statusCode()) {
+			throw BusinessRuntimeException.getInstance("企业微信获取企业标签库错误: " + res.body());
+		}
+
+		return Jsons.parseObject(res.body(), CorpUserExternalTagGroupList.class);
+	}
+
+	@Override
+	public List<String> getFollowUserList(String corpId) throws Exception {
+		String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/get_follow_user_list?access_token=" + getAccessToken(corpId);
+		HttpResponse<String> res =
+				J11HttpC.custom()
+						.ofGet()
+						.url(url)
+						.send(HttpResponse.BodyHandlers.ofString());
+		if (200 != res.statusCode()) {
+			throw BusinessRuntimeException.getInstance("企业微信获取客户联系功能的成员列表错误:" + res.body());
+		}
+
+		return Jsons.parseObject(res.body(), UserWithExternalPermission.class).getFollowers();
+	}
+
+	@Override
+	public CorpUserInfo getFollowUser(String corpId, String userId) throws Exception {
+		String url = "https://qyapi.weixin.qq.com/cgi-bin/user/get?access_token=" + getAccessToken(corpId) + "&userid=" + userId;
+		HttpResponse<String> res =
+				J11HttpC.custom()
+						.ofGet()
+						.url(url)
+						.send(HttpResponse.BodyHandlers.ofString());
+		if (200 != res.statusCode()) {
+			throw BusinessRuntimeException.getInstance("企业微信获取客户联系功能的成员列表错误:" + res.body());
+		}
+
+		return Jsons.parseObject(res.body(), CorpUserInfo.class);
+	}
+
+	@Override
+	public List<String> listExternalContacts(String corpId, String userId) throws Exception {
+		String url = "https://qyapi.weixin.qq.com/cgi-bin/externalcontact/list?access_token=" + getAccessToken(corpId) + "&userid=" + userId;
+		HttpResponse<String> res =
+				J11HttpC.custom()
+						.ofGet()
+						.url(url)
+						.send(HttpResponse.BodyHandlers.ofString());
+		if (200 != res.statusCode()) {
+			throw BusinessRuntimeException.getInstance("企业微信获取客户列表错误:" + res.body());
+		}
+
+		return Jsons.parseObject(res.body(), UserExternalContactList.class).getExternalUserId();
+	}
+
+	@Override
+	public String createUrl(String corpId, String state) {
+		BaseWxCorpConfig wxCorpConfig = WxCorpFactory.getBaseWxCorpConfig(corpId);
+		return "https://open.weixin.qq.com/connect/oauth2/authorize" +
+				"?appid=" + wxCorpConfig.getCorpId() +
+				"&redirect_uri=" + URLEncoder.encode(wxCorpConfig.getDomain() + "/manage/corp/redirect", IoKit.Charsets.UTF_8.getCharset()) +
+				"&response_type=code" +
+				"&scope=snsapi_base" +
+				"&state=" + state +
+				"#wechat_redirect";
+	}
+
+	@Override
+	public CorpOauth2UserInfo getUserInfo(String corpId, String code) throws Exception {
+		String url = "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo" +
+				"?access_token=" + getAccessToken(corpId) +
+				"&code=" + code;
+
+		HttpResponse<String> res =
+				J11HttpC.custom()
+						.ofGet()
+						.url(url)
+						.cacheURI()
+						.send(HttpResponse.BodyHandlers.ofString());
+
+		log.info("企业微信根据code获取成员信息 res:{}", res.body());
+		if (200 != res.statusCode()) {
+			throw BusinessRuntimeException.getInstance("企业微信根据code获取成员信息失败: " + res.body());
+		}
+
+		return Jsons.parseObject(res.body(), CorpOauth2UserInfo.class);
+	}
+
+	@Override
+	public String getJsTicket(String corpId) throws Exception {
+		String jsTicket = redisService.getStr(RedisKey.JS_TICKET_KEY + corpId);
+		if (StrUtil.isBlank(jsTicket)) {
+			return js_ticket(this.getAccessToken(corpId));
+		}
+		return jsTicket;
+	}
+
+	@Override
+	public String getAgentJsTicket(String corpId, String agentId) throws Exception {
+		String ticket = redisService.getStr(RedisService.key.CORP_AGENT_JS_TICKET_KEY.getName() + corpId);
+		if (StrUtil.isBlank(ticket)) {
+			return agentJsTicket(corpId);
+		}
+		return ticket;
+	}
+
+	public String access_token(String corpId) throws Exception {
+		corpId = Optional.ofNullable(corpId).orElse(yhlXWxCorpConfig.getCorpId());
+
+		String url = "http://" + remoteUrl + "/wx/corp/access_token" +
+				"?corpId=" + corpId;
+		HttpResponse<byte[]> res =
+				J11HttpC.custom()
+						.ofGet()
+						.url(url)
+						.cacheURI()
+						.send(HttpResponse.BodyHandlers.ofByteArray());
+
+		if (200 != res.statusCode()) {
+			throw BusinessRuntimeException.getInstance("获取access_token失败: " + IoKit.toString(res.body()));
+		}
+
+		Callback callback = Jsons.parseObject(res.body(), Callback.class);
+		if (!callback.isSuccess()) {
+			throw BusinessRuntimeException.getInstance(callback.getMessage());
+		}
+		return (String) callback.getValue();
+	}
+
+	public String js_ticket(String corpId) throws Exception {
+		String url = "http://" + remoteUrl + "/wx/corp/js_ticket" +
+				"?corpId=" + corpId;
+		HttpResponse<byte[]> res =
+				J11HttpC.custom()
+						.ofGet()
+						.url(url)
+						.cacheURI()
+						.send(HttpResponse.BodyHandlers.ofByteArray());
+
+		if (200 != res.statusCode()) {
+			throw BusinessRuntimeException.getInstance("获取access_token失败: " + IoKit.toString(res.body()));
+		}
+
+		Callback callback = Jsons.parseObject(res.body(), Callback.class);
+		if (!callback.isSuccess()) {
+			throw BusinessRuntimeException.getInstance(callback.getMessage());
+		}
+		return (String) callback.getValue();
+	}
+
+	private String agentJsTicket(String corpId) throws Exception {
+		String url = "http://" + remoteUrl + "/wx/corp/agent_js_ticket" +
+				"?corpId=" + corpId;
+		HttpResponse<byte[]> res =
+				J11HttpC.custom()
+						.ofGet()
+						.url(url)
+						.cacheURI()
+						.send(HttpResponse.BodyHandlers.ofByteArray());
+
+		if (200 != res.statusCode()) {
+			throw BusinessRuntimeException.getInstance("获取agent_js_ticket失败: " + IoKit.toString(res.body()));
+		}
+
+		Callback callback = Jsons.parseObject(res.body(), Callback.class);
+		if (!callback.isSuccess()) {
+			throw BusinessRuntimeException.getInstance(callback.getMessage());
+		}
+		return (String) callback.getValue();
+	}
+}

+ 26 - 0
netflix-service/src/main/java/com/cyksj/service/corp/msg/CorpEventActionService.java

@@ -0,0 +1,26 @@
+package com.cyksj.service.corp.msg;
+
+import com.cyksj.model.request.corp.CorpXmlMessage;
+import com.cyksj.model.request.corp.CorpXmlOutMessage;
+
+import java.util.Map;
+
+/*
+ *项目名: netflix
+ *文件名: CorpEventOperateService
+ *创建者: JavaZou
+ *创建时间:2022/10/13 16:11
+ */
+public interface CorpEventActionService {
+	CorpXmlOutMessage addExternalContact(String corpId, String userId, String externalUserId, String welcomeCode, Map<String, Object> context) throws Exception;
+
+	CorpXmlOutMessage editExternalContact(CorpXmlMessage message, Map<String, Object> context) throws Exception;
+
+	CorpXmlOutMessage delExternalContact(CorpXmlMessage message, Map<String, Object> context);
+
+	CorpXmlOutMessage delFollowUser(CorpXmlMessage message, Map<String, Object> context);
+
+	CorpXmlOutMessage saveCorpTag(CorpXmlMessage message, Map<String, Object> context) throws Exception;
+
+	CorpXmlOutMessage delCorpTag(CorpXmlMessage message, Map<String, Object> context);
+}

+ 25 - 0
netflix-service/src/main/java/com/cyksj/service/corp/msg/CorpMessageHandler.java

@@ -0,0 +1,25 @@
+package com.cyksj.service.corp.msg;
+
+import com.cyksj.model.request.corp.CorpXmlMessage;
+import com.cyksj.model.request.corp.CorpXmlOutMessage;
+import com.cyksj.service.corp.CorpService;
+
+import java.util.Map;
+
+/**
+ * 处理微信推送消息的处理器接口
+ *
+ * @author chan
+ * @date 2022-03-14 下午1:35
+ */
+public interface CorpMessageHandler {
+
+	/**
+	 * @param context 上下文,如果handler或interceptor之间有信息要传递,可以用这个
+	 * @return xml格式的消息 ,如果在异步规则里处理的话,可以返回null
+	 */
+	CorpXmlOutMessage handle(CorpXmlMessage message,
+	                         Map<String, Object> context,
+	                         CorpService corpService) throws Exception;
+
+}

+ 26 - 0
netflix-service/src/main/java/com/cyksj/service/corp/msg/CorpMessageInterceptor.java

@@ -0,0 +1,26 @@
+package com.cyksj.service.corp.msg;
+
+
+import com.cyksj.model.request.corp.CorpXmlMessage;
+import com.cyksj.service.corp.CorpService;
+
+import java.util.Map;
+
+/**
+ * 微信消息拦截器,可以用来做验证
+ * @author chan
+ * @date 2022-03-14 下午1:36
+ */
+public interface CorpMessageInterceptor {
+
+  /**
+   * 拦截微信消息
+   *
+   * @param context        上下文,如果handler或interceptor之间有信息要传递,可以用这个
+   * @return true代表OK ,false代表不OK
+   */
+  boolean intercept(CorpXmlMessage message,
+                    Map<String, Object> context,
+                    CorpService corpService) throws Exception;
+
+}

+ 20 - 0
netflix-service/src/main/java/com/cyksj/service/corp/msg/CorpMessageMatcher.java

@@ -0,0 +1,20 @@
+package com.cyksj.service.corp.msg;
+
+import com.cyksj.model.request.corp.CorpXmlMessage;
+
+/**
+ * 消息匹配器,用在消息路由的时候
+ * @author chan
+ * @date 2022-03-14 下午1:37
+ */
+public interface CorpMessageMatcher {
+
+	/**
+	 * 消息是否匹配某种模式
+	 *
+	 * @param message the message
+	 * @return the boolean
+	 */
+	boolean match(CorpXmlMessage message);
+
+}

+ 105 - 0
netflix-service/src/main/java/com/cyksj/service/corp/msg/CorpMessageRouter.java

@@ -0,0 +1,105 @@
+package com.cyksj.service.corp.msg;
+
+
+import com.cyksj.common.task.GlobalThreadPoolTaskExecutor;
+import com.cyksj.model.request.corp.CorpXmlMessage;
+import com.cyksj.model.request.corp.CorpXmlOutMessage;
+import com.cyksj.service.corp.CorpService;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.Future;
+
+/**
+ * 微信消息路由器,通过代码化的配置,把来自微信的消息交给handler处理
+ *
+ * @author chan
+ * @date 2022-03-14 下午3:42
+ */
+@Slf4j
+public class CorpMessageRouter {
+
+	private static final GlobalThreadPoolTaskExecutor TASK_EXECUTOR = GlobalThreadPoolTaskExecutor.getInstance();
+
+	private final List<CorpMessageRouterRule> rules = new ArrayList<>();
+
+	private final CorpService corpService;
+
+	public CorpMessageRouter(CorpService wxCpService) {
+		this.corpService = wxCpService;
+	}
+
+	List<CorpMessageRouterRule> getRules() {
+		return this.rules;
+	}
+
+	/**
+	 * 开始一个新的Route规则.
+	 */
+	public CorpMessageRouterRule rule() {
+		return new CorpMessageRouterRule(this);
+	}
+
+	/**
+	 * 处理微信消息.
+	 */
+	public CorpXmlOutMessage route(final CorpXmlMessage message, final Map<String, Object> context) {
+
+		final List<CorpMessageRouterRule> matchRules = new ArrayList<>();
+		// 收集匹配的规则
+		for (final CorpMessageRouterRule rule : this.rules) {
+			if (rule.test(message)) {
+				matchRules.add(rule);
+				if (!rule.isReEnter()) {
+					break;
+				}
+			}
+		}
+
+		if (matchRules.size() == 0) {
+			return null;
+		}
+
+		CorpXmlOutMessage res = null;
+		final List<Future> futures = new ArrayList<>();
+		for (final CorpMessageRouterRule rule : matchRules) {
+			// 返回最后一个非异步的rule的执行结果
+			if (rule.isAsync()) {
+				futures.add(
+						TASK_EXECUTOR.submit(() -> rule.service(message, context, CorpMessageRouter.this.corpService))
+				);
+			} else {
+				res = rule.service(message, context, this.corpService);
+			}
+		}
+
+		if (futures.size() > 0) {
+			TASK_EXECUTOR.submit(() -> {
+				for (Future future : futures) {
+					try {
+						future.get();
+					} catch (InterruptedException e) {
+						log.error("Error happened when wait task finish", e);
+						Thread.currentThread().interrupt();
+					} catch (ExecutionException e) {
+						log.error("Error happened when wait task finish", e);
+					}
+				}
+				return null;
+			});
+		}
+		return res;
+	}
+
+	/**
+	 * 处理微信消息.
+	 */
+	public CorpXmlOutMessage route(final CorpXmlMessage message) {
+		return this.route(message, new HashMap<>(2));
+	}
+
+}

+ 265 - 0
netflix-service/src/main/java/com/cyksj/service/corp/msg/CorpMessageRouterRule.java

@@ -0,0 +1,265 @@
+package com.cyksj.service.corp.msg;
+
+
+import com.cyksj.model.request.corp.CorpXmlMessage;
+import com.cyksj.model.request.corp.CorpXmlOutMessage;
+import com.cyksj.service.corp.CorpService;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.*;
+import java.util.regex.Pattern;
+
+/**
+ * @author chan
+ * @date 2022-03-14 下午4:16
+ */
+@Data
+@Slf4j
+public class CorpMessageRouterRule {
+	private final CorpMessageRouter routerBuilder;
+
+	private boolean async = true;
+
+	private String fromUser;
+
+	private String msgType;
+
+	private String event;
+
+	private String eventKey;
+
+	private String eventKeyRegex;
+
+	private String content;
+
+	private String rContent;
+
+	private String infoType;
+
+	private String changeType;
+
+	private CorpMessageMatcher matcher;
+
+	private boolean reEnter = false;
+
+	private Integer agentId;
+
+	private List<CorpMessageHandler> handlers = new ArrayList<>();
+
+	private List<CorpMessageInterceptor> interceptors = new ArrayList<>();
+
+
+	protected CorpMessageRouterRule(CorpMessageRouter routerBuilder) {
+		this.routerBuilder = routerBuilder;
+	}
+
+	/**
+	 * 设置是否异步执行,默认是true
+	 */
+	public CorpMessageRouterRule async(boolean async) {
+		this.async = async;
+		return this;
+	}
+
+	/**
+	 * 如果agentId匹配
+	 */
+	public CorpMessageRouterRule agentId(Integer agentId) {
+		this.agentId = agentId;
+		return this;
+	}
+
+	/**
+	 * 如果msgType等于某值
+	 */
+	public CorpMessageRouterRule msgType(String msgType) {
+		this.msgType = msgType;
+		return this;
+	}
+
+	/**
+	 * 如果event等于某值
+	 */
+	public CorpMessageRouterRule event(String event) {
+		this.event = event;
+		return this;
+	}
+
+	/**
+	 * 如果eventKey等于某值
+	 */
+	public CorpMessageRouterRule eventKey(String eventKey) {
+		this.eventKey = eventKey;
+		return this;
+	}
+
+	/**
+	 * 如果eventKey匹配该正则表达式
+	 */
+	public CorpMessageRouterRule eventKeyRegex(String regex) {
+		this.eventKeyRegex = regex;
+		return this;
+	}
+
+	/**
+	 * 如果content等于某值
+	 */
+	public CorpMessageRouterRule content(String content) {
+		this.content = content;
+		return this;
+	}
+
+	/**
+	 * 如果content匹配该正则表达式
+	 */
+	public CorpMessageRouterRule rContent(String regex) {
+		this.rContent = regex;
+		return this;
+	}
+
+	/**
+	 * 如果fromUser等于某值
+	 */
+	public CorpMessageRouterRule fromUser(String fromUser) {
+		this.fromUser = fromUser;
+		return this;
+	}
+
+	/**
+	 * infoType
+	 */
+	public CorpMessageRouterRule changeType(String changeType) {
+		this.changeType = changeType;
+		return this;
+	}
+
+	/**
+	 * 如果消息匹配某个matcher,用在用户需要自定义更复杂的匹配规则的时候
+	 */
+	public CorpMessageRouterRule matcher(CorpMessageMatcher matcher) {
+		this.matcher = matcher;
+		return this;
+	}
+
+	/**
+	 * 设置微信消息拦截器
+	 */
+	public CorpMessageRouterRule interceptor(CorpMessageInterceptor interceptor) {
+		return interceptor(interceptor, (CorpMessageInterceptor[]) null);
+	}
+
+	/**
+	 * 设置微信消息拦截器
+	 */
+	public CorpMessageRouterRule interceptor(CorpMessageInterceptor interceptor, CorpMessageInterceptor... otherInterceptors) {
+		this.interceptors.add(interceptor);
+		if (otherInterceptors != null && otherInterceptors.length > 0) {
+			Collections.addAll(this.interceptors, otherInterceptors);
+		}
+		return this;
+	}
+
+	/**
+	 * 设置微信消息处理器
+	 */
+	public CorpMessageRouterRule handler(CorpMessageHandler handler) {
+		return handler(handler, (CorpMessageHandler[]) null);
+	}
+
+	/**
+	 * 设置微信消息处理器
+	 */
+	public CorpMessageRouterRule handler(CorpMessageHandler handler, CorpMessageHandler... otherHandlers) {
+		this.handlers.add(handler);
+		if (otherHandlers != null && otherHandlers.length > 0) {
+			Collections.addAll(this.handlers, otherHandlers);
+		}
+		return this;
+	}
+
+	/**
+	 * 规则结束,代表如果一个消息匹配该规则,那么它将不再会进入其他规则
+	 */
+	public CorpMessageRouter end() {
+		this.routerBuilder.getRules().add(this);
+		return this.routerBuilder;
+	}
+
+	/**
+	 * 规则结束,但是消息还会进入其他规则
+	 */
+	public CorpMessageRouter next() {
+		this.reEnter = true;
+		return end();
+	}
+
+	/**
+	 * Test boolean.
+	 *
+	 * @param message the wx message
+	 * @return the boolean
+	 */
+	protected boolean test(CorpXmlMessage message) {
+		return
+				(this.fromUser == null || this.fromUser.equals(message.getFromUserName()))
+						&&
+						(this.agentId == null || this.agentId.equals(message.getAgentId()))
+						&&
+						(this.msgType == null || this.msgType.equalsIgnoreCase(message.getMsgType()))
+						&&
+						(this.event == null || this.event.equalsIgnoreCase(message.getEvent()))
+						&&
+						(this.eventKey == null || this.eventKey.equalsIgnoreCase(message.getEventKey()))
+						&&
+						(this.eventKeyRegex == null || Pattern.matches(this.eventKeyRegex, StringUtils.trimToEmpty(message.getEventKey())))
+						&&
+						(this.content == null || this.content.equals(StringUtils.trimToNull(message.getContent())))
+						&&
+						(this.rContent == null || Pattern.matches(this.rContent, StringUtils.trimToEmpty(message.getContent())))
+						&&
+						(this.matcher == null || this.matcher.match(message))
+						&&
+						(this.changeType == null || this.changeType.equals(message.getChangeType()))
+				;
+	}
+
+	/**
+	 * 处理微信推送过来的消息
+	 */
+	protected CorpXmlOutMessage service(CorpXmlMessage message,
+	                                    Map<String, Object> context,
+	                                    CorpService corpService) {
+
+		if (context == null) {
+			context = new HashMap<>();
+		}
+
+		try {
+			// 如果拦截器不通过
+			for (CorpMessageInterceptor interceptor : this.interceptors) {
+				if (!interceptor.intercept(message, context, corpService)) {
+					return null;
+				}
+			}
+
+			// 交给handler处理
+			CorpXmlOutMessage res = null;
+			for (CorpMessageHandler handler : this.handlers) {
+				// 返回最后handler的结果
+				res = handler.handle(message, context, corpService);
+			}
+			return res;
+
+		} catch (Exception e) {
+			//TODO 处理异常
+			log.error("企业微信推送 路由处理错误 error:{}", e);
+		}
+
+		return null;
+
+	}
+
+
+}

+ 5 - 5
netflix-service/src/main/java/com/cyksj/service/mange/CmsAccountService.java

@@ -1,16 +1,16 @@
 package com.cyksj.service.mange;
 
 import com.baomidou.mybatisplus.extension.service.IService;
-import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
-import com.cyksj.mapper.AccountMapper;
 import com.cyksj.model.entity.Account;
-import lombok.RequiredArgsConstructor;
-import lombok.extern.slf4j.Slf4j;
-import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
 
 /**
  * @author chan
  * @date 2022/9/27 6:23 PM
  */
 public interface CmsAccountService extends IService<Account> {
+
+	List<Integer> getNumOfUser(List<Long> accountIds, Date yesZeroDate, Date thisZeroDate);
 }

+ 6 - 0
netflix-service/src/main/java/com/cyksj/service/mange/CmsGroupService.java

@@ -13,4 +13,10 @@ import org.springframework.stereotype.Service;
  * @date 2022/9/27 6:27 PM
  */
 public interface CmsGroupService extends IService<GroupsTrips> {
+
+    GroupsTrips issuance(GroupsTrips groups);
+
+    void close(Long groupId);
+
+    void setAccount(GroupsTrips groupsTrips);
 }

+ 6 - 0
netflix-service/src/main/java/com/cyksj/service/mange/CmsOrderDonService.java

@@ -2,7 +2,10 @@ package com.cyksj.service.mange;
 
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.cyksj.model.entity.OrderDon;
+import com.cyksj.model.entity.OrderDonTransport;
+import com.cyksj.model.entity.OrderDonWaybill;
 import com.cyksj.model.excel.ExcelOrderDonInfo;
+import com.cyksj.model.manage.request.ReqSetLogisticsPost;
 
 import java.util.List;
 
@@ -17,4 +20,7 @@ public interface CmsOrderDonService extends IService<OrderDon> {
      */
     List<ExcelOrderDonInfo> exportOrderInfo(Long promotionId, String start, String end);
 
+    OrderDonTransport getTransport(Long orderId);
+
+    OrderDonWaybill setWaybill(ReqSetLogisticsPost reqSetLogisticsPost);
 }

+ 9 - 0
netflix-service/src/main/java/com/cyksj/service/mange/account/CmsAccountServiceImpl.java

@@ -8,6 +8,9 @@ import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
+import java.util.Date;
+import java.util.List;
+
 /**
  * @author chan
  * @date 2022/9/27 6:23 PM
@@ -16,4 +19,10 @@ import org.springframework.stereotype.Service;
 @Service("cms")
 @RequiredArgsConstructor
 public class CmsAccountServiceImpl extends ServiceImpl<AccountMapper, Account> implements CmsAccountService {
+	private final AccountMapper accountMapper;
+
+	@Override
+	public List<Integer> getNumOfUser(List<Long> accountIds,Date yesZeroDate, Date thisZeroDate) {
+		return accountMapper.getNumOfUser(accountIds,yesZeroDate, thisZeroDate);
+	}
 }

+ 87 - 0
netflix-service/src/main/java/com/cyksj/service/mange/group/CmsGroupServiceImpl.java

@@ -1,13 +1,28 @@
 package com.cyksj.service.mange.group;
 
+import cn.hutool.core.date.DateField;
+import cn.hutool.core.date.DateUtil;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.cyksj.common.exception.BusinessRuntimeException;
+import com.cyksj.mapper.GoodsDonSkuMapper;
 import com.cyksj.mapper.GroupsMapper;
+import com.cyksj.mapper.GroupsRelationMapper;
+import com.cyksj.mapper.OrderDonMapper;
+import com.cyksj.model.entity.GoodsDonSku;
+import com.cyksj.model.entity.GroupsRelation;
 import com.cyksj.model.entity.GroupsTrips;
+import com.cyksj.model.entity.OrderDon;
 import com.cyksj.service.mange.CmsGroupService;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.stereotype.Service;
 
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
 /**
  * @author chan
  * @date 2022/9/27 6:27 PM
@@ -16,4 +31,76 @@ import org.springframework.stereotype.Service;
 @Service
 @RequiredArgsConstructor
 public class CmsGroupServiceImpl extends ServiceImpl<GroupsMapper,GroupsTrips> implements CmsGroupService {
+
+    private final GoodsDonSkuMapper skuMapper;
+
+    private final GroupsRelationMapper relationMapper;
+
+    private final OrderDonMapper orderDonMapper;
+
+
+    @Override
+    public GroupsTrips issuance(GroupsTrips groups) {
+        GoodsDonSku sku = skuMapper.selectById(groups.getSkuId());
+        if (sku == null) {
+            throw new BusinessRuntimeException("该商品规格不存在!");
+        }
+        groups.setNum(sku.getNum());
+        groups.setAvailableNum(sku.getNum());
+        this.save(groups);
+
+        for (Integer i = 1; i <= groups.getNum(); i++) {
+            GroupsRelation relation = new GroupsRelation();
+            relation.setGroupsId(groups.getId());
+            relation.setStatus(GroupsRelation.Status.none);
+            relation.setNum(i);
+            relationMapper.insert(relation);
+        }
+        return groups;
+    }
+
+    @Override
+    public void close(Long groupId) {
+        GroupsTrips groupsTrips = this.getById(groupId);
+        if(groupsTrips == null){
+            throw new BusinessRuntimeException("非法参数.车队不存在");
+        }
+        Integer count = relationMapper.selectCount(Wrappers.lambdaQuery(GroupsRelation.class).in(GroupsRelation::getStatus, List.of(GroupsRelation.Status.locking, GroupsRelation.Status.validity)));
+        if (count > 0) {
+            throw new BusinessRuntimeException("该车队已有用户购买或锁定.无法删除");
+        }else {
+            relationMapper.delete(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getGroupsId,groupId));
+            this.removeById(groupId);
+        }
+    }
+
+    @Override
+    public void setAccount(GroupsTrips groupsTrips) {
+        int count = count(Wrappers.lambdaQuery(GroupsTrips.class).eq(GroupsTrips::getAccountId, groupsTrips.getAccountId()));
+        if (count > 0) {
+            throw new BusinessRuntimeException("该账号已发车.请选择未发车账户");
+        }
+        List<GroupsRelation> groupsRelations = relationMapper.selectList(Wrappers.lambdaQuery(GroupsRelation.class).eq(GroupsRelation::getGroupsId, groupsTrips.getId()).eq(GroupsRelation::getStatus, GroupsRelation.Status.validity));
+       groupsRelations.forEach((relation)->{
+           if (relation.getExpiryTime() == null) {
+               OrderDon orderDon = orderDonMapper.selectOne(Wrappers.lambdaQuery(OrderDon.class).eq(OrderDon::getUserId, relation.getUserId()).eq(OrderDon::getRelationId, relation.getId()).eq(OrderDon::getStatus, OrderDon.Status.hasPayment));
+               if (orderDon != null) {
+                   //如果续费增加时间,如果首次则设置当前时间为初始时间
+                   Date expiryTime = Optional.ofNullable(relation.getExpiryTime()).orElse(new Date());
+                   GoodsDonSku donSku = skuMapper.selectById(getById(groupsTrips.getId()).getSkuId());
+
+                   Date newDate = DateUtil.offset(expiryTime, DateField.MONTH, donSku.getMonths() * orderDon.getNum());
+                   relation.setExpiryTime(newDate);
+                   relation.setStartTime(relation.getStartTime() == null ? new Date() : null);
+                   relationMapper.updateById(relation);
+                   orderDon.setStatus(OrderDon.Status.complete);
+                   orderDonMapper.updateById(orderDon);
+               }
+           }
+       });
+       groupsTrips.setStatus(GroupsTrips.Status.validity);
+       updateById(groupsTrips);
+
+    }
+
 }

+ 38 - 0
netflix-service/src/main/java/com/cyksj/service/mange/impl/CmsOrderDonServiceImpl.java

@@ -1,14 +1,22 @@
 package com.cyksj.service.mange.impl;
 
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.cyksj.mapper.OrderDonMapper;
+import com.cyksj.mapper.OrderDonTransportMapper;
+import com.cyksj.mapper.OrderDonWaybillMapper;
 import com.cyksj.model.entity.OrderDon;
+import com.cyksj.model.entity.OrderDonTransport;
+import com.cyksj.model.entity.OrderDonWaybill;
 import com.cyksj.model.excel.ExcelOrderDonInfo;
+import com.cyksj.model.manage.request.ReqSetLogisticsPost;
 import com.cyksj.service.mange.CmsOrderDonService;
+import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.stereotype.Service;
 
 import java.util.List;
+import java.util.Optional;
 
 /**
  * @author chan
@@ -16,10 +24,40 @@ import java.util.List;
  */
 @Service
 @Slf4j
+@RequiredArgsConstructor
 public class CmsOrderDonServiceImpl extends ServiceImpl<OrderDonMapper,OrderDon> implements CmsOrderDonService {
 
+    private final OrderDonTransportMapper transportMapper;
+
+    private final OrderDonWaybillMapper orderDonWaybillMapper;
+
     @Override
     public List<ExcelOrderDonInfo> exportOrderInfo(Long promotionId, String start, String end) {
         return this.getBaseMapper().exportOrderInfo(promotionId,start,end);
     }
+
+    @Override
+    public OrderDonTransport getTransport(Long orderId) {
+        return transportMapper.selectOne(Wrappers.lambdaQuery(OrderDonTransport.class).eq(OrderDonTransport::getOrderId, orderId));
+    }
+
+    @Override
+    public OrderDonWaybill setWaybill(ReqSetLogisticsPost reqSetLogisticsPost) {
+        OrderDonWaybill orderDonWaybill = Optional.ofNullable(orderDonWaybillMapper.selectOne(Wrappers.lambdaQuery(OrderDonWaybill.class).eq(OrderDonWaybill::getOrderId, reqSetLogisticsPost.getOrderId()))).orElse(new OrderDonWaybill());
+        orderDonWaybill.setCodeCn(reqSetLogisticsPost.getCodeCn());
+        orderDonWaybill.setTrackingNumber(reqSetLogisticsPost.getTrackingNumber());
+        orderDonWaybill.setOrderId(reqSetLogisticsPost.getOrderId());
+        if(orderDonWaybill.getId() == null){
+            orderDonWaybillMapper.insert(orderDonWaybill);
+            OrderDon orderDon = getById(orderDonWaybill.getOrderId());
+            orderDon.setStatus(OrderDon.Status.transport);
+            updateById(orderDon);
+            //发送微信模板消息
+        }else {
+            orderDonWaybillMapper.updateById(orderDonWaybill);
+        }
+        return orderDonWaybill;
+    }
+
+
 }

+ 14 - 0
netflix-service/src/main/java/com/cyksj/service/mange/statistics/StatisticsDataService.java

@@ -0,0 +1,14 @@
+package com.cyksj.service.mange.statistics;
+
+import com.cyksj.dto.Result;
+import com.cyksj.model.views.BackgroundDataView;
+
+/*
+ *项目名: netflix
+ *文件名: StatisticsService
+ *创建者: JavaZou
+ *创建时间:2022/10/17 14:43
+ */
+public interface StatisticsDataService {
+	Result<BackgroundDataView> getStatisticsByCondition(Long startTime, Long endTime);
+}

+ 145 - 0
netflix-service/src/main/java/com/cyksj/service/mange/statistics/impl/StatisticsDataServiceImpl.java

@@ -0,0 +1,145 @@
+package com.cyksj.service.mange.statistics.impl;
+
+import cn.hutool.core.date.DateTime;
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.cyksj.dto.Result;
+import com.cyksj.enums.GatewayResponse;
+import com.cyksj.mapper.GroupsRelationMapper;
+import com.cyksj.mapper.manage.statistics.AppleOneDataMapper;
+import com.cyksj.mapper.manage.statistics.StreamingAccountDataMapper;
+import com.cyksj.model.entity.*;
+import com.cyksj.model.views.BackgroundDataView;
+import com.cyksj.redis.RedisService;
+import com.cyksj.service.mange.CmsAccountService;
+import com.cyksj.service.mange.statistics.StatisticsDataService;
+import com.cyksj.service.order.OrderDonService;
+import com.cyksj.service.user.UserService;
+import com.cyksj.task.StatisticsDataScheduler;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Optional;
+
+/*
+ *项目名: netflix
+ *文件名: StatisticsDataServiceImpl
+ *创建者: JavaZou
+ *创建时间:2022/10/17 14:45
+ */
+@Service
+@RequiredArgsConstructor
+public class StatisticsDataServiceImpl implements StatisticsDataService {
+	private final UserService userService;
+
+	private final OrderDonService orderDonService;
+
+	private final GroupsRelationMapper groupsRelationMapper;
+
+	private final CmsAccountService accountService;
+
+	private final RedisService redisService;
+
+	private final AppleOneDataMapper appleOneDataMapper;
+
+	private final StreamingAccountDataMapper streamingAccountDataMapper;
+
+	@Override
+	public Result<BackgroundDataView> getStatisticsByCondition(Long startTime, Long endTime) {
+		BackgroundDataView backgroundDataView = new BackgroundDataView();
+		Date startDate = null;
+		Date endDate = null;
+		if (startTime != null) {
+			startDate = DateUtil.date(startTime);
+		}
+		if (endTime != null) {
+			endDate = DateUtil.date(endTime);
+		}
+		//头部数据
+		headerData(backgroundDataView, startDate, endDate);
+		//appleOne数据
+		getAppleOneDataView(backgroundDataView, startDate, endDate);
+		//流媒体账号
+		getStreamingAccountDataView(backgroundDataView, startDate, endDate);
+		return GatewayResponse.SUCCESS.newBuilder().toResult(backgroundDataView);
+	}
+
+	private void getAppleOneDataView(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
+		LambdaQueryWrapper<AppleOneData> wrapper = Wrappers.lambdaQuery(AppleOneData.class);
+		if (startDate != null) {
+			wrapper.ge(AppleOneData::getCreatedTime, startDate);
+		}
+		if (endDate != null) {
+			wrapper.le(AppleOneData::getCreatedTime, endDate);
+		}
+		wrapper.orderByDesc(AppleOneData::getShowId);
+		wrapper.select(AppleOneData::getShowId);
+		wrapper.last("limit 1");
+		AppleOneData max = appleOneDataMapper.selectOne(wrapper);
+		if (max == null) {
+			backgroundDataView.setAppleOneDataViews(null);
+		} else {
+			List<AppleOneData> appleOneData = Optional.ofNullable(appleOneDataMapper.selectList(Wrappers.lambdaQuery(AppleOneData.class).eq(AppleOneData::getShowId, max.getShowId()))).orElse(new ArrayList<>());
+			backgroundDataView.setAppleOneDataViews(appleOneData);
+		}
+	}
+
+	private void getStreamingAccountDataView(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
+		LambdaQueryWrapper<StreamingAccountData> wrapper = Wrappers.lambdaQuery(StreamingAccountData.class);
+		if (startDate != null) {
+			wrapper.ge(StreamingAccountData::getCreatedTime, startDate);
+		}
+		if (endDate != null) {
+			wrapper.le(StreamingAccountData::getCreatedTime, endDate);
+		}
+		wrapper.orderByDesc(StreamingAccountData::getShowId);
+		wrapper.select(StreamingAccountData::getShowId);
+		wrapper.last("limit 1");
+		StreamingAccountData max = streamingAccountDataMapper.selectOne(wrapper);
+		if (max == null) {
+			backgroundDataView.setStreamAccountDataViews(null);
+		} else {
+			List<StreamingAccountData> streamingAccountData = streamingAccountDataMapper.selectList(Wrappers.lambdaQuery(StreamingAccountData.class).eq(StreamingAccountData::getShowId, max.getShowId()));
+			backgroundDataView.setStreamAccountDataViews(streamingAccountData);
+		}
+	}
+
+	private void headerData(BackgroundDataView backgroundDataView, Date startDate, Date endDate) {
+		//总用户数
+		backgroundDataView.setTotalNumOfUser(userService.count(Wrappers.lambdaQuery(User.class).ge(ObjectUtil.isNotNull(startDate), User::getCreatedTime, startDate).le(ObjectUtil.isNotNull(endDate), User::getCreatedTime, endDate)));
+		//总订单数
+		List<OrderDon> orderDons = Optional.ofNullable(orderDonService.list(Wrappers.lambdaQuery(OrderDon.class).notIn(OrderDon::getStatus, StatisticsDataScheduler.noOrderStatus).ge(ObjectUtil.isNotNull(startDate), OrderDon::getCreatedTime, startDate).le(ObjectUtil.isNotNull(endDate), OrderDon::getCreatedTime, endDate))).orElse(new ArrayList<>());
+		backgroundDataView.setTotalNumOfOrder(orderDons.size());
+		BigDecimal totalMoney = orderDons.stream().map(OrderDon::getMoney).reduce(BigDecimal::add).get();
+		//总订单金额
+		backgroundDataView.setTotalOrderAmount(totalMoney);
+		//近5天将要到期的主账号总数
+		DateTime now = DateTime.now();
+		DateTime zero = DateUtil.beginOfDay(now);
+		Object accountHead = redisService.get(RedisService.key.CACHE_HEAR_DATA_KEY.getNameFormat(zero.toString()));
+		if (accountHead != null) {
+			BackgroundDataView dataView = (BackgroundDataView) accountHead;
+			backgroundDataView.setTotalNumOfWillExpireAccount(dataView.getTotalNumOfWillExpireAccount());
+			backgroundDataView.setTotalExpiredAccountNum(dataView.getTotalExpiredAccountNum());
+			backgroundDataView.setTotalNumOfExpiredSubAccount(dataView.getTotalNumOfExpiredSubAccount());
+		} else {
+			DateTime fiveDays = DateUtil.offsetDay(zero, 5);
+			//5天后将到期的主账号
+			List<Account> willExpireAccounts = Optional.ofNullable(accountService.list(Wrappers.lambdaQuery(Account.class).gt(Account::getExpiryTime, zero).le(Account::getExpiryTime, fiveDays))).orElse(new ArrayList<>());
+			backgroundDataView.setTotalNumOfWillExpireAccount(willExpireAccounts.size());
+			//已到期主账号
+			List<Account> expiredAccounts = Optional.ofNullable(accountService.list(Wrappers.lambdaQuery(Account.class).le(Account::getExpiryTime, now))).orElse(new ArrayList<>());
+			backgroundDataView.setTotalExpiredAccountNum(expiredAccounts.size());
+			//已到期子账号
+			List<GroupsRelation> expiredSubAccounts = Optional.ofNullable(groupsRelationMapper.selectList(Wrappers.lambdaQuery(GroupsRelation.class).le(GroupsRelation::getExpiryTime, now))).orElse(new ArrayList<>());
+			backgroundDataView.setTotalNumOfExpiredSubAccount(expiredSubAccounts.size());
+			redisService.set(RedisService.key.CACHE_HEAR_DATA_KEY.getNameFormat(zero.toString()), backgroundDataView, RedisService.key.CACHE_HEAR_DATA_KEY.getTimeout());
+		}
+	}
+}

+ 9 - 2
netflix-service/src/main/java/com/cyksj/service/order/OrderDonService.java

@@ -1,12 +1,13 @@
 package com.cyksj.service.order;
 
-import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.cyksj.model.dto.H5JsPayParams;
 import com.cyksj.model.entity.OrderDon;
+import com.cyksj.model.manage.views.OrderDonView;
 import com.cyksj.model.request.OrderPayRequest;
 
-import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -31,4 +32,10 @@ public interface OrderDonService extends IService<OrderDon> {
      * 关闭订单
      */
     void closeOrder(Long orderId);
+
+    OrderDon renewal(OrderPayRequest request);
+
+    OrderDonView getDetail(Long orderId, long userId);
+
+	List<OrderDon> getAppleOneOrderDons(String appleOne, List<Long> skuIds, List<String> noOrderStatus, Date yesZeroDate, Date thisZeroDate);
 }

Някои файлове не бяха показани, защото твърде много файлове са промени