# Conflicts:
#	yudao-framework/yudao-spring-boot-starter-web/src/main/java/cn/iocoder/yudao/framework/apilog/core/interceptor/ApiAccessLogInterceptor.java
#	yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/service/brokerage/BrokerageUserService.java
#	yudao-module-report/yudao-module-report-biz/src/main/java/cn/iocoder/yudao/module/report/framework/security/config/SecurityConfiguration.java
This commit is contained in:
YunaiV 2024-07-24 18:46:33 +08:00
commit 257acba31e
29 changed files with 330 additions and 828 deletions

File diff suppressed because one or more lines are too long

View File

@ -39,4 +39,11 @@ public class TenantProperties {
*/ */
private Set<String> ignoreTables = Collections.emptySet(); private Set<String> ignoreTables = Collections.emptySet();
/**
* 需要忽略多租户的 Spring Cache 缓存
*
* 即默认所有缓存都开启多租户的功能所以记得添加对应的 tenant_id 字段哟
*/
private Set<String> ignoreCaches = Collections.emptySet();
} }

View File

@ -120,13 +120,14 @@ public class YudaoTenantAutoConfiguration {
@Primary // 引入租户时tenantRedisCacheManager 为主 Bean @Primary // 引入租户时tenantRedisCacheManager 为主 Bean
public RedisCacheManager tenantRedisCacheManager(RedisTemplate<String, Object> redisTemplate, public RedisCacheManager tenantRedisCacheManager(RedisTemplate<String, Object> redisTemplate,
RedisCacheConfiguration redisCacheConfiguration, RedisCacheConfiguration redisCacheConfiguration,
YudaoCacheProperties yudaoCacheProperties) { YudaoCacheProperties yudaoCacheProperties,
TenantProperties tenantProperties) {
// 创建 RedisCacheWriter 对象 // 创建 RedisCacheWriter 对象
RedisConnectionFactory connectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory()); RedisConnectionFactory connectionFactory = Objects.requireNonNull(redisTemplate.getConnectionFactory());
RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory, RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory,
BatchStrategies.scan(yudaoCacheProperties.getRedisScanBatchSize())); BatchStrategies.scan(yudaoCacheProperties.getRedisScanBatchSize()));
// 创建 TenantRedisCacheManager 对象 // 创建 TenantRedisCacheManager 对象
return new TenantRedisCacheManager(cacheWriter, redisCacheConfiguration); return new TenantRedisCacheManager(cacheWriter, redisCacheConfiguration, tenantProperties.getIgnoreCaches());
} }
} }

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.framework.tenant.core.redis; package cn.iocoder.yudao.framework.tenant.core.redis;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.redis.core.TimeoutRedisCacheManager; import cn.iocoder.yudao.framework.redis.core.TimeoutRedisCacheManager;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder; import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -8,6 +9,8 @@ import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter; import org.springframework.data.redis.cache.RedisCacheWriter;
import java.util.Set;
/** /**
* 多租户的 {@link RedisCacheManager} 实现类 * 多租户的 {@link RedisCacheManager} 实现类
* *
@ -18,16 +21,21 @@ import org.springframework.data.redis.cache.RedisCacheWriter;
@Slf4j @Slf4j
public class TenantRedisCacheManager extends TimeoutRedisCacheManager { public class TenantRedisCacheManager extends TimeoutRedisCacheManager {
private final Set<String> ignoreCaches;
public TenantRedisCacheManager(RedisCacheWriter cacheWriter, public TenantRedisCacheManager(RedisCacheWriter cacheWriter,
RedisCacheConfiguration defaultCacheConfiguration) { RedisCacheConfiguration defaultCacheConfiguration,
Set<String> ignoreCaches) {
super(cacheWriter, defaultCacheConfiguration); super(cacheWriter, defaultCacheConfiguration);
this.ignoreCaches = ignoreCaches;
} }
@Override @Override
public Cache getCache(String name) { public Cache getCache(String name) {
// 如果开启多租户 name 拼接租户后缀 // 如果开启多租户 name 拼接租户后缀
if (!TenantContextHolder.isIgnore() if (!TenantContextHolder.isIgnore()
&& TenantContextHolder.getTenantId() != null) { && TenantContextHolder.getTenantId() != null
&& !CollUtil.contains(ignoreCaches, name)) {
name = name + ":" + TenantContextHolder.getTenantId(); name = name + ":" + TenantContextHolder.getTenantId();
} }

View File

@ -56,7 +56,7 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> {
default <D> PageResult<D> selectJoinPage(PageParam pageParam, Class<D> clazz, MPJLambdaWrapper<T> lambdaWrapper) { default <D> PageResult<D> selectJoinPage(PageParam pageParam, Class<D> clazz, MPJLambdaWrapper<T> lambdaWrapper) {
// 特殊不分页直接查询全部 // 特殊不分页直接查询全部
if (PageParam.PAGE_SIZE_NONE.equals(pageParam.getPageNo())) { if (PageParam.PAGE_SIZE_NONE.equals(pageParam.getPageSize())) {
List<D> list = selectJoinList(clazz, lambdaWrapper); List<D> list = selectJoinList(clazz, lambdaWrapper);
return new PageResult<>(list, (long) list.size()); return new PageResult<>(list, (long) list.size());
} }

View File

@ -27,7 +27,11 @@ public class SecurityFrameworkServiceImpl implements SecurityFrameworkService {
@Override @Override
public boolean hasAnyPermissions(String... permissions) { public boolean hasAnyPermissions(String... permissions) {
return permissionApi.hasAnyPermissions(getLoginUserId(), permissions); Long userId = getLoginUserId();
if (userId == null) {
return false;
}
return permissionApi.hasAnyPermissions(userId, permissions);
} }
@Override @Override
@ -37,7 +41,11 @@ public class SecurityFrameworkServiceImpl implements SecurityFrameworkService {
@Override @Override
public boolean hasAnyRoles(String... roles) { public boolean hasAnyRoles(String... roles) {
return permissionApi.hasAnyRoles(getLoginUserId(), roles); Long userId = getLoginUserId();
if (userId == null) {
return false;
}
return permissionApi.hasAnyRoles(userId, roles);
} }
@Override @Override

View File

@ -1,17 +1,23 @@
package cn.iocoder.yudao.framework.apilog.core.interceptor; package cn.iocoder.yudao.framework.apilog.core.interceptor;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.common.util.spring.SpringUtils; import cn.iocoder.yudao.framework.common.util.spring.SpringUtils;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StopWatch; import org.springframework.util.StopWatch;
import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest; import java.lang.reflect.Method;
import javax.servlet.http.HttpServletResponse; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Optional;
import java.util.stream.IntStream;
/** /**
* API 访问日志 Interceptor * API 访问日志 Interceptor
@ -49,6 +55,8 @@ public class ApiAccessLogInterceptor implements HandlerInterceptor {
StopWatch stopWatch = new StopWatch(); StopWatch stopWatch = new StopWatch();
stopWatch.start(); stopWatch.start();
request.setAttribute(ATTRIBUTE_STOP_WATCH, stopWatch); request.setAttribute(ATTRIBUTE_STOP_WATCH, stopWatch);
// 打印 Controller 路径
printHandlerMethodPosition(handlerMethod);
} }
return true; return true;
} }
@ -64,4 +72,32 @@ public class ApiAccessLogInterceptor implements HandlerInterceptor {
} }
} }
/**
* 打印 Controller 方法路径
*/
private void printHandlerMethodPosition(HandlerMethod handlerMethod) {
if (handlerMethod == null) {
return;
}
Method method = handlerMethod.getMethod();
Class<?> clazz = method.getDeclaringClass();
try {
// 获取 method lineNumber
List<String> clazzContents = FileUtil.readUtf8Lines(
ResourceUtil.getResource(null, clazz).getPath().replace("/target/classes/", "/src/main/java/")
+ clazz.getSimpleName() + ".java");
Optional<Integer> lineNumber = IntStream.range(0, clazzContents.size())
.filter(i -> clazzContents.get(i).contains(" " + method.getName() + "(")) // 简单匹配不考虑方法重名
.mapToObj(i -> i + 1) // 行号从 1 开始
.findFirst();
if (lineNumber.isEmpty()) {
return;
}
// 打印结果
System.out.printf("\tController 方法路径:%s(%s.java:%d)\n", clazz.getName(), clazz.getSimpleName(), lineNumber.get());
} catch (Exception ignore) {
// 忽略异常原因仅仅打印非重要逻辑
}
}
} }

