You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

294 lines
12 KiB

1 month ago
1 month ago
1 month ago
1 month ago
  1. package com.example.demo.controller.cash;
  2. import com.example.demo.Util.JWTUtil;
  3. import com.example.demo.config.RateLimitUtil;
  4. import com.example.demo.domain.entity.Admin;
  5. import com.example.demo.domain.vo.cash.CashRecordDTO;
  6. import com.example.demo.domain.vo.cash.CashRecordDone;
  7. import com.example.demo.domain.vo.cash.CashRecordRefund;
  8. import com.example.demo.domain.vo.coin.Page;
  9. import com.example.demo.domain.vo.coin.RechargeUser;
  10. import com.example.demo.domain.vo.coin.Result;
  11. import com.example.demo.service.cash.RefundService;
  12. import com.example.demo.service.coin.MarketService;
  13. import jakarta.annotation.Resource;
  14. import jakarta.servlet.http.HttpServletRequest;
  15. import lombok.RequiredArgsConstructor;
  16. import lombok.extern.slf4j.Slf4j;
  17. import org.apache.commons.lang3.StringUtils;
  18. import org.springframework.beans.factory.annotation.Autowired;
  19. import org.springframework.util.ObjectUtils;
  20. import org.springframework.web.bind.annotation.*;
  21. import org.springframework.web.context.request.RequestContextHolder;
  22. import org.springframework.web.context.request.ServletRequestAttributes;
  23. import java.util.Arrays;
  24. import java.util.List;
  25. import java.util.Objects;
  26. /**
  27. * @program: GOLD
  28. * @ClassName RefundController
  29. * @description:
  30. * @author: huangqizhen
  31. * @create: 202509-26 14:15
  32. * @Version 1.0
  33. **/
  34. @RestController
  35. @RequestMapping("/Money")
  36. @RequiredArgsConstructor
  37. @Slf4j
  38. @CrossOrigin
  39. public class CashRefundController {
  40. @Autowired
  41. private RefundService refundService;
  42. @Autowired
  43. MarketService marketService;
  44. /**
  45. * 当地财务负责人退款记录
  46. */
  47. @PostMapping("/select")
  48. public Result select(@RequestBody Page page) throws Exception {
  49. // 获取当前请求对象
  50. HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  51. String token = request.getHeader("token");
  52. // 解析 token 获取用户信息
  53. Admin admin = (Admin) JWTUtil.getUserDetailsList(String.valueOf(token), Admin.class);
  54. List<String> userMarkets = Arrays.asList(StringUtils.split(admin.getMarkets(), ","));
  55. List<String> markets = marketService.getMarketIds(userMarkets);
  56. // 校验分页参数
  57. if (ObjectUtils.isEmpty(page.getPageNum())) {
  58. return Result.error("页码数为空!");
  59. }
  60. if (ObjectUtils.isEmpty(page.getPageSize())) {
  61. return Result.error("页大小为空!");
  62. }
  63. // 获取传入的市场列表
  64. List<String> requestedMarkets = page.getCashRecordDTO() != null ? page.getCashRecordDTO().getMarkets() : null;
  65. // 权限校验逻辑
  66. if (markets.contains("9") || markets.contains("9999")) {
  67. // 特权市场:9 或 9999,跳过权限校验,直接放行传入的 markets
  68. // 如果业务需要,也可以在这里做空值处理
  69. if (page.getCashRecordDTO() != null) {
  70. // 保持 requestedMarkets 不变,原样接受
  71. // 可选:如果 requestedMarkets 为 null,可设为默认值或保持 null
  72. }
  73. } else {
  74. // 普通用户:必须校验权限
  75. if (requestedMarkets == null || requestedMarkets.isEmpty()) {
  76. page.getCashRecordDTO().setMarkets(markets);
  77. }
  78. if (!markets.containsAll(requestedMarkets)) {
  79. return Result.error("无权限!请求的市场不在授权范围内。");
  80. }
  81. // 校验通过,保持 requestedMarkets 不变
  82. }
  83. return Result.success(refundService.financeSelect(page.getPageNum(), page.getPageSize(), page.getCashRecordDTO()));
  84. }
  85. /**
  86. * 添加退款现金记录
  87. */
  88. @PostMapping("/add")
  89. public Result add(@RequestBody CashRecordRefund cashRecordRefund) throws Exception {
  90. cashRecordRefund.setStatus(10);
  91. try {
  92. return Result.success(refundService.add(cashRecordRefund));
  93. } catch (Exception e) {
  94. return Result.error(e.getMessage());
  95. }
  96. }
  97. /**
  98. * 执行人查看退款现金记录
  99. */
  100. @PostMapping("/exSelect")
  101. public Result executor(@RequestBody Page page) throws Exception {
  102. HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  103. String token = request.getHeader("token");
  104. // 解析 token 获取用户信息
  105. Admin admin = (Admin) JWTUtil.getUserDetailsList(String.valueOf(token), Admin.class);
  106. List<String> userMarkets = Arrays.asList(StringUtils.split(admin.getMarkets(), ","));
  107. List<String> markets = marketService.getMarketIds(userMarkets);
  108. // 校验分页参数
  109. if (ObjectUtils.isEmpty(page.getPageNum())) {
  110. return Result.error("页码数为空!");
  111. }
  112. if (ObjectUtils.isEmpty(page.getPageSize())) {
  113. return Result.error("页大小为空!");
  114. }
  115. //// 获取传入的市场列表
  116. // List<String> requestedMarkets = page.getCashRecordDTO() != null ? page.getCashRecordDTO().getMarkets() : null;
  117. //
  118. //// 权限校验逻辑
  119. // if (markets.contains("9") || markets.contains("9999")) {
  120. // // 特权市场:9 或 9999,跳过权限校验,直接放行传入的 markets
  121. // // 如果业务需要,也可以在这里做空值处理
  122. // if (page.getCashRecordDTO() != null) {
  123. // // 保持 requestedMarkets 不变,原样接受
  124. // // 可选:如果 requestedMarkets 为 null,可设为默认值或保持 null
  125. // }
  126. // } else {
  127. // // 普通用户:必须校验权限
  128. // if (requestedMarkets == null || requestedMarkets.isEmpty()) {
  129. // page.getCashRecordDTO().setMarkets(markets);
  130. // }
  131. // if (!markets.containsAll(requestedMarkets)) {
  132. // return Result.error("无权限!请求的市场不在授权范围内。");
  133. // }
  134. // // 校验通过,保持 requestedMarkets 不变
  135. // }
  136. return Result.success(refundService.exSelect(page.getPageNum(), page.getPageSize(), page.getCashRecordDTO()));
  137. }
  138. /**
  139. * 查询客服提交现金记录
  140. */
  141. @PostMapping("/selecta")
  142. public Result selecta(@RequestBody Page page) {
  143. // 校验分页参数
  144. if (ObjectUtils.isEmpty(page.getPageNum())) {
  145. return Result.error("页码数为空!");
  146. }
  147. if (ObjectUtils.isEmpty(page.getPageSize())) {
  148. return Result.error("页大小为空!");
  149. }
  150. // 获取传入的市场列表
  151. List<String> requestedMarkets = page.getCashRecordDTO() != null ? page.getCashRecordDTO().getMarkets() : null;
  152. return Result.success(refundService.select(page.getPageNum(), page.getPageSize(), page.getCashRecordDTO()));
  153. }
  154. @PostMapping("/update")
  155. public Result update(@RequestBody CashRecordDone cashRecordDone)throws Exception {
  156. if (cashRecordDone.getStatus() == null) {
  157. return Result.error("状态为空");
  158. }
  159. if (cashRecordDone.getStatus() == 10) {
  160. return Result.success(refundService.withdraw(cashRecordDone));
  161. }
  162. else if (cashRecordDone.getStatus() == 11) {
  163. try {
  164. return Result.success(refundService.update(cashRecordDone));
  165. } catch (Exception e) {
  166. return Result.error(e.getMessage());
  167. }
  168. }
  169. else return Result.error("该订单状态无法支持此操作");
  170. }
  171. @PostMapping("/review")
  172. public Result review(@RequestBody CashRecordDone cashRecordDone){
  173. try {
  174. return Result.success(refundService.review(cashRecordDone));
  175. } catch (Exception e) {
  176. return Result.error(e.getMessage());
  177. }
  178. }
  179. @PostMapping("/finalReview")
  180. public Result finalReview(@RequestBody CashRecordDone cashRecordDone,HttpServletRequest request) {
  181. {
  182. // --------------- 限流逻辑开始 ---------------
  183. String limitKey = null;
  184. try {
  185. // 1. 优先用「用户ID」作为限流标识(从token解析,精准限流)
  186. HttpServletRequest req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
  187. String token = req.getHeader("token");
  188. Admin admin = (Admin) JWTUtil.getUserDetailsList(String.valueOf(token), Admin.class);
  189. if (admin != null && admin.getId() != null) {
  190. limitKey = "finalReview_" + admin.getId(); // 格式:接口名_用户ID
  191. }
  192. } catch (Exception e) {
  193. // token解析失败(用户未登录),降级用「IP地址」限流
  194. limitKey = "finalReview_" + getIpAddress(request); // 格式:接口名_IP
  195. }
  196. // 2. 校验限流:3秒内同一key不允许重复请求
  197. if (Objects.isNull(limitKey) || !RateLimitUtil.isAllowed(limitKey)) {
  198. return Result.error("3秒内只能请求一次,请稍后再试"); // 限流提示
  199. }
  200. // --------------- 限流逻辑结束 ---------------
  201. try {
  202. // 原有业务逻辑:执行最终审核
  203. return Result.success(refundService.finalreview(cashRecordDone));
  204. } catch (Exception e) {
  205. // 接口执行失败时,移除限流标识(允许用户重新尝试)
  206. RateLimitUtil.removeKey(limitKey);
  207. return Result.error("审核失败:" + e.getMessage());
  208. }
  209. }}
  210. @PostMapping("/executor")
  211. public Result executor(@RequestBody CashRecordDone cashRecordDone) throws Exception {
  212. try {
  213. return Result.success(refundService.executor(cashRecordDone));
  214. }
  215. catch (Exception e) {
  216. return Result.error(e.getMessage());
  217. }
  218. }
  219. /**
  220. * 新增线上退款订单
  221. */
  222. @PostMapping("/addOnline")
  223. public Result addOnline(@RequestBody CashRecordRefund cashRecordRefund){
  224. cashRecordRefund.setStatus(20);
  225. try {
  226. return Result.success(refundService.add(cashRecordRefund));
  227. } catch (Exception e) {
  228. return Result.error(e.getMessage());
  229. }
  230. }
  231. @PostMapping("/export")
  232. public Result export(@RequestBody Page page) throws Exception {
  233. // 校验分页参数
  234. if (ObjectUtils.isEmpty(page.getPageNum())) {
  235. return Result.error("页码数为空!");
  236. }
  237. if (ObjectUtils.isEmpty(page.getPageSize())) {
  238. return Result.error("页大小为空!");
  239. }
  240. return Result.success(refundService.financeSelect(page.getPageNum(), page.getPageSize(), page.getCashRecordDTO()));
  241. }
  242. @PostMapping("/ceshi")
  243. public Result ceshi() {
  244. return Result.success("测试消息");
  245. }
  246. /**
  247. * 辅助方法获取用户真实IP处理反向代理/负载均衡场景
  248. */
  249. private String getIpAddress(HttpServletRequest request) {
  250. String ip = request.getHeader("x-forwarded-for");
  251. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
  252. ip = request.getHeader("Proxy-Client-IP");
  253. }
  254. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
  255. ip = request.getHeader("WL-Proxy-Client-IP");
  256. }
  257. if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
  258. ip = request.getRemoteAddr();
  259. }
  260. // 多IP场景(如多层代理),取第一个非unknown的IP
  261. if (ip != null && ip.contains(",")) {
  262. ip = ip.split(",")[0].trim();
  263. }
  264. return ip;
  265. }
  266. }