diff --git a/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java b/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java index e72e3bcf9..15f6d4f6b 100644 --- a/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java +++ b/ruoyi-admin/src/main/java/org/dromara/DromaraApplication.java @@ -4,6 +4,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; import org.springframework.context.annotation.ComponentScan; +import org.springframework.scheduling.annotation.EnableScheduling; /** * 启动程序 @@ -12,6 +13,7 @@ import org.springframework.context.annotation.ComponentScan; */ @SpringBootApplication +@EnableScheduling @ComponentScan(basePackages = {"org.dromara", "com.wzj.soopin"}) public class DromaraApplication { diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index dc636b5c8..1438502be 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -181,6 +181,8 @@ tenant: - sys_version - ums_member_wechat - sys_tenant_extend + - commission_template + - commission_rate_range diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/controller/VlogController.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/controller/VlogController.java index 1eafba0fc..69ec7b2b2 100644 --- a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/controller/VlogController.java +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/controller/VlogController.java @@ -23,6 +23,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import com.wzj.soopin.content.domain.bo.IndexListBO; import com.wzj.soopin.content.domain.bo.MyListBO; import com.wzj.soopin.content.domain.bo.SimpleListBO; +import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.web.bind.annotation.*; @@ -303,4 +304,43 @@ public class VlogController extends BaseInfoProperties { return R.ok(vlogService.getVlogBeLikedCounts(vlogId)); } + @Tag(name = "手动触发缓存点赞最多视频") + @PostMapping("/cacheTopLikedVlogs") + public R cacheTopLikedVlogs(@RequestParam(defaultValue = "100") int limit) { + try { + vlogService.cacheTopLikedVlogs(limit); + return R.ok(); + } catch (Exception e) { + log.error("手动触发缓存点赞最多视频失败", e); + return R.fail("缓存失败: " + e.getMessage()); + } + } + + @Tag(name = "获取缓存中的点赞最多视频") + @GetMapping("/getTopLikedVlogs") + public R getTopLikedVlogs(@RequestParam(defaultValue = "") String date) { + try { + String redisKey; + if (StringUtils.isBlank(date)) { + // 如果没有指定日期,使用今天的日期 + redisKey = "top_liked_vlogs:" + java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } else { + redisKey = "top_liked_vlogs:" + date; + } + + String cachedData = redis.get(redisKey); + if (StringUtils.isNotBlank(cachedData)) { + // 解析JSON数据 + ObjectMapper objectMapper = new ObjectMapper(); + List> vlogList = objectMapper.readValue(cachedData, new com.fasterxml.jackson.core.type.TypeReference>>() {}); + return R.ok(vlogList); + } else { + return R.fail("未找到缓存数据,请先执行缓存任务"); + } + } catch (Exception e) { + log.error("获取缓存中的点赞最多视频失败", e); + return R.fail("获取缓存失败: " + e.getMessage()); + } + } + } diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/mapper/VlogMapper.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/mapper/VlogMapper.java index 4aa0d129a..2cf73a4fa 100644 --- a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/mapper/VlogMapper.java +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/mapper/VlogMapper.java @@ -112,4 +112,31 @@ public interface VlogMapper extends BaseMapper { "ORDER BY " + " DATE_FORMAT(create_time, '%Y-%m')") List> getMonthlyVlog(); + + /** + * 查询所有公开的视频列表(用于从Redis获取点赞数) + * @return 视频信息列表 + */ + @Select("SELECT " + + " v.id, " + + " v.vloger_id, " + + " v.url, " + + " v.cover, " + + " v.title, " + + " v.width, " + + " v.height, " + + " v.like_counts, " + + " v.comments_counts, " + + " v.is_private, " + + " v.create_time, " + + " v.update_time, " + + " v.status, " + + " v.file_id, " + + " v.reason, " + + "city_code,"+ + " v.first_frame_img " + + "FROM t_vlog v " + + "WHERE v.status = 1 AND v.is_private = 0 " + + "ORDER BY v.create_time DESC") + List> selectAllPublicVlogs(); } diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/VlogService.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/VlogService.java index a0c4a19df..f2afcbcfe 100644 --- a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/VlogService.java +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/VlogService.java @@ -137,4 +137,10 @@ public interface VlogService { * @return 分页结果 */ IPage> getVlogListByMobile(Page> page, VlogBO vlogBO); + + /** + * 查询点赞最多的视频列表并存储到Redis + * @param limit 查询数量限制 + */ + void cacheTopLikedVlogs(int limit); } diff --git a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/VlogServiceImpl.java b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/VlogServiceImpl.java index d4b932928..1804f271d 100644 --- a/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/VlogServiceImpl.java +++ b/ruoyi-modules/ruoyi-content/src/main/java/com/wzj/soopin/content/service/impl/VlogServiceImpl.java @@ -47,7 +47,10 @@ import java.time.ZoneOffset; import java.time.format.DateTimeFormatter; import java.util.*; import java.util.stream.Collectors; +import java.util.ArrayList; +import lombok.extern.slf4j.Slf4j; +@Slf4j @Service public class VlogServiceImpl extends BaseInfoProperties implements VlogService { @@ -598,4 +601,73 @@ public class VlogServiceImpl extends BaseInfoProperties implements VlogService { return vlogMapper.selectVlogListWithAggregatedData(page, vlogBO); } + + @Override + public void cacheTopLikedVlogs(int limit) { + try { + log.info("开始查询点赞最多的{}条视频", limit); + + // 查询所有公开的视频列表 + List> allVlogs = vlogMapper.selectAllPublicVlogs(); + + if (allVlogs != null && !allVlogs.isEmpty()) { + // 从Redis获取每个视频的点赞数量 + List> vlogsWithLikeCounts = new ArrayList<>(); + + for (Map vlog : allVlogs) { + String vlogId = vlog.get("id").toString(); + String redisLikeKey = REDIS_VLOG_BE_LIKED_COUNTS + ":" + vlogId; + String likeCountStr = redis.get(redisLikeKey); + + // 获取Redis中的点赞数,如果没有则使用数据库中的默认值 + int likeCount = 0; + if (likeCountStr != null && !likeCountStr.isEmpty()) { + try { + likeCount = Integer.parseInt(likeCountStr); + } catch (NumberFormatException e) { + log.warn("Redis中视频{}的点赞数格式错误: {}", vlogId, likeCountStr); + likeCount = 0; + } + } + + // 添加Redis中的点赞数到视频信息中 + vlog.put("redis_like_count", likeCount); + vlogsWithLikeCounts.add(vlog); + } + + // 按Redis中的点赞数排序,获取前limit个 + vlogsWithLikeCounts.sort((v1, v2) -> { + int count1 = (Integer) v1.get("redis_like_count"); + int count2 = (Integer) v2.get("redis_like_count"); + return Integer.compare(count2, count1); // 降序排列 + }); + + // 取前limit个 + List> topLikedVlogs = vlogsWithLikeCounts.stream() + .limit(limit) + .collect(Collectors.toList()); + + if (!topLikedVlogs.isEmpty()) { + // 将结果存储到Redis中,使用JSON格式 + ObjectMapper objectMapper = new ObjectMapper(); + // 注册JavaTimeModule以支持LocalDateTime序列化 + objectMapper.registerModule(new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule()); + objectMapper.disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + String jsonData = objectMapper.writeValueAsString(topLikedVlogs); + + // 存储到Redis,设置24小时过期时间 + String redisKey = "top_liked_vlogs:" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + redis.set(redisKey, jsonData, 24 * 60 * 60); // 24小时过期 + + log.info("成功缓存{}条点赞最多的视频到Redis,key: {}", topLikedVlogs.size(), redisKey); + } else { + log.warn("未查询到点赞最多的视频数据"); + } + } else { + log.warn("未查询到公开的视频数据"); + } + } catch (Exception e) { + log.error("缓存点赞最多视频到Redis失败", e); + } + } } diff --git a/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/controller/OrderController.java b/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/controller/OrderController.java index e6afe7be8..5abe5d444 100644 --- a/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/controller/OrderController.java +++ b/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/controller/OrderController.java @@ -11,6 +11,7 @@ import com.wzj.soopin.order.domain.form.DeliverProductForm; import com.wzj.soopin.order.domain.form.OrderPayForm; import com.wzj.soopin.order.domain.vo.*; import com.wzj.soopin.order.service.OrderService; +import com.wzj.soopin.order.service.OrderItemService; import com.wzj.soopin.order.service.impl.OrderServiceImpl; import io.swagger.annotations.ApiOperation; import io.swagger.v3.oas.annotations.tags.Tag; @@ -24,12 +25,14 @@ import org.dromara.common.excel.utils.ExcelUtil; import org.dromara.common.log.annotation.Log; import org.dromara.common.log.enums.BusinessType; import org.dromara.common.redis.redis.RedisService; +import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.web.core.BaseController; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.util.List; +import com.fasterxml.jackson.databind.ObjectMapper; /** * 订单表Controller * @@ -47,6 +50,7 @@ public class OrderController extends BaseController { private final OrderConvert convert; private final RedisService redisService; private final OrderService orderService; + private final OrderItemService orderItemService; @Tag(name ="查询订单列表") @@ -146,9 +150,41 @@ public class OrderController extends BaseController { return service.decryptPhone(orderId); } + @Tag(name = "手动触发缓存交易量最多商品") + @PostMapping("/cacheTopTradingProducts") + public R cacheTopTradingProducts(@RequestParam(defaultValue = "100") int limit) { + try { + orderItemService.cacheTopTradingProducts(limit); + return R.ok(); + } catch (Exception e) { + log.error("手动触发缓存交易量最多商品失败", e); + return R.fail("缓存失败: " + e.getMessage()); + } + } - - - + @Tag(name = "获取缓存交易量最多商品") + @GetMapping("/getTopTradingProducts") + public R getTopTradingProducts(@RequestParam(required = false) String date) { + try { + String redisKey; + if (date != null && !date.isEmpty()) { + redisKey = "top_trading_products:" + date; + } else { + redisKey = "top_trading_products:" + java.time.LocalDateTime.now().format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd")); + } + + String jsonData = RedisUtils.getCacheObject(redisKey); + if (jsonData != null && !jsonData.isEmpty()) { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.registerModule(new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule()); + return R.ok(objectMapper.readValue(jsonData, Object.class)); + } else { + return R.ok("未找到缓存数据"); + } + } catch (Exception e) { + log.error("获取缓存交易量最多商品失败", e); + return R.fail("获取失败: " + e.getMessage()); + } + } } diff --git a/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/mapper/OrderItemMapper.java b/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/mapper/OrderItemMapper.java index 3179656aa..3eaeb36c8 100644 --- a/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/mapper/OrderItemMapper.java +++ b/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/mapper/OrderItemMapper.java @@ -6,6 +6,7 @@ import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Select; import java.util.List; +import java.util.Map; /** * 订单中所包含的商品Mapper接口 @@ -34,4 +35,29 @@ public interface OrderItemMapper extends BaseMapper { "WHERE oi.order_id = #{orderId} " + "LIMIT 1") String getName(Long orderId); + + /** + * 查询交易量最多的商品列表 + * 统计已完成订单中商品的销售数量 + * + * @param limit 查询数量限制 + * @return 商品交易量信息列表 + */ + @Select("SELECT " + + " oi.product_id, " + + " oi.product_name, " + + " oi.pic, " + + " oi.out_product_id, " + + " oi.product_category_id, " + + " SUM(oi.quantity) as total_quantity, " + + " SUM(oi.quantity * oi.sale_price) as total_amount, " + + " COUNT(DISTINCT o.id) as order_count " + + "FROM oms_order_item oi " + + "JOIN oms_order o ON oi.order_id = o.id " + + "WHERE o.status = 3 " + // 已完成订单 + " AND o.delete_status = 0 " + // 未删除订单 + "GROUP BY oi.product_id, oi.product_name, oi.pic, oi.out_product_id, oi.product_category_id " + + "ORDER BY total_quantity DESC " + + "LIMIT #{limit}") + List> selectTopTradingProducts(int limit); } diff --git a/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/service/OrderItemService.java b/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/service/OrderItemService.java index e13d219fc..2b4586033 100644 --- a/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/service/OrderItemService.java +++ b/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/service/OrderItemService.java @@ -9,5 +9,9 @@ public interface OrderItemService extends IService { List findByOrderId(Long orderId); - + /** + * 缓存交易量最多的商品列表到Redis + * @param limit 查询数量限制 + */ + void cacheTopTradingProducts(int limit); } diff --git a/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/service/impl/OrderItemServiceImpl.java b/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/service/impl/OrderItemServiceImpl.java index 03cd9e0af..5b8f70694 100644 --- a/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/service/impl/OrderItemServiceImpl.java +++ b/ruoyi-modules/ruoyi-order/src/main/java/com/wzj/soopin/order/service/impl/OrderItemServiceImpl.java @@ -5,9 +5,17 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.wzj.soopin.order.domain.entity.OrderItem; import com.wzj.soopin.order.mapper.OrderItemMapper; import com.wzj.soopin.order.service.OrderItemService; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.wzj.soopin.content.utils.RedisOperator; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; import java.util.List; +import java.util.Map; +import java.util.HashMap; +import lombok.extern.slf4j.Slf4j; /** * 订单中所包含的商品Service业务层处理 @@ -15,12 +23,45 @@ import java.util.List; * * @author zcc */ +@Slf4j @Service public class OrderItemServiceImpl extends ServiceImpl implements OrderItemService { + @Autowired + private RedisOperator redis; + @Override public List findByOrderId(Long orderId) { return baseMapper.selectList(new QueryWrapper().lambda() .eq(OrderItem::getOrderId, orderId)); } + + @Override + public void cacheTopTradingProducts(int limit) { + try { + log.info("开始查询交易量最多的{}个商品", limit); + + // 查询交易量最多的商品列表 + List> topTradingProducts = baseMapper.selectTopTradingProducts(limit); + + if (topTradingProducts != null && !topTradingProducts.isEmpty()) { + // 将结果存储到Redis中,使用JSON格式 + ObjectMapper objectMapper = new ObjectMapper(); + // 注册JavaTimeModule以支持LocalDateTime序列化 + objectMapper.registerModule(new com.fasterxml.jackson.datatype.jsr310.JavaTimeModule()); + objectMapper.disable(com.fasterxml.jackson.databind.SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); + String jsonData = objectMapper.writeValueAsString(topTradingProducts); + + // 存储到Redis,设置24小时过期时间 + String redisKey = "top_trading_products:" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd")); + redis.set(redisKey, jsonData, 24 * 60 * 60); // 24小时过期 + + log.info("成功缓存{}个交易量最多的商品到Redis,key: {}", topTradingProducts.size(), redisKey); + } else { + log.warn("未查询到交易量最多的商品数据"); + } + } catch (Exception e) { + log.error("缓存交易量最多商品到Redis失败", e); + } + } } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/SysTenantAccountController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/SysTenantAccountController.java new file mode 100644 index 000000000..78df412f5 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/SysTenantAccountController.java @@ -0,0 +1,79 @@ +package org.dromara.system.controller; + +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.metadata.IPage; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.system.convert.SysTenantAccountConvert; +import org.dromara.system.domain.CommissionSection; +import org.dromara.system.domain.SysTenantAccount; +import org.dromara.system.domain.bo.CommissionSectionBo; +import org.dromara.system.domain.bo.SysTenantAccountBo; +import org.dromara.system.domain.vo.CommissionSectionVo; +import org.dromara.system.domain.vo.SysTenantAccountVo; +import org.dromara.system.service.ISysTenantAccountService; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +@Tag(name = "租户账户管理接口") +@RestController +@RequestMapping("/system/tenant/account") +@RequiredArgsConstructor +public class SysTenantAccountController { + + private final ISysTenantAccountService service; + private final SysTenantAccountConvert convert; + + @Operation(summary = "查询租户账户列表") + @PostMapping("/list") + public R> fansList(@RequestBody SysTenantAccountBo bo, @RequestBody Page page) { + LambdaQueryWrapper fansQuery = new LambdaQueryWrapper<>(); + Page fans = service.page(page, fansQuery); + return R.ok(convert.toVO(fans)); + } + + @Operation(summary = "导出租户账户列表") + @Log(title = "租户账户", businessType = BusinessType.EXPORT) + @GetMapping("/export") + public R export(SysTenantAccountBo query) { + List list = service.list(query); + ExcelUtil util = new ExcelUtil<>(SysTenantAccountVo.class); + return R.ok(util.writeExcel(convert.toVO(list), "租户账户数据")); + } + + @Operation(summary = "获取租户账户详细信息") + @GetMapping(value = "/{id}") + public R getInfo(@Parameter(description = "租户账户ID") @PathVariable("id") Long id) { + return R.ok(convert.toVO(service.getById(id))); + } + + @Operation(summary = "新增租户账户") + @Log(title = "租户账户", businessType = BusinessType.INSERT) + @PostMapping("/add") + public R add(@RequestBody SysTenantAccountBo tenantAccount) { + return R.ok(service.save(convert.toPo(tenantAccount))); + } + + @Operation(summary = "修改租户账户") + @Log(title = "租户账户", businessType = BusinessType.UPDATE) + @PutMapping("/update") + public R edit(@RequestBody SysTenantAccountBo tenantAccount) { + return R.ok(service.updateById(convert.toPo(tenantAccount))); + } + + @Operation(summary = "删除租户账户") + @Log(title = "租户账户", businessType = BusinessType.DELETE) + @DeleteMapping("/{id}") + public R remove(@Parameter(description = "租户账户ID") @PathVariable Long id) { + return R.ok(service.removeById(id)); + } +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/dto/CommissionSectionBatchAddDTO.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/dto/CommissionSectionBatchAddDTO.java new file mode 100644 index 000000000..d99daf643 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/dto/CommissionSectionBatchAddDTO.java @@ -0,0 +1,17 @@ +package org.dromara.system.domain.dto; + + + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "分成比例区间批量添加DTO") +public class CommissionSectionBatchAddDTO { + + @Schema(description = "模板ID") + private Integer templateId; + + @Schema(description = "区间列表,字符串形式的JSON数组") + private String templateList; +}