This commit is contained in:
2026-01-08 10:49:30 +08:00
parent 21b9acf3c9
commit e5be277941
39 changed files with 1290 additions and 46 deletions

View File

@@ -0,0 +1,75 @@
package com.czg.controller.admin;
import com.czg.EntryManager;
import com.czg.annotation.Debounce;
import com.czg.dto.req.AggregateMerchantDto;
import com.czg.dto.resp.BankBranchDto;
import com.czg.service.order.dto.AggregateMerchantVO;
import com.czg.service.order.service.ShopDirectMerchantService;
import com.czg.resp.CzgResult;
import com.czg.sa.StpKit;
import com.czg.task.EntryManagerTask;
import jakarta.annotation.Resource;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* 进件管理
*
* @author ww
*/
@AllArgsConstructor
@RestController
@RequestMapping("/admin/data/entryManager")
public class EntryManagerController {
@Resource
private ShopDirectMerchantService shopDirectMerchantService;
@Resource
private EntryManagerTask entryManagerTask;
/**
* 查询银行支行列表
*
* @param province 省份 陕西省 从 /system/admin/common/region获取
* @param city 城市 西安市 从 /system/admin/common/region获取
* @param instId 顶级机构ID CMB 从 /system/admin/common/bankInfo 获取
*/
@GetMapping("bankBranchList")
public CzgResult<List<BankBranchDto>> queryBankBranchList(String province, String city, String instId) {
return CzgResult.success(EntryManager.queryBankBranchList(province, city, instId));
}
/**
* 获取进件信息
*/
@GetMapping
public CzgResult<AggregateMerchantVO> getEntry(Long shopId) {
return CzgResult.success(shopDirectMerchantService.getEntry(shopId));
}
/**
* 主动查询进件信息状态
* 进件状态是INIT 待处理 AUDIT 审核中 SIGN 待签约
* 3分钟内只能查一次
*/
@GetMapping
@Debounce(value = "#shopId", interval = 1000 * 60 * 3)
public CzgResult<Boolean> queryEntry(Long shopId) {
entryManagerTask.entryManager(shopId);
return CzgResult.success();
}
/**
* 申请进件
*/
@Debounce(value = "#reqDto.shopId")
@PostMapping
public CzgResult<Boolean> entryManager(@RequestBody AggregateMerchantDto reqDto) {
return CzgResult.success(shopDirectMerchantService.entryManager(reqDto));
}
}

View File

@@ -0,0 +1,124 @@
package com.czg.mq;
import cn.hutool.core.util.StrUtil;
import com.czg.EntryManager;
import com.czg.PayCst;
import com.czg.config.RabbitConstants;
import com.czg.config.RedisCst;
import com.czg.dto.resp.EntryRespDto;
import com.czg.order.entity.ShopDirectMerchant;
import com.czg.service.RedisService;
import com.czg.service.order.dto.AggregateMerchantVO;
import com.czg.service.order.service.ShopDirectMerchantService;
import com.rabbitmq.client.Channel;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.ThreadContext;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.*;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* 打印mq消息处理器
*
* @author Administrator
*/
@Component
@Slf4j
public class EntryManagerMqListener {
@Resource
private RedisService redisService;
@Resource
private ShopDirectMerchantService shopDirectMerchantService;
String key = RedisCst.SHOP_ENTRY;
@RabbitListener(
bindings = @QueueBinding(
value = @Queue(value = "${spring.profiles.active}-" + RabbitConstants.Queue.SHOP_ENTRY_MANAGER,
durable = "true", exclusive = "false", autoDelete = "false"),
exchange = @Exchange(value = "${spring.profiles.active}-" + RabbitConstants.Exchange.CASH_EXCHANGE),
key = "${spring.profiles.active}-" + RabbitConstants.Queue.SHOP_ENTRY_MANAGER
),
concurrency = "5"
)
@RabbitHandler
public void handle(Message message, Channel channel, String msg) throws IOException {
String messageId = message.getMessageProperties().getMessageId();
if (hasMessageId(messageId)) {
return;
}
try {
Long shopId = Long.valueOf(msg);
// 将唯一标识添加到日志上下文
ThreadContext.put("traceId", messageId);
// 安全转换shopId
if (shopId == null) {
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
return;
}
AggregateMerchantVO entry = shopDirectMerchantService.getEntry(Long.valueOf(msg));
if (entry != null) {
EntryManager.uploadParamImage(entry);
List<String> platform = new ArrayList<>();
if (PayCst.EntryStatus.WAIT.equals(entry.getAlipayStatus())) {
platform.add(PayCst.Platform.ALIPAY);
}
if (PayCst.EntryStatus.WAIT.equals(entry.getWechatStatus())) {
platform.add(PayCst.Platform.WECHAT);
}
EntryRespDto resp = EntryManager.entryMerchant(entry, platform.toArray(new String[0]));
ShopDirectMerchant merchant = new ShopDirectMerchant();
merchant.setShopId(entry.getShopId());
merchant.setWechatStatus(resp.getWechatStatus());
merchant.setWechatErrorMsg(resp.getWechatErrorMsg());
merchant.setAlipayStatus(resp.getAlipayStatus());
merchant.setAlipayErrorMsg(resp.getAlipayErrorMsg());
shopDirectMerchantService.updateById(merchant);
}
channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
} catch (Exception e) {
log.error("进件MQ对接业务异常shopId:{}", msg, e);
ShopDirectMerchant merchant = new ShopDirectMerchant();
merchant.setShopId(Long.valueOf(msg));
merchant.setWechatStatus(PayCst.EntryStatus.REJECTED);
merchant.setAlipayStatus(PayCst.EntryStatus.REJECTED);
merchant.setErrorMsg("系统错误,请联系管理员后重试。");
shopDirectMerchantService.updateById(merchant);
channel.basicNack(message.getMessageProperties().getDeliveryTag(), false, false);
} finally {
delMessageId(messageId);
// 清除日志上下文信息
ThreadContext.remove("messageId");
}
}
public boolean hasMessageId(String messageId) {
if (!redisService.hasKey(key)) {
if (StrUtil.isNotBlank(messageId)) {
redisService.leftPush(key, messageId);
return false;
} else {
return true;
}
}
List<Object> list = redisService.lGet(key, 0, -1);
if (!list.contains(messageId)) {
redisService.leftPush(key, messageId);
return false;
}
return true;
}
public void delMessageId(String messageId) {
redisService.lRemove(key, 0, messageId);
}
}