View File

@ -33,7 +33,7 @@ public enum BpmProcessInstanceStatusEnum implements IntArrayValuable {
@Override @Override
public int[] array() { public int[] array() {
return new int[0]; return ARRAYS;
} }
} }

View File

@ -112,7 +112,7 @@ public class AppProductSpuController {
productBrowseHistoryService.createBrowseHistory(getLoginUserId(), id); productBrowseHistoryService.createBrowseHistory(getLoginUserId(), id);
// 拼接返回 // 拼接返回
spu.setBrowseCount(spu.getBrowseCount() + spu.getVirtualSalesCount()); spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount());
AppProductSpuDetailRespVO spuVO = BeanUtils.toBean(spu, AppProductSpuDetailRespVO.class) AppProductSpuDetailRespVO spuVO = BeanUtils.toBean(spu, AppProductSpuDetailRespVO.class)
.setSkus(BeanUtils.toBean(skus, AppProductSpuDetailRespVO.Sku.class)); .setSkus(BeanUtils.toBean(skus, AppProductSpuDetailRespVO.Sku.class));
// 处理 vip 价格 // 处理 vip 价格

View File

@ -26,7 +26,7 @@ public interface ProductSkuMapper extends BaseMapperX<ProductSkuDO> {
} }
/** /**
* 更新 SKU 库存增加 * 更新 SKU 库存增加销量减少
* *
* @param id 编号 * @param id 编号
* @param incrCount 增加库存正数 * @param incrCount 增加库存正数
@ -34,13 +34,14 @@ public interface ProductSkuMapper extends BaseMapperX<ProductSkuDO> {
default void updateStockIncr(Long id, Integer incrCount) { default void updateStockIncr(Long id, Integer incrCount) {
Assert.isTrue(incrCount > 0); Assert.isTrue(incrCount > 0);
LambdaUpdateWrapper<ProductSkuDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<ProductSkuDO>() LambdaUpdateWrapper<ProductSkuDO> lambdaUpdateWrapper = new LambdaUpdateWrapper<ProductSkuDO>()
.setSql(" stock = stock + " + incrCount) .setSql(" stock = stock + " + incrCount
+ ", sales_count = sales_count - " + incrCount)
.eq(ProductSkuDO::getId, id); .eq(ProductSkuDO::getId, id);
update(null, lambdaUpdateWrapper); update(null, lambdaUpdateWrapper);
} }
/** /**
* 更新 SKU 库存减少 * 更新 SKU 库存减少销量增加
* *
* @param id 编号 * @param id 编号
* @param incrCount 减少库存负数 * @param incrCount 减少库存负数
@ -48,10 +49,12 @@ public interface ProductSkuMapper extends BaseMapperX<ProductSkuDO> {
*/ */
default int updateStockDecr(Long id, Integer incrCount) { default int updateStockDecr(Long id, Integer incrCount) {
Assert.isTrue(incrCount < 0); Assert.isTrue(incrCount < 0);
incrCount = - incrCount; // 取正
LambdaUpdateWrapper<ProductSkuDO> updateWrapper = new LambdaUpdateWrapper<ProductSkuDO>() LambdaUpdateWrapper<ProductSkuDO> updateWrapper = new LambdaUpdateWrapper<ProductSkuDO>()
.setSql(" stock = stock + " + incrCount) // 负数所以使用 + .setSql(" stock = stock - " + incrCount
+ ", sales_count = sales_count + " + incrCount)
.eq(ProductSkuDO::getId, id) .eq(ProductSkuDO::getId, id)
.ge(ProductSkuDO::getStock, -incrCount); // cas 逻辑 .ge(ProductSkuDO::getStock, incrCount);
return update(null, updateWrapper); return update(null, updateWrapper);
} }

