推荐商品类型-包括促销推荐

This commit is contained in:
XinWei 2024-09-27 13:55:01 +08:00
parent b973bee0b3
commit 7728cc456a
12 changed files with 237 additions and 2 deletions

View File

@ -86,7 +86,7 @@
"source.fixAll.eslint": "explicit" "source.fixAll.eslint": "explicit"
}, },
"[vue]": { "[vue]": {
"editor.defaultFormatter": "rvest.vs-code-prettier-eslint" "editor.defaultFormatter": "Vue.volar"
}, },
"i18n-ally.localesPaths": ["src/locales"], "i18n-ally.localesPaths": ["src/locales"],
"i18n-ally.keystyle": "nested", "i18n-ally.keystyle": "nested",

View File

@ -17,6 +17,43 @@
<el-radio :label="true">多规格</el-radio> <el-radio :label="true">多规格</el-radio>
</el-radio-group> </el-radio-group>
</el-form-item> </el-form-item>
<el-form-item label="商品推荐">
<el-checkbox
v-model="formData.recommendHot"
:true-value="1"
:false-value="0"
name="productRecommend">
热卖单品
</el-checkbox>
<el-checkbox
v-model="formData.recommendBenefit"
:true-value="1"
:false-value="0"
name="productRecommend">
促销单品
</el-checkbox>
<el-checkbox
v-model="formData.recommendBest"
:true-value="1"
:false-value="0"
name="productRecommend">
精品推荐
</el-checkbox>
<el-checkbox
v-model="formData.recommendNew"
:true-value="1"
:false-value="0"
name="productRecommend">
新品单品
</el-checkbox>
<el-checkbox
v-model="formData.recommendGood"
:true-value="1"
:false-value="0"
name="productRecommend">
优品推荐
</el-checkbox>
</el-form-item>
<!-- 多规格添加--> <!-- 多规格添加-->
<el-form-item v-if="!formData.specType"> <el-form-item v-if="!formData.specType">
<SkuList <SkuList
@ -109,6 +146,11 @@ const skuListRef = ref() // 商品属性列表 Ref
const formData = reactive<Spu>({ const formData = reactive<Spu>({
specType: false, // specType: false, //
subCommissionType: false, // subCommissionType: false, //
recommendHot: 0, //
recommendBenefit: 0, //
recommendBest: 0, //
recommendNew: 0, //
recommendGood: 0, //
skus: [] skus: []
}) })
const rules = reactive({ const rules = reactive({

View File

@ -92,6 +92,11 @@ const formData = ref<ProductSpuApi.Spu>({
brandId: undefined, // brandId: undefined, //
specType: false, // specType: false, //
subCommissionType: false, // subCommissionType: false, //
recommendHot: 0, //
recommendBenefit: 0, //
recommendBest: 0, //
recommendNew: 0, //
recommendGood: 0, //
skus: [ skus: [
{ {
price: 0, // price: 0, //
@ -141,6 +146,7 @@ const getDetail = async () => {
} }
}) })
formData.value = res formData.value = res
} finally { } finally {
formLoading.value = false formLoading.value = false
} }

View File

@ -53,4 +53,6 @@ public interface ErrorCodeConstants {
ErrorCode FAVORITE_EXISTS = new ErrorCode(1_008_008_000, "该商品已经被收藏"); ErrorCode FAVORITE_EXISTS = new ErrorCode(1_008_008_000, "该商品已经被收藏");
ErrorCode FAVORITE_NOT_EXISTS = new ErrorCode(1_008_008_001, "商品收藏不存在"); ErrorCode FAVORITE_NOT_EXISTS = new ErrorCode(1_008_008_001, "商品收藏不存在");
ErrorCode PARAMETER_ERROR = new ErrorCode(1_008_008_002, "参数错误");
} }

View File

@ -6,6 +6,9 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils; import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.*;
import cn.iocoder.yudao.module.product.controller.app.spu.AppProductSpuController;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuRecommendPageReqVo;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuRespVO;
import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert; import cn.iocoder.yudao.module.product.convert.spu.ProductSpuConvert;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
@ -87,7 +90,13 @@ public class ProductSpuController {
} }
// 查询商品 SKU // 查询商品 SKU
List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spu.getId()); List<ProductSkuDO> skus = productSkuService.getSkuListBySpuId(spu.getId());
return success(ProductSpuConvert.INSTANCE.convert(spu, skus)); ProductSpuRespVO convert = ProductSpuConvert.INSTANCE.convert(spu, skus);
convert.setRecommendHot(spu.getRecommendHot());
convert.setRecommendBenefit(spu.getRecommendBenefit());
convert.setRecommendBest(spu.getRecommendBest());
convert.setRecommendNew(spu.getRecommendNew());
convert.setRecommendGood(spu.getRecommendGood());
return success(convert);
} }
@GetMapping("/list-all-simple") @GetMapping("/list-all-simple")

View File