View File

@@ -29,18 +29,14 @@ public class PrintMqListener {
private MqLogService mqLogService;
@Resource
private FunUtil funUtil;
// 注入自定义线程池(建议单独配置,避免使用默认线程池)
@Resource
private ThreadPoolTaskExecutor asyncExecutor;
@Lazy
@Resource
private PrinterHandler printerHandler;
private <T> void invokeFun(String type, String plat, T data, Consumer<T> consumer) {
private <T> void invokeFun(String queue, String type, String plat, T data, Consumer<T> consumer) {
long startTime = DateUtil.date().getTime();
log.info("接收到{}打印消息:{}", type, data);
MqLog mqLog = new MqLog().setQueue(RabbitConstants.Queue.ORDER_MACHINE_PRINT_QUEUE).setMsg(data.toString())
MqLog mqLog = new MqLog().setQueue(queue).setMsg(data.toString())
.setType(type).setPlat(plat).setCreateTime(DateUtil.date().toLocalDateTime());
try {
consumer.accept(data);
@@ -56,7 +52,7 @@ public class PrintMqListener {
@RabbitListener(queues = {"${spring.profiles.active}-" + RabbitConstants.Queue.ORDER_MACHINE_PRINT_QUEUE})
public void orderPrint(String req) {
// 执行核心打印逻辑
invokeFun("orderPrint", "java.order", req, (data) -> {
invokeFun(RabbitConstants.Queue.ORDER_MACHINE_PRINT_QUEUE, "orderPrint", "java.order", req, (data) -> {
JSONObject jsonObject = JSONObject.parseObject(data);
String orderId = jsonObject.getString("orderId");
if (orderId == null) {
@@ -68,33 +64,6 @@ public class PrintMqListener {
return null;
}, RedisCst.getLockKey("orderPrint", orderId));
});
// // 使用异步线程池执行延迟任务,不阻塞当前消费者线程
// CompletableFuture.runAsync(() -> {
// try {
// // 延迟3秒处理
// TimeUnit.SECONDS.sleep(3);
// // 执行核心打印逻辑
// invokeFun("orderPrint", "java.order", req, (data) -> {
// JSONObject jsonObject = JSONObject.parseObject(data);
// String orderId = jsonObject.getString("orderId");
// if (orderId == null) {
// throw new RuntimeException("订单打印失败未传递orderId");
// }
// Boolean printOrder = jsonObject.getBoolean("printOrder");
// funUtil.runFunAndCheckKey(() -> {
// printerHandler.handler(orderId, printOrder != null && !printOrder ? PrinterHandler.PrintTypeEnum.ONE : PrinterHandler.PrintTypeEnum.ONE_AND_ORDER);
// return null;
// }, RedisCst.getLockKey("orderPrint", orderId));
// });
// } catch (InterruptedException e) {
// Thread.currentThread().interrupt();
// // 记录中断日志
// log.warn("打印任务被中断req:{}", req, e);
// } catch (Exception e) {
// // 记录业务异常日志
// log.error("打印任务处理失败req:{}", req, e);
// }
// }, asyncExecutor);
}
/**
@@ -102,14 +71,16 @@ public class PrintMqListener {
*/
@RabbitListener(queues = {"${spring.profiles.active}-" + RabbitConstants.Queue.ORDER_HANDOVER_PRINT_QUEUE})
public void handoverPrint(String id) {
invokeFun("handoverPrint", "java.order", id, (data) -> printerHandler.handler(data, PrinterHandler.PrintTypeEnum.HANDOVER));
invokeFun(RabbitConstants.Queue.ORDER_HANDOVER_PRINT_QUEUE, "handoverPrint", "java.order", id, (data) ->
printerHandler.handler(data, PrinterHandler.PrintTypeEnum.HANDOVER));
}
/**
* 交班打印
* 叫号打印
*/
@RabbitListener(queues = {"${spring.profiles.active}-" + RabbitConstants.Queue.CALL_TABLE_PRINT_QUEUE})
@RabbitListener(queues = {"${spring.profiles.active}-" + RabbitConstants.Queue.CALL_TABLE_QUEUE})
public void callTablePrint(String id) {
invokeFun("handoverPrint", "java.order", id, (data) -> printerHandler.handler(data, PrinterHandler.PrintTypeEnum.CALL));
invokeFun(RabbitConstants.Queue.CALL_TABLE_QUEUE, "callTable", "java.order", id, (data) ->
printerHandler.handler(data, PrinterHandler.PrintTypeEnum.CALL));
}
}

View File

@@ -0,0 +1,87 @@
package com.czg.task;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.czg.EntryManager;
import com.czg.PayCst;
import com.czg.account.entity.ShopInfo;
import com.czg.account.service.ShopInfoService;
import com.czg.dto.resp.QueryStatusResp;
import com.czg.order.entity.ShopDirectMerchant;
import com.czg.order.service.ShopOrderStatisticService;
import com.czg.order.service.ShopProdStatisticService;
import com.czg.order.service.ShopTableOrderStatisticService;
import com.czg.service.RedisService;
import com.czg.service.order.service.ShopDirectMerchantService;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
/**
* 进件查询
*
* @author ww
*/
@Component
@Slf4j
public class EntryManagerTask {
@Resource
private ShopDirectMerchantService shopDirectMerchantService;
@DubboReference
private ShopInfoService shopInfoService;
//每10分钟查一次
@Scheduled(cron = "0 0/10 * * * ? ")
public void run() {
log.info("进件查询,定时任务执行");
long start = System.currentTimeMillis();
entryManager(null);
log.info("进件查询,定时任务执行完毕,耗时:{}ms", start - System.currentTimeMillis());
}
/**
* 查询状态为待处理、待签约、待审核的进件
*/
public void entryManager(Long shopId) {
List<ShopDirectMerchant> list = shopDirectMerchantService.list(QueryWrapper.create()
.eq(ShopDirectMerchant::getShopId, shopId)
.in(ShopDirectMerchant::getWechatStatus, PayCst.EntryStatus.NEED_QUERY_LIST)
.or(ShopDirectMerchant::getAlipayStatus).in(PayCst.EntryStatus.NEED_QUERY_LIST));
if (CollUtil.isEmpty(list)) {
return;
}
for (ShopDirectMerchant shopDirectMerchant : list) {
String wechatMerchantId = "";
String alipayMerchantId = "";
if (PayCst.EntryStatus.NEED_QUERY_LIST.contains(shopDirectMerchant.getWechatStatus())) {
QueryStatusResp wechatStatus = EntryManager.queryWechatEntryStatus(shopDirectMerchant.getMerchantCode());
shopDirectMerchant.setWechatStatus(wechatStatus.getStatus());
shopDirectMerchant.setWechatErrorMsg(wechatStatus.getFailReason());
shopDirectMerchant.setWechatSignUrl(wechatStatus.getSignUrl());
if (PayCst.EntryStatus.FINISH.equals(wechatStatus.getStatus())) {
wechatMerchantId = wechatStatus.getThirdMerchantId();
}
}
if (PayCst.EntryStatus.NEED_QUERY_LIST.contains(shopDirectMerchant.getAlipayStatus())) {
QueryStatusResp alipayStatus = EntryManager.queryAlipayEntryStatus(shopDirectMerchant.getMerchantCode());
shopDirectMerchant.setAlipayStatus(alipayStatus.getStatus());
shopDirectMerchant.setAlipayErrorMsg(alipayStatus.getFailReason());
shopDirectMerchant.setAlipaySignUrl(alipayStatus.getSignUrl());
if (PayCst.EntryStatus.FINISH.equals(alipayStatus.getStatus())) {
alipayMerchantId = alipayStatus.getThirdMerchantId();
}
}
shopDirectMerchantService.updateById(shopDirectMerchant);
if (StrUtil.isNotBlank(wechatMerchantId) || StrUtil.isNotBlank(alipayMerchantId)) {
shopInfoService.editEntry(shopDirectMerchant.getShopId(), wechatMerchantId, alipayMerchantId);
}
}
}
}

View File

@@ -28,6 +28,7 @@ import java.util.List;
/**
* 订单过期处理
* 退款失败 补偿
*
* @author ww
*/

View File

@@ -0,0 +1,61 @@
package com.czg.controller.admin;
import com.czg.BaseQueryParam;
import com.czg.resp.CzgResult;
import com.czg.system.entity.SysBankInfo;
import com.czg.system.entity.SysCategoryInfo;
import com.czg.system.entity.SysRegion;
import com.czg.system.service.SysBankInfoService;
import com.czg.system.service.SysCategoryInfoService;
import com.czg.system.service.SysRegionService;
import com.czg.system.vo.SysCategoryInfoVO;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
import java.util.Map;
/**
* 通用
*
* @author Administrator
*/
@RestController
@RequestMapping("/admin/common")
public class SysCommonController {
@Resource
private SysRegionService sysRegionService;
@Resource
private SysBankInfoService bankInfoService;
@Resource
private SysCategoryInfoService categoryInfoService;
/**
* 获取所有地域
*/
@GetMapping("/region")
public CzgResult<List<SysRegion>> region() {
return CzgResult.success(sysRegionService.regionList());
}
/**
* 获取银行信息
*/
@GetMapping("/bankInfo")
public CzgResult<Page<SysBankInfo>> bankInfo(BaseQueryParam param, @RequestParam String bankName) {
return CzgResult.success(bankInfoService.bankInfoList(param, bankName));
}
/**
* 类目信息表
*/
@GetMapping("/category")
public CzgResult<List<SysCategoryInfoVO>> category() {
return CzgResult.success(categoryInfoService.categoryList());
}
}

View File

@@ -21,12 +21,24 @@ public class RabbitConfig {
@Value("${spring.profiles.active}")
private String activeProfile;
@Bean
@Primary
public DirectExchange directExchange() {
return new DirectExchange(activeProfile + "-" + RabbitConstants.Exchange.CASH_EXCHANGE);
}
//------------------------------------------------------ 商家入驻
@Bean
public Queue entryManagerQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.SHOP_ENTRY_MANAGER, true, false, false);
}
@Bean
public Binding entryManagerExchange(Queue entryManagerQueue, DirectExchange exchange) {
return BindingBuilder.bind(entryManagerQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.SHOP_ENTRY_MANAGER);
}
//------------------------------------------------------订单打印队列
@Bean
public Queue orderPrintQueue() {
@@ -36,6 +48,7 @@ public class RabbitConfig {
args.put("x-message-ttl", 180000);
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_PRINT_QUEUE, true, false, false, args);
}
@Bean
public Binding bindingOrderPrintExchange(Queue orderPrintQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderPrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_PRINT_QUEUE);
@@ -51,6 +64,7 @@ public class RabbitConfig {
// args.put("x-message-ttl", 180000);
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_MACHINE_PRINT_QUEUE, true, false, false);
}
@Bean
public Binding bindingOrderMachinePrintExchange(Queue orderMachinePrintQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderMachinePrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_MACHINE_PRINT_QUEUE);
@@ -61,6 +75,7 @@ public class RabbitConfig {
public Queue handoverPrintQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_HANDOVER_PRINT_QUEUE, true, false, false);
}
@Bean
public Binding bindingHandoverPrintExchange(Queue handoverPrintQueue, DirectExchange exchange) {
return BindingBuilder.bind(handoverPrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_HANDOVER_PRINT_QUEUE);
@@ -69,11 +84,12 @@ public class RabbitConfig {
//------------------------------------------------------叫号 打票
@Bean
public Queue callTablePrintQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.CALL_TABLE_PRINT_QUEUE, true, false, false);
return new Queue(activeProfile + "-" + RabbitConstants.Queue.CALL_TABLE_QUEUE, true, false, false);
}
@Bean
public Binding bindingCallTablePrintExchange(Queue callTablePrintQueue, DirectExchange exchange) {
return BindingBuilder.bind(callTablePrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.CALL_TABLE_PRINT_QUEUE);
return BindingBuilder.bind(callTablePrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.CALL_TABLE_QUEUE);
}
//------------------------------------------------------订单取消
@@ -81,9 +97,10 @@ public class RabbitConfig {
public Queue orderCancelQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_CANCEL_QUEUE, true);
}
@Bean
public Binding bindingOrderCancelExchange(Queue orderPrintQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderPrintQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_CANCEL_QUEUE);
public Binding bindingOrderCancelExchange(Queue orderCancelQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderCancelQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_CANCEL_QUEUE);
}
//------------------------------------------------------ 订单库存更新
@@ -91,6 +108,7 @@ public class RabbitConfig {
public Queue orderStockQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_STOCK_QUEUE, true);
}
@Bean
public Binding bindingOrderStockExchange(Queue orderStockQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderStockQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_STOCK_QUEUE);
@@ -102,6 +120,7 @@ public class RabbitConfig {
public Queue productInfoChangeQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.PRODUCT_INFO_CHANGE_QUEUE, true);
}
@Bean
public Binding bindingProductInfoChange(Queue productInfoChangeQueue, DirectExchange exchange) {
return BindingBuilder.bind(productInfoChangeQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.PRODUCT_INFO_CHANGE_QUEUE);
@@ -112,6 +131,7 @@ public class RabbitConfig {
public Queue orderRefundQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_REFUND_QUEUE, true);
}
@Bean
public Binding bindingOrderRefundExchange(Queue orderRefundQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderRefundQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_REFUND_QUEUE);
@@ -119,6 +139,7 @@ public class RabbitConfig {
//------------------------------------------------------ 申请短信模板队列
/**
* 1,2,applySmsTemp 模版审核
* 1,2,sendMarkSms 发送营销短信
@@ -129,16 +150,18 @@ public class RabbitConfig {
public Queue applySmsTemplateQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.APPLY_SMS_TEMPLATE_QUEUE, true);
}
@Bean
public Binding bindingApplySmsTemplateExchange(Queue applySmsTemplateQueue, DirectExchange exchange) {
return BindingBuilder.bind(applySmsTemplateQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.APPLY_SMS_TEMPLATE_QUEUE);
}
//------------------------------------------------------ 生日礼品短信队列
//------------------------------------------------------ 生日礼品短信队列
@Bean
public Queue birthdayGiftSmsQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.BIRTHDAY_GIFT_SMS_QUEUE, true);
}
@Bean
public Binding bindingBirthdayGiftSmsExchange(Queue birthdayGiftSmsQueue, DirectExchange exchange) {
return BindingBuilder.bind(birthdayGiftSmsQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.BIRTHDAY_GIFT_SMS_QUEUE);
@@ -149,6 +172,7 @@ public class RabbitConfig {
public Queue orderProductStatusQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_PRODUCT_STATUS_QUEUE, true);
}
@Bean
public Binding bindingOrderProductStatusExchange(Queue orderProductStatusQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderProductStatusQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_PRODUCT_STATUS_QUEUE);
@@ -160,6 +184,7 @@ public class RabbitConfig {
public Queue orderDetailStatusQueue() {
return new Queue(activeProfile + "-" + RabbitConstants.Queue.ORDER_DETAIL_STATUS_QUEUE, true);
}
@Bean
public Binding bindingOrderDetailStatusExchange(Queue orderDetailStatusQueue, DirectExchange exchange) {
return BindingBuilder.bind(orderDetailStatusQueue).to(exchange).with(activeProfile + "-" + RabbitConstants.Queue.ORDER_DETAIL_STATUS_QUEUE);

View File

@@ -10,13 +10,14 @@ public interface RabbitConstants {
}
class Queue {
public static final String SHOP_ENTRY_MANAGER = "shop.entry.manager";
public static final String ORDER_STOCK_QUEUE = "order.stock.queue";
public static final String ORDER_REFUND_QUEUE = "order.refund.queue";
public static final String ORDER_CANCEL_QUEUE = "order.cancel.queue";
public static final String ORDER_PRINT_QUEUE = "order.print.queue";
public static final String ORDER_MACHINE_PRINT_QUEUE = "order.machine.print.queue";
public static final String ORDER_HANDOVER_PRINT_QUEUE = "order.handover.print.queue";
public static final String CALL_TABLE_PRINT_QUEUE = "call.table.print.queue";
public static final String CALL_TABLE_QUEUE = "call.table.print.queue";
public static final String PRODUCT_INFO_CHANGE_QUEUE = "product.info.change.queue";
/**

View File

@@ -130,6 +130,13 @@ public class RabbitPublisher {
sendMsg(RabbitConstants.Queue.ORDER_PRODUCT_STATUS_QUEUE, qrContent);
}
/**
* 订单商品状态消息
*/
public void sendEntryManagerMsg(String shopId) {
sendMsg(RabbitConstants.Queue.SHOP_ENTRY_MANAGER, shopId);
}
/**
* 订单商品状态消息

View File

@@ -33,6 +33,8 @@ public interface RedisCst {
public static final String EXPIRED_WECHAT = "expired:wechat:";
}
//商家进件
String SHOP_ENTRY = "shop:entry";
String SMS_CODE = "sms:code:";
// 店铺会员动态支付码

View File

@@ -142,6 +142,14 @@ public class ShopInfo implements Serializable {
* -1 平台禁用 0-过期1正式营业
*/
private Integer status;
/**
* 微信商户id
*/
private String wechatMerchantId;
/**
* 支付宝商户id
*/
private String alipayMerchantId;
/**
* 到期时间

View File

@@ -37,6 +37,11 @@ public interface ShopInfoService extends IService<ShopInfo> {
Boolean edit(ShopInfoEditDTO shopInfoEditDTO);
/**
* 进件结果保存
*/
Boolean editEntry(Long shopId, String wechatMerchantId, String alipayMerchantId);
ShopDetailDTO detail(Long id) throws CzgException;
ShopInfoByCodeDTO getByCode(String tableCode, String lat, String lng, boolean checkState);

View File

@@ -0,0 +1,111 @@
package com.czg.order.entity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 商户进件 实体类。
*
* @author ww
* @since 2026-01-07
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("tb_shop_direct_merchant")
public class ShopDirectMerchant implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 店铺id
*/
@Id
private Long shopId;
/**
* 营业执照编号
*/
private String licenceNo;
/**
* 商户编号(在当前系统唯一)
*/
private String merchantCode;
/**
* 商户基础信息
*/
private String merchantBaseInfo;
/**
* 法人信息
*/
private String legalPersonInfo;
/**
* 营业执照信息
*/
private String businessLicenceInfo;
/**
* 门店信息
*/
private String storeInfo;
/**
* 结算信息
*/
private String settlementInfo;
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
@Column(onInsertValue = "now()", onUpdateValue = "now()")
private LocalDateTime updateTime;
private String errorMsg;
/**
* 微信状态
*/
private String wechatStatus;
/**
* 微信进件错误信息
*/
private String wechatErrorMsg;
/**
* 微信进件签名地址
*/
private String wechatSignUrl;
/**
* 支付宝状态
*/
private String alipayStatus;
/**
* 支付宝进件错误信息
*/
private String alipayErrorMsg;
/**
* 支付宝进件签名地址
*/
private String alipaySignUrl;
}