View File

@ -85,9 +85,19 @@ public interface ProductSpuMapper extends BaseMapperX<ProductSpuDO> {
* @param incrCount 增加的库存数量 * @param incrCount 增加的库存数量
*/ */
default void updateStock(Long id, Integer incrCount) { default void updateStock(Long id, Integer incrCount) {
// 拼接 SQL
if (incrCount == 0) {
return;
}
String sql;
if (incrCount > 0) {
sql = " stock = stock + " + incrCount + ", sales_count = sales_count - " + incrCount;
} else {
sql = " stock = stock - " + Math.abs(incrCount) + ", sales_count = sales_count + " + Math.abs(incrCount);
}
// 执行更新
LambdaUpdateWrapper<ProductSpuDO> updateWrapper = new LambdaUpdateWrapper<ProductSpuDO>() LambdaUpdateWrapper<ProductSpuDO> updateWrapper = new LambdaUpdateWrapper<ProductSpuDO>()
// 负数所以使用 + .setSql(sql)
.setSql(" stock = stock +" + incrCount)
.eq(ProductSpuDO::getId, id); .eq(ProductSpuDO::getId, id);
update(null, updateWrapper); update(null, updateWrapper);
} }

View File

@ -6,7 +6,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi; import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO; import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.*; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.*;
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert; import cn.iocoder.yudao.module.promotion.convert.seckill.SeckillActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService; import cn.iocoder.yudao.module.promotion.service.seckill.SeckillActivityService;

View File

@ -4,7 +4,7 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.*; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.*;
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert; import cn.iocoder.yudao.module.promotion.convert.seckill.SeckillConfigConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO;
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService; import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;

View File

@ -12,7 +12,7 @@ import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppS
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO; import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO; import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO;
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert; import cn.iocoder.yudao.module.promotion.convert.seckill.SeckillActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;

View File

@ -3,7 +3,7 @@ package cn.iocoder.yudao.module.promotion.controller.app.seckill;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO; import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.config.AppSeckillConfigRespVO;
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert; import cn.iocoder.yudao.module.promotion.convert.seckill.SeckillConfigConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO;
import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService; import cn.iocoder.yudao.module.promotion.service.seckill.SeckillConfigService;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;

View File

@ -68,10 +68,11 @@ public interface CombinationActivityConvert {
List<ProductSpuRespDTO> spuList) { List<ProductSpuRespDTO> spuList) {
PageResult<CombinationActivityPageItemRespVO> pageResult = convertPage(page); PageResult<CombinationActivityPageItemRespVO> pageResult = convertPage(page);
Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId); Map<Long, ProductSpuRespDTO> spuMap = convertMap(spuList, ProductSpuRespDTO::getId);
Map<Long, List<CombinationProductDO>> productMap = convertMultiMap(productList, CombinationProductDO::getActivityId);
pageResult.getList().forEach(item -> { pageResult.getList().forEach(item -> {
MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()) MapUtils.findAndThen(spuMap, item.getSpuId(), spu -> item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl())
.setMarketPrice(spu.getMarketPrice())); .setMarketPrice(spu.getMarketPrice()));
item.setProducts(convertList2(productList)); item.setProducts(convertList2(productMap.get(item.getId())));
// 设置统计字段 // 设置统计字段
item.setGroupCount(groupCountMap.getOrDefault(item.getId(), 0)) item.setGroupCount(groupCountMap.getOrDefault(item.getId(), 0))
.setGroupSuccessCount(groupSuccessCountMap.getOrDefault(item.getId(), 0)) .setGroupSuccessCount(groupSuccessCountMap.getOrDefault(item.getId(), 0))

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity; package cn.iocoder.yudao.module.promotion.convert.seckill;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
@ -14,7 +14,6 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.Sec
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO; import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityDetailRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO; import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityNowRespVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO; import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityRespVO;
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;
@ -56,10 +55,11 @@ public interface SeckillActivityConvert {
PageResult<SeckillActivityRespVO> pageResult = convertPage(page); PageResult<SeckillActivityRespVO> pageResult = convertPage(page);
// 拼接商品 // 拼接商品
Map<Long, ProductSpuRespDTO> spuMap = CollectionUtils.convertMap(spuList, ProductSpuRespDTO::getId); Map<Long, ProductSpuRespDTO> spuMap = CollectionUtils.convertMap(spuList, ProductSpuRespDTO::getId);
pageResult.getList().forEach(item -> { Map<Long, List<SeckillProductDO>> productMap = convertMultiMap(seckillProducts, SeckillProductDO::getActivityId);
item.setProducts(convertList2(seckillProducts)); pageResult.getList().forEach(activity -> {
MapUtils.findAndThen(spuMap, item.getSpuId(), activity.setProducts(convertList2(productMap.get(activity.getId())));
spu -> item.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice())); MapUtils.findAndThen(spuMap, activity.getSpuId(),
spu -> activity.setSpuName(spu.getName()).setPicUrl(spu.getPicUrl()).setMarketPrice(spu.getMarketPrice()));
}); });
return pageResult; return pageResult;
} }