@ -9,6 +9,7 @@ import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data; import lombok.Data;
import javax.validation.Valid;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.util.List; import java.util.List;
@ -65,6 +66,25 @@ public class ProductSpuRespVO {
@ExcelProperty("创建时间") @ExcelProperty("创建时间")
private LocalDateTime createTime; private LocalDateTime createTime;
@Schema(description = "是否热卖推荐")
@ExcelProperty("是否热卖推荐")
private Integer recommendHot;
@Schema(description = "是否促销推荐")
@ExcelProperty("是否优惠推荐")
private Integer recommendBenefit;
@Schema(description = "是否精品推荐")
@ExcelProperty("是否精品推荐")
private Integer recommendBest;
@Schema(description = "是否新品推荐")
@ExcelProperty("是否新品推荐")
private Integer recommendNew;
@Schema(description = "是否优品推荐")
@ExcelProperty("是否优品推荐")
private Integer recommendGood;
// ========== SKU 相关字段 ========= // ========== SKU 相关字段 =========
@Schema(description = "规格类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "true") @Schema(description = "规格类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")

View File

@ -99,4 +99,23 @@ public class ProductSpuSaveReqVO {
@Valid @Valid
private List<ProductSkuSaveReqVO> skus; private List<ProductSkuSaveReqVO> skus;
@Schema(description = "是否热卖推荐")
@Valid
private Integer recommendHot;
@Schema(description = "是否促销推荐")
@Valid
private Integer recommendBenefit;
@Schema(description = "是否精品推荐")
@Valid
private Integer recommendBest;
@Schema(description = "是否新品推荐")
@Valid
private Integer recommendNew;
@Schema(description = "是否优品推荐")
@Valid
private Integer recommendGood;
} }

View File

@ -10,16 +10,21 @@ import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO; import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuDetailRespVO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuRecommendPageReqVo;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuRespVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuRespVO;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.yudao.module.product.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
import cn.iocoder.yudao.module.product.service.history.ProductBrowseHistoryService; import cn.iocoder.yudao.module.product.service.history.ProductBrowseHistoryService;
import cn.iocoder.yudao.module.product.service.sku.ProductSkuService; import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
import cn.iocoder.yudao.module.product.service.spu.ProductSpuService; import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
import cn.iocoder.yudao.module.product.service.spu.ProductSpuServiceImpl;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import org.apache.commons.math3.stat.descriptive.summary.Product;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
@ -33,6 +38,7 @@ import java.util.List;
import java.util.Set; import java.util.Set;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_ENABLE; import static cn.iocoder.yudao.module.product.enums.ErrorCodeConstants.SPU_NOT_ENABLE;
@ -91,6 +97,23 @@ public class AppProductSpuController {
return success(voPageResult); return success(voPageResult);
} }
@GetMapping("/get-recommend-page")
@Operation(summary = "获得推荐类型对应的商品 SPU 分页")
public CommonResult<PageResult<AppProductSpuRespVO>> getRecommendPage(@Valid AppProductSpuRecommendPageReqVo recommendPageVo){
List<ProductSpuDO> recommendProductList = productSpuService.getRecommendProductIdList(recommendPageVo);
PageResult<ProductSpuDO> pageResult = getPaginatedList(recommendProductList, recommendPageVo.getPageNo(), recommendPageVo.getPageSize());
if (CollUtil.isEmpty(pageResult.getList())) {
return success(PageResult.empty(pageResult.getTotal()));
}
// 拼接返回
pageResult.getList().forEach(spu -> spu.setSalesCount(spu.getSalesCount() + spu.getVirtualSalesCount()));
PageResult<AppProductSpuRespVO> voPageResult = BeanUtils.toBean(pageResult, AppProductSpuRespVO.class);
// 处理 vip 价格
MemberLevelRespDTO memberLevel = getMemberLevel();
voPageResult.getList().forEach(vo -> vo.setVipPrice(calculateVipPrice(vo.getPrice(), memberLevel)));
return success(voPageResult);
}
@GetMapping("/get-detail") @GetMapping("/get-detail")
@Operation(summary = "获得商品 SPU 明细") @Operation(summary = "获得商品 SPU 明细")
@Parameter(name = "id", description = "编号", required = true) @Parameter(name = "id", description = "编号", required = true)
@ -148,5 +171,28 @@ public class AppProductSpuController {
return price - newPrice; return price - newPrice;
} }
/**
* 逻辑分页
* @param list
* @param pageSize
* @param pageNumber
* @return java.util.List<T>
*/
private PageResult<ProductSpuDO> getPaginatedList(List<ProductSpuDO> list, int pageNumber, int pageSize) {
// 计算起始索引
int fromIndex = (pageNumber - 1) * pageSize;
// 计算结束索引
int toIndex = Math.min(fromIndex + pageSize, list.size());
PageResult<ProductSpuDO> pageResult = new PageResult<>();
pageResult.setTotal((long)list.size());
// 如果起始索引超出范围返回空列表
if (fromIndex >= list.size() || fromIndex < 0) {
return pageResult;
}
// 逻辑分页
List<ProductSpuDO> result = list.subList(fromIndex, toIndex);
pageResult.setList(result);
return pageResult;
}
// TODO 芋艿商品的浏览记录 // TODO 芋艿商品的浏览记录
} }

