添加商品关联推荐
This commit is contained in:
@@ -72,6 +72,15 @@ public class UProductController {
|
||||
return CzgResult.success(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取相关推荐商品
|
||||
*/
|
||||
@GetMapping("/related/{id}")
|
||||
public CzgResult<List<ShopProductVo>> getRelatedProduct(@PathVariable("id") Long id) {
|
||||
AssertUtil.isNull(id, "商品id不能为空");
|
||||
return CzgResult.success(uProductService.queryProductRelatedList(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 小程序点餐-商品详情
|
||||
*
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.czg.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.czg.product.dto.ProductDTO;
|
||||
import com.czg.product.service.ProductService;
|
||||
import com.czg.product.service.UProductService;
|
||||
import com.czg.product.vo.ShopGroupProductVo;
|
||||
import com.czg.product.vo.ShopProductVo;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author yjjie
|
||||
* @date 2025/12/24 13:36
|
||||
*/
|
||||
@SpringBootTest
|
||||
public class ProductTest {
|
||||
|
||||
@Resource
|
||||
private ProductService productService;
|
||||
|
||||
@Resource
|
||||
private UProductService uProductService;
|
||||
|
||||
@Test
|
||||
public void testGetById() {
|
||||
// ProductDTO product = productService.getProductById(169L);
|
||||
// System.out.println(JSONObject.toJSONString( product));
|
||||
|
||||
List<ShopProductVo> productVos = uProductService.queryProductRelatedList(169L);
|
||||
System.out.println(JSONObject.toJSONString(productVos));
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,15 @@
|
||||
package com.czg.product.dto;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.annotation.JSONField;
|
||||
import com.czg.product.vo.ProductGroupVo;
|
||||
import com.czg.validator.group.DefaultGroup;
|
||||
import com.czg.validator.group.InsertGroup;
|
||||
import com.czg.validator.group.UpdateGroup;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import jakarta.validation.constraints.*;
|
||||
import lombok.Data;
|
||||
|
||||
@@ -235,6 +238,12 @@ public class ProductDTO implements Serializable {
|
||||
* 是否可售时间 1-是 0-否
|
||||
*/
|
||||
private Integer isSaleTime;
|
||||
/**
|
||||
* 相关推荐商品
|
||||
*/
|
||||
private List<RelatedProductDTO> relatedRecommendJson;
|
||||
@JsonIgnore
|
||||
private String relatedRecommend;
|
||||
|
||||
public Object getImages() {
|
||||
return JSON.parseArray(Convert.toStr(images, "[]"));
|
||||
@@ -250,4 +259,16 @@ public class ProductDTO implements Serializable {
|
||||
public Object getGroupSnap() {
|
||||
return JSON.parseArray(Convert.toStr(groupSnap, "[]"));
|
||||
}
|
||||
|
||||
public String getRelatedRecommendStr() {
|
||||
if (CollUtil.isNotEmpty(relatedRecommendJson)) {
|
||||
JSONArray array = new JSONArray();
|
||||
for (RelatedProductDTO relatedProductDTO : relatedRecommendJson) {
|
||||
array.add(relatedProductDTO.getId());
|
||||
}
|
||||
return array.toJSONString();
|
||||
}
|
||||
|
||||
return "[]";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.czg.product.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 相关推荐 商品 DTO
|
||||
*
|
||||
* @author yjjie
|
||||
* @date 2025/12/24 13:34
|
||||
*/
|
||||
@Data
|
||||
public class RelatedProductDTO implements Serializable {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 商品 ID
|
||||
*/
|
||||
private Long id;
|
||||
/**
|
||||
* 商品名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 商品图片
|
||||
*/
|
||||
private String coverImg;
|
||||
}
|
||||
@@ -142,6 +142,10 @@ public class Product implements Serializable {
|
||||
* 退款是否退回库存
|
||||
*/
|
||||
private Integer isRefundStock;
|
||||
/**
|
||||
* 相关推荐
|
||||
*/
|
||||
private String relatedRecommend;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.czg.product.service;
|
||||
|
||||
import com.czg.product.dto.ProductDTO;
|
||||
import com.czg.product.dto.RelatedProductDTO;
|
||||
import com.czg.product.entity.Product;
|
||||
import com.czg.product.entity.ProductStockFlow;
|
||||
import com.czg.product.param.*;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.czg.product.service;
|
||||
|
||||
import com.czg.product.dto.RelatedProductDTO;
|
||||
import com.czg.product.entity.Product;
|
||||
import com.czg.product.param.ShopProductSkuParam;
|
||||
import com.czg.product.vo.ShopGroupProductVo;
|
||||
@@ -95,4 +96,6 @@ public interface UProductService extends IService<Product> {
|
||||
* @return 是否可售时间 1-是,0-否
|
||||
*/
|
||||
Integer calcIsSaleTime(String days, LocalTime startTime, LocalTime endTime);
|
||||
|
||||
List<ShopProductVo> queryProductRelatedList(Long productId);
|
||||
}
|
||||
|
||||
@@ -16,9 +16,6 @@ import com.czg.exception.CzgException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.io.DataOutputStream;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -35,8 +32,8 @@ public class AliOcrUtil {
|
||||
/**
|
||||
* <b>description</b> :
|
||||
* <p>使用凭据初始化账号Client</p>
|
||||
* @return Client
|
||||
*
|
||||
* @return Client
|
||||
* @throws Exception
|
||||
*/
|
||||
public static com.aliyun.bailian20231229.Client createClient() {
|
||||
@@ -56,7 +53,6 @@ public class AliOcrUtil {
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static ApplyFileUploadLeaseResponseBody.ApplyFileUploadLeaseResponseBodyData applyFileUpload(byte[] bytes, String fileName) {
|
||||
|
||||
String md5 = DigestUtil.md5Hex(bytes);
|
||||
@@ -95,7 +91,7 @@ public class AliOcrUtil {
|
||||
.setCategoryId("default")
|
||||
.setCategoryType("SESSION_FILE");
|
||||
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
|
||||
java.util.Map<String, String> headers = new java.util.HashMap<>();
|
||||
java.util.Map<String, String> headers = new java.util.HashMap<>();
|
||||
try {
|
||||
// 复制代码运行请自行打印 API 的返回值
|
||||
AddFileResponse addFileResponse = client.addFileWithOptions("llm-9zg04s7wlbvi32tq", addFileRequest, headers, runtime);
|
||||
@@ -110,7 +106,7 @@ public class AliOcrUtil {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean getFileStatus(String fileId) {
|
||||
public static boolean getFileStatus(String fileId) {
|
||||
com.aliyun.bailian20231229.Client client = createClient();
|
||||
com.aliyun.teautil.models.RuntimeOptions runtime = new com.aliyun.teautil.models.RuntimeOptions();
|
||||
java.util.Map<String, String> headers = new java.util.HashMap<>();
|
||||
@@ -158,18 +154,17 @@ public class AliOcrUtil {
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static String appCall(byte[] bytes, String fileName) {
|
||||
String id = null;
|
||||
public static String appCall(byte[] bytes, String fileName) {
|
||||
String id;
|
||||
try {
|
||||
id = getSessionId(bytes, fileName);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
ApplicationParam param = ApplicationParam.builder()
|
||||
ApplicationParam param = ApplicationParam.builder()
|
||||
.apiKey("sk-2343af4413834ad1ab43b036e3a903de")
|
||||
.appId("cd612ac509a4499f8ac68a656532d4ae")
|
||||
.prompt("你是一名票据OCR结构化专家,请从我提供的票据图片中智能提取信息并只输出JSON,不得添加解释、不补充不存在内容、不得返回空字符串、字段缺失填null、字段不可省略、数字一律用字符串,使用以下固定JSON结构:{\"documentType\":\"\",\"orderNumber\":\"\",\"date\":\"\",\"customerName\":\"\",\"operator\":\"\",\"items\":[{\"conName\":\"\",\"spec\":\"\",\"unitName\":\"\",\"inOutNumber\":\"\",\"purchasePrice\":\"\",\"subTotal\":\"\"}],\"totalAmount\":\"\",\"remark\":\"\"}。字段映射规则:documentType对应单据类型/销售单/采购单/出货单;orderNumber对应单号/编号/No;date对应日期/开单日期;customerName对应客户名称/收货单位/供应商;operator对应业务员/经办人/制单人/操作员;items.conName对应品名/名称;items.spec对应规格/型号;items.unitName对应单位;items.inOutNumber对应数量;items.purchasePrice对应单价;items.subTotal对应金额/小计;totalAmount对应总金额/合计金额;remark对应备注。严禁生成图片中不存在的字段内容,看不清或未出现的字段必须为null,不允许推测或补全,不得生成多余字段;items只能根据识别到的行生成,不得虚构。必须能识别旋转、倾斜、模糊、撕裂、光照差异、列顺序混乱、无表格线等情况并尽量恢复信息。最终输出必须是纯JSON,不得包含任何非JSON字符。")
|
||||
.prompt("你是一名票据OCR结构化专家,请从我提供的票据图片中智能提取信息并只输出JSON,不得添加解释、不补充不存在内容、不得返回空字符串、字段缺失填null、字段不可省略、数字一律用字符串,使用以下固定JSON结构:{\"documentType\":\"\",\"orderNumber\":\"\",\"date\":\"\",\"customerName\":\"\",\"operator\":\"\",\"items\":[{\"conName\":\"\",\"spec\":\"\",\"unitName\":\"\",\"inOutNumber\":\"\",\"purchasePrice\":\"\",\"subTotal\":\"\"}],\"totalAmount\":\"\",\"remark\":\"\"}。字段映射规则:documentType对应单据类型/销售单/采购单/出货单;orderNumber对应单号/编号/No;date对应日期/开单日期;customerName对应客户名称/收货单位/供应商;operator对应业务员/经办人/制单人/操作员;items.conName对应品名/名称;items.spec对应规格/型号;items.unitName对应单位;items.inOutNumber对应数量;items.purchasePrice对应单价;items.subTotal对应金额/小计;totalAmount对应总金额/合计金额;remark对应备注。严禁生成图片中不存在的字段内容,看不清或未出现的字段必须为null,不允许推测或补全,不得生成多余字段;items只能根据识别到的行生成,不得虚构。必须能识别旋转、倾斜、模糊、撕裂、光照差异、列顺序混乱、无表格线等情况并尽量恢复信息。最终输出必须是纯JSON,不得包含任何非JSON字符。")
|
||||
.ragOptions(RagOptions.builder()
|
||||
.sessionFileIds(List.of(id))
|
||||
.build())
|
||||
@@ -187,11 +182,4 @@ public class AliOcrUtil {
|
||||
return result.getOutput().getText();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
}
|
||||
|
||||
static void main() throws Exception {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public interface ProductMapper extends BaseMapper<Product> {
|
||||
|
||||
List<ShopProductVo> selectHotsProductList(@Param("shopId") Long shopId);
|
||||
|
||||
List<ShopProductVo> selectGroupProductList(@Param("shopId") Long shopId);
|
||||
List<ShopProductVo> selectGroupProductList(@Param("shopId") Long shopId, @Param("idList") List<Long> idList);
|
||||
|
||||
ShopProductInfoVo selectOneProductInfo(@Param("id") Long id, @Param("shopId") Long shopId);
|
||||
|
||||
|
||||
@@ -6,14 +6,12 @@ import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONWriter;
|
||||
import com.czg.constant.CacheConstant;
|
||||
import com.czg.constants.SystemConstants;
|
||||
import com.czg.exception.CzgException;
|
||||
import com.czg.product.dto.ProdConsRelationDTO;
|
||||
import com.czg.product.dto.ProdSkuDTO;
|
||||
import com.czg.product.dto.ProductDTO;
|
||||
import com.czg.product.dto.ShopProdCategoryDTO;
|
||||
import com.czg.product.dto.*;
|
||||
import com.czg.product.entity.*;
|
||||
import com.czg.product.enums.*;
|
||||
import com.czg.product.param.*;
|
||||
@@ -310,6 +308,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
||||
dto.setSkuList(skuList);
|
||||
List<ProdConsRelationDTO> consList = prodConsRelationMapper.selectListByProdId(dto.getId());
|
||||
dto.setConsList(consList);
|
||||
dto.setRelatedRecommendJson(getRelateProductList(dto.getRelatedRecommend()));
|
||||
return dto;
|
||||
}
|
||||
|
||||
@@ -336,6 +335,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
||||
}
|
||||
entity.setIsDel(SystemConstants.OneZero.ZERO);
|
||||
entity.setShopId(shopId);
|
||||
entity.setRelatedRecommend(dto.getRelatedRecommendStr());
|
||||
super.save(entity);
|
||||
dto.setId(entity.getId());
|
||||
// 清除商品分类列表缓存
|
||||
@@ -404,6 +404,7 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
||||
if (!ProductTypeEnum.SKU.value().equals(entity.getType())) {
|
||||
UpdateChain.of(Product.class).set(Product::getSpecId, null).eq(Product::getId, dto.getId()).update();
|
||||
}
|
||||
entity.setRelatedRecommend(dto.getRelatedRecommendStr());
|
||||
super.updateById(entity);
|
||||
// 清除商品分类列表缓存
|
||||
clearProductCache(old.getCategoryId());
|
||||
@@ -788,4 +789,16 @@ public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> impl
|
||||
String key = StrUtil.format(CacheConstant.SHOP_PRODUCT_STOCK, shopId, productId);
|
||||
redisService.set(key, stockNumber);
|
||||
}
|
||||
|
||||
private List<RelatedProductDTO> getRelateProductList(String relatedProduct) {
|
||||
if (StrUtil.isNotBlank(relatedProduct) && !"[]".equals(relatedProduct)) {
|
||||
List<Long> idList = JSONArray.parseArray(relatedProduct, Long.class);
|
||||
|
||||
QueryWrapper wrapper = QueryWrapper.create().select(Product::getId, Product::getName, Product::getCoverImg).eq(Product::getIsDel, SystemConstants.OneZero.ZERO)
|
||||
.in(Product::getId, idList);
|
||||
return super.listAs(wrapper, RelatedProductDTO.class);
|
||||
}
|
||||
|
||||
return new ArrayList<>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.NumberUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.czg.constant.CacheConstant;
|
||||
import com.czg.constants.SystemConstants;
|
||||
import com.czg.exception.CzgException;
|
||||
@@ -27,6 +28,7 @@ import com.czg.service.product.mapper.ProdGroupMapper;
|
||||
import com.czg.service.product.mapper.ProdGroupRelationMapper;
|
||||
import com.czg.service.product.mapper.ProdSkuMapper;
|
||||
import com.czg.service.product.mapper.ProductMapper;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.spring.service.impl.ServiceImpl;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -78,7 +80,7 @@ public class UProductServiceImpl extends ServiceImpl<ProductMapper, Product> imp
|
||||
query().select(ProdGroup::getId, ProdGroup::getName, ProdGroup::getSortMode, ProdGroup::getUseTime, ProdGroup::getSaleStartTime, ProdGroup::getSaleEndTime)
|
||||
.eq(ProdGroup::getShopId, shopId).eq(ProdGroup::getStatus,SystemConstants.OneZero.ONE)
|
||||
.orderBy(ProdGroup::getSort, true), ShopGroupProductVo.class);
|
||||
List<ShopProductVo> productAllList = productMapper.selectGroupProductList(shopId);
|
||||
List<ShopProductVo> productAllList = productMapper.selectGroupProductList(shopId, null);
|
||||
productAllList.forEach(item -> {
|
||||
List<ProdSkuDTO> skuList = prodSkuMapper.selectListByQueryAs(query()
|
||||
.eq(ProdSku::getProductId, item.getId())
|
||||
@@ -233,6 +235,31 @@ public class UProductServiceImpl extends ServiceImpl<ProductMapper, Product> imp
|
||||
return SystemConstants.OneZero.ZERO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ShopProductVo> queryProductRelatedList(Long productId) {
|
||||
Product product = getOne(QueryWrapper.create().eq(Product::getId, productId)
|
||||
.eq(Product::getShopId, StpKit.USER.getShopId())
|
||||
.eq(Product::getIsDel, SystemConstants.OneZero.ZERO));
|
||||
|
||||
if (product == null) {
|
||||
throw new CzgException("商品信息不存在");
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(product.getRelatedRecommend()) || "[]".equals(product.getRelatedRecommend())) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
List<ShopProductVo> productAllList = productMapper.selectGroupProductList(product.getShopId(), JSONArray.parseArray(product.getRelatedRecommend(), Long.class));
|
||||
productAllList.forEach(item -> {
|
||||
List<ProdSkuDTO> skuList = prodSkuMapper.selectListByQueryAs(query()
|
||||
.eq(ProdSku::getProductId, item.getId())
|
||||
.eq(ProdSku::getIsGrounding, SystemConstants.OneZero.ONE)
|
||||
.eq(ProdSku::getIsDel, SystemConstants.OneZero.ZERO), ProdSkuDTO.class);
|
||||
item.setSkuList(skuList);
|
||||
});
|
||||
return productAllList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计算是否在可售时间内
|
||||
*
|
||||
|
||||
@@ -147,6 +147,12 @@
|
||||
and t2.sale_price is not null
|
||||
and t1.shop_id = #{shopId}
|
||||
</where>
|
||||
<if test="idList != null">
|
||||
and t1.id in
|
||||
<foreach item="item" collection="idList" separator="," open="(" close=")">
|
||||
#{item}
|
||||
</foreach>
|
||||
</if>
|
||||
order by t1.sort desc,t1.id desc
|
||||
</select>
|
||||
<select id="selectOneProductInfo" resultType="com.czg.product.vo.ShopProductInfoVo">
|
||||
|
||||
Reference in New Issue
Block a user