master:系统功能完善;

pull/1121/head
liujiang 2025-06-02 00:33:27 +08:00
parent 307155c359
commit c11ee0eb6b
36 changed files with 534 additions and 36 deletions

View File

@ -115,14 +115,14 @@ public class StoreController extends XktBaseController {
return R.ok(BeanUtil.toBean(storeService.indexTodaySaleRevenue(storeId), StoreIndexTodaySaleResVO.class));
}
@ApiOperation(value = "获取档口首页 商品销售额前10 ", httpMethod = "GET", response = R.class)
@GetMapping(value = "/index/sale/top10")
@ApiOperation(value = "获取档口首页 商品销售额前10 ", httpMethod = "POST", response = R.class)
@PostMapping(value = "/index/sale/top10")
public R<List<StoreIndexSaleTop10ResVO>> indexTop10Sale(@Validated @RequestBody StoreSaleTop10VO saleTop10VO) {
return R.ok(BeanUtil.copyToList(storeService.indexTop10Sale(BeanUtil.toBean(saleTop10VO, StoreSaleTop10DTO.class)), StoreIndexSaleTop10ResVO.class));
}
@ApiOperation(value = "获取档口首页 客户销售榜前10 ", httpMethod = "GET", response = R.class)
@GetMapping(value = "/index/sale-cus/top10")
@ApiOperation(value = "获取档口首页 客户销售榜前10 ", httpMethod = "POST", response = R.class)
@PostMapping(value = "/index/sale-cus/top10")
public R<List<StoreIndexCusSaleTop10ResVO>> indexTop10SaleCus(@Validated @RequestBody StoreSaleCustomerTop10VO saleCusTop10VO) {
return R.ok(BeanUtil.copyToList(storeService.indexTop10SaleCus(BeanUtil.toBean(saleCusTop10VO, StoreSaleCustomerTop10DTO.class)), StoreIndexCusSaleTop10ResVO.class));
}

View File

@ -59,31 +59,31 @@ public class StoreHomepageController extends XktBaseController {
}
@ApiOperation(value = "获取档口首页 模板一 数据", httpMethod = "GET", response = R.class)
@GetMapping(value = "/template-one/{storeId}")
@GetMapping(value = "/template/one/{storeId}")
public R<StoreHomeTemplateOneResVO> getTemplateOne(@PathVariable("storeId") Long storeId) {
return R.ok(BeanUtil.toBean(storeHomeService.getTemplateOne(storeId), StoreHomeTemplateOneResVO.class));
}
@ApiOperation(value = "获取档口首页 模板二 数据", httpMethod = "GET", response = R.class)
@GetMapping(value = "/template-two/{storeId}")
@GetMapping(value = "/template/two/{storeId}")
public R<StoreHomeTemplateTwoResVO> getTemplateTwo(@PathVariable("storeId") Long storeId) {
return R.ok(BeanUtil.toBean(storeHomeService.getTemplateTwo(storeId), StoreHomeTemplateTwoResVO.class));
}
@ApiOperation(value = "获取档口首页 模板三 数据", httpMethod = "GET", response = R.class)
@GetMapping(value = "/template-third/{storeId}")
@GetMapping(value = "/template/three/{storeId}")
public R<StoreHomeTemplateThirdResVO> getTemplateThird(@PathVariable("storeId") Long storeId) {
return R.ok(BeanUtil.toBean(storeHomeService.getTemplateThird(storeId), StoreHomeTemplateThirdResVO.class));
}
@ApiOperation(value = "获取档口首页 模板四 数据", httpMethod = "GET", response = R.class)
@GetMapping(value = "/template-four/{storeId}")
@GetMapping(value = "/template/four/{storeId}")
public R<StoreHomeTemplateFourResVO> getTemplateFour(@PathVariable("storeId") Long storeId) {
return R.ok(BeanUtil.toBean(storeHomeService.getTemplateFour(storeId), StoreHomeTemplateFourResVO.class));
}
@ApiOperation(value = "获取档口首页 模板五 数据", httpMethod = "GET", response = R.class)
@GetMapping(value = "/template-five/{storeId}")
@GetMapping(value = "/template/five/{storeId}")
public R<StoreHomeTemplateFiveResVO> getTemplateFive(@PathVariable("storeId") Long storeId) {
return R.ok(BeanUtil.toBean(storeHomeService.getTemplateFive(storeId), StoreHomeTemplateFiveResVO.class));
}

View File

@ -1,9 +1,19 @@
package com.ruoyi.web.controller.xkt;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.core.controller.XktBaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.web.controller.xkt.vo.userBrowsingHistory.UserBrowHisPageVO;
import com.ruoyi.xkt.dto.userBrowsingHistory.UserBrowHisPageDTO;
import com.ruoyi.xkt.dto.userBrowsingHistory.UserBrowsingHisPageResDTO;
import com.ruoyi.xkt.service.IUserBrowsingHistoryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@ -21,4 +31,10 @@ public class UserBrowsingHistoryController extends XktBaseController {
final IUserBrowsingHistoryService userBrowHisService;
@ApiOperation(value = "获取用户浏览足迹", httpMethod = "POST", response = R.class)
@PostMapping(value = "/page")
public R<Page<UserBrowsingHisPageResDTO>> page(@Validated @RequestBody UserBrowHisPageVO pageVO) {
return R.ok(userBrowHisService.page(BeanUtil.toBean(pageVO, UserBrowHisPageDTO.class)));
}
}

