|
@@ -0,0 +1,209 @@
|
|
|
|
|
+package com.etotem.cfc.service;
|
|
|
|
|
+
|
|
|
|
|
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|
|
|
|
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
|
|
|
|
+import com.etotem.cfc.entity.CategoryPpoint;
|
|
|
|
|
+import com.etotem.cfc.entity.Product;
|
|
|
|
|
+import com.etotem.cfc.entity.ProductPpoint;
|
|
|
|
|
+import com.etotem.cfc.mapper.CategoryPpointMapper;
|
|
|
|
|
+import com.etotem.cfc.mapper.ProductMapper;
|
|
|
|
|
+import com.etotem.cfc.mapper.ProductPpointMapper;
|
|
|
|
|
+import org.slf4j.Logger;
|
|
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
|
|
+
|
|
|
|
|
+import javax.annotation.Resource;
|
|
|
|
|
+import java.util.Date;
|
|
|
|
|
+import java.util.HashMap;
|
|
|
|
|
+import java.util.List;
|
|
|
|
|
+import java.util.Map;
|
|
|
|
|
+import java.util.stream.Collectors;
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * P点配置管理 — 综合品类级比例 + 商品级固定值
|
|
|
|
|
+ * 查询优先级:商品级 ProductPpoint > 品类级 CategoryPpoint.ratio > 商品 profitRate
|
|
|
|
|
+ */
|
|
|
|
|
+@Service
|
|
|
|
|
+public class PpointConfigService {
|
|
|
|
|
+
|
|
|
|
|
+ private static final Logger log = LoggerFactory.getLogger(PpointConfigService.class);
|
|
|
|
|
+
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private ProductPpointMapper productPpointMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private CategoryPpointMapper categoryPpointMapper;
|
|
|
|
|
+
|
|
|
|
|
+ @Resource
|
|
|
|
|
+ private ProductMapper productMapper;
|
|
|
|
|
+
|
|
|
|
|
+ // ======================== 品类级P点比例 ========================
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取品类当前有效的P点比例
|
|
|
|
|
+ * @param categoryId 品类ID
|
|
|
|
|
+ * @return 千分比(如 200 = 20%),0表示未配置
|
|
|
|
|
+ */
|
|
|
|
|
+ public int getCategoryRatio(Long categoryId) {
|
|
|
|
|
+ if (categoryId == null) return 0;
|
|
|
|
|
+ Date now = new Date();
|
|
|
|
|
+ LambdaQueryWrapper<CategoryPpoint> wrapper = new LambdaQueryWrapper<CategoryPpoint>()
|
|
|
|
|
+ .eq(CategoryPpoint::getCategoryId, categoryId)
|
|
|
|
|
+ .le(CategoryPpoint::getStartDate, now)
|
|
|
|
|
+ .and(w -> w.isNull(CategoryPpoint::getEndDate).or().ge(CategoryPpoint::getEndDate, now))
|
|
|
|
|
+ .orderByDesc(CategoryPpoint::getStartDate)
|
|
|
|
|
+ .last("LIMIT 1");
|
|
|
|
|
+ CategoryPpoint record = categoryPpointMapper.selectOne(wrapper);
|
|
|
|
|
+ if (record != null && record.getRatio() != null && record.getRatio() > 0) {
|
|
|
|
|
+ return record.getRatio();
|
|
|
|
|
+ }
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 获取商品综合有效的P点值(优先商品级 → 品类级 → profitRate)
|
|
|
|
|
+ * @param productId 商品ID
|
|
|
|
|
+ * @param categoryId 商品品类ID(可为null)
|
|
|
|
|
+ * @return P点值
|
|
|
|
|
+ */
|
|
|
|
|
+ public int getEffectivePpoint(Long productId, Long categoryId) {
|
|
|
|
|
+ // 1. 商品级 ProductPpoint
|
|
|
|
|
+ Date now = new Date();
|
|
|
|
|
+ LambdaQueryWrapper<ProductPpoint> pw = new LambdaQueryWrapper<ProductPpoint>()
|
|
|
|
|
+ .eq(ProductPpoint::getProductId, productId)
|
|
|
|
|
+ .le(ProductPpoint::getStartDate, now)
|
|
|
|
|
+ .and(w -> w.isNull(ProductPpoint::getEndDate).or().ge(ProductPpoint::getEndDate, now))
|
|
|
|
|
+ .orderByDesc(ProductPpoint::getStartDate)
|
|
|
|
|
+ .last("LIMIT 1");
|
|
|
|
|
+ ProductPpoint productPpoint = productPpointMapper.selectOne(pw);
|
|
|
|
|
+ if (productPpoint != null && productPpoint.getPpoint() != null && productPpoint.getPpoint() > 0) {
|
|
|
|
|
+ return productPpoint.getPpoint();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 品类级比例(千分比)
|
|
|
|
|
+ if (categoryId != null) {
|
|
|
|
|
+ int categoryRatio = getCategoryRatio(categoryId);
|
|
|
|
|
+ if (categoryRatio > 0) {
|
|
|
|
|
+ return categoryRatio;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 3. 商品 profitRate 回退
|
|
|
|
|
+ Product product = productMapper.selectById(productId);
|
|
|
|
|
+ if (product != null && product.getProfitRate() != null) {
|
|
|
|
|
+ return product.getProfitRate() * 100;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // ======================== 品类级CRUD ========================
|
|
|
|
|
+
|
|
|
|
|
+ public void saveCategoryRatio(Long categoryId, Integer ratio, Date startDate, Date endDate, Long adminUserId) {
|
|
|
|
|
+ LambdaQueryWrapper<CategoryPpoint> wrapper = new LambdaQueryWrapper<CategoryPpoint>()
|
|
|
|
|
+ .eq(CategoryPpoint::getCategoryId, categoryId);
|
|
|
|
|
+ CategoryPpoint existing = categoryPpointMapper.selectOne(wrapper);
|
|
|
|
|
+ if (existing != null) {
|
|
|
|
|
+ existing.setRatio(ratio);
|
|
|
|
|
+ existing.setStartDate(startDate);
|
|
|
|
|
+ existing.setEndDate(endDate);
|
|
|
|
|
+ existing.setCreatedBy(adminUserId);
|
|
|
|
|
+ categoryPpointMapper.updateById(existing);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ CategoryPpoint record = new CategoryPpoint();
|
|
|
|
|
+ record.setCategoryId(categoryId);
|
|
|
|
|
+ record.setRatio(ratio);
|
|
|
|
|
+ record.setStartDate(startDate);
|
|
|
|
|
+ record.setEndDate(endDate);
|
|
|
|
|
+ record.setCreatedBy(adminUserId);
|
|
|
|
|
+ record.setCreatedAt(new Date());
|
|
|
|
|
+ categoryPpointMapper.insert(record);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public void deleteCategoryRatio(Long id) {
|
|
|
|
|
+ categoryPpointMapper.deleteById(id);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ public List<CategoryPpoint> getByCategoryId(Long categoryId) {
|
|
|
|
|
+ return categoryPpointMapper.selectList(
|
|
|
|
|
+ new LambdaQueryWrapper<CategoryPpoint>()
|
|
|
|
|
+ .eq(CategoryPpoint::getCategoryId, categoryId)
|
|
|
|
|
+ .orderByDesc(CategoryPpoint::getStartDate)
|
|
|
|
|
+ );
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 品类P点比例分页列表(带品类名称)
|
|
|
|
|
+ */
|
|
|
|
|
+ public Map<String, Object> adminCategoryList(Page<CategoryPpoint> pageParam, String keyword) {
|
|
|
|
|
+ LambdaQueryWrapper<CategoryPpoint> wrapper = new LambdaQueryWrapper<CategoryPpoint>()
|
|
|
|
|
+ .orderByDesc(CategoryPpoint::getCreatedAt);
|
|
|
|
|
+ Page<CategoryPpoint> page = categoryPpointMapper.selectPage(pageParam, wrapper);
|
|
|
|
|
+ List<CategoryPpoint> records = page.getRecords();
|
|
|
|
|
+
|
|
|
|
|
+ if (!records.isEmpty()) {
|
|
|
|
|
+ List<Long> categoryIds = records.stream()
|
|
|
|
|
+ .map(CategoryPpoint::getCategoryId)
|
|
|
|
|
+ .distinct()
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ // 品类名称查询(直接通过 product_categories 表获取品类名称)
|
|
|
|
|
+ Map<Long, String> categoryNames = new HashMap<>();
|
|
|
|
|
+ if (!categoryIds.isEmpty()) {
|
|
|
|
|
+ String ids = categoryIds.stream().map(String::valueOf).collect(Collectors.joining(","));
|
|
|
|
|
+ try {
|
|
|
|
|
+ List<Map<String, Object>> cats = categoryPpointMapper.selectMaps(
|
|
|
|
|
+ new LambdaQueryWrapper<com.etotem.cfc.entity.ProductCategory>()
|
|
|
|
|
+ .in(com.etotem.cfc.entity.ProductCategory::getId, categoryIds)
|
|
|
|
|
+ .select(com.etotem.cfc.entity.ProductCategory::getId, com.etotem.cfc.entity.ProductCategory::getName)
|
|
|
|
|
+ );
|
|
|
|
|
+ for (Map<String, Object> cat : cats) {
|
|
|
|
|
+ Object id = cat.get("id");
|
|
|
|
|
+ Object name = cat.get("name");
|
|
|
|
|
+ if (id != null && name != null) {
|
|
|
|
|
+ categoryNames.put(Long.valueOf(id.toString()), name.toString());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log.warn("查询品类名称失败: {}", e.getMessage());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ final Map<Long, String> nameMap = categoryNames;
|
|
|
|
|
+ List<Map<String, Object>> enriched = records.stream().map(r -> {
|
|
|
|
|
+ Map<String, Object> m = new HashMap<>();
|
|
|
|
|
+ m.put("id", r.getId());
|
|
|
|
|
+ m.put("categoryId", r.getCategoryId());
|
|
|
|
|
+ m.put("ratio", r.getRatio());
|
|
|
|
|
+ m.put("startDate", r.getStartDate());
|
|
|
|
|
+ m.put("endDate", r.getEndDate());
|
|
|
|
|
+ m.put("createdBy", r.getCreatedBy());
|
|
|
|
|
+ m.put("createdAt", r.getCreatedAt());
|
|
|
|
|
+ m.put("categoryName", nameMap.getOrDefault(r.getCategoryId(), "未知品类"));
|
|
|
|
|
+ return m;
|
|
|
|
|
+ }).collect(Collectors.toList());
|
|
|
|
|
+
|
|
|
|
|
+ // keyword 内存过滤
|
|
|
|
|
+ if (keyword != null && !keyword.trim().isEmpty()) {
|
|
|
|
|
+ String kw = keyword.trim().toLowerCase();
|
|
|
|
|
+ enriched = enriched.stream()
|
|
|
|
|
+ .filter(e -> e.get("categoryName") != null && e.get("categoryName").toString().toLowerCase().contains(kw))
|
|
|
|
|
+ .collect(Collectors.toList());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
|
|
+ result.put("records", enriched);
|
|
|
|
|
+ result.put("total", page.getTotal());
|
|
|
|
|
+ result.put("page", page.getCurrent());
|
|
|
|
|
+ result.put("size", page.getSize());
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ Map<String, Object> result = new HashMap<>();
|
|
|
|
|
+ result.put("records", records);
|
|
|
|
|
+ result.put("total", page.getTotal());
|
|
|
|
|
+ result.put("page", page.getCurrent());
|
|
|
|
|
+ result.put("size", page.getSize());
|
|
|
|
|
+ return result;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|