View File

@ -1,4 +1,4 @@
package cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig; package cn.iocoder.yudao.module.promotion.convert.seckill;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO;

View File

@ -17,7 +17,7 @@ import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.Se
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.activity.SeckillActivityUpdateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.product.SeckillProductBaseVO;
import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO; import cn.iocoder.yudao.module.promotion.controller.app.seckill.vo.activity.AppSeckillActivityPageReqVO;
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillactivity.SeckillActivityConvert; import cn.iocoder.yudao.module.promotion.convert.seckill.SeckillActivityConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillActivityDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillProductDO;

View File

@ -8,7 +8,7 @@ import cn.iocoder.yudao.framework.common.util.date.LocalDateTimeUtils;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigCreateReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigPageReqVO;
import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO; import cn.iocoder.yudao.module.promotion.controller.admin.seckill.vo.config.SeckillConfigUpdateReqVO;
import cn.iocoder.yudao.module.promotion.convert.seckill.seckillconfig.SeckillConfigConvert; import cn.iocoder.yudao.module.promotion.convert.seckill.SeckillConfigConvert;
import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO; import cn.iocoder.yudao.module.promotion.dal.dataobject.seckill.SeckillConfigDO;
import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig.SeckillConfigMapper; import cn.iocoder.yudao.module.promotion.dal.mysql.seckill.seckillconfig.SeckillConfigMapper;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;

