From 786d281c0e339535eb5602ca95c465b53447656e Mon Sep 17 00:00:00 2001 From: sunjiabei Date: Fri, 27 Jun 2025 15:01:26 +0800 Subject: [PATCH 01/16] =?UTF-8?q?=E6=B5=8B=E8=AF=95git?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/demo/controller/ConsumeController.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/com/example/demo/controller/ConsumeController.java b/src/main/java/com/example/demo/controller/ConsumeController.java index ba399bb..47b6baa 100644 --- a/src/main/java/com/example/demo/controller/ConsumeController.java +++ b/src/main/java/com/example/demo/controller/ConsumeController.java @@ -50,6 +50,7 @@ public class ConsumeController { } + //消耗明细筛选 @PostMapping("/selectBy") public Result selcetBy(@RequestBody Page page) { From 22171610c607870ec5a64d063d486a4609addb75 Mon Sep 17 00:00:00 2001 From: sunjiabei Date: Sun, 29 Jun 2025 10:43:15 +0800 Subject: [PATCH 02/16] =?UTF-8?q?=E6=8E=92=E5=BA=8F=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/demo/controller/ConsumeController.java | 6 +- .../example/demo/controller/RefundController.java | 7 +- .../com/example/demo/domain/vo/ConsumeUser.java | 3 + .../com/example/demo/domain/vo/RefundUser.java | 3 + .../com/example/demo/mapper/ConsumeMapper.java | 2 +- .../java/com/example/demo/mapper/RefundMapper.java | 2 +- .../com/example/demo/service/ConsumeService.java | 4 +- .../com/example/demo/service/RefundService.java | 4 +- .../demo/serviceImpl/ConsumeServiceImpl.java | 27 +++--- .../demo/serviceImpl/RefundServiceImpl.java | 22 ++--- src/main/resources/mapper/ConsumeMapper.xml | 100 +++++++++++++++++---- src/main/resources/mapper/RefundMapper.xml | 68 ++++++++++++++ 12 files changed, 194 insertions(+), 54 deletions(-) diff --git a/src/main/java/com/example/demo/controller/ConsumeController.java b/src/main/java/com/example/demo/controller/ConsumeController.java index 47b6baa..cb99af9 100644 --- a/src/main/java/com/example/demo/controller/ConsumeController.java +++ b/src/main/java/com/example/demo/controller/ConsumeController.java @@ -41,7 +41,7 @@ public class ConsumeController { if (ObjectUtils.isEmpty(page.getPageSize())) { return Result.error("页大小为空!"); } else { - return Result.success(consumeService.selectAll(page.getPageNum(), page.getPageSize())); + return Result.success(consumeService.selectAll(page.getPageNum(), page.getPageSize(),page.getConsumeUser())); } } catch (Exception e) { return Result.error("接口调用失败"); @@ -71,9 +71,9 @@ public class ConsumeController { //消耗金币统计 @PostMapping("/statsGold") - public Result statsGold() { + public Result statsGold(@RequestBody ConsumeUser consumeUser) { try { - Gold gold = consumeService.statsGold(); + Gold gold = consumeService.statsGold(consumeUser); return Result.success(gold); } catch (Exception e) { return Result.error("接口调用失败"); diff --git a/src/main/java/com/example/demo/controller/RefundController.java b/src/main/java/com/example/demo/controller/RefundController.java index 51f92f7..30c180a 100644 --- a/src/main/java/com/example/demo/controller/RefundController.java +++ b/src/main/java/com/example/demo/controller/RefundController.java @@ -2,6 +2,7 @@ package com.example.demo.controller; import com.example.demo.domain.vo.Gold; import com.example.demo.domain.vo.Page; +import com.example.demo.domain.vo.RefundUser; import com.example.demo.domain.vo.Result; import com.example.demo.service.ConsumeService; import com.example.demo.service.RefundService; @@ -40,7 +41,7 @@ public class RefundController { if (ObjectUtils.isEmpty(page.getPageSize())) { return Result.error("页大小为空!"); } else { - return Result.success(refundService.selectAll(page.getPageNum(), page.getPageSize())); + return Result.success(refundService.selectAll(page.getPageNum(), page.getPageSize(), page.getRefundUser())); } } catch (Exception e) { return Result.error("接口调用失败"); @@ -66,9 +67,9 @@ public class RefundController { } @PostMapping("/statsGold") - public Result statsGold() { + public Result statsGold(@RequestBody RefundUser refundUser) { try { - Gold gold = refundService.statsGold(); + Gold gold = refundService.statsGold(refundUser); return Result.success(gold); } catch (Exception e) { return Result.error("接口调用失败"); diff --git a/src/main/java/com/example/demo/domain/vo/ConsumeUser.java b/src/main/java/com/example/demo/domain/vo/ConsumeUser.java index f1617c7..40768ea 100644 --- a/src/main/java/com/example/demo/domain/vo/ConsumeUser.java +++ b/src/main/java/com/example/demo/domain/vo/ConsumeUser.java @@ -43,4 +43,7 @@ public class ConsumeUser implements Serializable { private Date startTime; // 开始时间 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") private Date endTime; // 结束时间 + + private String sortField; //排序字段 + private String sortOrder; //排序顺序 } diff --git a/src/main/java/com/example/demo/domain/vo/RefundUser.java b/src/main/java/com/example/demo/domain/vo/RefundUser.java index 0d4d3d4..6ca6b78 100644 --- a/src/main/java/com/example/demo/domain/vo/RefundUser.java +++ b/src/main/java/com/example/demo/domain/vo/RefundUser.java @@ -43,4 +43,7 @@ public class RefundUser { private Date startTime; // 开始时间 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") private Date endTime; // 结束时间 + + private String sortField; //排序字段 + private String sortOrder; //排序顺序 } diff --git a/src/main/java/com/example/demo/mapper/ConsumeMapper.java b/src/main/java/com/example/demo/mapper/ConsumeMapper.java index 31d0355..489028a 100644 --- a/src/main/java/com/example/demo/mapper/ConsumeMapper.java +++ b/src/main/java/com/example/demo/mapper/ConsumeMapper.java @@ -18,7 +18,7 @@ import java.util.List; @Mapper public interface ConsumeMapper { - List selectAll(); + List selectAll(ConsumeUser consumeUser); List selectBy(ConsumeUser consumeUser); diff --git a/src/main/java/com/example/demo/mapper/RefundMapper.java b/src/main/java/com/example/demo/mapper/RefundMapper.java index 3067263..fd6c184 100644 --- a/src/main/java/com/example/demo/mapper/RefundMapper.java +++ b/src/main/java/com/example/demo/mapper/RefundMapper.java @@ -19,7 +19,7 @@ import java.util.List; @Mapper public interface RefundMapper { - List selectAll(); + List selectAll(RefundUser refundUser); List selectBy(RefundUser refundUser); diff --git a/src/main/java/com/example/demo/service/ConsumeService.java b/src/main/java/com/example/demo/service/ConsumeService.java index 519492b..9ab9a3d 100644 --- a/src/main/java/com/example/demo/service/ConsumeService.java +++ b/src/main/java/com/example/demo/service/ConsumeService.java @@ -18,9 +18,9 @@ import com.github.pagehelper.PageInfo; public interface ConsumeService { - PageInfo selectAll(Integer pageNum, Integer pageSize); + PageInfo selectAll(Integer pageNum, Integer pageSize, ConsumeUser consumeUser); - Gold statsGold(); + Gold statsGold(ConsumeUser consumeUser); PageInfo selectBy(Integer pageNum, Integer pageSize, ConsumeUser consumeUser); diff --git a/src/main/java/com/example/demo/service/RefundService.java b/src/main/java/com/example/demo/service/RefundService.java index f09b86d..40e0b25 100644 --- a/src/main/java/com/example/demo/service/RefundService.java +++ b/src/main/java/com/example/demo/service/RefundService.java @@ -18,9 +18,9 @@ import com.github.pagehelper.PageInfo; public interface RefundService { - PageInfo selectAll(Integer pageNum, Integer pageSize); + PageInfo selectAll(Integer pageNum, Integer pageSize, RefundUser refundUser); - Gold statsGold(); + Gold statsGold(RefundUser refundUser); PageInfo selectBy(Integer pageNum, Integer pageSize, RefundUser refundUser); diff --git a/src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java index b8699f7..7ca6043 100644 --- a/src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java @@ -42,17 +42,17 @@ public class ConsumeServiceImpl implements ConsumeService { //消耗明细 @Override - public PageInfo selectAll(Integer pageNum, Integer pageSize) { + public PageInfo selectAll(Integer pageNum, Integer pageSize, ConsumeUser consumeUser) { PageHelper.startPage(pageNum, pageSize); - List consumeUsers = consumeMapper.selectAll(); + List consumeUsers = consumeMapper.selectAll(consumeUser); return new PageInfo<>(consumeUsers); } //消耗金币统计 @Override - public Gold statsGold() { + public Gold statsGold(ConsumeUser consumeUser) { Gold gold = new Gold(); - List consumeUsers = consumeMapper.selectAll(); + List consumeUsers = consumeMapper.selectBy(consumeUser); // 初始化累加器 int permanentGoldSum = 0; @@ -60,18 +60,18 @@ public class ConsumeServiceImpl implements ConsumeService { int taskGoldSum = 0; // 遍历消费记录并累加金币 - for (ConsumeUser consumeUser : consumeUsers) { + for (ConsumeUser user : consumeUsers) { // 累加永久金币 - if (consumeUser.getPermanentGold() != null) { - permanentGoldSum += consumeUser.getPermanentGold(); + if (user.getPermanentGold() != null) { + permanentGoldSum += user.getPermanentGold(); } // 累加免费金币 - if (consumeUser.getFreeGold() != null) { - freeGoldSum += consumeUser.getFreeGold(); + if (user.getFreeGold() != null) { + freeGoldSum += user.getFreeGold(); } // 累加任务金币 - if (consumeUser.getTaskGold() != null) { - taskGoldSum += consumeUser.getTaskGold(); + if (user.getTaskGold() != null) { + taskGoldSum += user.getTaskGold(); } } @@ -105,12 +105,9 @@ public class ConsumeServiceImpl implements ConsumeService { int count = atomicInteger.getAndUpdate(c -> (c >= 999) ? 0 : c + 1); String counterPart = String.format("%03d", count); - // 生成随机数部分(四位数) - Random RANDOM = new Random(); - int randomNum = RANDOM.nextInt(9000) + 1000; //订单号生成 - userGoldRecord.setOrderCode(timestampPart + counterPart + randomNum); + userGoldRecord.setOrderCode("XF" + timestampPart + counterPart); userGoldRecord.setJwcode(consumeUser.getJwcode()); userGoldRecord.setGoodsName(consumeUser.getGoodsName()); userGoldRecord.setSumGold(consumeUser.getSumGold()); diff --git a/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java index e852d3f..200f391 100644 --- a/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java @@ -34,16 +34,16 @@ public class RefundServiceImpl implements RefundService { private UserMapper userMapper; @Override - public PageInfo selectAll(Integer pageNum, Integer pageSize) { + public PageInfo selectAll(Integer pageNum, Integer pageSize, RefundUser refundUser) { PageHelper.startPage(pageNum, pageSize); - List refundUsers = refundMapper.selectAll(); + List refundUsers = refundMapper.selectAll(refundUser); return new PageInfo<>(refundUsers); } @Override - public Gold statsGold() { + public Gold statsGold(RefundUser refundUser) { Gold gold = new Gold(); - List refundUsers = refundMapper.selectAll(); + List refundUsers = refundMapper.selectBy(refundUser); // 初始化累加器 int permanentGoldSum = 0; @@ -51,18 +51,18 @@ public class RefundServiceImpl implements RefundService { int taskGoldSum = 0; // 遍历推开记录并累加金币 - for (RefundUser refundUser : refundUsers) { + for (RefundUser user : refundUsers) { // 累加永久金币 - if (refundUser.getPermanentGold() != null) { - permanentGoldSum += refundUser.getPermanentGold(); + if (user.getPermanentGold() != null) { + permanentGoldSum += user.getPermanentGold(); } // 累加免费金币 - if (refundUser.getFreeGold() != null) { - freeGoldSum += refundUser.getFreeGold(); + if (user.getFreeGold() != null) { + freeGoldSum += user.getFreeGold(); } // 累加任务金币 - if (refundUser.getTaskGold() != null) { - taskGoldSum += refundUser.getTaskGold(); + if (user.getTaskGold() != null) { + taskGoldSum += user.getTaskGold(); } } diff --git a/src/main/resources/mapper/ConsumeMapper.xml b/src/main/resources/mapper/ConsumeMapper.xml index 2d42f22..b365123 100644 --- a/src/main/resources/mapper/ConsumeMapper.xml +++ b/src/main/resources/mapper/ConsumeMapper.xml @@ -4,24 +4,58 @@ @@ -61,6 +95,40 @@ AND ugr.create_time BETWEEN #{startTime} AND #{endTime} + + + + + + + ugr.sum_gold + ugr.permanent_gold + (COALESCE(ugr.free_june, 0) + COALESCE(ugr.free_december, 0)) + + ugr.create_time + + ugr.create_time + + + + + + ASC + DESC + DESC + + + + DESC + + + + + + ugr.create_time DESC + + + diff --git a/src/main/resources/mapper/RefundMapper.xml b/src/main/resources/mapper/RefundMapper.xml index d00d506..48f1fd9 100644 --- a/src/main/resources/mapper/RefundMapper.xml +++ b/src/main/resources/mapper/RefundMapper.xml @@ -23,6 +23,40 @@ JOIN admin a ON ugr.admin_id = a.id WHERE ugr.type = 2 + + + + + + + ugr.sum_gold + ugr.permanent_gold + (COALESCE(ugr.free_june, 0) + COALESCE(ugr.free_december, 0)) + + ugr.create_time + + ugr.create_time + + + + + + ASC + DESC + DESC + + + + DESC + + + + + + ugr.create_time DESC + + + @@ -63,6 +97,40 @@ AND ugr.create_time BETWEEN #{startTime} AND #{endTime} + + + + + + + ugr.sum_gold + ugr.permanent_gold + (COALESCE(ugr.free_june, 0) + COALESCE(ugr.free_december, 0)) + + ugr.create_time + + ugr.create_time + + + + + + ASC + DESC + DESC + + + + DESC + + + + + + ugr.create_time DESC + + + From cb5e5687f5e995acb5419546e19ac817569fbb15 Mon Sep 17 00:00:00 2001 From: sunjiabei Date: Sun, 29 Jun 2025 14:53:09 +0800 Subject: [PATCH 03/16] =?UTF-8?q?=E5=85=85=E5=80=BC=E8=AF=A6=E6=83=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/controller/RechargeController.java | 93 +++++++++++ src/main/java/com/example/demo/domain/vo/Page.java | 1 + .../com/example/demo/domain/vo/RechargeUser.java | 50 ++++++ .../com/example/demo/mapper/RechargeMapper.java | 27 ++++ .../com/example/demo/service/RechargeService.java | 26 +++ .../demo/serviceImpl/ConsumeServiceImpl.java | 1 + .../demo/serviceImpl/RechargeServiceImpl.java | 84 ++++++++++ src/main/resources/mapper/ConsumeMapper.xml | 6 +- src/main/resources/mapper/RechargeMapper.xml | 179 +++++++++++++++++++++ src/main/resources/mapper/RefundMapper.xml | 4 +- 10 files changed, 467 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/example/demo/controller/RechargeController.java create mode 100644 src/main/java/com/example/demo/domain/vo/RechargeUser.java create mode 100644 src/main/java/com/example/demo/mapper/RechargeMapper.java create mode 100644 src/main/java/com/example/demo/service/RechargeService.java create mode 100644 src/main/java/com/example/demo/serviceImpl/RechargeServiceImpl.java create mode 100644 src/main/resources/mapper/RechargeMapper.xml diff --git a/src/main/java/com/example/demo/controller/RechargeController.java b/src/main/java/com/example/demo/controller/RechargeController.java new file mode 100644 index 0000000..7ecf564 --- /dev/null +++ b/src/main/java/com/example/demo/controller/RechargeController.java @@ -0,0 +1,93 @@ +package com.example.demo.controller; + +import com.example.demo.domain.vo.*; +import com.example.demo.service.ConsumeService; +import com.example.demo.service.RechargeService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.util.ObjectUtils; +import org.springframework.web.bind.annotation.*; + +/** + * @program: gold-java + * @ClassName RechargeController + * @description: + * @author: Double + * @create: 2025−06-29 13:01 + * @Version 1.0 + **/ + +@RestController +@RequestMapping("/recharge") +@RequiredArgsConstructor +@Slf4j +@CrossOrigin +public class RechargeController { + + + @Autowired + private RechargeService rechargeService; + + //消耗明细 + @PostMapping("/selectAll") + public Result selcetAll(@RequestBody Page page) { + try { + if (ObjectUtils.isEmpty(page.getPageNum())) { + return Result.error("页码数为空!"); + } + if (ObjectUtils.isEmpty(page.getPageSize())) { + return Result.error("页大小为空!"); + } else { + return Result.success(rechargeService.selectAll(page.getPageNum(), page.getPageSize(),page.getRechargeUser())); + } + } catch (Exception e) { + return Result.error("接口调用失败"); + + } + + } + + + //消耗明细筛选 + @PostMapping("/selectBy") + public Result selcetBy(@RequestBody Page page) { + try { + if (ObjectUtils.isEmpty(page.getPageNum())) { + return Result.error("页码数为空!"); + } + if (ObjectUtils.isEmpty(page.getPageSize())) { + return Result.error("页大小为空!"); + } else { + return Result.success(rechargeService.selectBy(page.getPageNum(), page.getPageSize(), page.getRechargeUser())); + } + } catch (Exception e) { + return Result.error("接口调用失败"); + } + + } + + //消耗金币统计 + @PostMapping("/statsGold") + public Result statsGold(@RequestBody RechargeUser rechargeUser) { + try { + Gold gold = rechargeService.statsGold(rechargeUser); + return Result.success(gold); + } catch (Exception e) { + return Result.error("接口调用失败"); + } + } + + //消耗金币增加 + @PostMapping("/add") + public Result add(@RequestBody RechargeUser rechargeUser) { + try { + return rechargeService.add(rechargeUser); + } catch (Exception e) { + return Result.error("接口调用失败"); + } + } + + + +} diff --git a/src/main/java/com/example/demo/domain/vo/Page.java b/src/main/java/com/example/demo/domain/vo/Page.java index 978d398..16d172d 100644 --- a/src/main/java/com/example/demo/domain/vo/Page.java +++ b/src/main/java/com/example/demo/domain/vo/Page.java @@ -24,4 +24,5 @@ public class Page { private User user; private RefundUser refundUser; private Permission permission; + private RechargeUser rechargeUser; } diff --git a/src/main/java/com/example/demo/domain/vo/RechargeUser.java b/src/main/java/com/example/demo/domain/vo/RechargeUser.java new file mode 100644 index 0000000..55795d9 --- /dev/null +++ b/src/main/java/com/example/demo/domain/vo/RechargeUser.java @@ -0,0 +1,50 @@ +package com.example.demo.domain.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @program: gold-java + * @ClassName Recharge + * @description: + * @author: Double + * @create: 2025−06-29 13:18 + * @Version 1.0 + **/ + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class RechargeUser { + + private static final long serialVersionUID = 1L; + + private String name; // 客户姓名 + private Integer jwcode; // 精网号 + private String market; // 所属地区 + private String activity; // 活动名称 + private Integer rateId; // 汇率ID + private String rateName; // 汇率名称 + private Integer money; // 金额[分] + private Integer permanentGold; // 永久金币 + private Integer freeGold; // 免费金币 + private String payModel; // 支付方式 + private String payPlatform; // 支付平台 + private String remark; // 备注 + private Integer adminId; //提交人Id + private String adminName; //提交人姓名 + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date createTime; // 创建时间 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date startTime; // 开始时间 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date endTime; // 结束时间 + + private String sortField; //排序字段 + private String sortOrder; //排序顺序 +} diff --git a/src/main/java/com/example/demo/mapper/RechargeMapper.java b/src/main/java/com/example/demo/mapper/RechargeMapper.java new file mode 100644 index 0000000..e600ced --- /dev/null +++ b/src/main/java/com/example/demo/mapper/RechargeMapper.java @@ -0,0 +1,27 @@ +package com.example.demo.mapper; + + +import com.example.demo.domain.entity.UserGoldRecord; +import com.example.demo.domain.vo.RechargeUser; +import com.example.demo.domain.vo.RefundUser; +import org.apache.ibatis.annotations.Mapper; + +import java.util.List; + +/** + * @program: gold-java + * @ClassName RechargeMapper + * @description: + * @author: Double + * @create: 2025−06-29 13:41 + * @Version 1.0 + **/ + +@Mapper +public interface RechargeMapper { + List selectAll(RechargeUser rechargeUser); + + List selectBy(RechargeUser rechargeUser); + + void add(UserGoldRecord userGoldRecord); +} diff --git a/src/main/java/com/example/demo/service/RechargeService.java b/src/main/java/com/example/demo/service/RechargeService.java new file mode 100644 index 0000000..409fa16 --- /dev/null +++ b/src/main/java/com/example/demo/service/RechargeService.java @@ -0,0 +1,26 @@ +package com.example.demo.service; + +import com.example.demo.domain.vo.ConsumeUser; +import com.example.demo.domain.vo.Gold; +import com.example.demo.domain.vo.RechargeUser; +import com.example.demo.domain.vo.Result; +import com.github.pagehelper.PageInfo; + +/** + * @program: gold-java + * @ClassName RechargeService + * @description: + * @author: Double + * @create: 2025−06-29 13:39 + * @Version 1.0 + **/ + +public interface RechargeService { + PageInfo selectAll(Integer pageNum, Integer pageSize, RechargeUser rechargeUser); + + Gold statsGold(RechargeUser rechargeUser); + + PageInfo selectBy(Integer pageNum, Integer pageSize, RechargeUser rechargeUser); + + Result add(RechargeUser rechargeUser); +} diff --git a/src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java index 7ca6043..7fb3df7 100644 --- a/src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java @@ -145,6 +145,7 @@ public class ConsumeServiceImpl implements ConsumeService { userGoldRecord.setIsRefund((byte) 0); userGoldRecord.setPayPlatform("金币系统"); userGoldRecord.setAdminId(consumeUser.getAdminId()); + userGoldRecord.setAuditStatus(1); userGoldRecord.setCreateTime(new Date()); userGoldRecord.setPayTime(new Date()); consumeMapper.add(userGoldRecord); diff --git a/src/main/java/com/example/demo/serviceImpl/RechargeServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/RechargeServiceImpl.java new file mode 100644 index 0000000..be51029 --- /dev/null +++ b/src/main/java/com/example/demo/serviceImpl/RechargeServiceImpl.java @@ -0,0 +1,84 @@ +package com.example.demo.serviceImpl; + +import com.example.demo.domain.vo.ConsumeUser; +import com.example.demo.domain.vo.Gold; +import com.example.demo.domain.vo.RechargeUser; +import com.example.demo.domain.vo.Result; +import com.example.demo.mapper.ConsumeMapper; +import com.example.demo.mapper.RechargeMapper; +import com.example.demo.mapper.UserMapper; +import com.example.demo.service.RechargeService; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +/** + * @program: gold-java + * @ClassName RechrageServceImpl + * @description: + * @author: Double + * @create: 2025−06-29 13:40 + * @Version 1.0 + **/ + +@Service +public class RechargeServiceImpl implements RechargeService { + + @Autowired + private RechargeMapper rechargeMapper; + + @Autowired + private UserMapper userMapper; + + + @Override + public PageInfo selectAll(Integer pageNum, Integer pageSize, RechargeUser rechargeUser) { + PageHelper.startPage(pageNum, pageSize); + List rechargeUsers = rechargeMapper.selectAll(rechargeUser); + return new PageInfo<>(rechargeUsers); + } + + @Override + public PageInfo selectBy(Integer pageNum, Integer pageSize, RechargeUser rechargeUser) { + PageHelper.startPage(pageNum, pageSize); + List rechargeUsers = rechargeMapper.selectBy(rechargeUser); + return new PageInfo<>(rechargeUsers); + } + + @Override + public Gold statsGold(RechargeUser rechargeUser) { + Gold gold = new Gold(); + List rechargeUsers = rechargeMapper.selectBy(rechargeUser); + + // 初始化累加器 + int permanentGoldSum = 0; + int freeGoldSum = 0; + + // 遍历充值记录并累加金币 + for (RechargeUser user : rechargeUsers) { + // 累加永久金币 + if (user.getPermanentGold() != null) { + permanentGoldSum += user.getPermanentGold(); + } + // 累加免费金币 + if (user.getFreeGold() != null) { + freeGoldSum += user.getFreeGold(); + } + } + + // 将累加结果设置到Gold对象 + gold.setPermanentGolds(permanentGoldSum); + gold.setFreeGolds(freeGoldSum); + + return gold; + } + + + @Override + public Result add(RechargeUser rechargeUser) { + return null; + } +} diff --git a/src/main/resources/mapper/ConsumeMapper.xml b/src/main/resources/mapper/ConsumeMapper.xml index b365123..0098af5 100644 --- a/src/main/resources/mapper/ConsumeMapper.xml +++ b/src/main/resources/mapper/ConsumeMapper.xml @@ -28,7 +28,7 @@ - ugr.sum_gold + ugr.task_gold ugr.permanent_gold (COALESCE(ugr.free_june, 0) + COALESCE(ugr.free_december, 0)) @@ -101,7 +101,7 @@ - ugr.sum_gold + ugr.task_gold ugr.permanent_gold (COALESCE(ugr.free_june, 0) + COALESCE(ugr.free_december, 0)) @@ -147,6 +147,7 @@ pay_platform, is_refund, admin_id, + audit_status, create_time, pay_time @@ -165,6 +166,7 @@ #{payPlatform}, #{isRefund}, #{adminId}, + #{auditStatus}, #{createTime}, #{payTime} diff --git a/src/main/resources/mapper/RechargeMapper.xml b/src/main/resources/mapper/RechargeMapper.xml new file mode 100644 index 0000000..2af7769 --- /dev/null +++ b/src/main/resources/mapper/RechargeMapper.xml @@ -0,0 +1,179 @@ + + + + + + + + + + + + INSERT INTO user_gold_record + + order_code, + jwcode, + sum_gold, + permanent_gold, + free_june, + free_december, + task_gold, + goods_name, + remark, + type, + pay_platform, + is_refund, + admin_id, + audit_status, + create_time, + pay_time + + VALUES + + #{orderCode}, + #{jwcode}, + #{sumGold}, + #{permanentGold}, + #{freeJune}, + #{freeDecember}, + #{taskGold}, + #{goodsName}, + #{remark}, + #{type}, + #{payPlatform}, + #{isRefund}, + #{adminId}, + #{auditStatus}, + #{createTime}, + #{payTime} + + + \ No newline at end of file diff --git a/src/main/resources/mapper/RefundMapper.xml b/src/main/resources/mapper/RefundMapper.xml index 48f1fd9..2e70fec 100644 --- a/src/main/resources/mapper/RefundMapper.xml +++ b/src/main/resources/mapper/RefundMapper.xml @@ -29,7 +29,7 @@ - ugr.sum_gold + ugr.task_gold ugr.permanent_gold (COALESCE(ugr.free_june, 0) + COALESCE(ugr.free_december, 0)) @@ -103,7 +103,7 @@ - ugr.sum_gold + ugr.task_gold ugr.permanent_gold (COALESCE(ugr.free_june, 0) + COALESCE(ugr.free_december, 0)) From 056c957f75003ed9309dcace2c1e172893d37202 Mon Sep 17 00:00:00 2001 From: sunjiabei Date: Sun, 29 Jun 2025 17:39:50 +0800 Subject: [PATCH 04/16] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E5=85=85=E5=80=BC?= =?UTF-8?q?=E5=92=8C=E6=B4=BB=E5=8A=A8=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/demo/controller/GeneralController.java | 6 +++ .../com/example/demo/domain/vo/RechargeUser.java | 3 +- .../com/example/demo/mapper/GeneralMapper.java | 1 + .../com/example/demo/service/GeneralService.java | 3 ++ .../demo/serviceImpl/GeneralServiceImpl.java | 7 +++ .../demo/serviceImpl/RechargeServiceImpl.java | 57 ++++++++++++++++++++-- src/main/resources/mapper/GeneralMapper.xml | 3 ++ src/main/resources/mapper/RechargeMapper.xml | 32 ++++++------ 8 files changed, 92 insertions(+), 20 deletions(-) diff --git a/src/main/java/com/example/demo/controller/GeneralController.java b/src/main/java/com/example/demo/controller/GeneralController.java index f22a320..be01a78 100644 --- a/src/main/java/com/example/demo/controller/GeneralController.java +++ b/src/main/java/com/example/demo/controller/GeneralController.java @@ -47,4 +47,10 @@ public class GeneralController { List list = generalService.getGoods(); return Result.success(list); } + @PostMapping("/activity") + public Result getActivity() + { + List list = generalService.getActivity(); + return Result.success(list); + } } diff --git a/src/main/java/com/example/demo/domain/vo/RechargeUser.java b/src/main/java/com/example/demo/domain/vo/RechargeUser.java index 55795d9..1ae120c 100644 --- a/src/main/java/com/example/demo/domain/vo/RechargeUser.java +++ b/src/main/java/com/example/demo/domain/vo/RechargeUser.java @@ -34,12 +34,13 @@ public class RechargeUser { private Integer freeGold; // 免费金币 private String payModel; // 支付方式 private String payPlatform; // 支付平台 + private String voucher; // 支付凭证 private String remark; // 备注 private Integer adminId; //提交人Id private String adminName; //提交人姓名 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") - private Date createTime; // 创建时间 + private Date payTime; // 创建时间 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") private Date startTime; // 开始时间 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") diff --git a/src/main/java/com/example/demo/mapper/GeneralMapper.java b/src/main/java/com/example/demo/mapper/GeneralMapper.java index 8913458..de73b8a 100644 --- a/src/main/java/com/example/demo/mapper/GeneralMapper.java +++ b/src/main/java/com/example/demo/mapper/GeneralMapper.java @@ -17,4 +17,5 @@ public interface GeneralMapper { List getMarket(); List getPlatform(); List getGoods(); + List getActivity(); } diff --git a/src/main/java/com/example/demo/service/GeneralService.java b/src/main/java/com/example/demo/service/GeneralService.java index e19c4b9..806882f 100644 --- a/src/main/java/com/example/demo/service/GeneralService.java +++ b/src/main/java/com/example/demo/service/GeneralService.java @@ -20,7 +20,10 @@ public interface GeneralService { List getMarket(); //获取平台 List getPlatform(); + //获取商品 List getGoods(); + //获取活动 + List getActivity(); //获取昨天的日期 Date getYesterday(); //获取某天的开始时间(00:00:00) diff --git a/src/main/java/com/example/demo/serviceImpl/GeneralServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/GeneralServiceImpl.java index 6e55273..c3cce46 100644 --- a/src/main/java/com/example/demo/serviceImpl/GeneralServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/GeneralServiceImpl.java @@ -45,6 +45,13 @@ public class GeneralServiceImpl implements GeneralService { return list; } + @Override + public List getActivity() { + List list = generalMapper.getActivity(); + return list; + } + + /* 获取昨天的日期 */ diff --git a/src/main/java/com/example/demo/serviceImpl/RechargeServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/RechargeServiceImpl.java index be51029..bf93fd2 100644 --- a/src/main/java/com/example/demo/serviceImpl/RechargeServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/RechargeServiceImpl.java @@ -1,9 +1,8 @@ package com.example.demo.serviceImpl; -import com.example.demo.domain.vo.ConsumeUser; -import com.example.demo.domain.vo.Gold; -import com.example.demo.domain.vo.RechargeUser; -import com.example.demo.domain.vo.Result; +import com.example.demo.domain.entity.User; +import com.example.demo.domain.entity.UserGoldRecord; +import com.example.demo.domain.vo.*; import com.example.demo.mapper.ConsumeMapper; import com.example.demo.mapper.RechargeMapper; import com.example.demo.mapper.UserMapper; @@ -13,7 +12,12 @@ import com.github.pagehelper.PageInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.Date; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; /** * @program: gold-java @@ -79,6 +83,49 @@ public class RechargeServiceImpl implements RechargeService { @Override public Result add(RechargeUser rechargeUser) { - return null; + UserGoldRecord userGoldRecord = new UserGoldRecord(); + + // 获取当前时间戳部分 + String timestampPart = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")); + + // 获取自增计数器部分(三位数,不足补零) + AtomicInteger atomicInteger = new AtomicInteger(0); + + int count = atomicInteger.getAndUpdate(c -> (c >= 999) ? 0 : c + 1); + String counterPart = String.format("%03d", count); + + + //订单号生成 + userGoldRecord.setOrderCode("CZ" + timestampPart + counterPart); + userGoldRecord.setJwcode(rechargeUser.getJwcode()); + userGoldRecord.setActivity(rechargeUser.getActivity()); + userGoldRecord.setPermanentGold(rechargeUser.getPermanentGold()); + // 获取当前月份(1-12) + int currentMonth = LocalDate.now().getMonthValue(); + // 根据当前月份设置对应字段 + if (currentMonth >= 1 && currentMonth <= 6) { + // 1-6月:设置6月额度,12月保持默认值 + userGoldRecord.setFreeJune(0); + userGoldRecord.setFreeDecember(rechargeUser.getFreeGold()); + } else { + // 7-12月:设置12月额度,6月保持默认值 + userGoldRecord.setFreeJune(rechargeUser.getFreeGold()); + userGoldRecord.setFreeDecember(0); + } + userGoldRecord.setSumGold(rechargeUser.getFreeGold()+rechargeUser.getPermanentGold()); + userGoldRecord.setRateId(rechargeUser.getRateId()); + userGoldRecord.setMoney(rechargeUser.getMoney()); + userGoldRecord.setVoucher(rechargeUser.getVoucher()); + userGoldRecord.setPayPlatform("金币系统"); + userGoldRecord.setPayModel(rechargeUser.getPayModel()); + userGoldRecord.setPayTime(rechargeUser.getPayTime()); + userGoldRecord.setRemark(rechargeUser.getRemark()); + userGoldRecord.setAdminId(rechargeUser.getAdminId()); + userGoldRecord.setType((byte) 0); + userGoldRecord.setAuditStatus(0); + userGoldRecord.setCreateTime(new Date()); + + rechargeMapper.add(userGoldRecord); + return Result.success(); } } diff --git a/src/main/resources/mapper/GeneralMapper.xml b/src/main/resources/mapper/GeneralMapper.xml index 99103e2..6ddca20 100644 --- a/src/main/resources/mapper/GeneralMapper.xml +++ b/src/main/resources/mapper/GeneralMapper.xml @@ -11,4 +11,7 @@ + \ No newline at end of file diff --git a/src/main/resources/mapper/RechargeMapper.xml b/src/main/resources/mapper/RechargeMapper.xml index 2af7769..5bec492 100644 --- a/src/main/resources/mapper/RechargeMapper.xml +++ b/src/main/resources/mapper/RechargeMapper.xml @@ -141,39 +141,43 @@ order_code, jwcode, + activity, sum_gold, permanent_gold, free_june, free_december, - task_gold, - goods_name, - remark, - type, + rate_id, + money, + voucher, pay_platform, - is_refund, + pay_model, + pay_time, + remark, admin_id, + type, audit_status, - create_time, - pay_time + create_time VALUES #{orderCode}, #{jwcode}, + #{activity}, #{sumGold}, #{permanentGold}, #{freeJune}, #{freeDecember}, - #{taskGold}, - #{goodsName}, - #{remark}, - #{type}, + #{rateId}, + #{money}, + #{voucher}, #{payPlatform}, - #{isRefund}, + #{payModel}, + #{payTime}, + #{remark}, #{adminId}, + #{type}, #{auditStatus}, - #{createTime}, - #{payTime} + #{createTime} \ No newline at end of file From 77e0a6e31f706bfa65b1e9cd812f5f6b3d3f8396 Mon Sep 17 00:00:00 2001 From: sunjiabei Date: Mon, 30 Jun 2025 13:51:43 +0800 Subject: [PATCH 05/16] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E9=80=80=E6=AC=BE?= =?UTF-8?q?=E5=8F=8A=E9=99=84=E5=B1=9E=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/controller/RechargeController.java | 2 +- .../example/demo/controller/RefundController.java | 30 +++++++-- .../com/example/demo/domain/vo/RefundUser.java | 1 + .../java/com/example/demo/mapper/RefundMapper.java | 5 ++ .../com/example/demo/service/RefundService.java | 7 ++ .../demo/serviceImpl/RefundServiceImpl.java | 76 +++++++++++++++++++++- src/main/resources/mapper/RefundMapper.xml | 40 +++++++++--- 7 files changed, 147 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/example/demo/controller/RechargeController.java b/src/main/java/com/example/demo/controller/RechargeController.java index 7ecf564..005e08a 100644 --- a/src/main/java/com/example/demo/controller/RechargeController.java +++ b/src/main/java/com/example/demo/controller/RechargeController.java @@ -78,7 +78,7 @@ public class RechargeController { } } - //消耗金币增加 + //充值金币增加 @PostMapping("/add") public Result add(@RequestBody RechargeUser rechargeUser) { try { diff --git a/src/main/java/com/example/demo/controller/RefundController.java b/src/main/java/com/example/demo/controller/RefundController.java index 30c180a..d75573c 100644 --- a/src/main/java/com/example/demo/controller/RefundController.java +++ b/src/main/java/com/example/demo/controller/RefundController.java @@ -1,9 +1,6 @@ package com.example.demo.controller; -import com.example.demo.domain.vo.Gold; -import com.example.demo.domain.vo.Page; -import com.example.demo.domain.vo.RefundUser; -import com.example.demo.domain.vo.Result; +import com.example.demo.domain.vo.*; import com.example.demo.service.ConsumeService; import com.example.demo.service.RefundService; import lombok.RequiredArgsConstructor; @@ -12,6 +9,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.*; +import java.util.List; + /** * @program: gold-java * @ClassName RefundMapper.xml @@ -76,4 +75,27 @@ public class RefundController { } } + @PostMapping("/refundType") + public Result getRefundType() + { + List list = refundService.getRefundType(); + return Result.success(list); + } + + @PostMapping("/selectGoods") + public Result getSelectGoods(@RequestBody RefundUser refundUser) + { + List list = refundService.selectGoods(refundUser.getJwcode()); + return Result.success(list); + } + + //消耗金币增加 + @PostMapping("/add") + public Result add(@RequestBody RefundUser refundUser) { + try { + return refundService.add(refundUser); + } catch (Exception e) { + return Result.error("接口调用失败"); + } + } } diff --git a/src/main/java/com/example/demo/domain/vo/RefundUser.java b/src/main/java/com/example/demo/domain/vo/RefundUser.java index 6ca6b78..e0e42f6 100644 --- a/src/main/java/com/example/demo/domain/vo/RefundUser.java +++ b/src/main/java/com/example/demo/domain/vo/RefundUser.java @@ -23,6 +23,7 @@ public class RefundUser { private static final long serialVersionUID = 1L; + private String orderCode; // 订单号 private String name; // 客户姓名 private Integer jwcode; // 精网号 private String market; // 所属地区 diff --git a/src/main/java/com/example/demo/mapper/RefundMapper.java b/src/main/java/com/example/demo/mapper/RefundMapper.java index fd6c184..5f2970a 100644 --- a/src/main/java/com/example/demo/mapper/RefundMapper.java +++ b/src/main/java/com/example/demo/mapper/RefundMapper.java @@ -24,4 +24,9 @@ public interface RefundMapper { List selectBy(RefundUser refundUser); void add(UserGoldRecord userGoldRecord); + + List getRefundType(); + + List selectGoods(Integer jwcode); + } diff --git a/src/main/java/com/example/demo/service/RefundService.java b/src/main/java/com/example/demo/service/RefundService.java index 40e0b25..55b856c 100644 --- a/src/main/java/com/example/demo/service/RefundService.java +++ b/src/main/java/com/example/demo/service/RefundService.java @@ -7,6 +7,8 @@ import com.example.demo.domain.vo.RefundUser; import com.example.demo.domain.vo.Result; import com.github.pagehelper.PageInfo; +import java.util.List; + /** * @program: gold-java * @ClassName RefundService @@ -25,4 +27,9 @@ public interface RefundService { PageInfo selectBy(Integer pageNum, Integer pageSize, RefundUser refundUser); Result add(RefundUser refundUser); + + //获取退款类型 + List getRefundType(); + + List selectGoods(Integer jwcode); } diff --git a/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java index 200f391..8ff5138 100644 --- a/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java @@ -1,5 +1,6 @@ package com.example.demo.serviceImpl; +import com.example.demo.domain.entity.UserGoldRecord; import com.example.demo.domain.vo.ConsumeUser; import com.example.demo.domain.vo.Gold; import com.example.demo.domain.vo.RefundUser; @@ -13,7 +14,13 @@ import com.github.pagehelper.PageInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.ArrayList; +import java.util.Date; import java.util.List; +import java.util.concurrent.atomic.AtomicInteger; /** * @program: gold-java @@ -83,6 +90,73 @@ public class RefundServiceImpl implements RefundService { @Override public Result add(RefundUser refundUser) { - return null; + UserGoldRecord userGoldRecord = new UserGoldRecord(); + String goodsNameWithOrder = refundUser.getGoodsName(); + //订单号生成 + if (goodsNameWithOrder != null && goodsNameWithOrder.contains("_")) { + String[] parts = goodsNameWithOrder.split("_", 2); + if (parts.length >= 2) { + // 提取订单号(保留原始前缀) + String orderCode = parts[0]; // XF202506281545524400006580 + + // 提取商品名(处理可能包含下划线的情况) + String goodsName = parts[1]; // 商品A + + // 设置属性(添加退款前缀) + userGoldRecord.setOrderCode("TK" + orderCode); // TKXF202506281545524400006580 + userGoldRecord.setGoodsName(goodsName); // 商品A + } + } + userGoldRecord.setJwcode(refundUser.getJwcode()); + userGoldRecord.setRefundType(refundUser.getRefundType()); + userGoldRecord.setRefundModel(refundUser.getRefundModel()); + userGoldRecord.setPermanentGold(refundUser.getPermanentGold()); + // 获取当前月份(1-12) + int currentMonth = LocalDate.now().getMonthValue(); + // 根据当前月份设置对应字段 + if (currentMonth >= 1 && currentMonth <= 6) { + // 1-6月:设置6月额度,12月保持默认值 + userGoldRecord.setFreeJune(0); + userGoldRecord.setFreeDecember(refundUser.getFreeGold()); + } else { + // 7-12月:设置12月额度,6月保持默认值 + userGoldRecord.setFreeJune(refundUser.getFreeGold()); + userGoldRecord.setFreeDecember(0); + } + userGoldRecord.setTaskGold(refundUser.getTaskGold()); + userGoldRecord.setSumGold(refundUser.getSumGold()); + userGoldRecord.setPayPlatform("金币系统"); + userGoldRecord.setRemark(refundUser.getRemark()); + userGoldRecord.setAdminId(refundUser.getAdminId()); + userGoldRecord.setType((byte) 2); + userGoldRecord.setAuditStatus(0); + userGoldRecord.setCreateTime(new Date()); + refundMapper.add(userGoldRecord); + return Result.success(); + } + + @Override + public List getRefundType() { + List list = refundMapper.getRefundType(); + return list; + } + + @Override + public List selectGoods(Integer jwcode) { + List userGoldRecords = refundMapper.selectGoods(jwcode); + List list = new ArrayList<>(); + for (UserGoldRecord record : userGoldRecords) { + if (record == null) { + continue; + } + + String orderCode = record.getOrderCode() != null ? record.getOrderCode() : "无订单号"; + String goodsName = record.getGoodsName() != null ? record.getGoodsName() : "无商品名"; + + // 拼接格式:订单号_商品名(例如:XF20250629_商品BC) + String combined = orderCode + "_" + goodsName; + list.add(combined); + } + return list; } } diff --git a/src/main/resources/mapper/RefundMapper.xml b/src/main/resources/mapper/RefundMapper.xml index 2e70fec..ea654ba 100644 --- a/src/main/resources/mapper/RefundMapper.xml +++ b/src/main/resources/mapper/RefundMapper.xml @@ -7,6 +7,7 @@ SELECT u.name AS name, u.jwcode AS jwcode, u.market AS market, + ugr.order_code AS orderCode, ugr.goods_name AS goodsName, ugr.refund_model AS refundModel, ugr.refund_type AS refundType, @@ -64,6 +65,7 @@ SELECT u.name AS name, u.jwcode AS jwcode, u.market AS market, + ugr.order_code AS orderCode, ugr.goods_name AS goodsName, ugr.refund_model AS refundModel, ugr.refund_type AS refundType, @@ -138,37 +140,59 @@ order_code, jwcode, + refund_type, + refund_model, sum_gold, permanent_gold, free_june, free_december, task_gold, goods_name, + pay_platform, remark, type, - pay_platform, - is_refund, admin_id, - create_time, - pay_time + audit_status, + create_time VALUES #{orderCode}, #{jwcode}, + #{refundType}, + #{refundModel}, #{sumGold}, #{permanentGold}, #{freeJune}, #{freeDecember}, #{taskGold}, #{goodsName}, + #{payPlatform}, #{remark}, #{type}, - #{payPlatform}, - #{isRefund}, #{adminId}, - #{createTime}, - #{payTime} + #{auditStatus}, + #{createTime} + + + + \ No newline at end of file From 6bb3f5a45d05f9732d946c0f3a2b7c752c02c260 Mon Sep 17 00:00:00 2001 From: huangqizhen <15552608129@163.com> Date: Mon, 30 Jun 2025 15:40:11 +0800 Subject: [PATCH 06/16] =?UTF-8?q?=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 35 ++- .../com/example/demo/Util/ExcelUploadUtil.java | 200 ++++++++++++++++ .../example/demo/Util/ExecutionContextUtil.java | 227 ++++++++++++++++++ .../com/example/demo/Util/FeiShuAlertUtil.java | 173 ++++++++++++++ .../java/com/example/demo/Util/RedisLockUtil.java | 37 +++ src/main/java/com/example/demo/Util/RedisUtil.java | 31 ++- .../java/com/example/demo/config/EnvConfig.java | 18 ++ .../java/com/example/demo/config/RedisConfig.java | 4 +- .../example/demo/controller/ExportController.java | 28 +++ .../demo/controller/GoldDetailController.java | 31 +++ .../demo/controller/PermissionController.java | 4 + .../com/example/demo/domain/DTO/GoldDetailDTO.java | 44 ++++ .../com/example/demo/domain/export/Goldmingxi.java | 28 +++ .../demo/domain/vo/AiEmotionExportRecordVO.java | 28 +++ .../example/demo/domain/vo/ExecutionContext.java | 25 ++ .../java/com/example/demo/domain/vo/ExportVo.java | 26 +++ .../com/example/demo/mapper/AiEmotionMapper.java | 25 ++ .../java/com/example/demo/mapper/ExportMapper.java | 19 ++ .../com/example/demo/mapper/GoldDetailMapper.java | 15 +- .../com/example/demo/service/AiEmotionService.java | 19 ++ .../example/demo/service/ExportExcelService.java | 16 ++ .../example/demo/service/GoldDetailService.java | 7 + .../example/demo/service/PermissionService.java | 1 + .../demo/serviceImpl/AiEmotionServiceImpl.java | 35 +++ .../demo/serviceImpl/ExportExcelServiceImpl.java | 253 +++++++++++++++++++++ .../demo/serviceImpl/GoldDetailServiceImpl.java | 69 +++++- .../demo/serviceImpl/PermissionServiceImpl.java | 5 + src/main/resources/application.yml | 14 +- src/main/resources/mapper/AiEmotionMapper.xml | 17 ++ src/main/resources/mapper/ExportMapper.xml | 18 ++ src/main/resources/mapper/GoldDetailMapper.xml | 15 +- src/main/resources/mapper/PermissionMapper.xml | 19 +- src/main/resources/mapper/UrlMapper.xml | 8 + 33 files changed, 1444 insertions(+), 50 deletions(-) create mode 100644 src/main/java/com/example/demo/Util/ExcelUploadUtil.java create mode 100644 src/main/java/com/example/demo/Util/ExecutionContextUtil.java create mode 100644 src/main/java/com/example/demo/Util/FeiShuAlertUtil.java create mode 100644 src/main/java/com/example/demo/Util/RedisLockUtil.java create mode 100644 src/main/java/com/example/demo/config/EnvConfig.java create mode 100644 src/main/java/com/example/demo/controller/ExportController.java create mode 100644 src/main/java/com/example/demo/domain/DTO/GoldDetailDTO.java create mode 100644 src/main/java/com/example/demo/domain/export/Goldmingxi.java create mode 100644 src/main/java/com/example/demo/domain/vo/AiEmotionExportRecordVO.java create mode 100644 src/main/java/com/example/demo/domain/vo/ExecutionContext.java create mode 100644 src/main/java/com/example/demo/domain/vo/ExportVo.java create mode 100644 src/main/java/com/example/demo/mapper/AiEmotionMapper.java create mode 100644 src/main/java/com/example/demo/mapper/ExportMapper.java create mode 100644 src/main/java/com/example/demo/service/AiEmotionService.java create mode 100644 src/main/java/com/example/demo/service/ExportExcelService.java create mode 100644 src/main/java/com/example/demo/serviceImpl/AiEmotionServiceImpl.java create mode 100644 src/main/java/com/example/demo/serviceImpl/ExportExcelServiceImpl.java create mode 100644 src/main/resources/mapper/AiEmotionMapper.xml create mode 100644 src/main/resources/mapper/ExportMapper.xml create mode 100644 src/main/resources/mapper/UrlMapper.xml diff --git a/pom.xml b/pom.xml index 216c74b..93ebbc3 100644 --- a/pom.xml +++ b/pom.xml @@ -31,15 +31,48 @@ + com.alibaba + fastjson + 1.2.83 + + + org.apache.commons + commons-lang3 + 3.12.0 + + + + org.apache.httpcomponents + httpclient + 4.5.14 + + + cn.hutool + hutool-all + 5.8.24 + + org.springframework.boot spring-boot-starter-web + org.springframework.boot + spring-boot-starter-validation + + org.mybatis.spring.boot mybatis-spring-boot-starter 3.0.4 - + + com.alibaba + easyexcel + 3.1.3 + + + com.fasterxml.jackson.core + jackson-databind + org.springframework.boot spring-boot-devtools diff --git a/src/main/java/com/example/demo/Util/ExcelUploadUtil.java b/src/main/java/com/example/demo/Util/ExcelUploadUtil.java new file mode 100644 index 0000000..77bf58f --- /dev/null +++ b/src/main/java/com/example/demo/Util/ExcelUploadUtil.java @@ -0,0 +1,200 @@ +package com.example.demo.Util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.FileSystemResource; +import org.springframework.http.*; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.http.converter.StringHttpMessageConverter; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.client.RestTemplate; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.HashMap; +import java.util.Map; + +/** + * Excel文件上传工具类 + */ +public class ExcelUploadUtil { + private static final Logger logger = LoggerFactory.getLogger(ExcelUploadUtil.class); + + // 默认配置 + private static final int DEFAULT_CONNECT_TIMEOUT = 30000; // 30秒 + private static final int DEFAULT_READ_TIMEOUT = 60000; // 60秒 + + private final RestTemplate restTemplate; + private final String uploadUrl; + private final Map defaultHeaders; + private final Map defaultParams; + + /** + * 构造方法 + * + * @param uploadUrl 上传接口URL + */ + public ExcelUploadUtil(String uploadUrl) { + this(uploadUrl, new HashMap<>(), new HashMap<>()); + } + + /** + * 构造方法 + * + * @param uploadUrl 上传接口URL + * @param defaultHeaders 默认请求头 + * @param defaultParams 默认请求参数 + */ + public ExcelUploadUtil(String uploadUrl, Map defaultHeaders, Map defaultParams) { + this.uploadUrl = uploadUrl; + this.defaultHeaders = new HashMap<>(defaultHeaders); + this.defaultParams = new HashMap<>(defaultParams); + this.restTemplate = createRestTemplate(DEFAULT_CONNECT_TIMEOUT, DEFAULT_READ_TIMEOUT); + } + + /** + * 创建RestTemplate (Spring Boot 1.x 兼容版本) + */ + private RestTemplate createRestTemplate(int connectTimeout, int readTimeout) { + RestTemplate restTemplate = new RestTemplate(); + + // 添加字符串消息转换器 (Spring 1.x 使用Charset而不是StandardCharsets) + restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(Charset.forName("UTF-8"))); + + // 设置超时 (Spring 1.x 方式) + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + factory.setConnectTimeout(connectTimeout); + factory.setReadTimeout(readTimeout); + restTemplate.setRequestFactory(factory); + + return restTemplate; + } + + /** + * 上传Excel文件 + * + * @param excelFile Excel文件 + * @param targetDir 目标目录 + * @return 上传结果 + * @throws IOException 文件操作异常 + * @throws UploadException 上传异常 + */ + public String uploadExcel(File excelFile, String targetDir) throws IOException, UploadException { + return uploadExcel(excelFile, targetDir, new HashMap<>(), new HashMap<>()); + } + + /** + * 上传Excel文件(带自定义参数) + * + * @param excelFile Excel文件 + * @param targetDir 目标目录 + * @param customHeaders 自定义请求头 + * @param customParams 自定义请求参数 + * @return 上传结果 + * @throws IOException 文件操作异常 + * @throws UploadException 上传异常 + */ + public String uploadExcel(File excelFile, String targetDir, + Map customHeaders, + Map customParams) throws IOException, UploadException { + // 验证文件 + validateFile(excelFile); + + try { + // 准备请求 + HttpEntity> requestEntity = prepareRequest(excelFile, targetDir, customHeaders, customParams); + + // 执行上传 + ResponseEntity response = restTemplate.exchange( + uploadUrl, + HttpMethod.POST, + requestEntity, + String.class + ); + + // 处理响应 + return handleResponse(response, excelFile.getName()); + } catch (Exception e) { + logger.error("Excel文件上传失败: {}", excelFile.getAbsolutePath(), e); + throw new UploadException("文件上传失败: " + e.getMessage(), e); + } + } + + /** + * 验证文件 + */ + private void validateFile(File file) throws IOException { + if (file == null) { + throw new IOException("文件不能为null"); + } + if (!file.exists()) { + throw new IOException("文件不存在: " + file.getAbsolutePath()); + } + if (!file.isFile()) { + throw new IOException("不是有效的文件: " + file.getAbsolutePath()); + } + if (file.length() == 0) { + throw new IOException("文件内容为空: " + file.getAbsolutePath()); + } + if (!file.getName().toLowerCase().endsWith(".xlsx") && + !file.getName().toLowerCase().endsWith(".xls")) { + throw new IOException("仅支持Excel文件(.xlsx, .xls)"); + } + } + + /** + * 准备请求 + */ + private HttpEntity> prepareRequest(File file, String targetDir, + Map customHeaders, + Map customParams) { + // 设置请求头 + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.MULTIPART_FORM_DATA); + + // 添加默认和自定义请求头 + defaultHeaders.forEach(headers::set); + customHeaders.forEach(headers::set); + + // 准备请求体 + MultiValueMap body = new LinkedMultiValueMap<>(); + body.add("file", new FileSystemResource(file)); + body.add("dir", targetDir); + + // 添加默认和自定义参数 + defaultParams.forEach(body::add); + customParams.forEach(body::add); + + return new HttpEntity<>(body, headers); + } + + /** + * 处理响应 + */ + private String handleResponse(ResponseEntity response, String filename) throws UploadException { + if (response.getStatusCode() == HttpStatus.OK) { + logger.info("文件上传成功: {}", filename); + return response.getBody(); + } else { + String errorMsg = String.format("上传接口返回错误状态码: %d, 响应: %s", + response.getStatusCodeValue(), response.getBody()); + logger.error(errorMsg); + throw new UploadException(errorMsg); + } + } + + /** + * 自定义上传异常 + */ + public static class UploadException extends Exception { + public UploadException(String message) { + super(message); + } + + public UploadException(String message, Throwable cause) { + super(message, cause); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/Util/ExecutionContextUtil.java b/src/main/java/com/example/demo/Util/ExecutionContextUtil.java new file mode 100644 index 0000000..10bafa4 --- /dev/null +++ b/src/main/java/com/example/demo/Util/ExecutionContextUtil.java @@ -0,0 +1,227 @@ +package com.example.demo.Util; + + +import com.example.demo.domain.vo.ExecutionContext; +import jakarta.servlet.http.HttpServletRequest; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.util.*; +import java.util.stream.Collectors; + +public class ExecutionContextUtil { + + /** + * 获取当前执行环境信息 + * @param request 如果是Web请求,传入HttpServletRequest + * @return 执行环境信息对象 + */ + /** + * 从Spring上下文获取当前HttpServletRequest + */ + public static ExecutionContext getExecutionContext() { + ExecutionContext context = new ExecutionContext(); + context.setExecutionTime(new Date()); + + HttpServletRequest request = getCurrentHttpRequest(); + + if (isWebEnvironment(request)) { + // Web API 环境 + context.setExecutionType("API"); + context.setApiUrl(getRealRequestUrl(request)); + context.setRequestParams(getRequestParams(request)); + context.setToken(getRequestToken(request)); + context.setMethod(request.getMethod()); + } else { + // 脚本环境 + context.setExecutionType("SCRIPT"); + context.setScriptFile(getMainClassFile()); + } + + return context; + } + + private static HttpServletRequest getCurrentHttpRequest() { + try { + return ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); + } catch (IllegalStateException e) { + // 不在Web请求上下文中 + return null; + } + } + + private static boolean isWebEnvironment(HttpServletRequest request) { + return request != null; + } + + private static String getRealRequestUrl(HttpServletRequest request) { + // 1. 获取协议(优先从代理头获取) + String protocol = getHeaderWithFallback(request, + Arrays.asList("X-Forwarded-Proto", "X-Forwarded-Protocol"), + request.getScheme() + ); + + // 2. 获取真实域名(优先从代理头获取原始域名) + String domain = getHeaderWithFallback(request, + Arrays.asList( + "X-Original-Host", // 一些代理服务器设置的原始终端 + "X-Real-Host", // 另一个可能的原始主机头 + "X-Forwarded-Host", // 转发的主机头 + "Host" // 最后回退到常规主机头 + ), + request.getServerName() + ); + + // 3. 获取端口(智能处理默认端口) + Integer port = getRealPort(request, protocol); + + // 4. 获取原始路径(包括QueryString) + String path = getOriginalUri(request); + + // 组装完整URL + return String.format("%s://%s:%s%s", + protocol, + domain, + port, + path + ); + } + + // 辅助方法:带fallback的header获取 + // 方法1:保持强类型(推荐) + private static String getHeaderWithFallback( + HttpServletRequest request, + List headerNames, // 明确要求String列表 + String defaultValue + ) { + return headerNames.stream() + .map(request::getHeader) + .filter(Objects::nonNull) + .findFirst() + .orElse(defaultValue); + } + + // 获取真实端口(处理代理情况) + private static int getRealPort(HttpServletRequest request, String protocol) { + // 优先从代理头获取 + String forwardedPort = request.getHeader("X-Forwarded-Port"); + if (forwardedPort != null) { + return Integer.parseInt(forwardedPort); + } + + // 其次从请求获取 + int port = request.getServerPort(); + + // 处理反向代理场景 + if (port == 80 && "https".equals(protocol)) { + return 443; + } + if (port == 443 && "http".equals(protocol)) { + return 80; + } + return port; + } + + // 获取原始URI(包含QueryString) + private static String getOriginalUri(HttpServletRequest request) { + // 优先从代理头获取原始URI + String originalUri = request.getHeader("X-Original-URI"); + if (originalUri != null) { + return originalUri; + } + + // 默认从request获取 + String queryString = request.getQueryString(); + return request.getRequestURI() + + (queryString != null ? "?" + queryString : ""); + } + + private static String getRequestParams(HttpServletRequest request) { + try { + // 1. 优先读取Query String(无需缓存) + String queryString = request.getQueryString(); + if (queryString != null) return queryString; + + // 2. 检查表单参数(GET/POST都适用) + Map params = request.getParameterMap(); + if (!params.isEmpty()) return formatParams(params); + + // 3. 只有明确是JSON请求时才尝试读取body + if (isJsonRequest(request)) { + return readJsonBodyOnDemand(request); + } + + return "{}"; + } catch (Exception e) { + return "{\"error\":\"failed to read params\"}"; + } + } + + private static String readJsonBodyOnDemand(HttpServletRequest request) throws IOException { + // 关键点:直接读取原始InputStream(不缓存) + try (BufferedReader reader = request.getReader()) { + String body = reader.lines().collect(Collectors.joining()); + return body.isEmpty() ? "{}" : body; + } + } + + + private static boolean isJsonRequest(HttpServletRequest request) { + String contentType = request.getContentType(); + return contentType != null && contentType.contains("application/json"); + } + + + private static String formatParams(Map params) { + // 优化后的参数格式化方法 + return params.entrySet().stream() + .map(entry -> { + String key = escapeJson(entry.getKey()); + String[] values = entry.getValue(); + if (values.length == 1) { + return "\"" + key + "\":\"" + escapeJson(values[0]) + "\""; + } + return "\"" + key + "\":[" + + Arrays.stream(values) + .map(v -> "\"" + escapeJson(v) + "\"") + .collect(Collectors.joining(",")) + + "]"; + }) + .collect(Collectors.joining(",", "{", "}")); + } + + private static String escapeJson(String raw) { + return raw.replace("\\", "\\\\") + .replace("\"", "\\\"") + .replace("\n", "\\n"); + } + + private static String getRequestToken(HttpServletRequest request) { + String token = request.getHeader("Authorization"); + if (token == null) { + token = request.getHeader("token"); + } + return token; + } + + private static String getMainClassFile() { + try { + // 获取主类名 + String mainClass = ManagementFactory.getRuntimeMXBean().getSystemProperties().get("sun.java.command"); + if (mainClass != null) { + // 简单处理,提取主类名 + String className = mainClass.split(" ")[0]; + // 转换为文件路径 + return className.replace('.', File.separatorChar) + ".java"; + } + } catch (Exception e) { + e.printStackTrace(); + } + return "UnknownScript"; + } +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/Util/FeiShuAlertUtil.java b/src/main/java/com/example/demo/Util/FeiShuAlertUtil.java new file mode 100644 index 0000000..cf2a00e --- /dev/null +++ b/src/main/java/com/example/demo/Util/FeiShuAlertUtil.java @@ -0,0 +1,173 @@ +package com.example.demo.Util; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.example.demo.domain.vo.ExecutionContext; +import com.example.demo.config.EnvConfig; +import org.apache.http.HttpResponse; +import org.apache.http.HttpStatus; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.*; + +/** + * 飞书报警信息发送工具类 + */ +@Component +public class FeiShuAlertUtil { + + private static final String FEISHU_WEBHOOK_URL_PROD = "https://open.feishu.cn/open-apis/bot/v2/hook/1a515b19-b64f-46b7-9486-35842b9539fe"; + private static final String FEISHU_WEBHOOK_URL_TEST = "https://open.feishu.cn/open-apis/bot/v2/hook/384c78aa-8df1-498b-9c47-04e890ed9877"; + private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + + static { + DATE_FORMAT.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); + } + + /** + * 发送报警信息到飞书群(紧凑单行格式) + * + * @param context 请求接口 + * @param errorFile 错误文件 + * @param errorLine 错误行数 + * @param errorMsg 错误信息 + * @param params 脚本执行时需要手动传参,如果时API请求则无需传,自动获取参数 + * @return 是否发送成功 + */ + public static boolean sendAlertMessage(ExecutionContext context, + String errorFile, int errorLine, + String errorMsg, String params) { + JSONObject message = new JSONObject(); + message.put("msg_type", "post"); + + JSONObject content = new JSONObject(); + JSONObject post = new JSONObject(); + JSONObject zhCn = new JSONObject(); + String title = "⚠️ 系统异常报警 ⚠️"; + zhCn.put("title", title); + + List> contentList = new ArrayList<>(); + List elements = new ArrayList<>(); + + StringBuilder contentBuilder = new StringBuilder(); + contentBuilder.append("------------------------------\n\n"); + + if ("API".equals(context.getExecutionType())) { + contentBuilder.append("**执行类型**: API请求\n\n"); + contentBuilder.append("**请求接口**: ").append(context.getApiUrl()).append("\n\n"); + contentBuilder.append("**请求参数**: ").append(params).append("\n\n"); + contentBuilder.append("**请求方法**: ").append(context.getMethod()).append("\n\n"); + if (context.getToken() != null) { + contentBuilder.append("**请求Token**: ") + .append(context.getToken().length() > 10 ? + context.getToken().substring(0, 10) + "..." : + context.getToken()) + .append("\n\n"); + } + } else { + contentBuilder.append("**执行类型**: 脚本执行\n\n"); + contentBuilder.append("**脚本文件**: ").append(context.getScriptFile()).append("\n\n"); + contentBuilder.append("**请求参数**: ").append(params).append("\n\n"); + } + + contentBuilder.append("**错误位置**: ").append(errorFile).append(":").append(errorLine).append("\n\n"); + contentBuilder.append("**错误信息**: ").append(errorMsg).append("\n\n"); + contentBuilder.append("**执行时间**: ").append(formatDate(context.getExecutionTime())).append("\n\n"); + contentBuilder.append("**报警时间**: ").append(formatDate(new Date())).append("\n\n"); + contentBuilder.append("------------------------------"); + + addContentElement(elements, "text", contentBuilder.toString()); + + contentList.add(elements); + zhCn.put("content", contentList); + post.put("zh_cn", zhCn); + content.put("post", post); + message.put("content", content); + + return sendMessage(message); + } + + private static String formatDate(Date date) { + // 实现日期格式化方法 + return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(date); + } + + private static void addContentElement(List elements, String tag, String text) { + JSONObject element = new JSONObject(); + element.put("tag", tag); + element.put("text", text); + elements.add(element); + } + + private static boolean sendMessage(JSONObject message) { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + String FEISHU_WEBHOOK_URL; + String environment = EnvConfig.ENV; + System.out.println("当前环境变量:" + environment); + if (Objects.equals(environment, "unknown") || environment.equals("dev")) { + FEISHU_WEBHOOK_URL = FEISHU_WEBHOOK_URL_TEST; + } else { + FEISHU_WEBHOOK_URL = FEISHU_WEBHOOK_URL_PROD; + } + HttpPost httpPost = new HttpPost(FEISHU_WEBHOOK_URL); + httpPost.addHeader("Content-Type", "application/json; charset=utf-8"); + + StringEntity entity = new StringEntity(message.toJSONString(), "UTF-8"); + httpPost.setEntity(entity); + + HttpResponse response = httpClient.execute(httpPost); + if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { + String result = EntityUtils.toString(response.getEntity()); + JSONObject obj = JSON.parseObject(result); + return obj.getInteger("code") == 0; + } + } catch (IOException e) { + System.out.println("发送飞书异常" + e.getMessage()); + e.printStackTrace(); + } + return false; + } + + /** + * 发送普通信息到飞书群 + * + * @param title 消息标题 + * @param content 消息内容 + * @return 是否发送成功 + */ + public static boolean sendNormalMessage(String title, String content) { + JSONObject message = new JSONObject(); + message.put("msg_type", "post"); + + JSONObject messageContent = new JSONObject(); + JSONObject post = new JSONObject(); + JSONObject zhCn = new JSONObject(); + zhCn.put("title", title); + + List> contentList = new ArrayList<>(); + List elements = new ArrayList<>(); + + StringBuilder contentBuilder = new StringBuilder(); + contentBuilder.append("------------------------------\n\n"); + contentBuilder.append(content).append("\n\n"); + contentBuilder.append("**发送时间**: ").append(formatDate(new Date())).append("\n\n"); + contentBuilder.append("------------------------------"); + + addContentElement(elements, "text", contentBuilder.toString()); + + contentList.add(elements); + zhCn.put("content", contentList); + post.put("zh_cn", zhCn); + messageContent.put("post", post); + message.put("content", messageContent); + + return sendMessage(message); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/Util/RedisLockUtil.java b/src/main/java/com/example/demo/Util/RedisLockUtil.java new file mode 100644 index 0000000..5ae5858 --- /dev/null +++ b/src/main/java/com/example/demo/Util/RedisLockUtil.java @@ -0,0 +1,37 @@ +package com.example.demo.Util; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.stereotype.Component; + +import java.util.concurrent.TimeUnit; + +@Component +public class RedisLockUtil { + + @Autowired + private StringRedisTemplate redisTemplate; + + /** + * 尝试获取分布式锁 + * @param lockKey 锁的 Key + * @param requestId 请求 ID(可用 UUID) + * @param expireTime 锁的过期时间(毫秒) + * @return 是否获取成功 + */ + public boolean tryLock(String lockKey, String requestId, long expireTime) { + return redisTemplate.opsForValue().setIfAbsent(lockKey, requestId, expireTime, TimeUnit.MILLISECONDS); + } + + /** + * 释放分布式锁 + * @param lockKey 锁的 Key + * @param requestId 请求 ID + */ + public void unlock(String lockKey, String requestId) { + String currentValue = redisTemplate.opsForValue().get(lockKey); + if (requestId.equals(currentValue)) { + redisTemplate.delete(lockKey); + } + } +} diff --git a/src/main/java/com/example/demo/Util/RedisUtil.java b/src/main/java/com/example/demo/Util/RedisUtil.java index 5431742..47e9e23 100644 --- a/src/main/java/com/example/demo/Util/RedisUtil.java +++ b/src/main/java/com/example/demo/Util/RedisUtil.java @@ -1,4 +1,3 @@ -/* package com.example.demo.Util; import jakarta.annotation.PostConstruct; @@ -35,24 +34,24 @@ public class RedisUtil { delayMessageExecutor = Executors.newFixedThreadPool(DELAY_THREAD_POOL_SIZE); } - */ + /** * 发送消息到队列 * @param queueName 队列名称 * @param message 消息内容 - *//* + */ public void sendMessage(String queueName, Object message) { redisTemplate.opsForList().rightPush(queueName, message); } - */ + /** * 阻塞获取消息(优化版,增加重试机制) * @param queueName 队列名称 * @param timeout 超时时间(秒) * @return 消息内容 - *//* + */ public Object blockingGetMessage(String queueName, long timeout) { // 分段获取,避免长时间阻塞 @@ -66,35 +65,35 @@ public class RedisUtil { return null; } - */ + /** * 非阻塞获取消息 * @param queueName 队列名称 * @return 消息内容 - *//* + */ public Object getMessage(String queueName) { return redisTemplate.opsForList().leftPop(queueName); } - */ + /** * 获取队列长度 * @param queueName 队列名称 * @return 队列长度 - *//* + */ public Long getQueueSize(String queueName) { return redisTemplate.opsForList().size(queueName); } - */ + /** * 发送延迟消息(优化版) * @param queueName 队列名称 * @param message 消息内容 * @param delay 延迟时间(秒) - *//* + */ public void sendDelayMessage(String queueName, Object message, long delay) { String delayQueueKey = getDelayQueueKey(queueName); @@ -116,10 +115,10 @@ public class RedisUtil { }); } - */ + /** * 启动延迟消息处理任务 - *//* + */ @Scheduled(fixedRate = DELAY_QUEUE_POLL_INTERVAL) public void processDelayMessages() { @@ -134,10 +133,10 @@ public class RedisUtil { } } - */ + /** * 处理单个延迟队列 - *//* + */ private void processSingleDelayQueue(String queueName) { String delayQueueKey = getDelayQueueKey(queueName); @@ -187,4 +186,4 @@ public class RedisUtil { } return serialized; } -}*/ +} diff --git a/src/main/java/com/example/demo/config/EnvConfig.java b/src/main/java/com/example/demo/config/EnvConfig.java new file mode 100644 index 0000000..1e7df48 --- /dev/null +++ b/src/main/java/com/example/demo/config/EnvConfig.java @@ -0,0 +1,18 @@ +package com.example.demo.config; + +import org.springframework.context.annotation.Configuration; + +/** + * @program: GOLD + * @ClassName EnvConfig + * @description: + * @author: huangqizhen + * @create: 2025−06-29 13:55 + * @Version 1.0 + **/ +@Configuration +public class EnvConfig { + public static final String ENV = "dev"; + public static final String ENV_PROD = "prod"; + public static final String ENV_TEST = "test"; +} diff --git a/src/main/java/com/example/demo/config/RedisConfig.java b/src/main/java/com/example/demo/config/RedisConfig.java index dfd5115..3cae685 100644 --- a/src/main/java/com/example/demo/config/RedisConfig.java +++ b/src/main/java/com/example/demo/config/RedisConfig.java @@ -1,4 +1,4 @@ -/* + package com.example.demo.config; import org.springframework.beans.factory.annotation.Autowired; @@ -45,4 +45,4 @@ public class RedisConfig { } -*/ + diff --git a/src/main/java/com/example/demo/controller/ExportController.java b/src/main/java/com/example/demo/controller/ExportController.java new file mode 100644 index 0000000..4302859 --- /dev/null +++ b/src/main/java/com/example/demo/controller/ExportController.java @@ -0,0 +1,28 @@ +package com.example.demo.controller; + +import com.example.demo.domain.entity.Export; +import com.example.demo.domain.vo.Result; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * @program: GOLD + * @ClassName ExportController + * @description: + * @author: huangqizhen + * @create: 2025−06-28 15:22 + * @Version 1.0 + **/ +@RestController +@RequestMapping("/export") +@RequiredArgsConstructor +@Slf4j +@CrossOrigin +public class ExportController { + @PostMapping("/export") + public Result export(@RequestBody Export export){ + return null; + } +} diff --git a/src/main/java/com/example/demo/controller/GoldDetailController.java b/src/main/java/com/example/demo/controller/GoldDetailController.java index 71e86a3..41ba378 100644 --- a/src/main/java/com/example/demo/controller/GoldDetailController.java +++ b/src/main/java/com/example/demo/controller/GoldDetailController.java @@ -1,15 +1,23 @@ package com.example.demo.controller; +import com.example.demo.Util.BusinessException; +import com.example.demo.Util.RedisLockUtil; +import com.example.demo.domain.DTO.GoldDetailDTO; import com.example.demo.domain.entity.User; import com.example.demo.domain.vo.GoldDetail; import com.example.demo.domain.vo.Page; import com.example.demo.domain.vo.Result; import com.example.demo.service.GoldDetailService; +import com.example.demo.serviceImpl.AiEmotionServiceImpl; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.util.ObjectUtils; import org.springframework.web.bind.annotation.*; +import java.util.UUID; + /** * @program: GOLD * @ClassName GoldDetailController @@ -26,6 +34,12 @@ import org.springframework.web.bind.annotation.*; @CrossOrigin public class GoldDetailController { private final GoldDetailService goldDetailService; + + @Autowired + private RedisLockUtil redisLockUtil; + @Autowired + private AiEmotionServiceImpl aiEmotionServiceImpl; + @PostMapping("/getGoldDetail") public Result getGoldDetail(@RequestBody Page page){ @@ -58,4 +72,21 @@ public class GoldDetailController { } return Result.success(goldDetailService.getGold(page.getPageNum(), page.getPageSize(), page.getUser())); } + @PostMapping("export") + public Result export(@Valid @RequestBody GoldDetailDTO dto) { + String lockKey = "export:lock:" + dto.getToken(); // 锁的 Key(可按用户/业务区分) + String requestId = UUID.randomUUID().toString(); // 请求 ID(防止误删锁) + long expireTime = 5000; // 锁过期时间(5秒)s + try { + // 尝试获取锁 + if (!redisLockUtil.tryLock(lockKey, requestId, expireTime)) { + throw new BusinessException("操作太频繁,请稍后重试"); + } + // 执行业务逻辑 + return GoldDetailService.addExportRecord(dto); + } finally { + // 释放锁 + redisLockUtil.unlock(lockKey, requestId); + } + } } diff --git a/src/main/java/com/example/demo/controller/PermissionController.java b/src/main/java/com/example/demo/controller/PermissionController.java index 964c986..9e043d4 100644 --- a/src/main/java/com/example/demo/controller/PermissionController.java +++ b/src/main/java/com/example/demo/controller/PermissionController.java @@ -62,5 +62,9 @@ public class PermissionController { public Result updateAdminRole(@RequestBody AdminRole adminrole){ return Result.success(permissionService.updateAdminRole(adminrole)); } + @PostMapping("/upadatePermission") + public Result upadatePermission(@RequestBody Admin admin) throws Exception { + return Result.success(permissionService.upadatePermission(admin)); + } } diff --git a/src/main/java/com/example/demo/domain/DTO/GoldDetailDTO.java b/src/main/java/com/example/demo/domain/DTO/GoldDetailDTO.java new file mode 100644 index 0000000..9aa1dd0 --- /dev/null +++ b/src/main/java/com/example/demo/domain/DTO/GoldDetailDTO.java @@ -0,0 +1,44 @@ +package com.example.demo.domain.DTO; + +import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @program: GOLD + * @ClassName AiEmotionExportDTO + * @description: + * @author: huangqizhen + * @create: 2025−06-30 15:06 + * @Version 1.0 + **/ +@Data +@NoArgsConstructor +@AllArgsConstructor +public class GoldDetailDTO { + private String token; + private String url = ""; + private String fileName = ""; + private Integer sort = 0; + private String field = ""; + private Integer jwcode; + private Integer type = 0; //类型 + private Integer state = 0; //状态 + private String text = ""; //关键词搜索 + private Integer dataNum = 0; + private String deptid = ""; + + @NotNull(message = "page不能为空") + private Integer page = 1; + @NotNull(message = "pageSize不能为空") + private Integer pageSize = 20; + + @Override + public String toString() { + return String.format( + "AiEmotionExport(jwcode=%d, type=%d, state=%d, dataNum=%d)", + jwcode, type, state, dataNum + ); + } +} diff --git a/src/main/java/com/example/demo/domain/export/Goldmingxi.java b/src/main/java/com/example/demo/domain/export/Goldmingxi.java new file mode 100644 index 0000000..a5c0b08 --- /dev/null +++ b/src/main/java/com/example/demo/domain/export/Goldmingxi.java @@ -0,0 +1,28 @@ +package com.example.demo.domain.export; + +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @program: GOLD + * @ClassName goldmingxi + * @description: + * @author: huangqizhen + * @create: 2025−06-29 17:37 + * @Version 1.0 + **/ +@Data +@NoArgsConstructor +public class Goldmingxi { + private String name; // 名称 + private Integer jwcode; // 精网号 + private String market; // 所属地区 + private String payPlatform; // 支付平台 + private Integer type; // 类型 + private Integer sumGold; // 总金币 + private Integer permentGold; //永久金币 + private Integer freeJune; // 免费金币六月到期 + private Integer freeDecember; // 免费金币七月到期 + private Integer taskGold; // 任务金币 + private String adminName; //提交人 +} diff --git a/src/main/java/com/example/demo/domain/vo/AiEmotionExportRecordVO.java b/src/main/java/com/example/demo/domain/vo/AiEmotionExportRecordVO.java new file mode 100644 index 0000000..8f4a5e8 --- /dev/null +++ b/src/main/java/com/example/demo/domain/vo/AiEmotionExportRecordVO.java @@ -0,0 +1,28 @@ +package com.example.demo.domain.vo; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @program: GOLD + * @ClassName AiEmotionExportRecordVO + * @description: + * @author: huangqizhen + * @create: 2025−06-29 14:59 + * @Version 1.0 + **/ +@Data +@NoArgsConstructor +public class AiEmotionExportRecordVO { + private static final long serialVersionUID = 1L; + private String token; + private Long id; + private Long jwcode; + private String fileName; + private String url; + private Integer state; + private Date createTime; + private Date updateTime; +} diff --git a/src/main/java/com/example/demo/domain/vo/ExecutionContext.java b/src/main/java/com/example/demo/domain/vo/ExecutionContext.java new file mode 100644 index 0000000..76d3213 --- /dev/null +++ b/src/main/java/com/example/demo/domain/vo/ExecutionContext.java @@ -0,0 +1,25 @@ +package com.example.demo.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; + +import java.util.Date; + +@Data +@AllArgsConstructor +public class ExecutionContext { + // getters 和 setters + private String executionType; // "API" 或 "SCRIPT" + private String apiUrl; + private String requestParams; + private String token; + private String scriptFile; + private Date executionTime; + private String method; + + // 构造方法 + public ExecutionContext() { + this.executionTime = new Date(); + } + +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/domain/vo/ExportVo.java b/src/main/java/com/example/demo/domain/vo/ExportVo.java new file mode 100644 index 0000000..3042db9 --- /dev/null +++ b/src/main/java/com/example/demo/domain/vo/ExportVo.java @@ -0,0 +1,26 @@ +package com.example.demo.domain.vo; + +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @program: GOLD + * @ClassName ExportVo + * @description: + * @author: huangqizhen + * @create: 2025−06-29 17:24 + * @Version 1.0 + **/ +@Data +@NoArgsConstructor + +public class ExportVo { + private String token; + private Long id; + private String fileName; + private String url; + private Integer state; + +} diff --git a/src/main/java/com/example/demo/mapper/AiEmotionMapper.java b/src/main/java/com/example/demo/mapper/AiEmotionMapper.java new file mode 100644 index 0000000..52cd24b --- /dev/null +++ b/src/main/java/com/example/demo/mapper/AiEmotionMapper.java @@ -0,0 +1,25 @@ +package com.example.demo.mapper; + +import com.example.demo.domain.vo.AiEmotionExportRecordVO; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +/** + * @program: GOLD + * @ClassName AiEmotionMapper + * @description: + * @author: huangqizhen + * @create: 2025−06-29 16:48 + * @Version 1.0 + **/ +@Mapper +public interface AiEmotionMapper { + void updateStatus( + @Param("recordId") Long recordId, + @Param("state") Integer state, + @Param("url") String url, + @Param("reason") String reason, + @Param("dataNum") Integer dataNum + ); + AiEmotionExportRecordVO getRecordById(Long recordId); +} diff --git a/src/main/java/com/example/demo/mapper/ExportMapper.java b/src/main/java/com/example/demo/mapper/ExportMapper.java new file mode 100644 index 0000000..3d95954 --- /dev/null +++ b/src/main/java/com/example/demo/mapper/ExportMapper.java @@ -0,0 +1,19 @@ +package com.example.demo.mapper; + +import com.example.demo.domain.vo.ExportVo; +import org.apache.ibatis.annotations.Mapper; + +/** + * @program: GOLD + * @ClassName ExportMapper + * @description: + * @author: huangqizhen + * @create: 2025−06-29 17:28 + * @Version 1.0 + **/ +@Mapper +public interface ExportMapper { + ExportVo getExportData(Integer id); + ExportVo updateExportData(Long recordId, Integer state, String url, String reason, Integer dataNum); + +} diff --git a/src/main/java/com/example/demo/mapper/GoldDetailMapper.java b/src/main/java/com/example/demo/mapper/GoldDetailMapper.java index a6343f2..eaf1ee7 100644 --- a/src/main/java/com/example/demo/mapper/GoldDetailMapper.java +++ b/src/main/java/com/example/demo/mapper/GoldDetailMapper.java @@ -4,6 +4,7 @@ import com.example.demo.domain.entity.User; import com.example.demo.domain.vo.GoldDetail; import com.example.demo.domain.vo.Total; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; import java.util.List; @@ -19,7 +20,19 @@ import java.util.List; public interface GoldDetailMapper { List getGoldDetail(GoldDetail goldDetail); Total getTotal(GoldDetail goldDetail); - List getGold(User user); Total GoldTotal(User user); + public static class ExportRecordIdHolder{ + private Long id; + } + void insertExportRecord( + @Param("recordId") ExportRecordIdHolder recordId, // 用于接收主键 + @Param("jwcode") Integer jwcode, + @Param("type") Integer type, + @Param("state") Integer state, + @Param("url") String url, + @Param("fileName") String fileName, + @Param("dataNum") Integer dataNum + ); + ); } diff --git a/src/main/java/com/example/demo/service/AiEmotionService.java b/src/main/java/com/example/demo/service/AiEmotionService.java new file mode 100644 index 0000000..919e782 --- /dev/null +++ b/src/main/java/com/example/demo/service/AiEmotionService.java @@ -0,0 +1,19 @@ +package com.example.demo.service; + +import com.example.demo.domain.vo.AiEmotionExportRecordVO; +import com.example.demo.domain.vo.ExportVo; + +/** + * @program: GOLD + * @ClassName AiEmotionService + * @description: + * @author: huangqizhen + * @create: 2025−06-29 14:27 + * @Version 1.0 + **/ +public interface AiEmotionService { + + ExportVo updateStatus(Long recordId, int i, String s, String s1, int i1); + AiEmotionExportRecordVO getRecordById(Long id) throws Exception; + +} diff --git a/src/main/java/com/example/demo/service/ExportExcelService.java b/src/main/java/com/example/demo/service/ExportExcelService.java new file mode 100644 index 0000000..7db47e3 --- /dev/null +++ b/src/main/java/com/example/demo/service/ExportExcelService.java @@ -0,0 +1,16 @@ +package com.example.demo.service; + +import com.example.demo.domain.vo.AiEmotionExportRecordVO; + +/** + * @program: GOLD + * @ClassName exportService + * @description: + * @author: huangqizhen + * @create: 2025−06-28 15:39 + * @Version 1.0 + **/ +public interface ExportExcelService { + Exception handleExcelExportData(String message) throws Exception; + +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/service/GoldDetailService.java b/src/main/java/com/example/demo/service/GoldDetailService.java index 2592acc..6106f9e 100644 --- a/src/main/java/com/example/demo/service/GoldDetailService.java +++ b/src/main/java/com/example/demo/service/GoldDetailService.java @@ -1,9 +1,14 @@ package com.example.demo.service; +import com.example.demo.domain.DTO.GoldDetailDTO; import com.example.demo.domain.entity.User; import com.example.demo.domain.vo.GoldDetail; +import com.example.demo.domain.vo.Result; import com.example.demo.domain.vo.Total; import com.github.pagehelper.PageInfo; +import jakarta.servlet.http.HttpServletResponse; + +import java.io.IOException; /** * @program: GOLD @@ -19,4 +24,6 @@ public interface GoldDetailService { PageInfo getGold(Integer pageNum, Integer pageSize, User user); Total GoldTotal(User user); + //异步导出客户明细 + Result addExportRecord(GoldDetailDTO dto); } diff --git a/src/main/java/com/example/demo/service/PermissionService.java b/src/main/java/com/example/demo/service/PermissionService.java index 3cc4fe7..8d124bf 100644 --- a/src/main/java/com/example/demo/service/PermissionService.java +++ b/src/main/java/com/example/demo/service/PermissionService.java @@ -26,4 +26,5 @@ public interface PermissionService { List getRole(String token); Integer deleteAdmin(Integer id); Integer updateAdminRole(AdminRole adminRole); + Integer upadatePermission(Admin admin) throws Exception; } diff --git a/src/main/java/com/example/demo/serviceImpl/AiEmotionServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/AiEmotionServiceImpl.java new file mode 100644 index 0000000..e709ee4 --- /dev/null +++ b/src/main/java/com/example/demo/serviceImpl/AiEmotionServiceImpl.java @@ -0,0 +1,35 @@ +package com.example.demo.serviceImpl; + +import com.example.demo.domain.vo.AiEmotionExportRecordVO; +import com.example.demo.domain.vo.ExportVo; +import com.example.demo.mapper.AiEmotionMapper; +import com.example.demo.mapper.ExportMapper; +import com.example.demo.service.AiEmotionService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * @program: GOLD + * @ClassName AiEmotionServiceImpl + * @description: + * @author: huangqizhen + * @create: 2025−06-29 14:46 + * @Version 1.0 + **/ +@Service +public class AiEmotionServiceImpl implements AiEmotionService { + @Autowired + private ExportMapper exportMapper; + @Autowired + private AiEmotionMapper aiEmotionMapper; + + @Override + public ExportVo updateStatus(Long recordId, int i, String s, String s1, int i1) { + return exportMapper.updateExportData(recordId, i, s, s1, i1); + } + + @Override + public AiEmotionExportRecordVO getRecordById(Long id) throws Exception { + return aiEmotionMapper.getRecordById(id); + } +} diff --git a/src/main/java/com/example/demo/serviceImpl/ExportExcelServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/ExportExcelServiceImpl.java new file mode 100644 index 0000000..5895109 --- /dev/null +++ b/src/main/java/com/example/demo/serviceImpl/ExportExcelServiceImpl.java @@ -0,0 +1,253 @@ +package com.example.demo.serviceImpl; + +import cn.hutool.log.AbstractLog; +import com.alibaba.excel.EasyExcel; +import com.alibaba.excel.ExcelWriter; +import com.alibaba.excel.write.metadata.WriteSheet; +import com.example.demo.Util.ExcelUploadUtil; +import com.example.demo.controller.GoldDetailController; +import com.example.demo.domain.export.Goldmingxi; +import com.example.demo.domain.vo.*; + +import com.example.demo.service.ExportExcelService; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; + + + +import com.example.demo.service.AiEmotionService; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.io.*; +import java.util.List; +import java.util.Map; + + +@Service +@Slf4j +public class ExportExcelServiceImpl implements ExportExcelService { + + private static final ObjectMapper objectMapper = new ObjectMapper(); + + //注入AiEmotionService + @Autowired + private AiEmotionService aiEmotionService; + //注入GoldDetailController + @Autowired + private GoldDetailController goldDetailController; + + // 每页查询的数据量 + private static final int PAGE_SIZE = 1000; + + + @Transactional + @Override + public Exception handleExcelExportData(String message) throws Exception { + System.out.println("明细导出excel数据开始执行:" + message); + long startTime = System.currentTimeMillis(); + Long recordId = null; + String fileName = null; + File tempFile = null; + OutputStream outputStream = null; + ExcelWriter excelWriter = null; + + try { + // 1. 解析JSON任务 + JsonNode rootNode = objectMapper.readTree(message); + // 2. 获取基本参数 + recordId = rootNode.path("recordId").asLong(); + JsonNode requestDataNode = rootNode.path("requestData"); + // 3. 验证导出记录 + AiEmotionExportRecordVO record = validateExportRecord(recordId); + if (record == null) return null; + //4. 更新状态为处理中 + aiEmotionService.updateStatus(recordId, 1, "", "", 0); + // 5. 准备Excel文件 + fileName = record.getFileName(); + // 初始化临时文件(保存到本地临时目录) + tempFile = File.createTempFile("export_", ".xlsx"); + outputStream = new FileOutputStream(tempFile); // 使用文件输出流 + // 从JSON中提取单个值 + String text = requestDataNode.has("text") ? requestDataNode.get("text").asText() : null; + Integer sort = requestDataNode.has("sort") ? requestDataNode.get("sort").asInt() : null; + String field = requestDataNode.has("field") ? requestDataNode.get("field").asText() : null; + String deptId = requestDataNode.has("deptId") ? requestDataNode.get("deptId").asText() : null; + + try { + // 6. 初始化Excel写入器(指向本地文件流) + excelWriter = initExcelWriter(outputStream, "user"); + WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build(); + // 7. 分页查询并写入数据 + Page page = new Page(); + page.setPageNum(1); + page.setPageSize(1000); + Integer totalCount = 0; + boolean hasMore = true; + while (hasMore) { + Result pageResult = goldDetailController.getGoldDetail(page); + Integer code = pageResult.getCode(); + Object data = pageResult.getData(); + if (code == 200) { + Map rawData = (Map) data; + Long total = (Long) rawData.get("total"); + List> list = (List>) rawData.get("list"); + // 检查是否还有数据 + if (list == null || list.isEmpty()) { + hasMore = false; + } else { + // 写入数据(注意:finish()应在所有数据写入后调用) + excelWriter.write(list, writeSheet); + page.setPageNum(page.getPageNum() + 1); + totalCount += list.size(); + log.info("导出进度 recordId: {}, 已处理: {}条", recordId, totalCount); + // 检查是否还有更多数据 + hasMore = totalCount < total; + } + } else { + hasMore = false; + log.error("获取数据失败,状态码: {}", code); + } + } + // 7. 完成Excel写入(所有数据写入后关闭写入器) + if (excelWriter != null) { + excelWriter.finish(); + } + if (outputStream != null) { + outputStream.flush(); // 确保所有数据写入 + outputStream.close(); // 关闭文件流 + } + // 检查文件是否存在且不为空 + if (tempFile != null && tempFile.exists() && tempFile.length() > 0) { + // 8. 上传到OSS(读取本地临时文件) + // 获取接口的基础 URL + String uploadUrl = "http://39.101.133.168:8828/hljw/api/aws/upload"; + try { + // 1. 创建上传工具实例 + ExcelUploadUtil uploadUtil = new ExcelUploadUtil(uploadUrl); + + // 2. 准备要上传的文件 + File excelFile = new File(tempFile.toURI()); + try { + // 3. 执行上传 + String result = uploadUtil.uploadExcel(excelFile, "export/excel/"); + // 1. 解析JSON任务 + JsonNode uploadResult = objectMapper.readTree(result); + long code = uploadResult.path("code").asLong(); + String url = String.valueOf(uploadResult.path("data")); + url = url.replace("\"", ""); + if (code == 1) { + // 3. 验证导出记录decodecode + aiEmotionService.updateStatus(recordId, 2, url, "", totalCount); + } else { + //更新失败 + aiEmotionService.updateStatus(recordId, 3, "", url, 0); + } + } catch (Exception e) { + //更新失败 + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + throw new Exception("文件上传云端失败1", e); + } + } catch (Exception e) { + log.error("上传文件失败 recordId: {}, 文件名: {}", recordId, fileName, e); + //更新状态为失败 + if (recordId != null) { + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + } + throw new Exception("文件上传云端失败2", e); + } + } else { + throw new Exception("导出的Excel文件不存在或为空"); + } + + } catch (Exception e) { + System.out.println("导出异常" + e.getMessage()); + log.error("导出任务处理失败 recordId: {}", recordId, e); + // 更新状态为失败 + if (recordId != null) { + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + } + throw new Exception("导出异常", e); + } finally { + // 确保资源被关闭 + try { + if (excelWriter != null) { + excelWriter.finish(); + } + if (outputStream != null) { + outputStream.close(); + } + } catch (Exception e) { + log.error("关闭资源失败", e); + throw new Exception("excel文件关闭资源失败", e); + } + } + } catch (Exception e) { + log.error("导出任务处理失败 recordId: {}", recordId, e); + // 更新状态为失败 + if (recordId != null) { + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + } + System.out.println("<导出失败>" + e.getMessage()); + throw new Exception("导出任务处理失败", e); + } finally { + // 清理临时文件 + if (tempFile != null && tempFile.exists()) { + try { + if (tempFile.delete()) { + log.info("临时文件已删除: {}", tempFile.getAbsolutePath()); + } else { + log.warn("无法删除临时文件: {}", tempFile.getAbsolutePath()); + } + } catch (Exception e) { + log.error("删除临时文件失败", e.getMessage()); + throw new Exception("删除临时文件失败", e); + } + } + long endTime = System.currentTimeMillis(); + log.info("导出任务完成,耗时: {}毫秒", (endTime - startTime)); + } + return null; + } + + + /** + * 验证导出记录 + */ + private AiEmotionExportRecordVO validateExportRecord(Long recordId) throws Exception { + AiEmotionExportRecordVO record = aiEmotionService.getRecordById(recordId); + AbstractLog log = null; + if (record == null) { + log.error("导出记录不存在 recordId: {}", recordId); + return null; + } + + // 检查是否已经处理过 + if (record.getState() != 0) { + log.warn("导出记录已处理 recordId: {}, status: {}", recordId, record.getState()); + return null; + } + return record; + } + + /** + * 初始化excel文件 + * @param os + * @param exportType + * @return + */ + private ExcelWriter initExcelWriter(OutputStream os, String exportType) { + switch (exportType) { + case "user": + return EasyExcel.write(os, Goldmingxi.class) + .inMemory(Boolean.TRUE) + .build(); + default: + throw new IllegalArgumentException("不支持的导出类型: " + exportType); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java index adcc1c2..98bcb28 100644 --- a/src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java @@ -1,16 +1,24 @@ package com.example.demo.serviceImpl; +import com.example.demo.domain.DTO.GoldDetailDTO; import com.example.demo.domain.entity.User; import com.example.demo.domain.vo.GoldDetail; +import com.example.demo.domain.vo.Result; import com.example.demo.domain.vo.Total; import com.example.demo.mapper.GoldDetailMapper; import com.example.demo.service.GoldDetailService; +import com.fasterxml.jackson.databind.ObjectMapper; import com.github.pagehelper.PageHelper; import com.github.pagehelper.PageInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.io.IOException; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @program: GOLD @@ -25,24 +33,25 @@ public class GoldDetailServiceImpl implements GoldDetailService { @Autowired private GoldDetailMapper goldDetailMapper; + @Override public PageInfo getGoldDetail(Integer pageNum, Integer pageSize, GoldDetail goldDetail) { PageHelper.startPage(pageNum, pageSize); - List list= goldDetailMapper.getGoldDetail(goldDetail); + List list = goldDetailMapper.getGoldDetail(goldDetail); return new PageInfo<>(list); } @Override public Total getTotal(GoldDetail goldDetail) { - return goldDetailMapper.getTotal(goldDetail); + return goldDetailMapper.getTotal(goldDetail); } @Override public PageInfo getGold(Integer pageNum, Integer pageSize, User user) { PageHelper.startPage(pageNum, pageSize); - List list= goldDetailMapper.getGold(user); + List list = goldDetailMapper.getGold(user); return new PageInfo<>(list); } @@ -50,4 +59,58 @@ public class GoldDetailServiceImpl implements GoldDetailService { public Total GoldTotal(User user) { return goldDetailMapper.GoldTotal(user); } + + @Override + public Result addExportRecord(GoldDetailDTO dto) { + // 获取操作者 jwcode + + // 生成文件名 + String fileName = String.format("%s_%s_%s.xlsx", + "客户金币明细", + "操作人", + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); + System.out.println(fileName); + dto.setJwcode(123456); + dto.setUrl(""); + dto.setFileName(fileName); + dto.setDataNum(0); + try{ + // 调用方式 + GoldDetailMapper.ExportRecordIdHolder idHolder = new AiEmotionMapper.ExportRecordIdHolder(); + goldDetailMapper.insertExportRecord( + idHolder, // 用于接收主键 + dto.getJwcode(), + dto.getType(), + dto.getState(), + dto.getUrl(), + dto.getFileName(), + dto.getDataNum() + ); + // 获取主键 + Long recordId = idHolder.getId(); + // 2. 构造完整的 JSON 数据(包含所有请求参数) + Map exportData = new HashMap<>(); + exportData.put("recordId", recordId); + + // 手动构造请求数据(避免 toString() 只返回部分字段) + Map requestData = new HashMap<>(); + requestData.put("text", dto.getText()); + requestData.put("sort", dto.getSort()); + requestData.put("field", dto.getField()); + requestData.put("deptId", dto.getDeptid()); + exportData.put("requestData", requestData); + + // 3. 发送到 Redis 消息队列 + String jsonData = new ObjectMapper().writeValueAsString(exportData); + redisUtil.sendMessage("hwgold:queue:export_queue", jsonData); + }catch (Exception e){ + e.printStackTrace(); + throw new SystemException("导出数据异常,请稍后重试", e); + } + return Result.success(); + } + +} + } + } diff --git a/src/main/java/com/example/demo/serviceImpl/PermissionServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/PermissionServiceImpl.java index 83cdc06..d4b5cf5 100644 --- a/src/main/java/com/example/demo/serviceImpl/PermissionServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/PermissionServiceImpl.java @@ -111,5 +111,10 @@ public class PermissionServiceImpl implements PermissionService { return permissionMapper.updateAdminRole(adminRole); } + @Override + public Integer upadatePermission(Admin admin) throws Exception { + return permissionMapper.updatePermission(admin); + } + } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index cbbfb21..bb5201b 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -4,9 +4,9 @@ spring: fail-on-unknown-properties: false datasource: mysql1: - jdbc-url: jdbc:mysql://192.168.8.220:3306/hwgold?serverTimezone=Asia/Shanghai - username: hwgold - password: 123456 + jdbc-url: jdbc:mysql://18.143.76.3:3306/hwgoldc?serverTimezone=Asia/Shanghai + username: hwgoldc + password: zB48T55wCsHC8KPz driver-class-name: com.mysql.cj.jdbc.Driver hikari: pool-name: mysql1HikariCP @@ -62,10 +62,10 @@ spring: data: redis: database: 0 - host: 192.168.8.94 - port: 6379 - password: - timeout: 1000 + host: 18.143.76.3 + port: 10703 + password: Ngc0FYUTA6h3wC5J + lettuce: pool: max-active: 20 diff --git a/src/main/resources/mapper/AiEmotionMapper.xml b/src/main/resources/mapper/AiEmotionMapper.xml new file mode 100644 index 0000000..2824bba --- /dev/null +++ b/src/main/resources/mapper/AiEmotionMapper.xml @@ -0,0 +1,17 @@ + + + + + UPDATE admin_export_record + + state = #{state}, + url = #{url}, + reason = #{reason}, + data_num = #{dataNum}, + + WHERE id = #{recordId} + + + \ No newline at end of file diff --git a/src/main/resources/mapper/ExportMapper.xml b/src/main/resources/mapper/ExportMapper.xml new file mode 100644 index 0000000..8cfcb31 --- /dev/null +++ b/src/main/resources/mapper/ExportMapper.xml @@ -0,0 +1,18 @@ + + + + + UPDATE export + + state = #{state}, + url = #{url}, + reason = #{reason}, + data_num = #{dataNum}, + + WHERE id = #{recordId} + + + + \ No newline at end of file diff --git a/src/main/resources/mapper/GoldDetailMapper.xml b/src/main/resources/mapper/GoldDetailMapper.xml index 02cfb51..8e0c357 100644 --- a/src/main/resources/mapper/GoldDetailMapper.xml +++ b/src/main/resources/mapper/GoldDetailMapper.xml @@ -1,6 +1,9 @@ + + insert into + select * from user - + and jwcode = #{jwcode} @@ -83,7 +86,7 @@ sum(current_permanent_gold) + sum(current_free_june + current_free_december) + sum(current_task_gold) as Goldtotal from `user` - + and jwcode = #{jwcode} diff --git a/src/main/resources/mapper/PermissionMapper.xml b/src/main/resources/mapper/PermissionMapper.xml index e16d781..5fbb905 100644 --- a/src/main/resources/mapper/PermissionMapper.xml +++ b/src/main/resources/mapper/PermissionMapper.xml @@ -12,20 +12,11 @@ update admin - - admin_name=#{name}, - - - market=#{market}, - - - postiton=#{postiton}, - - - roleId=#{role}, + + admin_status= #{adminStatus}, - where id= #{id} + where id=#{id} update admin_role @@ -49,7 +40,7 @@ select distinct market from admin - + \ No newline at end of file diff --git a/src/main/resources/mapper/UrlMapper.xml b/src/main/resources/mapper/UrlMapper.xml new file mode 100644 index 0000000..714c781 --- /dev/null +++ b/src/main/resources/mapper/UrlMapper.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file From 979abbd622b4dfb5781f0f95d0360d11ee761286 Mon Sep 17 00:00:00 2001 From: sunjiabei Date: Mon, 30 Jun 2025 15:44:32 +0800 Subject: [PATCH 07/16] =?UTF-8?q?=E6=A5=BC=E4=B8=8A=E6=8E=A5=E5=8F=A3+?= =?UTF-8?q?=E5=95=86=E5=93=81=E6=9F=A5=E8=AF=A2=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/demo/controller/ConsumeController.java | 8 +++++++- .../com/example/demo/controller/RefundController.java | 2 +- .../java/com/example/demo/mapper/RefundMapper.java | 2 +- .../java/com/example/demo/service/RefundService.java | 2 +- .../example/demo/serviceImpl/ConsumeServiceImpl.java | 6 ++++++ .../example/demo/serviceImpl/RefundServiceImpl.java | 15 ++++++++++----- src/main/resources/application.yml | 6 +++--- src/main/resources/mapper/RechargeMapper.xml | 18 +++++++++--------- src/main/resources/mapper/RefundMapper.xml | 7 +++++-- 9 files changed, 43 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/example/demo/controller/ConsumeController.java b/src/main/java/com/example/demo/controller/ConsumeController.java index cb99af9..27039a3 100644 --- a/src/main/java/com/example/demo/controller/ConsumeController.java +++ b/src/main/java/com/example/demo/controller/ConsumeController.java @@ -84,7 +84,13 @@ public class ConsumeController { @PostMapping("/add") public Result add(@RequestBody ConsumeUser consumeUser) { try { - return consumeService.add(consumeUser); + if(consumeUser.getJwcode().equals(94226013)) + { + return consumeService.add(consumeUser); + }else { + return Result.error("不是测试的精网号,无法添加消费"); + } + } catch (Exception e) { return Result.error("接口调用失败"); } diff --git a/src/main/java/com/example/demo/controller/RefundController.java b/src/main/java/com/example/demo/controller/RefundController.java index d75573c..edd707b 100644 --- a/src/main/java/com/example/demo/controller/RefundController.java +++ b/src/main/java/com/example/demo/controller/RefundController.java @@ -85,7 +85,7 @@ public class RefundController { @PostMapping("/selectGoods") public Result getSelectGoods(@RequestBody RefundUser refundUser) { - List list = refundService.selectGoods(refundUser.getJwcode()); + List list = refundService.selectGoods(refundUser.getJwcode()); return Result.success(list); } diff --git a/src/main/java/com/example/demo/mapper/RefundMapper.java b/src/main/java/com/example/demo/mapper/RefundMapper.java index 5f2970a..3f8f14c 100644 --- a/src/main/java/com/example/demo/mapper/RefundMapper.java +++ b/src/main/java/com/example/demo/mapper/RefundMapper.java @@ -27,6 +27,6 @@ public interface RefundMapper { List getRefundType(); - List selectGoods(Integer jwcode); + List selectGoods(Integer jwcode); } diff --git a/src/main/java/com/example/demo/service/RefundService.java b/src/main/java/com/example/demo/service/RefundService.java index 55b856c..f8cbb41 100644 --- a/src/main/java/com/example/demo/service/RefundService.java +++ b/src/main/java/com/example/demo/service/RefundService.java @@ -31,5 +31,5 @@ public interface RefundService { //获取退款类型 List getRefundType(); - List selectGoods(Integer jwcode); + List selectGoods(Integer jwcode); } diff --git a/src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java index 7fb3df7..d8a066c 100644 --- a/src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/ConsumeServiceImpl.java @@ -1,5 +1,6 @@ package com.example.demo.serviceImpl; +import com.example.demo.Util.GoldTistV2; import com.example.demo.domain.entity.User; import com.example.demo.domain.entity.UserGoldRecord; import com.example.demo.domain.vo.ConsumeUser; @@ -14,6 +15,7 @@ import com.github.pagehelper.PageInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; @@ -158,6 +160,10 @@ public class ConsumeServiceImpl implements ConsumeService { user.setConsumeNum(gold.getConsumeNum() + 1); user.setSumConsume(consumeUser.getPermanentGold() + consumeUser.getFreeGold() + consumeUser.getTaskGold()); userMapper.updateGold(user); + //对接接口 + GoldTistV2.addCoinNew(userGoldRecord.getJwcode().toString(), 65, + userGoldRecord.getPermanentGold() + userGoldRecord.getFreeDecember()+userGoldRecord.getFreeJune()+userGoldRecord.getTaskGold(), + userGoldRecord.getRemark(),userGoldRecord.getPermanentGold(), userGoldRecord.getPayPlatform(), userGoldRecord.getGoodsName()); return Result.success(); } } diff --git a/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java index 8ff5138..680cf05 100644 --- a/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java @@ -142,10 +142,10 @@ public class RefundServiceImpl implements RefundService { } @Override - public List selectGoods(Integer jwcode) { - List userGoldRecords = refundMapper.selectGoods(jwcode); - List list = new ArrayList<>(); - for (UserGoldRecord record : userGoldRecords) { + public List selectGoods(Integer jwcode) { + List refundUsers = refundMapper.selectGoods(jwcode); + List list = new ArrayList<>(); + for (RefundUser record : refundUsers) { if (record == null) { continue; } @@ -155,7 +155,12 @@ public class RefundServiceImpl implements RefundService { // 拼接格式:订单号_商品名(例如:XF20250629_商品BC) String combined = orderCode + "_" + goodsName; - list.add(combined); + RefundUser refundUser = new RefundUser(); + refundUser.setGoodsName(combined); + refundUser.setPermanentGold(record.getPermanentGold()); + refundUser.setFreeGold(record.getFreeGold()); + refundUser.setTaskGold(record.getTaskGold()); + list.add(refundUser); } return list; } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index cbbfb21..704b8fa 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -4,9 +4,9 @@ spring: fail-on-unknown-properties: false datasource: mysql1: - jdbc-url: jdbc:mysql://192.168.8.220:3306/hwgold?serverTimezone=Asia/Shanghai - username: hwgold - password: 123456 + jdbc-url: jdbc:mysql://18.143.76.3:3306/hwgoldc?serverTimezone=Asia/Shanghai + username: hwgoldc + password: zB48T55wCsHC8KPz driver-class-name: com.mysql.cj.jdbc.Driver hikari: pool-name: mysql1HikariCP diff --git a/src/main/resources/mapper/RechargeMapper.xml b/src/main/resources/mapper/RechargeMapper.xml index 5bec492..99d86ad 100644 --- a/src/main/resources/mapper/RechargeMapper.xml +++ b/src/main/resources/mapper/RechargeMapper.xml @@ -19,7 +19,7 @@ ugr.remark AS remark, ugr.admin_id AS adminId, a.admin_name AS adminName, - ugr.create_time AS createTime + ugr.pay_time AS payTime FROM user u JOIN user_gold_record ugr ON u.jwcode = ugr.jwcode JOIN admin a ON ugr.admin_id = a.id @@ -35,9 +35,9 @@ ugr.permanent_gold (COALESCE(ugr.free_june, 0) + COALESCE(ugr.free_december, 0)) - ugr.create_time + ugr.pay_time - ugr.create_time + ugr.pay_time @@ -55,7 +55,7 @@ - ugr.create_time DESC + ugr.pay_time DESC @@ -78,7 +78,7 @@ ugr.remark AS remark, ugr.admin_id AS adminId, a.admin_name AS adminName, - ugr.create_time AS createTime + ugr.pay_time AS payTime FROM user u JOIN user_gold_record ugr ON u.jwcode = ugr.jwcode JOIN admin a ON ugr.admin_id = a.id @@ -98,7 +98,7 @@ AND ugr.pay_platform = #{payPlatform} - AND ugr.create_time BETWEEN #{startTime} AND #{endTime} + AND ugr.pay_time BETWEEN #{startTime} AND #{endTime} @@ -110,9 +110,9 @@ ugr.permanent_gold (COALESCE(ugr.free_june, 0) + COALESCE(ugr.free_december, 0)) - ugr.create_time + ugr.pay_time - ugr.create_time + ugr.pay_time @@ -130,7 +130,7 @@ - ugr.create_time DESC + ugr.pay_time DESC diff --git a/src/main/resources/mapper/RefundMapper.xml b/src/main/resources/mapper/RefundMapper.xml index ea654ba..0b74202 100644 --- a/src/main/resources/mapper/RefundMapper.xml +++ b/src/main/resources/mapper/RefundMapper.xml @@ -180,10 +180,13 @@ select DISTINCT refund_Type from user_gold_record - SELECT ugr.goods_name AS goodsName, - ugr.order_code AS orderCode + ugr.order_code AS orderCode, + ugr.permanent_gold AS permanentGold, + (COALESCE(ugr.free_june, 0) + COALESCE(ugr.free_december, 0)) AS freeGold, + ugr.task_gold AS taskGold FROM user_gold_record ugr ugr.type = 1 From e56cb9744f377b85c006eb1070940f500f9e2555 Mon Sep 17 00:00:00 2001 From: huangqizhen <15552608129@163.com> Date: Mon, 30 Jun 2025 15:56:13 +0800 Subject: [PATCH 08/16] =?UTF-8?q?=E5=8F=AF=E8=B7=91=EF=BC=88=E4=B8=8D?= =?UTF-8?q?=E5=90=88=E5=B9=B6=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../demo/controller/GoldDetailController.java | 4 +- .../example/demo/exception/SystemException.java | 13 ++++ .../com/example/demo/mapper/GoldDetailMapper.java | 3 +- .../service/listen/AiEmotionExportListener.java | 84 ++++++++++++++++++++++ .../service/queue/AbstractMessageListener.java | 69 ++++++++++++++++++ .../demo/serviceImpl/GoldDetailServiceImpl.java | 10 ++- src/main/resources/mapper/GoldDetailMapper.xml | 5 +- 7 files changed, 180 insertions(+), 8 deletions(-) create mode 100644 src/main/java/com/example/demo/exception/SystemException.java create mode 100644 src/main/java/com/example/demo/service/listen/AiEmotionExportListener.java create mode 100644 src/main/java/com/example/demo/service/queue/AbstractMessageListener.java diff --git a/src/main/java/com/example/demo/controller/GoldDetailController.java b/src/main/java/com/example/demo/controller/GoldDetailController.java index 41ba378..e188e13 100644 --- a/src/main/java/com/example/demo/controller/GoldDetailController.java +++ b/src/main/java/com/example/demo/controller/GoldDetailController.java @@ -72,7 +72,7 @@ public class GoldDetailController { } return Result.success(goldDetailService.getGold(page.getPageNum(), page.getPageSize(), page.getUser())); } - @PostMapping("export") + @PostMapping("/export") public Result export(@Valid @RequestBody GoldDetailDTO dto) { String lockKey = "export:lock:" + dto.getToken(); // 锁的 Key(可按用户/业务区分) String requestId = UUID.randomUUID().toString(); // 请求 ID(防止误删锁) @@ -83,7 +83,7 @@ public class GoldDetailController { throw new BusinessException("操作太频繁,请稍后重试"); } // 执行业务逻辑 - return GoldDetailService.addExportRecord(dto); + return goldDetailService.addExportRecord(dto); } finally { // 释放锁 redisLockUtil.unlock(lockKey, requestId); diff --git a/src/main/java/com/example/demo/exception/SystemException.java b/src/main/java/com/example/demo/exception/SystemException.java new file mode 100644 index 0000000..5a049f1 --- /dev/null +++ b/src/main/java/com/example/demo/exception/SystemException.java @@ -0,0 +1,13 @@ +package com.example.demo.exception; + +public class SystemException extends RuntimeException { + public SystemException(String message) { + super(message); + } + + + public SystemException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/src/main/java/com/example/demo/mapper/GoldDetailMapper.java b/src/main/java/com/example/demo/mapper/GoldDetailMapper.java index eaf1ee7..0bbaf61 100644 --- a/src/main/java/com/example/demo/mapper/GoldDetailMapper.java +++ b/src/main/java/com/example/demo/mapper/GoldDetailMapper.java @@ -3,6 +3,7 @@ package com.example.demo.mapper; import com.example.demo.domain.entity.User; import com.example.demo.domain.vo.GoldDetail; import com.example.demo.domain.vo.Total; +import lombok.Data; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; @@ -22,6 +23,7 @@ public interface GoldDetailMapper { Total getTotal(GoldDetail goldDetail); List getGold(User user); Total GoldTotal(User user); + @Data public static class ExportRecordIdHolder{ private Long id; } @@ -34,5 +36,4 @@ public interface GoldDetailMapper { @Param("fileName") String fileName, @Param("dataNum") Integer dataNum ); - ); } diff --git a/src/main/java/com/example/demo/service/listen/AiEmotionExportListener.java b/src/main/java/com/example/demo/service/listen/AiEmotionExportListener.java new file mode 100644 index 0000000..c2b3903 --- /dev/null +++ b/src/main/java/com/example/demo/service/listen/AiEmotionExportListener.java @@ -0,0 +1,84 @@ +package com.example.demo.service.listen; + +import cn.hutool.core.util.StrUtil; + + +import com.example.demo.Util.ExecutionContextUtil; +import com.example.demo.Util.FeiShuAlertUtil; +import com.example.demo.Util.RedisUtil; +import com.example.demo.domain.vo.ExecutionContext; +import com.example.demo.service.ExportExcelService; +import com.example.demo.service.queue.AbstractMessageListener; + + + + + + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import static java.lang.Thread.sleep; + + +@Component +public class AiEmotionExportListener extends AbstractMessageListener { + + + //注入ExportExcelService + @Autowired + private ExportExcelService exportExcelService; + + @Autowired + public AiEmotionExportListener( + RedisUtil redisQueueUtil + + ) { + super(redisQueueUtil, "hwgold:queue:export_queue"); + System.out.println("监听器已启动,队列: "); + } + + @Override + protected void handleMessage(String message) { + if (StrUtil.isBlank(message)) { + System.err.println("redis消息队列数据为空" + message); + } + try { + Thread.sleep(5000); + exportExcelService.handleExcelExportData(message); + } catch (Exception e) { + logError(e, message); + throw new RuntimeException("Failed to process AI emotion export: " + e.getMessage(), e); + } + + + } + + private void logError(Exception e, String message) { + System.err.println("Export data listener exception: " + e.getMessage()); + e.printStackTrace(); + try { + ExecutionContext context = ExecutionContextUtil.getExecutionContext(); + String cause = ""; + if (e.getCause() != null) { + cause = e.getCause().getMessage(); + } + FeiShuAlertUtil.sendAlertMessage( + context, + e.getStackTrace()[0].getFileName(), + e.getStackTrace()[0].getLineNumber(), + "AI Emotion Export Error: " + e.getMessage() + " 底层错误: " + cause , + "Failed message: " + message + ); + } catch (Exception alertEx) { + System.err.println("Failed to send Feishu alert: " + alertEx.getMessage()); + } + } + + @Override + protected void handleError(Exception e, String message) { + System.err.println("处理消息失败: " + message); + e.printStackTrace(); + } + +} diff --git a/src/main/java/com/example/demo/service/queue/AbstractMessageListener.java b/src/main/java/com/example/demo/service/queue/AbstractMessageListener.java new file mode 100644 index 0000000..db165db --- /dev/null +++ b/src/main/java/com/example/demo/service/queue/AbstractMessageListener.java @@ -0,0 +1,69 @@ +package com.example.demo.service.queue; + + + +import com.example.demo.Util.RedisUtil; +import jakarta.annotation.PostConstruct; + + +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; + +/** + * 抽象消息监听器 + */ +public abstract class AbstractMessageListener { + + private final ExecutorService executorService = Executors.newSingleThreadExecutor(); + protected final RedisUtil redisQueueUtil; + protected final String queueName; + + public AbstractMessageListener(RedisUtil redisQueueUtil, String queueName) { + this.redisQueueUtil = redisQueueUtil; + this.queueName = queueName; + } + + @PostConstruct + public void init() { + executorService.submit(this::listen); + } + + private void listen() { + System.out.println("消费者消费数据" + queueName + ""); + while (!Thread.currentThread().isInterrupted()) { + try { + Object message = redisQueueUtil.blockingGetMessage(queueName, 1); + if (message != null) { + try { + handleMessage((T) message); + } catch (Exception e) { + handleError(e, (T) message); + } + } + } catch (Exception e) { + System.err.println("监听队列异常: " + e.getMessage()); + try { + Thread.sleep(5000); + } catch (InterruptedException ex) { + Thread.currentThread().interrupt(); + } + } + } + } + + /** + * 处理消息 + * @param message 消息内容 + */ + protected abstract void handleMessage(T message); + + /** + * 处理错误 + * @param e 异常 + * @param message 消息内容 + */ + protected void handleError(Exception e, T message) { + System.err.println("处理消息异常: " + e.getMessage()); + } + +} diff --git a/src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java index 98bcb28..7d0dbcf 100644 --- a/src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java @@ -1,10 +1,12 @@ package com.example.demo.serviceImpl; +import com.example.demo.Util.RedisUtil; import com.example.demo.domain.DTO.GoldDetailDTO; import com.example.demo.domain.entity.User; import com.example.demo.domain.vo.GoldDetail; import com.example.demo.domain.vo.Result; import com.example.demo.domain.vo.Total; +import com.example.demo.exception.SystemException; import com.example.demo.mapper.GoldDetailMapper; import com.example.demo.service.GoldDetailService; import com.fasterxml.jackson.databind.ObjectMapper; @@ -33,6 +35,8 @@ public class GoldDetailServiceImpl implements GoldDetailService { @Autowired private GoldDetailMapper goldDetailMapper; + @Autowired + private RedisUtil redisUtil; @Override public PageInfo getGoldDetail(Integer pageNum, Integer pageSize, GoldDetail goldDetail) { @@ -76,7 +80,7 @@ public class GoldDetailServiceImpl implements GoldDetailService { dto.setDataNum(0); try{ // 调用方式 - GoldDetailMapper.ExportRecordIdHolder idHolder = new AiEmotionMapper.ExportRecordIdHolder(); + GoldDetailMapper.ExportRecordIdHolder idHolder = new GoldDetailMapper.ExportRecordIdHolder(); goldDetailMapper.insertExportRecord( idHolder, // 用于接收主键 dto.getJwcode(), @@ -111,6 +115,6 @@ public class GoldDetailServiceImpl implements GoldDetailService { } } - } -} + + diff --git a/src/main/resources/mapper/GoldDetailMapper.xml b/src/main/resources/mapper/GoldDetailMapper.xml index 8e0c357..10d027b 100644 --- a/src/main/resources/mapper/GoldDetailMapper.xml +++ b/src/main/resources/mapper/GoldDetailMapper.xml @@ -1,8 +1,9 @@ - - insert into + + insert into excprt (jwcode,type,state,url,file_name,data_num) + values(#{jwcode},#{type},#{state},#{url},#{fileName},#{dataNum}) SELECT + ugr.goods_name AS goodsName, ugr.order_code AS orderCode, ugr.permanent_gold AS permanentGold, From 04b61d26875890a19c9c700ef1114c4012945b4f Mon Sep 17 00:00:00 2001 From: jianlin Date: Tue, 1 Jul 2025 10:32:04 +0800 Subject: [PATCH 10/16] =?UTF-8?q?6-30=E5=AE=A1=E6=A0=B8=E7=9B=B8=E5=85=B3?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=EF=BC=88=E7=BC=BA=E7=BB=9F=E8=AE=A1=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/demo/controller/AuditController.java | 42 ++++++++- .../demo/controller/StatisticsController.java | 5 + .../demo/controller/WorkbenchController.java | 2 +- .../com/example/demo/domain/vo/AuditRequest.java | 18 ++++ src/main/java/com/example/demo/domain/vo/Page.java | 2 + .../com/example/demo/domain/vo/RechargeAudit.java | 57 +++++++++++ .../com/example/demo/domain/vo/RefundAudit.java | 55 +++++++++++ .../demo/domain/vo/WorkbenchMarketCard.java | 2 +- .../java/com/example/demo/mapper/AuditMapper.java | 25 ++++- .../com/example/demo/service/AuditService.java | 13 +++ .../com/example/demo/service/WorkbenchService.java | 2 +- .../example/demo/serviceImpl/AuditServiceImpl.java | 104 ++++++++++++++++++++- .../demo/serviceImpl/StatisticsServiceImpl.java | 12 ++- .../demo/serviceImpl/WorkbenchServiceImpl.java | 6 +- src/main/resources/application.yml | 6 +- src/main/resources/mapper/AuditMapper.xml | 103 ++++++++++++++++++++ src/main/resources/mapper/StatisticsMapper.xml | 4 +- 17 files changed, 441 insertions(+), 17 deletions(-) create mode 100644 src/main/java/com/example/demo/domain/vo/AuditRequest.java create mode 100644 src/main/java/com/example/demo/domain/vo/RechargeAudit.java create mode 100644 src/main/java/com/example/demo/domain/vo/RefundAudit.java diff --git a/src/main/java/com/example/demo/controller/AuditController.java b/src/main/java/com/example/demo/controller/AuditController.java index 7c58292..bec1e92 100644 --- a/src/main/java/com/example/demo/controller/AuditController.java +++ b/src/main/java/com/example/demo/controller/AuditController.java @@ -1,11 +1,17 @@ package com.example.demo.controller; +import com.example.demo.domain.vo.AuditRequest; +import com.example.demo.domain.vo.Page; +import com.example.demo.domain.vo.RechargeAudit; +import com.example.demo.domain.vo.RefundAudit; +import com.example.demo.service.AuditService; +import com.github.pagehelper.PageInfo; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; /** * @program: gold-java @@ -23,4 +29,34 @@ import org.springframework.web.bind.annotation.RestController; @Transactional @CrossOrigin public class AuditController { + + @Autowired + private AuditService auditService; + + //审核订单 + @PostMapping("audit") + public ResponseEntity auditOrder( + @RequestBody AuditRequest request) { + boolean result = auditService.auditOrder(request.getToken(),request.getOrderCode(), request.getAuditId(), request.getAction(),request.getRejectReason()); + return ResponseEntity.ok(result); +} + //多条件查询充值审核订单列表 + @PostMapping("selectRecharge") + public PageInfo searchRechargeAudit( + @RequestBody Page page) { + Integer pageNum = page.getPageNum(); + Integer pageSize = page.getPageSize(); + RechargeAudit rechargeAudit = page.getRechargeAudit(); + + return auditService.selectRechargeBy(pageNum, pageSize, rechargeAudit); +} //多条件查询退款审核订单列表 + @PostMapping("selectRefund") + public PageInfo searchRefundAudit( + @RequestBody Page page) { + Integer pageNum = page.getPageNum(); + Integer pageSize = page.getPageSize(); + RefundAudit refundAudit = page.getRefundAudit(); + + return auditService.selectRefundBy(pageNum, pageSize, refundAudit); +} } diff --git a/src/main/java/com/example/demo/controller/StatisticsController.java b/src/main/java/com/example/demo/controller/StatisticsController.java index d18fee3..c1a9726 100644 --- a/src/main/java/com/example/demo/controller/StatisticsController.java +++ b/src/main/java/com/example/demo/controller/StatisticsController.java @@ -44,6 +44,11 @@ public class StatisticsController { public void HourlyTask2() { statisticsService.runHourlyTaskPart2(); } + //测试一周内定时任务part2 + @PostMapping("/Daily2") + public void DailyTask2() { + statisticsService.runDailyTaskPart2(); + } diff --git a/src/main/java/com/example/demo/controller/WorkbenchController.java b/src/main/java/com/example/demo/controller/WorkbenchController.java index 3e73097..f6fcf8c 100644 --- a/src/main/java/com/example/demo/controller/WorkbenchController.java +++ b/src/main/java/com/example/demo/controller/WorkbenchController.java @@ -43,7 +43,7 @@ public class WorkbenchController { */ @PostMapping("getCard") public ResponseEntity card1(@RequestBody WorkbenchCard workbench){ - WorkbenchCard result =workbenchService.getCard(workbench.getToken(),workbench.getMarkets()); + WorkbenchCard result =workbenchService.getCard(workbench.getToken()); return ResponseEntity.ok(result); } /* diff --git a/src/main/java/com/example/demo/domain/vo/AuditRequest.java b/src/main/java/com/example/demo/domain/vo/AuditRequest.java new file mode 100644 index 0000000..3be612a --- /dev/null +++ b/src/main/java/com/example/demo/domain/vo/AuditRequest.java @@ -0,0 +1,18 @@ +package com.example.demo.domain.vo; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class AuditRequest { + private String token; + private String orderCode; //订单号 + private Integer auditId; //审核人id + private Integer action; //操作 + private String rejectReason; //驳回理由 + + +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/domain/vo/Page.java b/src/main/java/com/example/demo/domain/vo/Page.java index 978d398..ba295de 100644 --- a/src/main/java/com/example/demo/domain/vo/Page.java +++ b/src/main/java/com/example/demo/domain/vo/Page.java @@ -24,4 +24,6 @@ public class Page { private User user; private RefundUser refundUser; private Permission permission; + private RechargeAudit rechargeAudit; + private RefundAudit refundAudit; } diff --git a/src/main/java/com/example/demo/domain/vo/RechargeAudit.java b/src/main/java/com/example/demo/domain/vo/RechargeAudit.java new file mode 100644 index 0000000..4438ea6 --- /dev/null +++ b/src/main/java/com/example/demo/domain/vo/RechargeAudit.java @@ -0,0 +1,57 @@ +package com.example.demo.domain.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @program: gold-java + * @ClassName RechargeAudit + * @description: 充值审核 + * @author: Ethan + * @create: 2025−06-30 10:29 + * @Version 1.0 + **/ + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class RechargeAudit { + private static final long serialVersionUID = 1L; + + private String name; // 客户姓名 + private Integer jwcode; // 精网号 + private String orderCode; // 订单号 + private String activity; // 活动名称 + private String market; // 所属地区 + private Byte refundType; // 退款类型 + private Integer sumGold; //充值金额 + private Integer permanentGold; // 永久金币 + private Integer freeGold; // 免费金币 + private Integer freeJune; // 6月免费金币 + private Integer freeDecember; // 12月免费金币 + private String remark; // 备注 + private String payModel; //支付方式 + private String voucher; //支付凭证 + private Integer adminId; //提交人Id + private String adminName; //提交人姓名 + private String auditStatus; //审核状态 + private Integer auditId; //审核人Id + private String auditName; //审核人姓名 + private Byte type; //类型 + private String rejectReason; //驳回理由 + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private String payTime; //支付时间 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date createTime; // 创建时间 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date startTime; // 开始时间 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date endTime; // 结束时间 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date auditTime; // 审核时间 +} diff --git a/src/main/java/com/example/demo/domain/vo/RefundAudit.java b/src/main/java/com/example/demo/domain/vo/RefundAudit.java new file mode 100644 index 0000000..f7715c8 --- /dev/null +++ b/src/main/java/com/example/demo/domain/vo/RefundAudit.java @@ -0,0 +1,55 @@ +package com.example.demo.domain.vo; + +import com.fasterxml.jackson.annotation.JsonFormat; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Date; + +/** + * @program: gold-java + * @ClassName RechargeAudit + * @description: 退款审核 + * @author: Ethan + * @create: 2025−06-30 13:29 + * @Version 1.0 + **/ + +@Data +@NoArgsConstructor +@AllArgsConstructor +public class RefundAudit { + private static final long serialVersionUID = 1L; + private String name; // 客户姓名 + private Integer jwcode; // 精网号 + private String orderCode; // 订单号 + private String market; // 所属地区 + private Byte refundModel; // 退款方式-全额 部分 + private String goodsName; // 商品名称 + private Integer sumGold; // 退款金额 + private Integer permanentGold; // 永久金币 + private Integer freeGold; // 免费金币 + private Integer freeJune; // 6月免费金币 + private Integer freeDecember; // 12月免费金币 + private String remark; // 备注 + private String payModel; //支付方式 + private String voucher; //支付凭证 + private Integer adminId; //提交人Id + private String adminName; //提交人姓名 + private String auditStatus; //审核状态 + private Integer auditId; //审核人Id + private String auditName; //审核人姓名 + private String rejectReason; //驳回理由 + private Byte type; //类型 + + + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date createTime; // 创建时间 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date startTime; // 开始时间 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date endTime; // 结束时间 + @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") + private Date auditTime; // 审核时间 +} diff --git a/src/main/java/com/example/demo/domain/vo/WorkbenchMarketCard.java b/src/main/java/com/example/demo/domain/vo/WorkbenchMarketCard.java index 747c0bc..36db07f 100644 --- a/src/main/java/com/example/demo/domain/vo/WorkbenchMarketCard.java +++ b/src/main/java/com/example/demo/domain/vo/WorkbenchMarketCard.java @@ -45,7 +45,7 @@ public class WorkbenchMarketCard implements Serializable { private Integer refundFreeJune; // 当日新增退款(六月免费) private Integer refundFreeDecember; // 当日新增退款(十二月免费) private Integer refundTask; // 当日新增退款(任务) - private Integer dailyConsume; // 当日总消耗 = consumePermanent + consumeFreeJune + consumeFreeDecember + consumeTask - (refundPermanent + refundFreeJune + refundFreeDecember + refundTask) + private Integer dailyReduce; // 当日总消耗 = consumePermanent + consumeFreeJune + consumeFreeDecember + consumeTask - (refundPermanent + refundFreeJune + refundFreeDecember + refundTask) private Integer yearlyConsume; // 全年累计消费 private Integer yearlyRefund; // 全年累计退款金币数 private Integer yearlyReduce; // 全年累计消耗金币数 = yearlyConsume - yearlyRefund diff --git a/src/main/java/com/example/demo/mapper/AuditMapper.java b/src/main/java/com/example/demo/mapper/AuditMapper.java index 63dc767..1287ccd 100644 --- a/src/main/java/com/example/demo/mapper/AuditMapper.java +++ b/src/main/java/com/example/demo/mapper/AuditMapper.java @@ -1,6 +1,14 @@ package com.example.demo.mapper; +import com.example.demo.domain.entity.User; +import com.example.demo.domain.entity.UserGoldRecord; +import com.example.demo.domain.vo.RechargeAudit; +import com.example.demo.domain.vo.RefundAudit; +import com.github.pagehelper.PageInfo; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; /** * @program: gold-java @@ -13,6 +21,21 @@ import org.apache.ibatis.annotations.Mapper; @Mapper public interface AuditMapper { - + //根据订单号查订单 + UserGoldRecord selectOrderByOrderCode(String orderCode); + //修改订单审核人与审核状态 + int updateOrder (UserGoldRecord userGoldRecord); + //修改用户余额 + int updateUserGold(User user); + //修改消费订单为以退款 + int updateOrderRefund(String orderCode); + //多条件查询充值审核订单 + List selectRechargeBy(@Param("pageNum") Integer pageNum, + @Param("pageSize") Integer pageSize, + @Param("rechargeAudit") RechargeAudit rechargeAudit); + //多条件查询消费审核订单 + List selectRefundBy(@Param("pageNum") Integer pageNum, + @Param("pageSize") Integer pageSize, + @Param("refundAudit") RefundAudit refundAudit); } diff --git a/src/main/java/com/example/demo/service/AuditService.java b/src/main/java/com/example/demo/service/AuditService.java index ca524e9..36107e2 100644 --- a/src/main/java/com/example/demo/service/AuditService.java +++ b/src/main/java/com/example/demo/service/AuditService.java @@ -1,5 +1,10 @@ package com.example.demo.service; +import com.example.demo.domain.vo.Gold; +import com.example.demo.domain.vo.RechargeAudit; +import com.example.demo.domain.vo.RefundAudit; +import com.github.pagehelper.PageInfo; + /** * @program: gold-java * @ClassName AuditService @@ -11,4 +16,12 @@ package com.example.demo.service; public interface AuditService { + //审核订单并修改用户余额等 + boolean auditOrder(String token, String orderCode, Integer auditId,Integer action,String rejectReason); + //多条件查询充值审核订单 + PageInfo selectRechargeBy(Integer pageNum, Integer pageSize, RechargeAudit rechargeAudit); + //多条件查询退款审核订单 + PageInfo selectRefundBy(Integer pageNum, Integer pageSize, RefundAudit refundAudit); + //金币合计数 + Gold sumRechargeGold(); } diff --git a/src/main/java/com/example/demo/service/WorkbenchService.java b/src/main/java/com/example/demo/service/WorkbenchService.java index 30fad16..c66e860 100644 --- a/src/main/java/com/example/demo/service/WorkbenchService.java +++ b/src/main/java/com/example/demo/service/WorkbenchService.java @@ -18,7 +18,7 @@ import java.util.List; public interface WorkbenchService { //获取不同地区的工作台统计卡片 - WorkbenchCard getCard(String token, List markets); + WorkbenchCard getCard(String token); //获取不同地区的工作台柱状图数据(根据类型,起止时间,地区查询) WorkbenchCard getGraph(String token, Date startDate, Date endDate, List markets); //根据类型获取年初至今的统计数据 diff --git a/src/main/java/com/example/demo/serviceImpl/AuditServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/AuditServiceImpl.java index 19b30c0..8019806 100644 --- a/src/main/java/com/example/demo/serviceImpl/AuditServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/AuditServiceImpl.java @@ -1,6 +1,18 @@ package com.example.demo.serviceImpl; +import com.example.demo.domain.entity.User; +import com.example.demo.domain.entity.UserGoldRecord; +import com.example.demo.domain.vo.Gold; +import com.example.demo.domain.vo.RechargeAudit; +import com.example.demo.domain.vo.RefundAudit; +import com.example.demo.mapper.AuditMapper; import com.example.demo.service.AuditService; +import com.github.pagehelper.PageHelper; +import com.github.pagehelper.PageInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; /** * @program: gold-java @@ -11,6 +23,96 @@ import com.example.demo.service.AuditService; * @Version 1.0 **/ - +@Service public class AuditServiceImpl implements AuditService { + @Autowired + private AuditMapper auditMapper; + /* + 审核订单并修改用户余额等 + */ + @Override + public boolean auditOrder(String token, String orderCode, Integer auditId, Integer action,String rejectReason) { + UserGoldRecord order=auditMapper.selectOrderByOrderCode(orderCode); + if (order == null || order.getAuditStatus() != 0) { + throw new IllegalArgumentException("订单不存在或已被审核"); + } + //更新订单的审核状态和审核人 + UserGoldRecord updateOrder = new UserGoldRecord(); + updateOrder.setOrderCode(orderCode); + updateOrder.setAuditId(auditId); + //判断是通过还是驳回 + if (action==2){ //驳回 + updateOrder.setAuditStatus(2); + updateOrder.setRejectReason(rejectReason); + auditMapper.updateOrder(updateOrder); + return true; + }else if (action==1) { //通过 + updateOrder.setAuditStatus(1); + } + // 执行审核更新 + auditMapper.updateOrder(updateOrder); + //判断是充值还是退款 + if (order.getType()==0){ //充值 + //更新用户余额 + User update = new User(); + update.setJwcode(order.getJwcode()); //精网号 + update.setSumPermanentGold(order.getPermanentGold()); //历史永久金币 + update.setSumFreeJune(order.getFreeJune()); //历史六月免费金币 + update.setSumFreeDecember(order.getFreeDecember()); //历史十二月免费金币 + update.setSumTaskGold(order.getTaskGold()); //历史任务金币 + update.setCurrentPermanentGold(order.getPermanentGold()); //当前永久金币 + update.setCurrentFreeJune(order.getFreeJune()); //当前六月免费金币 + update.setCurrentFreeDecember(order.getFreeDecember()); //当前十二月免费金币 + update.setCurrentTaskGold(order.getTaskGold()); //当前任务金币 + auditMapper.updateUserGold(update); + }else if (order.getType()==2) { //退款 + //1.更新用户余额,并标记对应的消费订单为已退款 + User update = new User(); + update.setJwcode(order.getJwcode()); + update.setCurrentPermanentGold(order.getPermanentGold()); //当前永久金币 + update.setCurrentFreeJune(order.getFreeJune()); //当前六月免费金币 + update.setCurrentFreeDecember(order.getFreeDecember()); //当前十二月免费金币 + update.setCurrentTaskGold(order.getTaskGold()); //当前任务金币 + auditMapper.updateUserGold(update); + //2.获取对应的消费订单(退款订单号去掉开头"TK"即为对应消费订单) + String consumeOrderCode = order.getOrderCode().replaceFirst("TK", ""); + //3.更新消费订单是否已退款状态为1 + UserGoldRecord consumeOrder = auditMapper.selectOrderByOrderCode(consumeOrderCode); + if (consumeOrderCode != null&&consumeOrder.getType()==1){ //确保是消费订单 + auditMapper.updateOrderRefund(consumeOrderCode); + }else { + throw new IllegalArgumentException("找不到对应的订单或不是有效订单"); + } + } + return true; + } + /* + * 多条件查询充值订单列表 + */ + @Override + public PageInfo selectRechargeBy(Integer pageNum, Integer pageSize, RechargeAudit rechargeAudit) { + PageHelper.startPage(pageNum, pageSize); + + List rechargeAudits = auditMapper.selectRechargeBy(pageNum, pageSize, rechargeAudit); + return new PageInfo<>(rechargeAudits); + } + + @Override + public PageInfo selectRefundBy(Integer pageNum, Integer pageSize, RefundAudit refundAudit) { + PageHelper.startPage(pageNum, pageSize); + + List refundAudits = auditMapper.selectRefundBy(pageNum, pageSize, refundAudit); + + return new PageInfo<>(refundAudits); + } + /* + 金币合计数 + */ + @Override + public Gold sumRechargeGold() { + Gold gold = new Gold(); + //获取充值审核订单列表 + List rechargeAudits = auditMapper.selectRechargeBy(1, 1000, null); + return null; + } } diff --git a/src/main/java/com/example/demo/serviceImpl/StatisticsServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/StatisticsServiceImpl.java index b311ed8..8e346db 100644 --- a/src/main/java/com/example/demo/serviceImpl/StatisticsServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/StatisticsServiceImpl.java @@ -68,7 +68,17 @@ public class StatisticsServiceImpl implements StatisticsService { Calendar cal = Calendar.getInstance(); cal.add(Calendar.DAY_OF_YEAR, -7); // 一周前 Date startDate = cal.getTime(); - Date endDate = generalService.getYesterday(); // 昨天 + Date yesterday = generalService.getYesterday(); // 昨天 + // 获取 Calendar 实例并设置为昨天的日期 + Calendar calendar = Calendar.getInstance(); + calendar.setTime(yesterday); + + // 设置时间为昨天的23:55 + calendar.set(Calendar.HOUR_OF_DAY, 23); + calendar.set(Calendar.MINUTE, 59); + calendar.set(Calendar.SECOND, 55); + //把yesterday的结束时间设为结束时间 + Date endDate= calendar.getTime(); //近一周的日期列表 List dateList =generalService.getAllDatesBetween(startDate, endDate); diff --git a/src/main/java/com/example/demo/serviceImpl/WorkbenchServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/WorkbenchServiceImpl.java index 669e4ee..9dad75b 100644 --- a/src/main/java/com/example/demo/serviceImpl/WorkbenchServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/WorkbenchServiceImpl.java @@ -39,7 +39,7 @@ public class WorkbenchServiceImpl implements WorkbenchService { @Autowired private StatisticsMapper statisticsMapper; @Override - public WorkbenchCard getCard(String token, List markets) { + public WorkbenchCard getCard(String token) { Date date=new Date(); // 获取开始时间和结束时间(当天) LocalDateTime startOfDay = date.toInstant() @@ -53,7 +53,7 @@ public class WorkbenchServiceImpl implements WorkbenchService { // 获取当前年份的第一天 LocalDate firstDayOfYear = today.withDayOfYear(1); Date yearlyStartDate=Date.from(firstDayOfYear.atStartOfDay(ZoneId.systemDefault()).toInstant()); - + List markets = generalService.getMarket(); List marketCards = new ArrayList<>(); // 遍历每个 marketCard 并填充数据 for (String market : markets) { @@ -95,7 +95,7 @@ public class WorkbenchServiceImpl implements WorkbenchService { int totalConsume = card.getConsumePermanent() + card.getConsumeFreeJune() + card.getConsumeFreeDecember() + card.getConsumeTask(); //当日总退款 int totalRefund = card.getRefundPermanent() + card.getRefundFreeJune() + card.getRefundFreeDecember() + card.getRefundTask(); - card.setDailyConsume(totalConsume - totalRefund);//当日总消耗 + card.setDailyReduce(totalConsume - totalRefund);//当日总消耗 card.setYearlyConsume(calculateSum(market, "consume", yearlyStartDate,date));//年累计消费 card.setYearlyRefund(calculateSum(market, "refund",yearlyStartDate ,date));//年累计退款 card.setYearlyReduce(card.getYearlyConsume() - card.getYearlyRefund());//年累计消耗 diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index cbbfb21..704b8fa 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -4,9 +4,9 @@ spring: fail-on-unknown-properties: false datasource: mysql1: - jdbc-url: jdbc:mysql://192.168.8.220:3306/hwgold?serverTimezone=Asia/Shanghai - username: hwgold - password: 123456 + jdbc-url: jdbc:mysql://18.143.76.3:3306/hwgoldc?serverTimezone=Asia/Shanghai + username: hwgoldc + password: zB48T55wCsHC8KPz driver-class-name: com.mysql.cj.jdbc.Driver hikari: pool-name: mysql1HikariCP diff --git a/src/main/resources/mapper/AuditMapper.xml b/src/main/resources/mapper/AuditMapper.xml index f6453a2..71dd88c 100644 --- a/src/main/resources/mapper/AuditMapper.xml +++ b/src/main/resources/mapper/AuditMapper.xml @@ -1,5 +1,108 @@ + + + update user_gold_record + set audit_id = #{auditId}, + audit_status = #{auditStatus}, + reject_reason = #{rejectReason} + where order_code = #{orderCode} + + + + update user + set sum_permanent_gold = sum_permanent_gold + COALESCE(#{sumPermanentGold},0), + sum_free_june = sum_free_june + COALESCE(#{sumFreeJune},0), + sum_free_december = sum_free_december + COALESCE(#{sumFreeDecember},0), + sum_task_gold = sum_task_gold + COALESCE(#{sumTaskGold},0), + current_permanent_gold = current_permanent_gold + COALESCE(#{currentPermanentGold},0), + current_free_june = current_free_june + COALESCE(#{currentFreeJune},0), + current_free_december = current_free_december + COALESCE(#{currentFreeDecember},0), + current_task_gold = current_task_gold + COALESCE(#{currentTaskGold},0) + where jwcode = #{jwcode} + + + + update user_gold_record + set is_refund = 1 + where order_code = #{orderCode} + + + + + + + diff --git a/src/main/resources/mapper/StatisticsMapper.xml b/src/main/resources/mapper/StatisticsMapper.xml index 76dda9d..700ed65 100644 --- a/src/main/resources/mapper/StatisticsMapper.xml +++ b/src/main/resources/mapper/StatisticsMapper.xml @@ -27,13 +27,13 @@ market, current_datetime, current_gold, daily_change, current_permanent, current_free_june, - current_free_december, current_task, + current_free_december, current_task ) VALUES ( #{market}, #{currentDatetime}, #{currentGold}, #{dailyChange}, #{currentPermanent}, #{currentFreeJune}, - #{currentFreeDecember}, #{currentTask}, + #{currentFreeDecember}, #{currentTask} ) From 8bc41b60d66b188d240bb54d0439f2dcfae062bd Mon Sep 17 00:00:00 2001 From: sunjiabei Date: Tue, 1 Jul 2025 15:54:34 +0800 Subject: [PATCH 11/16] =?UTF-8?q?=E6=A5=BC=E4=B8=8A=E6=8E=A5=E5=8F=A3+?= =?UTF-8?q?=E5=95=86=E5=93=81=E6=9F=A5=E8=AF=A2=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 10 ++++++++++ .../java/com/example/demo/controller/ConsumeController.java | 1 + src/main/java/com/example/demo/domain/vo/ConsumeUser.java | 1 + src/main/resources/mapper/RechargeMapper.xml | 1 + 4 files changed, 13 insertions(+) diff --git a/pom.xml b/pom.xml index 216c74b..cf6eee2 100644 --- a/pom.xml +++ b/pom.xml @@ -89,6 +89,16 @@ pagehelper-spring-boot-starter 1.4.6 + + jakarta.validation + jakarta.validation-api + 3.0.2 + + + org.hibernate.validator + hibernate-validator + 8.0.0.Final + diff --git a/src/main/java/com/example/demo/controller/ConsumeController.java b/src/main/java/com/example/demo/controller/ConsumeController.java index 51c2411..9ddf11b 100644 --- a/src/main/java/com/example/demo/controller/ConsumeController.java +++ b/src/main/java/com/example/demo/controller/ConsumeController.java @@ -6,6 +6,7 @@ import com.example.demo.domain.vo.Gold; import com.example.demo.domain.vo.Page; import com.example.demo.domain.vo.Result; import com.example.demo.service.ConsumeService; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; diff --git a/src/main/java/com/example/demo/domain/vo/ConsumeUser.java b/src/main/java/com/example/demo/domain/vo/ConsumeUser.java index 40768ea..d2370ce 100644 --- a/src/main/java/com/example/demo/domain/vo/ConsumeUser.java +++ b/src/main/java/com/example/demo/domain/vo/ConsumeUser.java @@ -1,6 +1,7 @@ package com.example.demo.domain.vo; import com.fasterxml.jackson.annotation.JsonFormat; +import jakarta.validation.constraints.PositiveOrZero; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; diff --git a/src/main/resources/mapper/RechargeMapper.xml b/src/main/resources/mapper/RechargeMapper.xml index 99d86ad..e8405f8 100644 --- a/src/main/resources/mapper/RechargeMapper.xml +++ b/src/main/resources/mapper/RechargeMapper.xml @@ -108,6 +108,7 @@ ugr.permanent_gold + ugr.money (COALESCE(ugr.free_june, 0) + COALESCE(ugr.free_december, 0)) ugr.pay_time From ba196355204f71205ca1740f8c68fe0635f0cd35 Mon Sep 17 00:00:00 2001 From: sunjiabei Date: Tue, 1 Jul 2025 17:21:45 +0800 Subject: [PATCH 12/16] =?UTF-8?q?=E9=80=80=E6=AC=BE=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/example/demo/mapper/ConsumeMapper.java | 2 ++ .../java/com/example/demo/serviceImpl/RefundServiceImpl.java | 6 ++++-- src/main/resources/mapper/ConsumeMapper.xml | 11 +++++++++++ src/main/resources/mapper/RefundMapper.xml | 1 + 4 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/demo/mapper/ConsumeMapper.java b/src/main/java/com/example/demo/mapper/ConsumeMapper.java index 489028a..fd6bf53 100644 --- a/src/main/java/com/example/demo/mapper/ConsumeMapper.java +++ b/src/main/java/com/example/demo/mapper/ConsumeMapper.java @@ -23,4 +23,6 @@ public interface ConsumeMapper { List selectBy(ConsumeUser consumeUser); void add(UserGoldRecord userGoldRecord); + + void updateIsRefund(String orderCode); } diff --git a/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java index 680cf05..2269d4a 100644 --- a/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/RefundServiceImpl.java @@ -38,7 +38,7 @@ public class RefundServiceImpl implements RefundService { private RefundMapper refundMapper; @Autowired - private UserMapper userMapper; + private ConsumeMapper consumeMapper; @Override public PageInfo selectAll(Integer pageNum, Integer pageSize, RefundUser refundUser) { @@ -92,12 +92,13 @@ public class RefundServiceImpl implements RefundService { public Result add(RefundUser refundUser) { UserGoldRecord userGoldRecord = new UserGoldRecord(); String goodsNameWithOrder = refundUser.getGoodsName(); + String orderCode = ""; //订单号生成 if (goodsNameWithOrder != null && goodsNameWithOrder.contains("_")) { String[] parts = goodsNameWithOrder.split("_", 2); if (parts.length >= 2) { // 提取订单号(保留原始前缀) - String orderCode = parts[0]; // XF202506281545524400006580 + orderCode = parts[0]; // XF202506281545524400006580 // 提取商品名(处理可能包含下划线的情况) String goodsName = parts[1]; // 商品A @@ -132,6 +133,7 @@ public class RefundServiceImpl implements RefundService { userGoldRecord.setAuditStatus(0); userGoldRecord.setCreateTime(new Date()); refundMapper.add(userGoldRecord); + consumeMapper.updateIsRefund(orderCode); return Result.success(); } diff --git a/src/main/resources/mapper/ConsumeMapper.xml b/src/main/resources/mapper/ConsumeMapper.xml index 0098af5..c0d4592 100644 --- a/src/main/resources/mapper/ConsumeMapper.xml +++ b/src/main/resources/mapper/ConsumeMapper.xml @@ -171,4 +171,15 @@ #{payTime} + + + UPDATE user_gold_record + SET is_refund = 1 + + order_code = #{orderCode} + + AND is_refund != 0 + + + \ No newline at end of file diff --git a/src/main/resources/mapper/RefundMapper.xml b/src/main/resources/mapper/RefundMapper.xml index c80dac0..faa99a7 100644 --- a/src/main/resources/mapper/RefundMapper.xml +++ b/src/main/resources/mapper/RefundMapper.xml @@ -191,6 +191,7 @@ FROM user_gold_record ugr ugr.type = 1 + AND ugr.is_refund = 0 AND ugr.jwcode = #{jwcode} From dc95d625e60c1583536c1f9cb4a80aed507d79df Mon Sep 17 00:00:00 2001 From: huangqizhen <15552608129@163.com> Date: Tue, 1 Jul 2025 17:29:25 +0800 Subject: [PATCH 13/16] =?UTF-8?q?=E5=8F=AF=E8=B7=91=EF=BC=88=E4=B8=8D?= =?UTF-8?q?=E5=90=88=E5=B9=B6=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/example/demo/Export/ExportService.java | 25 + .../com/example/demo/Export/ExportServiceImpl.java | 177 +++++ .../example/demo/controller/AdminController.java | 43 + .../example/demo/controller/ExportController.java | 75 +- .../demo/controller/GoldDetailController.java | 19 + .../com/example/demo/domain/DTO/ConsumeDTO.java | 42 + .../com/example/demo/domain/DTO/GoldDetailDTO.java | 6 +- .../com/example/demo/domain/DTO/GoldUserDTO.java | 42 + .../com/example/demo/domain/DTO/RechargeDTO.java | 43 + .../com/example/demo/domain/DTO/RefundDTO.java | 42 + .../java/com/example/demo/domain/entity/Admin.java | 66 +- .../java/com/example/demo/mapper/ExportMapper.java | 6 +- .../com/example/demo/mapper/GoldDetailMapper.java | 2 +- .../com/example/demo/security/TokenFilter.java | 268 +------ .../com/example/demo/security/UploadFilter.java | 43 - .../com/example/demo/service/AdminService.java | 15 + .../com/example/demo/service/AiEmotionService.java | 2 +- .../example/demo/service/ExportExcelService.java | 10 +- .../example/demo/service/GoldDetailService.java | 6 +- .../service/listen/AiEmotionExportListener.java | 4 +- .../demo/service/listen/ConsumeListener.java | 81 ++ .../example/demo/service/listen/GoldListener.java | 82 ++ .../demo/service/listen/RechargeListener.java | 81 ++ .../demo/service/listen/RefundListener.java | 81 ++ .../example/demo/serviceImpl/AdminServiceImpl.java | 64 ++ .../demo/serviceImpl/AiEmotionServiceImpl.java | 2 +- .../demo/serviceImpl/ExportExcelServiceImpl.java | 877 ++++++++++++++++++++- .../demo/serviceImpl/GoldDetailServiceImpl.java | 52 +- src/main/resources/mapper/AiEmotionMapper.xml | 4 +- src/main/resources/mapper/ExportMapper.xml | 10 + src/main/resources/mapper/GoldDetailMapper.xml | 4 +- src/main/resources/mapper/PermissionMapper.xml | 6 +- 32 files changed, 1942 insertions(+), 338 deletions(-) create mode 100644 src/main/java/com/example/demo/Export/ExportService.java create mode 100644 src/main/java/com/example/demo/Export/ExportServiceImpl.java create mode 100644 src/main/java/com/example/demo/controller/AdminController.java create mode 100644 src/main/java/com/example/demo/domain/DTO/ConsumeDTO.java create mode 100644 src/main/java/com/example/demo/domain/DTO/GoldUserDTO.java create mode 100644 src/main/java/com/example/demo/domain/DTO/RechargeDTO.java create mode 100644 src/main/java/com/example/demo/domain/DTO/RefundDTO.java delete mode 100644 src/main/java/com/example/demo/security/UploadFilter.java create mode 100644 src/main/java/com/example/demo/service/AdminService.java create mode 100644 src/main/java/com/example/demo/service/listen/ConsumeListener.java create mode 100644 src/main/java/com/example/demo/service/listen/GoldListener.java create mode 100644 src/main/java/com/example/demo/service/listen/RechargeListener.java create mode 100644 src/main/java/com/example/demo/service/listen/RefundListener.java create mode 100644 src/main/java/com/example/demo/serviceImpl/AdminServiceImpl.java diff --git a/src/main/java/com/example/demo/Export/ExportService.java b/src/main/java/com/example/demo/Export/ExportService.java new file mode 100644 index 0000000..f8a35ad --- /dev/null +++ b/src/main/java/com/example/demo/Export/ExportService.java @@ -0,0 +1,25 @@ +package com.example.demo.Export; + +import com.example.demo.domain.DTO.ConsumeDTO; +import com.example.demo.domain.DTO.GoldDetailDTO; +import com.example.demo.domain.DTO.RechargeDTO; +import com.example.demo.domain.DTO.RefundDTO; +import com.example.demo.domain.vo.Result; + +/** + * @program: GOLD + * @ClassName ExportService + * @description: + * @author: huangqizhen + * @create: 2025−07-01 16:06 + * @Version 1.0 + **/ +public interface ExportService { + //充值导出 + Result addExportRecharge(RechargeDTO dto); + //退款导出 + Result addExportRefund(RefundDTO dto); + //消费导出 + Result addExportConsume(ConsumeDTO dto); + +} diff --git a/src/main/java/com/example/demo/Export/ExportServiceImpl.java b/src/main/java/com/example/demo/Export/ExportServiceImpl.java new file mode 100644 index 0000000..2c52080 --- /dev/null +++ b/src/main/java/com/example/demo/Export/ExportServiceImpl.java @@ -0,0 +1,177 @@ +package com.example.demo.Export; + +import com.example.demo.domain.DTO.ConsumeDTO; +import com.example.demo.domain.DTO.RechargeDTO; +import com.example.demo.domain.DTO.RefundDTO; +import com.example.demo.domain.vo.Result; +import com.example.demo.exception.SystemException; +import com.example.demo.mapper.GoldDetailMapper; +import com.example.demo.Util.RedisUtil; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.HashMap; +import java.util.Map; + +/** + * @program: GOLD + * @ClassName ExportServiceImpl + * @description: + * @author: huangqizhen + * @create: 2025−07-01 16:11 + * @Version 1.0 + **/ +@Service +public class ExportServiceImpl implements ExportService{ + @Autowired + private GoldDetailMapper goldDetailMapper; + @Autowired + private RedisUtil redisUtil; + + @Override + public Result addExportRecharge(RechargeDTO dto) { + // 生成文件名 + String fileName = String.format("%s_%s_%s.xlsx", + "充值明细", + "操作人", + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); + System.out.println(fileName); + dto.setAccount(123456); + dto.setUrl(""); + dto.setFileName(fileName); + dto.setDataNum(0); + try{ + // 调用方式 + GoldDetailMapper.ExportRecordIdHolder idHolder = new GoldDetailMapper.ExportRecordIdHolder(); + goldDetailMapper.insertExportRecord( + idHolder, // 用于接收主键 + dto.getAccount(), + dto.getType(), + dto.getState(), + dto.getUrl(), + dto.getFileName(), + dto.getDataNum() + ); + // 获取主键 + Long recordId = idHolder.getId(); + // 2. 构造完整的 JSON 数据(包含所有请求参数) + Map exportData = new HashMap<>(); + exportData.put("recordId", recordId); + + // 手动构造请求数据(避免 toString() 只返回部分字段) + Map requestData = new HashMap<>(); + requestData.put("text", dto.getText()); + requestData.put("sort", dto.getSort()); + requestData.put("field", dto.getField()); + requestData.put("deptId", dto.getDeptid()); + exportData.put("requestData", requestData); + + // 3. 发送到 Redis 消息队列 + String jsonData = new ObjectMapper().writeValueAsString(exportData); + redisUtil.sendMessage("recharge:queue:export_queue", jsonData); + }catch (Exception e){ + e.printStackTrace(); + throw new SystemException("导出数据异常,请稍后重试", e); + } + return Result.success(); + } + + @Override + public Result addExportRefund(RefundDTO dto) { + // 生成文件名 + String fileName = String.format("%s_%s_%s.xlsx", + "退款明细", + "操作人", + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); + System.out.println(fileName); + dto.setAccount(123456); + dto.setUrl(""); + dto.setFileName(fileName); + dto.setDataNum(0); + try{ + // 调用方式 + GoldDetailMapper.ExportRecordIdHolder idHolder = new GoldDetailMapper.ExportRecordIdHolder(); + goldDetailMapper.insertExportRecord( + idHolder, // 用于接收主键 + dto.getAccount(), + dto.getType(), + dto.getState(), + dto.getUrl(), + dto.getFileName(), + dto.getDataNum() + ); + // 获取主键 + Long recordId = idHolder.getId(); + // 2. 构造完整的 JSON 数据(包含所有请求参数) + Map exportData = new HashMap<>(); + exportData.put("recordId", recordId); + + // 手动构造请求数据(避免 toString() 只返回部分字段) + Map requestData = new HashMap<>(); + requestData.put("text", dto.getText()); + requestData.put("sort", dto.getSort()); + requestData.put("field", dto.getField()); + requestData.put("deptId", dto.getDeptid()); + exportData.put("requestData", requestData); + + // 3. 发送到 Redis 消息队列 + String jsonData = new ObjectMapper().writeValueAsString(exportData); + redisUtil.sendMessage("refund:queue:export_queue", jsonData); + }catch (Exception e){ + e.printStackTrace(); + throw new SystemException("导出数据异常,请稍后重试", e); + } + return Result.success(); + } + + @Override + public Result addExportConsume(ConsumeDTO dto) { + // 生成文件名 + String fileName = String.format("%s_%s_%s.xlsx", + "消费明细", + "操作人", + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); + System.out.println(fileName); + dto.setAccount(123456); + dto.setUrl(""); + dto.setFileName(fileName); + dto.setDataNum(0); + try{ + // 调用方式 + GoldDetailMapper.ExportRecordIdHolder idHolder = new GoldDetailMapper.ExportRecordIdHolder(); + goldDetailMapper.insertExportRecord( + idHolder, // 用于接收主键 + dto.getAccount(), + dto.getType(), + dto.getState(), + dto.getUrl(), + dto.getFileName(), + dto.getDataNum() + ); + // 获取主键 + Long recordId = idHolder.getId(); + // 2. 构造完整的 JSON 数据(包含所有请求参数) + Map exportData = new HashMap<>(); + exportData.put("recordId", recordId); + + // 手动构造请求数据(避免 toString() 只返回部分字段) + Map requestData = new HashMap<>(); + requestData.put("text", dto.getText()); + requestData.put("sort", dto.getSort()); + requestData.put("field", dto.getField()); + requestData.put("deptId", dto.getDeptid()); + exportData.put("requestData", requestData); + + // 3. 发送到 Redis 消息队列 + String jsonData = new ObjectMapper().writeValueAsString(exportData); + redisUtil.sendMessage("refund:queue:export_queue", jsonData); + }catch (Exception e){ + e.printStackTrace(); + throw new SystemException("导出数据异常,请稍后重试", e); + } + return Result.success(); + } +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/controller/AdminController.java b/src/main/java/com/example/demo/controller/AdminController.java new file mode 100644 index 0000000..c117b3e --- /dev/null +++ b/src/main/java/com/example/demo/controller/AdminController.java @@ -0,0 +1,43 @@ +package com.example.demo.controller; + +import com.example.demo.Util.JWTUtil; +import com.example.demo.domain.entity.Admin; +import com.example.demo.domain.vo.Result; +import com.example.demo.service.AdminService; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +/** + * @program: GOLD + * @ClassName AdminController + * @description: + * @author: huangqizhen + * @create: 2025−07-01 10:39 + * @Version 1.0 + **/ +@RestController +@RequestMapping("/admin") +@RequiredArgsConstructor +@Slf4j +@CrossOrigin +public class AdminController { + @Autowired + private AdminService adminService; + @PostMapping("/login") + public Result login(@RequestBody Admin admin){ + + try { + admin = adminService.login(admin); + admin.setPassword(null); + System.out.println("达瓦达瓦达瓦达瓦达瓦达瓦达瓦达瓦达瓦达瓦达瓦达瓦达瓦达瓦达瓦达瓦达瓦达瓦达瓦达瓦达"); + return Result.success(admin); + } catch (Exception e) { + e.printStackTrace(); + log.error(e.getMessage()); + return Result.error(e.getMessage()); + } + + } +} diff --git a/src/main/java/com/example/demo/controller/ExportController.java b/src/main/java/com/example/demo/controller/ExportController.java index 4302859..2269657 100644 --- a/src/main/java/com/example/demo/controller/ExportController.java +++ b/src/main/java/com/example/demo/controller/ExportController.java @@ -1,12 +1,24 @@ package com.example.demo.controller; +import com.example.demo.Util.BusinessException; +import com.example.demo.Util.RedisLockUtil; +import com.example.demo.domain.DTO.ConsumeDTO; +import com.example.demo.domain.DTO.RechargeDTO; +import com.example.demo.domain.DTO.RefundDTO; import com.example.demo.domain.entity.Export; import com.example.demo.domain.vo.Result; +import com.example.demo.service.ExportExcelService; +import com.example.demo.service.GoldDetailService; +import com.example.demo.Export.ExportService; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import java.util.List; +import java.util.UUID; + /** * @program: GOLD * @ClassName ExportController @@ -21,8 +33,67 @@ import org.springframework.web.bind.annotation.*; @Slf4j @CrossOrigin public class ExportController { + @Autowired + private ExportExcelService exportExcelService; + @Autowired + private RedisLockUtil redisLockUtil; + @Autowired + private GoldDetailService goldDetailService; + @Autowired + private ExportService exportService; @PostMapping("/export") - public Result export(@RequestBody Export export){ - return null; + public Result export(@RequestBody Export Export){ + return Result.success(exportExcelService.getExcel(Export)); + } + @PostMapping("/exportRecharge") + public Result export(@Valid @RequestBody RechargeDTO dto) { + String lockKey = "export:lock:" + dto.getToken(); // 锁的 Key(可按用户/业务区分) + String requestId = UUID.randomUUID().toString(); // 请求 ID(防止误删锁) + long expireTime = 5000; // 锁过期时间(5秒)s + try { + // 尝试获取锁 + if (!redisLockUtil.tryLock(lockKey, requestId, expireTime)) { + throw new BusinessException("操作太频繁,请稍后重试"); + } + // 执行业务逻辑 + return exportService.addExportRecharge(dto); + } finally { + // 释放锁 + redisLockUtil.unlock(lockKey, requestId); + } + } + @PostMapping("/exportRefund") + public Result export(@Valid @RequestBody RefundDTO dto) { + String lockKey = "export:lock:" + dto.getToken(); // 锁的 Key(可按用户/业务区分) + String requestId = UUID.randomUUID().toString(); // 请求 ID(防止误删锁) + long expireTime = 5000; // 锁过期时间(5秒)s + try { + // 尝试获取锁 + if (!redisLockUtil.tryLock(lockKey, requestId, expireTime)) { + throw new BusinessException("操作太频繁,请稍后重试"); + } + // 执行业务逻辑 + return exportService.addExportRefund(dto); + } finally { + // 释放锁 + redisLockUtil.unlock(lockKey, requestId); + } + } + @PostMapping("/exportConsume") + public Result export(@Valid @RequestBody ConsumeDTO dto) { + String lockKey = "export:lock:" + dto.getToken(); // 锁的 Key(可按用户/业务区分) + String requestId = UUID.randomUUID().toString(); // 请求 ID(防止误删锁) + long expireTime = 5000; // 锁过期时间(5秒)s + try { + // 尝试获取锁 + if (!redisLockUtil.tryLock(lockKey, requestId, expireTime)) { + throw new BusinessException("操作太频繁,请稍后重试"); + } + // 执行业务逻辑 + return exportService.addExportConsume(dto); + } finally { + // 释放锁 + redisLockUtil.unlock(lockKey, requestId); + } } } diff --git a/src/main/java/com/example/demo/controller/GoldDetailController.java b/src/main/java/com/example/demo/controller/GoldDetailController.java index e188e13..dde8d2d 100644 --- a/src/main/java/com/example/demo/controller/GoldDetailController.java +++ b/src/main/java/com/example/demo/controller/GoldDetailController.java @@ -3,6 +3,7 @@ package com.example.demo.controller; import com.example.demo.Util.BusinessException; import com.example.demo.Util.RedisLockUtil; import com.example.demo.domain.DTO.GoldDetailDTO; +import com.example.demo.domain.DTO.GoldUserDTO; import com.example.demo.domain.entity.User; import com.example.demo.domain.vo.GoldDetail; import com.example.demo.domain.vo.Page; @@ -89,4 +90,22 @@ public class GoldDetailController { redisLockUtil.unlock(lockKey, requestId); } } + @PostMapping("/exportGold") + public Result export(@Valid @RequestBody GoldUserDTO dto) { + String lockKey = "export:lock:" + dto.getToken(); // 锁的 Key(可按用户/业务区分) + String requestId = UUID.randomUUID().toString(); // 请求 ID(防止误删锁) + long expireTime = 5000; // 锁过期时间(5秒)s + try { + // 尝试获取锁 + if (!redisLockUtil.tryLock(lockKey, requestId, expireTime)) { + throw new BusinessException("操作太频繁,请稍后重试"); + } + // 执行业务逻辑 + return goldDetailService.addExportRecordGold(dto); + } finally { + // 释放锁 + redisLockUtil.unlock(lockKey, requestId); + } + } + } diff --git a/src/main/java/com/example/demo/domain/DTO/ConsumeDTO.java b/src/main/java/com/example/demo/domain/DTO/ConsumeDTO.java new file mode 100644 index 0000000..d8a7b01 --- /dev/null +++ b/src/main/java/com/example/demo/domain/DTO/ConsumeDTO.java @@ -0,0 +1,42 @@ +package com.example.demo.domain.DTO; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @program: GOLD + * @ClassName ConsumeDTO + * @description: + * @author: huangqizhen + * @create: 2025−07-01 16:17 + * @Version 1.0 + **/ +@Data +@NoArgsConstructor +public class ConsumeDTO { + private String token; + private String url = ""; + private String fileName = ""; + private Integer sort = 0; + private String field = ""; + private Integer account; + private Integer type = 4; //类型 + private Integer state = 0; //状态 + private String text = ""; //关键词搜索 + private Integer dataNum = 0; + private String deptid = ""; + + @NotNull(message = "page不能为空") + private Integer page = 1; + @NotNull(message = "pageSize不能为空") + private Integer pageSize = 20; + + @Override + public String toString() { + return String.format( + "AiEmotionExport(account=%d, type=%d, state=%d, dataNum=%d)", + account, type, state, dataNum + ); + } +} diff --git a/src/main/java/com/example/demo/domain/DTO/GoldDetailDTO.java b/src/main/java/com/example/demo/domain/DTO/GoldDetailDTO.java index 9aa1dd0..b03acca 100644 --- a/src/main/java/com/example/demo/domain/DTO/GoldDetailDTO.java +++ b/src/main/java/com/example/demo/domain/DTO/GoldDetailDTO.java @@ -22,7 +22,7 @@ public class GoldDetailDTO { private String fileName = ""; private Integer sort = 0; private String field = ""; - private Integer jwcode; + private Integer account; private Integer type = 0; //类型 private Integer state = 0; //状态 private String text = ""; //关键词搜索 @@ -37,8 +37,8 @@ public class GoldDetailDTO { @Override public String toString() { return String.format( - "AiEmotionExport(jwcode=%d, type=%d, state=%d, dataNum=%d)", - jwcode, type, state, dataNum + "AiEmotionExport(account=%d, type=%d, state=%d, dataNum=%d)", + account, type, state, dataNum ); } } diff --git a/src/main/java/com/example/demo/domain/DTO/GoldUserDTO.java b/src/main/java/com/example/demo/domain/DTO/GoldUserDTO.java new file mode 100644 index 0000000..0087f6f --- /dev/null +++ b/src/main/java/com/example/demo/domain/DTO/GoldUserDTO.java @@ -0,0 +1,42 @@ +package com.example.demo.domain.DTO; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @program: GOLD + * @ClassName GoldDTO + * @description: + * @author: huangqizhen + * @create: 2025−06-30 23:40 + * @Version 1.0 + **/ +@Data +@NoArgsConstructor +public class GoldUserDTO { + private String token; + private String url = ""; + private String fileName = ""; + private Integer sort = 0; + private String field = ""; + private Integer account; + private Integer type = 1; //类型 + private Integer state = 0; //状态 + private String text = ""; //关键词搜索 + private Integer dataNum = 0; + private String deptid = ""; + + @NotNull(message = "page不能为空") + private Integer page = 1; + @NotNull(message = "pageSize不能为空") + private Integer pageSize = 20; + + @Override + public String toString() { + return String.format( + "AiEmotionExport(account=%d, type=%d, state=%d, dataNum=%d)", + account, type, state, dataNum + ); + } +} diff --git a/src/main/java/com/example/demo/domain/DTO/RechargeDTO.java b/src/main/java/com/example/demo/domain/DTO/RechargeDTO.java new file mode 100644 index 0000000..d9608c4 --- /dev/null +++ b/src/main/java/com/example/demo/domain/DTO/RechargeDTO.java @@ -0,0 +1,43 @@ +package com.example.demo.domain.DTO; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @program: GOLD + * @ClassName RechargeDTO + * @description: + * @author: huangqizhen + * @create: 2025−07-01 16:15 + * @Version 1.0 + **/ + +@Data +@NoArgsConstructor +public class RechargeDTO { + private String token; + private String url = ""; + private String fileName = ""; + private Integer sort = 0; + private String field = ""; + private Integer account; + private Integer type = 2; //类型 + private Integer state = 0; //状态 + private String text = ""; //关键词搜索 + private Integer dataNum = 0; + private String deptid = ""; + + @NotNull(message = "page不能为空") + private Integer page = 1; + @NotNull(message = "pageSize不能为空") + private Integer pageSize = 20; + + @Override + public String toString() { + return String.format( + "AiEmotionExport(account=%d, type=%d, state=%d, dataNum=%d)", + account, type, state, dataNum + ); + } +} diff --git a/src/main/java/com/example/demo/domain/DTO/RefundDTO.java b/src/main/java/com/example/demo/domain/DTO/RefundDTO.java new file mode 100644 index 0000000..dcd232d --- /dev/null +++ b/src/main/java/com/example/demo/domain/DTO/RefundDTO.java @@ -0,0 +1,42 @@ +package com.example.demo.domain.DTO; + +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.NoArgsConstructor; + +/** + * @program: GOLD + * @ClassName RefundDTO + * @description: + * @author: huangqizhen + * @create: 2025−07-01 16:16 + * @Version 1.0 + **/ +@Data +@NoArgsConstructor +public class RefundDTO { + private String token; + private String url = ""; + private String fileName = ""; + private Integer sort = 0; + private String field = ""; + private Integer account; + private Integer type = 3; //类型 + private Integer state = 0; //状态 + private String text = ""; //关键词搜索 + private Integer dataNum = 0; + private String deptid = ""; + + @NotNull(message = "page不能为空") + private Integer page = 1; + @NotNull(message = "pageSize不能为空") + private Integer pageSize = 20; + + @Override + public String toString() { + return String.format( + "AiEmotionExport(account=%d, type=%d, state=%d, dataNum=%d)", + account, type, state, dataNum + ); + } +} diff --git a/src/main/java/com/example/demo/domain/entity/Admin.java b/src/main/java/com/example/demo/domain/entity/Admin.java index 666c30a..86dbb80 100644 --- a/src/main/java/com/example/demo/domain/entity/Admin.java +++ b/src/main/java/com/example/demo/domain/entity/Admin.java @@ -1,17 +1,19 @@ package com.example.demo.domain.entity; import com.fasterxml.jackson.annotation.JsonFormat; -import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonIgnore; import lombok.Data; import lombok.NoArgsConstructor; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.userdetails.UserDetails; import java.io.Serializable; -import java.util.Date; +import java.util.*; @Data @NoArgsConstructor -@JsonIgnoreProperties(ignoreUnknown = true) -public class Admin implements Serializable { +public class Admin implements UserDetails, Serializable { private static final long serialVersionUID = 1L; private Integer id; // 主键ID @@ -30,4 +32,60 @@ public class Admin implements Serializable { @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "Asia/Shanghai") private Date updateTime; // 更新时间 private Integer roleId; + + + @Override + public Collection getAuthorities() { + Set authorities = new HashSet<>(); + Optional.ofNullable(postiton) + .map(Integer::valueOf) + .ifPresent(permValue -> { + switch (permValue) { + case 1: + authorities.add(new SimpleGrantedAuthority("ROLE_SUPER_ADMIN")); + break; + case 2: + authorities.add(new SimpleGrantedAuthority("ROLE_ADMIN")); + break; + case 3: + authorities.add(new SimpleGrantedAuthority("ROLE_AUDITORS")); + break; + case 5: + authorities.add(new SimpleGrantedAuthority("Branch_Manager")); + break; + default: + // 可以添加默认角色或处理未知权限 + break; + } + }); + return authorities; + } + @Override + public String getUsername() { + return account; + } + + @Override + @JsonIgnore + public boolean isAccountNonExpired() { + return true; // 默认账户未过期 + } + + @Override + @JsonIgnore + public boolean isAccountNonLocked() { + return true; // 默认账户未锁定 + } + + @Override + @JsonIgnore + public boolean isCredentialsNonExpired() { + return true; // 默认凭证未过期 + } + + @Override + @JsonIgnore + public boolean isEnabled() { + return adminStatus != null && adminStatus == 1; + } } \ No newline at end of file diff --git a/src/main/java/com/example/demo/mapper/ExportMapper.java b/src/main/java/com/example/demo/mapper/ExportMapper.java index 3d95954..4bb7cd6 100644 --- a/src/main/java/com/example/demo/mapper/ExportMapper.java +++ b/src/main/java/com/example/demo/mapper/ExportMapper.java @@ -1,8 +1,11 @@ package com.example.demo.mapper; +import com.example.demo.domain.entity.Export; import com.example.demo.domain.vo.ExportVo; import org.apache.ibatis.annotations.Mapper; +import java.util.List; + /** * @program: GOLD * @ClassName ExportMapper @@ -14,6 +17,7 @@ import org.apache.ibatis.annotations.Mapper; @Mapper public interface ExportMapper { ExportVo getExportData(Integer id); - ExportVo updateExportData(Long recordId, Integer state, String url, String reason, Integer dataNum); + int updateExportData(Long recordId, Integer state, String url, String reason, Integer dataNum); + List getExportRecord(Integer account); } diff --git a/src/main/java/com/example/demo/mapper/GoldDetailMapper.java b/src/main/java/com/example/demo/mapper/GoldDetailMapper.java index 0bbaf61..7494332 100644 --- a/src/main/java/com/example/demo/mapper/GoldDetailMapper.java +++ b/src/main/java/com/example/demo/mapper/GoldDetailMapper.java @@ -29,7 +29,7 @@ public interface GoldDetailMapper { } void insertExportRecord( @Param("recordId") ExportRecordIdHolder recordId, // 用于接收主键 - @Param("jwcode") Integer jwcode, + @Param("account") Integer account, @Param("type") Integer type, @Param("state") Integer state, @Param("url") String url, diff --git a/src/main/java/com/example/demo/security/TokenFilter.java b/src/main/java/com/example/demo/security/TokenFilter.java index 7652567..00db23e 100644 --- a/src/main/java/com/example/demo/security/TokenFilter.java +++ b/src/main/java/com/example/demo/security/TokenFilter.java @@ -1,209 +1,14 @@ -//package com.example.demo.security; -// -// -//import com.example.demo.Util.JWTUtil; -//import com.example.demo.Util.RequestWrapper; -//import com.example.demo.domain.entity.Admin; -//import jakarta.servlet.FilterChain; -//import jakarta.servlet.ServletException; -//import jakarta.servlet.http.HttpServletRequest; -//import jakarta.servlet.http.HttpServletResponse; -//import org.springframework.core.annotation.Order; -//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -//import org.springframework.security.core.context.SecurityContextHolder; -//import org.springframework.security.core.userdetails.UserDetails; -//import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; -//import org.springframework.stereotype.Component; -//import org.springframework.util.ObjectUtils; -//import org.springframework.util.StringUtils; -//import org.springframework.web.filter.OncePerRequestFilter; -//import java.io.IOException; -// -// -//@Component -//public class TokenFilter extends OncePerRequestFilter { -// @Override -// protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { -// // 取Token 生成登录信息 -// String token = request.getHeader("token"); -// -// -// System.out.println(token+"123132132"); -// -// // token不为空 -// if (StringUtils.hasText(token)){ -// try { -// UserDetails userDetails = JWTUtil.getUserDetailsList(token, Admin.class); -// if ( ! ObjectUtils.isEmpty(userDetails)) { -// // 将这个用户注册到Security中 -// UsernamePasswordAuthenticationToken authenticationToken -// = new UsernamePasswordAuthenticationToken( -// userDetails, null, -// userDetails.getAuthorities()); -// authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); -// SecurityContextHolder.getContext().setAuthentication(authenticationToken); -// } -// } catch (Exception e) { -// e.printStackTrace(); -// // Token无效, -// } -// } -// // 过滤器放行 -// filterChain.doFilter(request, response); -// } -//} -//package com.example.demo.security; -// -//import com.example.demo.Util.JWTUtil; -//import com.example.demo.Util.RequestWrapper; -//import com.example.demo.Util.TokenPayload; -//import com.example.demo.domain.entity.Admin; -//import com.fasterxml.jackson.databind.ObjectMapper; -//import jakarta.servlet.FilterChain; -//import jakarta.servlet.ServletException; -//import jakarta.servlet.http.HttpServletRequest; -//import jakarta.servlet.http.HttpServletResponse; -//import org.springframework.core.annotation.Order; -//import org.springframework.security.access.prepost.PreFilter; -//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -//import org.springframework.security.core.context.SecurityContextHolder; -//import org.springframework.security.core.userdetails.UserDetails; -//import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; -//import org.springframework.stereotype.Component; -//import org.springframework.util.ObjectUtils; -//import org.springframework.util.StringUtils; -//import org.springframework.web.filter.OncePerRequestFilter; -//import java.io.IOException; -//import java.io.InputStream; -// -// -//@Component -//public class TokenFilter extends OncePerRequestFilter { -// -// @Override -// protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) -// throws ServletException, IOException { -// // 使用RequestWrapper包装原始的HttpServletRequest,使其输入流可以被重复读取 -// RequestWrapper requestWrapper = new RequestWrapper(request); -// // 确保请求体只被读取一次 -// boolean hasRequestBody = "POST".equals(requestWrapper.getMethod()); -// System.out.println("/*-/*-/*"+requestWrapper.getBodyString()); -// if (hasRequestBody) { -// // 获取输入流 -// InputStream inputStream = requestWrapper.getInputStream(); -// // 使用Jackson ObjectMapper解析JSON -// ObjectMapper objectMapper = new ObjectMapper(); -// TokenPayload tokenPayload = objectMapper.readValue(inputStream, TokenPayload.class); -// -// // 检查tokenPayload中是否存在token属性,并且这个属性不为空 -// String token = tokenPayload.getToken(); -// if (StringUtils.hasText(token)) { -// try { -// UserDetails userDetails = JWTUtil.getUserDetailsList(token, Admin.class); -// if (!ObjectUtils.isEmpty(userDetails)) { -// // 将这个用户注册到Security中 -// UsernamePasswordAuthenticationToken authenticationToken -// = new UsernamePasswordAuthenticationToken( -// userDetails, null, -// userDetails.getAuthorities()); -// authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(requestWrapper)); -// SecurityContextHolder.getContext().setAuthentication(authenticationToken); -// } -// } catch (Exception e) { -// e.printStackTrace(); -// // Token无效,可以在这里添加相应的处理逻辑,例如返回401状态码等 -// } -// } -// } -// filterChain.doFilter(requestWrapper, response); // 注意这里使用requestWrapper -// } -//} -//package com.example.demo.security; -// -//import com.example.demo.Util.JWTUtil; -//import com.example.demo.Util.RequestWrapper; -//import com.example.demo.Util.TokenPayload; -//import com.example.demo.domain.entity.Admin; -//import com.fasterxml.jackson.databind.ObjectMapper; -//import jakarta.servlet.FilterChain; -//import jakarta.servlet.ServletException; -//import jakarta.servlet.http.HttpServletRequest; -//import jakarta.servlet.http.HttpServletResponse; -//import org.springframework.core.annotation.Order; -//import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; -//import org.springframework.security.core.context.SecurityContextHolder; -//import org.springframework.security.core.userdetails.UserDetails; -//import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; -//import org.springframework.stereotype.Component; -//import org.springframework.util.ObjectUtils; -//import org.springframework.util.StringUtils; -//import org.springframework.web.filter.OncePerRequestFilter; -//import java.io.IOException; -//import java.io.InputStream; -// -//@Component -//public class TokenFilter extends OncePerRequestFilter { -// -// @Override -// protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) -// throws ServletException, IOException { -// // 检查是否是上传请求 -// boolean isUploadRequest = request.getRequestURI().startsWith("/upload"); -// System.out.println(request.getRequestURI()); -// System.out.println(isUploadRequest); -// if (isUploadRequest) { -// // 如果是上传请求,直接将请求传递给下一个过滤器或目标资源 -// filterChain.doFilter(request, response); -// return; -// } else { -// // 使用RequestWrapper包装原始的HttpServletRequest,使其输入流可以被重复读取 -// RequestWrapper requestWrapper = new RequestWrapper(request); -// System.out.println(request); -// // 确保请求体只被读取一次 -// boolean hasRequestBody = "POST".equals(requestWrapper.getMethod()); -// if (hasRequestBody) { -// // 获取输入流 -// InputStream inputStream = requestWrapper.getInputStream(); -// // 使用Jackson ObjectMapper解析JSON -// ObjectMapper objectMapper = new ObjectMapper(); -// TokenPayload tokenPayload = objectMapper.readValue(inputStream, TokenPayload.class); -// -// // 检查tokenPayload中是否存在token属性,并且这个属性不为空 -// String token = tokenPayload.getToken(); -// if (StringUtils.hasText(token)) { -// try { -// UserDetails userDetails = JWTUtil.getUserDetailsList(token, Admin.class); -// if (!ObjectUtils.isEmpty(userDetails)) { -// // 将这个用户注册到Security中 -// UsernamePasswordAuthenticationToken authenticationToken -// = new UsernamePasswordAuthenticationToken( -// userDetails, null, -// userDetails.getAuthorities()); -// authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(requestWrapper)); -// SecurityContextHolder.getContext().setAuthentication(authenticationToken); -// } -// } catch (Exception e) { -// e.printStackTrace(); -// // Token无效,可以在这里添加相应的处理逻辑,例如返回401状态码等 -// } -// } -// } -// // 非上传请求,继续执行过滤器链 -// filterChain.doFilter(requestWrapper, response); -// } -// } -//} package com.example.demo.security; + import com.example.demo.Util.JWTUtil; import com.example.demo.Util.RequestWrapper; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; +import com.example.demo.domain.entity.Admin; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import org.springframework.core.annotation.Order; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; @@ -212,66 +17,24 @@ import org.springframework.stereotype.Component; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.filter.OncePerRequestFilter; - import java.io.IOException; -import java.io.InputStream; -import java.util.Map; + @Component public class TokenFilter extends OncePerRequestFilter { - - private final ObjectMapper objectMapper = new ObjectMapper(); - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - // 检查是否是上传请求 - boolean isErpRequest = request.getRequestURI().startsWith("/ERP") || request.getRequestURI().contains("ERP"); - boolean isUploadRequest = request.getRequestURI().startsWith("/upload"); -// System.out.println(request.getRequestURI()); -// System.out.println(isUploadRequest); - if (isUploadRequest ) { - // 如果是上传请求,直接将请求传递给下一个过滤器或目标资源 - filterChain.doFilter(request, response); - return; - } else { - // 使用RequestWrapper包装原始的HttpServletRequest,使其输入流可以被重复读取 - RequestWrapper requestWrapper = new RequestWrapper(request); -// System.out.println(request); - - // 确保请求体只被读取一次 - boolean hasRequestBody = "POST".equals(requestWrapper.getMethod()); - if (hasRequestBody) { - // 获取输入流 - InputStream inputStream = requestWrapper.getInputStream(); + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { + // 取Token 生成登录信息 + String token = request.getHeader("token"); - try { - // 尝试将输入流转换为Map - Map jsonMap = objectMapper.readValue(inputStream, new TypeReference>() {}); - // 提取并处理token字段 - String token = (String) jsonMap.get("token"); - /* if (StringUtils.hasText(token)) { - processToken(token, requestWrapper); - }*/ + System.out.println(token+"123132132"); - // 处理其他字段(如recharge列表) - // 这里可以根据需要进一步解析其他字段 - } catch (JsonProcessingException e) { - e.printStackTrace(); - // JSON解析失败,可以在这里添加相应的处理逻辑,例如返回400状态码等 - } - } - // 非上传请求,继续执行过滤器链 - filterChain.doFilter(requestWrapper, response); - } - } - - /* private void processToken(String token, HttpServletRequest request) { - if (StringUtils.hasText(token)) { + // token不为空 + if (StringUtils.hasText(token)){ try { UserDetails userDetails = JWTUtil.getUserDetailsList(token, Admin.class); - if (!ObjectUtils.isEmpty(userDetails)) { + if ( ! ObjectUtils.isEmpty(userDetails)) { // 将这个用户注册到Security中 UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken( @@ -282,11 +45,10 @@ public class TokenFilter extends OncePerRequestFilter { } } catch (Exception e) { e.printStackTrace(); - // Token无效,可以在这里添加相应的处理逻辑,例如返回401状态码等 + // Token无效, } } - }*/ + // 过滤器放行 + filterChain.doFilter(request, response); + } } - - - diff --git a/src/main/java/com/example/demo/security/UploadFilter.java b/src/main/java/com/example/demo/security/UploadFilter.java deleted file mode 100644 index a23be26..0000000 --- a/src/main/java/com/example/demo/security/UploadFilter.java +++ /dev/null @@ -1,43 +0,0 @@ -package com.example.demo.security; - -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; -import org.springframework.web.multipart.MultipartResolver; - -import java.io.IOException; - - -@Component -public class UploadFilter extends OncePerRequestFilter { - - private final MultipartResolver multipartResolver; - - public UploadFilter(MultipartResolver multipartResolver) { - this.multipartResolver = multipartResolver; - } - - @Override - protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) - throws ServletException, IOException { - - // 检查请求是否为上传请求,这里假设上传请求的路径以 "/upload" 开头 - boolean isUploadRequest = request.getRequestURI().startsWith("/upload"); - System.out.println(isUploadRequest); - System.out.println("MultipartResolver: " + multipartResolver); - if (isUploadRequest ) { - System.out.println("执行upload-------------------------------"); - // 如果是上传请求且Content-Type为multipart/form-data,直接将请求传递给下一个过滤器或目标资源 - filterChain.doFilter(request, response); - } else { - // 如果不是上传请求,执行一些自定义逻辑 - // 例如,可以在这里添加令牌验证或其他安全检查 - - // 继续执行过滤器链 - filterChain.doFilter(request, response); - } - } -} \ No newline at end of file diff --git a/src/main/java/com/example/demo/service/AdminService.java b/src/main/java/com/example/demo/service/AdminService.java new file mode 100644 index 0000000..8f24f2d --- /dev/null +++ b/src/main/java/com/example/demo/service/AdminService.java @@ -0,0 +1,15 @@ +package com.example.demo.service; + +import com.example.demo.domain.entity.Admin; + +/** + * @program: GOLD + * @ClassName adminService + * @description: + * @author: huangqizhen + * @create: 2025−07-01 10:40 + * @Version 1.0 + **/ +public interface AdminService { + Admin login(Admin admin)throws Exception; +} diff --git a/src/main/java/com/example/demo/service/AiEmotionService.java b/src/main/java/com/example/demo/service/AiEmotionService.java index 919e782..c9b4f96 100644 --- a/src/main/java/com/example/demo/service/AiEmotionService.java +++ b/src/main/java/com/example/demo/service/AiEmotionService.java @@ -13,7 +13,7 @@ import com.example.demo.domain.vo.ExportVo; **/ public interface AiEmotionService { - ExportVo updateStatus(Long recordId, int i, String s, String s1, int i1); + int updateStatus(Long recordId, int i, String s, String s1, int i1); AiEmotionExportRecordVO getRecordById(Long id) throws Exception; } diff --git a/src/main/java/com/example/demo/service/ExportExcelService.java b/src/main/java/com/example/demo/service/ExportExcelService.java index 7db47e3..bf7134c 100644 --- a/src/main/java/com/example/demo/service/ExportExcelService.java +++ b/src/main/java/com/example/demo/service/ExportExcelService.java @@ -1,6 +1,8 @@ package com.example.demo.service; -import com.example.demo.domain.vo.AiEmotionExportRecordVO; +import com.example.demo.domain.entity.Export; + +import java.util.List; /** * @program: GOLD @@ -12,5 +14,9 @@ import com.example.demo.domain.vo.AiEmotionExportRecordVO; **/ public interface ExportExcelService { Exception handleExcelExportData(String message) throws Exception; - + Exception handleExcel(String message) throws Exception; + Exception rechargeExcel(String message) throws Exception; + Exception consumeExcel(String message) throws Exception; + Exception refundExcel(String message) throws Exception; + List getExcel(Export export); } \ No newline at end of file diff --git a/src/main/java/com/example/demo/service/GoldDetailService.java b/src/main/java/com/example/demo/service/GoldDetailService.java index 6106f9e..6ac1d18 100644 --- a/src/main/java/com/example/demo/service/GoldDetailService.java +++ b/src/main/java/com/example/demo/service/GoldDetailService.java @@ -1,14 +1,14 @@ package com.example.demo.service; import com.example.demo.domain.DTO.GoldDetailDTO; +import com.example.demo.domain.DTO.GoldUserDTO; import com.example.demo.domain.entity.User; import com.example.demo.domain.vo.GoldDetail; + import com.example.demo.domain.vo.Result; import com.example.demo.domain.vo.Total; import com.github.pagehelper.PageInfo; -import jakarta.servlet.http.HttpServletResponse; -import java.io.IOException; /** * @program: GOLD @@ -26,4 +26,6 @@ public interface GoldDetailService { Total GoldTotal(User user); //异步导出客户明细 Result addExportRecord(GoldDetailDTO dto); + //异步导出金币余额 + Result addExportRecordGold(GoldUserDTO dto); } diff --git a/src/main/java/com/example/demo/service/listen/AiEmotionExportListener.java b/src/main/java/com/example/demo/service/listen/AiEmotionExportListener.java index c2b3903..635ecdb 100644 --- a/src/main/java/com/example/demo/service/listen/AiEmotionExportListener.java +++ b/src/main/java/com/example/demo/service/listen/AiEmotionExportListener.java @@ -48,7 +48,7 @@ public class AiEmotionExportListener extends AbstractMessageListener { exportExcelService.handleExcelExportData(message); } catch (Exception e) { logError(e, message); - throw new RuntimeException("Failed to process AI emotion export: " + e.getMessage(), e); + throw new RuntimeException("Failed to process HWGOLD export: " + e.getMessage(), e); } @@ -67,7 +67,7 @@ public class AiEmotionExportListener extends AbstractMessageListener { context, e.getStackTrace()[0].getFileName(), e.getStackTrace()[0].getLineNumber(), - "AI Emotion Export Error: " + e.getMessage() + " 底层错误: " + cause , + "HWGOLD Export Error: " + e.getMessage() + " 底层错误: " + cause , "Failed message: " + message ); } catch (Exception alertEx) { diff --git a/src/main/java/com/example/demo/service/listen/ConsumeListener.java b/src/main/java/com/example/demo/service/listen/ConsumeListener.java new file mode 100644 index 0000000..853b0be --- /dev/null +++ b/src/main/java/com/example/demo/service/listen/ConsumeListener.java @@ -0,0 +1,81 @@ +package com.example.demo.service.listen; + +import cn.hutool.core.util.StrUtil; +import com.example.demo.Export.ExportService; +import com.example.demo.Util.ExecutionContextUtil; +import com.example.demo.Util.FeiShuAlertUtil; +import com.example.demo.Util.RedisUtil; +import com.example.demo.domain.vo.ExecutionContext; +import com.example.demo.service.ExportExcelService; +import com.example.demo.service.queue.AbstractMessageListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @program: GOLD + * @ClassName RechargeListener + * @description: + * @author: huangqizhen + * @create: 2025−07-01 15:46 + * @Version 1.0 + **/ +@Component +public class ConsumeListener extends AbstractMessageListener { + //注入ExportExcelService + @Autowired + private ExportExcelService exportService; + + @Autowired + public ConsumeListener( + RedisUtil redisQueueUtil + + ) { + super(redisQueueUtil, "consume:queue:export_queue"); + System.out.println("监听器已启动,队列: "); + } + + @Override + protected void handleMessage(String message) { + if (StrUtil.isBlank(message)) { + System.err.println("redis消息队列数据为空" + message); + } + try { + Thread.sleep(5000); + exportService.consumeExcel(message); + } catch (Exception e) { + logError(e, message); + throw new RuntimeException("Failed to process HWGOLD export: " + e.getMessage(), e); + } + + + } + + private void logError(Exception e, String message) { + System.err.println("Export data listener exception: " + e.getMessage()); + e.printStackTrace(); + try { + ExecutionContext context = ExecutionContextUtil.getExecutionContext(); + String cause = ""; + if (e.getCause() != null) { + cause = e.getCause().getMessage(); + } + FeiShuAlertUtil.sendAlertMessage( + context, + e.getStackTrace()[0].getFileName(), + e.getStackTrace()[0].getLineNumber(), + "HWGOLD Export Error: " + e.getMessage() + " 底层错误: " + cause , + "Failed message: " + message + ); + } catch (Exception alertEx) { + System.err.println("Failed to send Feishu alert: " + alertEx.getMessage()); + } + } + + @Override + protected void handleError(Exception e, String message) { + System.err.println("处理消息失败: " + message); + e.printStackTrace(); + } + +} + diff --git a/src/main/java/com/example/demo/service/listen/GoldListener.java b/src/main/java/com/example/demo/service/listen/GoldListener.java new file mode 100644 index 0000000..3736216 --- /dev/null +++ b/src/main/java/com/example/demo/service/listen/GoldListener.java @@ -0,0 +1,82 @@ +package com.example.demo.service.listen; + +import cn.hutool.core.util.StrUtil; + +import com.example.demo.Util.ExecutionContextUtil; +import com.example.demo.Util.FeiShuAlertUtil; +import com.example.demo.Util.RedisUtil; +import com.example.demo.domain.vo.ExecutionContext; +import com.example.demo.service.ExportExcelService; +import com.example.demo.service.GoldDetailService; +import com.example.demo.service.queue.AbstractMessageListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @program: GOLD + * @ClassName GoldListener + * @description: + * @author: huangqizhen + * @create: 2025−07-01 15:43 + * @Version 1.0 + **/ +@Component +public class GoldListener extends AbstractMessageListener { + //注入ExportExcelService + @Autowired + private ExportExcelService exportExcelService; + + @Autowired + public GoldListener( + RedisUtil redisQueueUtil + + ) { + super(redisQueueUtil, "gold:queue:export_queue"); + System.out.println("监听器已启动,队列: "); + } + + @Override + protected void handleMessage(String message) { + if (StrUtil.isBlank(message)) { + System.err.println("redis消息队列数据为空" + message); + } + try { + Thread.sleep(5000); + exportExcelService.handleExcel(message); + } catch (Exception e) { + logError(e, message); + throw new RuntimeException("Failed to process HWGOLD export: " + e.getMessage(), e); + } + + + } + + private void logError(Exception e, String message) { + System.err.println("Export data listener exception: " + e.getMessage()); + e.printStackTrace(); + try { + ExecutionContext context = ExecutionContextUtil.getExecutionContext(); + String cause = ""; + if (e.getCause() != null) { + cause = e.getCause().getMessage(); + } + FeiShuAlertUtil.sendAlertMessage( + context, + e.getStackTrace()[0].getFileName(), + e.getStackTrace()[0].getLineNumber(), + "HWGOLD Export Error: " + e.getMessage() + " 底层错误: " + cause , + "Failed message: " + message + ); + } catch (Exception alertEx) { + System.err.println("Failed to send Feishu alert: " + alertEx.getMessage()); + } + } + + @Override + protected void handleError(Exception e, String message) { + System.err.println("处理消息失败: " + message); + e.printStackTrace(); + } + +} + diff --git a/src/main/java/com/example/demo/service/listen/RechargeListener.java b/src/main/java/com/example/demo/service/listen/RechargeListener.java new file mode 100644 index 0000000..8240be4 --- /dev/null +++ b/src/main/java/com/example/demo/service/listen/RechargeListener.java @@ -0,0 +1,81 @@ +package com.example.demo.service.listen; + +import cn.hutool.core.util.StrUtil; +import com.example.demo.Export.ExportService; +import com.example.demo.Util.ExecutionContextUtil; +import com.example.demo.Util.FeiShuAlertUtil; +import com.example.demo.Util.RedisUtil; +import com.example.demo.domain.vo.ExecutionContext; +import com.example.demo.service.ExportExcelService; +import com.example.demo.service.queue.AbstractMessageListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @program: GOLD + * @ClassName RechargeListener + * @description: + * @author: huangqizhen + * @create: 2025−07-01 15:46 + * @Version 1.0 + **/ +@Component +public class RechargeListener extends AbstractMessageListener { + //注入ExportExcelService + @Autowired + private ExportExcelService exportService; + + @Autowired + public RechargeListener( + RedisUtil redisQueueUtil + + ) { + super(redisQueueUtil, "recharge:queue:export_queue"); + System.out.println("监听器已启动,队列: "); + } + + @Override + protected void handleMessage(String message) { + if (StrUtil.isBlank(message)) { + System.err.println("redis消息队列数据为空" + message); + } + try { + Thread.sleep(5000); + exportService.rechargeExcel(message); + } catch (Exception e) { + logError(e, message); + throw new RuntimeException("Failed to process HWGOLD export: " + e.getMessage(), e); + } + + + } + + private void logError(Exception e, String message) { + System.err.println("Export data listener exception: " + e.getMessage()); + e.printStackTrace(); + try { + ExecutionContext context = ExecutionContextUtil.getExecutionContext(); + String cause = ""; + if (e.getCause() != null) { + cause = e.getCause().getMessage(); + } + FeiShuAlertUtil.sendAlertMessage( + context, + e.getStackTrace()[0].getFileName(), + e.getStackTrace()[0].getLineNumber(), + "HWGOLD Export Error: " + e.getMessage() + " 底层错误: " + cause , + "Failed message: " + message + ); + } catch (Exception alertEx) { + System.err.println("Failed to send Feishu alert: " + alertEx.getMessage()); + } + } + + @Override + protected void handleError(Exception e, String message) { + System.err.println("处理消息失败: " + message); + e.printStackTrace(); + } + +} + diff --git a/src/main/java/com/example/demo/service/listen/RefundListener.java b/src/main/java/com/example/demo/service/listen/RefundListener.java new file mode 100644 index 0000000..fa71944 --- /dev/null +++ b/src/main/java/com/example/demo/service/listen/RefundListener.java @@ -0,0 +1,81 @@ +package com.example.demo.service.listen; + +import cn.hutool.core.util.StrUtil; +import com.example.demo.Export.ExportService; +import com.example.demo.Util.ExecutionContextUtil; +import com.example.demo.Util.FeiShuAlertUtil; +import com.example.demo.Util.RedisUtil; +import com.example.demo.domain.vo.ExecutionContext; +import com.example.demo.service.ExportExcelService; +import com.example.demo.service.queue.AbstractMessageListener; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +/** + * @program: GOLD + * @ClassName RechargeListener + * @description: + * @author: huangqizhen + * @create: 2025−07-01 15:46 + * @Version 1.0 + **/ +@Component +public class RefundListener extends AbstractMessageListener { + //注入ExportExcelService + @Autowired + private ExportExcelService exportExcelService; + + @Autowired + public RefundListener( + RedisUtil redisQueueUtil + + ) { + super(redisQueueUtil, "refund:queue:export_queue"); + System.out.println("监听器已启动,队列: "); + } + + @Override + protected void handleMessage(String message) { + if (StrUtil.isBlank(message)) { + System.err.println("redis消息队列数据为空" + message); + } + try { + Thread.sleep(5000); + exportExcelService.refundExcel(message); + } catch (Exception e) { + logError(e, message); + throw new RuntimeException("Failed to process HWGOLD export: " + e.getMessage(), e); + } + + + } + + private void logError(Exception e, String message) { + System.err.println("Export data listener exception: " + e.getMessage()); + e.printStackTrace(); + try { + ExecutionContext context = ExecutionContextUtil.getExecutionContext(); + String cause = ""; + if (e.getCause() != null) { + cause = e.getCause().getMessage(); + } + FeiShuAlertUtil.sendAlertMessage( + context, + e.getStackTrace()[0].getFileName(), + e.getStackTrace()[0].getLineNumber(), + "HWGOLD Export Error: " + e.getMessage() + " 底层错误: " + cause , + "Failed message: " + message + ); + } catch (Exception alertEx) { + System.err.println("Failed to send Feishu alert: " + alertEx.getMessage()); + } + } + + @Override + protected void handleError(Exception e, String message) { + System.err.println("处理消息失败: " + message); + e.printStackTrace(); + } + +} + diff --git a/src/main/java/com/example/demo/serviceImpl/AdminServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/AdminServiceImpl.java new file mode 100644 index 0000000..d9b1620 --- /dev/null +++ b/src/main/java/com/example/demo/serviceImpl/AdminServiceImpl.java @@ -0,0 +1,64 @@ +package com.example.demo.serviceImpl; + +import com.example.demo.domain.entity.Admin; +import com.example.demo.mapper.AdminMapper; +import com.example.demo.service.AdminService; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Service; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.transaction.annotation.Transactional; + +@Transactional +@Service +@RequiredArgsConstructor +public class AdminServiceImpl implements AdminService { + + @Autowired + private AuthenticationManager authenticationManager; + @Autowired + private AdminMapper adminMapper; + + @Override + public Admin login(Admin admin) throws Exception { + try { + Admin admin1 = adminMapper.getAdmin(admin.getAccount()); + String[] machineIds = admin1.getMachineId().split(","); + + boolean flag = false; + for (String machineId : machineIds) { + if (admin.getMachineId() != null && admin.getMachineId().equals(machineId)) + flag = true; + } + if (!flag) { + throw new RuntimeException("你没有使用该机器的权限!"); + } + System.out.println(admin.getAccount()); + System.out.println(admin.getPassword()+"---------------------------"); + UsernamePasswordAuthenticationToken token = + new UsernamePasswordAuthenticationToken(admin.getAccount(),admin.getPassword()); + System.out.println( token+"---------------------------"); +// Authentication authentication = authenticationManager.authenticate(token); +// Admin loginAdmin = (Admin) authentication.getPrincipal(); + Admin loginAdmin = (Admin) authenticationManager.authenticate(token).getPrincipal(); + + return loginAdmin; + + }catch (NullPointerException e){ + throw new RuntimeException("无此精网号"); + }catch(BadCredentialsException exception){ + throw new BadCredentialsException("密码错误"); + }catch (Exception e){ + throw new RuntimeException("你没有使用该机器的权限!"); + } + + + } + +} \ No newline at end of file diff --git a/src/main/java/com/example/demo/serviceImpl/AiEmotionServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/AiEmotionServiceImpl.java index e709ee4..3d68db2 100644 --- a/src/main/java/com/example/demo/serviceImpl/AiEmotionServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/AiEmotionServiceImpl.java @@ -24,7 +24,7 @@ public class AiEmotionServiceImpl implements AiEmotionService { private AiEmotionMapper aiEmotionMapper; @Override - public ExportVo updateStatus(Long recordId, int i, String s, String s1, int i1) { + public int updateStatus(Long recordId, int i, String s, String s1, int i1) { return exportMapper.updateExportData(recordId, i, s, s1, i1); } diff --git a/src/main/java/com/example/demo/serviceImpl/ExportExcelServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/ExportExcelServiceImpl.java index 5895109..98efdd1 100644 --- a/src/main/java/com/example/demo/serviceImpl/ExportExcelServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/ExportExcelServiceImpl.java @@ -5,10 +5,15 @@ import com.alibaba.excel.EasyExcel; import com.alibaba.excel.ExcelWriter; import com.alibaba.excel.write.metadata.WriteSheet; import com.example.demo.Util.ExcelUploadUtil; +import com.example.demo.controller.ConsumeController; import com.example.demo.controller.GoldDetailController; +import com.example.demo.controller.RechargeController; +import com.example.demo.controller.RefundController; +import com.example.demo.domain.entity.Export; import com.example.demo.domain.export.Goldmingxi; import com.example.demo.domain.vo.*; +import com.example.demo.mapper.ExportMapper; import com.example.demo.service.ExportExcelService; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; @@ -17,6 +22,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.example.demo.service.AiEmotionService; +import com.github.pagehelper.PageInfo; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; @@ -25,7 +31,6 @@ import org.springframework.transaction.annotation.Transactional; import java.io.*; import java.util.List; -import java.util.Map; @Service @@ -40,9 +45,17 @@ public class ExportExcelServiceImpl implements ExportExcelService { //注入GoldDetailController @Autowired private GoldDetailController goldDetailController; + @Autowired + private RechargeController rechargeController; + @Autowired + private RefundController refundController; + @Autowired + private ConsumeController consumeController; // 每页查询的数据量 private static final int PAGE_SIZE = 1000; + @Autowired + private ExportMapper exportMapper; @Transactional @@ -92,20 +105,31 @@ public class ExportExcelServiceImpl implements ExportExcelService { Result pageResult = goldDetailController.getGoldDetail(page); Integer code = pageResult.getCode(); Object data = pageResult.getData(); + if (code == 200) { - Map rawData = (Map) data; - Long total = (Long) rawData.get("total"); - List> list = (List>) rawData.get("list"); - // 检查是否还有数据 + // 判断 data 是否是 PageInfo 类型 + if (!(data instanceof PageInfo)) { + log.error("返回数据类型错误,期望 PageInfo,实际为:{}", data.getClass()); + hasMore = false; + continue; + } + + @SuppressWarnings("unchecked") + PageInfo pageInfo = (PageInfo) data; + + Long total = (long) pageInfo.getTotal(); // 转换为 long + List list = pageInfo.getList(); + if (list == null || list.isEmpty()) { hasMore = false; } else { - // 写入数据(注意:finish()应在所有数据写入后调用) + // 写入 Excel 数据 excelWriter.write(list, writeSheet); + page.setPageNum(page.getPageNum() + 1); totalCount += list.size(); log.info("导出进度 recordId: {}, 已处理: {}条", recordId, totalCount); - // 检查是否还有更多数据 + hasMore = totalCount < total; } } else { @@ -136,16 +160,35 @@ public class ExportExcelServiceImpl implements ExportExcelService { // 3. 执行上传 String result = uploadUtil.uploadExcel(excelFile, "export/excel/"); // 1. 解析JSON任务 +// JsonNode uploadResult = objectMapper.readTree(result); +// System.out.println(uploadResult+"11111111111111111111111"); +// long code = uploadResult.path("code").asLong(); +// String url = String.valueOf(uploadResult.path("data")); +// url = url.replace("\"", ""); +// if (code == 1) { +// // 3. 验证导出记录decodecode +// aiEmotionService.updateStatus(recordId, 2, url, "", totalCount); +// } else { +// //更新失败 +// aiEmotionService.updateStatus(recordId, 3, "", url, 0); +// } JsonNode uploadResult = objectMapper.readTree(result); long code = uploadResult.path("code").asLong(); - String url = String.valueOf(uploadResult.path("data")); - url = url.replace("\"", ""); - if (code == 1) { - // 3. 验证导出记录decodecode - aiEmotionService.updateStatus(recordId, 2, url, "", totalCount); + + String fileUrl = ""; + JsonNode dataNode = uploadResult.path("data"); + if (dataNode.isObject()) { + fileUrl = dataNode.path("url").asText(); + } else if (dataNode.isTextual()) { + fileUrl = dataNode.asText(); // 如果 data 是直接字符串 URL + } + + log.info("解析到的URL: {}", fileUrl); + + if (code == 200 && !fileUrl.isEmpty()) { + aiEmotionService.updateStatus(recordId, 2, fileUrl, "", totalCount); } else { - //更新失败 - aiEmotionService.updateStatus(recordId, 3, "", url, 0); + aiEmotionService.updateStatus(recordId, 3, "", "上传成功但URL为空或解析失败", 0); } } catch (Exception e) { //更新失败 @@ -215,6 +258,812 @@ public class ExportExcelServiceImpl implements ExportExcelService { } + + @Transactional + @Override + public Exception handleExcel(String message) throws Exception { + System.out.println("明细导出excel数据开始执行:" + message); + long startTime = System.currentTimeMillis(); + Long recordId = null; + String fileName = null; + File tempFile = null; + OutputStream outputStream = null; + ExcelWriter excelWriter = null; + + try { + // 1. 解析JSON任务 + JsonNode rootNode = objectMapper.readTree(message); + // 2. 获取基本参数 + recordId = rootNode.path("recordId").asLong(); + JsonNode requestDataNode = rootNode.path("requestData"); + // 3. 验证导出记录 + AiEmotionExportRecordVO record = validateExportRecord(recordId); + if (record == null) return null; + //4. 更新状态为处理中 + aiEmotionService.updateStatus(recordId, 1, "", "", 0); + // 5. 准备Excel文件 + fileName = record.getFileName(); + // 初始化临时文件(保存到本地临时目录) + tempFile = File.createTempFile("export_", ".xlsx"); + outputStream = new FileOutputStream(tempFile); // 使用文件输出流 + // 从JSON中提取单个值 + String text = requestDataNode.has("text") ? requestDataNode.get("text").asText() : null; + Integer sort = requestDataNode.has("sort") ? requestDataNode.get("sort").asInt() : null; + String field = requestDataNode.has("field") ? requestDataNode.get("field").asText() : null; + String deptId = requestDataNode.has("deptId") ? requestDataNode.get("deptId").asText() : null; + + try { + // 6. 初始化Excel写入器(指向本地文件流) + excelWriter = initExcelWriter(outputStream, "user"); + WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build(); + // 7. 分页查询并写入数据 + Page page = new Page(); + page.setPageNum(1); + page.setPageSize(1000); + Integer totalCount = 0; + boolean hasMore = true; + while (hasMore) { + Result pageResult = goldDetailController.getGold(page); + Integer code = pageResult.getCode(); + Object data = pageResult.getData(); + + if (code == 200) { + // 判断 data 是否是 PageInfo 类型 + if (!(data instanceof PageInfo)) { + log.error("返回数据类型错误,期望 PageInfo,实际为:{}", data.getClass()); + hasMore = false; + continue; + } + + @SuppressWarnings("unchecked") + PageInfo pageInfo = (PageInfo) data; + + Long total = (long) pageInfo.getTotal(); // 转换为 long + List list = pageInfo.getList(); + + if (list == null || list.isEmpty()) { + hasMore = false; + } else { + // 写入 Excel 数据 + excelWriter.write(list, writeSheet); + + page.setPageNum(page.getPageNum() + 1); + totalCount += list.size(); + log.info("导出进度 recordId: {}, 已处理: {}条", recordId, totalCount); + + hasMore = totalCount < total; + } + } else { + hasMore = false; + log.error("获取数据失败,状态码: {}", code); + } + } + // 7. 完成Excel写入(所有数据写入后关闭写入器) + if (excelWriter != null) { + excelWriter.finish(); + } + if (outputStream != null) { + outputStream.flush(); // 确保所有数据写入 + outputStream.close(); // 关闭文件流 + } + // 检查文件是否存在且不为空 + if (tempFile != null && tempFile.exists() && tempFile.length() > 0) { + // 8. 上传到OSS(读取本地临时文件) + // 获取接口的基础 URL + String uploadUrl = "http://39.101.133.168:8828/hljw/api/aws/upload"; + try { + // 1. 创建上传工具实例 + ExcelUploadUtil uploadUtil = new ExcelUploadUtil(uploadUrl); + + // 2. 准备要上传的文件 + File excelFile = new File(tempFile.toURI()); + try { + // 3. 执行上传 + String result = uploadUtil.uploadExcel(excelFile, "export/excel/"); + // 1. 解析JSON任务 +// JsonNode uploadResult = objectMapper.readTree(result); +// System.out.println(uploadResult+"11111111111111111111111"); +// long code = uploadResult.path("code").asLong(); +// String url = String.valueOf(uploadResult.path("data")); +// url = url.replace("\"", ""); +// if (code == 1) { +// // 3. 验证导出记录decodecode +// aiEmotionService.updateStatus(recordId, 2, url, "", totalCount); +// } else { +// //更新失败 +// aiEmotionService.updateStatus(recordId, 3, "", url, 0); +// } + JsonNode uploadResult = objectMapper.readTree(result); + long code = uploadResult.path("code").asLong(); + + String fileUrl = ""; + JsonNode dataNode = uploadResult.path("data"); + if (dataNode.isObject()) { + fileUrl = dataNode.path("url").asText(); + } else if (dataNode.isTextual()) { + fileUrl = dataNode.asText(); // 如果 data 是直接字符串 URL + } + + log.info("解析到的URL: {}", fileUrl); + + if (code == 200 && !fileUrl.isEmpty()) { + aiEmotionService.updateStatus(recordId, 2, fileUrl, "", totalCount); + } else { + aiEmotionService.updateStatus(recordId, 3, "", "上传成功但URL为空或解析失败", 0); + } + } catch (Exception e) { + //更新失败 + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + throw new Exception("文件上传云端失败1", e); + } + } catch (Exception e) { + log.error("上传文件失败 recordId: {}, 文件名: {}", recordId, fileName, e); + //更新状态为失败 + if (recordId != null) { + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + } + throw new Exception("文件上传云端失败2", e); + } + } else { + throw new Exception("导出的Excel文件不存在或为空"); + } + + } catch (Exception e) { + System.out.println("导出异常" + e.getMessage()); + log.error("导出任务处理失败 recordId: {}", recordId, e); + // 更新状态为失败 + if (recordId != null) { + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + } + throw new Exception("导出异常", e); + } finally { + // 确保资源被关闭 + try { + if (excelWriter != null) { + excelWriter.finish(); + } + if (outputStream != null) { + outputStream.close(); + } + } catch (Exception e) { + log.error("关闭资源失败", e); + throw new Exception("excel文件关闭资源失败", e); + } + } + } catch (Exception e) { + log.error("导出任务处理失败 recordId: {}", recordId, e); + // 更新状态为失败 + if (recordId != null) { + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + } + System.out.println("<导出失败>" + e.getMessage()); + throw new Exception("导出任务处理失败", e); + } finally { + // 清理临时文件 + if (tempFile != null && tempFile.exists()) { + try { + if (tempFile.delete()) { + log.info("临时文件已删除: {}", tempFile.getAbsolutePath()); + } else { + log.warn("无法删除临时文件: {}", tempFile.getAbsolutePath()); + } + } catch (Exception e) { + log.error("删除临时文件失败", e.getMessage()); + throw new Exception("删除临时文件失败", e); + } + } + long endTime = System.currentTimeMillis(); + log.info("导出任务完成,耗时: {}毫秒", (endTime - startTime)); + } + return null; + } + + @Transactional + @Override + public Exception rechargeExcel(String message) throws Exception { + System.out.println("明细导出excel数据开始执行:" + message); + long startTime = System.currentTimeMillis(); + Long recordId = null; + String fileName = null; + File tempFile = null; + OutputStream outputStream = null; + ExcelWriter excelWriter = null; + + try { + // 1. 解析JSON任务 + JsonNode rootNode = objectMapper.readTree(message); + // 2. 获取基本参数 + recordId = rootNode.path("recordId").asLong(); + JsonNode requestDataNode = rootNode.path("requestData"); + // 3. 验证导出记录 + AiEmotionExportRecordVO record = validateExportRecord(recordId); + if (record == null) return null; + //4. 更新状态为处理中 + aiEmotionService.updateStatus(recordId, 1, "", "", 0); + // 5. 准备Excel文件 + fileName = record.getFileName(); + // 初始化临时文件(保存到本地临时目录) + tempFile = File.createTempFile("export_", ".xlsx"); + outputStream = new FileOutputStream(tempFile); // 使用文件输出流 + // 从JSON中提取单个值 + String text = requestDataNode.has("text") ? requestDataNode.get("text").asText() : null; + Integer sort = requestDataNode.has("sort") ? requestDataNode.get("sort").asInt() : null; + String field = requestDataNode.has("field") ? requestDataNode.get("field").asText() : null; + String deptId = requestDataNode.has("deptId") ? requestDataNode.get("deptId").asText() : null; + + try { + // 6. 初始化Excel写入器(指向本地文件流) + excelWriter = initExcelWriter(outputStream, "user"); + WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build(); + // 7. 分页查询并写入数据 + Page page = new Page(); + page.setPageNum(1); + page.setPageSize(1000); + Integer totalCount = 0; + boolean hasMore = true; + while (hasMore) { + Result pageResult = rechargeController.selcetBy( page); + Integer code = pageResult.getCode(); + Object data = pageResult.getData(); + + if (code == 200) { + // 判断 data 是否是 PageInfo 类型 + if (!(data instanceof PageInfo)) { + log.error("返回数据类型错误,期望 PageInfo,实际为:{}", data.getClass()); + hasMore = false; + continue; + } + + @SuppressWarnings("unchecked") + PageInfo pageInfo = (PageInfo) data; + + Long total = (long) pageInfo.getTotal(); // 转换为 long + List list = pageInfo.getList(); + + if (list == null || list.isEmpty()) { + hasMore = false; + } else { + // 写入 Excel 数据 + excelWriter.write(list, writeSheet); + + page.setPageNum(page.getPageNum() + 1); + totalCount += list.size(); + log.info("导出进度 recordId: {}, 已处理: {}条", recordId, totalCount); + + hasMore = totalCount < total; + } + } else { + hasMore = false; + log.error("获取数据失败,状态码: {}", code); + } + } + // 7. 完成Excel写入(所有数据写入后关闭写入器) + if (excelWriter != null) { + excelWriter.finish(); + } + if (outputStream != null) { + outputStream.flush(); // 确保所有数据写入 + outputStream.close(); // 关闭文件流 + } + // 检查文件是否存在且不为空 + if (tempFile != null && tempFile.exists() && tempFile.length() > 0) { + // 8. 上传到OSS(读取本地临时文件) + // 获取接口的基础 URL + String uploadUrl = "http://39.101.133.168:8828/hljw/api/aws/upload"; + try { + // 1. 创建上传工具实例 + ExcelUploadUtil uploadUtil = new ExcelUploadUtil(uploadUrl); + + // 2. 准备要上传的文件 + File excelFile = new File(tempFile.toURI()); + try { + // 3. 执行上传 + String result = uploadUtil.uploadExcel(excelFile, "export/excel/"); + // 1. 解析JSON任务 +// JsonNode uploadResult = objectMapper.readTree(result); +// System.out.println(uploadResult+"11111111111111111111111"); +// long code = uploadResult.path("code").asLong(); +// String url = String.valueOf(uploadResult.path("data")); +// url = url.replace("\"", ""); +// if (code == 1) { +// // 3. 验证导出记录decodecode +// aiEmotionService.updateStatus(recordId, 2, url, "", totalCount); +// } else { +// //更新失败 +// aiEmotionService.updateStatus(recordId, 3, "", url, 0); +// } + JsonNode uploadResult = objectMapper.readTree(result); + long code = uploadResult.path("code").asLong(); + + String fileUrl = ""; + JsonNode dataNode = uploadResult.path("data"); + if (dataNode.isObject()) { + fileUrl = dataNode.path("url").asText(); + } else if (dataNode.isTextual()) { + fileUrl = dataNode.asText(); // 如果 data 是直接字符串 URL + } + + log.info("解析到的URL: {}", fileUrl); + + if (code == 200 && !fileUrl.isEmpty()) { + aiEmotionService.updateStatus(recordId, 2, fileUrl, "", totalCount); + } else { + aiEmotionService.updateStatus(recordId, 3, "", "上传成功但URL为空或解析失败", 0); + } + } catch (Exception e) { + //更新失败 + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + throw new Exception("文件上传云端失败1", e); + } + } catch (Exception e) { + log.error("上传文件失败 recordId: {}, 文件名: {}", recordId, fileName, e); + //更新状态为失败 + if (recordId != null) { + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + } + throw new Exception("文件上传云端失败2", e); + } + } else { + throw new Exception("导出的Excel文件不存在或为空"); + } + + } catch (Exception e) { + System.out.println("导出异常" + e.getMessage()); + log.error("导出任务处理失败 recordId: {}", recordId, e); + // 更新状态为失败 + if (recordId != null) { + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + } + throw new Exception("导出异常", e); + } finally { + // 确保资源被关闭 + try { + if (excelWriter != null) { + excelWriter.finish(); + } + if (outputStream != null) { + outputStream.close(); + } + } catch (Exception e) { + log.error("关闭资源失败", e); + throw new Exception("excel文件关闭资源失败", e); + } + } + } catch (Exception e) { + log.error("导出任务处理失败 recordId: {}", recordId, e); + // 更新状态为失败 + if (recordId != null) { + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + } + System.out.println("<导出失败>" + e.getMessage()); + throw new Exception("导出任务处理失败", e); + } finally { + // 清理临时文件 + if (tempFile != null && tempFile.exists()) { + try { + if (tempFile.delete()) { + log.info("临时文件已删除: {}", tempFile.getAbsolutePath()); + } else { + log.warn("无法删除临时文件: {}", tempFile.getAbsolutePath()); + } + } catch (Exception e) { + log.error("删除临时文件失败", e.getMessage()); + throw new Exception("删除临时文件失败", e); + } + } + long endTime = System.currentTimeMillis(); + log.info("导出任务完成,耗时: {}毫秒", (endTime - startTime)); + } + return null; + } + + @Transactional + @Override + public Exception consumeExcel(String message) throws Exception { + System.out.println("明细导出excel数据开始执行:" + message); + long startTime = System.currentTimeMillis(); + Long recordId = null; + String fileName = null; + File tempFile = null; + OutputStream outputStream = null; + ExcelWriter excelWriter = null; + + try { + // 1. 解析JSON任务 + JsonNode rootNode = objectMapper.readTree(message); + // 2. 获取基本参数 + recordId = rootNode.path("recordId").asLong(); + JsonNode requestDataNode = rootNode.path("requestData"); + // 3. 验证导出记录 + AiEmotionExportRecordVO record = validateExportRecord(recordId); + if (record == null) return null; + //4. 更新状态为处理中 + aiEmotionService.updateStatus(recordId, 1, "", "", 0); + // 5. 准备Excel文件 + fileName = record.getFileName(); + // 初始化临时文件(保存到本地临时目录) + tempFile = File.createTempFile("export_", ".xlsx"); + outputStream = new FileOutputStream(tempFile); // 使用文件输出流 + // 从JSON中提取单个值 + String text = requestDataNode.has("text") ? requestDataNode.get("text").asText() : null; + Integer sort = requestDataNode.has("sort") ? requestDataNode.get("sort").asInt() : null; + String field = requestDataNode.has("field") ? requestDataNode.get("field").asText() : null; + String deptId = requestDataNode.has("deptId") ? requestDataNode.get("deptId").asText() : null; + + try { + // 6. 初始化Excel写入器(指向本地文件流) + excelWriter = initExcelWriter(outputStream, "user"); + WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build(); + // 7. 分页查询并写入数据 + Page page = new Page(); + page.setPageNum(1); + page.setPageSize(1000); + Integer totalCount = 0; + boolean hasMore = true; + while (hasMore) { + Result pageResult = refundController.selcetBy(page); + Integer code = pageResult.getCode(); + Object data = pageResult.getData(); + + if (code == 200) { + // 判断 data 是否是 PageInfo 类型 + if (!(data instanceof PageInfo)) { + log.error("返回数据类型错误,期望 PageInfo,实际为:{}", data.getClass()); + hasMore = false; + continue; + } + + @SuppressWarnings("unchecked") + PageInfo pageInfo = (PageInfo) data; + + Long total = (long) pageInfo.getTotal(); // 转换为 long + List list = pageInfo.getList(); + + if (list == null || list.isEmpty()) { + hasMore = false; + } else { + // 写入 Excel 数据 + excelWriter.write(list, writeSheet); + + page.setPageNum(page.getPageNum() + 1); + totalCount += list.size(); + log.info("导出进度 recordId: {}, 已处理: {}条", recordId, totalCount); + + hasMore = totalCount < total; + } + } else { + hasMore = false; + log.error("获取数据失败,状态码: {}", code); + } + } + // 7. 完成Excel写入(所有数据写入后关闭写入器) + if (excelWriter != null) { + excelWriter.finish(); + } + if (outputStream != null) { + outputStream.flush(); // 确保所有数据写入 + outputStream.close(); // 关闭文件流 + } + // 检查文件是否存在且不为空 + if (tempFile != null && tempFile.exists() && tempFile.length() > 0) { + // 8. 上传到OSS(读取本地临时文件) + // 获取接口的基础 URL + String uploadUrl = "http://39.101.133.168:8828/hljw/api/aws/upload"; + try { + // 1. 创建上传工具实例 + ExcelUploadUtil uploadUtil = new ExcelUploadUtil(uploadUrl); + + // 2. 准备要上传的文件 + File excelFile = new File(tempFile.toURI()); + try { + // 3. 执行上传 + String result = uploadUtil.uploadExcel(excelFile, "export/excel/"); + // 1. 解析JSON任务 +// JsonNode uploadResult = objectMapper.readTree(result); +// System.out.println(uploadResult+"11111111111111111111111"); +// long code = uploadResult.path("code").asLong(); +// String url = String.valueOf(uploadResult.path("data")); +// url = url.replace("\"", ""); +// if (code == 1) { +// // 3. 验证导出记录decodecode +// aiEmotionService.updateStatus(recordId, 2, url, "", totalCount); +// } else { +// //更新失败 +// aiEmotionService.updateStatus(recordId, 3, "", url, 0); +// } + JsonNode uploadResult = objectMapper.readTree(result); + long code = uploadResult.path("code").asLong(); + + String fileUrl = ""; + JsonNode dataNode = uploadResult.path("data"); + if (dataNode.isObject()) { + fileUrl = dataNode.path("url").asText(); + } else if (dataNode.isTextual()) { + fileUrl = dataNode.asText(); // 如果 data 是直接字符串 URL + } + + log.info("解析到的URL: {}", fileUrl); + + if (code == 200 && !fileUrl.isEmpty()) { + aiEmotionService.updateStatus(recordId, 2, fileUrl, "", totalCount); + } else { + aiEmotionService.updateStatus(recordId, 3, "", "上传成功但URL为空或解析失败", 0); + } + } catch (Exception e) { + //更新失败 + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + throw new Exception("文件上传云端失败1", e); + } + } catch (Exception e) { + log.error("上传文件失败 recordId: {}, 文件名: {}", recordId, fileName, e); + //更新状态为失败 + if (recordId != null) { + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + } + throw new Exception("文件上传云端失败2", e); + } + } else { + throw new Exception("导出的Excel文件不存在或为空"); + } + + } catch (Exception e) { + System.out.println("导出异常" + e.getMessage()); + log.error("导出任务处理失败 recordId: {}", recordId, e); + // 更新状态为失败 + if (recordId != null) { + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + } + throw new Exception("导出异常", e); + } finally { + // 确保资源被关闭 + try { + if (excelWriter != null) { + excelWriter.finish(); + } + if (outputStream != null) { + outputStream.close(); + } + } catch (Exception e) { + log.error("关闭资源失败", e); + throw new Exception("excel文件关闭资源失败", e); + } + } + } catch (Exception e) { + log.error("导出任务处理失败 recordId: {}", recordId, e); + // 更新状态为失败 + if (recordId != null) { + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + } + System.out.println("<导出失败>" + e.getMessage()); + throw new Exception("导出任务处理失败", e); + } finally { + // 清理临时文件 + if (tempFile != null && tempFile.exists()) { + try { + if (tempFile.delete()) { + log.info("临时文件已删除: {}", tempFile.getAbsolutePath()); + } else { + log.warn("无法删除临时文件: {}", tempFile.getAbsolutePath()); + } + } catch (Exception e) { + log.error("删除临时文件失败", e.getMessage()); + throw new Exception("删除临时文件失败", e); + } + } + long endTime = System.currentTimeMillis(); + log.info("导出任务完成,耗时: {}毫秒", (endTime - startTime)); + } + return null; + } + + @Transactional + @Override + public Exception refundExcel(String message) throws Exception { + System.out.println("明细导出excel数据开始执行:" + message); + long startTime = System.currentTimeMillis(); + Long recordId = null; + String fileName = null; + File tempFile = null; + OutputStream outputStream = null; + ExcelWriter excelWriter = null; + + try { + // 1. 解析JSON任务 + JsonNode rootNode = objectMapper.readTree(message); + // 2. 获取基本参数 + recordId = rootNode.path("recordId").asLong(); + JsonNode requestDataNode = rootNode.path("requestData"); + // 3. 验证导出记录 + AiEmotionExportRecordVO record = validateExportRecord(recordId); + if (record == null) return null; + //4. 更新状态为处理中 + aiEmotionService.updateStatus(recordId, 1, "", "", 0); + // 5. 准备Excel文件 + fileName = record.getFileName(); + // 初始化临时文件(保存到本地临时目录) + tempFile = File.createTempFile("export_", ".xlsx"); + outputStream = new FileOutputStream(tempFile); // 使用文件输出流 + // 从JSON中提取单个值 + String text = requestDataNode.has("text") ? requestDataNode.get("text").asText() : null; + Integer sort = requestDataNode.has("sort") ? requestDataNode.get("sort").asInt() : null; + String field = requestDataNode.has("field") ? requestDataNode.get("field").asText() : null; + String deptId = requestDataNode.has("deptId") ? requestDataNode.get("deptId").asText() : null; + + try { + // 6. 初始化Excel写入器(指向本地文件流) + excelWriter = initExcelWriter(outputStream, "user"); + WriteSheet writeSheet = EasyExcel.writerSheet("Sheet1").build(); + // 7. 分页查询并写入数据 + Page page = new Page(); + page.setPageNum(1); + page.setPageSize(1000); + Integer totalCount = 0; + boolean hasMore = true; + while (hasMore) { + Result pageResult = consumeController.selcetBy(page); + Integer code = pageResult.getCode(); + Object data = pageResult.getData(); + + if (code == 200) { + // 判断 data 是否是 PageInfo 类型 + if (!(data instanceof PageInfo)) { + log.error("返回数据类型错误,期望 PageInfo,实际为:{}", data.getClass()); + hasMore = false; + continue; + } + + @SuppressWarnings("unchecked") + PageInfo pageInfo = (PageInfo) data; + + Long total = (long) pageInfo.getTotal(); // 转换为 long + List list = pageInfo.getList(); + + if (list == null || list.isEmpty()) { + hasMore = false; + } else { + // 写入 Excel 数据 + excelWriter.write(list, writeSheet); + + page.setPageNum(page.getPageNum() + 1); + totalCount += list.size(); + log.info("导出进度 recordId: {}, 已处理: {}条", recordId, totalCount); + + hasMore = totalCount < total; + } + } else { + hasMore = false; + log.error("获取数据失败,状态码: {}", code); + } + } + // 7. 完成Excel写入(所有数据写入后关闭写入器) + if (excelWriter != null) { + excelWriter.finish(); + } + if (outputStream != null) { + outputStream.flush(); // 确保所有数据写入 + outputStream.close(); // 关闭文件流 + } + // 检查文件是否存在且不为空 + if (tempFile != null && tempFile.exists() && tempFile.length() > 0) { + // 8. 上传到OSS(读取本地临时文件) + // 获取接口的基础 URL + String uploadUrl = "http://39.101.133.168:8828/hljw/api/aws/upload"; + try { + // 1. 创建上传工具实例 + ExcelUploadUtil uploadUtil = new ExcelUploadUtil(uploadUrl); + + // 2. 准备要上传的文件 + File excelFile = new File(tempFile.toURI()); + try { + // 3. 执行上传 + String result = uploadUtil.uploadExcel(excelFile, "export/excel/"); + // 1. 解析JSON任务 +// JsonNode uploadResult = objectMapper.readTree(result); +// System.out.println(uploadResult+"11111111111111111111111"); +// long code = uploadResult.path("code").asLong(); +// String url = String.valueOf(uploadResult.path("data")); +// url = url.replace("\"", ""); +// if (code == 1) { +// // 3. 验证导出记录decodecode +// aiEmotionService.updateStatus(recordId, 2, url, "", totalCount); +// } else { +// //更新失败 +// aiEmotionService.updateStatus(recordId, 3, "", url, 0); +// } + JsonNode uploadResult = objectMapper.readTree(result); + long code = uploadResult.path("code").asLong(); + + String fileUrl = ""; + JsonNode dataNode = uploadResult.path("data"); + if (dataNode.isObject()) { + fileUrl = dataNode.path("url").asText(); + } else if (dataNode.isTextual()) { + fileUrl = dataNode.asText(); // 如果 data 是直接字符串 URL + } + + log.info("解析到的URL: {}", fileUrl); + + if (code == 200 && !fileUrl.isEmpty()) { + aiEmotionService.updateStatus(recordId, 2, fileUrl, "", totalCount); + } else { + aiEmotionService.updateStatus(recordId, 3, "", "上传成功但URL为空或解析失败", 0); + } + } catch (Exception e) { + //更新失败 + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + throw new Exception("文件上传云端失败1", e); + } + } catch (Exception e) { + log.error("上传文件失败 recordId: {}, 文件名: {}", recordId, fileName, e); + //更新状态为失败 + if (recordId != null) { + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + } + throw new Exception("文件上传云端失败2", e); + } + } else { + throw new Exception("导出的Excel文件不存在或为空"); + } + + } catch (Exception e) { + System.out.println("导出异常" + e.getMessage()); + log.error("导出任务处理失败 recordId: {}", recordId, e); + // 更新状态为失败 + if (recordId != null) { + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + } + throw new Exception("导出异常", e); + } finally { + // 确保资源被关闭 + try { + if (excelWriter != null) { + excelWriter.finish(); + } + if (outputStream != null) { + outputStream.close(); + } + } catch (Exception e) { + log.error("关闭资源失败", e); + throw new Exception("excel文件关闭资源失败", e); + } + } + } catch (Exception e) { + log.error("导出任务处理失败 recordId: {}", recordId, e); + // 更新状态为失败 + if (recordId != null) { + aiEmotionService.updateStatus(recordId, 3, "", StringUtils.substring(e.getMessage(), 0, 500), 0); + } + System.out.println("<导出失败>" + e.getMessage()); + throw new Exception("导出任务处理失败", e); + } finally { + // 清理临时文件 + if (tempFile != null && tempFile.exists()) { + try { + if (tempFile.delete()) { + log.info("临时文件已删除: {}", tempFile.getAbsolutePath()); + } else { + log.warn("无法删除临时文件: {}", tempFile.getAbsolutePath()); + } + } catch (Exception e) { + log.error("删除临时文件失败", e.getMessage()); + throw new Exception("删除临时文件失败", e); + } + } + long endTime = System.currentTimeMillis(); + log.info("导出任务完成,耗时: {}毫秒", (endTime - startTime)); + } + return null; + } + + + @Override + public List getExcel(Export export) { + List list = exportMapper.getExportRecord(export.getAccount()); + System.out.println(list+"-------------------------------"); + return list; + } + + /** * 验证导出记录 */ diff --git a/src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java index 7d0dbcf..9fb1f91 100644 --- a/src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/GoldDetailServiceImpl.java @@ -2,6 +2,7 @@ package com.example.demo.serviceImpl; import com.example.demo.Util.RedisUtil; import com.example.demo.domain.DTO.GoldDetailDTO; +import com.example.demo.domain.DTO.GoldUserDTO; import com.example.demo.domain.entity.User; import com.example.demo.domain.vo.GoldDetail; import com.example.demo.domain.vo.Result; @@ -74,7 +75,7 @@ public class GoldDetailServiceImpl implements GoldDetailService { "操作人", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); System.out.println(fileName); - dto.setJwcode(123456); + dto.setAccount(123456); dto.setUrl(""); dto.setFileName(fileName); dto.setDataNum(0); @@ -83,7 +84,7 @@ public class GoldDetailServiceImpl implements GoldDetailService { GoldDetailMapper.ExportRecordIdHolder idHolder = new GoldDetailMapper.ExportRecordIdHolder(); goldDetailMapper.insertExportRecord( idHolder, // 用于接收主键 - dto.getJwcode(), + dto.getAccount(), dto.getType(), dto.getState(), dto.getUrl(), @@ -114,6 +115,53 @@ public class GoldDetailServiceImpl implements GoldDetailService { return Result.success(); } + @Override + public Result addExportRecordGold(GoldUserDTO dto) { + // 生成文件名 + String fileName = String.format("%s_%s_%s.xlsx", + "金币余额明细", + "操作人", + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))); + System.out.println(fileName); + dto.setAccount(123456); + dto.setUrl(""); + dto.setFileName(fileName); + dto.setDataNum(0); + try{ + // 调用方式 + GoldDetailMapper.ExportRecordIdHolder idHolder = new GoldDetailMapper.ExportRecordIdHolder(); + goldDetailMapper.insertExportRecord( + idHolder, // 用于接收主键 + dto.getAccount(), + dto.getType(), + dto.getState(), + dto.getUrl(), + dto.getFileName(), + dto.getDataNum() + ); + // 获取主键 + Long recordId = idHolder.getId(); + // 2. 构造完整的 JSON 数据(包含所有请求参数) + Map exportData = new HashMap<>(); + exportData.put("recordId", recordId); + + // 手动构造请求数据(避免 toString() 只返回部分字段) + Map requestData = new HashMap<>(); + requestData.put("text", dto.getText()); + requestData.put("sort", dto.getSort()); + requestData.put("field", dto.getField()); + requestData.put("deptId", dto.getDeptid()); + exportData.put("requestData", requestData); + + // 3. 发送到 Redis 消息队列 + String jsonData = new ObjectMapper().writeValueAsString(exportData); + redisUtil.sendMessage("gold:queue:export_queue", jsonData); + }catch (Exception e){ + e.printStackTrace(); + throw new SystemException("导出数据异常,请稍后重试", e); + } + return Result.success(); + } } diff --git a/src/main/resources/mapper/AiEmotionMapper.xml b/src/main/resources/mapper/AiEmotionMapper.xml index 2824bba..a927bd0 100644 --- a/src/main/resources/mapper/AiEmotionMapper.xml +++ b/src/main/resources/mapper/AiEmotionMapper.xml @@ -2,7 +2,7 @@ - UPDATE admin_export_record + UPDATE export state = #{state}, url = #{url}, @@ -12,6 +12,6 @@ WHERE id = #{recordId} \ No newline at end of file diff --git a/src/main/resources/mapper/ExportMapper.xml b/src/main/resources/mapper/ExportMapper.xml index 8cfcb31..f67834b 100644 --- a/src/main/resources/mapper/ExportMapper.xml +++ b/src/main/resources/mapper/ExportMapper.xml @@ -15,4 +15,14 @@ + + + \ No newline at end of file diff --git a/src/main/resources/mapper/GoldDetailMapper.xml b/src/main/resources/mapper/GoldDetailMapper.xml index 10d027b..cdb9a4e 100644 --- a/src/main/resources/mapper/GoldDetailMapper.xml +++ b/src/main/resources/mapper/GoldDetailMapper.xml @@ -2,8 +2,8 @@ - insert into excprt (jwcode,type,state,url,file_name,data_num) - values(#{jwcode},#{type},#{state},#{url},#{fileName},#{dataNum}) + insert into export (account,type,state,url,file_name,data_num) + values(#{account},#{type},#{state},#{url},#{fileName},#{dataNum}) - \ No newline at end of file + From 05cf4c59834b1a44e86a1cb76d9f52d1c5fa9dd7 Mon Sep 17 00:00:00 2001 From: jianlin Date: Tue, 1 Jul 2025 17:51:11 +0800 Subject: [PATCH 14/16] =?UTF-8?q?7-1=E5=AE=A1=E6=A0=B8=E7=BB=9F=E8=AE=A1?= =?UTF-8?q?=E6=95=B0=EF=BC=8C=E5=B7=A5=E4=BD=9C=E5=8F=B0=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../example/demo/controller/AuditController.java | 21 ++++- src/main/java/com/example/demo/domain/vo/Gold.java | 1 + .../com/example/demo/domain/vo/RefundAudit.java | 5 +- .../java/com/example/demo/mapper/AuditMapper.java | 2 +- .../com/example/demo/service/AuditService.java | 6 +- .../example/demo/service/StatisticsService.java | 2 +- .../com/example/demo/service/WorkbenchService.java | 3 + .../example/demo/serviceImpl/AuditServiceImpl.java | 103 +++++++++++++++++---- .../demo/serviceImpl/StatisticsServiceImpl.java | 2 +- .../demo/serviceImpl/WorkbenchServiceImpl.java | 77 ++++++++++++++- src/main/resources/mapper/AuditMapper.xml | 6 +- src/main/resources/mapper/StatisticsMapper.xml | 5 +- 12 files changed, 195 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/example/demo/controller/AuditController.java b/src/main/java/com/example/demo/controller/AuditController.java index bec1e92..349df97 100644 --- a/src/main/java/com/example/demo/controller/AuditController.java +++ b/src/main/java/com/example/demo/controller/AuditController.java @@ -1,9 +1,6 @@ package com.example.demo.controller; -import com.example.demo.domain.vo.AuditRequest; -import com.example.demo.domain.vo.Page; -import com.example.demo.domain.vo.RechargeAudit; -import com.example.demo.domain.vo.RefundAudit; +import com.example.demo.domain.vo.*; import com.example.demo.service.AuditService; import com.github.pagehelper.PageInfo; import lombok.RequiredArgsConstructor; @@ -59,4 +56,20 @@ public class AuditController { return auditService.selectRefundBy(pageNum, pageSize, refundAudit); } + //充值审核合计数 + @PostMapping("sumRechargeGold") + public Gold sumRechargeGold(@RequestBody Page page) { + Integer pageNum = page.getPageNum(); + Integer pageSize = page.getPageSize(); + RechargeAudit rechargeAudit = page.getRechargeAudit(); + return auditService.sumRechargeGold(pageNum, pageSize, rechargeAudit); + } + //退款审核合计数 + @PostMapping("sumRefundGold") + public Gold sumRefundGold(@RequestBody Page page) { + Integer pageNum = page.getPageNum(); + Integer pageSize = page.getPageSize(); + RefundAudit refundAudit = page.getRefundAudit(); + return auditService.sumRefundGold(pageNum, pageSize, refundAudit); + } } diff --git a/src/main/java/com/example/demo/domain/vo/Gold.java b/src/main/java/com/example/demo/domain/vo/Gold.java index a38a574..94119e2 100644 --- a/src/main/java/com/example/demo/domain/vo/Gold.java +++ b/src/main/java/com/example/demo/domain/vo/Gold.java @@ -20,6 +20,7 @@ import java.io.Serializable; @AllArgsConstructor public class Gold implements Serializable { private static final long serialVersionUID = 1L; + private Integer totalNum; //总条数 private Integer permanentGolds; // 永久金币总数 private Integer freeGolds; // 免费金币总数 private Integer taskGolds; // 任务金币总数 diff --git a/src/main/java/com/example/demo/domain/vo/RefundAudit.java b/src/main/java/com/example/demo/domain/vo/RefundAudit.java index f7715c8..3c18eb6 100644 --- a/src/main/java/com/example/demo/domain/vo/RefundAudit.java +++ b/src/main/java/com/example/demo/domain/vo/RefundAudit.java @@ -25,16 +25,15 @@ public class RefundAudit { private Integer jwcode; // 精网号 private String orderCode; // 订单号 private String market; // 所属地区 - private Byte refundModel; // 退款方式-全额 部分 + private Integer refundModel; // 退款方式-全额 部分 private String goodsName; // 商品名称 private Integer sumGold; // 退款金额 private Integer permanentGold; // 永久金币 private Integer freeGold; // 免费金币 private Integer freeJune; // 6月免费金币 private Integer freeDecember; // 12月免费金币 + private Integer taskGold; // 任务金币 private String remark; // 备注 - private String payModel; //支付方式 - private String voucher; //支付凭证 private Integer adminId; //提交人Id private String adminName; //提交人姓名 private String auditStatus; //审核状态 diff --git a/src/main/java/com/example/demo/mapper/AuditMapper.java b/src/main/java/com/example/demo/mapper/AuditMapper.java index 1287ccd..23041e2 100644 --- a/src/main/java/com/example/demo/mapper/AuditMapper.java +++ b/src/main/java/com/example/demo/mapper/AuditMapper.java @@ -28,7 +28,7 @@ public interface AuditMapper { //修改用户余额 int updateUserGold(User user); //修改消费订单为以退款 - int updateOrderRefund(String orderCode); + int updateOrderRefund(String orderCode ,Byte isRefund); //多条件查询充值审核订单 List selectRechargeBy(@Param("pageNum") Integer pageNum, @Param("pageSize") Integer pageSize, diff --git a/src/main/java/com/example/demo/service/AuditService.java b/src/main/java/com/example/demo/service/AuditService.java index 36107e2..5324288 100644 --- a/src/main/java/com/example/demo/service/AuditService.java +++ b/src/main/java/com/example/demo/service/AuditService.java @@ -22,6 +22,8 @@ public interface AuditService { PageInfo selectRechargeBy(Integer pageNum, Integer pageSize, RechargeAudit rechargeAudit); //多条件查询退款审核订单 PageInfo selectRefundBy(Integer pageNum, Integer pageSize, RefundAudit refundAudit); - //金币合计数 - Gold sumRechargeGold(); + //充值审核金币合计数 + Gold sumRechargeGold(Integer pageNum, Integer pageSize, RechargeAudit rechargeAudit); + //退款审核金币合计数 + Gold sumRefundGold(Integer pageNum, Integer pageSize,RefundAudit refundAudit); } diff --git a/src/main/java/com/example/demo/service/StatisticsService.java b/src/main/java/com/example/demo/service/StatisticsService.java index 30dcd01..fe06f8e 100644 --- a/src/main/java/com/example/demo/service/StatisticsService.java +++ b/src/main/java/com/example/demo/service/StatisticsService.java @@ -15,7 +15,7 @@ import java.util.Date; public interface StatisticsService { - //12点,18点,23点30分执行定时任务更新当天part2数据 + //1点,12点,18点,23点30分执行定时任务更新当天part1数据 public void runHourlyTaskPart1(); //12点,18点执行定时任务更新当天part2数据 public void runHourlyTaskPart2(); diff --git a/src/main/java/com/example/demo/service/WorkbenchService.java b/src/main/java/com/example/demo/service/WorkbenchService.java index c66e860..0207e5c 100644 --- a/src/main/java/com/example/demo/service/WorkbenchService.java +++ b/src/main/java/com/example/demo/service/WorkbenchService.java @@ -1,5 +1,6 @@ package com.example.demo.service; +import com.example.demo.domain.entity.Statistics; import com.example.demo.domain.vo.WorkbenchCard; import com.example.demo.domain.vo.WorkbenchMarketCard; @@ -19,6 +20,8 @@ import java.util.List; public interface WorkbenchService { //获取不同地区的工作台统计卡片 WorkbenchCard getCard(String token); + //获取卡片数据 + WorkbenchMarketCard createWorkbenchMarketCard(String market, Statistics statistics, Date yearlyStartDate, Date currentDate); //获取不同地区的工作台柱状图数据(根据类型,起止时间,地区查询) WorkbenchCard getGraph(String token, Date startDate, Date endDate, List markets); //根据类型获取年初至今的统计数据 diff --git a/src/main/java/com/example/demo/serviceImpl/AuditServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/AuditServiceImpl.java index 8019806..7ea5776 100644 --- a/src/main/java/com/example/demo/serviceImpl/AuditServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/AuditServiceImpl.java @@ -12,6 +12,7 @@ import com.github.pagehelper.PageInfo; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Date; import java.util.List; /** @@ -44,10 +45,22 @@ public class AuditServiceImpl implements AuditService { if (action==2){ //驳回 updateOrder.setAuditStatus(2); updateOrder.setRejectReason(rejectReason); + updateOrder.setAuditTime(new Date()); auditMapper.updateOrder(updateOrder); - return true; + if (order.getType()==2) { //退款 + //2.获取对应的消费订单(退款订单号去掉开头"TK"即为对应消费订单) + String consumeOrderCode = order.getOrderCode().replaceFirst("TK", ""); + //3.更新消费订单是否已退款状态为0 + UserGoldRecord consumeOrder = auditMapper.selectOrderByOrderCode(consumeOrderCode); + if (consumeOrderCode != null&&consumeOrder.getType()==1){ //确保是消费订单 + auditMapper.updateOrderRefund(consumeOrderCode,(byte)0); + }else { + throw new IllegalArgumentException("找不到对应的订单或不是有效订单"); + } + } }else if (action==1) { //通过 updateOrder.setAuditStatus(1); + updateOrder.setAuditTime(new Date()); } // 执行审核更新 auditMapper.updateOrder(updateOrder); @@ -66,23 +79,16 @@ public class AuditServiceImpl implements AuditService { update.setCurrentTaskGold(order.getTaskGold()); //当前任务金币 auditMapper.updateUserGold(update); }else if (order.getType()==2) { //退款 - //1.更新用户余额,并标记对应的消费订单为已退款 + //更新用户余额 User update = new User(); update.setJwcode(order.getJwcode()); update.setCurrentPermanentGold(order.getPermanentGold()); //当前永久金币 update.setCurrentFreeJune(order.getFreeJune()); //当前六月免费金币 update.setCurrentFreeDecember(order.getFreeDecember()); //当前十二月免费金币 update.setCurrentTaskGold(order.getTaskGold()); //当前任务金币 + auditMapper.updateUserGold(update); - //2.获取对应的消费订单(退款订单号去掉开头"TK"即为对应消费订单) - String consumeOrderCode = order.getOrderCode().replaceFirst("TK", ""); - //3.更新消费订单是否已退款状态为1 - UserGoldRecord consumeOrder = auditMapper.selectOrderByOrderCode(consumeOrderCode); - if (consumeOrderCode != null&&consumeOrder.getType()==1){ //确保是消费订单 - auditMapper.updateOrderRefund(consumeOrderCode); - }else { - throw new IllegalArgumentException("找不到对应的订单或不是有效订单"); - } + } return true; } @@ -94,25 +100,88 @@ public class AuditServiceImpl implements AuditService { PageHelper.startPage(pageNum, pageSize); List rechargeAudits = auditMapper.selectRechargeBy(pageNum, pageSize, rechargeAudit); + // rechargeAudit.setFreeGold(rechargeAudit.getFreeJune()+rechargeAudit.getFreeDecember()); return new PageInfo<>(rechargeAudits); } - + /* + 多条件查询退款订单 + */ @Override public PageInfo selectRefundBy(Integer pageNum, Integer pageSize, RefundAudit refundAudit) { PageHelper.startPage(pageNum, pageSize); List refundAudits = auditMapper.selectRefundBy(pageNum, pageSize, refundAudit); - + //refundAudit.setFreeGold(refundAudit.getFreeJune()+refundAudit.getFreeDecember()); return new PageInfo<>(refundAudits); } /* - 金币合计数 + 充值审核金币合计数 */ @Override - public Gold sumRechargeGold() { + public Gold sumRechargeGold(Integer pageNum, Integer pageSize, RechargeAudit rechargeAudit) { Gold gold = new Gold(); //获取充值审核订单列表 - List rechargeAudits = auditMapper.selectRechargeBy(1, 1000, null); - return null; + List rechargeAudits = auditMapper.selectRechargeBy(1, 500000, rechargeAudit); + // 初始化累加器 + int totalNum=0; + int permanentGoldSum = 0; + int freeGoldSum = 0; +// 遍历消费记录并累加金币 + for (RechargeAudit recharge : rechargeAudits) { + // 累加永久金币 + if (recharge.getPermanentGold() != null) { + permanentGoldSum += recharge.getPermanentGold(); + } + // 累加免费金币 + if (recharge.getFreeJune() != null||recharge.getFreeDecember() != null) { + freeGoldSum = freeGoldSum+recharge.getFreeJune()+recharge.getFreeDecember(); + } + + // 每遍历一条记录,总条数加1 + totalNum++; + } + // 将累加结果设置到Gold对象 + gold.setPermanentGolds(permanentGoldSum); + gold.setFreeGolds(freeGoldSum); + gold.setTotalNum(totalNum); + return gold; + } + + /* + 退款审核合计数 + */ + @Override + public Gold sumRefundGold(Integer pageNum, Integer pageSize, RefundAudit refundAudit) { + Gold gold = new Gold(); + //获取充值审核订单列表 + List refundAudits = auditMapper.selectRefundBy(1, 500000, refundAudit); + // 初始化累加器 + int totalNum=0; + int permanentGoldSum = 0; + int freeGoldSum = 0; + int taskGoldSum = 0; +// 遍历消费记录并累加金币 + for (RefundAudit refund : refundAudits) { + // 累加永久金币 + if (refund.getPermanentGold() != null) { + permanentGoldSum += refund.getPermanentGold(); + } + // 累加免费金币 + if (refund.getFreeJune() != null||refund.getFreeDecember()!=null) { + freeGoldSum += refund.getFreeJune()+refund.getFreeDecember(); + } + //累加任务金币 + if(refund.getTaskGold()!=null) + taskGoldSum+=refund.getTaskGold(); + + // 每遍历一条记录,总条数加1 + totalNum++; + } + // 将累加结果设置到Gold对象 + gold.setPermanentGolds(permanentGoldSum); + gold.setFreeGolds(freeGoldSum); + gold.setTotalNum(totalNum); + gold.setTaskGolds(taskGoldSum); + return gold; } } diff --git a/src/main/java/com/example/demo/serviceImpl/StatisticsServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/StatisticsServiceImpl.java index 8e346db..d93852e 100644 --- a/src/main/java/com/example/demo/serviceImpl/StatisticsServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/StatisticsServiceImpl.java @@ -39,7 +39,7 @@ public class StatisticsServiceImpl implements StatisticsService { 12点,18点,23点30分执行定时任务更新当天part1数据 */ @Override - @Scheduled(cron = "0 0 12,18 * * ?") // 分别在 12:00 和 18:00 执行 + @Scheduled(cron = "0 0 1,12,18 * * ?") // 分别在 1:00 12:00 和 18:00 执行 @Scheduled(cron = "0 30 23 * * ?") // 在 23:30 执行 public void runHourlyTaskPart1() { Date today = new Date(); //取当天日期 diff --git a/src/main/java/com/example/demo/serviceImpl/WorkbenchServiceImpl.java b/src/main/java/com/example/demo/serviceImpl/WorkbenchServiceImpl.java index 9dad75b..35c8833 100644 --- a/src/main/java/com/example/demo/serviceImpl/WorkbenchServiceImpl.java +++ b/src/main/java/com/example/demo/serviceImpl/WorkbenchServiceImpl.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; +import java.util.stream.Collectors; /** * @program: gold-java @@ -52,10 +53,29 @@ public class WorkbenchServiceImpl implements WorkbenchService { LocalDate today = LocalDate.now(); // 获取当前年份的第一天 LocalDate firstDayOfYear = today.withDayOfYear(1); + // 将年份的第一天日期转换为Date类型 Date yearlyStartDate=Date.from(firstDayOfYear.atStartOfDay(ZoneId.systemDefault()).toInstant()); List markets = generalService.getMarket(); - List marketCards = new ArrayList<>(); - // 遍历每个 marketCard 并填充数据 + // 并行处理市场列表,创建市场卡片列表 + List marketCards = markets.parallelStream() + // 过滤掉空或全空格的市场名称 + .filter(market -> market != null && !market.trim().isEmpty()) + .map(market -> { + // 根据市场名称和日期范围查询统计信息 + Statistics statistics = statisticsMapper.selectByMarketAndDate( + market, + Date.from(startOfDay.atZone(ZoneId.systemDefault()).toInstant()), + Date.from(endOfDay.atZone(ZoneId.systemDefault()).toInstant()) + ); + // 创建并返回市场卡片对象 + return createWorkbenchMarketCard(market, statistics, yearlyStartDate, date); + }) + // 收集并行流结果为列表 + .collect(Collectors.toList()); + + return new WorkbenchCard(token, marketCards, markets, date, date); + /* List marketCards = new ArrayList<>(); + // 遍历每个 marketCard 并填充数据 for (String market : markets) { if (market == null || market.trim().isEmpty()) continue; @@ -112,7 +132,58 @@ public class WorkbenchServiceImpl implements WorkbenchService { } } - return new WorkbenchCard(token, marketCards,markets,date,date); + return new WorkbenchCard(token, marketCards,markets,date,date);*/ + } + /* + 获取卡片数据 + */ + @Override + public WorkbenchMarketCard createWorkbenchMarketCard(String market, Statistics statistics, Date yearlyStartDate, Date currentDate) { + Date date=new Date(); + WorkbenchMarketCard card = new WorkbenchMarketCard(); + card.setMarket(market); + if (statistics != null) { + // 卡片一:当前金币相关 + card.setCurrentPermanent(statistics.getCurrentPermanent());//余量-永久金币 + card.setCurrentFreeJune(statistics.getCurrentFreeJune()); //余量-免费六月金币 + card.setCurrentFreeDecember(statistics.getCurrentFreeDecember()); //余量-免费十二月金币 + card.setCurrentTask(statistics.getCurrentTask()); //余量-任务金币 + card.setCurrentFree(card.getCurrentFreeJune() + card.getCurrentFreeDecember()); //余量-免费金币 + card.setCurrentGold(card.getCurrentPermanent() + card.getCurrentFree() + card.getCurrentTask()); //余量-总金币 + card.setDailyChange(statistics.getDailyChange()); //较前一日变化 + // 卡片二:充值相关 + card.setRecharge(statistics.getRecharge()); //充值-当日充值 + card.setMoney(statistics.getMoney()); //充值-当日金额(永久) + card.setYearlyRecharge(calculateSum(market, "recharge",yearlyStartDate ,date));//充值-全年累计充值 + card.setYearlyMoney(calculateSum(market, "money",yearlyStartDate ,date)); //充值-全年累计金额(永久) + // 卡片三:消费与退款 + card.setConsumePermanent(statistics.getConsumePermanent());//消费-永久金币 + card.setConsumeFreeJune(statistics.getConsumeFreeJune());//消费-免费六月金币 + card.setConsumeFreeDecember(statistics.getConsumeFreeDecember());//消费-免费十二月金币 + card.setConsumeTask(statistics.getConsumeTask());//消费-任务金币 + card.setRefundPermanent(statistics.getRefundPermanent());//退款-永久金币 + card.setRefundFreeJune(statistics.getRefundFreeJune());//退款-免费六月金币 + card.setRefundFreeDecember(statistics.getRefundFreeDecember());//退款-免费十二月金币 + card.setRefundTask(statistics.getRefundTask());//退款-任务金币 + //当日总消费 + int totalConsume = card.getConsumePermanent() + card.getConsumeFreeJune() + card.getConsumeFreeDecember() + card.getConsumeTask(); + //当日总退款 + int totalRefund = card.getRefundPermanent() + card.getRefundFreeJune() + card.getRefundFreeDecember() + card.getRefundTask(); + card.setDailyReduce(totalConsume - totalRefund);//当日总消耗 + card.setYearlyConsume(calculateSum(market, "consume", yearlyStartDate,date));//年累计消费 + card.setYearlyRefund(calculateSum(market, "refund",yearlyStartDate ,date));//年累计退款 + card.setYearlyReduce(card.getYearlyConsume() - card.getYearlyRefund());//年累计消耗 + // 卡片四:人头数相关 + card.setRechargeNum(statistics.getRechargeNum()); + card.setFirstRecharge(statistics.getFirstRecharge()); + card.setYearlyRechargeNum(calculateSum(market,"rechargeNum",yearlyStartDate,date)); + + + // 周环比、日同比 + card.setWow(calculateWeekOverWeek(market, currentDate)); + card.setDaily(calculateDayOverDay(market, currentDate)); + } + return card; } @Override diff --git a/src/main/resources/mapper/AuditMapper.xml b/src/main/resources/mapper/AuditMapper.xml index 71dd88c..ff9c12c 100644 --- a/src/main/resources/mapper/AuditMapper.xml +++ b/src/main/resources/mapper/AuditMapper.xml @@ -25,7 +25,7 @@ update user_gold_record - set is_refund = 1 + set is_refund = #{isRefund} where order_code = #{orderCode} @@ -82,10 +82,10 @@ LEFT JOIN admin a2 ON ugr.audit_id = a2.id - + AND ugr.jwcode = #{refundAudit.jwcode} - + AND ugr.refund_model = #{refundAudit.refundModel} diff --git a/src/main/resources/mapper/StatisticsMapper.xml b/src/main/resources/mapper/StatisticsMapper.xml index 700ed65..9ecf964 100644 --- a/src/main/resources/mapper/StatisticsMapper.xml +++ b/src/main/resources/mapper/StatisticsMapper.xml @@ -103,9 +103,8 @@ SELECT * FROM statistics WHERE market = #{market} - AND current_datetime >= #{startDate} - AND current_datetime <= #{endDate} - LIMIT 1 + AND current_datetime BETWEEN #{startDate} AND #{endDate} + + SELECT + *, + CASE + WHEN update_time IS NULL OR create_time > update_time THEN create_time + ELSE update_time + END AS last_time + FROM rate + + + + + + + UPDATE + rate + SET + rate_name=#{rateName}, + num=#{num}, + admin_id=#{adminId}, + update_time=#{updateTime} + WHERE + id=#{id} + + + + + INSERT INTO rate + (rate_name, num, admin_id, create_time) + VALUES + (#{rateName}, #{num}, #{adminId}, #{createTime}) + + SELECT LAST_INSERT_ID() + + + +