商品 批量操作

This commit is contained in:
2026-05-06 11:10:23 +08:00
parent 962e6d7a0c
commit d9d95da453
5 changed files with 129 additions and 5 deletions

View File

@@ -63,7 +63,6 @@ public class ProductController {
* 商品-分页
*/
@GetMapping("page")
@OperationLog("商品-分页")
//@SaAdminCheckPermission("product:page")
public CzgResult<Map<String, Object>> getProductPage(ProductDTO param) {
Page<ProductDTO> data = productService.getProductPage(param);
@@ -83,7 +82,6 @@ public class ProductController {
* 商品-列表
*/
@GetMapping("list")
@OperationLog("商品-列表")
public CzgResult<List<ProductDTO>> getProductList(@RequestParam(required = false) Long categoryId) {
return CzgResult.success(productService.getProductCacheList(StpKit.USER.getShopId(), categoryId));
}
@@ -92,7 +90,6 @@ public class ProductController {
* 商品-详情
*/
@GetMapping("{id}")
@OperationLog("商品-详情")
//@SaAdminCheckPermission("product:info")
public CzgResult<ProductDTO> getProductById(@PathVariable("id") Long id) {
AssertUtil.isNull(id, "{}不能为空", "id");
@@ -242,7 +239,6 @@ public class ProductController {
* 商品-统计
*/
@GetMapping("statistics")
@OperationLog("商品-统计")
//@SaAdminCheckPermission("product:statistics")
public CzgResult<ProductStatisticsVo> statistics(ProductInfoParam param) {
Long shopId = StpKit.USER.getShopId(0L);
@@ -251,6 +247,17 @@ public class ProductController {
return CzgResult.success(data);
}
/**
* 商品-批量操作
*/
@GetMapping("batchOperate")
public CzgResult<Void> batchOperate(ProductBatchParam param) {
Long shopId = StpKit.USER.getShopId();
param.setShopId(shopId);
productService.batchOperate(param);
return CzgResult.success();
}
/**
* 商品-报损
*/

View File

@@ -5,7 +5,10 @@ import com.alibaba.fastjson2.JSONWriter;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
@@ -52,6 +55,34 @@ public class RedisService {
return redisTemplate.delete(keys);
}
/**
* 删除某前缀Key
* @param prefix
*/
public void deleteKeysByPrefixSafe(String prefix) {
// 拼接匹配规则:前缀 + * → 比如传入 user → 匹配 user*
String pattern = prefix + "*";
// redisTemplate.execute使用 Redis 底层连接执行原生命令(性能更高)
redisTemplate.execute((RedisCallback<Void>) connection -> {
// try-with-resources自动关闭游标避免资源泄漏
try (Cursor<byte[]> cursor = connection.scan(
// SCAN 配置匹配规则、每次扫描1000条
ScanOptions.scanOptions().match(pattern).count(1000).build()
)) {
// 迭代遍历扫描到的所有 key
while (cursor.hasNext()) {
// 删除当前遍历到的 key
connection.del(cursor.next());
}
} catch (Exception e) {
// 异常捕获打印,避免删除失败导致程序报错
e.printStackTrace();
}
return null;
});
}
/**
* 指定缓存失效时间
*

View File

@@ -0,0 +1,44 @@
package com.czg.product.param;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.util.List;
/**
* 商品批量操作
*
* @author ww
*/
@Data
public class ProductBatchParam implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 商品id集合
*/
@NotNull(message = "商品id集合不能为空")
private List<Long> ids;
/**
* 商品操作
* category 修改分类
* isSale 上下架
* is_sold_stock 售罄
* isAutoSoldStock 自动售罄
*/
@NotBlank(message = "操作类型不能为空")
private String type;
/**
* 操作值
*/
@NotBlank(message = "操作值不能为空")
private String value;
/**
* 店铺id
*/
private Long shopId;
}

View File

@@ -110,7 +110,10 @@ public interface ProductService extends IService<Product> {
* @param param 商品报损入参
*/
void reportDamage(ProductReportDamageParam param);
/**
* 批量操作商品
*/
void batchOperate(ProductBatchParam param);
/**
* 商品统计
*

View File

@@ -401,6 +401,19 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
redisService.del(CacheConstant.USER_CLIENT_HOTS_PRODUCT + "::" + shopId);
}
/**
* 清除某个商品分类的缓存
*/
private void clearProductAllCache(Long shopId) {
//分类缓存
redisService.deleteKeysByPrefixSafe(ADMIN_CLIENT_PRODUCT_LIST + "::" + shopId);
//用户端分组缓存
redisService.del(CacheConstant.USER_CLIENT_GROUPS_PRODUCT + "::" + shopId);
//用户端热销缓存
redisService.del(CacheConstant.USER_CLIENT_HOTS_PRODUCT + "::" + shopId);
}
/**
* 计算是否在可售时间内
*
@@ -778,6 +791,32 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
consStockByProduct(shopId, InOutTypeEnum.OUT, InOutItemEnum.DAMAGE_OUT, productStockList, null, "【商品报损,自动报损相关耗材】");
}
@Override
public void batchOperate(ProductBatchParam param) {
Product product = new Product();
//商品操作
//category 修改分类
//isSale 上下架
//is_sold_stock 售罄
//isAutoSoldStock 自动售罄
switch (param.getType()) {
case "category":
product.setCategoryId(Long.valueOf(param.getValue()));
break;
case "isSale":
product.setIsSale(Integer.valueOf(param.getValue()));
break;
case "is_sold_stock":
product.setIsSoldStock(Integer.valueOf(param.getValue()));
break;
case "isAutoSoldStock":
product.setIsAutoSoldStock(Integer.valueOf(param.getValue()));
break;
}
update(product, query().eq(Product::getShopId, param.getShopId()).in(Product::getId, param.getIds()));
clearProductAllCache(param.getShopId());
}
@Override
public ProductStatisticsVo getProductStatistics(ProductInfoParam param) {
ProductStatisticsVo data = productStockFlowMapper.getProductStatistics(param);