View File

@ -0,0 +1,35 @@
package com.ruoyi.web.controller.xkt;
import com.ruoyi.common.core.controller.XktBaseController;
import com.ruoyi.common.core.domain.R;
import com.ruoyi.xkt.service.IUserSearchHistoryService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* Controller
*
* @author ruoyi
* @date 2025-03-26
*/
@Api(tags = "用户搜索历史")
@RestController
@RequiredArgsConstructor
@RequestMapping("/rest/v1/user-search-his")
public class UserSearchHistoryController extends XktBaseController {
final IUserSearchHistoryService userSearchHisService;
@ApiOperation(value = "获取用户搜索历史", httpMethod = "GET", response = R.class)
@GetMapping(value = "")
public R<List<String>> recordList() {
return R.ok(userSearchHisService.recordList());
}
}

View File

@ -4,6 +4,7 @@ import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
/**
@ -17,6 +18,8 @@ public class StoreIndexTodaySaleResVO {
@ApiModelProperty(value = "档口ID")
private Long storeId;
@ApiModelProperty(value = "其它销售额")
private BigDecimal otherAmount;
@ApiModelProperty(value = "档口商品销售额列表")
List<SITSProdSaleVO> saleList;

View File

@ -0,0 +1,19 @@
package com.ruoyi.web.controller.xkt.vo.userBrowsingHistory;
import com.ruoyi.web.controller.xkt.vo.BasePageVO;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@EqualsAndHashCode(callSuper = true)
@ApiModel("用户浏览足迹分页")
@Data
public class UserBrowHisPageVO extends BasePageVO {
}

View File

@ -0,0 +1,35 @@
package com.ruoyi.web.controller.xkt.vo.userSearchHistory;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.util.Date;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("用户搜索记录")
@Data
@Accessors(chain = true)
public class UserSearchHistoryVO {
@ApiModelProperty(value = "用户搜索ID")
private Long id;
@ApiModelProperty(value = "用户ID")
private Long userId;
@ApiModelProperty(value = "用户名称")
private String userName;
@ApiModelProperty(value = "搜索内容")
private String searchContent;
@ApiModelProperty(value = "平台ID")
private Integer platformId;
@ApiModelProperty(value = "搜索时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date searchTime;
}

View File

@ -219,6 +219,10 @@ public class CacheConstants {
*
*/
public static final String USER_SEARCH_HISTORY = "user_search_history:";
/**
*
*/
public static final String USER_BROWSING_HISTORY = "user_browsing_history:";
/**
* 20
*/

View File

@ -264,6 +264,4 @@ public class Constants
*/
public static final Set<Integer> STORE_RECOMMEND_INSERT_POSITIONS = new HashSet<>(Arrays.asList(2, 9, 18, 27, 36));
}

View File

@ -125,6 +125,10 @@ public class SecurityConfig
.antMatchers("/rest/v1/sys/prod-cate/**").permitAll()
// 商品所有风格
.antMatchers("/rest/v1/prods/styles").permitAll()
// 档口首页模板
.antMatchers("/rest/v1/store-home/template/**").permitAll()
// 档口推荐
.antMatchers("/rest/v1/store-home/recommend/**").permitAll()
// TODO 临时放开 临时放开
@ -132,6 +136,8 @@ public class SecurityConfig
.antMatchers("/rest/v1/pic-search").permitAll()
.antMatchers("/rest/v1/stores/simple/**").permitAll()
.antMatchers("/rest/v1/prods/status/num/**").permitAll()
.antMatchers("/rest/v1/prods/status/num/**").permitAll()
.antMatchers("/rest/v1/prods/pc/detail/**").permitAll()
// 除上面外的所有请求全部需要鉴权认证

View File