View File

@@ -0,0 +1,82 @@
package com.czg.system.entity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 银行账户信息表 实体类。
*
* @author ww
* @since 2026-01-06
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("sys_bank_info")
public class SysBankInfo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@Id(keyType = KeyType.Auto)
private BigInteger id;
/**
* 银行名称
*/
private String accountBank;
/**
* 银行数字编码
*/
private Integer accountBankCode;
/**
* 银行别名
*/
private String bankAlias;
/**
* 银行别名编码
*/
private String bankAliasCode;
/**
* 不知道干啥的
*/
private Boolean needBankBranch;
/**
* 银行英文编码
*/
private String bankCode;
/**
* 创建时间
*/
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
/**
* 更新时间
*/
@Column(onInsertValue = "now()", onUpdateValue = "now()")
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,77 @@
package com.czg.system.entity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.io.Serial;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 类目信息表 实体类。
*
* @author ww
* @since 2026-01-06
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("sys_category_info")
public class SysCategoryInfo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键ID
*/
@Id(keyType = KeyType.Auto)
private BigInteger id;
/**
* 一级类目
*/
private String firstCategory;
/**
* 二级类目code
*/
private String secondCategoryCode;
/**
* 二级类目
*/
private String secondCategory;
/**
* 适用商家说明
*/
private String applicableMerchant;
/**
* 特殊资质(为空则无需提供)
*/
private String specialQualification;
/**
* 创建时间
*/
@Column(onInsertValue = "now()")
private LocalDateTime createTime;
/**
* 更新时间
*/
@Column(onInsertValue = "now()", onUpdateValue = "now()")
private LocalDateTime updateTime;
}

