From 898dc1600c52b29b2752c05de48226bc1c7dc85e Mon Sep 17 00:00:00 2001
From: "382696293@qq.com" <382696293@qq.com>
Date: Fri, 29 Mar 2024 13:46:40 +0800
Subject: [PATCH] =?UTF-8?q?=E6=95=B0=E4=BA=91=E4=BC=9A=E5=91=98=E6=B3=A8?=
=?UTF-8?q?=E5=86=8C=E7=A7=AF=E5=88=86=E6=93=8D=E4=BD=9C=E5=AF=B9=E6=8E=A5?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.../common/core/constant/ShuYunConstants.java | 12 ++++
.../core/domain/shuyun/ShuYunMember.java | 3 +-
.../flossom/common/core/utils/DateUtils.java | 2 +
flossom-modules/flossom-mini-program/pom.xml | 25 +++++++
.../controller/WxUserIntegralController.java | 10 ++-
.../service/IWxUserIntegralService.java | 6 +-
.../impl/WxUserIntegralServiceImpl.java | 57 +++++++++++++++-
.../service/impl/WxUserMemberServiceImpl.java | 62 ++++++++++++++----
.../resources/lib/open-platform-sdk-1.0.1.jar | Bin 0 -> 15680 bytes
9 files changed, 153 insertions(+), 24 deletions(-)
create mode 100644 flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/constant/ShuYunConstants.java
create mode 100644 flossom-modules/flossom-mini-program/src/main/resources/lib/open-platform-sdk-1.0.1.jar
diff --git a/flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/constant/ShuYunConstants.java b/flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/constant/ShuYunConstants.java
new file mode 100644
index 0000000..2807d61
--- /dev/null
+++ b/flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/constant/ShuYunConstants.java
@@ -0,0 +1,12 @@
+package com.flossom.common.core.constant;
+
+/**
+ * 数云 常量
+ */
+public class ShuYunConstants {
+ /**
+ * 平台内系统用户的唯一标志
+ */
+ public static final String POINT_SERIAL_NUMBER_PREFIX = "hz_serial_number-";
+
+}
diff --git a/flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/domain/shuyun/ShuYunMember.java b/flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/domain/shuyun/ShuYunMember.java
index 48621af..f3dacfe 100644
--- a/flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/domain/shuyun/ShuYunMember.java
+++ b/flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/domain/shuyun/ShuYunMember.java
@@ -89,12 +89,13 @@ public class ShuYunMember {
* @param name
* @param mobile
*/
- public ShuYunMember(String id, String platCode, String shopId, String name, String mobile) {
+ public ShuYunMember(String id, String platCode, String shopId, String name, String mobile, String created) {
this.id = id;
this.platCode = platCode;
this.shopId = shopId;
this.name = name;
this.mobile = mobile;
+ this.created = created;
}
/**
diff --git a/flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/utils/DateUtils.java b/flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/utils/DateUtils.java
index f0c8ed3..1794248 100644
--- a/flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/utils/DateUtils.java
+++ b/flossom-common/flossom-common-core/src/main/java/com/flossom/common/core/utils/DateUtils.java
@@ -26,6 +26,8 @@ public class DateUtils extends org.apache.commons.lang3.time.DateUtils
public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
+ public static String YYYYMMDDHHMMSSS = "yyyyMMddHHmmssSSS";
+
public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
private static String[] parsePatterns = {
diff --git a/flossom-modules/flossom-mini-program/pom.xml b/flossom-modules/flossom-mini-program/pom.xml
index 4811904..3b54448 100644
--- a/flossom-modules/flossom-mini-program/pom.xml
+++ b/flossom-modules/flossom-mini-program/pom.xml
@@ -101,6 +101,20 @@
spring-boot-starter-test
test
+
+
+
+ com.shuyun.open
+ open-platform-sdk
+ 1.0.1
+ system
+ ${project.basedir}/src/main/resources/lib/open-platform-sdk-1.0.1.jar
+
+
+
+ cn.hutool
+ hutool-core
+
@@ -109,6 +123,17 @@
org.springframework.boot
spring-boot-maven-plugin
+
+
+ true
+
+
+
+
+ repackage
+
+
+
diff --git a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/controller/WxUserIntegralController.java b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/controller/WxUserIntegralController.java
index 364bcb0..956983c 100644
--- a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/controller/WxUserIntegralController.java
+++ b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/controller/WxUserIntegralController.java
@@ -1,13 +1,12 @@
package com.flossom.miniProgram.controller;
-import com.flossom.common.core.domain.entity.WxUserIntegralLog;
import com.flossom.common.core.web.controller.BaseController;
import com.flossom.common.core.web.page.TableDataInfo;
import com.flossom.miniProgram.service.IWxUserIntegralService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
-import java.util.List;
+import javax.validation.constraints.NotNull;
/**
* 微信用户积分 Controller
@@ -29,10 +28,9 @@ public class WxUserIntegralController extends BaseController {
* @return
*/
@GetMapping("/obtainUserIntegral")
- public TableDataInfo obtainUserIntegral() {
- startPage();
- List list = wxUserIntegralLogService.obtainUserIntegral();
- return getDataTable(list);
+ public TableDataInfo obtainUserIntegral(@NotNull(message = "pageSize 不能为空") @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
+ @NotNull(message = "pageNum 不能为空") @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum) {
+ return wxUserIntegralLogService.obtainUserIntegral(pageNum, pageSize);
}
}
diff --git a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/service/IWxUserIntegralService.java b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/service/IWxUserIntegralService.java
index 0cebe02..a4cc2a0 100644
--- a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/service/IWxUserIntegralService.java
+++ b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/service/IWxUserIntegralService.java
@@ -1,11 +1,9 @@
package com.flossom.miniProgram.service;
-import com.flossom.common.core.domain.entity.WxUserIntegralLog;
-
-import java.util.List;
+import com.flossom.common.core.web.page.TableDataInfo;
public interface IWxUserIntegralService {
- List obtainUserIntegral();
+ TableDataInfo obtainUserIntegral(Integer pageNum, Integer pageSize);
}
diff --git a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/service/impl/WxUserIntegralServiceImpl.java b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/service/impl/WxUserIntegralServiceImpl.java
index fd38a59..c545cd5 100644
--- a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/service/impl/WxUserIntegralServiceImpl.java
+++ b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/service/impl/WxUserIntegralServiceImpl.java
@@ -1,25 +1,78 @@
package com.flossom.miniProgram.service.impl;
+import com.flossom.common.core.constant.HttpStatus;
import com.flossom.common.core.domain.entity.WxUserIntegralLog;
import com.flossom.common.core.domain.entity.WxUserMember;
+import com.flossom.common.core.domain.shuyun.ShuYunPageReq;
+import com.flossom.common.core.domain.shuyun.ShuYunPageUtil;
+import com.flossom.common.core.domain.shuyun.ShuYunPointChangeLog;
+import com.flossom.common.core.enums.IntegralChangeTypeEnum;
+import com.flossom.common.core.exception.ServiceException;
import com.flossom.common.core.mapper.WxUserIntegralLogMapper;
+import com.flossom.common.core.utils.DateUtils;
+import com.flossom.common.core.web.page.TableDataInfo;
import com.flossom.common.security.utils.SecurityUtils;
import com.flossom.miniProgram.service.IWxUserIntegralService;
+import com.flossom.miniProgram.utils.shuyun.ShuYunApiUtils;
+import com.flossom.miniProgram.utils.shuyun.ShuYunConfig;
+import com.github.pagehelper.PageInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
+import java.util.ArrayList;
import java.util.List;
@Service
public class WxUserIntegralServiceImpl implements IWxUserIntegralService {
+ protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+
@Autowired
private WxUserIntegralLogMapper wxUserIntegralLogMapper;
+ @Autowired
+ private ShuYunConfig shuYunConfig;
+
@Override
- public List obtainUserIntegral() {
+ public TableDataInfo obtainUserIntegral(Integer pageNum, Integer pageSize) {
+ /**
+ * TODO:积分操作记录由数云提供(已完成)
+ */
WxUserMember wxUserMember = SecurityUtils.getLoginUser().getWxUserMember();
- return wxUserIntegralLogMapper.obtainUserIntegral(wxUserMember.getId());
+ ShuYunPageReq req = new ShuYunPageReq(SecurityUtils.getLoginUser().getWxUserMember().getUnionid(), shuYunConfig.getPlatCode(), shuYunConfig.getShopId(),
+ String.valueOf(pageSize), String.valueOf(pageNum));
+ ShuYunPageUtil pointChangeLogShuYunPageUtil = ShuYunApiUtils.pointChangeLogSearch(req);
+ if (pointChangeLogShuYunPageUtil == null) {
+ logger.error("积分查询失败,用户id:{},用户名:{},用户unionid:{},分页参数:pageNum={},pageSize={}",
+ wxUserMember.getId(), wxUserMember.getNickname(), wxUserMember.getUnionid(), pageNum, pageSize);
+ throw new ServiceException("积分查询失败");
+ }
+ List userIntegralLogList = new ArrayList<>();
+ WxUserIntegralLog userIntegralLog = null;
+ if (pointChangeLogShuYunPageUtil.getList() != null && pointChangeLogShuYunPageUtil.getList().size() > 0) {
+ for (ShuYunPointChangeLog shuYunPointChangeLog : pointChangeLogShuYunPageUtil.getList()) {
+ userIntegralLog = new WxUserIntegralLog();
+ userIntegralLog.setRemarkContent(shuYunPointChangeLog.getDesc());
+ // 变更积分
+ if (Integer.valueOf(shuYunPointChangeLog.getChangePoint()) > 0) {
+ userIntegralLog.setSource(IntegralChangeTypeEnum.INCREASE.getCode());
+ } else {
+ userIntegralLog.setSource(IntegralChangeTypeEnum.REDUCE.getCode());
+ }
+ userIntegralLog.setFloatScore(Math.abs(Long.valueOf(shuYunPointChangeLog.getChangePoint())));
+ // 变更时间
+ userIntegralLog.setCreateTime(DateUtils.parseDate(shuYunPointChangeLog.getCreated()));
+ }
+ userIntegralLogList.add(userIntegralLog);
+ }
+ TableDataInfo rspData = new TableDataInfo();
+ rspData.setCode(HttpStatus.SUCCESS);
+ rspData.setRows(userIntegralLogList);
+ rspData.setMsg("查询成功");
+ rspData.setTotal(pointChangeLogShuYunPageUtil.getTotals());
+ return rspData;
}
}
diff --git a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/service/impl/WxUserMemberServiceImpl.java b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/service/impl/WxUserMemberServiceImpl.java
index 109d00f..0dd744c 100644
--- a/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/service/impl/WxUserMemberServiceImpl.java
+++ b/flossom-modules/flossom-mini-program/src/main/java/com/flossom/miniProgram/service/impl/WxUserMemberServiceImpl.java
@@ -1,13 +1,18 @@
package com.flossom.miniProgram.service.impl;
+import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.flossom.common.core.constant.CacheConstants;
import com.flossom.common.core.constant.HttpStatus;
+import com.flossom.common.core.constant.ShuYunConstants;
import com.flossom.common.core.constant.UserConstants;
import com.flossom.common.core.domain.R;
import com.flossom.common.core.domain.entity.*;
+import com.flossom.common.core.domain.shuyun.ShuYunMember;
+import com.flossom.common.core.domain.shuyun.ShuYunPointChange;
import com.flossom.common.core.enums.IntegralChangeTypeEnum;
import com.flossom.common.core.enums.MessageTypeEnum;
+import com.flossom.common.core.enums.ShuYunPointSourceEnum;
import com.flossom.common.core.enums.WxUserIntegralMessageTypeEnum;
import com.flossom.common.core.exception.ServiceException;
import com.flossom.common.core.mapper.*;
@@ -18,6 +23,8 @@ import com.flossom.common.security.utils.SecurityUtils;
import com.flossom.miniProgram.domain.vo.*;
import com.flossom.miniProgram.service.IWxUserMemberService;
import com.flossom.miniProgram.utils.MiniProgramUtils;
+import com.flossom.miniProgram.utils.shuyun.ShuYunApiUtils;
+import com.flossom.miniProgram.utils.shuyun.ShuYunConfig;
import com.flossom.system.api.RemoteAuthService;
import com.flossom.system.api.model.LoginUser;
import org.slf4j.Logger;
@@ -28,6 +35,10 @@ import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.TemporalAdjusters;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@@ -61,6 +72,9 @@ public class WxUserMemberServiceImpl implements IWxUserMemberService {
@Autowired
private WxUserIntegralLogMapper wxUserIntegralLogMapper;
+ @Autowired
+ private ShuYunConfig shuYunConfig;
+
@Override
@Transactional
@@ -176,8 +190,11 @@ public class WxUserMemberServiceImpl implements IWxUserMemberService {
}
/**
- * TODO: 新用户注册,需要对接数云,将用户信息传给数云
+ * TODO: 1、新用户注册,需要对接数云,将用户信息传给数云(已完成,待添加操作日志)
*/
+ WxUserMember wxUserMember = wxUserMemberMapper.selectWxUserMemberById(SecurityUtils.getLoginUser().getWxUserMember().getId());
+ ShuYunApiUtils.registerMember(new ShuYunMember(wxUserMember.getUnionid(), shuYunConfig.getPlatCode(), shuYunConfig.getShopId(),
+ "用户" + wxUserMember.getId(), wxUserMember.getMobile(), DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, wxUserMember.getCreateTime())));
return wxCode2PhoneRet.getPhoneInfo().getPhoneNumber();
}
@@ -189,15 +206,13 @@ public class WxUserMemberServiceImpl implements IWxUserMemberService {
if (wxUserMember == null) {
throw new ServiceException("用户不存在");
}
- int floatScore = 0;
+ List integralGlobalList = integralGlobalMapper.selectIntegralGlobalList(new IntegralGlobal());
+ IntegralGlobal integralGlobal = integralGlobalList.get(0);
Boolean isCompleteInformation = false;
if (wxUserMember.getIsCompleteInformation() == null || wxUserMember.getIsCompleteInformation() == 0) {
isCompleteInformation = true;
// 修改完善状态
wxUserMember.setIsCompleteInformation(1);
- List integralGlobalList = integralGlobalMapper.selectIntegralGlobalList(new IntegralGlobal());
- IntegralGlobal integralGlobal = integralGlobalList.get(0);
- floatScore = integralGlobal.getIntegral().intValue();
wxUserMember.setCredit(wxUserMember.getCredit() + integralGlobal.getIntegral().intValue());
// 保存积分详情
@@ -212,7 +227,7 @@ public class WxUserMemberServiceImpl implements IWxUserMemberService {
wxUserIntegralLog.setCreateTime(DateUtils.getNowDate());
wxUserIntegralLogMapper.insertWxUserIntegralLog(wxUserIntegralLog);
- // 2.4、用户注册成功发送消息
+ // 2.4、用户升级会员成功发送消息
WxScriptMessage wxScriptMessage = wxScriptMessageMapper.selectOneByMessageType(MessageTypeEnum.COMPLETE_USER_INFORMATION.getCode());
if (wxScriptMessage != null) {
WxUserScriptLog wxUserScriptLog = new WxUserScriptLog();
@@ -229,17 +244,32 @@ public class WxUserMemberServiceImpl implements IWxUserMemberService {
wxUserScriptLog.setUpdateBy(null);
wxUserScriptLogMapper.insertWxUserScriptLog(wxUserScriptLog);
}
-
- // TODO: 首次完善,增加加分 (对接数云未完成)
}
BeanUtils.copyProperties(userMemberUpdateVo, wxUserMember);
wxUserMember.setUpdateTime(DateUtils.getNowDate());
wxUserMemberMapper.updateWxUserMember(wxUserMember);
- // 刷新用户信息
+ // 首次完善用户信息,增加积分,刷新了缓存
LoginUserVo loginUserVo = refreshWxUserInfo();
+ // TODO: 2、更新用户信息,同步到数云 (已完成,未保存记录)
+ // 1、完善用户信息
+ ShuYunMember member = new ShuYunMember();
+ member.setId(wxUserMember.getUnionid());
+ member.setPlatCode(shuYunConfig.getPlatCode());
+ member.setShopId(shuYunConfig.getShopId());
+ member.setName(userMemberUpdateVo.getNickname());
+ member.setBirthday(DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, userMemberUpdateVo.getBirthday()));
+ ShuYunApiUtils.modifyMember(member);
+
if (isCompleteInformation) {
- loginUserVo.setIntegralText("您已完善个人信息,获得" + floatScore + "积分");
+ loginUserVo.setIntegralText("您已完善个人信息,获得" + integralGlobal.getIntegral().intValue() + "积分");
+ // TODO: 3、首次完善,通知数云增加积分 (已完成,未保存记录)
+ // 2、完善会员信息增加积分
+ String sequence = ShuYunConstants.POINT_SERIAL_NUMBER_PREFIX + LocalDateTime.now().format(DateTimeFormatter.ofPattern(DateUtils.YYYYMMDDHHMMSSS)) + RandomUtil.randomInt(1000, 9999);
+ ShuYunPointChange shuYunPointChange = new ShuYunPointChange(wxUserMember.getUnionid(), shuYunConfig.getPlatCode(), shuYunConfig.getShopId(),
+ sequence, ShuYunPointSourceEnum.OTHER.getSource(), integralGlobal.getIntegral().intValue(),
+ LocalDateTime.now().format(DateTimeFormatter.ofPattern(DateUtils.YYYY_MM_DD_HH_MM_SS)), "首次完善用户信息");
+ ShuYunApiUtils.pointChange(shuYunPointChange);
}
return loginUserVo;
}
@@ -250,7 +280,7 @@ public class WxUserMemberServiceImpl implements IWxUserMemberService {
* @return
*/
@Override
- @Transactional(propagation = Propagation.SUPPORTS)
+ @Transactional(propagation = Propagation.NOT_SUPPORTED)
public LoginUserVo refreshWxUserInfo() {
LoginUser loginUser = SecurityUtils.getLoginUser();
@@ -266,6 +296,16 @@ public class WxUserMemberServiceImpl implements IWxUserMemberService {
BeanUtils.copyProperties(wxUserMember, loginUserVo);
loginUserVo.setToken(null);
loginUserVo.setIntegralText(null);
+ // TODO:调用数云接口获取最新的积分值(已完成,未保存操作记录)
+ ShuYunMember shuYunMember = ShuYunApiUtils.queryMember(wxUserMember.getUnionid(), shuYunConfig.getPlatCode(), shuYunConfig.getShopId());
+ loginUserVo.setCredit(Integer.valueOf(shuYunMember.getPoint()));
+ // TODO: 调用数云接口获取即将过期的积分值(未完成。。。。)
+ LocalDateTime now = LocalDateTime.now();
+ String startTime = now.plusHours(1).format(DateTimeFormatter.ofPattern(DateUtils.YYYY_MM_DD_HH_MM_SS));
+ String endTime = now.with(TemporalAdjusters.lastDayOfYear()).with(LocalTime.MAX).format(DateTimeFormatter.ofPattern(DateUtils.YYYY_MM_DD_HH_MM_SS));
+ // tenant 租户名称 数云说写死
+ Integer expireCredit = ShuYunApiUtils.pointWillDueSearch("zzsstest", wxUserMember.getUnionid(), "100000184001", "RELATIVE", startTime, endTime);
+ loginUserVo.setExpireCredit(expireCredit);
// 刷新缓存信息
String userKey = CacheConstants.LOGIN_TOKEN_KEY + loginUser.getToken();
diff --git a/flossom-modules/flossom-mini-program/src/main/resources/lib/open-platform-sdk-1.0.1.jar b/flossom-modules/flossom-mini-program/src/main/resources/lib/open-platform-sdk-1.0.1.jar
new file mode 100644
index 0000000000000000000000000000000000000000..45e534ee852ef4396298de5e6782ea85fc9ae00d
GIT binary patch
literal 15680
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