Merge remote-tracking branch 'origin/master'

This commit is contained in:
Tankaikai
2025-03-20 16:21:07 +08:00
33 changed files with 732 additions and 189 deletions

View File

@@ -1,5 +1,6 @@
package com.czg.controller.admin;
import com.czg.account.dto.WxMsgSubDTO;
import com.czg.account.dto.calltable.*;
import com.czg.account.entity.CallConfig;
import com.czg.account.entity.CallQueue;
@@ -135,8 +136,8 @@ public class CallTableController {
*/
@SaAdminCheckPermission(value = "callTable:queue:list", name = "获取叫号队列")
@GetMapping("queue")
public CzgResult<Page<CallQueue>> getQueue(Long callTableId, Integer state) {
return CzgResult.success(callTableService.getQueue(StpKit.USER.getShopId(), callTableId, state));
public CzgResult<Page<CallQueue>> getQueue(Long callTableId, Integer state, String openId) {
return CzgResult.success(callTableService.getQueue(StpKit.USER.getShopId(), openId, callTableId, state));
}
@@ -173,4 +174,15 @@ public class CallTableController {
public CzgResult<Boolean> updateConfig(@RequestBody UpdateConfigDTO configDTO) {
return CzgResult.success(callTableService.updateConfig(StpKit.USER.getShopId(), configDTO));
}
/**
* 消息订阅
* @return 是否成功
*/
@PostMapping("subMsg")
public CzgResult<?> subMsg(
@Validated @RequestBody CallSubMsgDTO subMsgDTO
) {
return CzgResult.success(callTableService.subMsg(subMsgDTO));
}
}

View File

@@ -100,9 +100,6 @@ public class HandoverRecordController {
//@SaAdminCheckPermission("handoverRecord:handover")
public CzgResult<Long> handover(@RequestParam Integer isPrint) {
Long id = handoverRecordService.handover();
if (isPrint == 1){
rabbitPublisher.sendHandoverPrintMsg(id.toString());
}
return CzgResult.success(id);
}

View File

@@ -3,14 +3,10 @@ package com.czg.controller.admin;
import com.czg.account.dto.user.SysUserAddDTO;
import com.czg.account.dto.user.SysUserEditDTO;
import com.czg.account.dto.user.SysUserEditPwdDTO;
import com.czg.account.entity.SysUser;
import com.czg.account.entity.SysUsersRoles;
import com.czg.account.service.SysUserService;
import com.czg.account.vo.SysUserDetailVO;
import com.czg.annotation.SaAdminCheckPermission;
import com.czg.annotation.SaAdminCheckRole;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
@@ -40,7 +36,7 @@ public class SysController {
// @SaAdminCheckPermission("sysUser:list")
@SaAdminCheckRole("admin")
@GetMapping
public CzgResult<Page<SysUser>> list(String key, String startTime, String endTime, Integer status) {
public CzgResult<Page<SysUserDetailVO>> list(String key, String startTime, String endTime, Integer status) {
return CzgResult.success(sysUserService.getPage(key, startTime, endTime, status));
}

View File

@@ -0,0 +1,81 @@
package com.czg.controller.user;
import com.czg.account.dto.calltable.CallSubMsgDTO;
import com.czg.account.dto.calltable.CallTableNumDTO;
import com.czg.account.dto.calltable.CallTablePage;
import com.czg.account.dto.calltable.TakeNumberDTO;
import com.czg.account.entity.CallQueue;
import com.czg.account.service.CallTableService;
import com.czg.annotation.SaAdminCheckPermission;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
/**
* 小程序叫号管理
* @author Administrator
*/
@RestController
@RequestMapping("/user/callTable")
public class UCallTableController {
@Resource
private CallTableService callTableService;
/**
* 获取叫号号码
*/
@PostMapping("takeNumber")
public CzgResult<CallTableNumDTO> takeNumber(@Validated @RequestBody TakeNumberDTO takeNumberDTO) {
return CzgResult.success(callTableService.takeNumber(StpKit.USER.getShopId(), takeNumberDTO));
}
/**
* 获取叫号队列
*
* @param callTableId 桌型id
* @param state 状态 -1已取消 0排队中 1叫号中 2已入座 3 已过号
* @return 分页数据
*/
@GetMapping("queue")
public CzgResult<Page<CallQueue>> getQueue(@RequestParam String openId, Long callTableId, Integer state) {
return CzgResult.success(callTableService.getQueue(StpKit.USER.getShopId(), openId, callTableId, state));
}
/**
* 叫号桌型获取
*
* @param callTableId 叫号桌型id
* @param state 0禁用 1使用
* @return 分页数据
*/
@GetMapping
public CzgResult<CallTablePage> get(Long callTableId, Integer state) {
return CzgResult.success(callTableService.get(StpKit.USER.getShopId(), callTableId, state));
}
/**
* 根据店铺id和openId获取当前叫号号码
* @param queueId 队列id
* @return 状态
*/
@GetMapping("/queue/detail")
public CzgResult<?> getStatus(@RequestParam String openId, @RequestParam(required = false) Long queueId) {
return CzgResult.success(callTableService.getStatus(StpKit.USER.getShopId(), openId, queueId));
}
/**
* 消息订阅
* @return 是否成功
*/
@PostMapping("subMsg")
public CzgResult<Boolean> subMsg(
@Validated @RequestBody CallSubMsgDTO subMsgDTO
) {
return CzgResult.success(callTableService.subMsg(subMsgDTO));
}
}

View File

@@ -15,6 +15,7 @@ import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpLogic;
import cn.hutool.core.util.StrUtil;
import com.czg.exception.ApiNotPrintException;
import com.czg.exception.CzgException;
import lombok.Getter;
import java.util.List;
@@ -43,6 +44,7 @@ public class MyStpLogic {
/**
* 校验员工权限
*
* @param code 权限码
*/
public void checkStaffPermission(String code) {
@@ -53,7 +55,7 @@ public class MyStpLogic {
/**
* @param id 登录账号id
* @param shopName 店铺名称
* @param shopName 店铺名称
* @param shopId 店铺id
* @param loginType 登录类型枚举
* @param isAdmin 是否为管理员账号
@@ -93,6 +95,7 @@ public class MyStpLogic {
/**
* 获取当前店铺用户名,仅后台可用
*
* @return 店铺名称
*/
public String getShopName() {
@@ -113,6 +116,10 @@ public class MyStpLogic {
Long shopId;
int errType;
if ("admin".equals(logic.getLoginType())) {
if (logic.getSession() == null) {
logout();
throw new CzgException("请重新登录");
}
Object info = logic.getSession().get("shopId");
shopId = info instanceof Long l ? l : null;
errType = 0;

View File

@@ -0,0 +1,27 @@
package com.czg.account.dto.calltable;
import jakarta.validation.constraints.NotEmpty;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
* @author Administrator
*/
@Data
public class CallSubMsgDTO {
/**
* 店铺id
*/
@NotNull
private Long shopId;
/**
* 队列id
*/
@NotNull
private Long queueId;
/**
* openId
*/
@NotEmpty
private String openId;
}

View File

@@ -21,4 +21,5 @@ public class CallTableNumDTO {
* 号码
*/
private String callNum;
private Long queueId;
}

View File

@@ -30,4 +30,8 @@ public class TakeNumberDTO extends BaseCallTableDTO{
* 姓名
*/
private String name;
/**
* openId
*/
private String openId;
}

View File

@@ -24,7 +24,7 @@ public class FreeDineConfigEditDTO {
/**
* 充值倍数
*/
@Min(1)
@Min(value = 2, message = "充值倍数不能小于2")
private Integer rechargeTimes;
/**
* 满多少可用

View File

@@ -4,11 +4,24 @@ import com.czg.account.entity.ShopUser;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
/**
* @author Administrator
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ShopUserDTO extends ShopUser {
/**
* 优惠券数量
*/
private Long couponNum;
/**
* 订单数量
*/
private Long orderNumber;
/**
* 充值金额
*/
private BigDecimal rechargeAmount;
}

View File

@@ -32,7 +32,7 @@ public class SysUserEditPwdDTO {
/**
* 密码
*/
@Size(min = 1, message = "密码不为空")
@NotBlank(message = "确认密码不为空")
private String password;

View File

@@ -4,6 +4,7 @@ import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@@ -30,9 +31,6 @@ public class FreeDineConfig implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Id(keyType = KeyType.Auto)
private Long id;
/**
* 是否启用
*/
@@ -71,6 +69,7 @@ public class FreeDineConfig implements Serializable {
/**
* 门店id
*/
@Id
private Long shopId;
/**
@@ -90,4 +89,7 @@ public class FreeDineConfig implements Serializable {
*/
private String childShopIdList;
public Integer getMultiple() {
return rechargeTimes == null ? 2 : rechargeTimes;
}
}

View File

@@ -34,7 +34,6 @@ public class SysUsersRoles implements Serializable {
/**
* 角色ID
*/
@Id
private Long roleId;
}

View File

@@ -29,11 +29,15 @@ public interface CallTableService extends IService<CallTable> {
boolean updateInfo(Long shopId, UpdateCallQueueDTO updateCallQueueDTO);
Page<CallQueue> getQueue(Long shopId, Long callTableId, Integer state);
Page<CallQueue> getQueue(Long shopId, String openId, Long callTableId, Integer state);
Page<CallRecordVO> getCallRecord(Long shopId, Integer callTableId);
CallConfig getConfig(Long shopId);
boolean updateConfig(Long shopId, UpdateConfigDTO configDTO);
boolean subMsg(CallSubMsgDTO subMsgDTO);
Object getStatus(Long shopId, String openId, Long queueId);
}

View File

@@ -25,7 +25,7 @@ public interface SysUserService extends IService<SysUser> {
Boolean removeUserAndRole(Long id);
Page<SysUser> getPage(String key, String startTime, String endTime, Integer status);
Page<SysUserDetailVO> getPage(String key, String startTime, String endTime, Integer status);
Boolean edit(SysUserEditDTO sysUserEditDTO);

View File

@@ -0,0 +1,47 @@
package com.czg.account.vo;
import lombok.Data;
/**
* @author Administrator
*/
@Data
public class CallQueueInfoVO {
/**
* 叫号队列idqueueId
*/
private Long id;
/**
* 桌型名称
*/
private String tableName;
/**
* 桌型备注
*/
private String tableNote;
/**
* 等待人数
*/
private Integer waitingCount;
/**
* 等待时间
*/
private Integer waitTime;
/**
* -1已取消 0排队中 1叫号中 2已入座 3 已过号
*/
private Integer state;
/**
* 叫号号码
*/
private String callNum;
private String shopState;
/**
* 店铺名称
*/
private String shopName;
/**
* logo
*/
private String logo;
}

View File

@@ -163,11 +163,11 @@
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>${dubbo-spring.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alibaba-seata -->
<!-- https://mvnrepository.com/artifact/io.seata/seata-spring-boot-starter -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<version>2023.0.3.2</version>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
<version>${seata.version}</version>
</dependency>
<dependency>

View File

@@ -1,9 +1,13 @@
package com.czg.service.account.mapper;
import com.czg.account.dto.calltable.CallRecordVO;
import com.czg.account.vo.CallQueueInfoVO;
import com.mybatisflex.core.BaseMapper;
import com.czg.account.entity.CallQueue;
import com.mybatisflex.core.paginate.Page;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 叫号排号队列表 映射层。
@@ -16,4 +20,5 @@ public interface CallQueueMapper extends BaseMapper<CallQueue> {
Page<CallRecordVO> selectCallRecord();
long selectCallRecord_COUNT();
List<CallQueueInfoVO> selectInfoByOpenId(@Param("shopId") Long shopId, @Param("openId") String openId, @Param("today") String today, @Param("queueId") Long queueId);
}

View File

@@ -1,7 +1,11 @@
package com.czg.service.account.mapper;
import com.czg.account.entity.SysUser;
import com.czg.account.vo.SysUserDetailVO;
import com.mybatisflex.core.BaseMapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* 系统用户 映射层。
@@ -11,4 +15,5 @@ import com.mybatisflex.core.BaseMapper;
*/
public interface SysUserMapper extends BaseMapper<SysUser> {
List<SysUserDetailVO> page(@Param("key") String key, @Param("startTime") String startTime, @Param("endTime") String endTime, @Param("status") Integer status);
}

View File

@@ -8,6 +8,7 @@ import cn.hutool.extra.qrcode.QrConfig;
import com.czg.account.dto.calltable.*;
import com.czg.account.entity.*;
import com.czg.account.service.*;
import com.czg.account.vo.CallQueueInfoVO;
import com.czg.config.RabbitPublisher;
import com.czg.config.RedisCst;
import com.czg.exception.ApiNotPrintException;
@@ -15,6 +16,7 @@ import com.czg.resp.CzgResult;
import com.czg.service.account.mapper.CallQueueMapper;
import com.czg.service.account.mapper.CallTableMapper;
import com.czg.service.account.util.FunUtil;
import com.czg.service.account.util.WechatMiniMsgUtil;
import com.czg.system.dto.SysParamsDTO;
import com.czg.system.service.SysParamsService;
import com.czg.utils.JoinQueryWrapper;
@@ -28,10 +30,7 @@ import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.data.redis.core.StringRedisTemplate;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Collections;
import java.util.List;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
@@ -62,6 +61,8 @@ public class CallTableServiceImpl extends ServiceImpl<CallTableMapper, CallTable
private CallQueueMapper callQueueMapper;
@Resource
private RabbitPublisher rabbitPublisher;
@Resource
private WechatMiniMsgUtil miniMsgUtil;
@Override
public CallTablePage get(Long shopId, Long callTableId, Integer state) {
@@ -222,7 +223,7 @@ public class CallTableServiceImpl extends ServiceImpl<CallTableMapper, CallTable
rabbitPublisher.printCallNumTicket(callQueue.getId());
return new CallTableNumDTO().setTableName(callTable.getName()).setTableNote(callTable.getNote())
.setCallNum(callQueue.getCallNum());
.setCallNum(callQueue.getCallNum()).setQueueId(callQueue.getId());
}
private String getCallNumber(Long shopId, CallTable callTable) {
@@ -322,8 +323,8 @@ public class CallTableServiceImpl extends ServiceImpl<CallTableMapper, CallTable
return -1;
}
// wxMiniUtils.sendCurrentOrNearCallMsg(shopInfo.getShopName(), getStrByState(Integer.valueOf(callQueue.getState())),
// callQueue.getCallNum(), current.isEmpty() ? "" : current.get(0).getCallNum(), "排号信息", callQueue.getOpenId(), false);
miniMsgUtil.sendCurrentOrNearCallMsg(shopInfo.getShopName(), getStrByState(callQueue.getState()),
callQueue.getCallNum(), current.isEmpty() ? "" : current.getFirst().getCallNum(), "排号信息", callQueue.getOpenId(), false);
CallConfig config = getConfig(shopId);
// 临近用户提醒
@@ -334,11 +335,20 @@ public class CallTableServiceImpl extends ServiceImpl<CallTableMapper, CallTable
.page(new Page<>(config.getNearNum(), 1)).getRecords();
if (!nearList.isEmpty()) {
CallQueue nearQueue = nearList.getFirst();
// wxMiniUtils.sendCurrentOrNearCallMsg(shopInfo.getShopName(), getStrByState(Integer.valueOf(nearQueue.getState())),
// nearQueue.getCallNum(), current.isEmpty() ? "" : current.get(0).getCallNum(), "排号信息", nearQueue.getOpenId(), true);
miniMsgUtil.sendCurrentOrNearCallMsg(shopInfo.getShopName(), getStrByState(nearQueue.getState()),
nearQueue.getCallNum(), current.isEmpty() ? "" : current.getFirst().getCallNum(), "排号信息", nearQueue.getOpenId(), true);
}
return 1;
}
private String getStrByState(Integer state) {
return switch (state) {
case -1 -> "已取消";
case 0 -> "排队中";
case 1 -> "已到号";
case 3 -> "已过号";
default -> "";
};
}
@Override
public boolean updateInfo(Long shopId, UpdateCallQueueDTO updateCallQueueDTO) {
@@ -455,7 +465,7 @@ public class CallTableServiceImpl extends ServiceImpl<CallTableMapper, CallTable
}
@Override
public Page<CallQueue> getQueue(Long shopId, Long callTableId, Integer state) {
public Page<CallQueue> getQueue(Long shopId, String openId, Long callTableId, Integer state) {
List<Long> tableIds;
if (callTableId != null) {
tableIds = Collections.singletonList(callTableId);
@@ -479,6 +489,10 @@ public class CallTableServiceImpl extends ServiceImpl<CallTableMapper, CallTable
query.in(CallQueue::getState, 0, 1);
}
if (StrUtil.isNotBlank(openId)) {
query.eq(CallQueue::getOpenId, openId);
}
Page<CallQueue> pageInfo = callQueueService.page(PageUtil.buildPage(), query
.orderBy(CallQueue::getCreateTime, true)
.orderBy(CallQueue::getState, false));
@@ -543,4 +557,60 @@ public class CallTableServiceImpl extends ServiceImpl<CallTableMapper, CallTable
tbCallConfig.setId(config.getId());
return callConfigService.updateById(tbCallConfig);
}
@Override
public boolean subMsg(CallSubMsgDTO subMsgDTO) {
CallQueue queue = callQueueService.getOne(new QueryWrapper()
.eq(CallQueue::getShopId, subMsgDTO.getShopId())
.eq(CallQueue::getId, subMsgDTO.getQueueId()));
if (queue == null) {
throw new ApiNotPrintException("您未排号请先排号");
}
if (queue.getOpenId() != null && queue.getOpenId().equals(subMsgDTO.getOpenId()) && queue.getSubState() == 1) {
return true;
}
if (StrUtil.isNotBlank(queue.getOpenId()) && queue.getSubState() == 1) {
throw new ApiNotPrintException("此号码已被其他用户订阅");
}
if (!subMsgDTO.getOpenId().equals(queue.getOpenId()) && queue.getSubState() == 0) {
long count = callQueueService.queryChain()
// .eq(CallQueue::getPhone, takeNumberDTO.getPhone())
.eq(CallQueue::getOpenId, subMsgDTO.getOpenId())
.eq(CallQueue::getShopId, subMsgDTO.getShopId())
.eq(CallQueue::getCreateDay, DateUtil.date().toString("yyyy-MM-dd"))
.in(CallQueue::getState, 0, 1)
.ne(CallQueue::getIsPostpone, 2)
.eq(CallQueue::getCallTableId, queue.getCallTableId()).count();
if (count > 0) {
throw new ApiNotPrintException("您已订阅其他号码,请勿重复订阅");
}
}
queue.setSubState(1);
queue.setOpenId(subMsgDTO.getOpenId());
return callQueueService.updateById(queue);
}
@Override
public Object getStatus(Long shopId, String openId, Long queueId) {
List<CallQueueInfoVO> callQueueInfoVOS = callQueueMapper.selectInfoByOpenId(shopId, openId, DateUtil.date().toString("yyyy-MM-dd"), null);
if (callQueueInfoVOS.isEmpty()) {
callQueueInfoVOS = callQueueMapper.selectInfoByOpenId(shopId, openId, DateUtil.date().toString("yyyy-MM-dd"), queueId);
}
if (!callQueueInfoVOS.isEmpty()) {
CallQueueInfoVO callQueueInfoVO = callQueueInfoVOS.getFirst();
CallQueue callQueue = new CallQueue();
callQueue.setOpenId(openId);
callQueue.setId(callQueueInfoVO.getId());
callQueueService.updateById(callQueue);
}
ShopInfo shopInfo = shopInfoService.getById(shopId);
HashMap<String, Object> data = new HashMap<>();
data.put("shopInfo", shopInfo);
data.put("queueInfo", callQueueInfoVOS.isEmpty() ? null : callQueueInfoVOS.getFirst());
return data;
}
}

View File

@@ -31,6 +31,7 @@ import org.springframework.cache.annotation.Cacheable;
import org.springframework.transaction.annotation.Transactional;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -66,10 +67,10 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
if (shopInfo == null) {
throw new ApiNotPrintException("店铺不存在");
}
if ((DateUtil.date().toLocalDateTime().isAfter(shopInfo.getExpireTime())) || shopInfo.getStatus() != StatusEnum.ENABLED.value()) {
if ((DateUtil.date().toLocalDateTime().isAfter(shopInfo.getExpireTime()))) {
throw new ApiNotPrintException("店铺已过期,请联系商家");
}
if (StatusEnum.DISABLE.value() == shopInfo.getOnSale()) {
if (StatusEnum.DISABLE.value() == shopInfo.getOnSale() || shopInfo.getStatus() != StatusEnum.ENABLED.value()) {
throw new ApiNotPrintException("店铺已停业,请联系商家");
}
@@ -98,7 +99,13 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
if (merchantRegister.getStatus() == 1) {
throw new CzgException("激活码已使用");
}
shopInfo.setExpireTime(DateUtil.offsetMonth(DateUtil.date(), merchantRegister.getPeriodMonth()).toLocalDateTime());
// 续期
if (shopInfo.getExpireTime() != null && shopInfo.getExpireTime().isAfter(LocalDateTime.now())) {
shopInfo.setExpireTime(DateUtil.offsetMonth(DateUtil.date(shopInfo.getExpireTime()), merchantRegister.getPeriodMonth()).toLocalDateTime());
}else {
shopInfo.setExpireTime(DateUtil.offsetMonth(DateUtil.date(), merchantRegister.getPeriodMonth()).toLocalDateTime());
}
merchantRegister.setStatus(1);
merchantRegister.setShopId(shopInfo.getId());
merchantRegisterService.updateById(merchantRegister);

View File

@@ -17,10 +17,13 @@ import com.czg.account.vo.SysUserDetailVO;
import com.czg.exception.ApiNotPrintException;
import com.czg.exception.CzgException;
import com.czg.sa.StpKit;
import com.czg.service.RedisService;
import com.czg.service.account.mapper.SysRoleMapper;
import com.czg.service.account.mapper.SysUserMapper;
import com.czg.service.account.mapper.SysUsersRolesMapper;
import com.czg.utils.PageUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
@@ -47,6 +50,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
private SysRoleMapper sysRoleMapper;
@Resource
private SysUsersRolesMapper sysUsersRolesMapper;
@Resource
private RedisService redisService;
@Override
public SysUser addUser(String nickname, String accountName, String accountPwd, String phone, Long roleId) {
@@ -96,24 +101,9 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
}
@Override
public Page<SysUser> getPage(String key, String startTime, String endTime, Integer status) {
QueryWrapper queryWrapper = new QueryWrapper();
if (StrUtil.isNotBlank(key)) {
queryWrapper.and(column(SysUser::getAccount).like(key).or(column(SysUser::getNickName).like(key)));
}
if (StrUtil.isNotBlank(startTime)) {
queryWrapper.ge(SysUser::getCreateTime, DateUtil.parse(startTime));
}
if (StrUtil.isNotBlank(endTime)) {
queryWrapper.le(SysUser::getCreateTime, DateUtil.parse(endTime));
}
if (status != null) {
queryWrapper.eq(SysUser::getStatus, status);
}
return page(PageUtil.buildPage(), queryWrapper);
public Page<SysUserDetailVO> getPage(String key, String startTime, String endTime, Integer status) {
PageHelper.startPage(PageUtil.buildPageHelp());
return PageUtil.convert(new PageInfo<>(mapper.page(key, startTime, endTime, status)));
}
@Override
@@ -177,8 +167,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
@Override
public void download(String key, String startTime, String endTime, Integer status, HttpServletResponse response) throws IOException {
Page<SysUser> sysUserPage = getPage(key, startTime, endTime, status);
List<SysUser> records = sysUserPage.getRecords();
Page<SysUserDetailVO> sysUserPage = getPage(key, startTime, endTime, status);
List<SysUserDetailVO> records = sysUserPage.getRecords();
// 1. 创建 ExcelWriter
// true 表示使用 XLSX 格式
@@ -232,7 +222,10 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
}
sysUser.setPassword(SecureUtil.md5(sysUser.getId() + sysUserEditPwdDTO.getPassword()));
return updateById(sysUser);
boolean isUp = updateById(sysUser);
if (isUp) {
redisService.del(STR."token:admin:session:\{sysUser.getId()}");
}
return isUp;
}
}

View File

@@ -10,16 +10,12 @@ import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.internal.util.AlipayEncrypt;
import com.alipay.api.request.AlipaySystemOauthTokenRequest;
import com.alipay.api.response.AlipaySystemOauthTokenResponse;
import com.czg.exception.ApiNotPrintException;
import com.czg.resp.CzgResult;
import com.czg.system.dto.SysParamsDTO;
import com.czg.system.service.SysParamsService;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
@@ -35,61 +31,6 @@ public class AlipayUtil {
@DubboReference
private SysParamsService sysParamsService;
/**
* 网关地址 线上https://openapi.alipay.com/gateway.do 沙箱https://openapi.alipaydev.com/gateway.do
*/
// @Value("${alipay.serverUrl}")
private String serverUrl;
/**
* 应用ID
*/
// @Value("${alipay.appId}")
private String appId;
/**
* 应用私钥
*/
// @Value("${alipay.privateKey}")
private String privateKey;
/**
* 支付宝公钥
*/
// @Value("${alipay.alipayPublicKey}")
private String alipayPublicKey;
/**
* 支付宝公钥
*/
// @Value("${alipay.encryptKey}")
private String encryptKey;
// @Value("${alipay.account.appId}")
private String accountAppId;
// @Value("${alipay.account.privateKey}")
private String accountPrivateKey;
// @Value("${alipay.account.publicKey}")
private String accountPublicKey;
// @PostConstruct
// private void init() {
// CzgResult<SysParamsDTO> aliGateway = sysParamsService.getParamsByCode("ali_gateway");
// CzgResult<SysParamsDTO> aliMiniAppId = sysParamsService.getParamsByCode("ali_mini_app_id");
// CzgResult<SysParamsDTO> aliMiniPrivateKey = sysParamsService.getParamsByCode("ali_mini_private_key");
// CzgResult<SysParamsDTO> aliMiniPublicKey = sysParamsService.getParamsByCode("ali_mini_public_key");
// CzgResult<SysParamsDTO> aliAccountAppId = sysParamsService.getParamsByCode("ali_account_app_id");
// CzgResult<SysParamsDTO> aliAccountPrivateKey = sysParamsService.getParamsByCode("ali_account_private_key");
// CzgResult<SysParamsDTO> aliAccountPublicKey = sysParamsService.getParamsByCode("ali_account_public_key");
// CzgResult<SysParamsDTO> aliEncryptKey = sysParamsService.getParamsByCode("ali_encrypt_key");
// serverUrl = aliGateway.getData().getParamValue();
// appId = aliMiniAppId.getData().getParamValue();
// privateKey = aliMiniPrivateKey.getData().getParamValue();
// alipayPublicKey = aliMiniPublicKey.getData().getParamValue();
// encryptKey = aliEncryptKey.getData().getParamValue();
// accountAppId = aliAccountAppId.getData().getParamValue();
// accountPrivateKey = aliAccountPrivateKey.getData().getParamValue();
// accountPublicKey = aliAccountPublicKey.getData().getParamValue();
// log.info("支付宝工具类初始化成功, {}", this);
// }
/**
* 创建支付宝客户端
*
@@ -97,6 +38,20 @@ public class AlipayUtil {
*/
@SneakyThrows
public AlipayClient createClient(boolean isAccount) {
CzgResult<SysParamsDTO> aliGateway = sysParamsService.getParamsByCode("ali_gateway");
CzgResult<SysParamsDTO> aliMiniAppId = sysParamsService.getParamsByCode("ali_mini_app_id");
CzgResult<SysParamsDTO> aliMiniPrivateKey = sysParamsService.getParamsByCode("ali_mini_private_key");
CzgResult<SysParamsDTO> aliMiniPublicKey = sysParamsService.getParamsByCode("ali_mini_public_key");
CzgResult<SysParamsDTO> aliAccountAppId = sysParamsService.getParamsByCode("ali_account_app_id");
CzgResult<SysParamsDTO> aliAccountPrivateKey = sysParamsService.getParamsByCode("ali_account_private_key");
CzgResult<SysParamsDTO> aliAccountPublicKey = sysParamsService.getParamsByCode("ali_account_public_key");
String serverUrl = aliGateway.getData().getParamValue();
String appId = aliMiniAppId.getData().getParamValue();
String privateKey = aliMiniPrivateKey.getData().getParamValue();
String alipayPublicKey = aliMiniPublicKey.getData().getParamValue();
String accountAppId = aliAccountAppId.getData().getParamValue();
String accountPrivateKey = aliAccountPrivateKey.getData().getParamValue();
String accountPublicKey = aliAccountPublicKey.getData().getParamValue();
AlipayConfig alipayConfig = new AlipayConfig();
//设置网关地址
alipayConfig.setServerUrl(serverUrl);
@@ -141,27 +96,30 @@ public class AlipayUtil {
}
public String getMobile(String encryptedData) {
if(StrUtil.isEmpty(encryptedData)){
if (StrUtil.isEmpty(encryptedData)) {
throw new RuntimeException("加密数据不能为空");
}
try {
CzgResult<SysParamsDTO> aliEncryptKey = sysParamsService.getParamsByCode("ali_encrypt_key");
String encryptKey = aliEncryptKey.getData().getParamValue();
log.info("解密前的数据,返回结果:{}", encryptedData);
String resp = AlipayEncrypt.decryptContent(encryptedData, "AES", encryptKey, "UTF-8");
log.info("解密后的数据,返回结果:{}", resp);
boolean isJson = JSONUtil.isTypeJSON(resp);
if(!isJson){
if (!isJson) {
throw new AlipayApiException("解密后的数据不是json格式");
}
JSONObject jsonObject = JSONUtil.parseObj(resp);
String code = jsonObject.getStr("code");
String msg = jsonObject.getStr("msg");
String mobile = jsonObject.getStr("mobile");
if("10000".equals(code)){
if ("10000".equals(code)) {
return mobile;
}else{
throw new AlipayApiException(code,msg);
} else {
throw new AlipayApiException(code, msg);
}
}catch (AlipayApiException e){
} catch (AlipayApiException e) {
log.error("获取支付宝用户的手机号码失败,错误码:{},错误信息:{}", e.getErrCode(), e.getErrMsg());
throw new RuntimeException(e);
}

View File

@@ -13,7 +13,6 @@ import com.czg.system.dto.SysParamsDTO;
import com.czg.system.enums.SysParamCodeEnum;
import com.czg.system.service.SysParamsService;
import com.google.gson.JsonObject;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotBlank;
import lombok.extern.slf4j.Slf4j;
@@ -38,16 +37,6 @@ public class WechatAuthUtil {
@Resource
private AliOssUtil aliOssUtil;
// @Value("${wx.appId}")
private String appId;
// @Value("${wx.secrete}")
private String secrete;
// @Value("${wx.account.appId}")
private String accountAppId;
// @Value("${wx.account.secrete}")
private String accountSecrete;
private static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
private static final String QR_CODE_URL = "https://api.weixin.qq.com/wxa/getwxacode";
@@ -68,20 +57,11 @@ public class WechatAuthUtil {
}
// @PostConstruct
// public void init() {
// CzgResult<SysParamsDTO> wxMiniAppId = sysParamsService.getParamsByCode("wx_mini_app_id");
// CzgResult<SysParamsDTO> wxMiniSecrete = sysParamsService.getParamsByCode("wx_mini_secrete");
// CzgResult<SysParamsDTO> wxAccountAppId = sysParamsService.getParamsByCode("wx_account_app_id");
// CzgResult<SysParamsDTO> wxAccountSecrete = sysParamsService.getParamsByCode("wx_account_secrete");
// appId = wxMiniAppId.getData().getParamValue();
// secrete = wxMiniSecrete.getData().getParamValue();
// accountAppId = wxAccountAppId.getData().getParamValue();
// accountSecrete = wxAccountSecrete.getData().getParamValue();
// log.info("微信工具类初始化成功, appId: {}, secrete: {}, accountAppId: {}, accountSecrete: {}", appId, secrete, accountAppId, accountSecrete);
// }
public String getAccountOpenId(String code) {
CzgResult<SysParamsDTO> wxAccountAppId = sysParamsService.getParamsByCode("wx_account_app_id");
CzgResult<SysParamsDTO> wxAccountSecrete = sysParamsService.getParamsByCode("wx_account_secrete");
String accountAppId = wxAccountAppId.getData().getParamValue();
String accountSecrete = wxAccountSecrete.getData().getParamValue();
String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?";
Map<String, Object> requestUrlParam = new HashMap<>();
// https://mp.weixin.qq.com/wxopen/devprofile?action=get_profile&token=164113089&lang=zh_CN
@@ -102,6 +82,10 @@ public class WechatAuthUtil {
//获取小程序token
private String getAccessToken() {
CzgResult<SysParamsDTO> wxMiniAppId = sysParamsService.getParamsByCode("wx_mini_app_id");
CzgResult<SysParamsDTO> wxMiniSecrete = sysParamsService.getParamsByCode("wx_mini_secrete");
String appId = wxMiniAppId.getData().getParamValue();
String secrete = wxMiniSecrete.getData().getParamValue();
String url = String.format("%s?grant_type=client_credential&appid=%s&secret=%s", TOKEN_URL, appId, secrete);
String response = HttpUtil.get(url);
com.alibaba.fastjson.JSONObject jsonResponse = com.alibaba.fastjson.JSONObject.parseObject(response);
@@ -114,8 +98,6 @@ public class WechatAuthUtil {
/**
* 生成 小程序码 跳转对应页面
*
* @param params
* @return
*/
public String getFetchQrCode(Map<String, Object> params) throws Exception {
String url = aliOssUtil.upload(fetchQrCode(params), aliOssUtil.getPath("shopVip", "png"));
@@ -127,7 +109,7 @@ public class WechatAuthUtil {
private InputStream fetchQrCode(Map<String, Object> params) {
JsonObject jsonObject = new JsonObject();
//路径
jsonObject.addProperty("path", sysParamsService.getSysParamValue(SysParamCodeEnum.WX_MINI_VIP_URL.getCode())+"?shopId="+params.get("shopId"));
jsonObject.addProperty("path", sysParamsService.getSysParamValue(SysParamCodeEnum.WX_MINI_VIP_URL.getCode()) + "?shopId=" + params.get("shopId"));
//是否需要透明底色,为 true 时,生成透明底色的小程序码
jsonObject.addProperty("is_hyaline", true);
//正式版为 release体验版为 trial开发版为 develop
@@ -144,6 +126,10 @@ public class WechatAuthUtil {
public JSONObject getSession(String code) {
CzgResult<SysParamsDTO> wxMiniSecrete = sysParamsService.getParamsByCode("wx_mini_secrete");
CzgResult<SysParamsDTO> wxMiniAppId = sysParamsService.getParamsByCode("wx_mini_app_id");
String appId = wxMiniAppId.getData().getParamValue();
String secrete = wxMiniSecrete.getData().getParamValue();
String requestUrl = "https://api.weixin.qq.com/sns/jscode2session";
Map<String, Object> requestUrlParam = new HashMap<>();
// https://mp.weixin.qq.com/wxopen/devprofile?action=get_profile&token=164113089&lang=zh_CN

View File

@@ -0,0 +1,256 @@
package com.czg.service.account.util;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.symmetric.AES;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.czg.config.RedisCst;
import com.czg.resp.CzgResult;
import com.czg.service.RedisService;
import com.czg.system.dto.SysParamsDTO;
import com.czg.system.enums.SysParamCodeEnum;
import com.czg.system.service.SysParamsService;
import com.google.gson.JsonObject;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotBlank;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Component;
import java.io.InputStream;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* @author Administrator
*/
@Slf4j
@Component
public class WechatMiniMsgUtil {
@DubboReference(check = false)
private SysParamsService sysParamsService;
@Resource
private RedisService redisService;
@Resource
private AliOssUtil aliOssUtil;
private static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token";
private static final String QR_CODE_URL = "https://api.weixin.qq.com/wxa/getwxacode";
static LinkedHashMap<String, String> linkedHashMap = new LinkedHashMap<>();
static {
linkedHashMap.put("40001", "获取 access_token 时 AppSecret 错误,或者 access_token 无效。请开发者认真比对 AppSecret 的正确性,或查看是否正在为恰当的公众号调用接口");
linkedHashMap.put("40003", "不合法的 OpenID ,请开发者确认 OpenID (该用户)是否已关注公众号,或是否是其他公众号的 OpenID");
linkedHashMap.put("40014", "不合法的 access_token ,请开发者认真比对 access_token 的有效性(如是否过期),或查看是否正在为恰当的公众号调用接口");
linkedHashMap.put("40037", "不合法的 template_id");
linkedHashMap.put("43101", "用户未订阅消息");
linkedHashMap.put("43107", "订阅消息能力封禁");
linkedHashMap.put("43108", "并发下发消息给同一个粉丝");
linkedHashMap.put("45168", "命中敏感词");
linkedHashMap.put("47003", "参数错误");
}
public JSONObject sendTempMsg(String tempId, String toUserOpenId, Map<String, Object> data, String note) {
log.info("开始发送" + note + "模板消息, 接收用户openId: {}, 消息数据: {}", toUserOpenId, data);
String token= getAccessToken();
JSONObject object1=new JSONObject();
object1.put("template_id", tempId);
object1.put("touser", toUserOpenId);
object1.put("data",data);
object1.put("miniprogram_state","trial");
object1.put("lang","zh_CN");
String response= HttpRequest.post("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=".concat(token)).body(object1.toString()).execute().body();
log.info("微信模板消息发送成功,相应内容:{}",response);
JSONObject resObj= JSONObject.parseObject(response);
if(ObjectUtil.isNotEmpty(resObj)&&ObjectUtil.isNotNull(resObj)&&"0".equals(resObj.get("errcode")+"")){
return resObj;
}
throw new RuntimeException(linkedHashMap.getOrDefault(resObj.get("errcode") + "", "未知错误"));
}
public void sendCurrentOrNearCallMsg(String shopName, String state, String callNum, String currentNum, String note, String openId, boolean isNear) {
CzgResult<SysParamsDTO> callNear = sysParamsService.getParamsByCode("wx_mini_msg_call_near");
CzgResult<SysParamsDTO> callCurrent = sysParamsService.getParamsByCode("wx_mini_msg_call_current");
Map<String, Object> data = new HashMap<String, Object>() {{
put("thing1", new HashMap<String, Object>() {{
put("value", shopName);
}});
put("phrase2", new HashMap<String, Object>() {{
put("value", state);
}});
put("character_string3", new HashMap<String, Object>() {{
put("value", callNum);
}});
put("character_string4", new HashMap<String, Object>() {{
put("value", currentNum);
}});
put("thing5", new HashMap<String, Object>() {{
put("value", note);
}});
}};
try {
sendTempMsg(isNear ? callNear.getData().getParamValue() : callCurrent.getData().getParamValue(), openId, data, "排队到号");
} catch (Exception e) {
log.error("发送失败, openId:{}, msg: {}", openId, e.getMessage());
}
}
public void sendPassCallMsg(String shopName, String state, String callNum, String currentNum, String note, String openId) {
CzgResult<SysParamsDTO> callPass = sysParamsService.getParamsByCode("wx_mini_msg_call_pass");
Map<String, Object> data = new HashMap<String, Object>() {{
put("thing1", new HashMap<String, Object>() {{
put("value", shopName);
}});
put("character_string2", new HashMap<String, Object>() {{
put("value", callNum);
}});
put("character_string3", new HashMap<String, Object>() {{
put("value", currentNum);
}});
put("phrase4", new HashMap<String, Object>() {{
put("value", state);
}});
put("thing5", new HashMap<String, Object>() {{
put("value", note);
}});
}};
try {
sendTempMsg(callPass.getData().getParamValue(), openId, data, "过号");
} catch (Exception e) {
log.error("发送失败, openId:{}, msg: {}", openId, e.getMessage());
}
}
public String getAccountOpenId(String code) {
CzgResult<SysParamsDTO> wxAccountAppId = sysParamsService.getParamsByCode("wx_account_app_id");
CzgResult<SysParamsDTO> wxAccountSecrete = sysParamsService.getParamsByCode("wx_account_secrete");
String accountAppId = wxAccountAppId.getData().getParamValue();
String accountSecrete = wxAccountSecrete.getData().getParamValue();
String requestUrl = "https://api.weixin.qq.com/sns/oauth2/access_token?";
Map<String, Object> requestUrlParam = new HashMap<>();
// https://mp.weixin.qq.com/wxopen/devprofile?action=get_profile&token=164113089&lang=zh_CN
//小程序appId
requestUrlParam.put("appid", accountAppId);
//小程序secret
requestUrlParam.put("secret", accountSecrete);
//小程序端返回的code
requestUrlParam.put("code", code);
//默认参数
requestUrlParam.put("grant_type", "authorization_code");
log.info("微信获取openid请求报文{}", requestUrlParam);
//发送post请求读取调用微信接口获取openid用户唯一标识
String resp = HttpUtil.post(requestUrl, requestUrlParam);
log.info("响应报文{}", resp);
return JSONObject.parseObject(resp).getString("openid");
}
//获取小程序token
private String getAccessToken() {
CzgResult<SysParamsDTO> wxMiniAppId = sysParamsService.getParamsByCode("wx_mini_app_id");
CzgResult<SysParamsDTO> wxMiniSecrete = sysParamsService.getParamsByCode("wx_mini_secrete");
String appId = wxMiniAppId.getData().getParamValue();
String secrete = wxMiniSecrete.getData().getParamValue();
String url = String.format("%s?grant_type=client_credential&appid=%s&secret=%s", TOKEN_URL, appId, secrete);
String response = HttpUtil.get(url);
JSONObject jsonResponse = JSONObject.parseObject(response);
if (!jsonResponse.containsKey("access_token")) {
throw new RuntimeException("Failed to retrieve access token: " + response);
}
return jsonResponse.getString("access_token");
}
/**
* 生成 小程序码 跳转对应页面
*
*/
public String getFetchQrCode(Map<String, Object> params) throws Exception {
String url = aliOssUtil.upload(fetchQrCode(params), aliOssUtil.getPath("shopVip", "png"));
redisService.set(RedisCst.SHOP_VIP_CODE + params.get("shopId"), url);
return url;
}
//生成页面地址
private InputStream fetchQrCode(Map<String, Object> params) {
JsonObject jsonObject = new JsonObject();
//路径
jsonObject.addProperty("path", sysParamsService.getSysParamValue(SysParamCodeEnum.WX_MINI_VIP_URL.getCode()) + "?shopId=" + params.get("shopId"));
//是否需要透明底色,为 true 时,生成透明底色的小程序码
jsonObject.addProperty("is_hyaline", true);
//正式版为 release体验版为 trial开发版为 develop
if (params.containsKey("env_version")) {
jsonObject.addProperty("env_version", "trial");
}
String accessToken = getAccessToken();
String url = String.format("%s?access_token=%s", QR_CODE_URL, accessToken);
return HttpUtil.createPost(url)
.body(jsonObject.toString(), "application/json")
.execute()
.bodyStream();
}
public JSONObject getSession(String code) {
CzgResult<SysParamsDTO> wxMiniSecrete = sysParamsService.getParamsByCode("wx_mini_secrete");
CzgResult<SysParamsDTO> wxMiniAppId = sysParamsService.getParamsByCode("wx_mini_app_id");
String appId = wxMiniAppId.getData().getParamValue();
String secrete = wxMiniSecrete.getData().getParamValue();
String requestUrl = "https://api.weixin.qq.com/sns/jscode2session";
Map<String, Object> requestUrlParam = new HashMap<>();
// https://mp.weixin.qq.com/wxopen/devprofile?action=get_profile&token=164113089&lang=zh_CN
//小程序appId
requestUrlParam.put("appid", appId);
//小程序secret
requestUrlParam.put("secret", secrete);
//小程序端返回的code
requestUrlParam.put("js_code", code);
//默认参数
requestUrlParam.put("grant_type", "authorization_code");
//发送post请求读取调用微信接口获取openid用户唯一标识
String resp = HttpUtil.post(requestUrl, requestUrlParam);
JSONObject jsonObject = JSON.parseObject(resp);
log.info("微信获取openid响应报文{}", resp);
return jsonObject;
}
public String getSessionKey(String code, String key) {
JSONObject session = getSession(code);
String info = session.getString(key);
if (StrUtil.isBlank(info)) {
throw new RuntimeException(key + "获取失败");
}
return info;
}
public String getSessionKeyOrOpenId(String code, boolean isAccount) {
return getSessionKey(code, "openid");
}
public static String decrypt(String sessionKey, @NotBlank(message = "数据不能为空") String encryptedData, String iv) {
// Base64 解码
byte[] keyBytes = Base64.decode(sessionKey);
byte[] encryptedBytes = Base64.decode(encryptedData);
byte[] ivBytes = Base64.decode(iv);
// 使用 Hutool 进行 AES-CBC 解密
AES aes = new AES("CBC", "PKCS5Padding", keyBytes, ivBytes);
byte[] decryptedBytes = aes.decrypt(encryptedBytes);
return new String(decryptedBytes, java.nio.charset.StandardCharsets.UTF_8);
}
}

View File

@@ -17,4 +17,59 @@
left join tb_call_table on tb_call_queue.call_table_id = tb_call_table.id
${qwSql}
</select>
<select id="selectInfoByOpenId" resultType="com.czg.account.vo.CallQueueInfoVO">
SELECT
d.shop_name,
d.logo,
d.status AS shop_state,
a.call_num,
a.id, -- 用户的排队记录ID
a.state,
a.user_id, -- 用户ID
b.name AS table_name, -- 桌子名称
b.note AS table_note, -- 桌子备注
(
SELECT COUNT(1)
FROM tb_call_queue c
WHERE
c.call_table_id = a.call_table_id
and c.shop_id=a.shop_id -- 同一张桌子
AND c.create_time &lt; a.create_time -- 在当前用户之前排队
AND c.state IN (0, 1) -- 排队中或等待中的人
AND c.create_day=#{today}
) AS waiting_count, -- 前面有几个人
(
SELECT COUNT(1) * b.wait_time
FROM tb_call_queue c
WHERE
c.call_table_id = a.call_table_id
AND c.shop_id=a.shop_id -- 同一张桌子
AND c.create_time &lt; a.create_time -- 在当前用户之前排队
AND c.state IN (0, 1) -- 排队中或等待中的人
AND c.create_day=#{today}
) AS wait_time -- 预计等待时间
FROM
tb_call_queue a
LEFT JOIN
tb_shop_info d ON a.shop_id = d.id
LEFT JOIN
tb_call_table b ON a.call_table_id = b.id
WHERE
a.shop_id = #{shopId}
AND a.create_day = #{today} -- 替换为目标日期
<if test="queueId != null">
and a.id = #{queueId} and (a.open_id = #{openId} or a.open_id is null)
</if>
<if test="queueId == null">
and a.open_id = #{openId} -- 替换为目标用户的 open_id
</if>
and a.state in (0, 1)
GROUP BY
a.id, a.user_id, b.name, b.note, b.wait_time
ORDER BY
a.create_time asc
</select>
</mapper>

View File

@@ -20,5 +20,6 @@
a.create_time &lt;= #{endTime}
</if>
</where>
order by a.create_time desc
</select>
</mapper>

View File

@@ -41,7 +41,7 @@
<select id="selectAssetsSummary" resultType="com.czg.account.dto.user.userinfo.UserInfoAssetsSummaryDTO">
select sum(IFNULL(b.amount, 0)) as amount,
sum(IFNULL(b.account_points, 0)) as points,
sum(IFNULL(c.id, 0)) as couponNum
count(c.id) as couponNum
from tb_user_info as a
left join tb_shop_user as b on a.id = b.user_id
left join tb_shop_activate_coupon_record as c
@@ -50,11 +50,13 @@
</select>
<select id="selectPageByKeyAndIsVip" resultType="com.czg.account.dto.shopuser.ShopUserDTO">
SELECT
a.*, count(c.id) couponNum
a.*, count(c.id) couponNum, count(d.id) orderNumber, IFNULL(sum(f.amount), 0) rechargeAmount
FROM
tb_shop_user a
LEFT JOIN tb_user_info b ON b.id = a.user_id
left join tb_shop_activate_coupon_record c on c.shop_user_id=a.id and c.`status`=0
left join tb_order_info as d on d.user_id=a.user_id and d.shop_id=a.shop_id
left join tb_shop_user_flow as f on f.user_id=a.user_id and f.shop_id=a.shop_id and f.biz_code in ('cashIn', 'wechatIn', 'alipayIn')
where a.shop_id=#{shopId}
<if test="isVip != null">

View File

@@ -4,4 +4,25 @@
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.czg.service.account.mapper.SysUserMapper">
<select id="page" resultType="com.czg.account.vo.SysUserDetailVO">
select a.*, b.role_id from sys_user as a
left join sys_users_roles as b on a.id=b.user_id
<where>
<if test="key != null and key != ''">
and (a.nick_name like concat('%', #{key}, '%') or a.account like concat('%', #{key}, '%'))
</if>
<if test="startTime != null and startTime != ''">
and a.create_time >= #{startTime}
</if>
<if test="endTime != null and endTime != ''">
and a.create_time &lt;= #{endTime}
</if>
<if test="status != null">
and a.status=#{status}
</if>
</where>
order by a.create_time desc
</select>
</mapper>

View File

@@ -162,7 +162,7 @@ public interface PrinterImpl {
StringBuilder builder = new StringBuilder()
.append(getFormatLabel(handoverRecord.getShopName(), signLabelInfo.center, signLabelInfo.f)).append(signLabelInfo.br)
.append(getFormatLabel("交班小票", signLabelInfo.l,signLabelInfo.center)).append(signLabelInfo.br)
.append("交班时间: ").append(handoverRecord.getHandoverTime()).append(signLabelInfo.br)
.append("交班时间: ").append(DateUtil.format(handoverRecord.getHandoverTime(), "yyyy-MM-dd HH:mm:ss")).append(signLabelInfo.br)
.append("收银员: ").append(handoverRecord.getStaffName()).append(signLabelInfo.br)
.append("当班总收入: ").append(handoverRecord.getHandAmount()).append(signLabelInfo.br)
.append("现金收入: ").append(handoverRecord.getCashAmount()).append(signLabelInfo.br)
@@ -303,7 +303,7 @@ public interface PrinterImpl {
data.append(getFormatLabel(StrUtil.format("原价:{}", toPlainStr(printInfoDTO.getOriginalAmount())), signLabelInfo.s))
.append(signLabelInfo.br);
// data.append(StrUtil.format("<S>原价:{}</S><BR>", toPlainStr(printInfoDTO.getOriginalAmount())));
data.append(getFormatLabel(StrUtil.format("折扣-{}", toPlainStr(printInfoDTO.getDiscountAmount())), signLabelInfo.s))
data.append(getFormatLabel(StrUtil.format("优惠-{}", toPlainStr(printInfoDTO.getDiscountAmount())), signLabelInfo.s))
.append(signLabelInfo.br);
// data.append(StrUtil.format("<S>折扣:-{}</S><BR>", toPlainStr(printInfoDTO.getDiscountAmount())));
}
@@ -330,12 +330,13 @@ public interface PrinterImpl {
data.append(getFormatLabel(StrUtil.format("积分:{}", printInfoDTO.getIntegral()), signLabelInfo.s))
.append(signLabelInfo.br);
// data.append(StrUtil.format("<S>积分:{}</S><BR>", printInfoDTO.getIntegral()));
}
data.append(getFormatLabel(StrUtil.format("余额:{}", toPlainStr(printInfoDTO.getBalance())), signLabelInfo.s))
.append(signLabelInfo.br);
data.append(getFormatLabel(StrUtil.format("余额:{}", toPlainStr(printInfoDTO.getBalance())), signLabelInfo.s))
.append(signLabelInfo.br);
// data.append(StrUtil.format("<S>余额:{}</S><BR>", toPlainStr(printInfoDTO.getBalance())));
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
.append(signLabelInfo.br);
data.append(getFormatLabel("--------------------------------", signLabelInfo.s))
.append(signLabelInfo.br);
}
// data.append("<S>--------------------------------</S><BR>");
if (StrUtil.isNotBlank(printInfoDTO.getRemark())) {
data.append(getFormatLabel(StrUtil.format("备注:{}", printInfoDTO.getRemark()), signLabelInfo.l, signLabelInfo.bold))

View File

@@ -319,8 +319,8 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
BigDecimalDTO packAmount = new BigDecimalDTO(BigDecimal.ZERO);
processOrderDetails2(orderDetails, prodCouponMap, prodCouponAmount, totalAmount, packAmount, param.isAllPack(), param.getUserAllPack(), param.isVipPrice());
//总商品支付金额 不包含打包费 用来计算后续
log.info("支付前置,商品金额{} 商品优惠券金额{} 总金额{}", totalAmount, prodCouponAmount, totalAmount.getPrice().add(orderInfo.getPackFee()));
if (prodCouponAmount.getPrice().compareTo(param.getProductCouponDiscountAmount()) != 0) {
log.info("支付计算金额不正确:商品券抵扣金额为:{},传递为:{}", prodCouponAmount.getPrice(), param.getProductCouponDiscountAmount());
throw new ValidateException("生成支付订单失败,商品优惠券优惠金额不正确");
}
orderInfo.setOriginAmount(totalAmount.getPrice().add(packAmount.getPrice()).add(orderInfo.getSeatAmount()));
@@ -352,16 +352,15 @@ public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo
// throw new ValidateException("生成支付订单失败,积分抵扣金额不正确");
// }
// }
log.info("支付前置2订单金额{} ", newTotalAmount);
newTotalAmount = newTotalAmount.subtract(param.getPointsDiscountAmount());
log.info("支付前置3订单金额{} ", newTotalAmount);
//抹零
newTotalAmount = newTotalAmount.subtract(param.getRoundAmount());
log.info("支付前置4订单金额{} ", newTotalAmount);
//校验最终金额(订单金额 (扣除各类折扣)+打包费 餐位费)
newTotalAmount = newTotalAmount.add(packAmount.getPrice()).add(orderInfo.getSeatAmount());
log.info("支付前置5订单金额{} ", newTotalAmount);
if (newTotalAmount.compareTo(param.getOrderAmount()) != 0) {
log.info("支付计算金额不正确订单Id:{},最终计算金额为:{},打包费:{},餐位费:{},商品券金额:{},满减券金额:{},积分抵扣金额:{},抹零金额:{}",
orderInfo.getId(), newTotalAmount, packAmount.getPrice(), orderInfo.getSeatAmount(), param.getProductCouponDiscountAmount(),
discountAmount.getPrice(), param.getPointsDiscountAmount(), param.getRoundAmount());
throw new ValidateException("生成支付订单失败,订单金额不正确");
}
orderInfo.setPackFee(packAmount.getPrice());

View File

@@ -44,7 +44,6 @@ import com.czg.utils.AssertUtil;
import com.czg.utils.MD5Util;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import io.seata.spring.annotation.GlobalTransactional;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotBlank;
import lombok.NonNull;
@@ -87,6 +86,8 @@ public class PayServiceImpl implements PayService {
private ShopCouponService couponService;
@DubboReference
private MemberPointsService pointsService;
@DubboReference
private FreeDineConfigService freeConfigService;
@Resource
private CzgPayService czgPayService;
@Resource
@@ -147,6 +148,11 @@ public class PayServiceImpl implements PayService {
throw new ValidateException("充值金额不正确");
}
if (payParam.getOrderId() != null) {
FreeDineConfig freeConfig = freeConfigService.getById(payParam.getShopId());
AssertUtil.isNull(freeConfig, "该店铺未启用霸王餐");
if (!freeConfig.getEnable()) {
throw new CzgException("该店铺未启用霸王餐");
}
OrderInfo orderInfo = orderInfoService.getById(payParam.getOrderId());
AssertUtil.isNull(orderInfo, "订单不存在");
//获取商品信息 计算金额 需要传入优惠券 减去优惠券
@@ -156,7 +162,12 @@ public class PayServiceImpl implements PayService {
//最终打包费
BigDecimalDTO packAmount = new BigDecimalDTO(BigDecimal.ZERO);
orderInfoService.processOrderDetails2(orderDetails, null, null, totalAmount, packAmount, payParam.isAllPack(), null, true);
BigDecimal payAmount = (totalAmount.getPrice().add(packAmount.getPrice())).multiply(BigDecimal.TWO);
BigDecimal total = totalAmount.getPrice().add(packAmount.getPrice());
if (total.compareTo(freeConfig.getRechargeThreshold()) < 0) {
throw new CzgException("霸王餐满" + freeConfig.getRechargeThreshold() + "可用,当前订单金额为" + total);
}
BigDecimal payAmount = (totalAmount.getPrice().add(packAmount.getPrice())).multiply(new BigDecimal(freeConfig.getMultiple()));
log.info("霸王餐应支付金额:{},充值金额为:{}", payAmount, payParam.getAmount());
if (payAmount.compareTo(payParam.getAmount()) != 0) {
throw new ValidateException("霸王餐支付金额不正确");
}
@@ -341,7 +352,6 @@ public class PayServiceImpl implements PayService {
@Override
@Transactional
public CzgResult<Object> cashPayVip(VipPayParamDTO payParam) {
boolean isFree = checkPayVip(payParam);
ShopUser shopUser = shopUserService.getById(payParam.getShopUserId());
AssertUtil.isNull(shopUser, "充值失败 该店铺用户不存在");
ShopInfo shopInfo = shopInfoService.getById(payParam.getShopId());
@@ -360,11 +370,6 @@ public class PayServiceImpl implements PayService {
updateInfo.setJoinTime(LocalDateTime.now());
updateInfo.setId(payParam.getShopUserId());
shopUserService.updateById(updateInfo);
// UpdateChain.of(ShopUser.class)
// .set(ShopUser::getIsVip, 1)
// .set(ShopUser::getJoinTime, LocalDateTime.now())
// .eq(ShopUser::getId, payParam.getShopUserId())
// .update();
}
ShopUserMoneyEditDTO shopUserMoneyEditDTO = new ShopUserMoneyEditDTO()
.setId(shopUser.getId())
@@ -372,20 +377,10 @@ public class PayServiceImpl implements PayService {
.setType(1)
.setRemark("现金充值")
.setBizEnum(ShopUserFlowBizEnum.CASH_IN);
if (isFree) {
shopUserMoneyEditDTO.setBizEnum(ShopUserFlowBizEnum.FREE_IN);
UpdateChain.of(OrderInfo.class).eq(OrderInfo::getId, payParam.getOrderId())
.set(OrderInfo::getStatus, OrderStatusEnums.DONE.getCode())
.set(OrderInfo::getIsFreeDine, 1)
.set(OrderInfo::getPayAmount, 0)
.update();
}
//更新会员余额 并生成流水
Long flowId = shopUserService.updateMoney(shopUser.getShopId(), shopUserMoneyEditDTO);
if (!isFree) {
//会员活动
shopActivateService.giveActivate(shopUser, payParam.getAmount(), payParam.getActivateId(), flowId);
}
//会员活动
shopActivateService.giveActivate(shopUser, payParam.getAmount(), payParam.getActivateId(), flowId);
return CzgResult.success();
}
@@ -557,8 +552,7 @@ public class PayServiceImpl implements PayService {
}
@Override
@GlobalTransactional
// @Transactional
@Transactional
public CzgResult<Object> refundOrderBefore(OrderInfoRefundDTO param) {
OrderInfo orderInfo = orderInfoService.getById(param.getOrderId());
ShopInfo shopInfo = shopInfoService.getById(orderInfo.getShopId());
@@ -569,7 +563,7 @@ public class PayServiceImpl implements PayService {
isPay = false;
refPayOrderNo = "";
}
if(isPay){
if (isPay) {
if (shopInfo.getIsReturnPwd().equals(1)) {
AssertUtil.isBlank(shopInfo.getOperationPwd(), "请设置操作密码后使用");
if (!SecureUtil.md5(param.getPwd()).equals(shopInfo.getOperationPwd())) {

View File

@@ -78,8 +78,8 @@
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
<groupId>io.seata</groupId>
<artifactId>seata-spring-boot-starter</artifactId>
</dependency>
<dependency>