二维码
This commit is contained in:
@ -94,6 +94,19 @@
|
||||
<artifactId>yudao-spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 二维码 -->
|
||||
<dependency>
|
||||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>core</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.zxing</groupId>
|
||||
<artifactId>javase</artifactId>
|
||||
<version>3.4.1</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
@ -75,4 +75,10 @@ public class BusinessRespVO {
|
||||
private BigDecimal reduce;
|
||||
|
||||
private String time;
|
||||
|
||||
private BigDecimal turnoverCompare;
|
||||
|
||||
private int orderSumCompare;
|
||||
|
||||
private BigDecimal priceAvgCompare;
|
||||
}
|
@ -173,6 +173,27 @@ public class AppStoreController {
|
||||
return JsonUtils.toJsonString(StoreResult.success(null));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@PostMapping("/mgcr/order/payByCodeOrder")
|
||||
@Operation(summary = "添加二维码订单")
|
||||
public String payByCodeOrder(@RequestBody StoreOrderDto dto) {
|
||||
|
||||
String s = orderService.cardPay(dto);
|
||||
|
||||
if("true".equals(s)){
|
||||
return JsonUtils.toJsonString(StoreResult.success(null));
|
||||
} else if ("false".equals(s)) {
|
||||
return JsonUtils.toJsonString(StoreResult.fail("余额不足"));
|
||||
}else {
|
||||
return JsonUtils.toJsonString(StoreResult.fail(s));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public String reverseHexAndConvert(String hexStr) {
|
||||
// 将十六进制字符串反转,每两位一组
|
||||
StringBuilder reversedHex = new StringBuilder();
|
||||
@ -191,4 +212,9 @@ public class AppStoreController {
|
||||
|
||||
return decimalStr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -6,4 +6,6 @@ import lombok.Data;
|
||||
public class StoreOrderDto extends StoreSaleGoodsDto{
|
||||
|
||||
private String cardNumber;
|
||||
|
||||
private String jwt;
|
||||
}
|
||||
|
@ -151,5 +151,11 @@ public class AppMemberUserController {
|
||||
public CommonResult<Map<String,Object>> getInfoByCard(String cardId,Long mobile){
|
||||
return success(userService.getInfoByCard(cardId,mobile));
|
||||
}
|
||||
|
||||
@GetMapping("/getQRCode")
|
||||
@Operation(summary = "获取消费二维码")
|
||||
public CommonResult<String> getQRCode(){
|
||||
return success(userService.getQRCode());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,60 +104,63 @@ public class BusinessServiceImpl implements BusinessService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized void updateStatistics(StatisticsVo vo) {
|
||||
// 获取今天的开始时间
|
||||
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
|
||||
// 获取今天的结束时间 (23:59:59.999)
|
||||
LocalDateTime endOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
|
||||
public void updateStatistics(StatisticsVo vo) {
|
||||
synchronized(vo.getCarteenId()){
|
||||
// 获取今天的开始时间
|
||||
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
|
||||
// 获取今天的结束时间 (23:59:59.999)
|
||||
LocalDateTime endOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MAX);
|
||||
|
||||
List<BusinessDO> businessDOS = businessMapper.selectList(Wrappers.<BusinessDO>lambdaQuery()
|
||||
.between(BusinessDO::getCreateTime, startOfDay, endOfDay)
|
||||
.eq(BusinessDO::getCarteenId, vo.getCarteenId()));
|
||||
if (CollectionUtil.isNotEmpty(businessDOS)) {
|
||||
BusinessDO businessDO = businessDOS.get(0);
|
||||
List<BusinessDO> businessDOS = businessMapper.selectList(Wrappers.<BusinessDO>lambdaQuery()
|
||||
.between(BusinessDO::getCreateTime, startOfDay, endOfDay)
|
||||
.eq(BusinessDO::getCarteenId, vo.getCarteenId()));
|
||||
if (CollectionUtil.isNotEmpty(businessDOS)) {
|
||||
BusinessDO businessDO = businessDOS.get(0);
|
||||
|
||||
//重量
|
||||
if(ObjectUtil.isNotEmpty(vo.getOrderId())){
|
||||
List<OrderDetailDO> orderDetailDOS = orderDetailMapper.selectList(Wrappers.<OrderDetailDO>lambdaQuery().eq(OrderDetailDO::getOrderId, vo.getOrderId()));
|
||||
if (CollectionUtil.isNotEmpty(orderDetailDOS)) {
|
||||
BigDecimal reduce = orderDetailDOS.stream().map(OrderDetailDO::getWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
businessDO.setWeigh(businessDO.getWeigh().add(reduce));
|
||||
//重量
|
||||
if(ObjectUtil.isNotEmpty(vo.getOrderId())){
|
||||
List<OrderDetailDO> orderDetailDOS = orderDetailMapper.selectList(Wrappers.<OrderDetailDO>lambdaQuery().eq(OrderDetailDO::getOrderId, vo.getOrderId()));
|
||||
if (CollectionUtil.isNotEmpty(orderDetailDOS)) {
|
||||
BigDecimal reduce = orderDetailDOS.stream().map(OrderDetailDO::getWeight).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
businessDO.setWeigh(businessDO.getWeigh().add(reduce));
|
||||
}
|
||||
}
|
||||
}
|
||||
//订单数
|
||||
businessDO.setOrderSum(businessDO.getOrderSum() + vo.getOrder_sum());
|
||||
//订单数
|
||||
businessDO.setOrderSum(businessDO.getOrderSum() + vo.getOrder_sum());
|
||||
|
||||
//营业额
|
||||
if(ObjectUtil.isNotEmpty(vo.getTotalMoney())){
|
||||
businessDO.setTurnover(businessDO.getTurnover().add(vo.getTotalMoney()));
|
||||
}
|
||||
|
||||
//客单价
|
||||
if(businessDO.getOrderSum() != 0){
|
||||
businessDO.setPriceAvg(businessDO.getTurnover().divide(new BigDecimal(businessDO.getOrderSum()), 2, RoundingMode.HALF_UP));
|
||||
}
|
||||
|
||||
//减免金额
|
||||
if(ObjectUtil.isNotEmpty(vo.getReduceMoney())){
|
||||
businessDO.setReduce(businessDO.getReduce().add(vo.getReduceMoney()));
|
||||
}
|
||||
|
||||
//早中晚金额
|
||||
if(ObjectUtil.isNotEmpty(vo.getTime())){
|
||||
String timePeriod = TimePeriodEnum.getTimePeriod(vo.getTime());
|
||||
|
||||
if(timePeriod.equals(CostTypeEnum.MORNING.getCode())){
|
||||
businessDO.setBreakfast(businessDO.getBreakfast().add(vo.getTotalMoney()));
|
||||
}else if (timePeriod.equals(CostTypeEnum.NOON.getCode())){
|
||||
businessDO.setLunch(businessDO.getLunch().add(vo.getTotalMoney()));
|
||||
}else if (timePeriod.equals(CostTypeEnum.NIGHT.getCode())){
|
||||
businessDO.setDinner(businessDO.getDinner().add(vo.getTotalMoney()));
|
||||
//营业额
|
||||
if(ObjectUtil.isNotEmpty(vo.getTotalMoney())){
|
||||
businessDO.setTurnover(businessDO.getTurnover().add(vo.getTotalMoney()));
|
||||
}
|
||||
}
|
||||
|
||||
businessMapper.updateById(businessDO);
|
||||
//客单价
|
||||
if(businessDO.getOrderSum() != 0){
|
||||
businessDO.setPriceAvg(businessDO.getTurnover().divide(new BigDecimal(businessDO.getOrderSum()), 2, RoundingMode.HALF_UP));
|
||||
}
|
||||
|
||||
//减免金额
|
||||
if(ObjectUtil.isNotEmpty(vo.getReduceMoney())){
|
||||
businessDO.setReduce(businessDO.getReduce().add(vo.getReduceMoney()));
|
||||
}
|
||||
|
||||
//早中晚金额
|
||||
if(ObjectUtil.isNotEmpty(vo.getTime())){
|
||||
String timePeriod = TimePeriodEnum.getTimePeriod(vo.getTime());
|
||||
|
||||
if(timePeriod.equals(CostTypeEnum.MORNING.getCode())){
|
||||
businessDO.setBreakfast(businessDO.getBreakfast().add(vo.getTotalMoney()));
|
||||
}else if (timePeriod.equals(CostTypeEnum.NOON.getCode())){
|
||||
businessDO.setLunch(businessDO.getLunch().add(vo.getTotalMoney()));
|
||||
}else if (timePeriod.equals(CostTypeEnum.NIGHT.getCode())){
|
||||
businessDO.setDinner(businessDO.getDinner().add(vo.getTotalMoney()));
|
||||
}
|
||||
}
|
||||
|
||||
businessMapper.updateById(businessDO);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -188,25 +191,6 @@ public class BusinessServiceImpl implements BusinessService {
|
||||
// 获取当月的总天数
|
||||
int daysInMonth = yearMonth.lengthOfMonth();
|
||||
|
||||
// 定义一个格式化器,格式为 "dd"(两位数的日期)
|
||||
DateTimeFormatter dayFormatter = DateTimeFormatter.ofPattern("dd");
|
||||
|
||||
// 循环遍历该月的每一天
|
||||
for (int day = 1; day <= daysInMonth; day++) {
|
||||
if(map.get(day) == null){
|
||||
BusinessRespVO bean = new BusinessRespVO();
|
||||
bean.setTurnover(BigDecimal.ZERO).setOrderSum(0).setReduce(BigDecimal.ZERO).setWeigh(BigDecimal.ZERO)
|
||||
.setBreakfast(BigDecimal.ZERO).setLunch(BigDecimal.ZERO).setDinner(BigDecimal.ZERO)
|
||||
.setTime(String.valueOf(day));
|
||||
monthData.put(day,bean);
|
||||
}else {
|
||||
BusinessRespVO bean = BeanUtils.toBean(map.get(day), BusinessRespVO.class);
|
||||
bean.setTime(String.valueOf(day));
|
||||
monthData.put(day,bean);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//获取上一个月最后一天的数据
|
||||
// 获取上一个月的最后一天
|
||||
YearMonth previousMonth = yearMonth.minusMonths(1);
|
||||
@ -230,7 +214,27 @@ public class BusinessServiceImpl implements BusinessService {
|
||||
.setBreakfast(BigDecimal.ZERO).setLunch(BigDecimal.ZERO).setDinner(BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
businessDataVO.setOld(old);
|
||||
// 循环遍历该月的每一天
|
||||
for (int day = 1; day <= daysInMonth; day++) {
|
||||
BusinessRespVO bean = new BusinessRespVO();
|
||||
if(map.get(day) == null){
|
||||
bean.setTurnover(BigDecimal.ZERO).setOrderSum(0).setReduce(BigDecimal.ZERO).setWeigh(BigDecimal.ZERO)
|
||||
.setBreakfast(BigDecimal.ZERO).setLunch(BigDecimal.ZERO).setDinner(BigDecimal.ZERO)
|
||||
.setTime(String.valueOf(day));
|
||||
}else {
|
||||
bean = BeanUtils.toBean(map.get(day), BusinessRespVO.class);
|
||||
bean.setTime(String.valueOf(day));
|
||||
}
|
||||
//计算差额
|
||||
if(day == 1){
|
||||
compare(bean,old);
|
||||
}else {
|
||||
compare(bean,monthData.get(day-1));
|
||||
}
|
||||
monthData.put(day,bean);
|
||||
|
||||
}
|
||||
|
||||
businessDataVO.setBusinessList(new ArrayList<>(monthData.values()));
|
||||
return businessDataVO;
|
||||
}
|
||||
@ -289,7 +293,7 @@ public class BusinessServiceImpl implements BusinessService {
|
||||
List<BusinessDO> businessDOS = businessMapper.selectList(wrapper);
|
||||
|
||||
Map<Integer,BusinessRespVO> map = new HashMap<>();
|
||||
|
||||
//时间处理
|
||||
for (int i = 1; i <= 12; i++) {
|
||||
BusinessRespVO bean = new BusinessRespVO();
|
||||
bean.setTurnover(BigDecimal.ZERO).setOrderSum(0).setReduce(BigDecimal.ZERO).setWeigh(BigDecimal.ZERO)
|
||||
@ -297,6 +301,7 @@ public class BusinessServiceImpl implements BusinessService {
|
||||
.setTime(String.valueOf(i));
|
||||
map.put(i,bean);
|
||||
}
|
||||
//数据统计
|
||||
for (BusinessDO businessDO : businessDOS) {
|
||||
|
||||
LocalDate date = businessDO.getCreateTime().toLocalDate();
|
||||
@ -320,8 +325,15 @@ public class BusinessServiceImpl implements BusinessService {
|
||||
for (BusinessDO businessDO : previousList) {
|
||||
handleBusiness(businessDO,previousVO);
|
||||
}
|
||||
//差额统计
|
||||
for (int i = 1; i <= 12; i++) {
|
||||
if(i == 1){
|
||||
compare(map.get(i),previousVO);
|
||||
}else {
|
||||
compare(map.get(i),map.get(i-1));
|
||||
}
|
||||
}
|
||||
|
||||
businessDataVO.setOld(previousVO);
|
||||
businessDataVO.setBusinessList(new ArrayList<>(map.values()));
|
||||
|
||||
return businessDataVO;
|
||||
@ -349,4 +361,10 @@ public class BusinessServiceImpl implements BusinessService {
|
||||
businessRespVO.setCarteenId(businessDO.getCarteenId());
|
||||
}
|
||||
|
||||
void compare(BusinessRespVO today, BusinessRespVO last) {
|
||||
today.setTurnoverCompare(today.getTurnover().subtract(last.getTurnover()));
|
||||
today.setOrderSumCompare(today.getOrderSum()-last.getOrderSum());
|
||||
today.setPriceAvgCompare(today.getPriceAvg().subtract(last.getPriceAvg()));
|
||||
}
|
||||
|
||||
}
|
@ -62,5 +62,7 @@ public interface StoreOrderService {
|
||||
|
||||
String cardPay(StoreOrderDto dto);
|
||||
|
||||
String codePay(StoreOrderDto dto);
|
||||
|
||||
void batchCacheOrder(StoreOrderUploadDto dto);
|
||||
}
|
@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.member.service.storeorder;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.module.member.controller.admin.storeorder.vo.StoreOrderPageReqVO;
|
||||
@ -35,6 +36,7 @@ import java.util.List;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.STORE_ORDER_NOT_EXISTS;
|
||||
import static cn.iocoder.yudao.module.member.util.QRCodeWithJWTUtil.validateJWT;
|
||||
|
||||
/**
|
||||
* 商品订单 Service 实现类
|
||||
@ -154,6 +156,20 @@ public class StoreOrderServiceImpl implements StoreOrderService {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String codePay(StoreOrderDto dto) {
|
||||
String s = validateJWT(dto.getJwt());
|
||||
if (StrUtil.isBlank(s)) {
|
||||
return "false";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void batchCacheOrder(StoreOrderUploadDto dto) {
|
||||
for (StoreLocalOrderDto orderDto :dto.getMgcrCacheOrderVoList()){
|
||||
|
@ -259,4 +259,5 @@ public interface MemberUserService {
|
||||
|
||||
boolean delete(Long userId);
|
||||
|
||||
String getQRCode();
|
||||
}
|
||||
|
@ -51,6 +51,7 @@ import cn.iocoder.yudao.module.member.service.orderdetail.OrderDetailService;
|
||||
import cn.iocoder.yudao.module.member.service.tag.MemberTagService;
|
||||
import cn.iocoder.yudao.module.member.service.userexpand.UserExpandService;
|
||||
import cn.iocoder.yudao.module.member.util.MemberConstants;
|
||||
import cn.iocoder.yudao.module.member.util.QRCodeWithJWTUtil;
|
||||
import cn.iocoder.yudao.module.system.api.dishesnutrition.DishesNutritionApi;
|
||||
import cn.iocoder.yudao.module.system.api.dishesnutrition.dto.DishesNutritionRespDTO;
|
||||
import cn.iocoder.yudao.module.system.api.sms.SmsCodeApi;
|
||||
@ -63,6 +64,7 @@ import com.baomidou.mybatisplus.core.toolkit.Wrappers;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@ -83,12 +85,16 @@ import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
|
||||
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.setLoginUser;
|
||||
import static cn.iocoder.yudao.module.member.enums.ErrorCodeConstants.*;
|
||||
import static cn.iocoder.yudao.module.member.util.QRCodeWithJWTUtil.generateJWT;
|
||||
import static cn.iocoder.yudao.module.member.util.QRCodeWithJWTUtil.validateJWT;
|
||||
|
||||
/**
|
||||
* 会员 User Service 实现类
|
||||
@ -140,6 +146,9 @@ public class MemberUserServiceImpl implements MemberUserService {
|
||||
@Resource
|
||||
private MemberTagService memberTagService;
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate memberUserRedisTemplate;
|
||||
|
||||
|
||||
@Override
|
||||
public MemberUserDO getUserByMobile(String mobile) {
|
||||
@ -897,4 +906,21 @@ public class MemberUserServiceImpl implements MemberUserService {
|
||||
memberUserMapper.deleteFace(userId);
|
||||
return i>0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getQRCode() {
|
||||
Long userId = getLoginUserId();
|
||||
String redisKey = QRCodeWithJWTUtil.QR_PREFIX+userId;
|
||||
String url = memberUserRedisTemplate.opsForValue().get(redisKey);
|
||||
if(StrUtil.isNotEmpty(url)){
|
||||
return url;
|
||||
}
|
||||
|
||||
String jwt = generateJWT(userId); // 1分钟后过期
|
||||
String fileName = "QRCode_" + userId + ".png";
|
||||
String path = QRCodeWithJWTUtil.BASE_PATH+fileName;
|
||||
QRCodeWithJWTUtil.generateQRCode(jwt, 350, 350, path); // 生
|
||||
memberUserRedisTemplate.opsForValue().set(redisKey,path,60, TimeUnit.SECONDS);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,66 @@
|
||||
package cn.iocoder.yudao.module.member.util;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.extra.qrcode.QrCodeUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
|
||||
import cn.hutool.jwt.JWTUtil;
|
||||
|
||||
|
||||
import java.io.File;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
public class QRCodeWithJWTUtil {
|
||||
private static final String SECRET_KEY = "your_secret_key"; // 使用HS256算法生成秘钥
|
||||
public static final String BASE_PATH = "qrCodes/";
|
||||
public static final String QR_PREFIX = "QRCODE_";
|
||||
// public static void main(String[] args) throws WriterException, IOException {
|
||||
// // 用户ID
|
||||
// Long userId = 123L;
|
||||
//
|
||||
// // 生成包含JWT的二维码
|
||||
// String jwt = generateJWT(userId, 1); // 1分钟后过期
|
||||
// String fileName = "QRCode_" + userId + ".png";
|
||||
// generateQRCode(jwt, 350, 350, BASE_PATH+fileName); // 生成二维码并保存
|
||||
// }
|
||||
|
||||
// 生成 JWT
|
||||
public static String generateJWT(Long userId) {
|
||||
// 创建 JWT payload
|
||||
Map<String, Object> payload = new HashMap<>();
|
||||
payload.put("userId", userId);
|
||||
|
||||
// 设置过期时间为1分钟
|
||||
long expireTime = System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(1);
|
||||
payload.put("exp", expireTime); // 添加过期时间到 payload
|
||||
|
||||
// 生成 JWT
|
||||
|
||||
return JWTUtil.createToken(payload, SECRET_KEY.getBytes());
|
||||
}
|
||||
|
||||
// 生成二维码图片
|
||||
public static void generateQRCode(String data, int width, int height, String filePath) {
|
||||
QrCodeUtil.generate(data, width, height, new File(filePath));
|
||||
}
|
||||
|
||||
// 验证JWT是否有效和未过期
|
||||
public static String validateJWT(String jwt) {
|
||||
boolean isValid = JWTUtil.verify(jwt, SECRET_KEY.getBytes());
|
||||
if (isValid) {
|
||||
System.out.println("JWT 验证成功!");
|
||||
// 解析 JWT
|
||||
JSONObject payloads = JWTUtil.parseToken(jwt).getPayloads();
|
||||
Map<String, Object> map = JSONUtil.toBean(payloads, Map.class);
|
||||
return map.get("userId").toString();
|
||||
} else {
|
||||
System.out.println("JWT 验证失败!");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user