View File

@@ -0,0 +1,70 @@
package com.czg.system.entity;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.Table;
import java.io.Serializable;
import java.io.Serial;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 行政区表 实体类。
*
* @author ww
* @since 2026-01-06
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table("sys_region")
public class SysRegion implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 区域编码
*/
@Id
private String regionId;
/**
* 上级区域编码
*/
private String parentRegionId;
/**
* 区域级别1=国家2=省3=市4=县
*/
@Id
private Integer regionLevel;
/**
* 区域中文全称
*/
private String regionName;
/**
* 区域拼音
*/
private String regionPinyin;
/**
* 全级别名称(如“中国|北京|北京市|东城区)
*/
private String fullName;
/**
* 子级区域
*/
@Column(ignore = true)
private List<SysRegion> children;
}

View File

@@ -0,0 +1,19 @@
package com.czg.system.service;
import com.czg.BaseQueryParam;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.service.IService;
import com.czg.system.entity.SysBankInfo;
import java.util.List;
/**
* 银行账户信息表 服务层。
*
* @author ww
* @since 2026-01-06
*/
public interface SysBankInfoService extends IService<SysBankInfo> {
Page<SysBankInfo> bankInfoList(BaseQueryParam param, String bankName);
}

View File

@@ -0,0 +1,20 @@
package com.czg.system.service;
import com.czg.system.vo.SysCategoryInfoVO;
import com.mybatisflex.core.service.IService;
import com.czg.system.entity.SysCategoryInfo;
import java.util.List;
import java.util.Map;
/**
* 类目信息表 服务层。
*
* @author ww
* @since 2026-01-06
*/
public interface SysCategoryInfoService extends IService<SysCategoryInfo> {
List<SysCategoryInfoVO> categoryList();
}

