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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