@ -30,6 +30,7 @@ import com.ruoyi.xkt.dto.order.StoreOrderCancelDTO;
import com.ruoyi.xkt.dto.order.StoreOrderRefund;
import com.ruoyi.xkt.dto.storeProductFile.StoreProdFileLatestFourProdDTO;
import com.ruoyi.xkt.dto.useSearchHistory.UserSearchHistoryDTO;
import com.ruoyi.xkt.dto.userBrowsingHistory.UserBrowsingHisDTO;
import com.ruoyi.xkt.enums.*;
import com.ruoyi.xkt.manager.PaymentManager;
import com.ruoyi.xkt.mapper.*;
@ -95,6 +96,7 @@ public class XktTask {
final StoreProductStatisticsMapper storeProdStatMapper;
final StoreProductFileMapper storeProdFileMapper;
final UserSearchHistoryMapper userSearchHisMapper;
final UserBrowsingHistoryMapper userBrowHisMapper;
/**
*
@ -592,21 +594,62 @@ public class XktTask {
});
// 用户最新搜索列表
List<UserSearchHistoryDTO> insertSearchList = redisSearchList.stream().filter(x -> ObjectUtils.isEmpty(x.getId())).collect(Collectors.toList());
if (CollectionUtils.isEmpty(insertSearchList)) {
return;
if (CollectionUtils.isNotEmpty(insertSearchList)) {
this.userSearchHisMapper.insert(BeanUtil.copyToList(insertSearchList, UserSearchHistory.class));
}
this.userSearchHisMapper.insert(BeanUtil.copyToList(insertSearchList, UserSearchHistory.class));
final Date sixMonthAgo = java.sql.Date.valueOf(LocalDate.now().minusMonths(6));
final Date now = java.sql.Date.valueOf(LocalDate.now());
// 将最新的数据更新到redis中
List<UserSearchHistory> latestSearchList = this.userSearchHisMapper.selectList(new LambdaQueryWrapper<UserSearchHistory>()
.eq(UserSearchHistory::getDelFlag, Constants.UNDELETED));
.eq(UserSearchHistory::getDelFlag, Constants.UNDELETED).between(UserSearchHistory::getSearchTime, sixMonthAgo, now));
if (CollectionUtils.isEmpty(latestSearchList)) {
return;
}
latestSearchList.stream().collect(Collectors.groupingBy(UserSearchHistory::getUserId))
.forEach((userId, list) -> {
// 获取用户最新搜索的20条数据
list = list.stream().sorted(Comparator.comparing(UserSearchHistory::getSearchTime).reversed()).limit(20).collect(Collectors.toList());
// 反转列表
Collections.reverse(list);
redisCache.setCacheObject(CacheConstants.USER_SEARCH_HISTORY + userId, BeanUtil.copyToList(list, UserSearchHistoryDTO.class));
});
}
/**
* 2:05
*/
@Transactional
public void dailyUpdateUserBrowsingHistory() {
Collection<String> keyList = this.redisCache.scanKeys(CacheConstants.USER_BROWSING_HISTORY + "*");
if (CollectionUtils.isEmpty(keyList)) {
return;
}
List<UserBrowsingHisDTO> redisBrowsingList = new ArrayList<>();
keyList.forEach(key -> {
List<UserBrowsingHisDTO> tempList = this.redisCache.getCacheObject(key);
CollectionUtils.addAll(redisBrowsingList, tempList);
});
// 用户最新浏览列表
List<UserBrowsingHisDTO> insertBrowsingList = redisBrowsingList.stream().filter(x -> ObjectUtils.isEmpty(x.getId())).collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(insertBrowsingList)) {
this.userBrowHisMapper.insert(BeanUtil.copyToList(insertBrowsingList, UserBrowsingHistory.class));
}
final Date sixMonthAgo = java.sql.Date.valueOf(LocalDate.now().minusMonths(6));
final Date now = java.sql.Date.valueOf(LocalDate.now());
// 将最新的数据更新到redis中
List<UserBrowsingHistory> latestBrowsingList = this.userBrowHisMapper.selectList(new LambdaQueryWrapper<UserBrowsingHistory>()
.eq(UserBrowsingHistory::getDelFlag, Constants.UNDELETED).between(UserBrowsingHistory::getBrowsingTime, sixMonthAgo, now));
if (CollectionUtils.isEmpty(latestBrowsingList)) {
return;
}
latestBrowsingList.stream().collect(Collectors.groupingBy(x -> x.getUserId()))
.forEach((userId, list) -> {
// 按照浏览时间升序排
list.sort(Comparator.comparing(UserBrowsingHistory::getBrowsingTime));
redisCache.setCacheObject(CacheConstants.USER_BROWSING_HISTORY + userId, BeanUtil.copyToList(list, UserBrowsingHisDTO.class));
});
}
/**
* 3redis
*/

View File

@ -50,7 +50,7 @@
</select>
<select id="voucherDateEnd" resultType="com.ruoyi.xkt.dto.store.StoreIndexSaleTop10ResDTO">
<select id="selectTop10SaleList" resultType="com.ruoyi.xkt.dto.store.StoreIndexSaleTop10ResDTO">
SELECT
dsp.store_prod_id,
dsp.prod_art_num,

View File

@ -57,8 +57,8 @@ public class UserBrowsingHistory extends XktBaseEntity {
*/
private BigDecimal price;
/**
*
*
*/
private Date voucherDate;
private Date browsingTime;
}

View File

