diff --git a/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/job/QywxMessageJob.java b/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/job/QywxMessageJob.java index df6432b..ae37557 100644 --- a/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/job/QywxMessageJob.java +++ b/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/job/QywxMessageJob.java @@ -110,19 +110,12 @@ public class QywxMessageJob { return; } - // 5. 筛选createTime超过一周的记录 - Date oneWeekAgo = DateUtil.offsetDay(new Date(), -7); - List overdueRecords = unReturnOrderGoods.stream() - .filter(record -> record.getCreateTime().before(oneWeekAgo)) - .collect(Collectors.toList()); - - if (CollectionUtils.isEmpty(overdueRecords)) { - log.info("企业[{}]没有超过一周未归还的商品记录", authCorpInfo.getCorpid()); - return; - } - - // 6. 遍历逾期记录发送消息 - for (ShopOrderGoodsEntity record : overdueRecords) { + // 5. 筛选逾期记录 + List overdueRecords = new ArrayList<>(); + for (ShopOrderGoodsEntity record : unReturnOrderGoods) { + // 获取逾期天数 + int overdueDays = 7; // 默认一周 + if (record.getCellId() != null) { CabinetCellEntity cell = cabinetCellService.getById(record.getCellId()); if (cell == null) { @@ -136,12 +129,36 @@ public class QywxMessageJob { continue; } + // 检查是否为购买订单,如果是则跳过 if (record.getMode().equals(0) && cabinet.getMode().equals(0) && cabinet.getReturnDeadline() != null && cabinet.getReturnDeadline() > 0) { log.info("订单[{}]为购买订单,无需发送逾期提醒", record.getOrderId()); continue; } + + // 根据智能柜的归还期限设置逾期天数 + if (cabinet.getReturnDeadline() != null && cabinet.getReturnDeadline() > 0) { + overdueDays = cabinet.getReturnDeadline(); + } } + + // 计算逾期截止日期 + Date deadlineDate = DateUtil.offsetDay(record.getCreateTime(), overdueDays); + Date now = new Date(); + + // 如果当前时间晚于逾期截止日期,则商品已逾期 + if (now.after(deadlineDate)) { + overdueRecords.add(record); + } + } + + if (CollectionUtils.isEmpty(overdueRecords)) { + log.info("企业[{}]没有逾期未归还的商品记录", authCorpInfo.getCorpid()); + return; + } + + // 6. 遍历逾期记录发送消息 + for (ShopOrderGoodsEntity record : overdueRecords) { sendSingleReminder(accessToken.getAccessToken(), authCorpInfo, record); } } catch (Exception e) { diff --git a/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/LoginService.java b/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/LoginService.java index 6b87c88..534ed98 100644 --- a/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/LoginService.java +++ b/agileboot-admin/src/main/java/com/agileboot/admin/customize/service/login/LoginService.java @@ -262,6 +262,16 @@ public class LoginService { } private String getQyUserid(String corpid, String code) { + // 构建缓存键 + String cacheKey = corpid + ":" + code; + + // 先从缓存获取 + String cachedUserid = caffeineCache.qyUseridCache.get(cacheKey); + if (cachedUserid != null) { + log.debug("从缓存获取企业微信用户ID,corpid: {}, code: {}, userid: {}", corpid, code, cachedUserid); + return cachedUserid; + } + try { QyAuthCorpInfoEntity authCorpInfo = authCorpInfoApplicationService.selectByCorpid(corpid); if (authCorpInfo == null) { @@ -281,7 +291,13 @@ public class LoginService { throw new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, "无效的code参数"); } - return String.valueOf(result.get("userid")); + String userid = String.valueOf(result.get("userid")); + + // 将结果存入缓存 + caffeineCache.qyUseridCache.put(cacheKey, userid); + log.debug("缓存企业微信用户ID,corpid: {}, code: {}, userid: {}", corpid, code, userid); + + return userid; } catch (RestClientException e) { log.error("获取openid失败", e); throw new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, "微信服务调用失败"); diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/CabinetTemplateEnum.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/CabinetTemplateEnum.java index a26d835..c11aa8e 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/CabinetTemplateEnum.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/CabinetTemplateEnum.java @@ -24,7 +24,7 @@ public enum CabinetTemplateEnum { /** 4口机柜模板,1块主板,每块主板4个单元格 */ CABINET_4(9, "cabinet_4.jpg","4口机柜", 1, 4), /** 10口机柜模板,1块主板,每块主板10个单元格 */ - CABINET_10(1, "cabinet_16.jpg", "10口机柜", 1, 10); + CABINET_10(10, "cabinet_16.jpg", "10口机柜", 1, 10); /** 模板代码 */ private final int code; diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/SmartCabinetApplicationService.java b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/SmartCabinetApplicationService.java index 793b4b3..b324454 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/SmartCabinetApplicationService.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/cabinet/smartCabinet/SmartCabinetApplicationService.java @@ -8,6 +8,8 @@ import com.agileboot.domain.cabinet.cell.db.CabinetCellService; import com.agileboot.domain.cabinet.cell.model.CabinetCellModel; import com.agileboot.domain.cabinet.cell.model.CabinetCellModelFactory; import com.agileboot.domain.cabinet.mainboard.command.AddCabinetMainboardCommand; +import com.agileboot.domain.cabinet.mainboard.db.CabinetMainboardEntity; +import com.agileboot.domain.cabinet.mainboard.db.CabinetMainboardService; import com.agileboot.domain.cabinet.mainboard.model.CabinetMainboardModel; import com.agileboot.domain.cabinet.mainboard.model.CabinetMainboardModelFactory; import com.agileboot.domain.cabinet.smartCabinet.db.SmartCabinetDO; @@ -43,6 +45,7 @@ public class SmartCabinetApplicationService { private final SmartCabinetService smartCabinetService; private final SmartCabinetModelFactory smartCabinetModelFactory; private final CabinetCellService cabinetCellService; + private final CabinetMainboardService cabinetMainboardService; private final ShopGoodsService shopGoodsService; private final ShopService shopService; private final CabinetMainboardModelFactory cabinetMainboardModelFactory; @@ -138,6 +141,17 @@ public class SmartCabinetApplicationService { public void deleteSmartCabinet(BulkOperationCommand command) { for (Long cabinetId : command.getIds()) { + // 先删除相关的 cabinet_cell 数据 + QueryWrapper cellWrapper = new QueryWrapper<>(); + cellWrapper.eq("cabinet_id", cabinetId); + cabinetCellService.remove(cellWrapper); + + // 再删除相关的 cabinet_mainboard 数据 + QueryWrapper mainboardWrapper = new QueryWrapper<>(); + mainboardWrapper.eq("cabinet_id", cabinetId); + cabinetMainboardService.remove(mainboardWrapper); + + // 最后删除智能柜本身 SmartCabinetModel model = smartCabinetModelFactory.loadById(cabinetId); model.deleteById(); } diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/CacheCenter.java b/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/CacheCenter.java index dcee774..5537654 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/CacheCenter.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/CacheCenter.java @@ -34,6 +34,8 @@ public class CacheCenter { public static AbstractCaffeineCacheTemplate postCache; + public static AbstractCaffeineCacheTemplate qyUseridCache; + @PostConstruct public void init() { GuavaCacheService guavaCache = SpringUtil.getBean(GuavaCacheService.class); @@ -47,6 +49,7 @@ public class CacheCenter { userCache = caffeineCache.userCache; roleCache = caffeineCache.roleCache; postCache = caffeineCache.postCache; + qyUseridCache = caffeineCache.qyUseridCache; } } diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/CaffeineCacheService.java b/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/CaffeineCacheService.java index 38ba78d..4d118cd 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/CaffeineCacheService.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/common/cache/CaffeineCacheService.java @@ -61,6 +61,14 @@ public class CaffeineCacheService { } }; + public AbstractCaffeineCacheTemplate qyUseridCache = new AbstractCaffeineCacheTemplate() { + @Override + public String getObjectFromDb(Object id) { + // 企业微信用户ID需要通过API获取,这里返回null,由调用方处理 + return null; + } + }; + /** * 获取缓存统计信息 * @return 统计信息字符串 @@ -73,6 +81,7 @@ public class CaffeineCacheService { stats.append("User Cache: ").append(userCache.getStats()).append("\n"); stats.append("Role Cache: ").append(roleCache.getStats()).append("\n"); stats.append("Post Cache: ").append(postCache.getStats()).append("\n"); + stats.append("QyUserid Cache: ").append(qyUseridCache.getStats()).append("\n"); return stats.toString(); } } \ No newline at end of file diff --git a/agileboot-domain/src/main/java/com/agileboot/domain/shop/shop/ShopApplicationService.java b/agileboot-domain/src/main/java/com/agileboot/domain/shop/shop/ShopApplicationService.java index dc0aa9f..51d82a1 100644 --- a/agileboot-domain/src/main/java/com/agileboot/domain/shop/shop/ShopApplicationService.java +++ b/agileboot-domain/src/main/java/com/agileboot/domain/shop/shop/ShopApplicationService.java @@ -32,7 +32,9 @@ public class ShopApplicationService { private final CabinetCellService cabinetCellService; public PageDTO getShopPage(SearchShopQuery query) { - Page page = shopService.getShopList(query.toPage(), query.toQueryWrapper()); + QueryWrapper queryWrapper = query.toQueryWrapper(); + queryWrapper.eq("s.deleted", false); + Page page = shopService.getShopList(query.toPage(), queryWrapper); List dtoList = page.getRecords().stream() .map(ShopDTO::new) .collect(Collectors.toList()); @@ -40,7 +42,10 @@ public class ShopApplicationService { } public List getShopList(SearchShopQuery query) { - List list = shopService.list(); + // 1. 先查询所有商店 + QueryWrapper queryWrapper = new QueryWrapper<>(); + queryWrapper.eq("deleted", false); + List list = shopService.list(queryWrapper); return list.stream() .map(ShopDTO::new) .collect(Collectors.toList()); diff --git a/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/cache/caffeine/AbstractCaffeineCacheTemplate.java b/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/cache/caffeine/AbstractCaffeineCacheTemplate.java index 94435d6..7d4730f 100644 --- a/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/cache/caffeine/AbstractCaffeineCacheTemplate.java +++ b/agileboot-infrastructure/src/main/java/com/agileboot/infrastructure/cache/caffeine/AbstractCaffeineCacheTemplate.java @@ -27,9 +27,9 @@ public abstract class AbstractCaffeineCacheTemplate { // 设置软引用值 .softValues() // 设置过期时间 - 最后一次写入后经过固定时间过期 - .expireAfterWrite(10, TimeUnit.MINUTES) + .expireAfterWrite(10, TimeUnit.HOURS) // 设置刷新时间 - 写入后经过固定时间刷新 - .refreshAfterWrite(5, TimeUnit.MINUTES) + .refreshAfterWrite(10, TimeUnit.HOURS) // 所有segment的初始总容量大小 .initialCapacity(128) // 开启缓存统计 diff --git a/doc/sql/cabinet.sql b/doc/sql/cabinet.sql new file mode 100644 index 0000000..f4e1453 --- /dev/null +++ b/doc/sql/cabinet.sql @@ -0,0 +1,72 @@ +-- `agileboot-pure`.smart_cabinet definition + +CREATE TABLE `smart_cabinet` ( + `cabinet_id` bigint NOT NULL AUTO_INCREMENT COMMENT '柜机唯一ID', + `cabinet_name` varchar(100) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '柜机名称', + `cabinet_type` tinyint NOT NULL DEFAULT '0' COMMENT '柜机类型(0主柜 1副柜)', + `main_cabinet` bigint DEFAULT NULL COMMENT '归属主柜ID', + `balance_enable` tinyint NOT NULL DEFAULT '1' COMMENT '借呗支付(1-正常使用 0-禁止使用)', + `mode` tinyint NOT NULL DEFAULT '0' COMMENT '运行模式(0-支付模式 1-审批模式 2-借还模式 3-会员模式)', + `belong_type` tinyint NOT NULL DEFAULT '0' COMMENT '归属类型(0-借还柜 1-固资通)', + `shop_id` bigint DEFAULT NULL COMMENT '归属商店ID', + `mqtt_server_id` bigint DEFAULT NULL COMMENT 'MQTT服务ID', + `template_no` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL COMMENT '柜机模版编号', + `lock_control_no` int NOT NULL COMMENT '锁控板序号', + `location` int NOT NULL COMMENT '柜机位置', + `creator_id` bigint NOT NULL DEFAULT '0' COMMENT '创建者ID', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` bigint NOT NULL DEFAULT '0' COMMENT '更新者ID', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标志(0存在 1删除)', + `return_deadline` int NOT NULL DEFAULT '0' COMMENT '归还期限(天),0表示不限制', + PRIMARY KEY (`cabinet_id`), + KEY `idx_template_no` (`template_no`), + KEY `idx_location` (`location`) +) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='智能柜信息表'; + + +-- `agileboot-pure`.cabinet_mainboard definition + +CREATE TABLE `cabinet_mainboard` ( + `mainboard_id` bigint NOT NULL AUTO_INCREMENT COMMENT '主板唯一ID', + `cabinet_id` bigint NOT NULL COMMENT '关联柜机ID', + `lock_control_no` int NOT NULL COMMENT '锁控板序号', + `creator_id` bigint DEFAULT '0' COMMENT '创建者ID', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` bigint DEFAULT '0' COMMENT '更新者ID', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标志(0存在 1删除)', + PRIMARY KEY (`mainboard_id`), + KEY `idx_cabinet` (`cabinet_id`), + CONSTRAINT `fk_mainboard_cabinet` FOREIGN KEY (`cabinet_id`) REFERENCES `smart_cabinet` (`cabinet_id`) +) ENGINE=InnoDB AUTO_INCREMENT=32 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='机柜主板信息表'; + + +-- `agileboot-pure`.cabinet_cell definition + +CREATE TABLE `cabinet_cell` ( + `cell_id` bigint NOT NULL AUTO_INCREMENT COMMENT '格口唯一ID', + `cabinet_id` bigint NOT NULL COMMENT '关联柜机ID', + `mainboard_id` bigint DEFAULT NULL COMMENT '归属主板ID', + `goods_id` bigint DEFAULT NULL COMMENT '关联商品ID', + `cell_no` int NOT NULL COMMENT '格口号', + `pin_no` int NOT NULL COMMENT '针脚序号', + `stock` int NOT NULL DEFAULT '0' COMMENT '库存数量', + `cell_price` decimal(15,2) NOT NULL DEFAULT '0.00' COMMENT '格口租用价格', + `is_rented` tinyint(1) NOT NULL DEFAULT '0' COMMENT '是否已租用:0-未租用,1-已租用', + `cell_type` tinyint NOT NULL DEFAULT '1' COMMENT '格口类型(1小格 2中格 3大格 4超大格)', + `usage_status` tinyint NOT NULL DEFAULT '1' COMMENT '使用状态(1空闲 2已占用)', + `available_status` tinyint NOT NULL DEFAULT '1' COMMENT '可用状态(1正常 2故障)', + `creator_id` bigint NOT NULL DEFAULT '0' COMMENT '创建者ID', + `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间', + `updater_id` bigint NOT NULL DEFAULT '0' COMMENT '更新者ID', + `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间', + `deleted` tinyint(1) NOT NULL DEFAULT '0' COMMENT '删除标志(0存在 1删除)', + PRIMARY KEY (`cell_id`), + KEY `idx_cabinet` (`cabinet_id`), + KEY `idx_usage_status` (`usage_status`), + KEY `idx_available_status` (`available_status`), + KEY `idx_goods` (`goods_id`), + CONSTRAINT `fk_cell_cabinet` FOREIGN KEY (`cabinet_id`) REFERENCES `smart_cabinet` (`cabinet_id`), + CONSTRAINT `fk_cell_goods` FOREIGN KEY (`goods_id`) REFERENCES `shop_goods` (`goods_id`) +) ENGINE=InnoDB AUTO_INCREMENT=712 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='柜机格口信息表'; \ No newline at end of file