feat: 添加企业微信用户ID缓存功能

- 新增qyUseridCache用于缓存企业微信用户ID
- 调整缓存过期时间为10小时
- 在登录服务中添加缓存逻辑
- 修复机柜模板枚举值错误
- 完善智能柜删除逻辑,同时删除关联数据
- 优化逾期商品检测逻辑,支持自定义逾期天数
- 添加智能柜相关SQL表结构文档
This commit is contained in:
dzq 2025-10-09 17:08:41 +08:00
parent 8c29745228
commit ddc3c914b7
9 changed files with 155 additions and 19 deletions

View File

@ -110,19 +110,12 @@ public class QywxMessageJob {
return;
}
// 5. 筛选createTime超过一周的记录
Date oneWeekAgo = DateUtil.offsetDay(new Date(), -7);
List<ShopOrderGoodsEntity> 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<ShopOrderGoodsEntity> 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) {

View File

@ -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("从缓存获取企业微信用户IDcorpid: {}, 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("缓存企业微信用户IDcorpid: {}, code: {}, userid: {}", corpid, code, userid);
return userid;
} catch (RestClientException e) {
log.error("获取openid失败", e);
throw new ApiException(ErrorCode.Client.COMMON_REQUEST_PARAMETERS_INVALID, "微信服务调用失败");

View File

@ -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;

View File

@ -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<Long> command) {
for (Long cabinetId : command.getIds()) {
// 先删除相关的 cabinet_cell 数据
QueryWrapper<CabinetCellEntity> cellWrapper = new QueryWrapper<>();
cellWrapper.eq("cabinet_id", cabinetId);
cabinetCellService.remove(cellWrapper);
// 再删除相关的 cabinet_mainboard 数据
QueryWrapper<CabinetMainboardEntity> mainboardWrapper = new QueryWrapper<>();
mainboardWrapper.eq("cabinet_id", cabinetId);
cabinetMainboardService.remove(mainboardWrapper);
// 最后删除智能柜本身
SmartCabinetModel model = smartCabinetModelFactory.loadById(cabinetId);
model.deleteById();
}

View File

@ -34,6 +34,8 @@ public class CacheCenter {
public static AbstractCaffeineCacheTemplate<SysPostEntity> postCache;
public static AbstractCaffeineCacheTemplate<String> 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;
}
}

View File

@ -61,6 +61,14 @@ public class CaffeineCacheService {
}
};
public AbstractCaffeineCacheTemplate<String> qyUseridCache = new AbstractCaffeineCacheTemplate<String>() {
@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();
}
}

View File

@ -32,7 +32,9 @@ public class ShopApplicationService {
private final CabinetCellService cabinetCellService;
public PageDTO<ShopDTO> getShopPage(SearchShopQuery<ShopEntity> query) {
Page<ShopEntity> page = shopService.getShopList(query.toPage(), query.toQueryWrapper());
QueryWrapper<ShopEntity> queryWrapper = query.toQueryWrapper();
queryWrapper.eq("s.deleted", false);
Page<ShopEntity> page = shopService.getShopList(query.toPage(), queryWrapper);
List<ShopDTO> dtoList = page.getRecords().stream()
.map(ShopDTO::new)
.collect(Collectors.toList());
@ -40,7 +42,10 @@ public class ShopApplicationService {
}
public List<ShopDTO> getShopList(SearchShopQuery<ShopEntity> query) {
List<ShopEntity> list = shopService.list();
// 1. 先查询所有商店
QueryWrapper<ShopEntity> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("deleted", false);
List<ShopEntity> list = shopService.list(queryWrapper);
return list.stream()
.map(ShopDTO::new)
.collect(Collectors.toList());

View File

@ -27,9 +27,9 @@ public abstract class AbstractCaffeineCacheTemplate<T> {
// 设置软引用值
.softValues()
// 设置过期时间 - 最后一次写入后经过固定时间过期
.expireAfterWrite(10, TimeUnit.MINUTES)
.expireAfterWrite(10, TimeUnit.HOURS)
// 设置刷新时间 - 写入后经过固定时间刷新
.refreshAfterWrite(5, TimeUnit.MINUTES)
.refreshAfterWrite(10, TimeUnit.HOURS)
// 所有segment的初始总容量大小
.initialCapacity(128)
// 开启缓存统计

72
doc/sql/cabinet.sql Normal file
View File

@ -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='柜机格口信息表';