View File

@@ -0,0 +1,17 @@
package com.czg.system.service;
import com.mybatisflex.core.service.IService;
import com.czg.system.entity.SysRegion;
import java.util.List;
/**
* 行政区表 服务层。
*
* @author ww
* @since 2026-01-06
*/
public interface SysRegionService extends IService<SysRegion> {
List<SysRegion> regionList();
}

View File

@@ -0,0 +1,40 @@
package com.czg.system.vo;
import com.czg.system.entity.SysCategoryInfo;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.Id;
import com.mybatisflex.annotation.KeyType;
import com.mybatisflex.annotation.Table;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.List;
/**
* 类目信息表 实体类。
*
* @author ww
* @since 2026-01-06
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class SysCategoryInfoVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 一级类目
*/
private String firstCategory;
private List<SysCategoryInfo> child;
}

View File

@@ -1,7 +1,10 @@
package com.czg;
import java.util.List;
/**
* 支付相关常量
*
* @author yjjie
* @date 2026/1/7 09:20
*/
@@ -34,7 +37,6 @@ public interface PayCst {
* 待处理
*/
public static final String INIT = "INIT";
/**
* 审核中
*/
@@ -54,6 +56,13 @@ public interface PayCst {
* 失败
*/
public static final String REJECTED = "REJECTED";
/**
* 需要查询的状态列表
* 待处理、待签约、待审核的进件
*/
public static final List<String> NEED_QUERY_LIST = List.of(INIT, AUDIT, SIGN);
}
/**

View File

@@ -10,9 +10,14 @@ import lombok.Data;
*/
@Data
public class AggregateMerchantDto {
/**
* 商户Id
*/
private Long shopId;
/**
* 【必填】
* 自己生成 CZGyyyy-MM-dd HH:mm:ss.SSS
* 商户编号(在当前系统唯一)
*/
private String merchantCode;

View File

@@ -16,7 +16,7 @@ public class MerchantBaseInfoDto {
* 商户类型
* 0: 个体商户;
* 1: 企业商户;
* 3: 小微商户
* 3: 小微商户 暂不支持
*/
private String userType;

View File

@@ -324,6 +324,15 @@ public class ShopInfoServiceImpl extends ServiceImpl<ShopInfoMapper, ShopInfo> i
return false;
}
@Override
@CacheEvict(key = "#shopId")
public Boolean editEntry(Long shopId, String wechatMerchantId, String alipayMerchantId) {
ShopInfo shopInfo = new ShopInfo();
shopInfo.setWechatMerchantId(wechatMerchantId);
shopInfo.setAlipayMerchantId(alipayMerchantId);
return update(shopInfo, new QueryWrapper().eq(ShopInfo::getId, shopId));
}
@Override
public ShopDetailDTO detail(Long id) throws CzgException {
ShopInfo shopInfo = queryChain().eq(ShopInfo::getId, id == null ? StpKit.USER.getShopId() : id).one();

View File

@@ -0,0 +1,52 @@
package com.czg.service.order.dto;
import com.czg.dto.req.*;
import lombok.Data;
import java.time.LocalDateTime;
/**
* @author ww
*/
@Data
public class AggregateMerchantVO extends AggregateMerchantDto{
private LocalDateTime createTime;
private LocalDateTime updateTime;
private String errorMsg;
/**
* {@link com.czg.PayCst.EntryStatus}
* 微信状态
* WAIT 待提交 INIT 待处理 AUDIT 审核中 SIGN 待签约 REJECTED 失败 FINISH 已完成
*/
private String wechatStatus;
/**
* 微信进件错误信息
*/
private String wechatErrorMsg;
/**
* 微信进件签名地址
*/
private String wechatSignUrl;
/**
* {@link com.czg.PayCst.EntryStatus}
* 支付宝状态
* WAIT 待提交 INIT 待处理 AUDIT 审核中 SIGN 待签约 REJECTED 失败 FINISH 已完成
*/
private String alipayStatus;
/**
* 支付宝进件错误信息
*/
private String alipayErrorMsg;
/**
* 支付宝进件签名地址
*/
private String alipaySignUrl;
}

View File

@@ -0,0 +1,14 @@
package com.czg.service.order.mapper;
import com.mybatisflex.core.BaseMapper;
import com.czg.order.entity.ShopDirectMerchant;
/**
* 商户进件 映射层。
*
* @author ww
* @since 2026-01-07
*/
public interface ShopDirectMerchantMapper extends BaseMapper<ShopDirectMerchant> {
}

View File

@@ -0,0 +1,19 @@
package com.czg.service.order.service;
import com.czg.dto.req.AggregateMerchantDto;
import com.czg.service.order.dto.AggregateMerchantVO;
import com.mybatisflex.core.service.IService;
import com.czg.order.entity.ShopDirectMerchant;
/**
* 商户进件 服务层。
*
* @author ww
* @since 2026-01-07
*/
public interface ShopDirectMerchantService extends IService<ShopDirectMerchant> {
AggregateMerchantVO getEntry(Long shopId);
boolean entryManager(AggregateMerchantDto reqDto);
}

View File

@@ -0,0 +1,133 @@
package com.czg.service.order.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.io.unit.DataSizeUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
import com.czg.EntryManager;
import com.czg.PayCst;
import com.czg.config.RabbitPublisher;
import com.czg.dto.req.*;
import com.czg.service.order.dto.AggregateMerchantVO;
import com.czg.utils.FunUtils;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.czg.order.entity.ShopDirectMerchant;
import com.czg.service.order.service.ShopDirectMerchantService;
import com.czg.service.order.mapper.ShopDirectMerchantMapper;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import java.util.Date;
import java.util.concurrent.atomic.AtomicLong;
/**
* 商户进件 服务层实现。
*
* @author ww
* @since 2026-01-07
*/
@Service
public class ShopDirectMerchantServiceImpl extends ServiceImpl<ShopDirectMerchantMapper, ShopDirectMerchant> implements ShopDirectMerchantService {
@Resource
private RabbitPublisher rabbitPublisher;
// 全局原子计数器,按天重置(避免数值过大)
private static final AtomicLong COUNTER = new AtomicLong(0);
// 记录上一次的日期,用于重置计数器
private static String LAST_DATE = DateUtil.format(new Date(), "yyyyMMdd");
@Override
public AggregateMerchantVO getEntry(Long shopId) {
ShopDirectMerchant merchant = getById(shopId);
if (merchant == null) {
return null;
}
return convertVO(merchant);
}
@Override
public boolean entryManager(AggregateMerchantDto reqDto) {
boolean isSave = false;
boolean result;
if (StrUtil.isBlank(reqDto.getMerchantCode())) {
reqDto.setMerchantCode(getMerchantCode());
isSave = true;
}
EntryManager.verifyEntryParam(reqDto);
ShopDirectMerchant merchant = new ShopDirectMerchant();
merchant.setShopId(reqDto.getShopId());
merchant.setMerchantCode(reqDto.getMerchantCode());
merchant.setLicenceNo(reqDto.getBusinessLicenceInfo().getLicenceNo());
merchant.setMerchantBaseInfo(JSONObject.toJSONString(reqDto.getMerchantBaseInfo()));
merchant.setLegalPersonInfo(JSONObject.toJSONString(reqDto.getLegalPersonInfo()));
merchant.setBusinessLicenceInfo(JSONObject.toJSONString(reqDto.getBusinessLicenceInfo()));
merchant.setStoreInfo(JSONObject.toJSONString(reqDto.getStoreInfo()));
merchant.setSettlementInfo(JSONObject.toJSONString(reqDto.getSettlementInfo()));
merchant.setWechatStatus(PayCst.EntryStatus.WAIT);
merchant.setAlipayStatus(PayCst.EntryStatus.WAIT);
if (isSave) {
result = save(merchant);
} else {
result = updateById(merchant);
}
//发送进件队列消息
FunUtils.transactionSafeRun(() -> rabbitPublisher.sendEntryManagerMsg(reqDto.getShopId().toString()));
return result;
}
private static String getMerchantCode() {
Date now = new Date();
// 1. 获取当前日期yyyyMMdd
String currentDate = DateUtil.format(now, "yyyyMMdd");
// 2. 每天重置计数器,避免数值溢出
synchronized (COUNTER) {
if (!currentDate.equals(LAST_DATE)) {
COUNTER.set(0);
LAST_DATE = currentDate;
}
}
// 3. 原子递增,获取唯一序号(同一毫秒内不会重复)
long seq = COUNTER.incrementAndGet();
// 4. 时间戳(毫秒级)+ 6位序号补零
String timeStr = DateUtil.format(now, "yyyyMMddHHmmss");
String seqStr = String.format("%03d", seq);
return "CZG" + timeStr + seqStr;
}
public AggregateMerchantVO convertVO(ShopDirectMerchant entity) {
if (entity == null) {
return null;
}
AggregateMerchantVO vo = new AggregateMerchantVO();
vo.setShopId(entity.getShopId());
vo.setMerchantCode(entity.getMerchantCode());
// 解析JSON字段
vo.setMerchantBaseInfo(JSONObject.parseObject(entity.getMerchantBaseInfo(), MerchantBaseInfoDto.class));
vo.setLegalPersonInfo(JSONObject.parseObject(entity.getLegalPersonInfo(), LegalPersonInfoDto.class));
vo.setBusinessLicenceInfo(JSONObject.parseObject(entity.getBusinessLicenceInfo(), BusinessLicenceInfoDto.class));
vo.setStoreInfo(JSONObject.parseObject(entity.getStoreInfo(), StoreInfoDto.class));
vo.setSettlementInfo(JSONObject.parseObject(entity.getSettlementInfo(), SettlementInfoDto.class));
// 设置其他字段
vo.setCreateTime(entity.getCreateTime());
vo.setUpdateTime(entity.getUpdateTime());
vo.setWechatStatus(entity.getWechatStatus());
vo.setWechatErrorMsg(entity.getWechatErrorMsg());
vo.setWechatSignUrl(entity.getWechatSignUrl());
vo.setAlipayStatus(entity.getAlipayStatus());
vo.setAlipayErrorMsg(entity.getAlipayErrorMsg());
vo.setAlipaySignUrl(entity.getAlipaySignUrl());
return vo;
}
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.czg.service.order.mapper.ShopDirectMerchantMapper">
</mapper>

View File

@@ -26,6 +26,11 @@
<artifactId>czg-pay</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.czg</groupId>
<artifactId>aggregation-pay</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,14 @@
package com.czg.service.system.mapper;
import com.mybatisflex.core.BaseMapper;
import com.czg.system.entity.SysBankInfo;
/**
* 银行账户信息表 映射层。
*
* @author ww
* @since 2026-01-06
*/
public interface SysBankInfoMapper extends BaseMapper<SysBankInfo> {
}

View File

@@ -0,0 +1,14 @@
package com.czg.service.system.mapper;
import com.mybatisflex.core.BaseMapper;
import com.czg.system.entity.SysCategoryInfo;
/**
* 类目信息表 映射层。
*
* @author ww
* @since 2026-01-06
*/
public interface SysCategoryInfoMapper extends BaseMapper<SysCategoryInfo> {
}

View File

@@ -0,0 +1,14 @@
package com.czg.service.system.mapper;
import com.mybatisflex.core.BaseMapper;
import com.czg.system.entity.SysRegion;
/**
* 行政区表 映射层。
*
* @author ww
* @since 2026-01-06
*/
public interface SysRegionMapper extends BaseMapper<SysRegion> {
}

View File

@@ -0,0 +1,26 @@
package com.czg.service.system.service.impl;
import com.czg.BaseQueryParam;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.czg.system.entity.SysBankInfo;
import com.czg.system.service.SysBankInfoService;
import com.czg.service.system.mapper.SysBankInfoMapper;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* 银行账户信息表 服务层实现。
*
* @author ww
* @since 2026-01-06
*/
@Service
public class SysBankInfoServiceImpl extends ServiceImpl<SysBankInfoMapper, SysBankInfo> implements SysBankInfoService {
@Override
public Page<SysBankInfo> bankInfoList(BaseQueryParam param, String bankName) {
return page(Page.of(param.getPage(), param.getSize()), query().like(SysBankInfo::getBankAlias, bankName));
}
}

View File

@@ -0,0 +1,43 @@
package com.czg.service.system.service.impl;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.collection.CollUtil;
import com.czg.system.vo.SysCategoryInfoVO;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import com.czg.system.entity.SysCategoryInfo;
import com.czg.system.service.SysCategoryInfoService;
import com.czg.service.system.mapper.SysCategoryInfoMapper;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 类目信息表 服务层实现。
*
* @author ww
* @since 2026-01-06
*/
@Service
public class SysCategoryInfoServiceImpl extends ServiceImpl<SysCategoryInfoMapper, SysCategoryInfo> implements SysCategoryInfoService {
@Cacheable(value = "common:category", key = "'all'")
@Override
public List<SysCategoryInfoVO> categoryList() {
List<SysCategoryInfo> list = list();
if (CollUtil.isEmpty(list)) {
return List.of();
}
List<SysCategoryInfoVO> result = new ArrayList<>();
Map<String, List<SysCategoryInfo>> stringListMap = CollStreamUtil.groupByKey(list, SysCategoryInfo::getFirstCategory);
stringListMap.forEach((k, v) -> {
SysCategoryInfoVO vo = new SysCategoryInfoVO();
vo.setFirstCategory(k);
vo.setChild(v);
result.add(vo);
});
return result;
}
}

View File

@@ -0,0 +1,56 @@
package com.czg.service.system.service.impl;
import com.czg.service.system.mapper.SysRegionMapper;
import com.czg.system.entity.SysRegion;
import com.czg.system.service.SysRegionService;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 行政区表 服务层实现。
*
* @author ww
* @since 2026-01-06
*/
@Service
public class SysRegionServiceImpl extends ServiceImpl<SysRegionMapper, SysRegion> implements SysRegionService {
@Cacheable(value = "common:region", key = "'all'")
@Override
public List<SysRegion> regionList() {
// 1. 单次查询获取所有数据
List<SysRegion> allRegions = list(query().ne(SysRegion::getRegionLevel, 1));
// 2. 一次性按层级分组,减少流遍历次数
Map<Integer, List<SysRegion>> regionByLevel = allRegions.stream()
.collect(Collectors.groupingBy(SysRegion::getRegionLevel));
// 3. 获取各层级数据,默认空列表避免空指针
List<SysRegion> parents = regionByLevel.getOrDefault(2, List.of());
List<SysRegion> level3Regions = regionByLevel.getOrDefault(3, List.of());
List<SysRegion> level4Regions = regionByLevel.getOrDefault(4, List.of());
// 4. 构建3级地区的子节点映射4级使用HashMap保证性能
Map<String, List<SysRegion>> level4ByParentId = level4Regions.stream()
.collect(Collectors.groupingBy(SysRegion::getParentRegionId, Collectors.toList()));
level3Regions.forEach(level3 -> {
List<SysRegion> children = level4ByParentId.getOrDefault(level3.getRegionId(), List.of());
level3.setChildren(children);
});
Map<String, List<SysRegion>> level3ByParentId = level3Regions.stream()
.collect(Collectors.groupingBy(SysRegion::getParentRegionId));
parents.forEach(parent -> {
List<SysRegion> children = level3ByParentId.getOrDefault(parent.getRegionId(), List.of());
parent.setChildren(children);
});
return parents;
}
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.czg.service.system.mapper.SysBankInfoMapper">
</mapper>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.czg.service.system.mapper.SysCategoryInfoMapper">
</mapper>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.czg.service.system.mapper.SysRegionMapper">
</mapper>