Files
FlashSaleSystem/src/main/java/com/org/flashsalesystem/service/AdminService.java
YoVinchen 6788fcd5ea refactor: 后端核心模块功能增强与代码优化
- 完善 User/Product/Order 实体字段和关联关系
- 更新 DTO 适配新增字段
- 增强 Service 层业务逻辑和 Repository 查询方法
- 优化控制器接口,完善管理后台 API
- 新增请求监控过滤器和指标服务
2026-03-10 23:18:08 +08:00

856 lines
36 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package com.org.flashsalesystem.service;
import com.org.flashsalesystem.dto.UserDTO;
import com.org.flashsalesystem.entity.Order;
import com.org.flashsalesystem.entity.Product;
import com.org.flashsalesystem.entity.ProductReview;
import com.org.flashsalesystem.entity.User;
import com.org.flashsalesystem.entity.UserFavorite;
import com.org.flashsalesystem.repository.FlashSaleRepository;
import com.org.flashsalesystem.repository.OrderItemRepository;
import com.org.flashsalesystem.repository.OrderRepository;
import com.org.flashsalesystem.repository.ProductRepository;
import com.org.flashsalesystem.repository.ProductReviewRepository;
import com.org.flashsalesystem.repository.UserFavoriteRepository;
import com.org.flashsalesystem.repository.UserRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.io.File;
import java.lang.management.ManagementFactory;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;
/**
* 管理后台服务类
*/
@Service
@Slf4j
public class AdminService {
@Autowired
private UserRepository userRepository;
@Autowired
private ProductRepository productRepository;
@Autowired
private OrderRepository orderRepository;
@Autowired
private OrderItemRepository orderItemRepository;
@Autowired
private ProductReviewRepository productReviewRepository;
@Autowired
private UserFavoriteRepository userFavoriteRepository;
@Autowired
private FlashSaleRepository flashSaleRepository;
@Autowired
private RedisService redisService;
@Autowired
private DataSource dataSource;
@Autowired
private RequestMetricsService requestMetricsService;
/**
* 获取仪表盘统计数据
*/
public Map<String, Object> getDashboardStats() {
Map<String, Object> stats = new HashMap<>();
try {
// 总用户数
long totalUsers = userRepository.count();
stats.put("totalUsers", totalUsers);
// 总商品数
long totalProducts = productRepository.count();
stats.put("totalProducts", totalProducts);
// 活跃秒杀数
LocalDateTime now = LocalDateTime.now();
long activeFlashSales = flashSaleRepository.countByStartTimeLessThanEqualAndEndTimeGreaterThanEqual(now,
now);
stats.put("activeFlashSales", activeFlashSales);
// 今日订单数
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
LocalDateTime endOfDay = LocalDate.now().atTime(LocalTime.MAX);
long todayOrders = orderRepository.countByCreatedAtBetween(startOfDay, endOfDay);
stats.put("todayOrders", todayOrders);
// 总订单数
long totalOrders = orderRepository.count();
stats.put("totalOrders", totalOrders);
// 已支付订单数
Long paidOrdersCount = orderRepository.countByStatus(2); // 2-已支付
long paidOrders = paidOrdersCount != null ? paidOrdersCount : 0L;
stats.put("paidOrders", paidOrders);
// 待处理订单数
Long pendingOrdersCount = orderRepository.countByStatus(1); // 1-待支付
long pendingOrders = pendingOrdersCount != null ? pendingOrdersCount : 0L;
stats.put("pendingOrders", pendingOrders);
// 总交易额
BigDecimal totalAmount = orderRepository.sumTotalPriceByStatus(2); // 2-已支付
if (totalAmount == null) {
totalAmount = BigDecimal.ZERO;
}
stats.put("totalAmount", totalAmount);
log.info("获取仪表盘统计数据成功: {}", stats);
} catch (Exception e) {
log.error("获取仪表盘统计数据失败", e);
// 返回默认值
stats.put("totalUsers", 0L);
stats.put("totalProducts", 0L);
stats.put("activeFlashSales", 0L);
stats.put("todayOrders", 0L);
stats.put("totalOrders", 0L);
stats.put("paidOrders", 0L);
stats.put("pendingOrders", 0L);
stats.put("totalAmount", BigDecimal.ZERO);
}
return stats;
}
/**
* 获取用户统计数据
*/
public Map<String, Object> getUserStats() {
Map<String, Object> stats = new HashMap<>();
try {
// 总用户数
long totalUsers = userRepository.count();
stats.put("totalUsers", totalUsers);
// 活跃用户数最近7天登录
LocalDateTime sevenDaysAgo = LocalDateTime.now().minusDays(7);
long activeUsers = userRepository.countByLastLoginAfter(sevenDaysAgo);
stats.put("activeUsers", activeUsers);
// 新用户数(今天注册)
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
LocalDateTime endOfDay = LocalDate.now().atTime(LocalTime.MAX);
long newUsers = userRepository.countByCreatedAtBetween(startOfDay, endOfDay);
stats.put("newUsers", newUsers);
// 在线用户数从Redis获取
String onlineUsersKey = "online_users";
long onlineUsers = redisService.sCard(onlineUsersKey);
stats.put("onlineUsers", onlineUsers);
} catch (Exception e) {
log.error("获取用户统计数据失败", e);
stats.put("totalUsers", 0L);
stats.put("activeUsers", 0L);
stats.put("newUsers", 0L);
stats.put("onlineUsers", 0L);
}
return stats;
}
/**
* 获取订单统计数据
*/
public Map<String, Object> getOrderStats() {
Map<String, Object> stats = new HashMap<>();
try {
// 总订单数
long totalOrders = orderRepository.count();
stats.put("totalOrders", totalOrders);
// 已支付订单数
Long paidOrdersCount = orderRepository.countByStatus(2); // 2-已支付
long paidOrders = paidOrdersCount != null ? paidOrdersCount : 0L;
stats.put("paidOrders", paidOrders);
// 待处理订单数
Long pendingOrdersCount = orderRepository.countByStatus(1); // 1-待支付
long pendingOrders = pendingOrdersCount != null ? pendingOrdersCount : 0L;
stats.put("pendingOrders", pendingOrders);
// 已取消订单数
Long cancelledOrdersCount = orderRepository.countByStatus(5); // 5-已取消
long cancelledOrders = cancelledOrdersCount != null ? cancelledOrdersCount : 0L;
stats.put("cancelledOrders", cancelledOrders);
// 总交易额
BigDecimal totalAmount = orderRepository.sumTotalPriceByStatus(2); // 2-已支付
if (totalAmount == null) {
totalAmount = BigDecimal.ZERO;
}
stats.put("totalAmount", totalAmount);
// 今日订单数
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
LocalDateTime endOfDay = LocalDate.now().atTime(LocalTime.MAX);
long todayOrders = orderRepository.countByCreatedAtBetween(startOfDay, endOfDay);
stats.put("todayOrders", todayOrders);
} catch (Exception e) {
log.error("获取订单统计数据失败", e);
stats.put("totalOrders", 0L);
stats.put("paidOrders", 0L);
stats.put("pendingOrders", 0L);
stats.put("cancelledOrders", 0L);
stats.put("totalAmount", BigDecimal.ZERO);
stats.put("todayOrders", 0L);
}
return stats;
}
/**
* 获取商品统计数据
*/
public Map<String, Object> getProductStats() {
Map<String, Object> stats = new HashMap<>();
try {
// 总商品数
long totalProducts = productRepository.count();
stats.put("totalProducts", totalProducts);
// 上架商品数
long activeProducts = productRepository.countByStatus(1);
stats.put("activeProducts", activeProducts);
// 下架商品数
long inactiveProducts = productRepository.countByStatus(0);
stats.put("inactiveProducts", inactiveProducts);
// 库存不足商品数库存小于10
long lowStockProducts = productRepository.countByStockLessThan(10);
stats.put("lowStockProducts", lowStockProducts);
} catch (Exception e) {
log.error("获取商品统计数据失败", e);
stats.put("totalProducts", 0L);
stats.put("activeProducts", 0L);
stats.put("inactiveProducts", 0L);
stats.put("lowStockProducts", 0L);
}
return stats;
}
/**
* 获取秒杀统计数据
*/
public Map<String, Object> getFlashSaleStats() {
Map<String, Object> stats = new HashMap<>();
try {
LocalDateTime now = LocalDateTime.now();
// 总秒杀活动数
long totalFlashSales = flashSaleRepository.count();
stats.put("totalFlashSales", totalFlashSales);
// 活跃秒杀数
long activeFlashSales = flashSaleRepository.countByStartTimeLessThanEqualAndEndTimeGreaterThanEqual(now,
now);
stats.put("activeFlashSales", activeFlashSales);
// 即将开始的秒杀数
LocalDateTime oneHourLater = now.plusHours(1);
long upcomingFlashSales = flashSaleRepository.countByStartTimeBetween(now, oneHourLater);
stats.put("upcomingFlashSales", upcomingFlashSales);
// 已结束的秒杀数
long endedFlashSales = flashSaleRepository.countByEndTimeLessThan(now);
stats.put("endedFlashSales", endedFlashSales);
} catch (Exception e) {
log.error("获取秒杀统计数据失败", e);
stats.put("totalFlashSales", 0L);
stats.put("activeFlashSales", 0L);
stats.put("upcomingFlashSales", 0L);
stats.put("endedFlashSales", 0L);
}
return stats;
}
/**
* 获取最近订单列表
*/
public List<Map<String, Object>> getRecentOrders(int limit) {
try {
Pageable pageable = PageRequest.of(0, limit, Sort.by(Sort.Direction.DESC, "createdAt"));
Page<Order> orders = orderRepository.findAll(pageable);
return orders.getContent().stream().map(order -> {
Map<String, Object> orderMap = new HashMap<>();
orderMap.put("id", order.getId());
orderMap.put("username", order.getUser().getUsername());
orderMap.put("productName", order.getProduct().getName());
orderMap.put("quantity", order.getQuantity());
orderMap.put("totalAmount", order.getTotalPrice());
orderMap.put("status", order.getStatus());
orderMap.put("createdAt", order.getCreatedAt());
orderMap.put("isFlashSale", order.getOrderType() == 2); // 2表示秒杀订单
return orderMap;
}).collect(Collectors.toList());
} catch (Exception e) {
log.error("获取最近订单失败", e);
return new ArrayList<>();
}
}
/**
* 获取热门商品列表
*/
public List<Map<String, Object>> getHotProducts(int limit) {
try {
// 这里可以根据销量排序,暂时按创建时间排序
Pageable pageable = PageRequest.of(0, limit, Sort.by(Sort.Direction.DESC, "createdAt"));
Page<Product> products = productRepository.findAll(pageable);
return products.getContent().stream().map(product -> {
Map<String, Object> productMap = new HashMap<>();
productMap.put("id", product.getId());
productMap.put("name", product.getName());
productMap.put("price", product.getPrice());
productMap.put("category", product.getCategory());
productMap.put("stock", product.getStock());
productMap.put("sales", 0); // 暂时设为0后续可以添加销量统计
return productMap;
}).collect(Collectors.toList());
} catch (Exception e) {
log.error("获取热门商品失败", e);
return new ArrayList<>();
}
}
/**
* 获取用户列表
*/
public Map<String, Object> getUsers(int page, int size, String keyword, Integer status) {
try {
Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createdAt"));
Page<User> userPage;
if (keyword != null && !keyword.trim().isEmpty()) {
userPage = userRepository.findByUsernameContainingOrEmailContaining(keyword, keyword, pageable);
} else if (status != null) {
userPage = userRepository.findByStatus(status, pageable);
} else {
userPage = userRepository.findAll(pageable);
}
List<UserDTO> userDTOs = userPage.getContent().stream().map(user -> {
UserDTO dto = new UserDTO();
BeanUtils.copyProperties(user, dto);
dto.setPassword(null); // 不返回密码
dto.setIsOnline(redisService.sIsMember("online_users", user.getId().toString()));
dto.setRole(user.getRole() == null ? ("admin".equalsIgnoreCase(user.getUsername()) ? "ADMIN" : "USER") : user.getRole());
dto.setAvatar("");
return dto;
}).collect(Collectors.toList());
Map<String, Object> result = new HashMap<>();
result.put("users", userDTOs);
result.put("total", userPage.getTotalElements());
result.put("totalPages", userPage.getTotalPages());
result.put("currentPage", page);
result.put("size", size);
return result;
} catch (Exception e) {
log.error("获取用户列表失败", e);
Map<String, Object> result = new HashMap<>();
result.put("users", new ArrayList<>());
result.put("total", 0L);
result.put("totalPages", 0);
result.put("currentPage", page);
result.put("size", size);
return result;
}
}
/**
* 获取订单列表
*/
public Map<String, Object> getOrders(int page, int size, String keyword, String status) {
try {
Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createdAt"));
Page<Order> orderPage;
if (keyword != null && !keyword.trim().isEmpty()) {
orderPage = orderRepository.findByIdContainingOrUserUsernameContaining(keyword, keyword, pageable);
} else if (status != null && !status.trim().isEmpty()) {
Integer statusInt = Integer.parseInt(status);
orderPage = orderRepository.findByStatus(statusInt, pageable);
} else {
orderPage = orderRepository.findAll(pageable);
}
List<Map<String, Object>> orders = orderPage.getContent().stream().map(order -> {
Map<String, Object> orderMap = new HashMap<>();
orderMap.put("id", order.getId());
orderMap.put("username", order.getUser().getUsername());
orderMap.put("productName", order.getProduct().getName());
orderMap.put("quantity", order.getQuantity());
orderMap.put("totalAmount", order.getTotalPrice());
orderMap.put("status", order.getStatus());
orderMap.put("createdAt", order.getCreatedAt());
orderMap.put("isFlashSale", order.getOrderType() == 2); // 2表示秒杀订单
return orderMap;
}).collect(Collectors.toList());
Map<String, Object> result = new HashMap<>();
result.put("orders", orders);
result.put("total", orderPage.getTotalElements());
result.put("totalPages", orderPage.getTotalPages());
result.put("currentPage", page);
result.put("size", size);
return result;
} catch (Exception e) {
log.error("获取订单列表失败", e);
Map<String, Object> result = new HashMap<>();
result.put("orders", new ArrayList<>());
result.put("total", 0L);
result.put("totalPages", 0);
result.put("currentPage", page);
result.put("size", size);
return result;
}
}
/**
* 获取商品列表
*/
public Object getProducts(int page, int size, String keyword, String category, Integer status) {
try {
Pageable pageable = PageRequest.of(page - 1, size, Sort.by(Sort.Direction.DESC, "createdAt"));
Page<Product> productPage;
productPage = productRepository.searchProducts(
status,
keyword != null && !keyword.trim().isEmpty() ? keyword.trim() : null,
category != null && !category.trim().isEmpty() ? category.trim() : null,
null,
null,
pageable
);
// 转换为DTO
List<Map<String, Object>> productList = productPage.getContent().stream().map(product -> {
Map<String, Object> productMap = new HashMap<>();
productMap.put("id", product.getId());
productMap.put("name", product.getName());
productMap.put("price", product.getPrice());
productMap.put("category", product.getCategory());
productMap.put("stock", product.getStock());
productMap.put("status", product.getStatus());
productMap.put("description", product.getDescription());
productMap.put("imageUrl", product.getImageUrl());
productMap.put("createdAt", product.getCreatedAt());
return productMap;
}).collect(Collectors.toList());
Map<String, Object> result = new HashMap<>();
result.put("products", productList);
result.put("total", productPage.getTotalElements());
result.put("totalPages", productPage.getTotalPages());
result.put("currentPage", page);
result.put("size", size);
return result;
} catch (Exception e) {
log.error("获取商品列表失败", e);
Map<String, Object> result = new HashMap<>();
result.put("products", new ArrayList<>());
result.put("total", 0L);
result.put("totalPages", 0);
result.put("currentPage", page);
result.put("size", size);
return result;
}
}
/**
* 获取系统状态
*/
public Object getSystemStatus() {
try {
Map<String, Object> systemStatus = new HashMap<>();
Runtime runtime = Runtime.getRuntime();
long totalMemory = runtime.totalMemory();
long freeMemory = runtime.freeMemory();
long usedMemory = totalMemory - freeMemory;
double memoryUsage = totalMemory == 0 ? 0 : (double) usedMemory / totalMemory * 100;
double cpuUsage = 0;
java.lang.management.OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean();
if (osBean instanceof com.sun.management.OperatingSystemMXBean) {
cpuUsage = ((com.sun.management.OperatingSystemMXBean) osBean).getSystemCpuLoad() * 100;
if (cpuUsage < 0) {
cpuUsage = 0;
}
}
File root = new File("/");
long totalSpace = root.getTotalSpace();
long usableSpace = root.getUsableSpace();
long usedSpace = totalSpace - usableSpace;
double diskUsage = totalSpace == 0 ? 0 : (double) usedSpace / totalSpace * 100;
boolean dbHealthy = false;
try (java.sql.Connection connection = dataSource.getConnection()) {
dbHealthy = connection.isValid(2);
}
String redisPing = redisService.ping();
boolean redisHealthy = "PONG".equalsIgnoreCase(redisPing);
String requestCountKey = "request_count:" + LocalDate.now().format(java.time.format.DateTimeFormatter.BASIC_ISO_DATE);
Object requestCountValue = redisService.get(requestCountKey);
long requestCountToday = requestCountValue == null ? requestMetricsService.getTotalRequests() : Long.parseLong(requestCountValue.toString());
systemStatus.put("status", dbHealthy && redisHealthy ? "正常" : "异常");
systemStatus.put("cpuUsage", Math.round(cpuUsage));
systemStatus.put("memoryUsage", Math.round(memoryUsage));
systemStatus.put("diskUsage", Math.round(diskUsage));
systemStatus.put("availableProcessors", runtime.availableProcessors());
systemStatus.put("totalMemory", totalMemory / 1024 / 1024 + "MB");
systemStatus.put("usedMemory", usedMemory / 1024 / 1024 + "MB");
systemStatus.put("dbStatus", dbHealthy ? "正常" : "异常");
systemStatus.put("redisStatus", redisHealthy ? "正常" : "异常");
systemStatus.put("requestCountToday", requestCountToday);
return systemStatus;
} catch (Exception e) {
log.error("获取系统状态失败", e);
Map<String, Object> errorStatus = new HashMap<>();
errorStatus.put("status", "异常");
errorStatus.put("cpuUsage", 0);
errorStatus.put("memoryUsage", 0);
errorStatus.put("diskUsage", 0);
errorStatus.put("dbStatus", "异常");
errorStatus.put("redisStatus", "异常");
errorStatus.put("requestCountToday", requestMetricsService.getTotalRequests());
return errorStatus;
}
}
/**
* 获取Redis状态
*/
public Object getRedisStatus() {
try {
List<Map<String, Object>> redisNodes = new ArrayList<>();
Properties memoryInfo = redisService.info("memory");
Properties clientInfo = redisService.info("clients");
String ping = redisService.ping();
Map<String, Object> nodeStatus = new HashMap<>();
nodeStatus.put("node", "default");
nodeStatus.put("status", "PONG".equalsIgnoreCase(ping) ? "正常" : "异常");
nodeStatus.put("memory", memoryInfo.getProperty("used_memory_human", "unknown"));
nodeStatus.put("connections", Integer.parseInt(clientInfo.getProperty("connected_clients", "0")));
redisNodes.add(nodeStatus);
return redisNodes;
} catch (Exception e) {
log.error("获取Redis状态失败", e);
return new ArrayList<>();
}
}
/**
* 获取单个商品详情
*/
public Object getProduct(Long id) {
try {
Optional<Product> productOpt = productRepository.findById(id);
if (productOpt.isPresent()) {
Product product = productOpt.get();
Map<String, Object> productMap = new HashMap<>();
productMap.put("id", product.getId());
productMap.put("name", product.getName());
productMap.put("price", product.getPrice());
productMap.put("stock", product.getStock());
productMap.put("status", product.getStatus());
productMap.put("description", product.getDescription());
productMap.put("imageUrl", product.getImageUrl());
productMap.put("createdAt", product.getCreatedAt());
productMap.put("updatedAt", product.getUpdatedAt());
long totalSales = orderItemRepository.countByProductId(product.getId());
java.math.BigDecimal totalRevenue = orderItemRepository.sumSubtotalByProductId(product.getId());
Double averageRating = productReviewRepository.findAverageRatingByProductId(product.getId());
long reviewCount = productReviewRepository.countByProductId(product.getId());
productMap.put("totalSales", totalSales);
productMap.put("totalRevenue", totalRevenue == null ? 0.0 : totalRevenue);
productMap.put("viewCount", 0);
productMap.put("rating", averageRating == null ? 0.0 : averageRating);
productMap.put("reviewCount", reviewCount);
return productMap;
} else {
throw new RuntimeException("商品不存在");
}
} catch (Exception e) {
log.error("获取商品详情失败", e);
throw new RuntimeException("获取商品详情失败");
}
}
/**
* 更新商品
*/
public void updateProduct(Long id, Map<String, Object> productData) {
try {
Optional<Product> productOpt = productRepository.findById(id);
if (productOpt.isPresent()) {
Product product = productOpt.get();
if (productData.containsKey("name")) {
product.setName((String) productData.get("name"));
}
if (productData.containsKey("price")) {
product.setPrice(new BigDecimal(productData.get("price").toString()));
}
if (productData.containsKey("stock")) {
product.setStock(Integer.parseInt(productData.get("stock").toString()));
}
if (productData.containsKey("category")) {
product.setCategory((String) productData.get("category"));
}
if (productData.containsKey("status")) {
product.setStatus(Integer.parseInt(productData.get("status").toString()));
}
if (productData.containsKey("description")) {
product.setDescription((String) productData.get("description"));
}
if (productData.containsKey("imageUrl")) {
product.setImageUrl((String) productData.get("imageUrl"));
}
product.setUpdatedAt(LocalDateTime.now());
productRepository.save(product);
} else {
throw new RuntimeException("商品不存在");
}
} catch (Exception e) {
log.error("更新商品失败", e);
throw new RuntimeException("更新商品失败: " + e.getMessage());
}
}
/**
* 删除商品
*/
public void deleteProduct(Long id) {
try {
if (productRepository.existsById(id)) {
productRepository.deleteById(id);
} else {
throw new RuntimeException("商品不存在");
}
} catch (Exception e) {
log.error("删除商品失败", e);
throw new RuntimeException("删除商品失败: " + e.getMessage());
}
}
/**
* 添加商品
*/
public Object addProduct(Map<String, Object> productData) {
try {
Product product = new Product();
product.setName((String) productData.get("name"));
product.setPrice(new BigDecimal(productData.get("price").toString()));
product.setCategory((String) productData.getOrDefault("category", "默认分类"));
product.setStock(Integer.parseInt(productData.get("stock").toString()));
product.setStatus(Integer.parseInt(productData.get("status").toString()));
product.setDescription((String) productData.get("description"));
product.setImageUrl((String) productData.get("imageUrl"));
product.setCreatedAt(LocalDateTime.now());
product.setUpdatedAt(LocalDateTime.now());
Product savedProduct = productRepository.save(product);
Map<String, Object> result = new HashMap<>();
result.put("id", savedProduct.getId());
result.put("name", savedProduct.getName());
result.put("price", savedProduct.getPrice());
result.put("category", savedProduct.getCategory());
result.put("stock", savedProduct.getStock());
result.put("status", savedProduct.getStatus());
result.put("description", savedProduct.getDescription());
result.put("imageUrl", savedProduct.getImageUrl());
result.put("createdAt", savedProduct.getCreatedAt());
return result;
} catch (Exception e) {
log.error("添加商品失败", e);
throw new RuntimeException("添加商品失败: " + e.getMessage());
}
}
public Map<String, Object> getReviewStats() {
Map<String, Object> stats = new HashMap<>();
List<ProductReview> reviews = productReviewRepository.findAll();
LocalDateTime startOfDay = LocalDate.now().atStartOfDay();
long todayReviews = reviews.stream().filter(item -> item.getCreatedAt() != null && item.getCreatedAt().isAfter(startOfDay)).count();
double averageRating = reviews.isEmpty() ? 0.0 : reviews.stream().mapToInt(ProductReview::getRating).average().orElse(0.0);
stats.put("totalReviews", reviews.size());
stats.put("todayReviews", todayReviews);
stats.put("averageRating", averageRating);
stats.put("fiveStarReviews", reviews.stream().filter(item -> item.getRating() == 5).count());
return stats;
}
public Map<String, Object> getFavoriteStats() {
Map<String, Object> stats = new HashMap<>();
List<UserFavorite> favorites = userFavoriteRepository.findAll();
stats.put("totalFavorites", favorites.size());
stats.put("favoriteUsers", favorites.stream().map(UserFavorite::getUserId).distinct().count());
stats.put("favoriteProducts", favorites.stream().map(UserFavorite::getProductId).distinct().count());
stats.put("todayFavorites", favorites.stream().filter(item -> item.getCreatedAt() != null && item.getCreatedAt().isAfter(LocalDate.now().atStartOfDay())).count());
return stats;
}
public Map<String, Object> getReviews(int page, int size, String keyword) {
List<Map<String, Object>> rows = productReviewRepository.findAll(Sort.by(Sort.Direction.DESC, "createdAt"))
.stream()
.map(review -> {
Map<String, Object> item = new HashMap<>();
item.put("id", review.getId());
item.put("productId", review.getProductId());
item.put("userId", review.getUserId());
item.put("orderId", review.getOrderId());
item.put("rating", review.getRating());
item.put("content", review.getContent());
item.put("status", review.getStatus());
item.put("statusText", review.getStatus() != null && review.getStatus() == 1 ? "显示" : "隐藏");
item.put("adminReply", review.getAdminReply());
item.put("repliedAt", review.getRepliedAt());
item.put("createdAt", review.getCreatedAt());
Product product = productRepository.findById(review.getProductId()).orElse(null);
User user = userRepository.findById(review.getUserId()).orElse(null);
item.put("productName", product != null ? product.getName() : "未知商品");
item.put("username", user != null ? user.getUsername() : "未知用户");
return item;
})
.filter(item -> {
if (keyword == null || keyword.trim().isEmpty()) return true;
String value = keyword.trim().toLowerCase();
return String.valueOf(item.get("productName")).toLowerCase().contains(value)
|| String.valueOf(item.get("username")).toLowerCase().contains(value)
|| String.valueOf(item.get("content")).toLowerCase().contains(value);
})
.collect(Collectors.toList());
return paginate(rows, page, size, "reviews");
}
public Object updateReview(Long id, com.org.flashsalesystem.dto.ProductReviewDTO.UpdateDTO updateDTO) {
ProductReview review = productReviewRepository.findById(id)
.orElseThrow(() -> new RuntimeException("评价不存在"));
if (updateDTO.getStatus() != null) {
review.setStatus(updateDTO.getStatus());
}
if (updateDTO.getAdminReply() != null) {
review.setAdminReply(updateDTO.getAdminReply());
review.setRepliedAt(java.time.LocalDateTime.now());
}
review = productReviewRepository.save(review);
Map<String, Object> result = new HashMap<>();
result.put("id", review.getId());
result.put("status", review.getStatus());
result.put("statusText", review.getStatus() != null && review.getStatus() == 1 ? "显示" : "隐藏");
result.put("adminReply", review.getAdminReply());
result.put("repliedAt", review.getRepliedAt());
return result;
}
public void deleteReview(Long id) {
productReviewRepository.deleteById(id);
}
public Map<String, Object> getFavorites(int page, int size, String keyword) {
List<Map<String, Object>> rows = userFavoriteRepository.findAll(Sort.by(Sort.Direction.DESC, "createdAt"))
.stream()
.map(favorite -> {
Map<String, Object> item = new HashMap<>();
item.put("id", favorite.getId());
item.put("userId", favorite.getUserId());
item.put("productId", favorite.getProductId());
item.put("createdAt", favorite.getCreatedAt());
Product product = productRepository.findById(favorite.getProductId()).orElse(null);
User user = userRepository.findById(favorite.getUserId()).orElse(null);
item.put("productName", product != null ? product.getName() : "未知商品");
item.put("productCategory", product != null ? product.getCategory() : "默认分类");
item.put("username", user != null ? user.getUsername() : "未知用户");
return item;
})
.filter(item -> {
if (keyword == null || keyword.trim().isEmpty()) return true;
String value = keyword.trim().toLowerCase();
return String.valueOf(item.get("productName")).toLowerCase().contains(value)
|| String.valueOf(item.get("username")).toLowerCase().contains(value);
})
.collect(Collectors.toList());
return paginate(rows, page, size, "favorites");
}
public void deleteFavorite(Long id) {
userFavoriteRepository.deleteById(id);
}
private Map<String, Object> paginate(List<Map<String, Object>> rows, int page, int size, String key) {
int currentPage = Math.max(page, 1);
int pageSize = Math.max(size, 1);
int fromIndex = Math.min((currentPage - 1) * pageSize, rows.size());
int toIndex = Math.min(fromIndex + pageSize, rows.size());
Map<String, Object> result = new HashMap<>();
result.put(key, rows.subList(fromIndex, toIndex));
result.put("total", rows.size());
result.put("totalPages", (int) Math.ceil(rows.size() * 1.0 / pageSize));
result.put("currentPage", currentPage);
result.put("size", pageSize);
return result;
}
}