View File

@ -50,10 +50,9 @@ public interface BrokerageRecordMapper extends BaseMapperX<BrokerageRecordDO> {
.eq(BrokerageRecordDO::getStatus, status)); .eq(BrokerageRecordDO::getStatus, status));
} }
default BrokerageRecordDO selectByBizTypeAndBizIdAndUserId(Integer bizType, String bizId, Long userId) { default List<BrokerageRecordDO> selectListByBizTypeAndBizId(Integer bizType, String bizId) {
return selectOne(BrokerageRecordDO::getBizType, bizType, return selectList(BrokerageRecordDO::getBizType, bizType,
BrokerageRecordDO::getBizId, bizId, BrokerageRecordDO::getBizId, bizId);
BrokerageRecordDO::getUserId, userId);
} }
default List<UserBrokerageSummaryRespBO> selectCountAndSumPriceByUserIdInAndBizTypeAndStatus(Collection<Long> userIds, default List<UserBrokerageSummaryRespBO> selectCountAndSumPriceByUserIdInAndBizTypeAndStatus(Collection<Long> userIds,

View File

@ -78,11 +78,10 @@ public interface BrokerageRecordService {
/** /**
* 取消佣金将佣金记录状态修改为已失效 * 取消佣金将佣金记录状态修改为已失效
* *
* @param userId 会员编号
* @param bizType 业务类型 * @param bizType 业务类型
* @param bizId 业务编号 * @param bizId 业务编号
*/ */
void cancelBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId); void cancelBrokerage(BrokerageRecordBizTypeEnum bizType, String bizId);
/** /**
* 解冻佣金将待结算的佣金记录状态修改为已结算 * 解冻佣金将待结算的佣金记录状态修改为已结算

View File

@ -107,27 +107,29 @@ public class BrokerageRecordServiceImpl implements BrokerageRecordService {
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void cancelBrokerage(Long userId, BrokerageRecordBizTypeEnum bizType, String bizId) { public void cancelBrokerage(BrokerageRecordBizTypeEnum bizType, String bizId) {
BrokerageRecordDO record = brokerageRecordMapper.selectByBizTypeAndBizIdAndUserId(bizType.getType(), bizId, userId); List<BrokerageRecordDO> records = brokerageRecordMapper.selectListByBizTypeAndBizId(bizType.getType(), bizId);
if (record == null) { if (CollUtil.isEmpty(records)) {
log.error("[cancelBrokerage][userId({})][bizId({}) 更新为已失效失败:记录不存在]", userId, bizId); log.error("[cancelBrokerage][bizId({}) bizType({}) 更新为已失效失败:记录不存在]", bizId, bizType);
return; return;
} }
// 1. 更新佣金记录为已失效 records.forEach(record -> {
BrokerageRecordDO updateObj = new BrokerageRecordDO().setStatus(BrokerageRecordStatusEnum.CANCEL.getStatus()); // 1. 更新佣金记录为已失效
int updateRows = brokerageRecordMapper.updateByIdAndStatus(record.getId(), record.getStatus(), updateObj); BrokerageRecordDO updateObj = new BrokerageRecordDO().setStatus(BrokerageRecordStatusEnum.CANCEL.getStatus());
if (updateRows == 0) { int updateRows = brokerageRecordMapper.updateByIdAndStatus(record.getId(), record.getStatus(), updateObj);
log.error("[cancelBrokerage][record({}) 更新为已失效失败]", record.getId()); if (updateRows == 0) {
return; log.error("[cancelBrokerage][record({}) 更新为已失效失败]", record.getId());
} return;
}
// 2. 更新用户的佣金 // 2. 更新用户的佣金
if (BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus().equals(record.getStatus())) { if (BrokerageRecordStatusEnum.WAIT_SETTLEMENT.getStatus().equals(record.getStatus())) {
brokerageUserService.updateUserFrozenPrice(userId, -record.getPrice()); brokerageUserService.updateUserFrozenPrice(record.getUserId(), -record.getPrice());
} else if (BrokerageRecordStatusEnum.SETTLEMENT.getStatus().equals(record.getStatus())) { } else if (BrokerageRecordStatusEnum.SETTLEMENT.getStatus().equals(record.getStatus())) {
brokerageUserService.updateUserPrice(userId, -record.getPrice()); brokerageUserService.updateUserPrice(record.getUserId(), -record.getPrice());
} }
});
} }
/** /**

View File

@ -7,10 +7,7 @@ import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokera
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankByUserCountRespVO; import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankByUserCountRespVO;
import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankPageReqVO; import cn.iocoder.yudao.module.trade.controller.app.brokerage.vo.user.AppBrokerageUserRankPageReqVO;
import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO; import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO;
import jakarta.validation.constraints.NotNull;
import javax.validation.constraints.NotNull;
import java.util.Collection;
import java.util.List;
/** /**
* 分销用户 Service 接口 * 分销用户 Service 接口
@ -27,14 +24,6 @@ public interface BrokerageUserService {
*/ */
BrokerageUserDO getBrokerageUser(Long id); BrokerageUserDO getBrokerageUser(Long id);
/**
* 获得分销用户列表
*
* @param ids 编号
* @return 分销用户列表
*/
List<BrokerageUserDO> getBrokerageUserList(Collection<Long> ids);
/** /**
* 获得分销用户分页 * 获得分销用户分页
* *

View File

@ -60,11 +60,6 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
return brokerageUserMapper.selectById(id); return brokerageUserMapper.selectById(id);
} }
@Override
public List<BrokerageUserDO> getBrokerageUserList(Collection<Long> ids) {
return brokerageUserMapper.selectBatchIds(ids);
}
@Override @Override
public PageResult<BrokerageUserDO> getBrokerageUserPage(BrokerageUserPageReqVO pageReqVO) { public PageResult<BrokerageUserDO> getBrokerageUserPage(BrokerageUserPageReqVO pageReqVO) {
List<Long> childIds = getChildUserIdsByLevel(pageReqVO.getBindUserId(), pageReqVO.getLevel()); List<Long> childIds = getChildUserIdsByLevel(pageReqVO.getBindUserId(), pageReqVO.getLevel());
@ -130,6 +125,7 @@ public class BrokerageUserServiceImpl implements BrokerageUserService {
@Override @Override
public BrokerageUserDO getOrCreateBrokerageUser(Long id) { public BrokerageUserDO getOrCreateBrokerageUser(Long id) {
// TODO @芋艿这块优化下统一到注册时处理
BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(id); BrokerageUserDO brokerageUser = brokerageUserMapper.selectById(id);
// 特殊人人分销的情况下如果分销人为空则创建分销人 // 特殊人人分销的情况下如果分销人为空则创建分销人
if (brokerageUser == null && ObjUtil.equal(BrokerageEnabledConditionEnum.ALL.getCondition(), if (brokerageUser == null && ObjUtil.equal(BrokerageEnabledConditionEnum.ALL.getCondition(),

View File

@ -83,7 +83,7 @@ public class TradeBrokerageOrderHandler implements TradeOrderHandler {
if (order.getBrokerageUserId() == null) { if (order.getBrokerageUserId() == null) {
return; return;
} }
cancelBrokerage(order.getBrokerageUserId(), orderItem.getId()); brokerageRecordService.cancelBrokerage(BrokerageRecordBizTypeEnum.ORDER, String.valueOf(orderItem.getId()));
} }
/** /**
@ -111,8 +111,4 @@ public class TradeBrokerageOrderHandler implements TradeOrderHandler {
brokerageRecordService.addBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, addList); brokerageRecordService.addBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, addList);
} }
protected void cancelBrokerage(Long userId, Long orderItemId) {
brokerageRecordService.cancelBrokerage(userId, BrokerageRecordBizTypeEnum.ORDER, String.valueOf(orderItemId));
}
} }

View File

@ -133,6 +133,13 @@ public class JmReportTokenServiceImpl implements JmReportTokenServiceI {
@Override @Override
public String[] getRoles(String token) { public String[] getRoles(String token) {
// 设置租户上下文原因是/jmreport/** 纯前端地址不会走 buildLoginUserByToken 逻辑
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
if (loginUser == null) {
return null;
}
TenantContextHolder.setTenantId(loginUser.getTenantId());
// 参见文档 https://help.jeecg.com/jimureport/prodSafe.html 文档 // 参见文档 https://help.jeecg.com/jimureport/prodSafe.html 文档
// 适配如果是本系统的管理员则转换成 jimu 报表的管理员 // 适配如果是本系统的管理员则转换成 jimu 报表的管理员
Long userId = SecurityFrameworkUtils.getLoginUserId(); Long userId = SecurityFrameworkUtils.getLoginUserId();

View File

@ -1,13 +1,10 @@
package cn.iocoder.yudao.module.report.framework.security.config; package cn.iocoder.yudao.module.report.framework.security.config;
import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer; import cn.iocoder.yudao.framework.security.config.AuthorizeRequestsCustomizer;
import cn.iocoder.yudao.module.system.api.oauth2.OAuth2TokenApi;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer; import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
import javax.annotation.Resource;
/** /**
* Report 模块的 Security 配置 * Report 模块的 Security 配置
@ -15,16 +12,13 @@ import javax.annotation.Resource;
@Configuration("reportSecurityConfiguration") @Configuration("reportSecurityConfiguration")
public class SecurityConfiguration { public class SecurityConfiguration {
@Resource
private OAuth2TokenApi oauth2TokenApi;
@Bean("reportAuthorizeRequestsCustomizer") @Bean("reportAuthorizeRequestsCustomizer")
public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() { public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
return new AuthorizeRequestsCustomizer() { return new AuthorizeRequestsCustomizer() {
@Override @Override
public void customize(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry) { public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
registry.antMatchers("/jmreport/**").permitAll(); // 积木报表 registry.requestMatchers("/jmreport/**").permitAll(); // 积木报表
} }
}; };

View File

@ -286,6 +286,13 @@ yudao:
- rep_demo_jianpiao - rep_demo_jianpiao
- tmp_report_data_1 - tmp_report_data_1
- tmp_report_data_income - tmp_report_data_income
ignore-caches:
- permission_menu_ids
- oauth_client
- notify_template
- mail_account
- mail_template
- sms_template
sms-code: # 短信验证码相关的配置项 sms-code: # 短信验证码相关的配置项
expire-times: 10m expire-times: 10m
send-frequency: 1m send-frequency: 1m