byteContainer = new ArrayList<>();
+
+ public byte[] toBytes() {
+ byte[] bytes = new byte[byteContainer.size()];
+ for (int i = 0; i < byteContainer.size(); i++) {
+ bytes[i] = byteContainer.get(i);
+ }
+ return bytes;
+ }
+
+ public void addBytes(byte[] bytes) {
+ for (byte b : bytes) {
+ byteContainer.add(b);
+ }
+ }
+
+ public int size() {
+ return byteContainer.size();
+ }
+}
diff --git a/xinelu-common/src/main/java/com/xinelu/common/utils/aes/PKCS7Encoder.java b/xinelu-common/src/main/java/com/xinelu/common/utils/aes/PKCS7Encoder.java
new file mode 100644
index 0000000..86f1920
--- /dev/null
+++ b/xinelu-common/src/main/java/com/xinelu/common/utils/aes/PKCS7Encoder.java
@@ -0,0 +1,62 @@
+package com.xinelu.common.utils.aes;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+
+/**
+ * @Description 提供基于PKCS7算法的加解密接口
+ * @Author WeChat
+ * @Date 2023-03-14 15:09:50
+ */
+class PKCS7Encoder {
+ static Charset CHARSET = StandardCharsets.UTF_8;
+ static int BLOCK_SIZE = 32;
+
+ /**
+ * 获得对明文进行补位填充的字节.
+ *
+ * @param count 需要进行填充补位操作的明文字节个数
+ * @return 补齐用的字节数组
+ */
+ static byte[] encode(int count) {
+ // 计算需要填充的位数
+ int amountToPad = BLOCK_SIZE - (count % BLOCK_SIZE);
+ if (amountToPad == 0) {
+ amountToPad = 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 删除补位字符后的明文
+ */
+ 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 转化得到的字符
+ */
+ static char chr(int a) {
+ byte target = (byte) (a & 0xFF);
+ return (char) target;
+ }
+
+}
diff --git a/xinelu-common/src/main/java/com/xinelu/common/utils/aes/SHA1.java b/xinelu-common/src/main/java/com/xinelu/common/utils/aes/SHA1.java
new file mode 100644
index 0000000..7f4d926
--- /dev/null
+++ b/xinelu-common/src/main/java/com/xinelu/common/utils/aes/SHA1.java
@@ -0,0 +1,94 @@
+package com.xinelu.common.utils.aes;
+
+import org.apache.commons.lang3.BooleanUtils;
+
+import java.security.MessageDigest;
+import java.util.Arrays;
+
+
+/**
+ * SHA1 class
+ *
+ *
+ * @Description 计算公众平台的消息签名接口
+ * @Author WeChat
+ * @Date 2023-03-14 15:09:50
+ */
+class SHA1 {
+
+ /**
+ * 用SHA1算法生成安全签名
+ *
+ * @param token 票据
+ * @param timestamp 时间戳
+ * @param nonce 随机字符串
+ * @param encrypt 密文
+ * @return 安全签名
+ * @throws AesException 异常信息
+ */
+ public static String getShaOne(String token, String timestamp, String nonce, String encrypt) throws AesException {
+ return signatureByShaOne(token, timestamp, nonce, encrypt, true);
+ }
+
+ /**
+ * 用SHA1算法生成安全签名,小程序回调设置验证URL时计算签名使用
+ *
+ * @param token 票据
+ * @param timestamp 时间戳
+ * @param nonce 随机字符串
+ * @return 安全签名
+ * @throws AesException 异常信息
+ */
+ public static String getShaTwo(String token, String timestamp, String nonce) throws AesException {
+ return signatureByShaOne(token, timestamp, nonce, "", false);
+ }
+
+ /**
+ * 使用SHA-1计算签名公共方法
+ *
+ * @param token 令牌
+ * @param timestamp 时间粗
+ * @param nonce 随机字符串
+ * @param encrypt 密文
+ * @param encryptFlag 密文传入标识
+ * @return String 明文
+ * @throws AesException 异常信息
+ */
+ private static String signatureByShaOne(String token, String timestamp, String nonce, String encrypt, boolean encryptFlag) throws AesException {
+ try {
+ String[] array;
+ int size;
+ if (BooleanUtils.isTrue(encryptFlag)) {
+ array = new String[]{token, timestamp, nonce, encrypt};
+ size = 4;
+ } else {
+ array = new String[]{token, timestamp, nonce};
+ size = 3;
+ }
+ StringBuilder sb = new StringBuilder();
+ // 字符串排序
+ Arrays.sort(array);
+ for (int i = 0; i < size; i++) {
+ sb.append(array[i]);
+ }
+ String str = sb.toString();
+ // SHA1签名生成
+ MessageDigest md = MessageDigest.getInstance("SHA-1");
+ md.update(str.getBytes());
+ byte[] digest = md.digest();
+ StringBuilder hexStr = new StringBuilder();
+ String shaHex;
+ for (byte b : digest) {
+ shaHex = Integer.toHexString(b & 0xFF);
+ if (shaHex.length() < 2) {
+ hexStr.append(0);
+ }
+ hexStr.append(shaHex);
+ }
+ return hexStr.toString();
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AesException(AesException.COMPUTE_SIGNATURE_ERROR);
+ }
+ }
+}
diff --git a/xinelu-common/src/main/java/com/xinelu/common/utils/aes/WXBizMsgCrypt.java b/xinelu-common/src/main/java/com/xinelu/common/utils/aes/WXBizMsgCrypt.java
new file mode 100644
index 0000000..c595c4b
--- /dev/null
+++ b/xinelu-common/src/main/java/com/xinelu/common/utils/aes/WXBizMsgCrypt.java
@@ -0,0 +1,234 @@
+package com.xinelu.common.utils.aes;
+
+import org.apache.commons.codec.binary.Base64;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.util.Arrays;
+import java.util.Random;
+
+/**
+ * @Description 提供接收和推送给公众平台消息的加解密接口(UTF8编码的字符串).
+ * @Author WeChat
+ * @Date 2023-03-14 15:09:50
+ */
+public class WXBizMsgCrypt {
+ static Charset CHARSET = StandardCharsets.UTF_8;
+ Base64 base64 = new Base64();
+ byte[] aesKey;
+ String token;
+ String appId;
+
+ /**
+ * 构造函数
+ *
+ * @param token 公众平台上,开发者设置的token
+ * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey
+ * @param appId 公众平台appid
+ * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+ */
+ public WXBizMsgCrypt(String token, String encodingAesKey, String appId) throws AesException {
+ int length = 43;
+ if (encodingAesKey.length() != length) {
+ throw new AesException(AesException.ILLEGAL_AES_KEY);
+ }
+ this.token = token;
+ this.appId = appId;
+ aesKey = Base64.decodeBase64(encodingAesKey + "=");
+ }
+
+ /**
+ * 生成4个字节的网络字节序
+ *
+ * @param sourceNumber 数值
+ * @return 字节数组
+ */
+ byte[] getNetworkBytesOrder(int sourceNumber) {
+ byte[] orderBytes = new byte[4];
+ orderBytes[3] = (byte) (sourceNumber & 0xFF);
+ orderBytes[2] = (byte) (sourceNumber >> 8 & 0xFF);
+ orderBytes[1] = (byte) (sourceNumber >> 16 & 0xFF);
+ orderBytes[0] = (byte) (sourceNumber >> 24 & 0xFF);
+ return orderBytes;
+ }
+
+ /**
+ * 还原4个字节的网络字节序
+ *
+ * @param orderBytes 字节数组
+ * @return 数值
+ */
+ int recoverNetworkBytesOrder(byte[] orderBytes) {
+ int sourceNumber = 0;
+ for (int i = 0; i < 4; i++) {
+ sourceNumber <<= 8;
+ sourceNumber |= orderBytes[i] & 0xff;
+ }
+ return sourceNumber;
+ }
+
+ /**
+ * 随机生成16位字符串
+ *
+ * @return 随机字符串
+ */
+ String getRandomStr() {
+ 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();
+ }
+
+ /**
+ * 对明文进行加密.
+ *
+ * @param text 需要加密的明文
+ * @return 加密后base64编码的字符串
+ * @throws AesException aes加密失败
+ */
+ String encrypt(String randomStr, String text) throws AesException {
+ ByteGroup byteCollector = new ByteGroup();
+ byte[] randomStrBytes = randomStr.getBytes(CHARSET);
+ byte[] textBytes = text.getBytes(CHARSET);
+ byte[] networkBytesOrder = getNetworkBytesOrder(textBytes.length);
+ byte[] appidBytes = appId.getBytes(CHARSET);
+ // randomStr + networkBytesOrder + text + appid
+ byteCollector.addBytes(randomStrBytes);
+ byteCollector.addBytes(networkBytesOrder);
+ byteCollector.addBytes(textBytes);
+ 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(aesKey, "AES");
+ IvParameterSpec iv = new IvParameterSpec(aesKey, 0, 16);
+ cipher.init(Cipher.ENCRYPT_MODE, keySpec, iv);
+ // 加密
+ byte[] encrypted = cipher.doFinal(unencrypted);
+ // 使用BASE64对加密后的字符串进行编码
+ return base64.encodeToString(encrypted);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AesException(AesException.ENCRYPT_AES_ERROR);
+ }
+ }
+
+ /**
+ * 对密文进行解密.
+ *
+ * @param text 需要解密的密文
+ * @return 解密得到的明文
+ * @throws AesException aes解密失败
+ */
+ String decrypt(String text) throws AesException {
+ byte[] original;
+ try {
+ // 设置解密模式为AES的CBC模式
+ Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding");
+ SecretKeySpec keySpec = new SecretKeySpec(aesKey, "AES");
+ IvParameterSpec iv = new IvParameterSpec(Arrays.copyOfRange(aesKey, 0, 16));
+ cipher.init(Cipher.DECRYPT_MODE, keySpec, iv);
+ // 使用BASE64对密文进行解码
+ byte[] encrypted = Base64.decodeBase64(text);
+ // 解密
+ original = cipher.doFinal(encrypted);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AesException(AesException.DECRYPT_AES_ERROR);
+ }
+ String xmlContent, fromAppid;
+ try {
+ // 去除补位字符
+ byte[] bytes = PKCS7Encoder.decode(original);
+ // 分离16位随机字符串,网络字节序和AppId
+ byte[] networkOrder = Arrays.copyOfRange(bytes, 16, 20);
+ int xmlLength = recoverNetworkBytesOrder(networkOrder);
+ xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), CHARSET);
+ fromAppid = new String(Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length),
+ CHARSET);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AesException(AesException.ILLEGAL_BUFFER);
+ }
+ // appid不相同的情况
+ if (!fromAppid.equals(appId)) {
+ throw new AesException(AesException.VALIDATE_APP_ID_ERROR);
+ }
+ return xmlContent;
+ }
+
+ /**
+ * @param replyMsg 公众平台待回复用户的消息,xml格式的字符串
+ * @param timeStamp 时间戳,可以自己生成,也可以用URL参数的timestamp
+ * @param nonce 随机串,可以自己生成,也可以用URL参数的nonce
+ * @return 加密后的可以直接回复用户的密文,包括msg_signature, timestamp, nonce, encrypt的xml格式的字符串
+ * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+ * @Description 将公众平台回复用户的消息加密打包.
+ */
+ public String encryptMsg(String replyMsg, String timeStamp, String nonce) throws AesException {
+ // 加密
+ String encrypt = encrypt(getRandomStr(), replyMsg);
+ // 生成安全签名
+ if ("".equals(timeStamp)) {
+ timeStamp = Long.toString(System.currentTimeMillis());
+ }
+ String signature = SHA1.getShaOne(token, timeStamp, nonce, encrypt);
+ // 生成发送的xml
+ return XMLParse.generate(encrypt, signature, timeStamp, nonce);
+ }
+
+ /**
+ * @param msgSignature 签名串,对应URL参数的msg_signature
+ * @param timeStamp 时间戳,对应URL参数的timestamp
+ * @param nonce 随机串,对应URL参数的nonce
+ * @param postData 密文,对应POST请求的数据
+ * @return 解密后的原文
+ * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+ * @Description 检验消息的真实性,并且获取解密后的明文.
+ */
+ public String decryptMsg(String msgSignature, String timeStamp, String nonce, String postData)
+ throws AesException {
+ // 密钥,公众账号的app secret
+ // 提取密文
+ Object[] encrypt = XMLParse.extract(postData);
+ // 验证安全签名
+ String signature = SHA1.getShaTwo(token, timeStamp, nonce);
+ // 和URL中的签名比较是否相等
+ if (!signature.equals(msgSignature)) {
+ throw new AesException(AesException.VALIDATE_SIGNATURE_ERROR);
+ }
+ // 解密
+ return decrypt(encrypt[1].toString());
+ }
+
+ /**
+ * 验证URL
+ *
+ * @param msgSignature 签名串,对应URL参数的msg_signature
+ * @param timeStamp 时间戳,对应URL参数的timestamp
+ * @param nonce 随机串,对应URL参数的nonce
+ * @param echoStr 随机串,对应URL参数的echostr
+ * @return 原始的随机串echostr
+ * @throws AesException 执行失败,请查看该异常的错误码和具体的错误信息
+ */
+ public String verifyUrl(String msgSignature, String timeStamp, String nonce, String echoStr) throws AesException {
+ String signature = SHA1.getShaTwo(token, timeStamp, nonce);
+ if (!signature.equals(msgSignature)) {
+ throw new AesException(AesException.VALIDATE_SIGNATURE_ERROR);
+ }
+ return echoStr;
+ }
+
+}
\ No newline at end of file
diff --git a/xinelu-common/src/main/java/com/xinelu/common/utils/aes/XMLParse.java b/xinelu-common/src/main/java/com/xinelu/common/utils/aes/XMLParse.java
new file mode 100644
index 0000000..e2b6ac3
--- /dev/null
+++ b/xinelu-common/src/main/java/com/xinelu/common/utils/aes/XMLParse.java
@@ -0,0 +1,68 @@
+package com.xinelu.common.utils.aes;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import java.io.StringReader;
+
+/**
+ * @Description 提供提取消息格式中的密文及生成回复消息格式的接口.
+ * @Author WeChat
+ * @Date 2023-03-14 15:09:50
+ */
+class XMLParse {
+
+ /**
+ * 提取出xml数据包中的加密消息
+ *
+ * @param xmltext 待提取的xml字符串
+ * @return 提取出的加密消息字符串
+ * @throws AesException 异常信息
+ */
+ public static Object[] extract(String xmltext) throws AesException {
+ Object[] result = new Object[3];
+ try {
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
+ dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
+ dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
+ dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);
+ dbf.setXIncludeAware(false);
+ dbf.setExpandEntityReferences(false);
+ DocumentBuilder db = dbf.newDocumentBuilder();
+ StringReader sr = new StringReader(xmltext);
+ InputSource is = new InputSource(sr);
+ Document document = db.parse(is);
+ Element root = document.getDocumentElement();
+ NodeList nodelist1 = root.getElementsByTagName("Encrypt");
+ NodeList nodelist2 = root.getElementsByTagName("ToUserName");
+ result[0] = 0;
+ result[1] = nodelist1.item(0).getTextContent();
+ result[2] = nodelist2.item(0).getTextContent();
+ return result;
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new AesException(AesException.PARSE_XML_ERROR);
+ }
+ }
+
+ /**
+ * 生成xml消息
+ *
+ * @param encrypt 加密后的消息密文
+ * @param signature 安全签名
+ * @param timestamp 时间戳
+ * @param nonce 随机字符串
+ * @return 生成的xml字符串
+ */
+ public static String generate(String encrypt, String signature, String timestamp, String nonce) {
+ String format = "\n" + "\n"
+ + "\n"
+ + "%3$s\n" + "\n" + "";
+ return String.format(format, encrypt, signature, timestamp, nonce);
+ }
+}
diff --git a/xinelu-framework/src/main/java/com/xinelu/framework/aspectj/MobileRequestAuthorizationAspect.java b/xinelu-framework/src/main/java/com/xinelu/framework/aspectj/MobileRequestAuthorizationAspect.java
new file mode 100644
index 0000000..d1ce0be
--- /dev/null
+++ b/xinelu-framework/src/main/java/com/xinelu/framework/aspectj/MobileRequestAuthorizationAspect.java
@@ -0,0 +1,86 @@
+package com.xinelu.framework.aspectj;
+
+import com.xinelu.common.constant.Constants;
+import com.xinelu.common.exception.ServiceException;
+import io.jsonwebtoken.Jwts;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.Objects;
+
+/**
+ * @Description 移动端接口校验处理
+ * @Author 纪寒
+ * @Date 2022-12-09 10:55:53
+ * @Version 1.0
+ */
+@Slf4j
+@Aspect
+@Component
+public class MobileRequestAuthorizationAspect {
+
+ /**
+ * 令牌秘钥标识
+ */
+ @Value("${token.secret}")
+ private String secret;
+
+ /**
+ * 令牌自定义标识
+ */
+ @Value("${token.header}")
+ private String header;
+
+ /**
+ * 移动端令牌前缀
+ */
+ private static final String TOKEN_PREFIX = "Bearer ";
+
+ /**
+ * 移动端令牌前缀
+ */
+ private static final Integer ERROR_CODE = 9999;
+
+ @Resource
+ private RedisTemplate redisTemplate;
+
+ @Pointcut("execution(@com.xinelu.common.annotation.MobileRequestAuthorization * *(..))")
+ private void judgeTokenInfo() {
+ }
+
+ @Before("judgeTokenInfo()")
+ public void doJudgeTokenInfo() {
+ HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
+ String requestHeader = request.getHeader(header);
+ if (StringUtils.isBlank(requestHeader)) {
+ log.warn("获取请求头中的Authorization令牌头部信息失败!");
+ throw new ServiceException("验证签名错误,请重新登录!", ERROR_CODE);
+ }
+ try {
+ String token = request.getHeader(header).replaceAll(TOKEN_PREFIX, "");
+ if (StringUtils.isBlank(token)) {
+ log.warn("获取请求头中的Authorization令牌信息为空!");
+ throw new ServiceException("验证签名错误,请重新登录!", ERROR_CODE);
+ }
+ String uuid = (String) Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody().get(Constants.MOBILE_AUTHORIZATION_PREFIX);
+ String tokenString = redisTemplate.opsForValue().get(Constants.MOBILE_AUTHORIZATION_KEY + uuid);
+ if (StringUtils.isBlank(tokenString) || !StringUtils.equals(token, tokenString)) {
+ log.warn("Redis中的令牌信息已失效或者为空!");
+ throw new ServiceException("验证签名错误,请重新登录!", ERROR_CODE);
+ }
+ } catch (Exception e) {
+ log.error("移动端验证签名异常,异常信息为=====>{}", e.getMessage());
+ throw new ServiceException("验证签名错误,请重新登录!", ERROR_CODE);
+ }
+ }
+}
diff --git a/xinelu-framework/src/main/java/com/xinelu/framework/config/AsyncExecutorConfig.java b/xinelu-framework/src/main/java/com/xinelu/framework/config/AsyncExecutorConfig.java
new file mode 100644
index 0000000..a8c4058
--- /dev/null
+++ b/xinelu-framework/src/main/java/com/xinelu/framework/config/AsyncExecutorConfig.java
@@ -0,0 +1,39 @@
+package com.xinelu.framework.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * @Description 异步任务线程池配置类
+ * @Author 纪寒
+ * @Date 2023-03-17 09:55:36
+ * @Version 1.0
+ */
+@Slf4j
+@Configuration
+@EnableAsync
+public class AsyncExecutorConfig {
+ /**
+ * 创建一个核心线程为10个,最大线程为20,等待队列为10,拒绝策略为线程最大需求满就返回给调度线程执行
+ *
+ * @return 创建完的线程池
+ */
+ @Bean
+ public Executor asyncThreadServiceExecutor() {
+ log.info("异步线程池配置执行");
+ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+ executor.setCorePoolSize(10);
+ executor.setMaxPoolSize(20);
+ executor.setQueueCapacity(10);
+ executor.setThreadNamePrefix("async-thread-service-");
+ executor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
+ executor.initialize();
+ return executor;
+ }
+}
diff --git a/xinelu-framework/src/main/java/com/xinelu/framework/config/RedisDistributedLockUtilsConfig.java b/xinelu-framework/src/main/java/com/xinelu/framework/config/RedisDistributedLockUtilsConfig.java
new file mode 100644
index 0000000..58e1457
--- /dev/null
+++ b/xinelu-framework/src/main/java/com/xinelu/framework/config/RedisDistributedLockUtilsConfig.java
@@ -0,0 +1,21 @@
+package com.xinelu.framework.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.integration.redis.util.RedisLockRegistry;
+
+/**
+ * @Description Redis分布式锁配置
+ * @Author 纪寒
+ * @Date 2022-10-26 15:27:41
+ * @Version 1.0
+ */
+@Configuration
+public class RedisDistributedLockUtilsConfig {
+
+ @Bean
+ public RedisLockRegistry redisLockRegistry(RedisConnectionFactory redisConnectionFactory) {
+ return new RedisLockRegistry(redisConnectionFactory, this.getClass().getName());
+ }
+}
diff --git a/xinelu-nurse-applet/pom.xml b/xinelu-nurse-applet/pom.xml
index 63437ec..7567c88 100644
--- a/xinelu-nurse-applet/pom.xml
+++ b/xinelu-nurse-applet/pom.xml
@@ -40,5 +40,11 @@
swagger-models
1.6.2
+
+
+
+ org.simpleframework
+ simple-xml
+
\ No newline at end of file
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/controller/nursingstationgoods/NursingStationGoodsController.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/controller/nursingstationgoods/NursingStationGoodsController.java
new file mode 100644
index 0000000..d075c94
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/controller/nursingstationgoods/NursingStationGoodsController.java
@@ -0,0 +1,233 @@
+package com.xinelu.applet.controller.nursingstationgoods;
+
+import com.xinelu.applet.dto.nursingstationgoods.GoodsList;
+import com.xinelu.applet.dto.nursingstationgoods.GoodsOrderPatient;
+import com.xinelu.applet.dto.nursingstationgoods.GoodsOrderStationDTO;
+import com.xinelu.applet.service.nursingstationgoods.INursingStationGoodsService;
+import com.xinelu.applet.vo.nursingstationgoods.UpdateDefaultAddressVO;
+import com.xinelu.common.annotation.MobileRequestAuthorization;
+import com.xinelu.common.annotation.RepeatSubmit;
+import com.xinelu.common.core.controller.BaseController;
+import com.xinelu.common.core.domain.AjaxResult;
+import com.xinelu.common.core.page.TableDataInfo;
+import com.xinelu.common.custominterface.Insert;
+import com.xinelu.common.custominterface.Update;
+import com.xinelu.common.exception.ServiceException;
+import com.xinelu.manage.domain.goodsCategory.GoodsCategory;
+import com.xinelu.manage.domain.receiveAddressInfo.ReceiveAddressInfo;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.util.List;
+import java.util.Objects;
+
+
+/**
+ * 商品信息页面控制器
+ *
+ * @author ljh
+ * @version 1.0
+ * Create by 2022/10/17 13:40
+ */
+
+@RestController
+@RequestMapping("/nurseApplet/nursingStationGoods")
+public class NursingStationGoodsController extends BaseController {
+
+ @Resource
+ private INursingStationGoodsService nursingStationGoodsService;
+
+ /**
+ * 查询商品分类信息列表
+ */
+ @MobileRequestAuthorization
+ @GetMapping("/goodsCategoryList")
+ public TableDataInfo goodsCategoryList(GoodsCategory goodsCategory) {
+ startPage();
+ List goodsCategoryList = nursingStationGoodsService.getGoodsCategoryList(goodsCategory);
+ return getDataTable(goodsCategoryList);
+ }
+
+ /**
+ * 查询商品二级分类信息列表
+ */
+ @MobileRequestAuthorization
+ @GetMapping("/getGoodsCategoryNameList")
+ public AjaxResult getGoodsCategoryNameList(Long goodsCategoryId) {
+ if (Objects.isNull(goodsCategoryId)) {
+ return AjaxResult.error("商品分类信息id不能为空!");
+ }
+ return nursingStationGoodsService.getGoodsCategoryNameList(goodsCategoryId);
+ }
+
+ /**
+ * 根据商品分类id查询商品信息
+ *
+ * @param goodsList 商品信息
+ * @return com.xinyilu.common.core.page.TableDataInfo
+ **/
+ @MobileRequestAuthorization
+ @GetMapping("/goodsList")
+ public TableDataInfo goodsList(GoodsList goodsList) {
+ return nursingStationGoodsService.getGoodsInfoList(goodsList);
+ }
+
+
+ /**
+ * 根据商品id查询商品详细信息
+ *
+ * @param goodsInfoId 商品详细id
+ * @param patientId 用户信息id
+ * @return com.xinyilu.nurseapplet.domain.nearbynursingstation.NearbyNursingStationVO
+ **/
+ @MobileRequestAuthorization
+ @GetMapping("/goodsDetails")
+ public AjaxResult goodsDetails(Long goodsInfoId, Long patientId) {
+ if (Objects.isNull(goodsInfoId)) {
+ return AjaxResult.error("商品id不能为空!");
+ }
+ return AjaxResult.success(nursingStationGoodsService.getGoodsDetails(goodsInfoId, patientId));
+ }
+
+
+ /**
+ * 手机App和微信小程序商城确认订单方法
+ *
+ * @param goodsOrder 商品订单
+ * @return 结果
+ */
+ @MobileRequestAuthorization
+ @RepeatSubmit
+ @PostMapping("/addStationGoodsOrder")
+ public AjaxResult addStationGoodsOrder(@Validated(Insert.class) @RequestBody GoodsOrderStationDTO goodsOrder, BindingResult bindingResult) {
+ if (bindingResult.hasErrors()) {
+ throw new ServiceException(bindingResult.getAllErrors().get(0).getDefaultMessage());
+ }
+ if (Objects.nonNull(goodsOrder.getTotalPrice()) && goodsOrder.getTotalPrice().compareTo(BigDecimal.ZERO) <= 0) {
+ return AjaxResult.error("订单金额不正确,无法下单,请输入正确的订单金额!");
+ }
+ return nursingStationGoodsService.insertNurseStationGoodsOrder(goodsOrder);
+ }
+
+
+ /**
+ * 根据订单编号查询订单信息(废弃,暂时不用)
+ *
+ * @param orderNo 订单信息编号
+ * @return com.xinyilu.nurseapplet.domain.nursingStationGoods.GoodsOrderPatient
+ **/
+ @GetMapping("/orderPatient")
+ public AjaxResult orderPatient(String orderNo) {
+ if (StringUtils.isBlank(orderNo)) {
+ return AjaxResult.error("订单编号不能为空!");
+ }
+ GoodsOrderPatient orderPatient = nursingStationGoodsService.selectGoodsOrderPatient(orderNo);
+ return AjaxResult.success(orderPatient);
+ }
+
+ /**
+ * 根据被护理人id查询基本信息
+ *
+ * @param patientId 被护理人id
+ * @return com.xinyilu.base.domain.patientinfo.PatientInfo
+ **/
+ @MobileRequestAuthorization
+ @GetMapping("/goodPatientInfo")
+ public AjaxResult goodPatientInfo(Long patientId) {
+ if (Objects.isNull(patientId)) {
+ return AjaxResult.error("会员信息不能为空!");
+ }
+ return nursingStationGoodsService.getReceiveAddressInfoList(patientId);
+ }
+
+ /**
+ * 获取收货人地址信息详细信息
+ */
+ @MobileRequestAuthorization
+ @GetMapping(value = "/{id}")
+ public AjaxResult getInfo(@PathVariable("id") Long id) {
+ return AjaxResult.success(nursingStationGoodsService.selectReceiveAddressInfoById(id));
+ }
+
+
+ /**
+ * 新增收货人地址信息
+ */
+ @MobileRequestAuthorization
+ @PostMapping("/add")
+ public AjaxResult add(@Validated(Insert.class) @RequestBody ReceiveAddressInfo receiveAddressInfo, BindingResult bindingResult) {
+ if (bindingResult.hasErrors()) {
+ throw new ServiceException(bindingResult.getAllErrors().get(0).getDefaultMessage());
+ }
+ return toAjax(nursingStationGoodsService.insertReceiveAddressInfo(receiveAddressInfo));
+ }
+
+
+ /**
+ * 修改收货人地址信息
+ */
+ @MobileRequestAuthorization
+ @PostMapping("/edit")
+ public AjaxResult edit(@Validated(Update.class) @RequestBody ReceiveAddressInfo receiveAddressInfo, BindingResult bindingResult) {
+ if (bindingResult.hasErrors()) {
+ throw new ServiceException(bindingResult.getAllErrors().get(0).getDefaultMessage());
+ }
+ return toAjax(nursingStationGoodsService.updateReceiveAddressInfo(receiveAddressInfo));
+ }
+
+ /**
+ * 删除收货人地址信息
+ */
+ @MobileRequestAuthorization
+ @DeleteMapping("/{ids}")
+ public AjaxResult remove(@PathVariable Long[] ids) {
+ return toAjax(nursingStationGoodsService.deleteReceiveAddressInfoByIds(ids));
+ }
+
+
+ /**
+ * 获取区域详细信息
+ */
+ @MobileRequestAuthorization
+ @GetMapping("/getSubordinateRegions")
+ public AjaxResult getSubordinateRegionsFindSuperiorRegions(@RequestParam("areaCode") String areaCode) {
+ if (StringUtils.isBlank(areaCode)) {
+ return AjaxResult.error("区域编码不能为空!");
+ }
+ return AjaxResult.success(nursingStationGoodsService.getSubordinateRegionsFindSuperiorRegions(areaCode));
+ }
+
+ /**
+ * App和微信小程序确认收货
+ *
+ * @param orderNo 订单编号
+ * @return 返回结果
+ */
+ @MobileRequestAuthorization
+ @PostMapping("/confirmReceipt")
+ public AjaxResult confirmReceipt(String orderNo) {
+ if (StringUtils.isBlank(orderNo)) {
+ return AjaxResult.error("请选择订单信息!");
+ }
+ return nursingStationGoodsService.confirmReceipt(orderNo);
+ }
+
+ /**
+ * 微信小程序和会员App设置默认地址接口
+ *
+ * @param defaultAddressList 默认地址标识集合
+ * @return 结果
+ */
+ @PostMapping("/updateDefaultAddress")
+ public AjaxResult updateDefaultAddress(@RequestBody @Validated(Update.class) List defaultAddressList) {
+ if (CollectionUtils.isEmpty(defaultAddressList)) {
+ return AjaxResult.error("请选择要设置的收货地址信息!");
+ }
+ return nursingStationGoodsService.updateDefaultAddress(defaultAddressList);
+ }
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/controller/patientcenter/PatientCenterController.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/controller/patientcenter/PatientCenterController.java
new file mode 100644
index 0000000..556f272
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/controller/patientcenter/PatientCenterController.java
@@ -0,0 +1,197 @@
+package com.xinelu.applet.controller.patientcenter;
+
+import com.xinelu.applet.dto.nursingstationgoods.GoodsList;
+import com.xinelu.applet.dto.nursingstationgoods.GoodsOrderStationDTO;
+import com.xinelu.applet.dto.patientcenter.PatientCenterCouponDTO;
+import com.xinelu.applet.service.patientcenter.PatientCenterService;
+import com.xinelu.applet.vo.coupon.CouponVO;
+import com.xinelu.applet.vo.patientcenter.PatientCenterCouponVO;
+import com.xinelu.common.annotation.MobileRequestAuthorization;
+import com.xinelu.common.annotation.RepeatSubmit;
+import com.xinelu.common.core.controller.BaseController;
+import com.xinelu.common.core.domain.AjaxResult;
+import com.xinelu.common.core.page.TableDataInfo;
+import com.xinelu.common.custominterface.Insert;
+import com.xinelu.common.exception.ServiceException;
+import com.xinelu.manage.dto.subscribemessagerecord.SubscribeMessageRecordDTO;
+import com.xinelu.manage.service.patientinfo.IPatientInfoService;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.validation.BindingResult;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 被护理人基本信息Controller
+ *
+ * @author zhangheng
+ * @date 2022-09-02
+ */
+@RestController
+@RequestMapping("/nurseApplet/patientInfo")
+public class PatientCenterController extends BaseController {
+
+ @Resource
+ private IPatientInfoService patientInfoService;
+ @Resource
+ private PatientCenterService patientCenterService;
+
+ /**
+ * 根据登录id查询个人信息
+ *
+ * @param id 被护理人id
+ * @return 护理人信息
+ */
+ @GetMapping(value = "/id")
+ public AjaxResult getInfo(Long id) {
+ if (Objects.isNull(id)) {
+ return AjaxResult.error("被护理人编号不能为空!");
+ }
+ return AjaxResult.success(patientInfoService.selectPatientInfoById(id));
+ }
+
+ /**
+ * 会员app和微信小程序-签到方法
+ *
+ * @param patientId 会员用户id
+ * @param signInChannel 签到来源,微信小程序、会员APP
+ * @return 签到结果
+ */
+ @MobileRequestAuthorization
+ @PostMapping("/signIn")
+ public AjaxResult patientSignIn(Long patientId, String signInChannel) {
+ if (Objects.isNull(patientId)) {
+ return AjaxResult.error("会员信息不能为空!");
+ }
+ if (StringUtils.isBlank(signInChannel)) {
+ return AjaxResult.error("签到方式不能为为空!");
+ }
+ return patientCenterService.patientSignIn(patientId, signInChannel);
+ }
+
+ /**
+ * 个人中心优惠券(共用)
+ *
+ * @param patientCenterCouponVO 用户信息及优惠券状态
+ * @return List
+ */
+ @MobileRequestAuthorization
+ @GetMapping("/selectCoupon")
+ public TableDataInfo selectCoupon(@Validated(Insert.class) PatientCenterCouponVO patientCenterCouponVO) {
+ startPage();
+ List list = patientCenterService.selectCouponByUseStatus(patientCenterCouponVO);
+ return getDataTable(list);
+ }
+
+ /**
+ * 个人中心积分兑换-查询可以兑换的商品
+ *
+ * @return List
+ */
+ @MobileRequestAuthorization
+ @GetMapping("selectExchangeGoods")
+ public TableDataInfo selectExchangeGoods() {
+ startPage();
+ List list = patientCenterService.selectExchangeGoods();
+ return getDataTable(list);
+ }
+
+ /**
+ * 获取积分返回规则
+ *
+ * @param patientId 用户id
+ * @return com.xinyilu.nurseapplet.domain.vo.patientcenter.PatientSignInfoVO
+ **/
+ @MobileRequestAuthorization
+ @GetMapping("selectPatientSignIn")
+ public AjaxResult selectPatientSignIn(Long patientId) {
+ if (Objects.isNull(patientId)) {
+ return AjaxResult.error("会员信息不能为空!");
+ }
+ return AjaxResult.success(patientCenterService.selectPatientSignIn(patientId));
+ }
+
+ /**
+ * 微信小程序-邀请好友接口
+ *
+ * @param inviteId 邀请人id
+ * @return 邀请码图片地址
+ */
+ @MobileRequestAuthorization
+ @PostMapping("/inviteFriends")
+ public AjaxResult inviteFriends(Long inviteId) {
+ if (Objects.isNull(inviteId)) {
+ return AjaxResult.error("邀请人信息不能为空!");
+ }
+ return patientCenterService.inviteFriends(inviteId);
+ }
+
+ /**
+ * 新人福利优惠券(共用)
+ *
+ * @param patientCenterCouponDTO 用户信息及优惠券状态
+ * @return List
+ */
+ @MobileRequestAuthorization
+ @GetMapping("/couponByUseStatus")
+ public TableDataInfo couponByUseStatus(PatientCenterCouponDTO patientCenterCouponDTO) {
+ return patientCenterService.getCouponByUseStatus(patientCenterCouponDTO);
+ }
+
+ /**
+ * 新人福利-优惠券领取
+ *
+ * @param patientId 用户id
+ * @param couponId 优惠券id
+ * @return AjaxResult
+ */
+ @MobileRequestAuthorization
+ @PostMapping("/insertCouponReceive")
+ public AjaxResult insertCouponReceive(Long patientId, Long couponId) {
+ if (Objects.isNull(patientId) || Objects.isNull(couponId)) {
+ return AjaxResult.error("用户信息或优惠券信息不能为空!");
+ }
+ return patientCenterService.insertCouponReceive(patientId, couponId);
+ }
+
+ /**
+ * 手机App和微信小程序积分兑换订单方法
+ *
+ * @param goodsOrder 商品订单
+ * @return 结果
+ */
+ @MobileRequestAuthorization
+ @RepeatSubmit
+ @PostMapping("/integralGoodsOrder")
+ public AjaxResult integralGoodsOrder(@Validated(Insert.class) @RequestBody GoodsOrderStationDTO goodsOrder, BindingResult bindingResult) {
+ if (bindingResult.hasErrors()) {
+ throw new ServiceException(bindingResult.getAllErrors().get(0).getDefaultMessage());
+ }
+ if (Objects.isNull(goodsOrder.getIntegralExchangeSill()) || goodsOrder.getIntegralExchangeSill() <= 0) {
+ return AjaxResult.error("当前积分数值不足,无法兑换!");
+ }
+ if (Objects.isNull(goodsOrder.getIntegralExchangeCount()) || goodsOrder.getIntegralExchangeCount() <= 0) {
+ return AjaxResult.error("兑换商品数量不正确,无法兑换!");
+ }
+ return patientCenterService.insertIntegralGoodsOrder(goodsOrder);
+ }
+
+ /**
+ * 新增订阅微信小程序订阅消息记录,暂时走微信回调事件,未使用
+ *
+ * @param subscribeMessageRecord 订阅微信小程序订阅消息记录
+ * @return com.xinyilu.common.core.domain.AjaxResult
+ **/
+ @MobileRequestAuthorization
+ @PostMapping("/insertSubscribeMessageRecord")
+ public AjaxResult insertSubscribeMessageRecord(@RequestBody SubscribeMessageRecordDTO subscribeMessageRecord) {
+ if (CollectionUtils.isEmpty(subscribeMessageRecord.getSubscribeMessageRecordList())) {
+ return AjaxResult.error("订阅信息不能为空!");
+ }
+ return patientCenterService.insertSubscribeMessageRecord(subscribeMessageRecord.getSubscribeMessageRecordList());
+ }
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/controller/wechatappletcallback/WeChatAppletCallBackController.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/controller/wechatappletcallback/WeChatAppletCallBackController.java
new file mode 100644
index 0000000..9c9602e
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/controller/wechatappletcallback/WeChatAppletCallBackController.java
@@ -0,0 +1,74 @@
+package com.xinelu.applet.controller.wechatappletcallback;
+
+import com.xinelu.applet.dto.appletcallback.MessageSignDTO;
+import com.xinelu.applet.service.wechatappletcallback.WeChatAppletCallBackService;
+import com.xinelu.applet.utils.XmlUtil;
+import com.xinelu.applet.vo.messagepush.WeChatMessagePushVO;
+import com.xinelu.common.config.AppletChatConfig;
+import com.xinelu.common.utils.aes.AesException;
+import com.xinelu.common.utils.aes.WXBizMsgCrypt;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.Objects;
+
+/**
+ * @Description 微信小程序事件回调控制器
+ * @Author 纪寒
+ * @Date 2023-03-14 15:09:50
+ * @Version 1.0
+ */
+@Slf4j
+@RestController
+@RequestMapping("/nurseApplet/weChatAppletCallBack")
+public class WeChatAppletCallBackController {
+
+ @Resource
+ private AppletChatConfig appletChatConfig;
+ @Resource
+ private WeChatAppletCallBackService weChatAppletCallBackService;
+
+ /**
+ * 微信小程序回调验证方法
+ *
+ * @param messageSignDTO 微信输入参数
+ * @return 解密后的字符串
+ * @throws AesException 异常信息
+ */
+ @GetMapping
+ public String getWeChatAppletCallBack(MessageSignDTO messageSignDTO) throws AesException {
+ WXBizMsgCrypt wxCpt = new WXBizMsgCrypt(appletChatConfig.getToken(), appletChatConfig.getEncodingAesKey(), appletChatConfig.getAppletId());
+ String verifyMessage = wxCpt.verifyUrl(messageSignDTO.getSignature(), messageSignDTO.getTimestamp(), messageSignDTO.getNonce(), messageSignDTO.getEchostr());
+ log.info("微信小程序回调设置验证URL成功,验证信息:verifyMessage = [{}]", verifyMessage);
+ return verifyMessage;
+ }
+
+ /**
+ * 微信小程序消息推送事件回调POST处理
+ *
+ * @param signature 签名
+ * @param timestamp 时间戳
+ * @param nonce 随机字符串
+ * @param postData 消息体,xml格式
+ */
+ @PostMapping
+ public void handleWeChatAppletCallBack(@RequestParam("signature") String signature,
+ @RequestParam("timestamp") String timestamp,
+ @RequestParam("nonce") String nonce,
+ @RequestBody String postData) throws AesException {
+ WXBizMsgCrypt wxCpt = new WXBizMsgCrypt(appletChatConfig.getToken(), appletChatConfig.getEncodingAesKey(), appletChatConfig.getAppletId());
+ String decryptMsg = wxCpt.decryptMsg(signature, timestamp, nonce, postData);
+ WeChatMessagePushVO weChatMessagePushVO = (WeChatMessagePushVO) XmlUtil.fromXml(decryptMsg, WeChatMessagePushVO.class);
+ if (Objects.isNull(weChatMessagePushVO)) {
+ log.error("xml数据转换失败,请求信息为: [{}]", decryptMsg);
+ return;
+ }
+ if (StringUtils.isBlank(weChatMessagePushVO.getEvent()) || StringUtils.isBlank(weChatMessagePushVO.getMsgType())) {
+ return;
+ }
+ log.info("微信小程序消息推送回调执行,消息数据为: [{}]", weChatMessagePushVO);
+ weChatAppletCallBackService.handleWeChatAppletCallBack(weChatMessagePushVO);
+ }
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/dto/appletcallback/MessageSignDTO.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/dto/appletcallback/MessageSignDTO.java
new file mode 100644
index 0000000..f3397e9
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/dto/appletcallback/MessageSignDTO.java
@@ -0,0 +1,40 @@
+package com.xinelu.applet.dto.appletcallback;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @Description 消息验证实体类
+ * @Author 纪寒
+ * @Date 2023-03-14 15:53:01
+ * @Version 1.0
+ */
+@Data
+public class MessageSignDTO implements Serializable {
+ private static final long serialVersionUID = -2514572635286835742L;
+ /**
+ * 微信小程序签名
+ */
+ private String signature;
+
+ /**
+ * 时间戳
+ */
+ private String timestamp;
+
+ /**
+ * 随机字符串
+ */
+ private String nonce;
+
+ /**
+ * 加密的字符串
+ */
+ private String echostr;
+
+ /**
+ * 回调数据包,xml格式
+ */
+ private String postData;
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/dto/patientcenter/PatientCenterCouponDTO.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/dto/patientcenter/PatientCenterCouponDTO.java
new file mode 100644
index 0000000..6f6a144
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/dto/patientcenter/PatientCenterCouponDTO.java
@@ -0,0 +1,41 @@
+package com.xinelu.applet.dto.patientcenter;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author ljh
+ * @version 1.0
+ * Create by 2023/3/2 10:43
+ */
+@Data
+public class PatientCenterCouponDTO implements Serializable {
+ private static final long serialVersionUID = -3649311477999618876L;
+
+
+ /**
+ * 会员id
+ */
+ private Long patientId;
+
+ /**
+ * 优惠券使用状态
+ */
+ private String useStatus;
+
+ /**
+ * 领取方式,新人福利:NEW_PEOPLE_WELFARE,活动赠送:EVENT_GIFT,消费返券:CONSUME_REBATE
+ */
+ private String receiveType;
+
+ /**
+ * 优惠券来源
+ */
+ private String receiveSource;
+
+ /**
+ * 优惠券id
+ */
+ private String couponId;
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/mapper/nurseapplogin/NurseAppLoginMapper.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/mapper/nurseapplogin/NurseAppLoginMapper.java
index 15ed9e6..64dbc33 100644
--- a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/mapper/nurseapplogin/NurseAppLoginMapper.java
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/mapper/nurseapplogin/NurseAppLoginMapper.java
@@ -20,4 +20,12 @@ public interface NurseAppLoginMapper {
* @return PatientDiseaseInfo
*/
PatientAndDiseaseVO getPatientDiseaseByPatientId(@Param("patientId") Long patientId);
+
+ /**
+ * 查询信息完善标识符
+ *
+ * @param patientId 账号信息
+ * @return 数量
+ */
+ Integer getLoginFlagByPatientId(@Param("patientId") Long patientId);
}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/mapper/nursingstationgoods/NursingStationGoodsMapper.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/mapper/nursingstationgoods/NursingStationGoodsMapper.java
new file mode 100644
index 0000000..562203f
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/mapper/nursingstationgoods/NursingStationGoodsMapper.java
@@ -0,0 +1,152 @@
+package com.xinelu.applet.mapper.nursingstationgoods;
+
+import com.xinelu.applet.dto.nursingstationgoods.GoodDetails;
+import com.xinelu.applet.dto.nursingstationgoods.GoodsList;
+import com.xinelu.applet.dto.nursingstationgoods.GoodsOrderPatient;
+import com.xinelu.applet.vo.coupon.CouponVO;
+import com.xinelu.manage.domain.goodsAttributeDetails.GoodsAttributeDetails;
+import com.xinelu.manage.domain.goodsCategory.GoodsCategory;
+import com.xinelu.manage.domain.receiveAddressInfo.ReceiveAddressInfo;
+import com.xinelu.manage.vo.goodsCategory.GoodsCategoryNameVO;
+import com.xinelu.manage.vo.receiveAddressInfo.ReceiveAddressInfoVO;
+import com.xinelu.manage.vo.sysarea.SysAreaVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * @author ljh
+ * @version 1.0
+ * Create by 2022/10/17 13:31
+ */
+public interface NursingStationGoodsMapper {
+
+ /**
+ * 查询商品分类信息列表
+ *
+ * @param goodsCategory 商品分类信息
+ * @return 商品分类信息集合
+ */
+ List getGoodsCategoryList(GoodsCategory goodsCategory);
+
+ /**
+ * 根据商品分类id查询商品信息
+ *
+ * @param goodsList 商品信息
+ * @return 商品基本信息集合
+ */
+ List getGoodsInfoList(GoodsList goodsList);
+
+ /**
+ * 查询商品二级分类信息列表
+ *
+ * @param goodsCategory 商品分类信息
+ * @return 商品分类信息集合
+ */
+ List getGoodsCategoryNameList(GoodsCategoryNameVO goodsCategory);
+
+ /**
+ * 商品属性信息
+ *
+ * @param goodsInfoId 商品详细id
+ * @return java.util.List
+ **/
+ GoodDetails getGoodsDetailsList(Long goodsInfoId);
+
+ /**
+ * 根据被护理人id查询基本信息
+ *
+ * @param patientId 被护理人id
+ * @return com.xinyilu.base.domain.patientinfo.PatientInfo
+ **/
+ List getReceiveAddressInfoList(Long patientId);
+
+ /**
+ * 根据被护理人id查询基本信息集合
+ *
+ * @param patientId 被护理人id
+ * @return java.util.List
+ **/
+ List selectReceiveAddressInfoByPatientId(Long patientId);
+
+ /**
+ * 查询收货人地址信息
+ *
+ * @param id 收货人地址信息主键
+ * @return 收货人地址信息
+ */
+ ReceiveAddressInfo selectReceiveAddressInfoById(Long id);
+
+ /**
+ * 新增收货人地址信息
+ *
+ * @param receiveAddressInfo 收货人地址信息
+ * @return 结果
+ */
+ int insertReceiveAddressInfo(ReceiveAddressInfo receiveAddressInfo);
+
+ /**
+ * 修改收货人地址信息
+ *
+ * @param receiveAddressInfo 收货人地址信息
+ * @return 结果
+ */
+ int updateReceiveAddressInfo(ReceiveAddressInfo receiveAddressInfo);
+
+ /**
+ * 批量删除收货人地址信息
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ int deleteReceiveAddressInfoByIds(Long[] ids);
+
+ /**
+ * 下级区域寻找上级区域
+ *
+ * @param areaCode 区域编码
+ * @return com.xinyilu.base.domain.vo.sysarea.SysAreaVO
+ **/
+ SysAreaVO getSubordinateRegionsFindSuperiorRegions(@Param("areaCode") String areaCode);
+
+ /**
+ * 查询商品属性明细
+ *
+ * @param id 商品属性明细主键
+ * @return 商品属性明细
+ */
+ GoodsAttributeDetails selectGoodsAttributeDetailsGoodsStockById(Long id);
+
+ /**
+ * 修改商品属性明细
+ *
+ * @param goodsAttributeDetails 商品属性明细
+ * @return 结果
+ */
+ int updateGoodsAttributeDetails(GoodsAttributeDetails goodsAttributeDetails);
+
+ /**
+ * 根据订单编号查询订单信息
+ *
+ * @param orderNo 订单信息编号
+ * @return com.xinyilu.nurseapplet.domain.nursingStationGoods.GoodsOrderPatient
+ **/
+ GoodsOrderPatient selectGoodsOrderPatient(String orderNo);
+
+ /**
+ * 查询商品分类信息下的所有子id
+ *
+ * @param goodsCategoryId 当前商品分类id
+ * @return com.xinyilu.base.domain.goodsCategory.GoodsCategory
+ **/
+ String getChildrenCategoryIds(Long goodsCategoryId);
+
+ /**
+ * 商品详情查询用户优惠券信息
+ *
+ * @param patientId 用户信息
+ * @param useStatus 优惠券状态
+ * @return List
+ */
+ List selectCouponListByPatient(@Param("patientId") Long patientId, @Param("useStatus") String useStatus);
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/mapper/patientcenter/PatientCenterMapper.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/mapper/patientcenter/PatientCenterMapper.java
new file mode 100644
index 0000000..68fc236
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/mapper/patientcenter/PatientCenterMapper.java
@@ -0,0 +1,116 @@
+package com.xinelu.applet.mapper.patientcenter;
+
+import com.xinelu.applet.dto.nursingstationgoods.GoodsList;
+import com.xinelu.applet.dto.patientcenter.PatientCenterCouponDTO;
+import com.xinelu.applet.vo.coupon.CouponVO;
+import com.xinelu.applet.vo.patientcenter.PatientCenterCouponVO;
+import com.xinelu.applet.vo.patientcenter.PatientSignInVO;
+import com.xinelu.applet.vo.patientcenter.PatientSignInfoVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.time.LocalDate;
+import java.util.List;
+
+/**
+ * 个人中心Mapper接口
+ *
+ * @author zh
+ * @date 2023-02-24
+ */
+public interface PatientCenterMapper {
+ /**
+ * 根据优惠券状态查询优惠券信息
+ *
+ * @param patientCenterCouponVO 用户信息及优惠券状态
+ * @return List
+ */
+ List selectCouponByUseStatus(PatientCenterCouponVO patientCenterCouponVO);
+
+ /**
+ * 积分兑换 - 查询积分兑换商品
+ *
+ * @param integralExchangeFlag 积分兑换标识
+ * @param whetherShelf 是否上架
+ * @param goodsPurpose 商品用途
+ * @return List
+ */
+ List selectGoodsByExchangeFlag(@Param("integralExchangeFlag") Integer integralExchangeFlag, @Param("whetherShelf") Integer whetherShelf, @Param("goodsPurpose") String goodsPurpose);
+
+ /**
+ * 查询优惠券表所有id(待领取优惠券)
+ *
+ * @return List
+ */
+ List selectCouponId();
+
+ /**
+ * 根据id查询用户签到信息
+ *
+ * @param patientId 用户id
+ * @param nowDate 当前日期
+ * @return 签到信息
+ */
+ PatientSignInVO getPatientSignInInfo(@Param("patientId") Long patientId, @Param("nowDate") LocalDate nowDate);
+
+ /**
+ * 更新用户签到天数
+ *
+ * @param patientId 会员id
+ * @return 数量
+ */
+ int updateTotalSignInDays(Long patientId);
+
+ /**
+ * 修改用户账户的积分
+ *
+ * @param patientId 会员id
+ * @param integral 积分值
+ * @return 数量
+ */
+ int updatePatientIntegral(@Param("patientId") Long patientId, @Param("integral") Integer integral);
+
+ /**
+ * 更新用户签到天数
+ *
+ * @param patientId 会员id
+ * @return 数量
+ */
+ int clearTotalSignInDays(Long patientId);
+
+ /**
+ * 获取积分返回规则
+ *
+ * @param patientId 用户id
+ * @param nowDate 今天日期
+ * @param ruleList 规则集合
+ * @return com.xinyilu.nurseapplet.domain.vo.patientcenter.PatientSignInfoVO
+ **/
+ List selectPatientSignIn(@Param("patientId") Long patientId,
+ @Param("nowDate") LocalDate nowDate,
+ @Param("ruleList") List ruleList);
+
+ /**
+ * 新人福利查询优惠券
+ *
+ * @param receiveType 新人福利标识1/
+ * @return java.util.List
+ **/
+ List getCouponNewPeople(String receiveType);
+
+ /**
+ * 根据优惠券状态查询优惠券信息
+ *
+ * @param patientCenterCouponDTO 用户信息及优惠券状态
+ * @return List
+ */
+ List getCouponByUseStatus(PatientCenterCouponDTO patientCenterCouponDTO);
+
+ /**
+ * 查询用户签到信息和积分信息
+ *
+ * @param patientId 会员id
+ * @param nowDate 当前时间
+ * @return 信息
+ */
+ PatientSignInfoVO getPatientSignInfo(@Param("patientId") Long patientId, @Param("nowDate") LocalDate nowDate);
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/messagepush/Impl/MessagePushServiceImpl.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/messagepush/Impl/MessagePushServiceImpl.java
new file mode 100644
index 0000000..2647526
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/messagepush/Impl/MessagePushServiceImpl.java
@@ -0,0 +1,221 @@
+package com.xinelu.applet.service.messagepush.Impl;
+
+import com.alibaba.fastjson2.JSON;
+import com.xinelu.applet.service.messagepush.MessagePushService;
+import com.xinelu.common.config.AppletChatConfig;
+import com.xinelu.common.config.AppletPageConfig;
+import com.xinelu.common.constant.Constants;
+import com.xinelu.common.entity.AppletAccessToken;
+import com.xinelu.common.entity.MessageValueEntity;
+import com.xinelu.common.enums.AppletSubscriptionMessageEnum;
+import com.xinelu.common.enums.CouponTypeEnum;
+import com.xinelu.common.enums.SettingsTypeEnum;
+import com.xinelu.common.enums.SubscribeStatusEnum;
+import com.xinelu.common.utils.AppletChatUtil;
+import com.xinelu.common.utils.http.HttpUtils;
+import com.xinelu.manage.domain.subscribemessagerecord.SubscribeMessageRecord;
+import com.xinelu.manage.domain.systemsettingsinfo.SystemSettingsInfo;
+import com.xinelu.manage.mapper.subscribemessagerecord.SubscribeMessageRecordMapper;
+import com.xinelu.manage.mapper.systemsettingsinfo.SystemSettingsInfoMapper;
+import com.xinelu.manage.vo.patientcouponreceive.PatientCouponReceiveInfoVO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * @Description 消息推送实现层
+ * @Author zh
+ * @Date 2023-03-17
+ */
+@Slf4j
+@Service
+public class MessagePushServiceImpl implements MessagePushService {
+
+ @Resource
+ private AppletChatConfig appletChatConfig;
+ @Resource
+ private SubscribeMessageRecordMapper subscribeMessageRecordMapper;
+ @Resource
+ private SystemSettingsInfoMapper systemSettingsInfoMapper;
+ @Resource
+ private AppletPageConfig appletPageConfig;
+
+ /**
+ * 微信消息推送url
+ */
+ private static final String MESSAGE_PUSH_URL = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=";
+
+ /**
+ * 签到消息推送
+ *
+ * @param patientId 用户ID
+ * @param days 天数
+ */
+ @Override
+ @Async("asyncThreadServiceExecutor")
+ public void integralMessage(Long patientId, Integer days) {
+ //获取AppletAccessToken的值
+ AppletAccessToken appletAccessToken = AppletChatUtil.getAppletAccessToken(appletChatConfig.getAppletId(), appletChatConfig.getSecret());
+ if (Objects.isNull(appletAccessToken)) {
+ log.error("获取微信小程序accessToken信息失败!");
+ return;
+ }
+ if (Objects.nonNull(appletAccessToken.getErrcode()) && appletAccessToken.getErrcode() != AppletSubscriptionMessageEnum.SUCCESS_ERRCODE.getValue()) {
+ log.error("获取微信小程序accessToken信息失败,失败信息为:" + appletAccessToken.getErrmsg(), 201);
+ return;
+ }
+ if (StringUtils.isBlank(appletAccessToken.getAccessToken())) {
+ log.error("accessToken信息为空!");
+ return;
+ }
+ //获取用户信息、订阅消息记录、规则信息
+ SubscribeMessageRecord subscribeMessageRecord = subscribeMessageRecordMapper.selectSubscribeMessageRecordByPatientId(patientId, null, appletChatConfig.getSignTemplateId());
+ if (Objects.isNull(subscribeMessageRecord) || StringUtils.isBlank(subscribeMessageRecord.getOpenid()) || StringUtils.isBlank(subscribeMessageRecord.getSubscribeStatus()) || !SubscribeStatusEnum.ACCEPT.getInfo().equals(subscribeMessageRecord.getSubscribeStatus())) {
+ return;
+ }
+ SystemSettingsInfo systemSettingsInfo = systemSettingsInfoMapper.getSystemSettingsInfoByType(SettingsTypeEnum.SIGN_IN_RULE.getInfo());
+ if (Objects.isNull(systemSettingsInfo) || Objects.isNull(systemSettingsInfo.getIntegralCount()) || Objects.isNull(systemSettingsInfo.getTotalSignInDays())) {
+ return;
+ }
+ this.sendIntegralMessage(appletAccessToken, systemSettingsInfo, subscribeMessageRecord, days);
+ }
+
+
+ /**
+ * 签到消息推送
+ *
+ * @param appletAccessToken 令牌
+ * @param systemSettingsInfo 规则信息
+ * @param subscribeMessageRecord 订阅消息记录
+ * @param days 天数
+ */
+ public void sendIntegralMessage(AppletAccessToken appletAccessToken, SystemSettingsInfo systemSettingsInfo, SubscribeMessageRecord subscribeMessageRecord, Integer days) {
+ //模板参数、用户openid、推送消息模板id
+ Map paramsMap = new LinkedHashMap<>();
+ paramsMap.put("touser", subscribeMessageRecord.getOpenid());
+ paramsMap.put("template_id", appletChatConfig.getSignTemplateId());
+ paramsMap.put("page", appletPageConfig.getIntegralPageUrl());
+ //模板内容
+ Map messageValueEntityMap = new LinkedHashMap<>();
+ messageValueEntityMap.put("thing1", new MessageValueEntity("每日签到"));
+ //如果签到天数满足规则
+ if (days.equals(systemSettingsInfo.getTotalSignInDays())) {
+ messageValueEntityMap.put("thing2", new MessageValueEntity("今日已签到,已领取" + systemSettingsInfo.getIntegralCount() + "积分"));
+ } else {
+ messageValueEntityMap.put("thing2", new MessageValueEntity(LocalDate.now().getYear() + "年" + LocalDate.now().getMonthValue() + "月" + LocalDate.now().getDayOfMonth() + "日签到成功"));
+ }
+ messageValueEntityMap.put("thing3", new MessageValueEntity("累计签到" + systemSettingsInfo.getTotalSignInDays() + "天,可获得" + systemSettingsInfo.getIntegralCount() + "积分"));
+ paramsMap.put("data", messageValueEntityMap);
+ //发送
+ this.sendPosts(appletAccessToken, paramsMap);
+ }
+
+ /**
+ * 完善信息优惠券领取与优惠券领取共用异步发送订阅信息
+ *
+ * @param subscribeMessageRecord 微信小程序订阅消息记录表
+ * @param couponReceive 用户优惠券
+ **/
+ @Override
+ @Async("asyncThreadServiceExecutor")
+ public void messageCouponReceiveThread(SubscribeMessageRecord subscribeMessageRecord, PatientCouponReceiveInfoVO couponReceive) {
+ if (StringUtils.equals(CouponTypeEnum.FULL_REDUCTION_COUPON.getInfo(), couponReceive.getCouponType())) {
+ couponReceive.setCouponType("满减券");
+ }
+ if (StringUtils.equals(CouponTypeEnum.CASH_COUPON.getInfo(), couponReceive.getCouponType())) {
+ couponReceive.setCouponType("代金券");
+ }
+ if (StringUtils.equals(CouponTypeEnum.EXCHANGE_COUPON.getInfo(), couponReceive.getCouponType())) {
+ couponReceive.setCouponType("兑换券");
+ }
+ if (StringUtils.equals(CouponTypeEnum.DISCOUNT_COUPON.getInfo(), couponReceive.getCouponType())) {
+ couponReceive.setCouponType("折扣卷");
+ }
+ //获取AppletAccessToken的值
+ AppletAccessToken appletAccessToken = AppletChatUtil.getAppletAccessToken(appletChatConfig.getAppletId(), appletChatConfig.getSecret());
+ if (Objects.isNull(appletAccessToken)) {
+ log.error("获取微信小程序accessToken信息失败!");
+ }
+ if (Objects.nonNull(appletAccessToken.getErrcode()) && appletAccessToken.getErrcode() != AppletSubscriptionMessageEnum.SUCCESS_ERRCODE.getValue()) {
+ log.error("获取微信小程序accessToken信息失败,失败信息为:" + appletAccessToken.getErrmsg(), 201);
+ }
+ if (StringUtils.isBlank(appletAccessToken.getAccessToken())) {
+ log.error("accessToken信息为空!");
+ }
+ //构建微信小程序消息推送参数
+ Map paramsMap = new LinkedHashMap<>();
+ paramsMap.put("template_id", StringUtils.isBlank(subscribeMessageRecord.getTemplateId()) ? "" : subscribeMessageRecord.getTemplateId());
+ paramsMap.put("page", appletPageConfig.getCouponPageUrl());
+ paramsMap.put("touser", StringUtils.isBlank(subscribeMessageRecord.getOpenid()) ? "" : subscribeMessageRecord.getOpenid());
+ paramsMap.put("lang", "zh_CN");
+ //构建微信小程序消息推送内容参数
+ Map amountParamMap = new HashMap<>();
+ //优惠券名称
+ amountParamMap.put("thing3", new MessageValueEntity(StringUtils.isBlank(couponReceive.getCouponTitle()) ? "" : couponReceive.getCouponTitle()));
+ //优惠券金额
+ BigDecimal couponPrice = Objects.isNull(couponReceive.getCouponPrice()) ? BigDecimal.ZERO : couponReceive.getCouponPrice();
+ amountParamMap.put("amount2", new MessageValueEntity(couponPrice + "元"));
+ //优惠券类型
+ amountParamMap.put("thing4", new MessageValueEntity(StringUtils.isBlank(couponReceive.getCouponType()) ? "" : couponReceive.getCouponType()));
+ //发布时间
+ amountParamMap.put("time6", new MessageValueEntity(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(couponReceive.getReceiveTime())));
+ //温馨提示
+ amountParamMap.put("thing1", new MessageValueEntity("优惠券来啦,您可进入小程序进行使用"));
+ paramsMap.put("data", amountParamMap);
+ //发送
+ this.sendPosts(appletAccessToken, paramsMap);
+ }
+
+ /**
+ * 发送
+ *
+ * @param appletAccessToken 令牌
+ * @param paramsMap 模板
+ **/
+ @Override
+ public void sendPosts(AppletAccessToken appletAccessToken, Map paramsMap) {
+ //拼接请求地址并发送
+ String messageUrl = MESSAGE_PUSH_URL + appletAccessToken.getAccessToken();
+ String param = JSON.toJSONString(paramsMap);
+ String result = HttpUtils.sendPostJson(messageUrl, param);
+ //返回参数映射
+ AppletAccessToken errCode = JSON.parseObject(result, AppletAccessToken.class);
+ if (Objects.nonNull(errCode) && Objects.nonNull(errCode.getErrcode())) {
+ switch (errCode.getErrcode()) {
+ case Constants.SUCCESS_ERRCODE:
+ log.info("发送消息成功!");
+ break;
+ case Constants.INVALID_CREDENTIAL_ACCESS_TOKEN_ISINVALID_OR_NOT_LATEST:
+ log.error("取 access_token 时 AppSecret 错误,或者 access_token 无效!");
+ break;
+ case Constants.INVALID_OPENID:
+ log.error("不合法的 OpenId!");
+ break;
+ case Constants.INVALID_ACCESS_TOKEN:
+ log.error("合法的 access_token!");
+ break;
+ case Constants.INVALID_TEMPLATE_ID:
+ log.error("不合法的 template_id!");
+ break;
+ case Constants.ARGUMENT_INVALID:
+ log.error("参数无效!");
+ break;
+ case Constants.DENY_SUBSCRIPTION:
+ log.error("用户拒接订阅!");
+ break;
+ default:
+ break;
+ }
+ }
+ }
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/messagepush/MessagePushService.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/messagepush/MessagePushService.java
new file mode 100644
index 0000000..92f823b
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/messagepush/MessagePushService.java
@@ -0,0 +1,41 @@
+package com.xinelu.applet.service.messagepush;
+
+
+import com.xinelu.common.entity.AppletAccessToken;
+import com.xinelu.manage.domain.subscribemessagerecord.SubscribeMessageRecord;
+import com.xinelu.manage.vo.patientcouponreceive.PatientCouponReceiveInfoVO;
+
+import java.util.Map;
+
+/**
+ * @Description 消息推送业务层
+ * @Author zh
+ * @Date 2023-03-17
+ */
+
+public interface MessagePushService {
+
+ /**
+ * 签到消息推送
+ *
+ * @param patientId 用户ID
+ * @param days 天数
+ */
+ void integralMessage(Long patientId, Integer days);
+
+ /**
+ * 完善信息优惠券领取与优惠券领取共用异步发送订阅信息
+ *
+ * @param subscribeMessageRecord 微信小程序订阅消息记录表
+ * @param couponReceive 用户优惠券
+ **/
+ void messageCouponReceiveThread(SubscribeMessageRecord subscribeMessageRecord, PatientCouponReceiveInfoVO couponReceive);
+
+ /**
+ * 发送
+ *
+ * @param appletAccessToken 令牌
+ * @param paramsMap 模板
+ **/
+ void sendPosts(AppletAccessToken appletAccessToken, Map paramsMap);
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/nursingstationgoods/INursingStationGoodsService.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/nursingstationgoods/INursingStationGoodsService.java
new file mode 100644
index 0000000..4ea3f35
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/nursingstationgoods/INursingStationGoodsService.java
@@ -0,0 +1,137 @@
+package com.xinelu.applet.service.nursingstationgoods;
+
+import com.xinelu.applet.dto.nursingstationgoods.GoodDetails;
+import com.xinelu.applet.dto.nursingstationgoods.GoodsList;
+import com.xinelu.applet.dto.nursingstationgoods.GoodsOrderPatient;
+import com.xinelu.applet.dto.nursingstationgoods.GoodsOrderStationDTO;
+import com.xinelu.applet.vo.nursingstationgoods.UpdateDefaultAddressVO;
+import com.xinelu.common.core.domain.AjaxResult;
+import com.xinelu.common.core.page.TableDataInfo;
+import com.xinelu.manage.domain.goodsCategory.GoodsCategory;
+import com.xinelu.manage.domain.receiveAddressInfo.ReceiveAddressInfo;
+import com.xinelu.manage.vo.sysarea.SysAreaVO;
+
+import java.util.List;
+
+/**
+ * 商品信息
+ *
+ * @author zhangheng
+ * @date 2022-09-06
+ */
+public interface INursingStationGoodsService {
+
+ /**
+ * 查询商品分类信息列表
+ *
+ * @param goodsCategory 商品分类信息
+ * @return 商品分类信息集合
+ */
+ List getGoodsCategoryList(GoodsCategory goodsCategory);
+
+ /**
+ * 查询商品二级分类信息列表
+ *
+ * @param goodsCategoryId 商品分类信息
+ * @return 商品分类信息集合
+ */
+ AjaxResult getGoodsCategoryNameList(Long goodsCategoryId);
+
+ /**
+ * 根据商品分类id查询商品信息
+ *
+ * @param goodsList 商品信息
+ * @return 商品基本信息集合
+ */
+ TableDataInfo getGoodsInfoList(GoodsList goodsList);
+
+ /**
+ * 根据商品id查询商品详细信息
+ *
+ * @param goodsInfoId 商品详细id
+ * @param patientId 用户信息id
+ * @return com.xinyilu.nurseapplet.domain.nursingStationGoods.GoodDetails
+ **/
+ GoodDetails getGoodsDetails(Long goodsInfoId, Long patientId);
+
+ /**
+ * 根据被护理人id查询基本信息
+ *
+ * @param patientId 被护理人id
+ * @return com.xinyilu.base.domain.patientinfo.PatientInfo
+ **/
+ AjaxResult getReceiveAddressInfoList(Long patientId);
+
+ /**
+ * 查询收货人地址信息
+ *
+ * @param id 收货人地址信息主键
+ * @return 收货人地址信息
+ */
+ ReceiveAddressInfo selectReceiveAddressInfoById(Long id);
+
+ /**
+ * 新增收货人地址信息
+ *
+ * @param receiveAddressInfo 收货人地址信息
+ * @return 结果
+ */
+ int insertReceiveAddressInfo(ReceiveAddressInfo receiveAddressInfo);
+
+
+ /**
+ * 修改收货人地址信息
+ *
+ * @param receiveAddressInfo 收货人地址信息
+ * @return 结果
+ */
+ int updateReceiveAddressInfo(ReceiveAddressInfo receiveAddressInfo);
+
+ /**
+ * 批量删除收货人地址信息
+ *
+ * @param ids 需要删除的收货人地址信息主键集合
+ * @return 结果
+ */
+ int deleteReceiveAddressInfoByIds(Long[] ids);
+
+ /**
+ * 下级区域寻找上级区域
+ *
+ * @param areaCode 区域编码
+ * @return com.xinyilu.base.domain.vo.sysarea.SysAreaVO
+ **/
+ SysAreaVO getSubordinateRegionsFindSuperiorRegions(String areaCode);
+
+ /**
+ * 新增商品订单以及详细信息
+ *
+ * @param goodsOrder 商品订单
+ * @return 结果
+ */
+ AjaxResult insertNurseStationGoodsOrder(GoodsOrderStationDTO goodsOrder);
+
+ /**
+ * 根据订单编号查询订单信息
+ *
+ * @param orderNo 订单信息编号
+ * @return com.xinyilu.nurseapplet.domain.nursingStationGoods.GoodsOrderPatient
+ **/
+ GoodsOrderPatient selectGoodsOrderPatient(String orderNo);
+
+ /**
+ * App和小程序确认收货
+ *
+ * @param orderNo 订单编号
+ * @return 结果
+ */
+ AjaxResult confirmReceipt(String orderNo);
+
+ /**
+ * 微信小程序和会员App设置默认地址接口
+ *
+ * @param defaultAddressList 默认地址标识集合
+ * @return 结果
+ */
+ AjaxResult updateDefaultAddress(List defaultAddressList);
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/nursingstationgoods/impl/NursingStationGoodsServiceImpl.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/nursingstationgoods/impl/NursingStationGoodsServiceImpl.java
new file mode 100644
index 0000000..6587cc2
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/nursingstationgoods/impl/NursingStationGoodsServiceImpl.java
@@ -0,0 +1,562 @@
+package com.xinelu.applet.service.nursingstationgoods.impl;
+
+import com.xinelu.applet.dto.nursingstationgoods.*;
+import com.xinelu.applet.mapper.nursingstationgoods.NursingStationGoodsMapper;
+import com.xinelu.applet.service.nursingstationgoods.INursingStationGoodsService;
+import com.xinelu.applet.vo.coupon.CouponVO;
+import com.xinelu.applet.vo.nursingstationgoods.UpdateDefaultAddressVO;
+import com.xinelu.common.constant.Constants;
+import com.xinelu.common.core.domain.AjaxResult;
+import com.xinelu.common.core.page.TableDataInfo;
+import com.xinelu.common.enums.CouponUseStatusEnum;
+import com.xinelu.common.enums.GooodsOrderStatusEnum;
+import com.xinelu.common.enums.OrderTypeEnum;
+import com.xinelu.common.exception.ServiceException;
+import com.xinelu.common.utils.PageServiceUtil;
+import com.xinelu.common.utils.RedisDistributedLockUtils;
+import com.xinelu.common.utils.bean.BeanUtils;
+import com.xinelu.common.utils.regex.RegexUtil;
+import com.xinelu.manage.domain.goodsAttributeDetails.GoodsAttributeDetails;
+import com.xinelu.manage.domain.goodsCategory.GoodsCategory;
+import com.xinelu.manage.domain.goodsOrder.GoodsOrder;
+import com.xinelu.manage.domain.goodsOrderDetails.GoodsOrderDetails;
+import com.xinelu.manage.domain.receiveAddressInfo.ReceiveAddressInfo;
+import com.xinelu.manage.domain.sysarea.SysArea;
+import com.xinelu.manage.mapper.goodsAttributeDetails.GoodsAttributeDetailsMapper;
+import com.xinelu.manage.mapper.goodsOrder.GoodsOrderMapper;
+import com.xinelu.manage.mapper.goodsOrderDetails.GoodsOrderDetailsMapper;
+import com.xinelu.manage.mapper.patientcouponreceive.PatientCouponReceiveMapper;
+import com.xinelu.manage.mapper.patientinfo.PatientInfoMapper;
+import com.xinelu.manage.mapper.receiveAddressInfo.ReceiveAddressInfoMapper;
+import com.xinelu.manage.mapper.sysarea.SysAreaMapper;
+import com.xinelu.manage.vo.goodsCategory.GoodsCategoryNameVO;
+import com.xinelu.manage.vo.patientcouponreceive.PatientCouponReceiveVO;
+import com.xinelu.manage.vo.patientinfo.PatientInfoVO;
+import com.xinelu.manage.vo.receiveAddressInfo.ReceiveAddressInfoVO;
+import com.xinelu.manage.vo.sysarea.SysAreaVO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.compress.utils.Lists;
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+/**
+ * @author ljh
+ * @version 1.0
+ * Create by 2022/10/17 13:38
+ */
+@Slf4j
+@Service
+public class NursingStationGoodsServiceImpl implements INursingStationGoodsService {
+ @Resource
+ private NursingStationGoodsMapper nursingStationGoodsMapper;
+ @Resource
+ private RegexUtil regexUtil;
+ @Resource
+ private SysAreaMapper sysAreaMapper;
+ @Resource
+ private GoodsOrderMapper goodsOrderMapper;
+ @Resource
+ private RedisDistributedLockUtils redisDistributedLockUtils;
+ @Resource
+ private GoodsAttributeDetailsMapper goodsAttributeDetailsMapper;
+ @Resource
+ private PatientInfoMapper patientInfoMapper;
+ @Resource
+ private ReceiveAddressInfoMapper receiveAddressInfoMapper;
+ @Resource
+ private PageServiceUtil pageServiceUtil;
+ @Resource
+ private PatientCouponReceiveMapper patientCouponReceiveMapper;
+ @Resource
+ private GoodsOrderDetailsMapper goodsOrderDetailsMapper;
+
+ /**
+ * 所在省的级别
+ */
+ private static final int PROVINCE_AREA_LEVEL = 1;
+
+ /**
+ * 所在市的级别
+ */
+ private static final int CITY_AREA_LEVEL = 2;
+
+ /**
+ * 查询商城分类
+ *
+ * @param goodsCategory 商品分类信息表
+ * @return java.util.List
+ **/
+ @Override
+ public List getGoodsCategoryList(GoodsCategory goodsCategory) {
+ return nursingStationGoodsMapper.getGoodsCategoryList(goodsCategory);
+ }
+
+ /**
+ * 查询商品二级分类信息列表
+ *
+ * @param goodsCategoryId 商品分类信息
+ * @return 商品分类信息集合
+ */
+ @Override
+ public AjaxResult getGoodsCategoryNameList(Long goodsCategoryId) {
+ //查询当前分类下属所有分类id集合
+ List childCategoryIds = this.getChildCategoryIds(goodsCategoryId);
+ GoodsCategoryNameVO goodsCategoryNameVO = new GoodsCategoryNameVO();
+ goodsCategoryNameVO.setGoodsCategoryNameId(childCategoryIds);
+ goodsCategoryNameVO.setCategoryLevel(1);
+ return AjaxResult.success(nursingStationGoodsMapper.getGoodsCategoryNameList(goodsCategoryNameVO));
+ }
+
+ /**
+ * 根据商品分类id查询商品信息
+ *
+ * @param goodsList 商品信息
+ * @return java.util.List
+ **/
+ @Override
+ public TableDataInfo getGoodsInfoList(GoodsList goodsList) {
+ if (Objects.nonNull(goodsList) && Objects.isNull(goodsList.getGoodsCategoryId())) {
+ throw new ServiceException("所选商品分类不能为空!");
+ }
+ //查询当前分类下属所有分类id集合
+ List childCategoryIds = this.getChildCategoryIds(goodsList.getGoodsCategoryId());
+ goodsList.setGoodsCategoryIds(childCategoryIds);
+ pageServiceUtil.startPage();
+ List goodsInfoList = nursingStationGoodsMapper.getGoodsInfoList(goodsList);
+ return pageServiceUtil.getDataTable(goodsInfoList);
+ }
+
+ /**
+ * 根据商品id查询商品详细信息
+ *
+ * @param goodsInfoId 商品详细id
+ * @param patientId 用户信息
+ * @return com.xinyilu.nurseapplet.domain.nursingStationGoods.GoodDetails
+ **/
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public GoodDetails getGoodsDetails(Long goodsInfoId, Long patientId) {
+ GoodDetails goodsDetailsList = nursingStationGoodsMapper.getGoodsDetailsList(goodsInfoId);
+ //获取集合属性中的最小值
+ BigDecimal goodAttributeDetailsMin = goodsDetailsList.getGoodAttributeDetailsLists()
+ .stream()
+ .filter(Objects::nonNull)
+ .filter(good -> Objects.nonNull(good.getGoodsPrice()))
+ .map(GoodAttributeDetailsList::getGoodsPrice).min(BigDecimal::compareTo).orElse(BigDecimal.ZERO);
+ goodsDetailsList.setMinGoodsPrice(goodAttributeDetailsMin);
+ //查询用户未使用的优惠券信息
+ if (Objects.nonNull(patientId)) {
+ //数据库中查出的用户未使用的优惠券信息
+ List couponVOList = nursingStationGoodsMapper.selectCouponListByPatient(patientId, CouponUseStatusEnum.NOT_USED.getInfo());
+ //用流筛选出用户未使用以及未过期的 优惠券信息
+ List couponVO = couponVOList.stream()
+ .filter(cou -> (Objects.nonNull(cou.getExpirationEndTime()))).filter(coupon -> (coupon.getExpirationEndTime().isAfter(LocalDateTime.now()))).collect(Collectors.toList());
+ //未过期的优惠券塞入返回值中 返回
+ goodsDetailsList.setCouponList(couponVO);
+ //做差集取出用户未使用以及 过期的 优惠券信息
+ List couponSubtractList = new ArrayList<>(CollectionUtils.subtract(couponVOList, couponVO));
+ if (CollectionUtils.isNotEmpty(couponSubtractList)) {
+ //取出会员用户优惠券领取记录表id集合
+ List couponIdList = couponSubtractList.stream()
+ .filter(coupon -> (Objects.nonNull(coupon.getPatientCouponReceiveId())))
+ .map(CouponVO::getPatientCouponReceiveId).collect(Collectors.toList());
+ if (CollectionUtils.isNotEmpty(couponIdList)) {
+ int receiveStatusList = patientCouponReceiveMapper.updateCouponReceiveStatusList(CouponUseStatusEnum.EXPIRED.getInfo(), couponIdList);
+ if (receiveStatusList < 0) {
+ throw new ServiceException("优惠券查询失败,请联系管理员!");
+ }
+ }
+ }
+ }
+ return goodsDetailsList;
+ }
+
+ /**
+ * 根据被护理人id查询基本信息
+ *
+ * @param patientId 被护理人id
+ * @return java.util.List
+ **/
+ @Override
+ public AjaxResult getReceiveAddressInfoList(Long patientId) {
+ //根据id查询所有的地址
+ List receiveAddressInfoList = nursingStationGoodsMapper.getReceiveAddressInfoList(patientId);
+ //取出list集合中所有的AreaCode
+ List areaCodeList = receiveAddressInfoList.stream().filter(item -> StringUtils.isNotBlank(item.getAreaCode())).map(ReceiveAddressInfoVO::getAreaCode).distinct().collect(Collectors.toList());
+ if (CollectionUtils.isEmpty(areaCodeList)) {
+ return AjaxResult.success(receiveAddressInfoList);
+ }
+ //查询所在的街道的区域信息
+ Map sysStreetAreaMap = sysAreaMapper.getNurseStationAreaByList(areaCodeList).stream().filter(item -> StringUtils.isNotBlank(item.getStreetCode())).collect(Collectors.toMap(SysAreaVO::getStreetCode, item -> item));
+ //所在区的编码集合
+ List regionCodeList = new ArrayList<>();
+ for (ReceiveAddressInfoVO receiveAddressInfoVO : receiveAddressInfoList) {
+ SysAreaVO sysAreaVO = sysStreetAreaMap.getOrDefault(receiveAddressInfoVO.getAreaCode(), new SysAreaVO());
+ if (Objects.isNull(sysAreaVO.getStreetCode())) {
+ regionCodeList.add(receiveAddressInfoVO.getAreaCode());
+ continue;
+ }
+ //拼接省市区街道地址信息
+ String provinceName = StringUtils.isBlank(sysAreaVO.getProvinceName()) ? "" : sysAreaVO.getProvinceName();
+ String cityName = StringUtils.isBlank(sysAreaVO.getCityName()) ? "" : sysAreaVO.getCityName();
+ String regionName = StringUtils.isBlank(sysAreaVO.getRegionName()) ? "" : sysAreaVO.getRegionName();
+ String streetName = StringUtils.isBlank(sysAreaVO.getStreetName()) ? "" : sysAreaVO.getStreetName();
+ receiveAddressInfoVO.setAreaName(provinceName + cityName + regionName + streetName);
+ }
+ if (CollectionUtils.isNotEmpty(regionCodeList)) {
+ //查询所有区的各级信息
+ Map sysRegionAreaMap = sysAreaMapper.getNurseStationGoodsAreaByList(regionCodeList).stream().filter(item -> StringUtils.isNotBlank(item.getRegionCode())).collect(Collectors.toMap(SysAreaVO::getRegionCode, item -> item));
+ for (ReceiveAddressInfoVO receiveAddressInfoVO : receiveAddressInfoList) {
+ SysAreaVO sysAreaVO = sysRegionAreaMap.getOrDefault(receiveAddressInfoVO.getAreaCode(), null);
+ if (Objects.nonNull(sysAreaVO)) {
+ String provinceName = StringUtils.isBlank(sysAreaVO.getProvinceName()) ? "" : sysAreaVO.getProvinceName();
+ String cityName = StringUtils.isBlank(sysAreaVO.getCityName()) ? "" : sysAreaVO.getCityName();
+ String regionName = StringUtils.isBlank(sysAreaVO.getRegionName()) ? "" : sysAreaVO.getRegionName();
+ receiveAddressInfoVO.setAreaName(provinceName + cityName + regionName);
+ }
+ }
+ }
+ return AjaxResult.success(receiveAddressInfoList);
+ }
+
+
+ /**
+ * 查询收货人地址信息
+ *
+ * @param id 收货人地址信息主键
+ * @return 收货人地址信息
+ */
+ @Override
+ public ReceiveAddressInfo selectReceiveAddressInfoById(Long id) {
+ return nursingStationGoodsMapper.selectReceiveAddressInfoById(id);
+ }
+
+ /**
+ * 新增收货人地址信息
+ *
+ * @param receiveAddressInfo 收货人地址信息
+ * @return 结果
+ */
+ @Override
+ public int insertReceiveAddressInfo(ReceiveAddressInfo receiveAddressInfo) {
+ //设置创建人以及创建时间
+ receiveAddressInfo.setCreateTime(LocalDateTime.now());
+ receiveAddressInfo.setPatientId(receiveAddressInfo.getPatientId());
+ if (StringUtils.isNotBlank(receiveAddressInfo.getReceivePhone())) {
+ // 校验手机号是否正确
+ boolean phone = regexUtil.regexPhone(receiveAddressInfo.getReceivePhone());
+ if (BooleanUtils.isFalse(phone)) {
+ throw new ServiceException("您输入的联系电话" + receiveAddressInfo.getReceivePhone() + "不正确,请重新输入!");
+ }
+ }
+ //根据区域areaCode查询区域级别
+ SysArea sysArea = sysAreaMapper.selectSysAreaById(null, receiveAddressInfo.getAreaCode());
+ List areaLevelList = Arrays.asList(PROVINCE_AREA_LEVEL, CITY_AREA_LEVEL);
+ if (Objects.isNull(sysArea) || areaLevelList.contains(sysArea.getAreaLevel())) {
+ throw new ServiceException("所在地区必须选择到所在区或者街道,请重新选择!");
+ }
+ return nursingStationGoodsMapper.insertReceiveAddressInfo(receiveAddressInfo);
+ }
+
+
+ /**
+ * 修改收货人地址信息
+ *
+ * @param receiveAddressInfo 收货人地址信息
+ * @return 结果
+ */
+ @Override
+ public int updateReceiveAddressInfo(ReceiveAddressInfo receiveAddressInfo) {
+ //设置修改人以及修改时间
+ receiveAddressInfo.setUpdateTime(LocalDateTime.now());
+ if (StringUtils.isNotBlank(receiveAddressInfo.getReceivePhone())) {
+ // 校验手机号是否正确
+ boolean phone = regexUtil.regexPhone(receiveAddressInfo.getReceivePhone());
+ if (BooleanUtils.isFalse(phone)) {
+ throw new ServiceException("您输入的联系电话" + receiveAddressInfo.getReceivePhone() + "不正确,请重新输入!");
+ }
+ }
+ //根据区域areaCode查询区域级别
+ SysArea sysArea = sysAreaMapper.selectSysAreaById(null, receiveAddressInfo.getAreaCode());
+ List areaLevelList = Arrays.asList(PROVINCE_AREA_LEVEL, CITY_AREA_LEVEL);
+ if (Objects.isNull(sysArea) || areaLevelList.contains(sysArea.getAreaLevel())) {
+ throw new ServiceException("所在地区必须选择到所在区或者街道,请重新选择!");
+ }
+ return nursingStationGoodsMapper.updateReceiveAddressInfo(receiveAddressInfo);
+ }
+
+ /**
+ * 批量删除收货人地址信息
+ *
+ * @param ids 需要删除的收货人地址信息主键
+ * @return 结果
+ */
+ @Override
+ public int deleteReceiveAddressInfoByIds(Long[] ids) {
+ return nursingStationGoodsMapper.deleteReceiveAddressInfoByIds(ids);
+ }
+
+
+ /**
+ * 下级区域寻找上级区域
+ *
+ * @param areaCode 区域编码
+ * @return com.xinyilu.base.domain.vo.sysarea.SysAreaVO
+ **/
+ @Override
+ public SysAreaVO getSubordinateRegionsFindSuperiorRegions(String areaCode) {
+ return nursingStationGoodsMapper.getSubordinateRegionsFindSuperiorRegions(areaCode);
+ }
+
+ /**
+ * 新增商品订单以及详细信息
+ *
+ * @param goodsOrder 商品订单
+ * @return 结果
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public AjaxResult insertNurseStationGoodsOrder(GoodsOrderStationDTO goodsOrder) {
+ //校验优惠券等相关信息
+ AjaxResult ajaxResult = checkAddGoodOrderParam(goodsOrder);
+ if (Objects.nonNull(ajaxResult)) {
+ return ajaxResult;
+ }
+ //判断库存是否充足
+ GoodsAttributeDetails goodsAttributeDetails = nursingStationGoodsMapper.selectGoodsAttributeDetailsGoodsStockById(goodsOrder.getGoodsAttributeDetailsId());
+ if (Objects.isNull(goodsAttributeDetails.getGoodsStock()) || goodsAttributeDetails.getGoodsStock() == 0) {
+ return AjaxResult.error("当前商品库存不足,无法购买!");
+ }
+ //库存数量
+ AtomicInteger goodsStock = new AtomicInteger(goodsAttributeDetails.getGoodsStock());
+ AtomicInteger goodsCount = new AtomicInteger(goodsOrder.getGoodsCount());
+ if (goodsStock.get() < goodsCount.get()) {
+ return AjaxResult.error("当前商品库存不足,无法购买!");
+ }
+ //生成订单信息
+ String goodOrderNo = com.xinelu.common.utils.StringUtils.fillZeroByPatientId(goodsOrder.getPatientId(), 5) + System.nanoTime();
+ this.insertGoodsOrder(goodsOrder, goodsCount, goodOrderNo);
+ return AjaxResult.success(goodsOrderMapper.getGoodsOrderByOrderNo(goodOrderNo));
+ }
+
+ /**
+ * 根据订单编号查询订单信息
+ *
+ * @param orderNo 订单信息编号
+ * @return com.xinyilu.nurseapplet.domain.nursingStationGoods.GoodsOrderPatient
+ **/
+ @Override
+ public GoodsOrderPatient selectGoodsOrderPatient(String orderNo) {
+ return nursingStationGoodsMapper.selectGoodsOrderPatient(orderNo);
+ }
+
+ /**
+ * App和小程序确认收货
+ *
+ * @param orderNo 订单编号
+ * @return 结果信息
+ */
+ @Override
+ public AjaxResult confirmReceipt(String orderNo) {
+ GoodsOrder goodsOrderByOrderNo = goodsOrderMapper.getGoodsOrderByOrderNo(orderNo);
+ if (Objects.isNull(goodsOrderByOrderNo)) {
+ return AjaxResult.error("当前订单信息不存在,请重新选择!");
+ }
+ if (!GooodsOrderStatusEnum.WAIT_RECEIVED_GOODS.getInfo().equals(goodsOrderByOrderNo.getOrderStatus())) {
+ return AjaxResult.error("当前订单非待收货状态,无法确认收货!");
+ }
+ goodsOrderMapper.updateGoodsOrderStatus(GooodsOrderStatusEnum.RECEIVED_GOODS.getInfo(), orderNo);
+ return AjaxResult.success();
+ }
+
+ /**
+ * 微信小程序和会员App设置默认地址接口
+ *
+ * @param defaultAddressList 默认地址标识集合
+ * @return 结果
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public AjaxResult updateDefaultAddress(List defaultAddressList) {
+ for (UpdateDefaultAddressVO updateDefaultAddressVO : defaultAddressList) {
+ ReceiveAddressInfo receiveAddressInfo = new ReceiveAddressInfo();
+ receiveAddressInfo.setId(updateDefaultAddressVO.getId());
+ receiveAddressInfo.setUpdateTime(LocalDateTime.now());
+ receiveAddressInfo.setDefaultAddressFlag(updateDefaultAddressVO.getDefaultAddressFlag());
+ int updateReceiveCount = receiveAddressInfoMapper.updateReceiveAddressInfo(receiveAddressInfo);
+ if (updateReceiveCount <= 0) {
+ throw new ServiceException("设置默认收货地址失败,请联系管理员!");
+ }
+ }
+ return AjaxResult.success();
+ }
+
+ /**
+ * 根据当前分类id查询其下属所有子分类id集合
+ *
+ * @param categoryId 当前分类id
+ * @return 子分类id集合
+ */
+ private List getChildCategoryIds(Long categoryId) {
+ //查询当前分类下属所有分类id集合
+ String childrenCategoryIds = nursingStationGoodsMapper.getChildrenCategoryIds(categoryId);
+ //分割 ,去除第一个“ ” 获取数据 转换类型
+ String[] split;
+ List goodsCategoryIds = Lists.newArrayList();
+ if (childrenCategoryIds.length() > 0) {
+ split = StringUtils.split(childrenCategoryIds.substring(1), ",");
+ goodsCategoryIds = Arrays.stream(split).map(Integer::valueOf).collect(Collectors.toList());
+ }
+ return goodsCategoryIds;
+ }
+
+ /**
+ * 商品订单接口相关参数校验
+ *
+ * @param goodsOrder 商品订单信息
+ * @return 校验结果
+ */
+ private AjaxResult checkAddGoodOrderParam(GoodsOrderStationDTO goodsOrder) {
+ //判断当前会员信息是否存在
+ PatientInfoVO patientInfo = patientInfoMapper.getPatientInfoById(goodsOrder.getPatientId());
+ if (Objects.isNull(patientInfo)) {
+ return AjaxResult.error("用户信息不存在,无法购买商品!");
+ }
+ if (Objects.nonNull(goodsOrder.getCouponId())) {
+ //当前商品订单使用了优惠券
+ PatientCouponReceiveVO patientCouponInfo = patientCouponReceiveMapper.getPatientCouponInfo(goodsOrder.getPatientId(), goodsOrder.getCouponId());
+ if (Objects.isNull(patientCouponInfo)) {
+ return AjaxResult.error("优惠券信息不存在,无法购买商品!");
+ }
+ //优惠券金额是否被篡改过
+ if (Objects.nonNull(goodsOrder.getDiscountPrice()) && Objects.nonNull(patientCouponInfo.getCouponPrice()) && goodsOrder.getDiscountPrice().compareTo(patientCouponInfo.getCouponPrice()) != 0) {
+ return AjaxResult.error("优惠券金额已被篡改过,无法使用'" + patientCouponInfo.getCouponTitle() + "'优惠券购买商品!");
+ }
+ //优惠券门槛是否被篡改过
+ if (Objects.nonNull(goodsOrder.getCouponConsumePrice()) && Objects.nonNull(patientCouponInfo.getCouponConsumePrice()) && goodsOrder.getCouponConsumePrice().compareTo(patientCouponInfo.getCouponConsumePrice()) != 0) {
+ return AjaxResult.error("优惠券使用门槛已被篡改过,无法使用'" + patientCouponInfo.getCouponTitle() + "'优惠券购买商品!");
+ }
+ //判断当前优惠券是否过期
+ if (StringUtils.isNotBlank(patientCouponInfo.getUseStatus()) && CouponUseStatusEnum.USED.getInfo().equals(patientCouponInfo.getUseStatus())) {
+ return AjaxResult.error("优惠券:'" + patientCouponInfo.getCouponTitle() + "'已使用,无法使用!");
+ }
+ boolean isUsedStatus = StringUtils.isNotBlank(patientCouponInfo.getUseStatus()) && CouponUseStatusEnum.EXPIRED.getInfo().equals(patientCouponInfo.getUseStatus());
+ boolean expireTime = Objects.nonNull(patientCouponInfo.getExpirationEndTime()) && LocalDateTime.now().isAfter(patientCouponInfo.getExpirationEndTime());
+ if (BooleanUtils.isTrue(isUsedStatus) || BooleanUtils.isTrue(expireTime)) {
+ return AjaxResult.error("优惠券:'" + patientCouponInfo.getCouponTitle() + "'已过期,无法使用!");
+ }
+ //判断商品总金额是否大于使用优惠券使用门槛
+ if (Objects.nonNull(goodsOrder.getGoodsCount()) && Objects.nonNull(goodsOrder.getGoodsPrice()) && Objects.nonNull(patientCouponInfo.getCouponConsumePrice())) {
+ BigDecimal originalPrice = BigDecimal.valueOf(goodsOrder.getGoodsCount()).multiply(goodsOrder.getGoodsPrice()).setScale(2, BigDecimal.ROUND_DOWN);
+ if (Objects.nonNull(goodsOrder.getOriginalTotalPrice()) && originalPrice.compareTo(goodsOrder.getOriginalTotalPrice()) != 0) {
+ return AjaxResult.error("订单金额被篡改过,原始金额为:" + originalPrice + ", 篡改后金额为:" + goodsOrder.getOriginalTotalPrice() + ",无法购买!");
+ }
+ if (BooleanUtils.isFalse(originalPrice.compareTo(patientCouponInfo.getCouponConsumePrice()) >= 0)) {
+ return AjaxResult.error("订单金额未达到优惠券使用门槛,'" + patientCouponInfo.getCouponTitle() + "'优惠券无法使用!");
+ }
+ }
+ //判断,商品数量 * 商品单价 - 优惠券金额 = 应付总价格
+ if (Objects.nonNull(goodsOrder.getGoodsCount()) && Objects.nonNull(goodsOrder.getGoodsPrice()) && Objects.nonNull(goodsOrder.getDiscountPrice())) {
+ BigDecimal originalPrice = BigDecimal.valueOf(goodsOrder.getGoodsCount()).multiply(goodsOrder.getGoodsPrice()).setScale(2, BigDecimal.ROUND_DOWN);
+ if (Objects.nonNull(goodsOrder.getOriginalTotalPrice()) && originalPrice.compareTo(goodsOrder.getOriginalTotalPrice()) != 0) {
+ return AjaxResult.error("订单金额被篡改过,原始金额为:" + originalPrice + ", 篡改后金额为:" + goodsOrder.getOriginalTotalPrice() + ",无法购买!");
+ }
+ BigDecimal totalPrice = originalPrice.subtract(goodsOrder.getDiscountPrice()).setScale(2, BigDecimal.ROUND_DOWN);
+ if (totalPrice.compareTo(goodsOrder.getTotalPrice()) != 0) {
+ return AjaxResult.error("订单金额不正确,应付金额为:" + totalPrice + "元,支付金额为:" + goodsOrder.getTotalPrice() + ",无法购买!");
+ }
+ }
+ } else {
+ //未使用优惠券,计算:商品数量 * 商品单价 = 应付总价格
+ if (Objects.nonNull(goodsOrder.getGoodsCount()) && Objects.nonNull(goodsOrder.getGoodsPrice()) && Objects.nonNull(goodsOrder.getTotalPrice())) {
+ BigDecimal originalPrice = BigDecimal.valueOf(goodsOrder.getGoodsCount()).multiply(goodsOrder.getGoodsPrice()).setScale(2, BigDecimal.ROUND_DOWN);
+ if (Objects.nonNull(goodsOrder.getOriginalTotalPrice()) && originalPrice.compareTo(goodsOrder.getOriginalTotalPrice()) != 0) {
+ return AjaxResult.error("订单金额不正确,应付金额为:" + originalPrice + "元,支付金额为:" + goodsOrder.getOriginalTotalPrice() + ",无法购买!");
+ }
+ if (originalPrice.compareTo(goodsOrder.getTotalPrice()) != 0) {
+ return AjaxResult.error("订单金额不正确,应付金额为:" + originalPrice + "元,支付金额为:" + goodsOrder.getTotalPrice() + ",无法购买!");
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 商品订单接口-生成订单表和订单明细表信息
+ *
+ * @param goodsOrder 输入参数
+ * @param goodsCount 库存原子数量
+ * @param goodOrderNo 订单编号
+ */
+ private void insertGoodsOrder(GoodsOrderStationDTO goodsOrder, AtomicInteger goodsCount, String goodOrderNo) {
+ //新增商品订单主表信息
+ GoodsOrder good = new GoodsOrder();
+ BeanUtils.copyBeanProp(good, goodsOrder);
+ good.setPatientId(goodsOrder.getPatientId());
+ good.setOrderNo(goodOrderNo);
+ good.setOrderStatus(GooodsOrderStatusEnum.WAIT_PAY.getInfo());
+ good.setRemark(StringUtils.isBlank(goodsOrder.getRemark()) ? "" : goodsOrder.getRemark());
+ good.setOrderTime(LocalDateTime.now());
+ good.setDelFlag(0);
+ good.setOrderType(OrderTypeEnum.DIRECT_BUY.getInfo());
+ good.setCreateTime(LocalDateTime.now());
+ good.setOriginalTotalPrice(goodsOrder.getOriginalTotalPrice());
+ int stationGoodsOrder = goodsOrderMapper.insertGoodsOrder(good);
+ if (stationGoodsOrder <= 0) {
+ throw new ServiceException("商品订单新增信息失败,请联系管理员!");
+ }
+ //新增商品订单明细表信息
+ GoodsOrderDetails goodsOrderDetails = new GoodsOrderDetails();
+ BeanUtils.copyBeanProp(goodsOrderDetails, goodsOrder);
+ goodsOrderDetails.setGoodsOrderId(good.getId());
+ goodsOrderDetails.setOrderNo(goodOrderNo);
+ goodsOrderDetails.setDelFlag(0);
+ goodsOrderDetails.setCreateTime(LocalDateTime.now());
+ if (Objects.nonNull(goodsOrder.getCouponId())) {
+ goodsOrderDetails.setCouponId(goodsOrder.getCouponId());
+ }
+ if (StringUtils.isNotBlank(goodsOrder.getCouponTitle())) {
+ goodsOrderDetails.setCouponTitle(goodsOrderDetails.getCouponTitle());
+ }
+ if (Objects.nonNull(goodsOrderDetails.getDiscountPrice())) {
+ goodsOrderDetails.setDiscountPrice(goodsOrderDetails.getDiscountPrice());
+ }
+ int orderDetails = goodsOrderDetailsMapper.insertGoodsOrderDetails(goodsOrderDetails);
+ if (orderDetails <= 0) {
+ throw new ServiceException("商品订单明细新增信息失败,请联系管理员!");
+ }
+ //修改优惠券的状态
+ if (Objects.nonNull(goodsOrder.getCouponId())) {
+ patientCouponReceiveMapper.updatePatientCouponUseStatus(goodsOrder.getPatientId(), goodsOrder.getCouponId(), CouponUseStatusEnum.USED.getInfo());
+ }
+ //减少库存数量
+ String goodsStockKey = Constants.BUY_GOODS_REDUCE_STOCK_KEY + goodOrderNo + "_" + goodsOrderDetails.getId();
+ boolean tryLock = redisDistributedLockUtils.tryLock(goodsStockKey, 5);
+ if (!tryLock) {
+ log.info("商品订单获取Redis锁失败,订单编号 =====> {}", goodOrderNo);
+ throw new ServiceException("减少库存信息失败,请联系管理员!");
+ }
+ try {
+ //减少库存数量
+ int updateCount = goodsAttributeDetailsMapper.reduceGoodsStockCount(goodsOrder.getGoodsAttributeDetailsId(), goodsCount.get());
+ if (updateCount < 1) {
+ log.info("减少库存数量失败,订单编号:{},商品属性明细id:{},库存数量:{}", goodOrderNo, goodsOrder.getGoodsAttributeDetailsId(), goodsCount.get());
+ }
+ } catch (Exception e) {
+ log.error("减少库存信息失败,失败原因为 ====> {}", e.getMessage());
+ throw new ServiceException(e.getMessage());
+ } finally {
+ redisDistributedLockUtils.unlock(goodsStockKey);
+ }
+ }
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/patientcenter/PatientCenterService.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/patientcenter/PatientCenterService.java
new file mode 100644
index 0000000..d08b370
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/patientcenter/PatientCenterService.java
@@ -0,0 +1,95 @@
+package com.xinelu.applet.service.patientcenter;
+
+import com.xinelu.applet.dto.nursingstationgoods.GoodsList;
+import com.xinelu.applet.dto.nursingstationgoods.GoodsOrderStationDTO;
+import com.xinelu.applet.dto.patientcenter.PatientCenterCouponDTO;
+import com.xinelu.applet.vo.coupon.CouponVO;
+import com.xinelu.applet.vo.patientcenter.PatientCenterCouponVO;
+import com.xinelu.applet.vo.patientcenter.PatientSignInfoVO;
+import com.xinelu.common.core.domain.AjaxResult;
+import com.xinelu.common.core.page.TableDataInfo;
+import com.xinelu.manage.domain.subscribemessagerecord.SubscribeMessageRecord;
+
+import java.util.List;
+
+/**
+ * @Description 会员APP和小程序个人中心业务层
+ * @Author 纪寒
+ * @Date 2023-02-24 14:45:11
+ * @Version 1.0
+ */
+public interface PatientCenterService {
+
+ /**
+ * 会员app和微信小程序-签到方法
+ *
+ * @param patientId 会员用户id
+ * @param signInChannel 签到来源,微信小程序、会员APP
+ * @return 签到结果
+ */
+ AjaxResult patientSignIn(Long patientId, String signInChannel);
+
+ /**
+ * 个人中心优惠券
+ *
+ * @param patientCenterCouponVO 用户信息及优惠券状态
+ * @return List
+ */
+ List selectCouponByUseStatus(PatientCenterCouponVO patientCenterCouponVO);
+
+ /**
+ * 个人中心积分兑换 - 查询积分兑换商品
+ *
+ * @return AjaxResult
+ */
+ List selectExchangeGoods();
+
+ /**
+ * 获取积分返回规则
+ *
+ * @param patientId 用户id
+ * @return com.xinyilu.nurseapplet.domain.vo.patientcenter.PatientSignInfoVO
+ **/
+ PatientSignInfoVO selectPatientSignIn(Long patientId);
+
+ /**
+ * 新人福利优惠券
+ *
+ * @param patientCenterCouponVO 用户信息及优惠券状态
+ * @return List
+ */
+ TableDataInfo getCouponByUseStatus(PatientCenterCouponDTO patientCenterCouponVO);
+
+ /**
+ * 新人福利-优惠券领取
+ *
+ * @param patientId 用户id
+ * @param couponId 优惠券id
+ * @return AjaxResult
+ */
+ AjaxResult insertCouponReceive(Long patientId, Long couponId);
+
+ /**
+ * 微信小程序-邀请好友接口
+ *
+ * @param inviteId 邀请人id
+ * @return 邀请码图片地址
+ */
+ AjaxResult inviteFriends(Long inviteId);
+
+ /**
+ * 新增积分兑换商品订单以及详细信息
+ *
+ * @param goodsOrder 商品订单
+ * @return 结果
+ */
+ AjaxResult insertIntegralGoodsOrder(GoodsOrderStationDTO goodsOrder);
+
+ /**
+ * 新增订阅微信小程序订阅消息记录
+ *
+ * @param subscribeMessageRecord 订阅微信小程序订阅消息记录
+ * @return com.xinyilu.common.core.domain.AjaxResult
+ **/
+ AjaxResult insertSubscribeMessageRecord(List subscribeMessageRecord);
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/patientcenter/impl/PatientCenterServiceImpl.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/patientcenter/impl/PatientCenterServiceImpl.java
new file mode 100644
index 0000000..0ca33d1
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/patientcenter/impl/PatientCenterServiceImpl.java
@@ -0,0 +1,666 @@
+package com.xinelu.applet.service.patientcenter.impl;
+
+import com.xinelu.applet.dto.nursingstationgoods.GoodsList;
+import com.xinelu.applet.dto.nursingstationgoods.GoodsOrderStationDTO;
+import com.xinelu.applet.dto.patientcenter.PatientCenterCouponDTO;
+import com.xinelu.applet.mapper.nurseapplogin.NurseAppLoginMapper;
+import com.xinelu.applet.mapper.nursingstationgoods.NursingStationGoodsMapper;
+import com.xinelu.applet.mapper.patientcenter.PatientCenterMapper;
+import com.xinelu.applet.service.messagepush.MessagePushService;
+import com.xinelu.applet.service.patientcenter.PatientCenterService;
+import com.xinelu.applet.vo.coupon.CouponVO;
+import com.xinelu.applet.vo.patientcenter.PatientCenterCouponVO;
+import com.xinelu.applet.vo.patientcenter.PatientSignInVO;
+import com.xinelu.applet.vo.patientcenter.PatientSignInfoVO;
+import com.xinelu.common.config.AppletChatConfig;
+import com.xinelu.common.config.AppletPageConfig;
+import com.xinelu.common.config.XinELuConfig;
+import com.xinelu.common.constant.Constants;
+import com.xinelu.common.core.domain.AjaxResult;
+import com.xinelu.common.core.page.TableDataInfo;
+import com.xinelu.common.enums.*;
+import com.xinelu.common.exception.ServiceException;
+import com.xinelu.common.utils.AppletChatUtil;
+import com.xinelu.common.utils.PageServiceUtil;
+import com.xinelu.common.utils.RedisDistributedLockUtils;
+import com.xinelu.common.utils.bean.BeanUtils;
+import com.xinelu.manage.domain.coupon.Coupon;
+import com.xinelu.manage.domain.goodsAttributeDetails.GoodsAttributeDetails;
+import com.xinelu.manage.domain.goodsOrder.GoodsOrder;
+import com.xinelu.manage.domain.goodsOrderDetails.GoodsOrderDetails;
+import com.xinelu.manage.domain.patientcouponreceive.PatientCouponReceive;
+import com.xinelu.manage.domain.patientintegralchange.PatientIntegralChange;
+import com.xinelu.manage.domain.patientsignininfo.PatientSignInInfo;
+import com.xinelu.manage.domain.subscribemessagerecord.SubscribeMessageRecord;
+import com.xinelu.manage.domain.systemsettingsinfo.SystemSettingsInfo;
+import com.xinelu.manage.mapper.coupon.CouponMapper;
+import com.xinelu.manage.mapper.goodsAttributeDetails.GoodsAttributeDetailsMapper;
+import com.xinelu.manage.mapper.goodsOrder.GoodsOrderMapper;
+import com.xinelu.manage.mapper.goodsOrderDetails.GoodsOrderDetailsMapper;
+import com.xinelu.manage.mapper.patientcouponreceive.PatientCouponReceiveMapper;
+import com.xinelu.manage.mapper.patientinfo.PatientInfoMapper;
+import com.xinelu.manage.mapper.patientintegralchange.PatientIntegralChangeMapper;
+import com.xinelu.manage.mapper.patientsignininfo.PatientSignInInfoMapper;
+import com.xinelu.manage.mapper.subscribemessagerecord.SubscribeMessageRecordMapper;
+import com.xinelu.manage.mapper.systemsettingsinfo.SystemSettingsInfoMapper;
+import com.xinelu.manage.vo.patientcouponreceive.PatientCouponReceiveInfoVO;
+import com.xinelu.manage.vo.patientinfo.PatientInfoVO;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.BooleanUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.stream.Collectors;
+
+
+/**
+ * @Description 会员APP和小程序个人中心业务层实现类
+ * @Author 纪寒
+ * @Date 2023-02-24 14:45:35
+ * @Version 1.0
+ */
+@Slf4j
+@Service
+public class PatientCenterServiceImpl implements PatientCenterService {
+ @Resource
+ private PatientCenterMapper patientCenterMapper;
+ @Resource
+ private SystemSettingsInfoMapper systemSettingsInfoMapper;
+ @Resource
+ private PatientSignInInfoMapper patientSignInInfoMapper;
+ @Resource
+ private PatientIntegralChangeMapper patientIntegralChangeMapper;
+ @Resource
+ private PatientInfoMapper patientInfoMapper;
+ @Resource
+ private AppletPageConfig appletPageConfig;
+ @Resource
+ private XinELuConfig xinYiLuConfig;
+ @Resource
+ private NurseAppLoginMapper nurseAppLoginMapper;
+ @Resource
+ private PageServiceUtil pageServiceUtil;
+ @Resource
+ private PatientCouponReceiveMapper patientCouponReceiveMapper;
+ @Resource
+ private NursingStationGoodsMapper nursingStationGoodsMapper;
+ @Resource
+ private RedisDistributedLockUtils redisDistributedLockUtils;
+ @Resource
+ private GoodsAttributeDetailsMapper goodsAttributeDetailsMapper;
+ @Resource
+ private GoodsOrderMapper goodsOrderMapper;
+ @Resource
+ private GoodsOrderDetailsMapper goodsOrderDetailsMapper;
+ @Resource
+ private CouponMapper couponMapper;
+ @Resource
+ private AppletChatConfig appletChatConfig;
+ @Resource
+ private SubscribeMessageRecordMapper subscribeMessageRecordMapper;
+ @Resource
+ private MessagePushService messagePushService;
+
+ /**
+ * 用户第一次签到次数
+ */
+ private static final int FIRST_SIGN_COUNT = 1;
+
+ /**
+ * 获取小程序二维码接口失败标识
+ */
+ private static final String FAIL = "FAIL";
+
+ /**
+ * 会员app和微信小程序-签到方法
+ *
+ * @param patientId 会员用户id
+ * @param signInChannel 签到来源,微信小程序、会员APP
+ * @return 签到结果
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public AjaxResult patientSignIn(Long patientId, String signInChannel) {
+ //确认用户是否是第一次签到
+ PatientSignInVO patientSignInInfo = patientCenterMapper.getPatientSignInInfo(patientId, LocalDate.now());
+ if (Objects.isNull(patientSignInInfo)) {
+ return AjaxResult.error("当前用户信息不存在,无法进行签到,请联系管理员!");
+ }
+ if (Objects.nonNull(patientSignInInfo.getTotalSignInDays()) && patientSignInInfo.getTodaySignInCount() > 0) {
+ return AjaxResult.error("您今天已经签到!");
+ }
+ boolean isFirstSignIn = Objects.isNull(patientSignInInfo.getSignInCount()) || patientSignInInfo.getSignInCount() == 0;
+ if (Objects.isNull(patientSignInInfo.getTotalSignInDays()) && BooleanUtils.isTrue(isFirstSignIn)) {
+ //当前用户第一次签到,记录签到信息
+ patientCenterMapper.updateTotalSignInDays(patientId);
+ this.setPatientSignInInfo(patientId, signInChannel);
+ //第一次签到送积分以及记录积分变更记录
+ this.insertGoodPatientIntegral(patientSignInInfo, FIRST_SIGN_COUNT, patientId, signInChannel);
+ messagePushService.integralMessage(patientId, FIRST_SIGN_COUNT);
+ return AjaxResult.success(FIRST_SIGN_COUNT);
+ }
+ //用户不是第一次签到,判断当前用户是否到达签到天数并送积分
+ patientCenterMapper.updateTotalSignInDays(patientId);
+ this.setPatientSignInInfo(patientId, signInChannel);
+ AtomicInteger atomicInteger = new AtomicInteger(Objects.isNull(patientSignInInfo.getTotalSignInDays()) ? 0 : patientSignInInfo.getTotalSignInDays());
+ int increment = atomicInteger.incrementAndGet();
+ //新增账户积分以及记录积分变更记录
+ this.insertGoodPatientIntegral(patientSignInInfo, increment, patientId, signInChannel);
+ messagePushService.integralMessage(patientId, increment);
+ return AjaxResult.success(increment);
+ }
+
+ /**
+ * 个人中心优惠券
+ *
+ * @param patientCenterCouponVO 用户信息及优惠券状态
+ * @return List
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public List selectCouponByUseStatus(PatientCenterCouponVO patientCenterCouponVO) {
+ patientCenterCouponVO.setReceiveSource(CouponReceiveTypeEnum.NEW_PEOPLE_WELFARE.getInfo());
+ List useStatusList = Arrays.asList(CouponUseStatusEnum.USED.getInfo(), CouponUseStatusEnum.NOT_USED.getInfo(), CouponUseStatusEnum.EXPIRED.getInfo());
+ patientCenterCouponVO.setUseStatusList(useStatusList);
+ List couponList = patientCenterMapper.selectCouponByUseStatus(patientCenterCouponVO);
+ //筛查过期的优惠券
+ for (CouponVO couponVO : couponList) {
+ if (Objects.isNull(couponVO) || Objects.isNull(couponVO.getExpirationEndTime())) {
+ continue;
+ }
+ if (LocalDateTime.now().isAfter(couponVO.getExpirationEndTime())) {
+ PatientCouponReceive patientCouponReceive = new PatientCouponReceive();
+ patientCouponReceive.setId(Objects.isNull(couponVO.getPatientCouponReceiveId()) ? 0 : couponVO.getPatientCouponReceiveId());
+ patientCouponReceive.setUseStatus(CouponUseStatusEnum.EXPIRED.getInfo());
+ int couponReceive = patientCouponReceiveMapper.updatePatientCouponReceive(patientCouponReceive);
+ if (couponReceive < 0) {
+ throw new ServiceException("个人中心优惠券查询失败,请联系管理员!");
+ }
+ couponVO.setUseStatus(CouponUseStatusEnum.EXPIRED.getInfo());
+ }
+ }
+ return couponList;
+ }
+
+ /**
+ * 积分兑换 - 查询积分兑换商品
+ *
+ * @return AjaxResult
+ */
+ @Override
+ public List selectExchangeGoods() {
+ //传入积分兑换标识、是否上架、商品买卖
+ return patientCenterMapper.selectGoodsByExchangeFlag(CouponAndIntegralFlagEnum.CONVERTIBLE.getInfo(), WhetherShelfEnum.SHEL.getInfo(), GoodsPurposeEnum.BUSINESS.getInfo());
+ }
+
+ /**
+ * 获取积分返回规则
+ *
+ * @param patientId 用户id
+ * @return com.xinyilu.nurseapplet.domain.vo.patientcenter.PatientSignInfoVO
+ **/
+ @Override
+ public PatientSignInfoVO selectPatientSignIn(Long patientId) {
+ //查询积分签到规则和邀请好友规则
+ List ruleList = Arrays.asList(SettingsTypeEnum.INVITE_FRIENDS.getInfo(), SettingsTypeEnum.SIGN_IN_RULE.getInfo());
+ Map ruleMap = patientCenterMapper.selectPatientSignIn(patientId, LocalDate.now(), ruleList).stream().filter(item -> StringUtils.isNotBlank(item.getSettingsType())).collect(Collectors.toMap(PatientSignInfoVO::getSettingsType, item -> item));
+ PatientSignInfoVO vo = new PatientSignInfoVO();
+ //获取累计签到规则信息
+ PatientSignInfoVO signInfoVO = ruleMap.getOrDefault(SettingsTypeEnum.SIGN_IN_RULE.getInfo(), new PatientSignInfoVO());
+ if (Objects.nonNull(signInfoVO) && Objects.nonNull(signInfoVO.getTotalSignInDays())) {
+ vo.setTotalSignInDays(signInfoVO.getTotalSignInDays());
+ } else {
+ vo.setTotalSignInDays(0);
+ }
+ if (Objects.nonNull(signInfoVO) && Objects.nonNull(signInfoVO.getIntegralCount())) {
+ vo.setSignInCount(signInfoVO.getIntegralCount());
+ } else {
+ vo.setSignInCount(0);
+ }
+ //获取邀请规则信息
+ PatientSignInfoVO inviteVO = ruleMap.getOrDefault(SettingsTypeEnum.INVITE_FRIENDS.getInfo(), new PatientSignInfoVO());
+ if (Objects.nonNull(inviteVO) && Objects.nonNull(inviteVO.getIntegralCount())) {
+ vo.setInviteFriends(inviteVO.getIntegralCount());
+ } else {
+ vo.setInviteFriends(0);
+ }
+ //查询用户签到天数和账户积分信息
+ PatientSignInfoVO patientSignInfo = patientCenterMapper.getPatientSignInfo(patientId, LocalDate.now());
+ if (Objects.isNull(patientSignInfo)) {
+ throw new ServiceException("当前用户信息不存在,获取积分信息失败!");
+ }
+ vo.setPatientSignInCount(Objects.isNull(patientSignInfo.getPatientSignInCount()) ? 0 : patientSignInfo.getPatientSignInCount());
+ vo.setIntegral(Objects.isNull(patientSignInfo.getIntegral()) ? 0 : patientSignInfo.getIntegral());
+ vo.setTodaySignInCount(Objects.isNull(patientSignInfo.getTodaySignInCount()) ? 0 : patientSignInfo.getTodaySignInCount());
+ return vo;
+ }
+
+ /**
+ * 微信小程序-邀请好友接口
+ *
+ * @param inviteId 邀请人id
+ * @return 邀请码图片地址
+ */
+ @Override
+ public AjaxResult inviteFriends(Long inviteId) {
+ //获取微信小程序AccessToken的值
+ PatientInfoVO patientInfo = patientInfoMapper.getPatientInfoById(inviteId);
+ if (Objects.isNull(patientInfo)) {
+ return AjaxResult.error("当前用户信息不存在,请联系管理员!");
+ }
+ if (StringUtils.isBlank(patientInfo.getPersonalWechatCodeUrl())) {
+ String fileName = String.valueOf(System.nanoTime()) + inviteId + ".png";
+ //小程序跳转路径
+ String appletPageUrl = appletPageConfig.getPageUrl();
+ //邀请人二维码存放路径
+ String filePathWeChatCodeUrl = xinYiLuConfig.getPersonalWeChatCodeUrl();
+ String appletCodePicture = AppletChatUtil.createAppletCode(inviteId, false, fileName, appletPageUrl, filePathWeChatCodeUrl);
+ if (StringUtils.isNotBlank(appletCodePicture) && StringUtils.equals(FAIL, appletCodePicture)) {
+ //第一次调用获取小程序二维码信息失败,重新递归调用一次,第二次失败直接返回提示信息
+ appletCodePicture = AppletChatUtil.createAppletCode(inviteId, true, fileName, appletPageUrl, filePathWeChatCodeUrl);
+ if (StringUtils.isNotBlank(appletCodePicture) && StringUtils.equals(FAIL, appletCodePicture)) {
+ return AjaxResult.error("获取小程序二维码信息失败,请联系管理员!");
+ }
+ }
+ String pictureUrl = "";
+ if (StringUtils.isNotBlank(appletCodePicture)) {
+ pictureUrl = "/profile" + xinYiLuConfig.getPersonalWeChatCodeUrl() + "/" + inviteId + "/" + fileName;
+ int updateCount = patientInfoMapper.updatePersonalWeChatCodeUrl(inviteId, pictureUrl);
+ if (updateCount <= 0) {
+ throw new ServiceException("获取微信小程序二维码信息失败,请联系管理员!");
+ }
+ }
+ return AjaxResult.success(pictureUrl);
+ }
+ //直接返回二维码图片信息
+ return AjaxResult.success(patientInfo.getPersonalWechatCodeUrl());
+ }
+
+ /**
+ * 新增积分兑换商品订单以及详细信息
+ *
+ * @param goodsOrder 商品订单
+ * @return 结果
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public AjaxResult insertIntegralGoodsOrder(GoodsOrderStationDTO goodsOrder) {
+ //判断当前会员信息是否存在
+ PatientInfoVO patientInfo = patientInfoMapper.getPatientInfoById(goodsOrder.getPatientId());
+ if (Objects.isNull(patientInfo)) {
+ return AjaxResult.error("当前用户信息不存在,无法兑换!");
+ }
+ GoodsAttributeDetails goodsAttributeDetails = nursingStationGoodsMapper.selectGoodsAttributeDetailsGoodsStockById(goodsOrder.getGoodsAttributeDetailsId());
+ //判断当前商品是否可兑换商品
+ if (Objects.nonNull(goodsAttributeDetails) && CouponAndIntegralFlagEnum.NOT_CONVERTIBLE.getInfo().equals(goodsAttributeDetails.getIntegralExchangeFlag())) {
+ return AjaxResult.error("当前商品非积分兑换商品,无法兑换!");
+ }
+ //判断积分兑换数值是否正确
+ boolean integralExchangeSill = Objects.nonNull(goodsAttributeDetails) && Objects.isNull(goodsAttributeDetails.getIntegralExchangeSill());
+ boolean equalIntegralExchangeSill = Objects.nonNull(goodsAttributeDetails) && !goodsOrder.getIntegralExchangeSill().equals(goodsAttributeDetails.getIntegralExchangeSill());
+ if (BooleanUtils.isTrue(integralExchangeSill) || BooleanUtils.isTrue(equalIntegralExchangeSill)) {
+ return AjaxResult.error("当前商品兑换需要使用的积分数值不正确,无法兑换!");
+ }
+ //判断积分兑换商品数目是否正确
+ boolean integralExchangeCount = Objects.nonNull(goodsAttributeDetails) && Objects.isNull(goodsAttributeDetails.getIntegralExchangeCount());
+ boolean equalIntegralExchangeCount = Objects.nonNull(goodsAttributeDetails) && !goodsOrder.getIntegralExchangeCount().equals(goodsAttributeDetails.getIntegralExchangeCount());
+ if (BooleanUtils.isTrue(integralExchangeCount) || BooleanUtils.isTrue(equalIntegralExchangeCount)) {
+ return AjaxResult.error("当前积分兑换商品的数量不正确,无法兑换!");
+ }
+ //判断库存是否充足
+ if (Objects.isNull(goodsAttributeDetails.getGoodsStock()) || goodsAttributeDetails.getGoodsStock() == 0) {
+ return AjaxResult.error("当前商品库存不足,无法购买!");
+ }
+ //判读用户账户积分是否充足
+ AtomicInteger patientIntegral = new AtomicInteger(Objects.isNull(patientInfo.getIntegral()) ? 0 : patientInfo.getIntegral());
+ AtomicInteger exchangeIntegralSkill = new AtomicInteger(Objects.isNull(goodsOrder.getIntegralExchangeSill()) ? 0 : goodsOrder.getIntegralExchangeSill());
+ if (patientIntegral.get() < exchangeIntegralSkill.get()) {
+ return AjaxResult.error("当前用户的账户积分数值不足,无法兑换!");
+ }
+ //判断商品库存数量是否满足兑换数量
+ AtomicInteger goodsStock = new AtomicInteger(goodsAttributeDetails.getGoodsStock());
+ AtomicInteger exchangeGoodsCount = new AtomicInteger(goodsOrder.getIntegralExchangeCount());
+ if (goodsStock.get() < exchangeGoodsCount.get()) {
+ return AjaxResult.error("当前商品库存不足,无法兑换!");
+ }
+ //生成兑换商品订单信息
+ String goodOrderNo = com.xinelu.common.utils.StringUtils.fillZeroByPatientId(goodsOrder.getPatientId(), 5) + System.nanoTime();
+ this.addExchangeGoodsOrderInfo(goodsOrder, patientInfo, exchangeIntegralSkill, exchangeGoodsCount, goodOrderNo);
+ return AjaxResult.success(goodsOrderMapper.getGoodsOrderByOrderNo(goodOrderNo));
+ }
+
+ /**
+ * 新增订阅微信小程序订阅消息记录
+ *
+ * @param subscribeMessageRecord 订阅微信小程序订阅消息记录
+ * @return com.xinyilu.common.core.domain.AjaxResult
+ **/
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public AjaxResult insertSubscribeMessageRecord(List subscribeMessageRecord) {
+ SubscribeMessageRecord messageRecord = new SubscribeMessageRecord();
+ messageRecord.setPatientId(subscribeMessageRecord.get(0).getPatientId());
+ messageRecord.setOpenid(subscribeMessageRecord.get(0).getOpenid());
+ //查询数据库中的数据 并去重
+ List subscribeMessageRecords = subscribeMessageRecordMapper.selectSubscribeMessageRecordList(messageRecord);
+ //前端穿过聊的数据并去重
+ List subscribeRecordVO = subscribeMessageRecord.stream().distinct().collect(Collectors.toList());
+ //求出差集 要新增的
+ List messageRecordSubtract = new ArrayList<>(CollectionUtils.subtract(subscribeRecordVO, subscribeMessageRecords));
+ //求出交集 要修改的
+ List messageRecordRetainAll = new ArrayList<>(CollectionUtils.intersection(subscribeRecordVO, subscribeMessageRecords));
+ if (CollectionUtils.isNotEmpty(messageRecordRetainAll)) {
+ for (SubscribeMessageRecord record : messageRecordRetainAll) {
+ subscribeMessageRecordMapper.updateSubscribeMessageTemplateId(record.getOpenid(), record.getTemplateId(), record.getSubscribeStatus(), record.getPatientId());
+ }
+ }
+ if (CollectionUtils.isNotEmpty(messageRecordSubtract)) {
+ return AjaxResult.success();
+ }
+ //新增订阅消息表信息
+ for (SubscribeMessageRecord record : messageRecordSubtract) {
+ record.setAppletId(appletChatConfig.getAppletId());
+ record.setSubscribeCount(1);
+ record.setSubscribeTime(LocalDateTime.now());
+ record.setSubscribeStatus(record.getSubscribeStatus());
+ if (StringUtils.equals(appletChatConfig.getAppointOrderTemplateId(), record.getTemplateId())) {
+ record.setMessageType(SubscribeMessageTypeEnum.APPOINT_ORDER_MESSAGE_PUSH.getInfo());
+ }
+ if (StringUtils.equals(appletChatConfig.getCouponReceiveTemplateId(), record.getTemplateId())) {
+ record.setMessageType(SubscribeMessageTypeEnum.COUPON_RECEIVE_MESSAGE_PUSH.getInfo());
+ }
+ if (StringUtils.equals(appletChatConfig.getGoodsOrderTemplateId(), record.getTemplateId())) {
+ record.setMessageType(SubscribeMessageTypeEnum.GOODS_ORDER_MESSAGE_PUSH.getInfo());
+ }
+ }
+ int insertRecord = subscribeMessageRecordMapper.insertSubscribeMessageRecordList(messageRecordSubtract);
+ if (insertRecord <= 0) {
+ return AjaxResult.error("新增订阅消息失败,请联系管理员!");
+ }
+ return AjaxResult.success();
+ }
+
+ /**
+ * 新人福利优惠券
+ *
+ * @param patientCenterCouponDTO 用户信息及优惠券状态
+ * @return List
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public TableDataInfo getCouponByUseStatus(PatientCenterCouponDTO patientCenterCouponDTO) {
+ //用户无登录情况下
+ if (Objects.isNull(patientCenterCouponDTO.getPatientId())) {
+ pageServiceUtil.startPage();
+ List couponNewPeople = patientCenterMapper.getCouponNewPeople(CouponReceiveTypeEnum.NEW_PEOPLE_WELFARE.getInfo());
+ return pageServiceUtil.getDataTable(couponNewPeople);
+ }
+ // 根据传过来的人员id去查询会员表中的完善标识字段
+ Integer loginFlag = nurseAppLoginMapper.getLoginFlagByPatientId(patientCenterCouponDTO.getPatientId());
+ patientCenterCouponDTO.setReceiveType(CouponReceiveTypeEnum.NEW_PEOPLE_WELFARE.getInfo());
+ //去判断完善标识是否完善 如果没有完善就是新人 否则就是注册过的
+ if (Objects.isNull(loginFlag)) {
+ pageServiceUtil.startPage();
+ List couponNewPeople = patientCenterMapper.getCouponNewPeople(CouponReceiveTypeEnum.NEW_PEOPLE_WELFARE.getInfo());
+ return pageServiceUtil.getDataTable(couponNewPeople);
+ }
+ pageServiceUtil.startPage();
+ List couponList = patientCenterMapper.getCouponByUseStatus(patientCenterCouponDTO);
+ //筛查过期的优惠券
+ for (CouponVO couponVO : couponList) {
+ if (Objects.isNull(couponVO) || Objects.isNull(couponVO.getExpirationEndTime())) {
+ continue;
+ }
+ if (LocalDateTime.now().isAfter(couponVO.getExpirationEndTime())) {
+ PatientCouponReceive patientCouponReceive = new PatientCouponReceive();
+ patientCouponReceive.setId(Objects.isNull(couponVO.getPatientCouponReceiveId()) ? 0 : couponVO.getPatientCouponReceiveId());
+ patientCouponReceive.setUseStatus(CouponUseStatusEnum.EXPIRED.getInfo());
+ patientCouponReceiveMapper.updatePatientCouponReceive(patientCouponReceive);
+ couponVO.setUseStatus(CouponUseStatusEnum.EXPIRED.getInfo());
+ }
+ }
+ return pageServiceUtil.getDataTable(couponList);
+ }
+
+ /**
+ * 优惠券领取
+ *
+ * @param patientId 用户id
+ * @param couponId 优惠券id
+ * @return AjaxResult
+ */
+ @Override
+ public AjaxResult insertCouponReceive(Long patientId, Long couponId) {
+ PatientInfoVO patientInfo = patientInfoMapper.getPatientInfoById(patientId);
+ if (Objects.isNull(patientInfo)) {
+ return AjaxResult.error("用户不存在,无法领取!");
+ }
+ PatientCouponReceiveInfoVO patientCouponReceive = patientCouponReceiveMapper.selectPatientCouponReceive(patientId, couponId);
+ //查询微信小程序订阅消息记录表该会员是否已订阅
+ SubscribeMessageRecord subscribeMessageRecord = subscribeMessageRecordMapper.selectSubscribeMessageRecordByPatientId(null, patientInfo.getOpenid(), appletChatConfig.getCouponReceiveTemplateId());
+ if (Objects.nonNull(patientCouponReceive)) {
+ if (StringUtils.isNotBlank(patientCouponReceive.getUseStatus()) && !CouponUseStatusEnum.WAIT_RECEIVE.getInfo().equals(patientCouponReceive.getUseStatus())) {
+ return AjaxResult.error("该优惠券已领取!");
+ }
+ patientCouponReceive.setExpirationStartTime(LocalDateTime.now());
+ patientCouponReceive.setExpirationEndTime(LocalDate.now().plusDays(patientCouponReceive.getCouponReductionDays()).atTime(23, 59, 59));
+ patientCouponReceive.setReceiveTime(LocalDateTime.now());
+ patientCouponReceive.setUseStatus(CouponUseStatusEnum.NOT_USED.getInfo());
+ patientCouponReceive.setUpdateTime(LocalDateTime.now());
+ patientCouponReceive.setCouponType(CouponTypeEnum.FULL_REDUCTION_COUPON.getInfo());
+ patientCouponReceiveMapper.updatePatientCouponReceive(patientCouponReceive);
+ boolean subscribeMessage = Objects.nonNull(subscribeMessageRecord)
+ && StringUtils.isNotBlank(subscribeMessageRecord.getSubscribeStatus())
+ && SubscribeStatusEnum.ACCEPT.getInfo().equals(subscribeMessageRecord.getSubscribeStatus());
+ if (BooleanUtils.isTrue(subscribeMessage)) {
+ //优惠券领取异步发送信息
+ messagePushService.messageCouponReceiveThread(subscribeMessageRecord, patientCouponReceive);
+ }
+ return AjaxResult.success();
+ }
+ //组装优惠券信息 并发送订阅消息
+ this.setCouponReceive(patientId, couponId, subscribeMessageRecord);
+ return AjaxResult.success();
+ }
+
+
+ /**
+ * 生成签到信息
+ *
+ * @param patientId 用户id
+ * @param signInChannel 签到渠道,微信小程序、手机APP
+ */
+ private void setPatientSignInInfo(Long patientId, String signInChannel) {
+ PatientSignInInfo signInInfo = new PatientSignInInfo();
+ signInInfo.setPatientId(patientId);
+ signInInfo.setSignInChannel(signInChannel);
+ signInInfo.setSignInTime(LocalDate.now());
+ signInInfo.setCreateTime(LocalDateTime.now());
+ int insertCount = patientSignInInfoMapper.insertPatientSignInInfo(signInInfo);
+ if (insertCount <= 0) {
+ log.error("生成签到记录表信息失败,签到信息:{}", signInInfo);
+ throw new ServiceException("签到失败,请联系管理员!");
+ }
+ }
+
+ /**
+ * 生成签到信息
+ *
+ * @param patientId 用户id
+ * @param signInChannel 签到渠道,微信小程序、手机APP
+ * @param originalIntegral 原始账户积分
+ * @param changeIntegral 赠送变更积分
+ */
+ private void setPatientIntegral(Long patientId, String signInChannel, int originalIntegral, int changeIntegral) {
+ PatientIntegralChange integralChange = new PatientIntegralChange();
+ integralChange.setPatientId(patientId);
+ integralChange.setOriginalIntegral(originalIntegral);
+ integralChange.setChangeIntegral(changeIntegral);
+ integralChange.setChangeTime(LocalDateTime.now());
+ integralChange.setChangeType(IntegralChangeType.SIGN_IN.getInfo());
+ integralChange.setChangeRemark("签到赠送积分");
+ integralChange.setChangeIntegralChannel(signInChannel);
+ integralChange.setCreateTime(LocalDateTime.now());
+ int insertCount = patientIntegralChangeMapper.insertPatientIntegralChange(integralChange);
+ if (insertCount <= 0) {
+ log.error("用户签到-生成积分变更记录表信息失败,积分变更信息:{}", integralChange);
+ throw new ServiceException("签到失败,请联系管理员!");
+ }
+ }
+
+
+ /**
+ * 新增商品订单主表信息减积分数与库存
+ *
+ * @param goodsOrder 前端穿过来的订单数据
+ * @param patientInfo 数据库查出的会员信息
+ * @param exchangeIntegralSkill 前端传的商品兑换数值
+ * @param exchangeGoodsCount 前端传的兑换商品积分数量
+ */
+ private void addExchangeGoodsOrderInfo(GoodsOrderStationDTO goodsOrder, PatientInfoVO patientInfo, AtomicInteger exchangeIntegralSkill, AtomicInteger exchangeGoodsCount, String goodOrderNo) {
+ GoodsOrder good = new GoodsOrder();
+ BeanUtils.copyBeanProp(good, goodsOrder);
+ good.setPatientId(goodsOrder.getPatientId());
+ good.setOrderNo(goodOrderNo);
+ good.setOrderStatus(GooodsOrderStatusEnum.WAIT_RECEIVED_GOODS.getInfo());
+ good.setRemark(com.xinelu.common.utils.StringUtils.isBlank(goodsOrder.getRemark()) ? "" : goodsOrder.getRemark());
+ good.setOrderTime(LocalDateTime.now());
+ good.setDelFlag(0);
+ good.setTotalPrice(BigDecimal.ZERO);
+ good.setOrderType(OrderTypeEnum.INTEGRAL_EXCHANGE.getInfo());
+ good.setCreateTime(LocalDateTime.now());
+ good.setNurseStationId(Objects.isNull(goodsOrder.getNurseStationId()) ? null : goodsOrder.getNurseStationId());
+ good.setBuySource(Objects.nonNull(good.getNurseStationId()) ? BuySourceEnum.NURSE_STATION.getInfo() : BuySourceEnum.SHOPPING_MALL.getInfo());
+ good.setOriginalTotalPrice(BigDecimal.ZERO);
+ int stationGoodsOrder = goodsOrderMapper.insertGoodsOrder(good);
+ if (stationGoodsOrder <= 0) {
+ throw new ServiceException("商品订单新增信息失败,请联系管理员!");
+ }
+ //新增商品订单明细表信息
+ GoodsOrderDetails goodsOrderDetails = new GoodsOrderDetails();
+ BeanUtils.copyBeanProp(goodsOrderDetails, goodsOrder);
+ goodsOrderDetails.setGoodsOrderId(good.getId());
+ goodsOrderDetails.setOrderNo(goodOrderNo);
+ goodsOrderDetails.setDelFlag(0);
+ goodsOrderDetails.setTotalPrice(BigDecimal.ZERO);
+ goodsOrderDetails.setCreateTime(LocalDateTime.now());
+ goodsOrderDetails.setIntegralExchangeSill(goodsOrder.getIntegralExchangeSill());
+ goodsOrderDetails.setIntegralExchangeCount(goodsOrder.getIntegralExchangeCount());
+ int orderDetails = goodsOrderDetailsMapper.insertGoodsOrderDetails(goodsOrderDetails);
+ if (orderDetails <= 0) {
+ throw new ServiceException("商品订单明细新增信息失败,请联系管理员!");
+ }
+ //减少库存数量
+ String goodsStockKey = Constants.BUY_GOODS_REDUCE_STOCK_KEY + goodOrderNo + "_" + goodsOrderDetails.getId();
+ boolean tryLock = redisDistributedLockUtils.tryLock(goodsStockKey, 5);
+ if (!tryLock) {
+ log.info("商品订单获取Redis锁失败,订单编号 =====> {}", goodOrderNo);
+ throw new ServiceException("减少库存信息失败,请联系管理员!");
+ }
+ try {
+ //减少会员账户积分数
+ patientInfoMapper.reducePatientIntegralCount(patientInfo.getId(), exchangeIntegralSkill.get());
+ //减少库存数量
+ goodsAttributeDetailsMapper.reduceGoodsStockCount(goodsOrder.getGoodsAttributeDetailsId(), exchangeGoodsCount.get());
+ //会员积分变更记录
+ this.setGoodPatientIntegral(patientInfo, exchangeIntegralSkill, good);
+ } catch (Exception e) {
+ log.error("减少库存与会员积分信息失败,失败原因为 ====> {}", e.getMessage());
+ throw new ServiceException(e.getMessage());
+ } finally {
+ redisDistributedLockUtils.unlock(goodsStockKey);
+ }
+ }
+
+
+ /**
+ * 记录商品兑换积分变更信息
+ *
+ * @param patientInfo 会员信息
+ * @param exchangeIntegralSkill 前端传的购买商品积分数量
+ * @param good 商品信息
+ **/
+ private void setGoodPatientIntegral(PatientInfoVO patientInfo, AtomicInteger exchangeIntegralSkill, GoodsOrder good) {
+ PatientIntegralChange patientIntegralChange = new PatientIntegralChange();
+ patientIntegralChange.setPatientId(patientInfo.getId());
+ patientIntegralChange.setOriginalIntegral(patientInfo.getIntegral());
+ patientIntegralChange.setChangeIntegral(exchangeIntegralSkill.get());
+ patientIntegralChange.setChangeTime(LocalDateTime.now());
+ patientIntegralChange.setChangeType(IntegralChangeType.COMMODITY_EXCHANGE.getInfo());
+ patientIntegralChange.setChangeRemark("商品兑换扣减积分");
+ patientIntegralChange.setChangeIntegralChannel(good.getOrderChannel());
+ patientIntegralChange.setCreateTime(LocalDateTime.now());
+ int integralChange = patientIntegralChangeMapper.insertPatientIntegralChange(patientIntegralChange);
+ if (integralChange <= 0) {
+ log.error("积分兑换商品-生成积分变更记录表信息失败,积分变更信息:{}", integralChange);
+ throw new ServiceException("兑换商品失败,请联系管理员!");
+ }
+ }
+
+ /**
+ * 签到送积分-记录积分信息
+ *
+ * @param patientSignInInfo 会员
+ * @param increment 签到天数
+ * @param patientId 会员id
+ * @param signInChannel 亲到方式
+ */
+ private void insertGoodPatientIntegral(PatientSignInVO patientSignInInfo, int increment, Long patientId, String signInChannel) {
+ SystemSettingsInfo settingsInfo = systemSettingsInfoMapper.getSystemSettingsInfoByType(SettingsTypeEnum.SIGN_IN_RULE.getInfo());
+ if (Objects.nonNull(settingsInfo) && Objects.nonNull(settingsInfo.getTotalSignInDays()) && increment >= settingsInfo.getTotalSignInDays()) {
+ //赠送积分
+ int originalIntegral = Objects.isNull(patientSignInInfo.getIntegral()) ? 0 : patientSignInInfo.getIntegral();
+ int changeIntegral = Objects.isNull(settingsInfo.getIntegralCount()) ? 0 : settingsInfo.getIntegralCount();
+ patientCenterMapper.updatePatientIntegral(patientId, changeIntegral);
+ this.setPatientIntegral(patientId, signInChannel, originalIntegral, changeIntegral);
+ //将用户表的签到天数清零
+ patientCenterMapper.clearTotalSignInDays(patientId);
+ }
+ }
+
+
+ /**
+ * 组装优惠券信息 并发送订阅消息
+ *
+ * @param patientId 会员id
+ * @param couponId 优惠券id
+ * @param subscribeMessageRecord 微信小程序订阅消息记录信息
+ **/
+ private void setCouponReceive(Long patientId, Long couponId, SubscribeMessageRecord subscribeMessageRecord) {
+ //组装优惠券信息
+ Coupon couponInfo = couponMapper.selectCouponById(couponId);
+ PatientCouponReceive couponReceive = new PatientCouponReceive();
+ couponReceive.setPatientId(patientId);
+ couponReceive.setCouponId(couponId);
+ couponReceive.setReceiveSource(CouponReceiveTypeEnum.NEW_PEOPLE_WELFARE.getInfo());
+ couponReceive.setExpirationStartTime(LocalDateTime.now());
+ couponReceive.setExpirationEndTime(LocalDate.now().plusDays(couponInfo.getCouponReductionDays()).atTime(23, 59, 59));
+ couponReceive.setReceiveTime(LocalDateTime.now());
+ couponReceive.setCreateTime(LocalDateTime.now());
+ couponReceive.setCouponTitle(com.xinelu.common.utils.StringUtils.isBlank(couponInfo.getCouponTitle()) ? "" : couponInfo.getCouponTitle());
+ couponReceive.setCouponPrice(Objects.isNull(couponInfo.getCouponPrice()) ? BigDecimal.ZERO : couponInfo.getCouponPrice());
+ couponReceive.setCouponConsumePrice(Objects.isNull(couponInfo.getCouponConsumePrice()) ? BigDecimal.ZERO : couponInfo.getCouponConsumePrice());
+ couponReceive.setCouponDescription(com.xinelu.common.utils.StringUtils.isBlank(couponInfo.getCouponDescription()) ? "" : couponInfo.getCouponDescription());
+ couponReceive.setUseStatus(CouponUseStatusEnum.NOT_USED.getInfo());
+ patientCouponReceiveMapper.insertPatientCouponReceive(couponReceive);
+ //新建对象并复制
+ PatientCouponReceiveInfoVO couponReceiveInfoVO = new PatientCouponReceiveInfoVO();
+ BeanUtils.copyProperties(couponReceive, couponReceiveInfoVO);
+ couponReceiveInfoVO.setCouponType(CouponTypeEnum.FULL_REDUCTION_COUPON.getInfo());
+ boolean subscribeMessage = Objects.nonNull(subscribeMessageRecord)
+ && StringUtils.isNotBlank(subscribeMessageRecord.getSubscribeStatus())
+ && SubscribeStatusEnum.ACCEPT.getInfo().equals(subscribeMessageRecord.getSubscribeStatus());
+ if (BooleanUtils.isTrue(subscribeMessage)) {
+ //异步发送信息
+ messagePushService.messageCouponReceiveThread(subscribeMessageRecord, couponReceiveInfoVO);
+ }
+ }
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/wechatappletcallback/WeChatAppletCallBackService.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/wechatappletcallback/WeChatAppletCallBackService.java
new file mode 100644
index 0000000..c9a5a36
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/wechatappletcallback/WeChatAppletCallBackService.java
@@ -0,0 +1,19 @@
+package com.xinelu.applet.service.wechatappletcallback;
+
+import com.xinelu.applet.vo.messagepush.WeChatMessagePushVO;
+
+/**
+ * @Description 微信小程序事件回调业务层
+ * @Author 纪寒
+ * @Date 2023-03-15 13:49:50
+ * @Version 1.0
+ */
+public interface WeChatAppletCallBackService {
+
+ /**
+ * 微信小程序消息推送事件回调POST处理
+ *
+ * @param weChatMessagePushVO 请求参数
+ */
+ void handleWeChatAppletCallBack(WeChatMessagePushVO weChatMessagePushVO);
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/wechatappletcallback/impl/WeChatAppletCallBackServiceImpl.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/wechatappletcallback/impl/WeChatAppletCallBackServiceImpl.java
new file mode 100644
index 0000000..ce6c096
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/service/wechatappletcallback/impl/WeChatAppletCallBackServiceImpl.java
@@ -0,0 +1,276 @@
+package com.xinelu.applet.service.wechatappletcallback.impl;
+
+import com.xinelu.applet.mapper.appletlogin.AppletLoginMapper;
+import com.xinelu.applet.service.wechatappletcallback.WeChatAppletCallBackService;
+import com.xinelu.applet.vo.messagepush.WeChatMessagePushVO;
+import com.xinelu.common.config.AppletChatConfig;
+import com.xinelu.common.enums.SubscribeMessageTypeEnum;
+import com.xinelu.common.exception.ServiceException;
+import com.xinelu.common.utils.DateUtils;
+import com.xinelu.manage.domain.patientinfo.PatientInfo;
+import com.xinelu.manage.domain.subscribemessagerecord.SubscribeMessageRecord;
+import com.xinelu.manage.domain.subscribemessagesendrecord.SubscribeMessageSendRecord;
+import com.xinelu.manage.mapper.subscribemessagerecord.SubscribeMessageRecordMapper;
+import com.xinelu.manage.mapper.subscribemessagesendrecord.SubscribeMessageSendRecordMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.compress.utils.Lists;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * @Description 微信小程序事件回调业务层实现类
+ * @Author 纪寒
+ * @Date 2023-03-15 13:50:06
+ * @Version 1.0
+ */
+@Service
+@Slf4j
+public class WeChatAppletCallBackServiceImpl implements WeChatAppletCallBackService {
+
+ @Resource
+ private SubscribeMessageRecordMapper subscribeMessageRecordMapper;
+ @Resource
+ private AppletChatConfig appletChatConfig;
+ @Resource
+ private AppletLoginMapper appletLoginMapper;
+ @Resource
+ private SubscribeMessageSendRecordMapper subscribeMessageSendRecordMapper;
+ /**
+ * 微信消息推送变更事件标识
+ */
+ private static final String SUBSCRIBE_MSG_CHANGE_EVENT = "subscribe_msg_change_event";
+
+ /**
+ * 微信消息推送订阅事件标识
+ */
+ private static final String SUBSCRIBE_MSG_POPUP_EVENT = "subscribe_msg_popup_event";
+
+ /**
+ * 微信消息推送发送结果事件标识
+ */
+ private static final String SUBSCRIBE_MSG__SENT_EVENT = "subscribe_msg_sent_event";
+
+ /**
+ * 微信小程序消息推送事件回调POST处理
+ *
+ * @param weChatMessagePushVO 请求参数
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public void handleWeChatAppletCallBack(WeChatMessagePushVO weChatMessagePushVO) {
+ if (weChatMessagePushVO.getEvent().equals(SUBSCRIBE_MSG_POPUP_EVENT)) {
+ //处理用户订阅授权事件
+ this.handleSubscribeMsgPopupEvent(weChatMessagePushVO);
+ }
+ if (weChatMessagePushVO.getEvent().equals(SUBSCRIBE_MSG_CHANGE_EVENT)) {
+ //处理订阅消息变更事件
+ this.handleSubscribeMsgChangeEvent(weChatMessagePushVO);
+ }
+ if (weChatMessagePushVO.getEvent().equals(SUBSCRIBE_MSG__SENT_EVENT)) {
+ //处理订阅消息发送结果事件
+ this.handleSubscribeMsgSentEvent(weChatMessagePushVO);
+ }
+ }
+
+ /**
+ * 处理用户订阅授权事件
+ *
+ * @param weChatMessagePushVO 参数信息
+ */
+ private void handleSubscribeMsgPopupEvent(WeChatMessagePushVO weChatMessagePushVO) {
+ //处理订阅消息授权事件
+ if (Objects.isNull(weChatMessagePushVO.getSubscribeMsgPopupEvent()) || CollectionUtils.isEmpty(weChatMessagePushVO.getSubscribeMsgPopupEvent().getSubscribeMsgPopupEventList())) {
+ return;
+ }
+ //查询用户信息表
+ PatientInfo patientInfo = appletLoginMapper.getPatientInfoByOpenId(StringUtils.isBlank(weChatMessagePushVO.getFromUserName()) ? "" : weChatMessagePushVO.getFromUserName());
+ //组装数据
+ List subscribeMessageRecordList = createSubscribeMessageRecordList(patientInfo, weChatMessagePushVO, SUBSCRIBE_MSG_POPUP_EVENT);
+ if (CollectionUtils.isEmpty(subscribeMessageRecordList)) {
+ return;
+ }
+ //根据openid查询数据库原有的订阅消息记录
+ SubscribeMessageRecord subscribeMessageRecord = new SubscribeMessageRecord();
+ subscribeMessageRecord.setOpenid(StringUtils.isBlank(weChatMessagePushVO.getFromUserName()) ? "" : weChatMessagePushVO.getFromUserName());
+ List existMessageRecordList = subscribeMessageRecordMapper.selectSubscribeMessageRecordList(subscribeMessageRecord);
+ List subtractSubscribeList = new ArrayList<>(CollectionUtils.subtract(subscribeMessageRecordList, existMessageRecordList));
+ if (CollectionUtils.isNotEmpty(subtractSubscribeList)) {
+ //新增订阅记录信息
+ int insertCount = subscribeMessageRecordMapper.insertSubscribeMessageRecordList(subtractSubscribeList);
+ if (insertCount <= 0) {
+ log.error("微信订阅消息回调,新增用户订阅消息记录失败,记录信息为:[{}]", subtractSubscribeList);
+ throw new ServiceException("微信订阅消息回调,新增用户订阅消息记录失败!");
+ }
+ }
+ List intersectionSubscribeList = new ArrayList<>(CollectionUtils.intersection(subscribeMessageRecordList, existMessageRecordList));
+ if (CollectionUtils.isNotEmpty(intersectionSubscribeList)) {
+ //修改订阅信息状态
+ for (SubscribeMessageRecord messageRecord : intersectionSubscribeList) {
+ Long patientId = null;
+ if (Objects.nonNull(patientInfo) && Objects.nonNull(patientInfo.getId())) {
+ patientId = patientInfo.getId();
+ }
+ String openId = StringUtils.isBlank(messageRecord.getOpenid()) ? "" : messageRecord.getOpenid();
+ String templateId = StringUtils.isBlank(messageRecord.getTemplateId()) ? "" : messageRecord.getTemplateId();
+ String subscribeStatus = StringUtils.isBlank(messageRecord.getSubscribeStatus()) ? "" : messageRecord.getSubscribeStatus();
+ subscribeMessageRecordMapper.updateSubscribeMessageTemplateId(openId, templateId, subscribeStatus, patientId);
+ }
+ }
+ }
+
+ /**
+ * 处理订阅消息变更事件
+ *
+ * @param weChatMessagePushVO 信息
+ */
+ private void handleSubscribeMsgChangeEvent(WeChatMessagePushVO weChatMessagePushVO) {
+ if (Objects.isNull(weChatMessagePushVO.getSubscribeMsgChangeEvent()) || CollectionUtils.isEmpty(weChatMessagePushVO.getSubscribeMsgChangeEvent().getSubscribeMsgPopupEventList())) {
+ return;
+ }
+ //查询用户信息表
+ PatientInfo patientInfo = appletLoginMapper.getPatientInfoByOpenId(StringUtils.isBlank(weChatMessagePushVO.getFromUserName()) ? "" : weChatMessagePushVO.getFromUserName());
+ //组装数据
+ List subscribeMessageRecordList = createSubscribeMessageRecordList(patientInfo, weChatMessagePushVO, SUBSCRIBE_MSG_CHANGE_EVENT);
+ if (CollectionUtils.isEmpty(subscribeMessageRecordList)) {
+ return;
+ }
+ //根据openid查询数据库原有的订阅消息记录
+ SubscribeMessageRecord subscribeMessageRecord = new SubscribeMessageRecord();
+ subscribeMessageRecord.setOpenid(StringUtils.isBlank(weChatMessagePushVO.getFromUserName()) ? "" : weChatMessagePushVO.getFromUserName());
+ List existMessageRecordList = subscribeMessageRecordMapper.selectSubscribeMessageRecordList(subscribeMessageRecord);
+ List intersectionSubscribeList = new ArrayList<>(CollectionUtils.intersection(subscribeMessageRecordList, existMessageRecordList));
+ if (CollectionUtils.isNotEmpty(intersectionSubscribeList)) {
+ //修改订阅信息状态
+ for (SubscribeMessageRecord messageRecord : intersectionSubscribeList) {
+ Long patientId = null;
+ if (Objects.nonNull(patientInfo) && Objects.nonNull(patientInfo.getId())) {
+ patientId = patientInfo.getId();
+ }
+ String openId = StringUtils.isBlank(messageRecord.getOpenid()) ? "" : messageRecord.getOpenid();
+ String templateId = StringUtils.isBlank(messageRecord.getTemplateId()) ? "" : messageRecord.getTemplateId();
+ String subscribeStatus = StringUtils.isBlank(messageRecord.getSubscribeStatus()) ? "" : messageRecord.getSubscribeStatus();
+ subscribeMessageRecordMapper.updateSubscribeMessageTemplateId(openId, templateId, subscribeStatus, patientId);
+ }
+ }
+ }
+
+ /**
+ * 处理订阅消息发送结果事件
+ *
+ * @param weChatMessagePushVO 信息
+ */
+ private void handleSubscribeMsgSentEvent(WeChatMessagePushVO weChatMessagePushVO) {
+ if (Objects.isNull(weChatMessagePushVO.getSubscribeMsgSentEvent()) || CollectionUtils.isEmpty(weChatMessagePushVO.getSubscribeMsgSentEvent().getSubscribeMsgSentEventList())) {
+ return;
+ }
+ //组装数据
+ List subscribeMessageSendRecordList = createSubscribeMessageSendRecordList(weChatMessagePushVO);
+ if (CollectionUtils.isNotEmpty(subscribeMessageSendRecordList)) {
+ int insertCount = subscribeMessageSendRecordMapper.insertSubscribeMessageSendRecordList(subscribeMessageSendRecordList);
+ if (insertCount <= 0) {
+ log.error("微信订阅消息回调,新增用户订阅消息发送记录失败,记录信息为:[{}]", subscribeMessageSendRecordList);
+ throw new ServiceException("微信订阅消息回调,新增用户订阅消息发送记录失败!");
+ }
+ }
+ }
+
+ /**
+ * 组装订阅消息数据
+ *
+ * @param patientInfo 会员用户信息
+ * @param weChatMessagePushVO 微信请求参数信息
+ * @param eventType 事件类型
+ * @return List
+ */
+ private List createSubscribeMessageRecordList(PatientInfo patientInfo, WeChatMessagePushVO weChatMessagePushVO, String eventType) {
+ List subscribeMessageRecordList = Lists.newArrayList();
+ if (SUBSCRIBE_MSG_POPUP_EVENT.equals(eventType)) {
+ subscribeMessageRecordList = weChatMessagePushVO.getSubscribeMsgPopupEvent().getSubscribeMsgPopupEventList().stream().filter(Objects::nonNull).map(item -> {
+ SubscribeMessageRecord subscribe = new SubscribeMessageRecord();
+ if (Objects.nonNull(patientInfo) && Objects.nonNull(patientInfo.getId())) {
+ subscribe.setPatientId(patientInfo.getId());
+ }
+ subscribe.setOpenid(StringUtils.isBlank(weChatMessagePushVO.getFromUserName()) ? "" : weChatMessagePushVO.getFromUserName());
+ subscribe.setAppletId(StringUtils.isBlank(weChatMessagePushVO.getToUserName()) ? "" : weChatMessagePushVO.getToUserName());
+ subscribe.setTemplateId(StringUtils.isBlank(item.getTemplateId()) ? "" : item.getTemplateId());
+ if (StringUtils.isNotBlank(item.getTemplateId()) && appletChatConfig.getCouponReceiveTemplateId().equals(item.getTemplateId())) {
+ subscribe.setMessageType(SubscribeMessageTypeEnum.COUPON_RECEIVE_MESSAGE_PUSH.getInfo());
+ }
+ if (StringUtils.isNotBlank(item.getTemplateId()) && appletChatConfig.getAppointOrderTemplateId().equals(item.getTemplateId())) {
+ subscribe.setMessageType(SubscribeMessageTypeEnum.APPOINT_ORDER_MESSAGE_PUSH.getInfo());
+ }
+ if (StringUtils.isNotBlank(item.getTemplateId()) && appletChatConfig.getGoodsOrderTemplateId().equals(item.getTemplateId())) {
+ subscribe.setMessageType(SubscribeMessageTypeEnum.GOODS_ORDER_MESSAGE_PUSH.getInfo());
+ }
+ if (StringUtils.isNotBlank(item.getTemplateId()) && appletChatConfig.getSignTemplateId().equals(item.getTemplateId())) {
+ subscribe.setMessageType(SubscribeMessageTypeEnum.SIGN_MESSAGE_PUSH.getInfo());
+ }
+ subscribe.setSubscribeCount(1);
+ subscribe.setSubscribeTime(StringUtils.isBlank(weChatMessagePushVO.getCreateTime()) ? null : DateUtils.timestampToLocalDateTime(Long.parseLong(weChatMessagePushVO.getCreateTime()) * 1000L));
+ subscribe.setCreateTime(LocalDateTime.now());
+ subscribe.setSubscribeStatus(StringUtils.isBlank(item.getSubscribeStatusString()) ? "" : item.getSubscribeStatusString());
+ return subscribe;
+ }).collect(Collectors.toList());
+ }
+ if (SUBSCRIBE_MSG_CHANGE_EVENT.equals(eventType)) {
+ subscribeMessageRecordList = weChatMessagePushVO.getSubscribeMsgChangeEvent().getSubscribeMsgPopupEventList().stream().filter(Objects::nonNull).map(item -> {
+ SubscribeMessageRecord subscribe = new SubscribeMessageRecord();
+ if (Objects.nonNull(patientInfo) && Objects.nonNull(patientInfo.getId())) {
+ subscribe.setPatientId(patientInfo.getId());
+ }
+ subscribe.setOpenid(StringUtils.isBlank(weChatMessagePushVO.getFromUserName()) ? "" : weChatMessagePushVO.getFromUserName());
+ subscribe.setAppletId(StringUtils.isBlank(weChatMessagePushVO.getToUserName()) ? "" : weChatMessagePushVO.getToUserName());
+ subscribe.setTemplateId(StringUtils.isBlank(item.getTemplateId()) ? "" : item.getTemplateId());
+ if (StringUtils.isNotBlank(item.getTemplateId()) && appletChatConfig.getCouponReceiveTemplateId().equals(item.getTemplateId())) {
+ subscribe.setMessageType(SubscribeMessageTypeEnum.COUPON_RECEIVE_MESSAGE_PUSH.getInfo());
+ }
+ if (StringUtils.isNotBlank(item.getTemplateId()) && appletChatConfig.getAppointOrderTemplateId().equals(item.getTemplateId())) {
+ subscribe.setMessageType(SubscribeMessageTypeEnum.APPOINT_ORDER_MESSAGE_PUSH.getInfo());
+ }
+ if (StringUtils.isNotBlank(item.getTemplateId()) && appletChatConfig.getGoodsOrderTemplateId().equals(item.getTemplateId())) {
+ subscribe.setMessageType(SubscribeMessageTypeEnum.GOODS_ORDER_MESSAGE_PUSH.getInfo());
+ }
+ if (StringUtils.isNotBlank(item.getTemplateId()) && appletChatConfig.getSignTemplateId().equals(item.getTemplateId())) {
+ subscribe.setMessageType(SubscribeMessageTypeEnum.SIGN_MESSAGE_PUSH.getInfo());
+ }
+ subscribe.setSubscribeCount(1);
+ subscribe.setSubscribeTime(StringUtils.isBlank(weChatMessagePushVO.getCreateTime()) ? null : DateUtils.timestampToLocalDateTime(Long.parseLong(weChatMessagePushVO.getCreateTime()) * 1000L));
+ subscribe.setCreateTime(LocalDateTime.now());
+ subscribe.setSubscribeStatus(StringUtils.isBlank(item.getSubscribeStatusString()) ? "" : item.getSubscribeStatusString());
+ return subscribe;
+ }).collect(Collectors.toList());
+ }
+ return subscribeMessageRecordList;
+ }
+
+ /**
+ * 组装订阅消息发送结果数据
+ *
+ * @param weChatMessagePushVO 微信请求参数信息
+ * @return List
+ */
+ private List createSubscribeMessageSendRecordList(WeChatMessagePushVO weChatMessagePushVO) {
+ return weChatMessagePushVO.getSubscribeMsgSentEvent().getSubscribeMsgSentEventList().stream().map(item -> {
+ SubscribeMessageSendRecord sendRecord = new SubscribeMessageSendRecord();
+ sendRecord.setOpenid(StringUtils.isBlank(weChatMessagePushVO.getFromUserName()) ? "" : weChatMessagePushVO.getFromUserName());
+ sendRecord.setAppletId(StringUtils.isBlank(weChatMessagePushVO.getToUserName()) ? "" : weChatMessagePushVO.getToUserName());
+ sendRecord.setTemplateId(StringUtils.isBlank(item.getTemplateId()) ? "" : item.getTemplateId());
+ sendRecord.setMessageType(StringUtils.isBlank(weChatMessagePushVO.getMsgType()) ? "" : weChatMessagePushVO.getMsgType());
+ sendRecord.setMsgId(StringUtils.isBlank(item.getMsgId()) ? "" : item.getMsgId());
+ sendRecord.setSubscribeTime(StringUtils.isBlank(weChatMessagePushVO.getCreateTime()) ? null : DateUtils.timestampToLocalDateTime(Long.parseLong(weChatMessagePushVO.getCreateTime()) * 1000L));
+ sendRecord.setCreateTime(LocalDateTime.now());
+ sendRecord.setErrorStatus(StringUtils.isBlank(item.getErrorStatus()) ? "" : item.getErrorStatus());
+ sendRecord.setErrorCode(StringUtils.isBlank(item.getErrorCode()) ? null : Integer.parseInt(item.getErrorCode()));
+ return sendRecord;
+ }).collect(Collectors.toList());
+ }
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/utils/XmlUtil.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/utils/XmlUtil.java
new file mode 100644
index 0000000..6793acc
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/utils/XmlUtil.java
@@ -0,0 +1,29 @@
+package com.xinelu.applet.utils;
+
+import org.simpleframework.xml.Serializer;
+import org.simpleframework.xml.core.Persister;
+
+/**
+ * @Description Xml格式数据工具类
+ * @Author 纪寒
+ * @Date 2023-03-15 13:37:34
+ * @Version 1.0
+ */
+public class XmlUtil {
+ /**
+ * Xml数据转换
+ *
+ * @param xml 数据格式
+ * @param objClass 要转换的类
+ * @return 返回结果
+ */
+ public static Object fromXml(String xml, Class objClass) {
+ Serializer serializer = new Persister();
+ try {
+ return serializer.read(objClass, xml);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/SubscribeMsgChangeEventVO.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/SubscribeMsgChangeEventVO.java
new file mode 100644
index 0000000..5359f1a
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/SubscribeMsgChangeEventVO.java
@@ -0,0 +1,25 @@
+package com.xinelu.applet.vo.messagepush;
+
+import lombok.Data;
+import org.simpleframework.xml.ElementList;
+import org.simpleframework.xml.Root;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @Description 当用户在手机端服务通知里消息卡片右上角“...”管理消息实体类
+ * @Author 纪寒
+ * @Date 2023-03-15 10:19:23
+ * @Version 1.0
+ */
+@Root(name = "SubscribeMsgChangeEvent", strict = false)
+@Data
+public class SubscribeMsgChangeEventVO implements Serializable {
+ private static final long serialVersionUID = -6682105837610124794L;
+ /**
+ * 信息集合
+ */
+ @ElementList(inline = true, required = false)
+ private List subscribeMsgPopupEventList;
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/SubscribeMsgPopupEventListVO.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/SubscribeMsgPopupEventListVO.java
new file mode 100644
index 0000000..5f0a563
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/SubscribeMsgPopupEventListVO.java
@@ -0,0 +1,36 @@
+package com.xinelu.applet.vo.messagepush;
+
+import lombok.Data;
+import org.simpleframework.xml.Element;
+import org.simpleframework.xml.Root;
+
+import java.io.Serializable;
+
+/**
+ * @Description 模板信息集合
+ * @Author 纪寒
+ * @Date 2023-03-15 10:28:02
+ * @Version 1.0
+ */
+@Root(name = "List", strict = false)
+@Data
+public class SubscribeMsgPopupEventListVO implements Serializable {
+ private static final long serialVersionUID = 548605591615555467L;
+ /**
+ * 模板id
+ */
+ @Element(name = "TemplateId", required = false)
+ private String templateId;
+
+ /**
+ * 订阅结果(accept接收;reject拒收)
+ */
+ @Element(name = "SubscribeStatusString", required = false)
+ private String subscribeStatusString;
+
+ /**
+ * 弹框场景,0代表在小程序页面内
+ */
+ @Element(name = "PopupScene", required = false)
+ private String popupScene;
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/SubscribeMsgPopupEventVO.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/SubscribeMsgPopupEventVO.java
new file mode 100644
index 0000000..e907408
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/SubscribeMsgPopupEventVO.java
@@ -0,0 +1,25 @@
+package com.xinelu.applet.vo.messagepush;
+
+import lombok.Data;
+import org.simpleframework.xml.ElementList;
+import org.simpleframework.xml.Root;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @Description 当用户触发订阅消息弹框后信息实体类
+ * @Author 纪寒
+ * @Date 2023-03-15 10:19:23
+ * @Version 1.0
+ */
+@Root(name = "SubscribeMsgPopupEvent", strict = false)
+@Data
+public class SubscribeMsgPopupEventVO implements Serializable {
+ private static final long serialVersionUID = -6682105837610124794L;
+ /**
+ * 信息集合
+ */
+ @ElementList(inline = true, required = false)
+ private List subscribeMsgPopupEventList;
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/SubscribeMsgSentEventListVO.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/SubscribeMsgSentEventListVO.java
new file mode 100644
index 0000000..1a0e8d1
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/SubscribeMsgSentEventListVO.java
@@ -0,0 +1,42 @@
+package com.xinelu.applet.vo.messagepush;
+
+import lombok.Data;
+import org.simpleframework.xml.Element;
+import org.simpleframework.xml.Root;
+
+import java.io.Serializable;
+
+/**
+ * @Description 调用订阅消息接口发送消息给用户的最终结果信息集合实体类
+ * @Author 纪寒
+ * @Date 2023-03-15 11:20:38
+ * @Version 1.0
+ */
+@Root(name = "List", strict = false)
+@Data
+public class SubscribeMsgSentEventListVO implements Serializable {
+ private static final long serialVersionUID = 3771741965224817805L;
+ /**
+ * 模板id
+ */
+ @Element(name = "TemplateId", required = false)
+ private String templateId;
+
+ /**
+ * 消息id(调用接口时也会返回)
+ */
+ @Element(name = "MsgID", required = false)
+ private String msgId;
+
+ /**
+ * 推送结果状态码(0表示成功)
+ */
+ @Element(name = "ErrorCode", required = false)
+ private String errorCode;
+
+ /**
+ * 推送结果状态码对应的含义
+ */
+ @Element(name = "ErrorStatus", required = false)
+ private String errorStatus;
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/SubscribeMsgSentEventVO.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/SubscribeMsgSentEventVO.java
new file mode 100644
index 0000000..892d557
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/SubscribeMsgSentEventVO.java
@@ -0,0 +1,25 @@
+package com.xinelu.applet.vo.messagepush;
+
+import lombok.Data;
+import org.simpleframework.xml.ElementList;
+import org.simpleframework.xml.Root;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @Description 调用订阅消息接口发送消息给用户的最终结果实体类
+ * @Author 纪寒
+ * @Date 2023-03-15 10:19:23
+ * @Version 1.0
+ */
+@Root(name = "SubscribeMsgSentEvent", strict = false)
+@Data
+public class SubscribeMsgSentEventVO implements Serializable {
+ private static final long serialVersionUID = -6682105837610124794L;
+ /**
+ * 信息集合
+ */
+ @ElementList(inline = true, required = false)
+ private List subscribeMsgSentEventList;
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/WeChatMessagePushVO.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/WeChatMessagePushVO.java
new file mode 100644
index 0000000..c4e12d8
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/messagepush/WeChatMessagePushVO.java
@@ -0,0 +1,66 @@
+package com.xinelu.applet.vo.messagepush;
+
+import lombok.Data;
+import org.simpleframework.xml.Element;
+import org.simpleframework.xml.Root;
+
+import java.io.Serializable;
+
+/**
+ * @Description 微信小程序消息推送回调实体类
+ * @Author 纪寒
+ * @Date 2023-03-15 10:14:17
+ * @Version 1.0
+ */
+@Root(name = "xml", strict = false)
+@Data
+public class WeChatMessagePushVO implements Serializable {
+ private static final long serialVersionUID = 6233209958847696141L;
+ /**
+ * 小程序账号
+ */
+ @Element(name = "ToUserName", required = false)
+ private String toUserName;
+
+ /**
+ * 用户openid
+ */
+ @Element(name = "FromUserName", required = false)
+ private String fromUserName;
+
+ /**
+ * 时间戳
+ */
+ @Element(name = "CreateTime", required = false)
+ private String createTime;
+
+ /**
+ * 消息类型
+ */
+ @Element(name = "MsgType", required = false)
+ private String msgType;
+
+ /**
+ * 事件类型
+ */
+ @Element(name = "Event", required = false)
+ private String event;
+
+ /**
+ * 当用户触发订阅消息弹框后触发时间集合
+ */
+ @Element(name = "SubscribeMsgPopupEvent", required = false)
+ private SubscribeMsgPopupEventVO subscribeMsgPopupEvent;
+
+ /**
+ * 当用户在手机端服务通知里消息卡片右上角“...”管理消息时
+ */
+ @Element(name = "SubscribeMsgChangeEvent", required = false)
+ private SubscribeMsgChangeEventVO subscribeMsgChangeEvent;
+
+ /**
+ * 当用户在手机端服务通知里消息卡片右上角“...”管理消息时
+ */
+ @Element(name = "SubscribeMsgSentEvent", required = false)
+ private SubscribeMsgSentEventVO subscribeMsgSentEvent;
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/nursingstationgoods/UpdateDefaultAddressVO.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/nursingstationgoods/UpdateDefaultAddressVO.java
new file mode 100644
index 0000000..641136f
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/nursingstationgoods/UpdateDefaultAddressVO.java
@@ -0,0 +1,30 @@
+package com.xinelu.applet.vo.nursingstationgoods;
+
+import com.xinelu.common.custominterface.Update;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+/**
+ * @Description 修改默认地址参数实体类
+ * @Author 纪寒
+ * @Date 2023-01-11 16:29:16
+ * @Version 1.0
+ */
+@Data
+public class UpdateDefaultAddressVO implements Serializable {
+ private static final long serialVersionUID = -5824121578070763076L;
+
+ /**
+ * 主键id
+ */
+ @NotNull(message = "收货地址id不能为空!", groups = {Update.class})
+ private Long id;
+
+ /**
+ * 默认地址标识,0:否,1:是
+ */
+ @NotNull(message = "默认收货地址标识不能为空!", groups = {Update.class})
+ private Integer defaultAddressFlag;
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/patientcenter/PatientCenterCouponVO.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/patientcenter/PatientCenterCouponVO.java
new file mode 100644
index 0000000..e4ba6e7
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/patientcenter/PatientCenterCouponVO.java
@@ -0,0 +1,44 @@
+package com.xinelu.applet.vo.patientcenter;
+
+import com.xinelu.common.custominterface.Insert;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @Description 个人中心优惠券前端传入VO
+ * @Author ZH
+ * @Date 2023-02-27
+ */
+@Data
+public class PatientCenterCouponVO implements Serializable {
+ private static final long serialVersionUID = -4238035673079939685L;
+
+ /**
+ * 会员id
+ */
+ @NotNull(message = "会员信息不能为空", groups = {Insert.class})
+ private Long patientId;
+
+ /**
+ * 优惠券使用状态
+ */
+ private String useStatus;
+
+ /**
+ * 领取方式,新人福利:NEW_PEOPLE_WELFARE,活动赠送:EVENT_GIFT,消费返券:CONSUME_REBATE
+ */
+ private String receiveType;
+
+ /**
+ * 优惠券来源
+ */
+ private String receiveSource;
+
+ /**
+ * 优惠券状态集合
+ */
+ List useStatusList;
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/patientcenter/PatientSignInVO.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/patientcenter/PatientSignInVO.java
new file mode 100644
index 0000000..3fd3360
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/patientcenter/PatientSignInVO.java
@@ -0,0 +1,41 @@
+package com.xinelu.applet.vo.patientcenter;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @Description 用户签到信息实体类
+ * @Author 纪寒
+ * @Date 2023-02-24 15:37:07
+ * @Version 1.0
+ */
+@Data
+public class PatientSignInVO implements Serializable {
+ private static final long serialVersionUID = -1266359305276156027L;
+
+ /**
+ * 用户id
+ */
+ private Long patientId;
+
+ /**
+ * 签到天数,每到一个周期以后自动清零
+ */
+ private Integer totalSignInDays;
+
+ /**
+ * 签到次数
+ */
+ private Integer signInCount;
+
+ /**
+ * 会员账户积分
+ */
+ private Integer integral;
+
+ /**
+ * 当前签到日期
+ */
+ private Integer todaySignInCount;
+}
diff --git a/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/patientcenter/PatientSignInfoVO.java b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/patientcenter/PatientSignInfoVO.java
new file mode 100644
index 0000000..d0d55f8
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/java/com/xinelu/applet/vo/patientcenter/PatientSignInfoVO.java
@@ -0,0 +1,55 @@
+package com.xinelu.applet.vo.patientcenter;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author ljh
+ * @version 1.0
+ * Create by 2023/2/27 16:50
+ */
+@Data
+public class PatientSignInfoVO implements Serializable {
+ private static final long serialVersionUID = -1943601999448833477L;
+
+ /**
+ * 系统配置信息表累计签到天数
+ */
+ private Integer totalSignInDays;
+
+ /**
+ * 系统配置信息表累计签到赠送积分数
+ */
+ private Integer signInCount;
+
+ /**
+ * 系统配置信息表邀请好友赠送积分数值
+ */
+ private Integer inviteFriends;
+
+ /**
+ * 系统配置信息表规则类型
+ */
+ private String settingsType;
+
+ /**
+ * 会用用户当天是否签到标识,0:都,1:是
+ */
+ private Integer todaySignInCount;
+
+ /**
+ * 会员累计签到天数
+ */
+ private Integer patientSignInCount;
+
+ /**
+ * 会员用户账户总积分
+ */
+ private Integer integral;
+
+ /**
+ * 系统配置参数信息表积分数值
+ */
+ private Integer integralCount;
+}
diff --git a/xinelu-nurse-applet/src/main/resources/mapper/applet/nurseapplogin/NurseAppLoginMapper.xml b/xinelu-nurse-applet/src/main/resources/mapper/applet/nurseapplogin/NurseAppLoginMapper.xml
index 94e45b9..f9e2506 100644
--- a/xinelu-nurse-applet/src/main/resources/mapper/applet/nurseapplogin/NurseAppLoginMapper.xml
+++ b/xinelu-nurse-applet/src/main/resources/mapper/applet/nurseapplogin/NurseAppLoginMapper.xml
@@ -64,4 +64,15 @@
+
+
diff --git a/xinelu-nurse-applet/src/main/resources/mapper/applet/nursingStationGoods/NursingStationGoodsMapper.xml b/xinelu-nurse-applet/src/main/resources/mapper/applet/nursingStationGoods/NursingStationGoodsMapper.xml
new file mode 100644
index 0000000..d1121e8
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/resources/mapper/applet/nursingStationGoods/NursingStationGoodsMapper.xml
@@ -0,0 +1,513 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ insert into receive_address_info
+
+ id,
+
+ patient_id,
+
+ openid,
+
+ unionid,
+
+ receive_name,
+
+ receive_phone,
+
+ receive_address,
+
+ area_code,
+
+ create_by,
+
+ create_time,
+
+ update_by,
+
+ update_time,
+
+
+
+ #{id},
+
+ #{patientId},
+
+ #{openid},
+
+ #{unionid},
+
+ #{receiveName},
+
+ #{receivePhone},
+
+ #{receiveAddress},
+
+ #{areaCode},
+
+ #{createBy},
+
+ #{createTime},
+
+ #{updateBy},
+
+ #{updateTime},
+
+
+
+
+
+ update receive_address_info
+
+ patient_id =
+ #{patientId},
+
+ openid =
+ #{openid},
+
+ unionid =
+ #{unionid},
+
+ receive_name =
+ #{receiveName},
+
+ receive_phone =
+ #{receivePhone},
+
+ receive_address =
+ #{receiveAddress},
+
+ area_code =
+ #{areaCode},
+
+ create_by =
+ #{createBy},
+
+ create_time =
+ #{createTime},
+
+ update_by =
+ #{updateBy},
+
+ update_time =
+ #{updateTime},
+
+
+ where id = #{id}
+
+
+
+ delete from receive_address_info where id in
+
+ #{id}
+
+
+
+
+
+
+
+
+
+
+
+ update goods_attribute_details
+
+ goods_attribute_id =
+ #{goodsAttributeId},
+
+ attribute_details_name =
+ #{attributeDetailsName},
+
+ goods_stock =
+ #{goodsStock},
+
+ goods_price =
+ #{goodsPrice},
+
+ attribute_piture_url =
+ #{attributePitureUrl},
+
+ sort =
+ #{sort},
+
+ create_by =
+ #{createBy},
+
+ create_time =
+ #{createTime},
+
+ update_by =
+ #{updateBy},
+
+ update_time =
+ #{updateTime},
+
+
+ where id = #{id}
+
+
+
+
diff --git a/xinelu-nurse-applet/src/main/resources/mapper/applet/patientcenter/PatientCenterMapper.xml b/xinelu-nurse-applet/src/main/resources/mapper/applet/patientcenter/PatientCenterMapper.xml
new file mode 100644
index 0000000..939d694
--- /dev/null
+++ b/xinelu-nurse-applet/src/main/resources/mapper/applet/patientcenter/PatientCenterMapper.xml
@@ -0,0 +1,225 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ update patient_info
+ set total_sign_in_days = IFNULL(total_sign_in_days, 0) + 1,
+ update_time = now()
+ where id = #{patientId}
+ and del_flag = 0
+
+
+
+ update patient_info
+ set integral = IFNULL(integral, 0) + #{integral},
+ update_time = now()
+ where id = #{patientId}
+ and del_flag = 0
+
+
+
+ update patient_info
+ set total_sign_in_days = 0,
+ update_time = now()
+ where id = #{patientId}
+ and del_flag = 0
+
+
+
+
+
+
+
+
+
+
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/goodsOrderDetails/GoodsOrderDetails.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/goodsOrderDetails/GoodsOrderDetails.java
new file mode 100644
index 0000000..0a0b8d5
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/goodsOrderDetails/GoodsOrderDetails.java
@@ -0,0 +1,197 @@
+package com.xinelu.manage.domain.goodsOrderDetails;
+
+import com.xinelu.common.annotation.Excel;
+import com.xinelu.common.core.domain.BaseDomain;
+import com.xinelu.common.custominterface.Insert;
+import com.xinelu.common.custominterface.Update;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+/**
+ * 商品订单明细对象 goods_order_details
+ *
+ * @author xinyilu
+ * @date 2022-10-18
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "商品订单明细对象", description = "goods_order_details")
+public class GoodsOrderDetails extends BaseDomain implements Serializable {
+ private static final long serialVersionUID = -2047412676286670313L;
+ /**
+ * 主键id
+ */
+ private Long id;
+
+ /**
+ * 商品订单表id
+ */
+ @ApiModelProperty(value = "商品订单表id")
+ @Excel(name = "商品订单表id")
+ @NotNull(message = "商品订单表id为空", groups = {Insert.class, Update.class})
+ private Long goodsOrderId;
+
+ /**
+ * 商品属性id
+ */
+ @ApiModelProperty(value = "商品属性id")
+ @Excel(name = "商品属性id")
+ @NotNull(message = "商品属性id不能为空", groups = {Insert.class, Update.class})
+ private Long goodsAttributeId;
+
+ /**
+ * 商品属性明细id
+ */
+ @ApiModelProperty(value = "商品属性明细id")
+ @Excel(name = "商品属性明细id")
+ @NotNull(message = "商品属性明细id不能为空", groups = {Insert.class, Update.class})
+ private Long goodsAttributeDetailsId;
+
+ /**
+ * 订单编号
+ */
+ @ApiModelProperty(value = "订单编号")
+ @Excel(name = "订单编号")
+ private String orderNo;
+
+ /**
+ * 商品名称
+ */
+ @ApiModelProperty(value = "商品名称")
+ @Excel(name = "商品名称")
+ @NotBlank(message = "商品名称不能为空", groups = {Insert.class, Update.class})
+ @Length(max = 50, message = "商品名称不能超过50位", groups = {Insert.class, Update.class})
+ private String goodsName;
+
+ /**
+ * 商品数量
+ */
+ @ApiModelProperty(value = "商品数量")
+ @Excel(name = "商品数量")
+ @NotNull(message = "商品数量不能为空", groups = {Insert.class, Update.class})
+ @Length(max = 10, message = "商品数量不能超过10位", groups = {Insert.class, Update.class})
+ private Integer goodsCount;
+
+ /**
+ * 商品属性名称
+ */
+ @ApiModelProperty(value = "商品属性名称")
+ @Excel(name = "商品属性名称")
+ private String goodsAttributeName;
+
+ /**
+ * 商品属性内容
+ */
+ @ApiModelProperty(value = "商品属性内容")
+ @Excel(name = "商品属性内容")
+ private String goodsAttributeContent;
+
+ /**
+ * 商品单价(元)
+ */
+ @ApiModelProperty(value = "商品单价")
+ @Excel(name = "商品单价", readConverterExp = "元=")
+ @NotNull(message = "商品单价不能为空", groups = {Insert.class, Update.class})
+ @Length(max = 10, message = "商品单价不能超过10位", groups = {Insert.class, Update.class})
+ private BigDecimal goodsPrice;
+
+ /**
+ * 应付总金额(元)
+ */
+ @ApiModelProperty(value = "应付总金额")
+ @Excel(name = "应付总金额", readConverterExp = "元=")
+ private BigDecimal totalPrice;
+
+ /**
+ * 优惠金额(元)
+ */
+ @ApiModelProperty(value = "优惠金额")
+ @Excel(name = "优惠金额", readConverterExp = "元=")
+ private BigDecimal discountPrice;
+
+ /**
+ * 运费金额(元)
+ */
+ @ApiModelProperty(value = "运费金额")
+ @Excel(name = "运费金额", readConverterExp = "元=")
+ private BigDecimal transportPrice;
+
+ /**
+ * 赠送积分
+ */
+ @ApiModelProperty(value = "赠送积分")
+ @Excel(name = "赠送积分")
+ private Integer giveIntegral;
+
+ /**
+ * 0:否,1:是
+ */
+ private Integer delFlag;
+
+ /**
+ * 优惠券id
+ */
+ private Long couponId;
+
+ /**
+ * 积分抵扣数量
+ */
+ private Integer integralDeductionCount;
+
+ /**
+ * 积分抵扣金额
+ */
+ private BigDecimal integralDeductionPrice;
+
+ /**
+ * 优惠券名称
+ */
+ private String couponTitle;
+
+ /**
+ * 积分兑换商品使用积分数值
+ */
+ private Integer integralExchangeSill;
+
+ /**
+ * 积分兑换商品数量
+ */
+ private Integer integralExchangeCount;
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ .append("id", getId())
+ .append("goodsOrderId", getGoodsOrderId())
+ .append("orderNo", getOrderNo())
+ .append("goodsName", getGoodsName())
+ .append("goodsCount", getGoodsCount())
+ .append("goodsAttributeName", getGoodsAttributeName())
+ .append("goodsAttributeContent", getGoodsAttributeContent())
+ .append("goodsPrice", getGoodsPrice())
+ .append("totalPrice", getTotalPrice())
+ .append("discountPrice", getDiscountPrice())
+ .append("transportPrice", getTransportPrice())
+ .append("giveIntegral", getGiveIntegral())
+ .append("delFlag", getDelFlag())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .toString();
+ }
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/patientcouponreceive/PatientCouponReceive.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/patientcouponreceive/PatientCouponReceive.java
new file mode 100644
index 0000000..74d2b2d
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/patientcouponreceive/PatientCouponReceive.java
@@ -0,0 +1,140 @@
+package com.xinelu.manage.domain.patientcouponreceive;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.xinelu.common.annotation.Excel;
+import com.xinelu.common.core.domain.BaseDomain;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * 会员用户优惠券领取记录对象 patient_coupon_receive
+ *
+ * @author xinyilu
+ * @date 2023-02-24
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "会员用户优惠券领取记录对象", description = "patient_coupon_receive")
+public class PatientCouponReceive extends BaseDomain implements Serializable {
+ private static final long serialVersionUID = 5822850923451694701L;
+ /**
+ * 主键id
+ */
+ private Long id;
+
+ /**
+ * 会员id
+ */
+ @ApiModelProperty(value = "会员id")
+ @Excel(name = "会员id")
+ private Long patientId;
+
+ /**
+ * 优惠券id
+ */
+ @ApiModelProperty(value = "优惠券id")
+ @Excel(name = "优惠券id")
+ private Long couponId;
+
+ /**
+ * 新人福利:NEW_PEOPLE_WELFARE,活动赠送:EVENT_GIFT,消费返券:CONSUME_REBATE
+ */
+ @ApiModelProperty(value = "新人福利:NEW_PEOPLE_WELFARE,活动赠送:EVENT_GIFT,消费返券:CONSUME_REBATE")
+ @Excel(name = "新人福利:NEW_PEOPLE_WELFARE,活动赠送:EVENT_GIFT,消费返券:CONSUME_REBATE")
+ private String receiveSource;
+
+ /**
+ * 有效期开始时间,yyyy-MM-dd HH:mm:ss
+ */
+ @ApiModelProperty(value = "有效期开始时间,yyyy-MM-dd HH:mm:ss")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @Excel(name = "有效期开始时间,yyyy-MM-dd HH:mm:ss", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime expirationStartTime;
+
+ /**
+ * 有效期结束时间,yyyy-MM-dd HH:mm:ss
+ */
+ @ApiModelProperty(value = "有效期结束时间,yyyy-MM-dd HH:mm:ss")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @Excel(name = "有效期结束时间,yyyy-MM-dd HH:mm:ss", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime expirationEndTime;
+
+ /**
+ * 领取时间,yyyy-MM-dd HH:mm:ss
+ */
+ @ApiModelProperty(value = "领取时间,yyyy-MM-dd HH:mm:ss")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @Excel(name = "领取时间,yyyy-MM-dd HH:mm:ss", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime receiveTime;
+
+ /**
+ * 未使用:NOT_USED,已使用:USED,已过期:EXPIRED
+ */
+ @ApiModelProperty(value = "未使用:NOT_USED,已使用:USED,已过期:EXPIRED")
+ @Excel(name = "未使用:NOT_USED,已使用:USED,已过期:EXPIRED")
+ private String useStatus;
+
+ /**
+ * 优惠券名称
+ */
+ @ApiModelProperty(value = "优惠券名称")
+ @Excel(name = "优惠券名称")
+ private String couponTitle;
+
+ /**
+ * 优惠券面额
+ */
+ @ApiModelProperty(value = "优惠券面额")
+ @Excel(name = "优惠券面额")
+ private BigDecimal couponPrice;
+
+ /**
+ * 优惠券适用门槛
+ */
+ @ApiModelProperty(value = "优惠券适用门槛")
+ @Excel(name = "优惠券适用门槛")
+ private BigDecimal couponConsumePrice;
+
+ /**
+ * 优惠券概述,包括使用范围,使用注意事项等信息
+ */
+ @ApiModelProperty(value = "优惠券概述,包括使用范围,使用注意事项等信息")
+ @Excel(name = "优惠券概述,包括使用范围,使用注意事项等信息")
+ private String couponDescription;
+
+ /**
+ * 优惠券有效期,单位:天
+ */
+ private Integer couponReductionDays;
+
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ .append("id", getId())
+ .append("patientId", getPatientId())
+ .append("couponId", getCouponId())
+ .append("receiveSource", getReceiveSource())
+ .append("expirationStartTime", getExpirationStartTime())
+ .append("expirationEndTime", getExpirationEndTime())
+ .append("receiveTime", getReceiveTime())
+ .append("useStatus", getUseStatus())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .toString();
+ }
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/patientintegralchange/PatientIntegralChange.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/patientintegralchange/PatientIntegralChange.java
new file mode 100644
index 0000000..02c28ef
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/patientintegralchange/PatientIntegralChange.java
@@ -0,0 +1,103 @@
+package com.xinelu.manage.domain.patientintegralchange;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.xinelu.common.annotation.Excel;
+import com.xinelu.common.core.domain.BaseDomain;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 会员积分变更记录对象 patient_integral_change
+ *
+ * @author xinyilu
+ * @date 2023-02-27
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "会员积分变更记录对象", description = "patient_integral_change")
+public class PatientIntegralChange extends BaseDomain implements Serializable {
+ private static final long serialVersionUID = 3874412439515378186L;
+ /**
+ * 主键id
+ */
+ private Long id;
+
+ /**
+ * 会员id
+ */
+ @ApiModelProperty(value = "会员id")
+ @Excel(name = "会员id")
+ private Long patientId;
+
+ /**
+ * 原始积分
+ */
+ @ApiModelProperty(value = "原始积分")
+ @Excel(name = "原始积分")
+ private Integer originalIntegral;
+
+ /**
+ * 变动积分
+ */
+ @ApiModelProperty(value = "变动积分")
+ @Excel(name = "变动积分")
+ private Integer changeIntegral;
+
+ /**
+ * 积分变更时间
+ */
+ @ApiModelProperty(value = "积分变更时间")
+ @JsonFormat(pattern = "yyyy-MM-dd, HH:mm:ss")
+ @Excel(name = "积分变更时间", width = 30, dateFormat = "yyyy-MM-dd, HH:mm:ss")
+ private LocalDateTime changeTime;
+
+ /**
+ * 积分变动类型,商品兑换:COMMODITY_EXCHANGE,好友邀请:FRIEND_INVITATION,观看视频:WATCH_VIDEO,
+ * 会员签到:SIGN_IN
+ */
+ @ApiModelProperty(value = "积分变动类型,商品兑换:COMMODITY_EXCHANGE,好友邀请:FRIEND_INVITATION,观看视频:WATCH_VIDEO,会员签到:SIGN_IN")
+ @Excel(name = "积分变动类型,商品兑换:COMMODITY_EXCHANGE,好友邀请:FRIEND_INVITATION,观看视频:WATCH_VIDEO,会员签到:SIGN_IN")
+ private String changeType;
+
+ /**
+ * 积分变更描述
+ */
+ @ApiModelProperty(value = "积分变更描述")
+ @Excel(name = "积分变更描述")
+ private String changeRemark;
+
+ /**
+ * 积分变更方式,手机App:MOBILE_APP,微信小程序:WECHAT_APPLET,支付宝小程序:ALI_PAY_APPLET
+ */
+ @ApiModelProperty(value = "积分变更方式,手机App:MOBILE_APP,微信小程序:WECHAT_APPLET,支付宝小程序:ALI_PAY_APPLET")
+ @Excel(name = "积分变更方式,手机App:MOBILE_APP,微信小程序:WECHAT_APPLET,支付宝小程序:ALI_PAY_APPLET")
+ private String changeIntegralChannel;
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ .append("id", getId())
+ .append("patientId", getPatientId())
+ .append("originalIntegral", getOriginalIntegral())
+ .append("changeIntegral", getChangeIntegral())
+ .append("changeTime", getChangeTime())
+ .append("changeType", getChangeType())
+ .append("changeRemark", getChangeRemark())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .toString();
+ }
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/patientsignininfo/PatientSignInInfo.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/patientsignininfo/PatientSignInInfo.java
new file mode 100644
index 0000000..49a423f
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/patientsignininfo/PatientSignInInfo.java
@@ -0,0 +1,72 @@
+package com.xinelu.manage.domain.patientsignininfo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.xinelu.common.annotation.Excel;
+import com.xinelu.common.core.domain.BaseDomain;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+import java.time.LocalDate;
+
+/**
+ * 会员用户签到记录对象 patient_sign_in_info
+ *
+ * @author xinyilu
+ * @date 2023-02-27
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "会员用户签到记录对象", description = "patient_sign_in_info")
+public class PatientSignInInfo extends BaseDomain implements Serializable {
+ private static final long serialVersionUID = -6783715945093928258L;
+ /**
+ * 主键id
+ */
+ private Long id;
+
+ /**
+ * 会员id
+ */
+ @ApiModelProperty(value = "会员id")
+ @Excel(name = "会员id")
+ private Long patientId;
+
+ /**
+ * 签到时间,yyyy-MM-dd,同一天只记录一次
+ */
+ @ApiModelProperty(value = "签到时间,yyyy-MM-dd,同一天只记录一次")
+ @JsonFormat(pattern = "yyyy-MM-dd")
+ @Excel(name = "签到时间,yyyy-MM-dd,同一天只记录一次", width = 30, dateFormat = "yyyy-MM-dd")
+ private LocalDate signInTime;
+
+ /**
+ * 签到方式,手机App:MOBILE_APP,微信小程序:WECHAT_APPLET,支付宝小程序:ALI_PAY_APPLET
+ */
+ @ApiModelProperty(value = "签到方式,手机App:MOBILE_APP,微信小程序:WECHAT_APPLET,支付宝小程序:ALI_PAY_APPLET")
+ @Excel(name = "签到方式,手机App:MOBILE_APP,微信小程序:WECHAT_APPLET,支付宝小程序:ALI_PAY_APPLET")
+ private String signInChannel;
+
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ .append("id", getId())
+ .append("patientId", getPatientId())
+ .append("signInTime", getSignInTime())
+ .append("signInChannel", getSignInChannel())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .toString();
+ }
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/subscribemessagerecord/SubscribeMessageRecord.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/subscribemessagerecord/SubscribeMessageRecord.java
new file mode 100644
index 0000000..24630b8
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/subscribemessagerecord/SubscribeMessageRecord.java
@@ -0,0 +1,131 @@
+package com.xinelu.manage.domain.subscribemessagerecord;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.xinelu.common.annotation.Excel;
+import com.xinelu.common.core.domain.BaseDomain;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+import java.util.Objects;
+
+/**
+ * 微信小程序订阅消息记录对象 subscribe_message_record
+ *
+ * @author xinyilu
+ * @date 2023-03-14
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@ApiModel(value = "微信小程序订阅消息记录对象", description = "subscribe_message_record")
+public class SubscribeMessageRecord extends BaseDomain implements Serializable {
+ private static final long serialVersionUID = -474969938563834831L;
+ /**
+ * 主键id
+ */
+ private Long id;
+
+ /**
+ * 会员id
+ */
+ @ApiModelProperty(value = "会员id")
+ @Excel(name = "会员id")
+ private Long patientId;
+
+ /**
+ * 微信unionid标识
+ */
+ @ApiModelProperty(value = "微信unionid标识")
+ @Excel(name = "微信unionid标识")
+ private String unionid;
+
+ /**
+ * 微信小程序的openid
+ */
+ @ApiModelProperty(value = "微信小程序的openid")
+ @Excel(name = "微信小程序的openid")
+ private String openid;
+
+ /**
+ * 消息模板id
+ */
+ @ApiModelProperty(value = "消息模板id")
+ @Excel(name = "消息模板id")
+ private String templateId;
+
+ /**
+ * 订阅消息类型,消费提醒:CONSUME_MESSAGE_PUSH,优惠券到期提醒:COUPON_EXPIRE_MESSAGE_PUSH,积分过期提醒:INTEGRAL_EXPIRE_MESSAGE_PUSH
+ */
+ @ApiModelProperty(value = "订阅消息类型,消费提醒:CONSUME_MESSAGE_PUSH,优惠券到期提醒:COUPON_EXPIRE_MESSAGE_PUSH,积分过期提醒:INTEGRAL_EXPIRE_MESSAGE_PUSH")
+ @Excel(name = "订阅消息类型,消费提醒:CONSUME_MESSAGE_PUSH,优惠券到期提醒:COUPON_EXPIRE_MESSAGE_PUSH,积分过期提醒:INTEGRAL_EXPIRE_MESSAGE_PUSH")
+ private String messageType;
+
+ /**
+ * 用于订阅消息次数
+ */
+ @ApiModelProperty(value = "用于订阅消息次数")
+ @Excel(name = "用于订阅消息次数")
+ private Integer subscribeCount;
+
+ /**
+ * 订阅时间
+ */
+ @ApiModelProperty(value = "订阅时间")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @Excel(name = "订阅时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime subscribeTime;
+
+ /**
+ * 微信小程序账户id
+ */
+ private String appletId;
+
+ /**
+ * 订阅状态,accept:接受,reject:拒绝
+ */
+ private String subscribeStatus;
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ SubscribeMessageRecord that = (SubscribeMessageRecord) o;
+ return Objects.equals(openid, that.openid) && Objects.equals(templateId, that.templateId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(openid, templateId);
+ }
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ .append("id", getId())
+ .append("patientId", getPatientId())
+ .append("unionid", getUnionid())
+ .append("openid", getOpenid())
+ .append("templateId", getTemplateId())
+ .append("messageType", getMessageType())
+ .append("subscribeCount", getSubscribeCount())
+ .append("subscribeTime", getSubscribeTime())
+ .append("appletId", getAppletId())
+ .append("subscribeStatus", getSubscribeStatus())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .toString();
+ }
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/subscribemessagesendrecord/SubscribeMessageSendRecord.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/subscribemessagesendrecord/SubscribeMessageSendRecord.java
new file mode 100644
index 0000000..a6c6336
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/domain/subscribemessagesendrecord/SubscribeMessageSendRecord.java
@@ -0,0 +1,119 @@
+package com.xinelu.manage.domain.subscribemessagesendrecord;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.xinelu.common.annotation.Excel;
+import com.xinelu.common.core.domain.BaseDomain;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 微信小程序订阅消息发送结果记录对象 subscribe_message_send_record
+ *
+ * @author xinyilu
+ * @date 2023-03-16
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@ApiModel(value = "微信小程序订阅消息发送结果记录对象", description = "subscribe_message_send_record")
+public class SubscribeMessageSendRecord extends BaseDomain implements Serializable {
+ private static final long serialVersionUID = 4503696547761494422L;
+ /**
+ * 主键id
+ */
+ private Long id;
+
+ /**
+ * 微信unionid
+ */
+ @ApiModelProperty(value = "微信unionid")
+ @Excel(name = "微信unionid")
+ private String unionid;
+
+ /**
+ * 微信openid
+ */
+ @ApiModelProperty(value = "微信openid")
+ @Excel(name = "微信openid")
+ private String openid;
+
+ /**
+ * 微信小程序id
+ */
+ @ApiModelProperty(value = "微信小程序id")
+ @Excel(name = "微信小程序id")
+ private String appletId;
+
+ /**
+ * 订阅消息发送时间
+ */
+ @ApiModelProperty(value = "订阅消息发送时间")
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ @Excel(name = "订阅消息发送时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime subscribeTime;
+
+ /**
+ * 消息模板id
+ */
+ @ApiModelProperty(value = "消息模板id")
+ @Excel(name = "消息模板id")
+ private String templateId;
+
+ /**
+ * 消息id
+ */
+ @ApiModelProperty(value = "消息id")
+ @Excel(name = "消息id")
+ private String msgId;
+
+ /**
+ * 订阅消息类型,预约服务付款通知提醒:APPOINT_ORDER_MESSAGE_PUSH,优惠券领取提醒:COUPON_RECEIVE_MESSAGE_PUSH,商品订单支付成功提醒:GOODS_ORDER_MESSAGE_PUSH
+ */
+ @ApiModelProperty(value = "订阅消息类型")
+ @Excel(name = "订阅消息类型")
+ private String messageType;
+
+ /**
+ * 推送结果状态码(0表示成功)
+ */
+ @ApiModelProperty(value = "推送结果状态码")
+ @Excel(name = "推送结果状态码", readConverterExp = "0=表示成功")
+ private Integer errorCode;
+
+ /**
+ * 推送结果状态码,success:成功
+ */
+ @ApiModelProperty(value = "推送结果状态码,success:成功")
+ @Excel(name = "推送结果状态码,success:成功")
+ private String errorStatus;
+
+
+ @Override
+ public String toString() {
+ return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+ .append("id", getId())
+ .append("unionid", getUnionid())
+ .append("openid", getOpenid())
+ .append("appletId", getAppletId())
+ .append("subscribeTime", getSubscribeTime())
+ .append("templateId", getTemplateId())
+ .append("msgId", getMsgId())
+ .append("errorCode", getErrorCode())
+ .append("errorStatus", getErrorStatus())
+ .append("createBy", getCreateBy())
+ .append("createTime", getCreateTime())
+ .append("updateBy", getUpdateBy())
+ .append("updateTime", getUpdateTime())
+ .toString();
+ }
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/dto/subscribemessagerecord/SubscribeMessageRecordDTO.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/dto/subscribemessagerecord/SubscribeMessageRecordDTO.java
new file mode 100644
index 0000000..253e20d
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/dto/subscribemessagerecord/SubscribeMessageRecordDTO.java
@@ -0,0 +1,24 @@
+package com.xinelu.manage.dto.subscribemessagerecord;
+
+import com.xinelu.manage.domain.subscribemessagerecord.SubscribeMessageRecord;
+import lombok.Data;
+
+import javax.validation.Valid;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author ljh
+ * @version 1.0
+ * Create by 2023/3/15 10:01
+ */
+@Data
+public class SubscribeMessageRecordDTO implements Serializable {
+
+ private static final long serialVersionUID = -5480052884317349349L;
+ /**
+ * 微信小程序订阅消息记录对象集合
+ **/
+ @Valid
+ List subscribeMessageRecordList;
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/goodsOrderDetails/GoodsOrderDetailsMapper.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/goodsOrderDetails/GoodsOrderDetailsMapper.java
new file mode 100644
index 0000000..eb02cf2
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/goodsOrderDetails/GoodsOrderDetailsMapper.java
@@ -0,0 +1,71 @@
+package com.xinelu.manage.mapper.goodsOrderDetails;
+
+import com.xinelu.manage.domain.goodsOrderDetails.GoodsOrderDetails;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 商品订单明细Mapper接口
+ *
+ * @author xinyilu
+ * @date 2022-10-18
+ */
+public interface GoodsOrderDetailsMapper {
+ /**
+ * 查询商品订单明细
+ *
+ * @param id 商品订单明细主键
+ * @return 商品订单明细
+ */
+ GoodsOrderDetails selectGoodsOrderDetailsById(Long id);
+
+ /**
+ * 查询商品订单明细列表
+ *
+ * @param goodsOrderDetails 商品订单明细
+ * @return 商品订单明细集合
+ */
+ List selectGoodsOrderDetailsList(GoodsOrderDetails goodsOrderDetails);
+
+ /**
+ * 新增商品订单明细
+ *
+ * @param goodsOrderDetails 商品订单明细
+ * @return 结果
+ */
+ int insertGoodsOrderDetails(GoodsOrderDetails goodsOrderDetails);
+
+ /**
+ * 修改商品订单明细
+ *
+ * @param goodsOrderDetails 商品订单明细
+ * @return 结果
+ */
+ int updateGoodsOrderDetails(GoodsOrderDetails goodsOrderDetails);
+
+ /**
+ * 删除商品订单明细
+ *
+ * @param id 商品订单明细主键
+ * @return 结果
+ */
+ int deleteGoodsOrderDetailsById(Long id);
+
+ /**
+ * 批量删除商品订单明细
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ int deleteGoodsOrderDetailsByIds(Long[] ids);
+
+ /**
+ * 根据订单数量和订单明细查询订单信息
+ *
+ * @param orderNo 订单编号
+ * @param goodsOrderDetailId 明细id
+ * @return 订单明细信息
+ */
+ GoodsOrderDetails getGoodsOrderDetailInfo(@Param("orderNo") String orderNo, @Param("goodsOrderDetailId") Long goodsOrderDetailId);
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/patientcouponreceive/PatientCouponReceiveMapper.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/patientcouponreceive/PatientCouponReceiveMapper.java
new file mode 100644
index 0000000..c013787
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/patientcouponreceive/PatientCouponReceiveMapper.java
@@ -0,0 +1,130 @@
+package com.xinelu.manage.mapper.patientcouponreceive;
+
+import com.xinelu.manage.domain.patientcouponreceive.PatientCouponReceive;
+import com.xinelu.manage.vo.patientcouponreceive.PatientCouponReceiveInfoVO;
+import com.xinelu.manage.vo.patientcouponreceive.PatientCouponReceiveVO;
+import org.apache.ibatis.annotations.Param;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+
+/**
+ * 会员用户优惠券领取记录Mapper接口
+ *
+ * @author xinyilu
+ * @date 2023-02-24
+ */
+public interface PatientCouponReceiveMapper {
+ /**
+ * 查询会员用户优惠券领取记录
+ *
+ * @param id 会员用户优惠券领取记录主键
+ * @return 会员用户优惠券领取记录
+ */
+ PatientCouponReceive selectPatientCouponReceiveById(Long id);
+
+ /**
+ * 查询会员用户优惠券领取记录列表
+ *
+ * @param patientCouponReceive 会员用户优惠券领取记录
+ * @return 会员用户优惠券领取记录集合
+ */
+ List selectPatientCouponReceiveList(PatientCouponReceive patientCouponReceive);
+
+ /**
+ * 新增会员用户优惠券领取记录
+ *
+ * @param patientCouponReceive 会员用户优惠券领取记录
+ * @return 结果
+ */
+ int insertPatientCouponReceive(PatientCouponReceive patientCouponReceive);
+
+ /**
+ * 修改会员用户优惠券领取记录
+ *
+ * @param patientCouponReceive 会员用户优惠券领取记录
+ * @return 结果
+ */
+ int updatePatientCouponReceive(PatientCouponReceive patientCouponReceive);
+
+ /**
+ * 删除会员用户优惠券领取记录
+ *
+ * @param id 会员用户优惠券领取记录主键
+ * @return 结果
+ */
+ int deletePatientCouponReceiveById(Long id);
+
+ /**
+ * 批量删除会员用户优惠券领取记录
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ int deletePatientCouponReceiveByIds(Long[] ids);
+
+ /**
+ * 批量新增用户优惠券信息
+ *
+ * @param couponReceiveList 优惠券信息集合
+ * @return 新增数量
+ */
+ int insertBatchPatientReceive(@Param("couponReceiveList") List couponReceiveList);
+
+ /**
+ * 查询会员用户过期的优惠券领取记录列表
+ *
+ * @param expirationEndTime 过期的优惠券时间
+ * @param couponUseStatus 优惠券状态
+ * @return 会员用户优惠券领取记录集合
+ */
+ List getPatientCouponExpirationEndTime(@Param("expirationEndTime") LocalDateTime expirationEndTime, @Param("couponUseStatus") String couponUseStatus);
+
+ /**
+ * 批量更新优惠券状态
+ *
+ * @param couponUseStatus 状态
+ * @param idList id集合
+ * @return 更新数量
+ */
+ int updateCouponReceiveStatus(@Param("couponUseStatus") String couponUseStatus, @Param("idList") List idList);
+
+
+ /**
+ * 批量更新优惠券状态集合
+ *
+ * @param couponUseStatus 状态
+ * @param idList 优惠券id集合
+ * @return int
+ **/
+ int updateCouponReceiveStatusList(@Param("couponUseStatus") String couponUseStatus, @Param("idList") List idList);
+
+ /**
+ * 查询用户所属的优惠券券信息
+ *
+ * @param patientId 会员id
+ * @param couponId 优惠券id
+ * @return 用户优惠券信息
+ */
+ PatientCouponReceiveVO getPatientCouponInfo(@Param("patientId") Long patientId, @Param("couponId") Long couponId);
+
+ /**
+ * 优惠用户优惠表中的优惠券状态
+ *
+ * @param patientId 会员id
+ * @param couponId 优惠券id
+ * @param useStatus 优惠券状态
+ * @return 数量
+ */
+ int updatePatientCouponUseStatus(@Param("patientId") Long patientId, @Param("couponId") Long couponId, @Param("useStatus") String useStatus);
+
+ /**
+ * 查询会员用户优惠券领取记录
+ *
+ * @param patientId 会员用户主键
+ * @param couponId 优惠券领取主键
+ * @return 会员用户优惠券领取记录
+ */
+ PatientCouponReceiveInfoVO selectPatientCouponReceive(@Param("patientId") Long patientId, @Param("couponId") Long couponId);
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/patientintegralchange/PatientIntegralChangeMapper.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/patientintegralchange/PatientIntegralChangeMapper.java
new file mode 100644
index 0000000..d0c0c98
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/patientintegralchange/PatientIntegralChangeMapper.java
@@ -0,0 +1,61 @@
+package com.xinelu.manage.mapper.patientintegralchange;
+
+import com.xinelu.manage.domain.patientintegralchange.PatientIntegralChange;
+
+import java.util.List;
+
+/**
+ * 会员积分变更记录Mapper接口
+ *
+ * @author xinyilu
+ * @date 2023-02-27
+ */
+public interface PatientIntegralChangeMapper {
+ /**
+ * 查询会员积分变更记录
+ *
+ * @param id 会员积分变更记录主键
+ * @return 会员积分变更记录
+ */
+ PatientIntegralChange selectPatientIntegralChangeById(Long id);
+
+ /**
+ * 查询会员积分变更记录列表
+ *
+ * @param patientIntegralChange 会员积分变更记录
+ * @return 会员积分变更记录集合
+ */
+ List selectPatientIntegralChangeList(PatientIntegralChange patientIntegralChange);
+
+ /**
+ * 新增会员积分变更记录
+ *
+ * @param patientIntegralChange 会员积分变更记录
+ * @return 结果
+ */
+ int insertPatientIntegralChange(PatientIntegralChange patientIntegralChange);
+
+ /**
+ * 修改会员积分变更记录
+ *
+ * @param patientIntegralChange 会员积分变更记录
+ * @return 结果
+ */
+ int updatePatientIntegralChange(PatientIntegralChange patientIntegralChange);
+
+ /**
+ * 删除会员积分变更记录
+ *
+ * @param id 会员积分变更记录主键
+ * @return 结果
+ */
+ int deletePatientIntegralChangeById(Long id);
+
+ /**
+ * 批量删除会员积分变更记录
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ int deletePatientIntegralChangeByIds(Long[] ids);
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/patientsignininfo/PatientSignInInfoMapper.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/patientsignininfo/PatientSignInInfoMapper.java
new file mode 100644
index 0000000..1fd6651
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/patientsignininfo/PatientSignInInfoMapper.java
@@ -0,0 +1,72 @@
+package com.xinelu.manage.mapper.patientsignininfo;
+
+import com.xinelu.manage.domain.patientsignininfo.PatientSignInInfo;
+import org.apache.ibatis.annotations.Param;
+
+import java.time.LocalDate;
+import java.util.List;
+
+/**
+ * 会员用户签到记录Mapper接口
+ *
+ * @author xinyilu
+ * @date 2023-02-27
+ */
+public interface PatientSignInInfoMapper {
+ /**
+ * 查询会员用户签到记录
+ *
+ * @param id 会员用户签到记录主键
+ * @return 会员用户签到记录
+ */
+ PatientSignInInfo selectPatientSignInInfoById(Long id);
+
+ /**
+ * 查询会员用户签到记录列表
+ *
+ * @param patientSignInInfo 会员用户签到记录
+ * @return 会员用户签到记录集合
+ */
+ List selectPatientSignInInfoList(PatientSignInInfo patientSignInInfo);
+
+ /**
+ * 新增会员用户签到记录
+ *
+ * @param patientSignInInfo 会员用户签到记录
+ * @return 结果
+ */
+ int insertPatientSignInInfo(PatientSignInInfo patientSignInInfo);
+
+ /**
+ * 修改会员用户签到记录
+ *
+ * @param patientSignInInfo 会员用户签到记录
+ * @return 结果
+ */
+ int updatePatientSignInInfo(PatientSignInInfo patientSignInInfo);
+
+ /**
+ * 删除会员用户签到记录
+ *
+ * @param id 会员用户签到记录主键
+ * @return 结果
+ */
+ int deletePatientSignInInfoById(Long id);
+
+ /**
+ * 批量删除会员用户签到记录
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ int deletePatientSignInInfoByIds(Long[] ids);
+
+ /**
+ * 根据签到日期查询当前人员有没有签到过
+ *
+ * @param patientId 会员id
+ * @param signInTime 签到日期
+ * @return 签到数量
+ */
+ int getPatientSignInInfoCountByDate(@Param("patientId") Long patientId, @Param("signInTime") LocalDate signInTime);
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/receiveAddressInfo/ReceiveAddressInfoMapper.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/receiveAddressInfo/ReceiveAddressInfoMapper.java
new file mode 100644
index 0000000..40eb349
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/receiveAddressInfo/ReceiveAddressInfoMapper.java
@@ -0,0 +1,74 @@
+package com.xinelu.manage.mapper.receiveAddressInfo;
+
+import com.xinelu.manage.domain.receiveAddressInfo.ReceiveAddressInfo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 收货人地址信息Mapper接口
+ *
+ * @author xinyilu
+ * @date 2022-10-18
+ */
+public interface ReceiveAddressInfoMapper {
+ /**
+ * 查询收货人地址信息
+ *
+ * @param id 收货人地址信息主键
+ * @return 收货人地址信息
+ */
+ ReceiveAddressInfo selectReceiveAddressInfoById(Long id);
+
+ /**
+ * 查询收货人地址信息列表
+ *
+ * @param receiveAddressInfo 收货人地址信息
+ * @return 收货人地址信息集合
+ */
+ List selectReceiveAddressInfoList(ReceiveAddressInfo receiveAddressInfo);
+
+ /**
+ * 新增收货人地址信息
+ *
+ * @param receiveAddressInfo 收货人地址信息
+ * @return 结果
+ */
+ int insertReceiveAddressInfo(ReceiveAddressInfo receiveAddressInfo);
+
+ /**
+ * 修改收货人地址信息
+ *
+ * @param receiveAddressInfo 收货人地址信息
+ * @return 结果
+ */
+ int updateReceiveAddressInfo(ReceiveAddressInfo receiveAddressInfo);
+
+ /**
+ * 删除收货人地址信息
+ *
+ * @param id 收货人地址信息主键
+ * @return 结果
+ */
+ int deleteReceiveAddressInfoById(Long id);
+
+ /**
+ * 批量删除收货人地址信息
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ int deleteReceiveAddressInfoByIds(Long[] ids);
+
+ /**
+ * 查询当前收货地址是否存在
+ *
+ * @param patientId 会员id
+ * @param receiveName 收货人名称
+ * @param receivePhone 收货人电话
+ * @param receiveAddress 收货地址
+ * @return 数量
+ */
+ int getReceiveAddressInfo(@Param("patientId") Long patientId, @Param("receiveName") String receiveName,
+ @Param("receivePhone") String receivePhone, @Param("receiveAddress") String receiveAddress);
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/subscribemessagerecord/SubscribeMessageRecordMapper.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/subscribemessagerecord/SubscribeMessageRecordMapper.java
new file mode 100644
index 0000000..5a550b8
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/subscribemessagerecord/SubscribeMessageRecordMapper.java
@@ -0,0 +1,108 @@
+package com.xinelu.manage.mapper.subscribemessagerecord;
+
+import com.xinelu.manage.domain.subscribemessagerecord.SubscribeMessageRecord;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 微信小程序订阅消息记录Mapper接口
+ *
+ * @author xinyilu
+ * @date 2023-03-14
+ */
+public interface SubscribeMessageRecordMapper {
+ /**
+ * 查询微信小程序订阅消息记录
+ *
+ * @param id 微信小程序订阅消息记录主键
+ * @return 微信小程序订阅消息记录
+ */
+ SubscribeMessageRecord selectSubscribeMessageRecordById(Long id);
+
+ /**
+ * 查询微信小程序订阅消息记录列表
+ *
+ * @param subscribeMessageRecord 微信小程序订阅消息记录
+ * @return 微信小程序订阅消息记录集合
+ */
+ List selectSubscribeMessageRecordList(SubscribeMessageRecord subscribeMessageRecord);
+
+ /**
+ * 新增微信小程序订阅消息记录
+ *
+ * @param subscribeMessageRecord 微信小程序订阅消息记录
+ * @return 结果
+ */
+ int insertSubscribeMessageRecord(SubscribeMessageRecord subscribeMessageRecord);
+
+ /**
+ * 修改微信小程序订阅消息记录
+ *
+ * @param subscribeMessageRecord 微信小程序订阅消息记录
+ * @return 结果
+ */
+ int updateSubscribeMessageRecord(SubscribeMessageRecord subscribeMessageRecord);
+
+ /**
+ * 删除微信小程序订阅消息记录
+ *
+ * @param id 微信小程序订阅消息记录主键
+ * @return 结果
+ */
+ int deleteSubscribeMessageRecordById(Long id);
+
+ /**
+ * 批量删除微信小程序订阅消息记录
+ *
+ * @param ids 需要删除的数据主键集合
+ * @return 结果
+ */
+ int deleteSubscribeMessageRecordByIds(Long[] ids);
+
+ /**
+ * 根据用户id,openid,消息模板id查询微信小程序订阅消息记录
+ *
+ * @param patientId 会员id
+ * @param openid openid
+ * @param templateId 消息模板id
+ * @return com.xinyilu.base.domain.subscribemessagerecord.SubscribeMessageRecord
+ **/
+ SubscribeMessageRecord selectSubscribeMessageRecordByPatientId(@Param("patientId") Long patientId, @Param("openid") String openid, @Param("templateId") String templateId);
+
+ /**
+ * 根据用户id查询微信小程序订阅消息记录次数
+ *
+ * @param subscribeMessageRecord 微信小程序订阅消息记录
+ * @return int
+ **/
+ int selectSubscribeMessageRecordByCount(SubscribeMessageRecord subscribeMessageRecord);
+
+ /**
+ * 批量新增微信小程序订阅消息记录
+ *
+ * @param subscribeMessageRecordList 新增微信小程序订阅消息记录
+ * @return int
+ **/
+ int insertSubscribeMessageRecordList(List subscribeMessageRecordList);
+
+ /**
+ * 根据会员openid与templateId修改微信小程序订阅消息记录
+ *
+ * @param openId 微信openid
+ * @param templateId 模板id
+ * @param subscribeStatus 订阅状态
+ * @return int
+ **/
+ int updateSubscribeMessageTemplateId(@Param("openId") String openId, @Param("templateId") String templateId, @Param("subscribeStatus") String subscribeStatus, @Param("patientId") Long patientId);
+
+ /**
+ * 查询
+ *
+ * @param ids 会员id
+ * @param subscribeStatus 订阅状态
+ * @param messageType 订阅消息类型
+ * @return List
+ */
+ List selectSubscribeList(@Param("list") List ids, @Param("subscribeStatus") String subscribeStatus, @Param("messageType") String messageType);
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/subscribemessagesendrecord/SubscribeMessageSendRecordMapper.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/subscribemessagesendrecord/SubscribeMessageSendRecordMapper.java
new file mode 100644
index 0000000..456172d
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/mapper/subscribemessagesendrecord/SubscribeMessageSendRecordMapper.java
@@ -0,0 +1,22 @@
+package com.xinelu.manage.mapper.subscribemessagesendrecord;
+
+import com.xinelu.manage.domain.subscribemessagesendrecord.SubscribeMessageSendRecord;
+
+import java.util.List;
+
+/**
+ * 微信小程序订阅消息发送结果记录Mapper接口
+ *
+ * @author xinyilu
+ * @date 2023-03-16
+ */
+public interface SubscribeMessageSendRecordMapper {
+
+ /**
+ * 批量新增微信小程序订阅消息发送记录
+ *
+ * @param subscribeMessageSendRecordList 微信小程序订阅发送消息记录
+ * @return int
+ **/
+ int insertSubscribeMessageSendRecordList(List subscribeMessageSendRecordList);
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/vo/patientcouponreceive/PatientCouponReceiveInfoVO.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/vo/patientcouponreceive/PatientCouponReceiveInfoVO.java
new file mode 100644
index 0000000..037df6d
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/vo/patientcouponreceive/PatientCouponReceiveInfoVO.java
@@ -0,0 +1,22 @@
+package com.xinelu.manage.vo.patientcouponreceive;
+
+import com.xinelu.manage.domain.patientcouponreceive.PatientCouponReceive;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.io.Serializable;
+
+/**
+ * @author ljh
+ * @version 1.0
+ * Create by 2023/3/15 9:07
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+public class PatientCouponReceiveInfoVO extends PatientCouponReceive implements Serializable {
+ private static final long serialVersionUID = 7762303477160252595L;
+ /**
+ * 优惠券类型,满减券:FULL_REDUCTION_COUPON,代金券:CASH_COUPON,兑换券:EXCHANGE_COUPON,折扣券:DISCOUNT_COUPON',
+ **/
+ private String couponType;
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/vo/patientcouponreceive/PatientCouponReceiveVO.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/vo/patientcouponreceive/PatientCouponReceiveVO.java
new file mode 100644
index 0000000..2250d08
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/vo/patientcouponreceive/PatientCouponReceiveVO.java
@@ -0,0 +1,76 @@
+package com.xinelu.manage.vo.patientcouponreceive;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.time.LocalDateTime;
+
+/**
+ * @Description 优惠券信息与用户优惠券领取信息实体类
+ * @Author 纪寒
+ * @Date 2023-03-01 16:21:07
+ * @Version 1.0
+ */
+@Data
+public class PatientCouponReceiveVO implements Serializable {
+ private static final long serialVersionUID = -7141760788932626416L;
+ /**
+ * 主键id
+ */
+ private Long id;
+
+ /**
+ * 会员id
+ */
+ private Long patientId;
+
+ /**
+ * 优惠券id
+ */
+ private Long couponId;
+
+ /**
+ * 新人福利:NEW_PEOPLE_WELFARE,活动赠送:EVENT_GIFT,消费返券:CONSUME_REBATE
+ */
+ private String receiveSource;
+
+ /**
+ * 有效期开始时间,yyyy-MM-dd HH:mm:ss
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime expirationStartTime;
+
+ /**
+ * 有效期结束时间,yyyy-MM-dd HH:mm:ss
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime expirationEndTime;
+
+ /**
+ * 领取时间,yyyy-MM-dd HH:mm:ss
+ */
+ @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+ private LocalDateTime receiveTime;
+
+ /**
+ * 未使用:NOT_USED,已使用:USED,已过期:EXPIRED
+ */
+ private String useStatus;
+
+ /**
+ * 优惠券面额
+ */
+ private BigDecimal couponPrice;
+
+ /**
+ * 优惠券名称
+ */
+ private String couponTitle;
+
+ /**
+ * 优惠券使用门槛
+ */
+ private BigDecimal couponConsumePrice;
+}
diff --git a/xinelu-nurse-manage/src/main/java/com/xinelu/manage/vo/receiveAddressInfo/ReceiveAddressInfoVO.java b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/vo/receiveAddressInfo/ReceiveAddressInfoVO.java
new file mode 100644
index 0000000..8e45fa7
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/java/com/xinelu/manage/vo/receiveAddressInfo/ReceiveAddressInfoVO.java
@@ -0,0 +1,141 @@
+package com.xinelu.manage.vo.receiveAddressInfo;
+
+import com.xinelu.common.annotation.Excel;
+import com.xinelu.common.custominterface.Insert;
+import com.xinelu.common.custominterface.Update;
+import com.xinelu.manage.vo.sysarea.SysAreaVO;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * @author ljh
+ * @version 1.0
+ * Create by 2022/10/25 10:36
+ */
+@Data
+public class ReceiveAddressInfoVO implements Serializable {
+ private static final long serialVersionUID = -4835574485358136057L;
+
+ /**
+ * 主键id
+ */
+ private Long id;
+
+ /**
+ * 会员id
+ */
+ @ApiModelProperty(value = "会员id")
+ @Excel(name = "会员id")
+ @NotNull(message = "会员id为空", groups = {Insert.class, Update.class})
+ private Long patientId;
+
+ /**
+ * 微信openid
+ */
+ @ApiModelProperty(value = "微信openid")
+ @Excel(name = "微信openid")
+ private String openid;
+
+ /**
+ * 微信unionid
+ */
+ @ApiModelProperty(value = "微信unionid")
+ @Excel(name = "微信unionid")
+ private String unionid;
+
+ /**
+ * 收货人名称
+ */
+ @ApiModelProperty(value = "收货人名称")
+ @Excel(name = "收货人名称")
+ @NotBlank(message = "收货人名称为空", groups = {Insert.class, Update.class})
+ @Length(max = 30, message = "收货人名称不能超过30位", groups = {Insert.class, Update.class})
+ private String receiveName;
+
+ /**
+ * 联系电话
+ */
+ @ApiModelProperty(value = "联系电话")
+ @Excel(name = "联系电话")
+ @NotBlank(message = "联系电话不能为空", groups = {Insert.class, Update.class})
+ @Length(max = 11, message = "联系电话不能超过11位", groups = {Insert.class, Update.class})
+ private String receivePhone;
+
+ /**
+ * 收货人地址
+ */
+ @ApiModelProperty(value = "收货人地址")
+ @Excel(name = "收货人地址")
+ @NotBlank(message = "收货人地址不能为空", groups = {Insert.class, Update.class})
+ @Length(max = 50, message = "收货人地址不能超过50位", groups = {Insert.class, Update.class})
+ private String receiveAddress;
+
+ /**
+ * 区域编码
+ */
+ @ApiModelProperty(value = "区域编码")
+ @Excel(name = "区域编码")
+ @Length(max = 20, message = "区域编码不能超过20位", groups = {Insert.class, Update.class})
+ private String areaCode;
+
+ /**
+ * 区域集合
+ */
+ List sysAreaVOList;
+
+ /**
+ * 省名称
+ */
+ private String provinceName;
+
+ /**
+ * 省区域编码
+ */
+ private String provinceCode;
+
+ /**
+ * 市名称
+ */
+ private String cityName;
+
+ /**
+ * 市区域编码
+ */
+ private String cityCode;
+
+ /**
+ * 区域名称
+ */
+ private String regionName;
+
+ /**
+ * 区区域编码
+ */
+ private String regionCode;
+
+ /**
+ * 街道名称
+ */
+ private String streetName;
+
+ /**
+ * 街道区域编码
+ */
+ private String streetCode;
+
+ /**
+ * 区域名称
+ */
+ private String areaName;
+
+ /**
+ * 默认收货地址标识,0:否,1:是
+ */
+ private Integer defaultAddressFlag;
+}
diff --git a/xinelu-nurse-manage/src/main/resources/mapper/manage/goodsOrderDetails/GoodsOrderDetailsMapper.xml b/xinelu-nurse-manage/src/main/resources/mapper/manage/goodsOrderDetails/GoodsOrderDetailsMapper.xml
new file mode 100644
index 0000000..8d6f540
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/resources/mapper/manage/goodsOrderDetails/GoodsOrderDetailsMapper.xml
@@ -0,0 +1,311 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id,
+ goods_order_id,
+ order_no,
+ goods_name,
+ goods_count,
+ goods_attribute_name,
+ goods_attribute_content,
+ goods_price,
+ total_price,
+ discount_price,
+ transport_price,
+ give_integral,
+ del_flag,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+ coupon_id,
+ integral_deduction_count,
+ integral_deduction_price,
+ couponTitle,
+ integral_exchange_sill,
+ integral_exchange_count
+ from goods_order_details
+
+
+
+
+
+
+
+ insert into goods_order_details
+
+ goods_order_id,
+
+ goods_attribute_id,
+
+ goods_attribute_details_id,
+
+ order_no,
+
+ goods_name,
+
+ goods_count,
+
+ goods_attribute_name,
+
+ goods_attribute_content,
+
+ goods_price,
+
+ total_price,
+
+ discount_price,
+
+ transport_price,
+
+ give_integral,
+
+ del_flag,
+
+ create_by,
+
+ create_time,
+
+ update_by,
+
+ update_time,
+
+ coupon_id,
+
+ integral_deduction_count,
+
+ integral_deduction_price,
+
+ coupon_title,
+
+ integral_exchange_sill,
+
+ integral_exchange_count,
+
+
+
+ #{goodsOrderId},
+
+ #{goodsAttributeId},
+
+ #{goodsAttributeDetailsId},
+
+ #{orderNo},
+
+ #{goodsName},
+
+ #{goodsCount},
+
+ #{goodsAttributeName},
+
+ #{goodsAttributeContent},
+
+ #{goodsPrice},
+
+ #{totalPrice},
+
+ #{discountPrice},
+
+ #{transportPrice},
+
+ #{giveIntegral},
+
+ #{delFlag},
+
+ #{createBy},
+
+ #{createTime},
+
+ #{updateBy},
+
+ #{updateTime},
+
+ #{couponId},
+
+ #{integralDeductionCount},
+
+ #{integralDeductionPrice},
+
+ #{couponTitle},
+
+ #{integralExchangeSill},
+
+ #{integralExchangeCount},
+
+
+
+
+
+ update goods_order_details
+
+ goods_order_id =
+ #{goodsOrderId},
+
+ order_no =
+ #{orderNo},
+
+ goods_name =
+ #{goodsName},
+
+ goods_count =
+ #{goodsCount},
+
+ goods_attribute_name =
+ #{goodsAttributeName},
+
+ goods_attribute_content =
+ #{goodsAttributeContent},
+
+ goods_price =
+ #{goodsPrice},
+
+ total_price =
+ #{totalPrice},
+
+ discount_price =
+ #{discountPrice},
+
+ transport_price =
+ #{transportPrice},
+
+ give_integral =
+ #{giveIntegral},
+
+ del_flag =
+ #{delFlag},
+
+ create_by =
+ #{createBy},
+
+ create_time =
+ #{createTime},
+
+ update_by =
+ #{updateBy},
+
+ update_time =
+ #{updateTime},
+
+ coupon_id =
+ #{couponId},
+
+ integral_deduction_count =
+ #{integralDeductionCount},
+
+ integral_deduction_price =
+ #{integralDeductionPrice},
+
+ coupon_title =
+ #{couponTitle},
+
+ integral_exchange_sill =
+ #{integralExchangeSill},
+
+ integral_exchange_count =
+ #{integralExchangeCount},
+
+
+ where id = #{id}
+
+
+
+ delete
+ from goods_order_details
+ where id = #{id}
+
+
+
+ delete from goods_order_details where id in
+
+ #{id}
+
+
+
+
+
diff --git a/xinelu-nurse-manage/src/main/resources/mapper/manage/patientcouponreceive/PatientCouponReceiveMapper.xml b/xinelu-nurse-manage/src/main/resources/mapper/manage/patientcouponreceive/PatientCouponReceiveMapper.xml
new file mode 100644
index 0000000..96b3072
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/resources/mapper/manage/patientcouponreceive/PatientCouponReceiveMapper.xml
@@ -0,0 +1,366 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id,
+ patient_id,
+ coupon_id,
+ receive_source,
+ expiration_start_time,
+ expiration_end_time,
+ receive_time,
+ use_status,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+ coupon_title,
+ coupon_price,
+ coupon_consume_price,
+ coupon_description,
+ coupon_reduction_days
+ from patient_coupon_receive
+
+
+
+
+
+
+
+ insert into patient_coupon_receive
+
+ patient_id,
+
+ coupon_id,
+
+ receive_source,
+
+ expiration_start_time,
+
+ expiration_end_time,
+
+ receive_time,
+
+ use_status,
+
+ create_by,
+
+ create_time,
+
+ update_by,
+
+ update_time,
+
+ coupon_title,
+
+ coupon_price,
+
+ coupon_consume_price,
+
+ coupon_description,
+
+ coupon_reduction_days,
+
+
+
+ #{patientId},
+
+ #{couponId},
+
+ #{receiveSource},
+
+ #{expirationStartTime},
+
+ #{expirationEndTime},
+
+ #{receiveTime},
+
+ #{useStatus},
+
+ #{createBy},
+
+ #{createTime},
+
+ #{updateBy},
+
+ #{updateTime},
+
+ #{couponTitle},
+
+ #{couponPrice},
+
+ #{couponConsumePrice},
+
+ #{couponDescription},
+
+ #{couponReductionDays},
+
+
+
+
+
+ update patient_coupon_receive
+
+ patient_id =
+ #{patientId},
+
+ coupon_id =
+ #{couponId},
+
+ receive_source =
+ #{receiveSource},
+
+ expiration_start_time =
+ #{expirationStartTime},
+
+ expiration_end_time =
+ #{expirationEndTime},
+
+ receive_time =
+ #{receiveTime},
+
+ use_status =
+ #{useStatus},
+
+ create_by =
+ #{createBy},
+
+ create_time =
+ #{createTime},
+
+ update_by =
+ #{updateBy},
+
+ update_time =
+ #{updateTime},
+
+ coupon_title =
+ #{couponTitle},
+
+ coupon_price =
+ #{couponPrice},
+
+ coupon_consume_price =
+ #{couponConsumePrice},
+
+ coupon_description =
+ #{couponDescription},
+
+ coupon_reduction_days =
+ #{couponReductionDays},
+
+
+ where id = #{id}
+
+
+
+ delete
+ from patient_coupon_receive
+ where id = #{id}
+
+
+
+ delete from patient_coupon_receive where id in
+
+ #{id}
+
+
+
+
+ insert into patient_coupon_receive(
+ patient_id,
+ coupon_id,
+ receive_source,
+ expiration_start_time,
+ expiration_end_time,
+ receive_time,
+ use_status,
+ create_time,
+ coupon_title,
+ coupon_price,
+ coupon_consume_price,
+ coupon_description,
+ coupon_reduction_days
+ ) values
+
+ (
+ #{couponReceive.patientId},
+ #{couponReceive.couponId},
+ #{couponReceive.receiveSource},
+ #{couponReceive.expirationStartTime},
+ #{couponReceive.expirationEndTime},
+ #{couponReceive.receiveTime},
+ #{couponReceive.useStatus},
+ #{couponReceive.createTime},
+ #{couponReceive.couponTitle},
+ #{couponReceive.couponPrice},
+ #{couponReceive.couponConsumePrice},
+ #{couponReceive.couponDescription},
+ #{couponReceive.couponReductionDays}
+ )
+
+
+
+
+
+
+ update patient_coupon_receive set use_status = #{couponUseStatus}, update_time = now()
+ where id in
+
+ #{id}
+
+
+
+
+ update patient_coupon_receive set use_status = #{couponUseStatus}, update_time = now()
+
+ id in
+
+ #{id}
+
+
+
+
+
+
+
+ update patient_coupon_receive
+ set use_status = #{useStatus},
+ update_time = now()
+ where patient_id = #{patientId}
+ and coupon_id = #{couponId}
+ and use_status <> #{useStatus}
+
+
+
+
diff --git a/xinelu-nurse-manage/src/main/resources/mapper/manage/patientintegralchange/PatientIntegralChangeMapper.xml b/xinelu-nurse-manage/src/main/resources/mapper/manage/patientintegralchange/PatientIntegralChangeMapper.xml
new file mode 100644
index 0000000..b19ef66
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/resources/mapper/manage/patientintegralchange/PatientIntegralChangeMapper.xml
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id, patient_id, original_integral, change_integral, change_time, change_type, change_remark,change_integral_channel, create_by, create_time, update_by, update_time from patient_integral_change
+
+
+
+
+
+
+
+ insert into patient_integral_change
+
+ patient_id,
+
+ original_integral,
+
+ change_integral,
+
+ change_time,
+
+ change_type,
+
+ change_remark,
+
+ change_integral_channel,
+
+ create_by,
+
+ create_time,
+
+ update_by,
+
+ update_time,
+
+
+
+ #{patientId},
+
+ #{originalIntegral},
+
+ #{changeIntegral},
+
+ #{changeTime},
+
+ #{changeType},
+
+ #{changeRemark},
+
+ #{changeIntegralChannel},
+
+ #{createBy},
+
+ #{createTime},
+
+ #{updateBy},
+
+ #{updateTime},
+
+
+
+
+
+ update patient_integral_change
+
+ patient_id =
+ #{patientId},
+
+ original_integral =
+ #{originalIntegral},
+
+ change_integral =
+ #{changeIntegral},
+
+ change_time =
+ #{changeTime},
+
+ change_type =
+ #{changeType},
+
+ change_remark =
+ #{changeRemark},
+
+ change_integral_channel =
+ #{changeIntegralChannel},
+
+ create_by =
+ #{createBy},
+
+ create_time =
+ #{createTime},
+
+ update_by =
+ #{updateBy},
+
+ update_time =
+ #{updateTime},
+
+
+ where id = #{id}
+
+
+
+ delete from patient_integral_change where id = #{id}
+
+
+
+ delete from patient_integral_change where id in
+
+ #{id}
+
+
+
diff --git a/xinelu-nurse-manage/src/main/resources/mapper/manage/patientsignininfo/PatientSignInInfoMapper.xml b/xinelu-nurse-manage/src/main/resources/mapper/manage/patientsignininfo/PatientSignInInfoMapper.xml
new file mode 100644
index 0000000..ed49b89
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/resources/mapper/manage/patientsignininfo/PatientSignInInfoMapper.xml
@@ -0,0 +1,125 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id, patient_id, sign_in_time, sign_in_channel, create_by, create_time, update_by, update_time from patient_sign_in_info
+
+
+
+
+
+
+
+ insert into patient_sign_in_info
+
+ id,
+
+ patient_id,
+
+ sign_in_time,
+
+ sign_in_channel,
+
+ create_by,
+
+ create_time,
+
+ update_by,
+
+ update_time,
+
+
+
+ #{id},
+
+ #{patientId},
+
+ #{signInTime},
+
+ #{signInChannel},
+
+ #{createBy},
+
+ #{createTime},
+
+ #{updateBy},
+
+ #{updateTime},
+
+
+
+
+
+ update patient_sign_in_info
+
+ patient_id =
+ #{patientId},
+
+ sign_in_time =
+ #{signInTime},
+
+ sign_in_channel =
+ #{signInChannel},
+
+ create_by =
+ #{createBy},
+
+ create_time =
+ #{createTime},
+
+ update_by =
+ #{updateBy},
+
+ update_time =
+ #{updateTime},
+
+
+ where id = #{id}
+
+
+
+ delete from patient_sign_in_info where id = #{id}
+
+
+
+ delete from patient_sign_in_info where id in
+
+ #{id}
+
+
+
+
+
\ No newline at end of file
diff --git a/xinelu-nurse-manage/src/main/resources/mapper/manage/receiveAddressInfo/ReceiveAddressInfoMapper.xml b/xinelu-nurse-manage/src/main/resources/mapper/manage/receiveAddressInfo/ReceiveAddressInfoMapper.xml
new file mode 100644
index 0000000..4e1b39f
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/resources/mapper/manage/receiveAddressInfo/ReceiveAddressInfoMapper.xml
@@ -0,0 +1,200 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id,
+ patient_id,
+ openid,
+ unionid,
+ receive_name,
+ receive_phone,
+ receive_address,
+ area_code,
+ create_by,
+ create_time,
+ update_by,
+ update_time,
+ default_address_flag
+ from receive_address_info
+
+
+
+
+
+
+
+ insert into receive_address_info
+
+ id,
+
+ patient_id,
+
+ openid,
+
+ unionid,
+
+ receive_name,
+
+ receive_phone,
+
+ receive_address,
+
+ area_code,
+
+ create_by,
+
+ create_time,
+
+ update_by,
+
+ update_time,
+
+ default_address_flag,
+
+
+
+ #{id},
+
+ #{patientId},
+
+ #{openid},
+
+ #{unionid},
+
+ #{receiveName},
+
+ #{receivePhone},
+
+ #{receiveAddress},
+
+ #{areaCode},
+
+ #{createBy},
+
+ #{createTime},
+
+ #{updateBy},
+
+ #{updateTime},
+
+ #{defaultAddressFlag},
+
+
+
+
+
+ update receive_address_info
+
+ patient_id =
+ #{patientId},
+
+ openid =
+ #{openid},
+
+ unionid =
+ #{unionid},
+
+ receive_name =
+ #{receiveName},
+
+ receive_phone =
+ #{receivePhone},
+
+ receive_address =
+ #{receiveAddress},
+
+ area_code =
+ #{areaCode},
+
+ create_by =
+ #{createBy},
+
+ create_time =
+ #{createTime},
+
+ update_by =
+ #{updateBy},
+
+ update_time =
+ #{updateTime},
+
+ default_address_flag =
+ #{defaultAddressFlag},
+
+
+ where id = #{id}
+
+
+
+ delete
+ from receive_address_info
+ where id = #{id}
+
+
+
+ delete from receive_address_info where id in
+
+ #{id}
+
+
+
+
+
diff --git a/xinelu-nurse-manage/src/main/resources/mapper/manage/subscribemessagerecord/SubscribeMessageRecordMapper.xml b/xinelu-nurse-manage/src/main/resources/mapper/manage/subscribemessagerecord/SubscribeMessageRecordMapper.xml
new file mode 100644
index 0000000..27bc353
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/resources/mapper/manage/subscribemessagerecord/SubscribeMessageRecordMapper.xml
@@ -0,0 +1,307 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ select id,
+ patient_id,
+ unionid,
+ openid,
+ template_id,
+ message_type,
+ subscribe_count,
+ subscribe_time,
+ applet_id,
+ subscribe_status,
+ create_by,
+ create_time,
+ update_by,
+ update_time
+ from subscribe_message_record
+
+
+
+
+
+
+
+ insert into subscribe_message_record
+
+ patient_id,
+
+ unionid,
+
+ openid,
+
+ template_id,
+
+ message_type,
+
+ subscribe_count,
+
+ subscribe_time,
+
+ applet_id,
+
+ subscribe_status,
+
+ create_by,
+
+ create_time,
+
+ update_by,
+
+ update_time,
+
+
+
+ #{patientId},
+
+ #{unionid},
+
+ #{openid},
+
+ #{templateId},
+
+ #{messageType},
+
+ #{subscribeCount},
+
+ #{subscribeTime},
+
+ #{appletId},
+
+ #{subscribeStatus},
+
+ #{createBy},
+
+ #{createTime},
+
+ #{updateBy},
+
+ #{updateTime},
+
+
+
+
+
+ update subscribe_message_record
+
+ patient_id =
+ #{patientId},
+
+ unionid =
+ #{unionid},
+
+ openid =
+ #{openid},
+
+ template_id =
+ #{templateId},
+
+ message_type =
+ #{messageType},
+
+ subscribe_count =
+ #{subscribeCount},
+
+ subscribe_time =
+ #{subscribeTime},
+
+ applet_id =
+ #{appletId},
+
+ subscribe_status =
+ #{subscribeStatus},
+
+ create_by =
+ #{createBy},
+
+ create_time =
+ #{createTime},
+
+ update_by =
+ #{updateBy},
+
+ update_time =
+ #{updateTime},
+
+
+ where id = #{id}
+
+
+
+ delete
+ from subscribe_message_record
+ where id = #{id}
+
+
+
+ delete from subscribe_message_record where id in
+
+ #{id}
+
+
+
+
+
+
+
+
+
+
+
+ insert into subscribe_message_record(
+ patient_id,
+ unionid,
+ openid,
+ template_id,
+ message_type,
+ subscribe_count,
+ subscribe_time,
+ applet_id,
+ subscribe_status,
+ create_by,
+ create_time,
+ update_by,
+ update_time
+ ) values
+
+ (
+ #{subscribeMessageRecordList.patientId},
+ #{subscribeMessageRecordList.unionid},
+ #{subscribeMessageRecordList.openid},
+ #{subscribeMessageRecordList.templateId},
+ #{subscribeMessageRecordList.messageType},
+ #{subscribeMessageRecordList.subscribeCount},
+ #{subscribeMessageRecordList.subscribeTime},
+ #{subscribeMessageRecordList.appletId},
+ #{subscribeMessageRecordList.subscribeStatus},
+ #{subscribeMessageRecordList.createBy},
+ #{subscribeMessageRecordList.createTime},
+ #{subscribeMessageRecordList.updateBy},
+ #{subscribeMessageRecordList.updateTime}
+ )
+
+
+
+
+ update subscribe_message_record
+ set patient_id = #{patientId}, subscribe_status = #{subscribeStatus}, update_time = now()
+ where openid = #{openId} and template_id = #{templateId}
+
+
diff --git a/xinelu-nurse-manage/src/main/resources/mapper/manage/subscribemessagesendrecord/SubscribeMessageSendRecordMapper.xml b/xinelu-nurse-manage/src/main/resources/mapper/manage/subscribemessagesendrecord/SubscribeMessageSendRecordMapper.xml
new file mode 100644
index 0000000..25ec845
--- /dev/null
+++ b/xinelu-nurse-manage/src/main/resources/mapper/manage/subscribemessagesendrecord/SubscribeMessageSendRecordMapper.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+ insert into subscribe_message_send_record(
+ openid,
+ applet_id,
+ subscribe_time,
+ template_id,
+ msg_id,
+ message_type,
+ error_code,
+ error_status,
+ create_time
+ ) values
+
+ (
+ #{sendRecord.openid},
+ #{sendRecord.appletId},
+ #{sendRecord.subscribeTime},
+ #{sendRecord.templateId},
+ #{sendRecord.msgId},
+ #{sendRecord.messageType},
+ #{sendRecord.errorCode},
+ #{sendRecord.errorStatus},
+ #{sendRecord.createTime}
+ )
+
+
+
\ No newline at end of file