View File

@ -0,0 +1,26 @@
package cn.iocoder.yudao.module.product.controller.app.spu.vo;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
import java.util.List;
@Schema(description = "用户 App - 推荐商品 SPU 分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class AppProductSpuRecommendPageReqVo extends PageParam {
@Schema(description = "热卖推荐", example = "1")
private Integer recommendHot;
@Schema(description = "促销推荐", example = "1")
private Integer recommendBenefit;
@Schema(description = "精品推荐", example = "1")
private Integer recommendBest;
@Schema(description = "新品推荐", example = "1")
private Integer recommendNew;
@Schema(description = "优品推荐", example = "1")
private Integer recommendGood;
}

View File

@ -6,11 +6,13 @@ import cn.iocoder.yudao.module.product.dal.dataobject.brand.ProductBrandDO;
import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO; import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO;
import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO; import cn.iocoder.yudao.module.product.dal.dataobject.sku.ProductSkuDO;
import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum; import cn.iocoder.yudao.module.product.enums.spu.ProductSpuStatusEnum;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotation.KeySequence; import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*; import lombok.*;
import java.util.List; import java.util.List;
@ -88,6 +90,31 @@ public class ProductSpuDO extends BaseDO {
*/ */
private Integer status; private Integer status;
/**
* 是否热卖推荐
*/
private Integer recommendHot;
/**
* 是否优惠推荐
*/
private Integer recommendBenefit;
/**
* 是否精品推荐
*/
private Integer recommendBest;
/**
* 是否新品推荐
*/
private Integer recommendNew;
/**
* 是否优品推荐
*/
private Integer recommendGood;
// ========== SKU 相关字段 ========= // ========== SKU 相关字段 =========
/** /**

View File

@ -5,6 +5,7 @@ import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReq
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuSaveReqVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuSaveReqVO;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateStatusReqVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateStatusReqVO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuRecommendPageReqVo;
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
@ -131,4 +132,10 @@ public interface ProductSpuService {
@Async @Async
void updateBrowseCount(Long id, int incrCount); void updateBrowseCount(Long id, int incrCount);
/**
* 获取推荐类型的 SPU ID列表
* @param pageVo
* @return
*/
List<ProductSpuDO> getRecommendProductIdList(AppProductSpuRecommendPageReqVo pageVo);
} }

View File

@ -6,12 +6,15 @@ import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils; import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO; import cn.iocoder.yudao.module.product.controller.admin.category.vo.ProductCategoryListReqVO;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSkuSaveReqVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSkuSaveReqVO;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuPageReqVO;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuSaveReqVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuSaveReqVO;
import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateStatusReqVO; import cn.iocoder.yudao.module.product.controller.admin.spu.vo.ProductSpuUpdateStatusReqVO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO; import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuPageReqVO;
import cn.iocoder.yudao.module.product.controller.app.spu.vo.AppProductSpuRecommendPageReqVo;
import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO; import cn.iocoder.yudao.module.product.dal.dataobject.category.ProductCategoryDO;
import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO; import cn.iocoder.yudao.module.product.dal.dataobject.spu.ProductSpuDO;
import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper; import cn.iocoder.yudao.module.product.dal.mysql.spu.ProductSpuMapper;
@ -160,6 +163,34 @@ public class ProductSpuServiceImpl implements ProductSpuService {
productSpuMapper.updateBrowseCount(id , incrCount); productSpuMapper.updateBrowseCount(id , incrCount);
} }
@Override
public List<ProductSpuDO> getRecommendProductIdList(AppProductSpuRecommendPageReqVo pageVo) {
LambdaQueryWrapperX<ProductSpuDO> wrapperX = new LambdaQueryWrapperX<>();
Integer recommendHot = pageVo.getRecommendHot();
Integer recommendBenefit = pageVo.getRecommendBenefit();
Integer recommendBest = pageVo.getRecommendBest();
Integer recommendNew = pageVo.getRecommendNew();
Integer recommendGood = pageVo.getRecommendGood();
if (recommendHot != null && recommendHot != 0){
wrapperX.eq(ProductSpuDO::getRecommendHot, recommendHot);
}
if (recommendBenefit != null && recommendBenefit != 0){
wrapperX.eq(ProductSpuDO::getRecommendBenefit, recommendBenefit);
}
if (recommendBest != null && recommendBest != 0){
wrapperX.eq(ProductSpuDO::getRecommendBest, recommendBest);
}
if (recommendNew != null && recommendNew != 0){
wrapperX.eq(ProductSpuDO::getRecommendNew, recommendNew);
}
if (recommendGood != null && recommendGood != 0){
wrapperX.eq(ProductSpuDO::getRecommendGood, recommendGood);
}
wrapperX.eq(ProductSpuDO::getStatus, 1);
wrapperX.last(" ORDER BY (sales_count + virtual_sales_count) DESC, sort DESC, id DESC");
return productSpuMapper.selectList(wrapperX);
}
@Override @Override
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public void deleteSpu(Long id) { public void deleteSpu(Long id) {