@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.List;
/**
@ -27,6 +28,10 @@ public class APPIndexHotSaleDTO {
private String prodArtNum;
@ApiModelProperty(value = "主图")
private String mainPicUrl;
@ApiModelProperty(value = "主图名称")
private String mainPicName;
@ApiModelProperty(value = "主图大小")
private BigDecimal mainPicSize;
@ApiModelProperty(value = "单价")
private String prodPrice;
@ApiModelProperty(value = "标题")

View File

@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.List;
/**
@ -27,6 +28,10 @@ public class APPIndexNewProdDTO {
private String prodArtNum;
@ApiModelProperty(value = "主图")
private String mainPicUrl;
@ApiModelProperty(value = "主图名称")
private String mainPicName;
@ApiModelProperty(value = "主图大小")
private BigDecimal mainPicSize;
@ApiModelProperty(value = "单价")
private String prodPrice;
@ApiModelProperty(value = "是否广告")

View File

@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.List;
/**
@ -27,6 +28,10 @@ public class APPIndexPopularSaleDTO {
private String prodArtNum;
@ApiModelProperty(value = "主图")
private String mainPicUrl;
@ApiModelProperty(value = "主图名称")
private String mainPicName;
@ApiModelProperty(value = "主图大小")
private BigDecimal mainPicSize;
@ApiModelProperty(value = "单价")
private String prodPrice;
@ApiModelProperty(value = "是否广告")

View File

@ -6,6 +6,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.List;
/**
@ -29,6 +30,10 @@ public class APPSearchDTO {
private String prodArtNum;
@ApiModelProperty(value = "主图")
private String mainPicUrl;
@ApiModelProperty(value = "主图名称")
private String mainPicName;
@ApiModelProperty(value = "主图大小")
private BigDecimal mainPicSize;
@ApiModelProperty(value = "单价")
private String prodPrice;
@ApiModelProperty(value = "是否广告")

View File

@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.List;
/**
@ -27,6 +28,10 @@ public class PCSearchDTO {
private String prodArtNum;
@ApiModelProperty(value = "主图")
private String mainPicUrl;
@ApiModelProperty(value = "主图名称")
private String mainPicName;
@ApiModelProperty(value = "主图大小")
private BigDecimal mainPicSize;
@ApiModelProperty(value = "单价")
private String prodPrice;
@ApiModelProperty(value = "是否广告")

View File

@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.List;
/**
@ -31,6 +32,10 @@ public class PCIndexRecommendDTO {
private String prodArtNum;
@ApiModelProperty(value = "主图")
private String mainPicUrl;
@ApiModelProperty(value = "主图名称")
private String mainPicName;
@ApiModelProperty(value = "主图大小")
private BigDecimal mainPicSize;
@ApiModelProperty(value = "单价")
private String prodPrice;
@ApiModelProperty(value = "是否广告")

View File

@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.List;
/**
@ -31,6 +32,10 @@ public class PCNewRecommendDTO {
private String prodArtNum;
@ApiModelProperty(value = "主图")
private String mainPicUrl;
@ApiModelProperty(value = "主图名称")
private String mainPicName;
@ApiModelProperty(value = "主图大小")
private BigDecimal mainPicSize;
@ApiModelProperty(value = "单价")
private String prodPrice;
@ApiModelProperty(value = "是否广告")

View File

@ -5,6 +5,7 @@ import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.List;
/**
@ -37,6 +38,10 @@ public class ESProductDTO {
private String createTime;
@ApiModelProperty(value = "主图")
private String mainPicUrl;
@ApiModelProperty(value = "主图名称")
private String mainPicName;
@ApiModelProperty(value = "主图大小")
private BigDecimal mainPicSize;
@ApiModelProperty(value = "上级分类名称")
private String parCateName;
@ApiModelProperty(value = "上级分类ID")

View File

@ -27,6 +27,8 @@ public class StoreProdAppResDTO {
private Long storeProdId;
@ApiModelProperty(value = "档口ID")
private Long storeId;
@ApiModelProperty(value = "档口名称")
private String storeName;
@ApiModelProperty(value = "档口商品名称")
private String prodName;
@ApiModelProperty(value = "商品货号")

View File

@ -20,6 +20,10 @@ import java.util.List;
@Accessors(chain = true)
public class StoreProdPCResDTO {
@ApiModelProperty(value = "档口ID")
private Long storeId;
@ApiModelProperty(value = "档口名称")
private String storeName;
@ApiModelProperty(value = "档口商品ID")
private Long storeProdId;
@ApiModelProperty(value = "商品货号")

View File

@ -38,6 +38,10 @@ public class StoreProdPriceAndMainPicAndTagDTO {
private BigDecimal minPrice;
@ApiModelProperty(value = "档口商品主图")
private String mainPicUrl;
@ApiModelProperty(value = "主图名称")
private String mainPicName;
@ApiModelProperty(value = "主图大小")
private BigDecimal mainPicSize;
@ApiModelProperty(value = "商品标题")
private String prodTitle;
@ApiModelProperty(value = "是否有主图视频")

View File

@ -0,0 +1,19 @@
package com.ruoyi.xkt.dto.userBrowsingHistory;
import com.ruoyi.xkt.dto.BasePageDTO;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@EqualsAndHashCode(callSuper = true)
@ApiModel("用户浏览足迹分页")
@Data
public class UserBrowHisPageDTO extends BasePageDTO {
}

View File

@ -0,0 +1,43 @@
package com.ruoyi.xkt.dto.userBrowsingHistory;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("用户浏览历史")
@Data
@Accessors(chain = true)
public class UserBrowsingHisDTO {
@ApiModelProperty(value = "浏览历史ID")
private Long id;
@ApiModelProperty(value = "用户ID")
private Long userId;
@ApiModelProperty(value = "档口ID")
private Long storeId;
@ApiModelProperty(value = "档口名称")
private String storeName;
@ApiModelProperty(value = "档口商品ID")
private Long storeProdId;
@ApiModelProperty(value = "档口商品标题")
private String prodTitle;
@ApiModelProperty(value = "档口商品主图url")
private String mainPicUrl;
@ApiModelProperty(value = "商品货号")
private String prodArtNum;
@ApiModelProperty(value = "商品价格")
private BigDecimal prodPrice;
@ApiModelProperty(value = "浏览日期")
private Date browsingTime;
}

View File

@ -0,0 +1,42 @@
package com.ruoyi.xkt.dto.userBrowsingHistory;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.math.BigDecimal;
import java.util.Date;
/**
* @author liujiang
* @version v1.0
* @date 2025/3/27 15:12
*/
@ApiModel("用户浏览历史")
@Data
@Accessors(chain = true)
public class UserBrowsingHisPageResDTO {
@ApiModelProperty(value = "浏览历史ID")
private Long id;
@ApiModelProperty(value = "档口ID")
private Long storeId;
@ApiModelProperty(value = "档口名称")
private String storeName;
@ApiModelProperty(value = "档口商品ID")
private Long storeProdId;
@ApiModelProperty(value = "档口商品标题")
private String prodTitle;
@ApiModelProperty(value = "档口商品主图url")
private String mainPicUrl;
@ApiModelProperty(value = "商品货号")
private String prodArtNum;
@ApiModelProperty(value = "商品价格")
private BigDecimal prodPrice;
@ApiModelProperty(value = "浏览日期")
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
private Date browsingTime;
}

