diff --git a/pom.xml b/pom.xml
index a329465..26116b3 100644
--- a/pom.xml
+++ b/pom.xml
@@ -70,6 +70,12 @@
hutool-all
5.8.24
+
+
+ com.google.guava
+ guava
+ 32.1.3-jre
+
org.springframework.boot
spring-boot-starter-web
diff --git a/src/main/java/com/example/demo/config/RateLimitUtil.java b/src/main/java/com/example/demo/config/RateLimitUtil.java
new file mode 100644
index 0000000..12453b5
--- /dev/null
+++ b/src/main/java/com/example/demo/config/RateLimitUtil.java
@@ -0,0 +1,39 @@
+package com.example.demo.config;
+
+import com.google.common.cache.Cache;
+import com.google.common.cache.CacheBuilder;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 本地限流工具类(基于Guava Cache)
+ */
+public class RateLimitUtil {
+ // 缓存:key=限流标识(用户ID/IP),value=占位符(无实际意义)
+ private static final Cache RATE_LIMIT_CACHE = CacheBuilder.newBuilder()
+ .expireAfterWrite(3, TimeUnit.SECONDS) // 3秒后自动过期(时间窗口)
+ .maximumSize(5000) // 最大缓存容量(防止内存溢出,根据用户量调整)
+ .build();
+
+ /**
+ * 判断是否允许请求
+ * @param key 限流唯一标识(如用户ID、IP)
+ * @return true=允许请求,false=限流中
+ */
+ public static boolean isAllowed(String key) {
+ // 1. 尝试从缓存获取key,存在则说明3秒内已请求过(限流)
+ if (RATE_LIMIT_CACHE.getIfPresent(key) != null) {
+ return false;
+ }
+ // 2. 缓存中不存在,存入缓存(占位符用new Object()即可)
+ RATE_LIMIT_CACHE.put(key, new Object());
+ return true;
+ }
+
+ /**
+ * 手动移除限流标识(如接口执行失败时,释放限流)
+ * @param key 限流唯一标识
+ */
+ public static void removeKey(String key) {
+ RATE_LIMIT_CACHE.invalidate(key);
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/example/demo/controller/cash/CashRefundController.java b/src/main/java/com/example/demo/controller/cash/CashRefundController.java
index d3d0281..6f0339e 100644
--- a/src/main/java/com/example/demo/controller/cash/CashRefundController.java
+++ b/src/main/java/com/example/demo/controller/cash/CashRefundController.java
@@ -2,6 +2,7 @@ package com.example.demo.controller.cash;
import com.example.demo.Util.JWTUtil;
+import com.example.demo.config.RateLimitUtil;
import com.example.demo.domain.entity.Admin;
import com.example.demo.domain.vo.cash.CashRecordDTO;
import com.example.demo.domain.vo.cash.CashRecordDone;
@@ -26,6 +27,7 @@ import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.Arrays;
import java.util.List;
+import java.util.Objects;
/**
* @program: GOLD
@@ -196,9 +198,38 @@ public class CashRefundController {
}
}
@PostMapping("/finalReview")
- public Result finalReview(@RequestBody CashRecordDone cashRecordDone) {
- return Result.success(refundService.finalreview(cashRecordDone));
- }
+ public Result finalReview(@RequestBody CashRecordDone cashRecordDone,HttpServletRequest request) {
+ {
+ // --------------- 限流逻辑开始 ---------------
+ String limitKey = null;
+ try {
+ // 1. 优先用「用户ID」作为限流标识(从token解析,精准限流)
+ HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+ String token = req.getHeader("token");
+ Admin admin = (Admin) JWTUtil.getUserDetailsList(String.valueOf(token), Admin.class);
+ if (admin != null && admin.getId() != null) {
+ limitKey = "finalReview_" + admin.getId(); // 格式:接口名_用户ID
+ }
+ } catch (Exception e) {
+ // token解析失败(用户未登录),降级用「IP地址」限流
+ limitKey = "finalReview_" + getIpAddress(request); // 格式:接口名_IP
+ }
+
+ // 2. 校验限流:3秒内同一key不允许重复请求
+ if (Objects.isNull(limitKey) || !RateLimitUtil.isAllowed(limitKey)) {
+ return Result.error("3秒内只能请求一次,请稍后再试"); // 限流提示
+ }
+ // --------------- 限流逻辑结束 ---------------
+
+ try {
+ // 原有业务逻辑:执行最终审核
+ return Result.success(refundService.finalreview(cashRecordDone));
+ } catch (Exception e) {
+ // 接口执行失败时,移除限流标识(允许用户重新尝试)
+ RateLimitUtil.removeKey(limitKey);
+ return Result.error("审核失败:" + e.getMessage());
+ }
+ }}
@PostMapping("/executor")
public Result executor(@RequestBody CashRecordDone cashRecordDone) throws Exception {
try {
@@ -239,4 +270,25 @@ public class CashRefundController {
public Result ceshi() {
return Result.success("测试消息");
}
+
+ /**
+ * 辅助方法:获取用户真实IP(处理反向代理/负载均衡场景)
+ */
+ private String getIpAddress(HttpServletRequest request) {
+ String ip = request.getHeader("x-forwarded-for");
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getHeader("WL-Proxy-Client-IP");
+ }
+ if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+ ip = request.getRemoteAddr();
+ }
+ // 多IP场景(如多层代理),取第一个非unknown的IP
+ if (ip != null && ip.contains(",")) {
+ ip = ip.split(",")[0].trim();
+ }
+ return ip;
+ }
}
diff --git a/src/main/java/com/example/demo/domain/entity/User.java b/src/main/java/com/example/demo/domain/entity/User.java
index 1dda6e9..1fee4db 100644
--- a/src/main/java/com/example/demo/domain/entity/User.java
+++ b/src/main/java/com/example/demo/domain/entity/User.java
@@ -28,6 +28,7 @@ public class User implements Serializable {
private String name; // 客户姓名
@ExcelProperty("所属地区")
private String market; // 所属地区
+ @ExcelIgnore
private String marketName; // 所属地区
@ExcelIgnore
private BigDecimal sumPermanentGold; // 历史永久金币
diff --git a/src/main/java/com/example/demo/domain/vo/cash/CashCollection.java b/src/main/java/com/example/demo/domain/vo/cash/CashCollection.java
index 322615d..7d06b5e 100644
--- a/src/main/java/com/example/demo/domain/vo/cash/CashCollection.java
+++ b/src/main/java/com/example/demo/domain/vo/cash/CashCollection.java
@@ -30,6 +30,7 @@ public class CashCollection implements Serializable {
@ExcelProperty("序号")
private Integer id;
//订单信息
+ @ExcelIgnore
private Integer orderType; // 订单类型:1-收款,2-退款
@ExcelProperty("精网号")
private Integer jwcode; // 精网号
@@ -68,7 +69,7 @@ public class CashCollection implements Serializable {
private BigDecimal receivedAmount; // 到账金额
@ExcelProperty("手续费")
private BigDecimal handlingCharge; // 手续费
- @ExcelProperty("到账币种")
+ @ExcelProperty("到账地区")
private String receivedMarket; //到账地区
// 支付信息
@ExcelProperty("支付方式")
@@ -90,7 +91,7 @@ public class CashCollection implements Serializable {
private String submitterName; // 提交人 姓名
@ExcelProperty("转账凭证")
private String voucher; // 转账凭证
- @ExcelIgnore
+ @ExcelProperty("备注")
private String remark; // 备注
@ExcelIgnore
private String receivedRemark; //到账备注
diff --git a/src/main/java/com/example/demo/domain/vo/cash/CashRecordDone.java b/src/main/java/com/example/demo/domain/vo/cash/CashRecordDone.java
index 170f203..41215e6 100644
--- a/src/main/java/com/example/demo/domain/vo/cash/CashRecordDone.java
+++ b/src/main/java/com/example/demo/domain/vo/cash/CashRecordDone.java
@@ -119,6 +119,9 @@ public class CashRecordDone {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date eTime; // 结束时间
private Integer relatedId;
+ private BigDecimal NewRefundGold;
+ private BigDecimal NewRefundFree;
+ private Integer adminId;
}
\ No newline at end of file
diff --git a/src/main/java/com/example/demo/domain/vo/coin/GoldUser.java b/src/main/java/com/example/demo/domain/vo/coin/GoldUser.java
index 8fa5110..515f82d 100644
--- a/src/main/java/com/example/demo/domain/vo/coin/GoldUser.java
+++ b/src/main/java/com/example/demo/domain/vo/coin/GoldUser.java
@@ -1,5 +1,6 @@
package com.example.demo.domain.vo.coin;
+import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
@@ -56,5 +57,6 @@ public class GoldUser {
@ExcelProperty("首充日期")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai")
private Date firstRecharge; // 首充日期
+ @ExcelIgnore
private List markets; // 地区列表
}
diff --git a/src/main/java/com/example/demo/domain/vo/coin/RechargeActivity.java b/src/main/java/com/example/demo/domain/vo/coin/RechargeActivity.java
index 97a2ae3..763eb2e 100644
--- a/src/main/java/com/example/demo/domain/vo/coin/RechargeActivity.java
+++ b/src/main/java/com/example/demo/domain/vo/coin/RechargeActivity.java
@@ -1,5 +1,6 @@
package com.example.demo.domain.vo.coin;
+import com.alibaba.excel.annotation.ExcelIgnore;
import com.alibaba.excel.annotation.ExcelProperty;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.AllArgsConstructor;
@@ -30,7 +31,7 @@ public class RechargeActivity {
@ExcelProperty("业绩归属地")
private String businessBelong; // 业绩归属地
-
+ @ExcelIgnore
private String area; // 地区
@ExcelProperty("地区")
diff --git a/src/main/java/com/example/demo/mapper/cash/CashCollectionMapper.java b/src/main/java/com/example/demo/mapper/cash/CashCollectionMapper.java
index ecbb39f..976a803 100644
--- a/src/main/java/com/example/demo/mapper/cash/CashCollectionMapper.java
+++ b/src/main/java/com/example/demo/mapper/cash/CashCollectionMapper.java
@@ -51,7 +51,7 @@ public interface CashCollectionMapper {
//根据精网号获取市场名
String getMarketNameByJwcode(Integer jwcode);
//获取收款活动列表
- List getActivityList();
+ List getActivityList(@Param("now")LocalDateTime now);
//查找未同步的订单
ListgetUnSync(@Param("size")int size);
//给同步过去的gOrder设置同步状态
diff --git a/src/main/java/com/example/demo/serviceImpl/bean/BeanConsumeServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/bean/BeanConsumeServiceImpl.java
index 6b50165..44cb3e4 100644
--- a/src/main/java/com/example/demo/serviceImpl/bean/BeanConsumeServiceImpl.java
+++ b/src/main/java/com/example/demo/serviceImpl/bean/BeanConsumeServiceImpl.java
@@ -158,7 +158,7 @@ public class BeanConsumeServiceImpl implements BeanConsumeService {
//筛选查询直播消费
@Override
public Object selectLiveBy(Integer pageNum, Integer pageSize, BeanConsumeLive beanConsumeLive) {
- PageHelper.startPage(pageNum, pageSize);
+
String channel=roleMapper.getChannel(beanConsumeLive.getRoleId());
if (channel==null){
return "角色频道有误";
@@ -166,7 +166,7 @@ public class BeanConsumeServiceImpl implements BeanConsumeService {
if (!channel.equals("全部")){
beanConsumeLive.setLiveChannel(channel);
}
-
+ PageHelper.startPage(pageNum, pageSize);
List beanConsumeLives = liveMapper.selectLiveBy(beanConsumeLive);
//int total = liveMapper.selectLiveCount(beanConsumeLive);
return new PageInfo<>(beanConsumeLives);
@@ -174,7 +174,7 @@ public class BeanConsumeServiceImpl implements BeanConsumeService {
//筛选查询铁粉消费
@Override
public Object selectFanBy(Integer pageNum, Integer pageSize, BeanConsumeFan beanConsumeFan) {
- PageHelper.startPage(pageNum, pageSize);
+
String channel=roleMapper.getChannel(beanConsumeFan.getRoleId());
if (channel==null){
return "角色频道有误";
@@ -182,6 +182,7 @@ public class BeanConsumeServiceImpl implements BeanConsumeService {
if (!channel.equals("全部")){
beanConsumeFan.setChannel(channel);
}
+ PageHelper.startPage(pageNum, pageSize);
List beanConsumeFans = beanConsumeMapper.selectFanBy(beanConsumeFan);
return new PageInfo<>(beanConsumeFans);
}
diff --git a/src/main/java/com/example/demo/serviceImpl/cash/CashAuditServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/cash/CashAuditServiceImpl.java
index 69f2a40..328c554 100644
--- a/src/main/java/com/example/demo/serviceImpl/cash/CashAuditServiceImpl.java
+++ b/src/main/java/com/example/demo/serviceImpl/cash/CashAuditServiceImpl.java
@@ -6,6 +6,7 @@ import com.example.demo.domain.entity.CashRecord;
import com.example.demo.domain.entity.User;
import com.example.demo.domain.entity.UserGoldRecord;
import com.example.demo.domain.vo.cash.CashCollectionMessage;
+import com.example.demo.domain.vo.coin.Messages;
import com.example.demo.mapper.cash.CashAuditMapper;
import com.example.demo.mapper.cash.CashCollectionMapper;
import com.example.demo.mapper.coin.AuditMapper;
@@ -130,17 +131,16 @@ public class CashAuditServiceImpl implements CashAuditService {
//更新订单
cashAuditMapper.updateOrder(updateOrder);
// 创建消息队列,用于发送审核结果通知
- CashCollectionMessage message = new CashCollectionMessage();
- message.setId(order.getId());
- message.setOrderCode(orderCode);
+ Messages message = new Messages();
+ message.setJwcode(order.getJwcode());
+ message.setName(order.getName());
message.setStatus(updateOrder.getStatus());
- message.setStatusDescription(action == 1 ? "线下财务审核通过待填手续费" : "线下财务审核驳回");
- message.setMessage(action == 1 ? "收款订单审核通过" : "收款订单审核驳回");
- message.setSubmitterId(order.getSubmitterId());
- message.setAuditId(auditId);
- message.setAuditName(auditName);
- message.setTimestamp(LocalDateTime.now());
-
+ message.setDesc(order.getJwcode() + action==1?"收款记录需补充手续费,前往填写":"现金收款申请已被驳回,前往查看驳回理");
+ message.setTitle(action==1?"收款订单审核通过":"收款订单审核驳回");
+ message.setType(1);
+ message.setTypeId(order.getId());
+ message.setMarket(Integer.valueOf(order.getMarket()));
+ rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_COLLECTION_EXCHANGE, "cash.collection.save", message);
// 根据审核结果发送不同的消息
if (action == 1) {
// 发送审核通过消息
diff --git a/src/main/java/com/example/demo/serviceImpl/cash/CashCollectionServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/cash/CashCollectionServiceImpl.java
index 891dd33..6e0e9bc 100644
--- a/src/main/java/com/example/demo/serviceImpl/cash/CashCollectionServiceImpl.java
+++ b/src/main/java/com/example/demo/serviceImpl/cash/CashCollectionServiceImpl.java
@@ -132,7 +132,7 @@ public class CashCollectionServiceImpl implements CashCollectionService {
message.setJwcode(cashRecord.getJwcode());
message.setName(cashRecord.getName());
message.setStatus(cashRecord.getStatus());
- message.setDesc(cashRecord.getJwcode()+"用户有条收款订单需审核");
+ message.setDesc(cashRecord.getJwcode()+"用户的现金收款申请待审核,请前往审核");
message.setTitle("现金收款--新增收款");
message.setType(1);
message.setTypeId(cashRecord.getId());
@@ -326,7 +326,8 @@ public User getNameAndMarket(Integer jwcode) {
//获取收款活动列表
@Override
public List getActivityList() {
- return cashCollectionMapper.getActivityList();
+ LocalDateTime now = LocalDateTime.now();
+ return cashCollectionMapper.getActivityList(now);
}
//同步g_order订单到cash_record表
diff --git a/src/main/java/com/example/demo/serviceImpl/cash/CashRefundServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/cash/CashRefundServiceImpl.java
index bce68b5..cf01b1b 100644
--- a/src/main/java/com/example/demo/serviceImpl/cash/CashRefundServiceImpl.java
+++ b/src/main/java/com/example/demo/serviceImpl/cash/CashRefundServiceImpl.java
@@ -204,7 +204,7 @@ public class CashRefundServiceImpl implements RefundService {
message.setJwcode(cashRecordRefund.getJwcode());
message.setName(cashRecordRefund.getName());
message.setStatus(cashRecordRefund.getStatus());
- message.setDesc(cashRecordRefund.getJwcode()+"用户有条退款订单需审核");
+ message.setDesc(cashRecordRefund.getJwcode()+"用户的客服退款申请待审核,前往处理");
message.setTitle("现金退款--新增退款");
message.setType(0);
message.setTypeId(cashRecordRefund.getId());
@@ -232,8 +232,28 @@ public class CashRefundServiceImpl implements RefundService {
if (cashRecordDone.getRefundReason()== null) {
throw new RuntimeException("请填写退款理由");
}
+ if(cashRecordDone.getNewRefundGold()== null){
+ cashRecordDone.setNewRefundGold(BigDecimal.valueOf(0));
+ }
+ if(cashRecordDone.getNewRefundFree()== null){
+ cashRecordDone.setNewRefundFree(BigDecimal.valueOf(0));
+ }
int result = cashRefundMapper.update(cashRecordDone);
- return (result > 0 ? Result.success("提交成功") : Result.error("提交失败")).getCode();
+ CashRecordDTO cashRecordDTO = cashRefundMapper.selectById(cashRecordDone.getId());
+ if (result > 0) {
+ // 发送审核消息
+ Messages message = new Messages();
+ message.setJwcode(cashRecordDTO.getJwcode());
+ message.setName(cashRecordDTO.getName());
+ message.setStatus(cashRecordDTO.getStatus());
+ message.setDesc(cashRecordDTO.getJwcode() + "用户的退款申请待审核,前往处理");
+ message.setTitle("现金退款--当地退款审核(编辑后提交)");
+ message.setType(1);
+ message.setTypeId(cashRecordDTO.getId());
+ message.setMarket(cashRecordDTO.getMarket());
+ rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_REFUND_EXCHANGE, "cash.refund.save", message);
+ }
+ return (result > 0 ? Result.success("提交成功") : Result.error("提交失败")).getCode();
}
@Override
@@ -263,15 +283,14 @@ CashRecordDone cashRecordDone1 = new CashRecordDone();
message.setJwcode(cashRecordDTO.getJwcode());
message.setName(cashRecordDTO.getName());
message.setStatus(cashRecordDTO.getStatus());
- message.setDesc(cashRecordDTO.getJwcode()+"用户有条退款订单需审核");
+ message.setDesc(cashRecordDTO.getJwcode()+cashRecordDTO.getStatus()!=12|| cashRecordDTO.getStatus()!=22?"用户的退款申请待审核,前往处理":"用户的现金退款申请已被驳回,前往查看详情");
message.setTitle("现金退款--当地退款审核");
message.setType(1);
message.setTypeId(cashRecordDTO.getId());
message.setMarket(cashRecordDTO.getMarket());
- if (cashRecordDTO.getStatus() != 12 || cashRecordDTO.getStatus() != 22) {
rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_REFUND_EXCHANGE, "cash.refund.save", message);
- }
+
}
return (result > 0 ? Result.success("提交成功") : Result.error("提交失败")).getCode();
@@ -346,7 +365,7 @@ CashRecordDone cashRecordDone1 = new CashRecordDone();
userGoldRecord.setGoodsName(cashRecordDone.getGoodsName());
userGoldRecord.setPayPlatform("金币系统");
userGoldRecord.setRemark(cashRecordDone.getRemark());
- userGoldRecord.setAdminId(cashRecordDone.getAuditId());
+ userGoldRecord.setAdminId(cashRecordDone.getAdminId());
userGoldRecord.setAuditStatus(1);
userGoldRecord.setTaskGold(0);
userGoldRecord.setCreateTime(new Date());
@@ -372,15 +391,12 @@ CashRecordDone cashRecordDone1 = new CashRecordDone();
message.setJwcode(cashRecordDTO.getJwcode());
message.setName(cashRecordDTO.getName());
message.setStatus(cashRecordDTO.getStatus());
- message.setDesc(cashRecordDTO.getJwcode()+"用户有条退款订单需审核");
+ message.setDesc(cashRecordDTO.getJwcode()+cashRecordDTO.getStatus()!=32?"用户的退款申请待审核,前往处理":"用户的现金退款申请已被驳回,前往查看详情");
message.setTitle("现金退款--执行人退款提交");
message.setType(1);
message.setTypeId(cashRecordDTO.getId());
message.setMarket(cashRecordDTO.getMarket());
- if (cashRecordDTO.getStatus() != 32) {
- rabbitTemplate.convertAndSend(RabbitMQConfig.CASH_REFUND_EXCHANGE, "cash.refund.save", message);
- }
}
return (result > 0 ? Result.success("提交成功") : Result.error("提交失败")).getCode();
}
diff --git a/src/main/java/com/example/demo/serviceImpl/cash/MessageServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/cash/MessageServiceImpl.java
index cffadd4..ff3e85a 100644
--- a/src/main/java/com/example/demo/serviceImpl/cash/MessageServiceImpl.java
+++ b/src/main/java/com/example/demo/serviceImpl/cash/MessageServiceImpl.java
@@ -24,6 +24,9 @@ public class MessageServiceImpl implements MessageService {
private MessageMapper messageMapper;
@Override
public List getMessage(List markets, List status) {
+ if(status== null|| status.size()==0){
+ status.add(99);
+ }
return messageMapper.getMessage(markets, status) ;
}
diff --git a/src/main/resources/cashMapper/CashCollectionMapper.xml b/src/main/resources/cashMapper/CashCollectionMapper.xml
index ab2423c..61119b2 100644
--- a/src/main/resources/cashMapper/CashCollectionMapper.xml
+++ b/src/main/resources/cashMapper/CashCollectionMapper.xml
@@ -222,7 +222,7 @@
select ra.id,ra.activity_name,ra.business_belong,m.name as area,ra.status
from recharge_activity ra
left join market m on m.id=ra.area
- where ra.flag=1
+ where ra.flag=1 and ra.status=1 and #{now} between start_time and end_time