View File

@ -1,15 +1,23 @@
package com.ruoyi.xkt.service;
import com.ruoyi.xkt.domain.UserBrowsingHistory;
import java.util.List;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.xkt.dto.userBrowsingHistory.UserBrowHisPageDTO;
import com.ruoyi.xkt.dto.userBrowsingHistory.UserBrowsingHisPageResDTO;
/**
* Service
* Service
*
* @author ruoyi
* @date 2025-03-26
*/
public interface IUserBrowsingHistoryService {
/**
*
*
* @param pageDTO
* @return Page<UserBrowsingHisResDTO>
*/
Page<UserBrowsingHisPageResDTO> page(UserBrowHisPageDTO pageDTO);
}

View File

@ -0,0 +1,19 @@
package com.ruoyi.xkt.service;
import java.util.List;
/**
* Service
*
* @author ruoyi
* @date 2025-03-26
*/
public interface IUserSearchHistoryService {
/**
*
*
* @return List<String>
*/
List<String> recordList();
}

View File

@ -16,9 +16,11 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.constant.HttpStatus;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
@ -39,6 +41,7 @@ import com.ruoyi.xkt.dto.storeProduct.*;
import com.ruoyi.xkt.dto.storeProductFile.StoreProdFileDTO;
import com.ruoyi.xkt.dto.storeProductFile.StoreProdFileResDTO;
import com.ruoyi.xkt.dto.storeProductFile.StoreProdMainPicDTO;
import com.ruoyi.xkt.dto.userBrowsingHistory.UserBrowsingHisDTO;
import com.ruoyi.xkt.enums.EProductStatus;
import com.ruoyi.xkt.enums.FileType;
import com.ruoyi.xkt.enums.ListingType;
@ -96,6 +99,7 @@ public class StoreProductServiceImpl implements IStoreProductService {
final IPictureService pictureService;
final StoreProductStatisticsMapper storeProductStatisticsMapper;
final StoreHomepageMapper storeHomepageMapper;
final RedisCache redisCache;
/**
@ -552,6 +556,17 @@ public class StoreProductServiceImpl implements IStoreProductService {
List<StoreProductColorSize> colorSizeList = this.storeProdColorSizeMapper.selectList(new LambdaQueryWrapper<StoreProductColorSize>()
.eq(StoreProductColorSize::getStoreProdId, storeProdId).eq(StoreProductColorSize::getDelFlag, Constants.UNDELETED)
.eq(StoreProductColorSize::getStandard, ProductSizeStatus.STANDARD.getValue()));
List<StoreProdFileResDTO> fileList = this.storeProdFileMapper.selectVideoAndMainPicList(storeProdId);
// 第一张商品主图
final String mainPicUrl = fileList.stream().filter(x -> Objects.equals(x.getFileType(), FileType.MAIN_PIC.getValue()))
.filter(x -> Objects.equals(x.getOrderNum(), ORDER_NUM_1)).map(StoreProdFileResDTO::getFileUrl).findAny().orElse("");
// 将用户浏览足迹添加到redis中
try {
this.updateUserBrowsingToRedis(storeProdId, appResDTO.getStoreId(), appResDTO.getStoreName(), appResDTO.getProdArtNum(),
appResDTO.getProdTitle(), appResDTO.getMinPrice(), mainPicUrl);
} catch (Exception e) {
e.printStackTrace();
}
return appResDTO.setTags(StringUtils.isNotBlank(appResDTO.getTagStr()) ? StrUtil.split(appResDTO.getTagStr(), ",") : null)
// 拼接几色几码
.setSpecification((CollectionUtils.isNotEmpty(colorList) ? colorList.size() + "色" : "") +
@ -559,7 +574,7 @@ public class StoreProductServiceImpl implements IStoreProductService {
// 获取商品的属性
.setCateAttr(BeanUtil.toBean(cateAttr, StoreProdCateAttrDTO.class))
// 获取商品的主图视频及主图
.setFileList(this.storeProdFileMapper.selectVideoAndMainPicList(storeProdId))
.setFileList(fileList)
// 获取商品的服务承诺
.setSvc(this.storeProdSvcMapper.selectSvc(storeProdId));
}
@ -640,14 +655,25 @@ public class StoreProductServiceImpl implements IStoreProductService {
@Override
@Transactional(readOnly = true)
public StoreProdPCResDTO getPCInfo(Long storeProdId) {
// TODO 去掉
// TODO 去掉
// TODO 去掉
// TODO 去掉
final Long userId = 1L;
// 商品基础信息
StoreProdPCResDTO prodInfoDTO = ObjectUtils.defaultIfNull(this.storeProdMapper.selectPCProdInfo(storeProdId, SecurityUtils.getUserId()), new StoreProdPCResDTO());
StoreProdPCResDTO prodInfoDTO = ObjectUtils.defaultIfNull(this.storeProdMapper.selectPCProdInfo(storeProdId, 1L), new StoreProdPCResDTO());
// StoreProdPCResDTO prodInfoDTO = ObjectUtils.defaultIfNull(this.storeProdMapper.selectPCProdInfo(storeProdId, SecurityUtils.getUserId()), new StoreProdPCResDTO());
// 获取商品的属性
StoreProductCategoryAttribute cateAttr = this.storeProdCateAttrMapper.selectOne(new LambdaQueryWrapper<StoreProductCategoryAttribute>()
.eq(StoreProductCategoryAttribute::getStoreProdId, storeProdId).eq(StoreProductCategoryAttribute::getDelFlag, Constants.UNDELETED));
List<StoreProdFileResDTO> fileList = this.storeProdFileMapper.selectVideoAndMainPicList(storeProdId);
prodInfoDTO.setCateAttr(BeanUtil.toBean(cateAttr, StoreProdPCResDTO.StoreProdCateAttrDTO.class))
// 获取商品的主图视频及主图
.setFileList(this.storeProdFileMapper.selectVideoAndMainPicList(storeProdId));
.setFileList(fileList);
// 档口商品的sku列表
List<StoreProdSkuDTO> prodSkuList = this.storeProdMapper.selectSkuList(storeProdId);
if (CollectionUtils.isEmpty(prodSkuList)) {
@ -667,6 +693,15 @@ public class StoreProductServiceImpl implements IStoreProductService {
.setStock(colorSizeStockMap.get(color.getStoreColorId() + ":" + size.getSize())))
.collect(Collectors.toList()));
});
final BigDecimal minPrice = Objects.requireNonNull(colorList.stream().min(Comparator.comparing(StoreProdSkuItemDTO::getPrice)).orElse(null)).getPrice();
final String mainPicUrl = fileList.stream().filter(x -> Objects.equals(x.getFileType(), FileType.MAIN_PIC.getValue()))
.filter(x -> Objects.equals(x.getOrderNum(), ORDER_NUM_1)).map(StoreProdFileResDTO::getFileUrl).findAny().orElse("");
// 将用户浏览足迹添加到redis中
try {
this.updateUserBrowsingToRedis(storeProdId, prodInfoDTO.getStoreId(), prodInfoDTO.getStoreName(), prodInfoDTO.getProdArtNum(), prodInfoDTO.getProdTitle(), minPrice, mainPicUrl);
} catch (Exception e) {
e.printStackTrace();
}
return prodInfoDTO.setColorList(colorList);
}
@ -935,4 +970,30 @@ public class StoreProductServiceImpl implements IStoreProductService {
}
/**
* Redis
* Redis便
*
* @param storeProdId ID
* @param storeId ID
* @param storeName
* @param prodArtNum
* @param prodTitle
* @param minPrice
* @param mainPicUrl URL
*/
private void updateUserBrowsingToRedis(Long storeProdId, Long storeId, String storeName, String prodArtNum, String prodTitle, BigDecimal minPrice, String mainPicUrl) {
final Long userId = SecurityUtils.getUserId();
if (ObjectUtils.isEmpty(userId)) {
return;
}
List<UserBrowsingHisDTO> browsingList = CollUtil.defaultIfEmpty(this.redisCache
.getCacheList(CacheConstants.USER_BROWSING_HISTORY + SecurityUtils.getUserId()), new ArrayList<>());
browsingList.add(new UserBrowsingHisDTO().setUserId(userId).setProdArtNum(prodArtNum).setProdTitle(prodTitle)
.setStoreId(storeId).setStoreName(storeName).setProdPrice(minPrice).setMainPicUrl(mainPicUrl)
.setBrowsingTime(new Date()).setStoreProdId(storeProdId));
this.redisCache.setCacheObject(CacheConstants.USER_BROWSING_HISTORY + SecurityUtils.getUserId(), browsingList);
}
}

View File

@ -1,14 +1,22 @@
package com.ruoyi.xkt.service.impl;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.xkt.domain.UserBrowsingHistory;
import com.ruoyi.xkt.mapper.UserBrowsingHistoryMapper;
import cn.hutool.core.bean.BeanUtil;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.page.Page;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.xkt.dto.userBrowsingHistory.UserBrowHisPageDTO;
import com.ruoyi.xkt.dto.userBrowsingHistory.UserBrowsingHisDTO;
import com.ruoyi.xkt.dto.userBrowsingHistory.UserBrowsingHisPageResDTO;
import com.ruoyi.xkt.service.IUserBrowsingHistoryService;
import org.springframework.beans.factory.annotation.Autowired;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* Service
@ -17,9 +25,33 @@ import java.util.List;
* @date 2025-03-26
*/
@Service
@RequiredArgsConstructor
public class UserBrowsingHistoryServiceImpl implements IUserBrowsingHistoryService {
final RedisCache redisCache;
/**
*
*
* @param pageDTO
* @return Page<UserBrowsingHisResDTO>
*/
@Override
@Transactional(readOnly = true)
public Page<UserBrowsingHisPageResDTO> page(UserBrowHisPageDTO pageDTO) {
// 从redis获取所有的浏览足迹
List<UserBrowsingHisDTO> redisList = this.redisCache.getCacheObject(CacheConstants.USER_BROWSING_HISTORY + SecurityUtils.getUserId());
if (CollectionUtils.isEmpty(redisList)) {
return Page.empty(pageDTO.getPageSize(), pageDTO.getPageNum());
}
// 按照浏览时间倒序排
redisList.sort(Comparator.comparing(UserBrowsingHisDTO::getBrowsingTime).reversed());
List<UserBrowsingHisPageResDTO> page = redisList.stream().sorted(Comparator.comparing(UserBrowsingHisDTO::getBrowsingTime).reversed())
.skip((long) (pageDTO.getPageNum() - 1) * pageDTO.getPageSize()).limit(pageDTO.getPageSize())
.map(x -> BeanUtil.toBean(x, UserBrowsingHisPageResDTO.class))
.collect(Collectors.toList());
final long pages = (long) Math.ceil((double) redisList.size() / pageDTO.getPageSize());
return new Page<>(pageDTO.getPageNum(), pageDTO.getPageSize(), pages, redisList.size(), page);
}
}

View File

@ -0,0 +1,37 @@
package com.ruoyi.xkt.service.impl;
import com.ruoyi.common.constant.CacheConstants;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.xkt.dto.useSearchHistory.UserSearchHistoryDTO;
import com.ruoyi.xkt.service.IUserSearchHistoryService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/**
* Service
*
* @author ruoyi
* @date 2025-03-26
*/
@Service
@RequiredArgsConstructor
public class UserSearchHistoryServiceImpl implements IUserSearchHistoryService {
final RedisCache redisCache;
@Override
@Transactional(readOnly = true)
public List<String> recordList() {
List<UserSearchHistoryDTO> redisList = this.redisCache.getCacheObject(CacheConstants.USER_SEARCH_HISTORY + SecurityUtils.getUserId());
// 按照搜索时间倒序排列,最新的搜索数据展示在最前面
return redisList.stream().sorted(Comparator.comparing(UserSearchHistoryDTO::getSearchTime).reversed())
.map(UserSearchHistoryDTO::getSearchContent).collect(Collectors.toList());
}
}

View File

@ -116,7 +116,9 @@ public class WebsiteAPPServiceImpl implements IWebsiteAPPService {
.setStoreName(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getStoreName() : "")
.setProdPrice(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMinPrice().toString() : null)
.setProdArtNum(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getProdArtNum() : "")
.setMainPicUrl(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicUrl() : "");
.setMainPicUrl(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicUrl() : "")
.setMainPicName(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicName() : "")
.setMainPicSize(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicSize() : null);
}).collect(Collectors.toList());
// 放到redis中 有效期1天
this.redisCache.setCacheObject(CacheConstants.APP_INDEX_HOT_SALE_ADVERT, hotSaleList, 1, TimeUnit.DAYS);
@ -170,7 +172,9 @@ public class WebsiteAPPServiceImpl implements IWebsiteAPPService {
.setStoreName(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getStoreName() : "")
.setProdPrice(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMinPrice().toString() : null)
.setProdArtNum(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getProdArtNum() : "")
.setMainPicUrl(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicUrl() : "");
.setMainPicUrl(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicUrl() : "")
.setMainPicName(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicName() : "")
.setMainPicSize(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicSize() : null);
}).collect(Collectors.toList());
// 放到redis中 有效期1天
this.redisCache.setCacheObject(CacheConstants.APP_INDEX_POPULAR_SALE_ADVERT, popularSaleList, 1, TimeUnit.DAYS);
@ -224,7 +228,9 @@ public class WebsiteAPPServiceImpl implements IWebsiteAPPService {
.setStoreName(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getStoreName() : "")
.setProdPrice(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMinPrice().toString() : null)
.setProdArtNum(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getProdArtNum() : "")
.setMainPicUrl(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicUrl() : "");
.setMainPicUrl(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicUrl() : "")
.setMainPicName(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicName() : "")
.setMainPicSize(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicSize() : null);
}).collect(Collectors.toList());
// 放到redis中 有效期1天
this.redisCache.setCacheObject(CacheConstants.APP_INDEX_NEW_PROD, newProdList, 1, TimeUnit.DAYS);
@ -245,7 +251,11 @@ public class WebsiteAPPServiceImpl implements IWebsiteAPPService {
@Transactional(readOnly = true)
public Page<APPSearchDTO> appSearchPage(IndexSearchDTO searchDTO) throws IOException {
// 更新用户搜索历史
updateRedisUserSearchHistory(searchDTO.getSearch());
try {
updateRedisUserSearchHistory(searchDTO.getSearch());
} catch (Exception e) {
e.printStackTrace();
}
// 用户搜索结果
Page<ESProductDTO> page = this.search(searchDTO);
// 筛选出真实的数据
@ -281,7 +291,9 @@ public class WebsiteAPPServiceImpl implements IWebsiteAPPService {
.setStoreName(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getStoreName() : "")
.setProdPrice(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMinPrice().toString() : null)
.setProdArtNum(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getProdArtNum() : "")
.setMainPicUrl(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicUrl() : "");
.setMainPicUrl(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicUrl() : "")
.setMainPicName(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicName() : "")
.setMainPicSize(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicSize() : null);
}).collect(Collectors.toList());
// 放到redis中 有效期1天
this.redisCache.setCacheObject(CacheConstants.APP_SEARCH, newProdList, 1, TimeUnit.DAYS);

View File

@ -144,6 +144,8 @@ public class WebsitePCServiceImpl implements IWebsitePCService {
.setProdPrice(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMinPrice().toString() : null)
.setProdArtNum(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getProdArtNum() : "")
.setMainPicUrl(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicUrl() : "")
.setMainPicName(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicName() : "")
.setMainPicSize(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicSize() : null)
.setTags(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getTags() : null));
});
});
@ -218,6 +220,8 @@ public class WebsitePCServiceImpl implements IWebsitePCService {
.setProdPrice(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMinPrice().toString() : null)
.setProdArtNum(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getProdArtNum() : "")
.setMainPicUrl(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicUrl() : "")
.setMainPicName(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicName() : "")
.setMainPicSize(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getMainPicSize() : null)
.setTags(ObjectUtils.isNotEmpty(attrDto) ? attrDto.getTags() : null));
});
});
@ -247,7 +251,11 @@ public class WebsitePCServiceImpl implements IWebsitePCService {
@Transactional(readOnly = true)
public Page<PCSearchDTO> psSearchPage(IndexSearchDTO searchDTO) throws IOException {
// 更新用户搜索历史
updateRedisUserSearchHistory(searchDTO.getSearch());
try {
updateRedisUserSearchHistory(searchDTO.getSearch());
} catch (Exception e) {
e.printStackTrace();
}
// 获取用户搜索结果列表
Page<ESProductDTO> page = this.search(searchDTO);
// 筛选出真实的数据

View File

@ -138,6 +138,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
spf.store_prod_id,
spf.file_id,
sf.file_url,
sf.file_name,
sf.file_size,
spf.file_type,
spf.order_num
FROM

View File

@ -114,6 +114,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
spc.parent_id AS parCateId,
sp.prod_art_num AS prodArtNum,
sf.file_url AS mainPicUrl,
sf.file_name AS mainPicName,
sf.file_size AS mainPicSize,
sp.prod_title,
MIN( spcp.price ) AS minPrice,
sp.store_id,
@ -217,6 +219,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<select id="selectPCProdInfo" resultType="com.ruoyi.xkt.dto.storeProduct.StoreProdPCResDTO">
SELECT
s.id AS store_id,
s.store_name,
sp.id AS storeProdId,
sp.prod_art_num,
sp.prod_title,
@ -227,6 +231,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
FROM
store_product sp
LEFT JOIN store_product_detail spd ON sp.id = spd.store_prod_id AND spd.del_flag = 0
LEFT JOIN store s ON sp.store_id = s.id
WHERE
sp.del_flag = 0
AND sp.id = #{storeProdId}
@ -271,6 +276,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
SELECT DISTINCT
sp.id AS storeProdId,
sp.store_id,
s.store_name,
sp.prod_name,
sp.prod_art_num,
sp.prod_title,