From 0c1b74ddc04519b6a210a9fc2f9bd5b94c712984 Mon Sep 17 00:00:00 2001 From: litianxiang Date: Mon, 11 May 2026 16:40:47 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B9=B0=E5=AE=B6=E7=AB=AF=E9=9C=80=E8=A6=81?= =?UTF-8?q?=E7=9A=84=E8=8E=B7=E5=8F=96=E5=95=86=E5=AE=B6=E4=B8=BB=E9=A1=B5?= =?UTF-8?q?=E5=92=8C=E6=A8=A1=E7=B3=8A=E6=90=9C=E7=B4=A2=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DesignerController.java | 20 ++++ .../designer/service/DesignerService.java | 20 ++++ .../designer/service/DesignerServiceImpl.java | 95 +++++++++++++++++++ .../module/designer/vo/DesignerSearchVO.java | 36 +++++++ .../module/designer/vo/DesignerShopVO.java | 32 +++++++ .../listing/controller/ListingController.java | 11 +++ .../module/listing/enums/DesignForEnum.java | 3 +- .../listing/service/ListingService.java | 12 +++ .../listing/service/ListingServiceImpl.java | 32 +++++++ .../module/listing/vo/ListingPageVO.java | 13 +-- src/main/resources/application.yml | 2 +- 11 files changed, 263 insertions(+), 13 deletions(-) create mode 100644 src/main/java/com/aida/seller/module/designer/vo/DesignerSearchVO.java create mode 100644 src/main/java/com/aida/seller/module/designer/vo/DesignerShopVO.java diff --git a/src/main/java/com/aida/seller/module/designer/controller/DesignerController.java b/src/main/java/com/aida/seller/module/designer/controller/DesignerController.java index 96abb18..e8a3ff7 100644 --- a/src/main/java/com/aida/seller/module/designer/controller/DesignerController.java +++ b/src/main/java/com/aida/seller/module/designer/controller/DesignerController.java @@ -8,12 +8,16 @@ import com.aida.seller.module.designer.dto.DesignerAuditDTO; import com.aida.seller.module.designer.dto.DesignerDTO; import com.aida.seller.module.designer.entity.DesignerEntity; import com.aida.seller.module.designer.service.DesignerService; +import com.aida.seller.module.designer.vo.DesignerSearchVO; +import com.aida.seller.module.designer.vo.DesignerShopVO; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; import io.swagger.v3.oas.annotations.tags.Tag; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.*; +import java.util.List; + @Tag(name = "设计师入驻管理") @RestController @RequestMapping("/designer") @@ -95,4 +99,20 @@ public class DesignerController { designerService.deleteByUserId(userId); return Response.success(); } + + @Operation(summary = "搜索设计师", description = "根据关键词不区分大小写同时匹配店铺名称和所有者姓名,返回设计师信息、最近5张商品封面图(按updateTime倒序)、商品总数") + @GetMapping("/search") + public Response> search( + @Parameter(description = "关键词(同时匹配店铺名称和所有者姓名,不区分大小写)") @RequestParam String keyword) { + List result = designerService.searchDesigners(keyword); + return Response.success(result); + } + + @Operation(summary = "获取设计师店铺详情", description = "根据 sellerId(即 卖家userId)获取店铺公开信息,供买家端店铺主页调用") + @GetMapping("/shop/{sellerId}") + public Response getShopDetail( + @Parameter(description = "设计师用户ID") @PathVariable Long sellerId) { + DesignerShopVO vo = designerService.getShopDetailBySellerId(sellerId); + return Response.success(vo); + } } diff --git a/src/main/java/com/aida/seller/module/designer/service/DesignerService.java b/src/main/java/com/aida/seller/module/designer/service/DesignerService.java index 6e9c768..445cdab 100644 --- a/src/main/java/com/aida/seller/module/designer/service/DesignerService.java +++ b/src/main/java/com/aida/seller/module/designer/service/DesignerService.java @@ -4,9 +4,13 @@ import com.aida.seller.module.designer.dto.DesignerApplyDTO; import com.aida.seller.module.designer.dto.DesignerAuditDTO; import com.aida.seller.module.designer.dto.DesignerDTO; import com.aida.seller.module.designer.entity.DesignerEntity; +import com.aida.seller.module.designer.vo.DesignerSearchVO; +import com.aida.seller.module.designer.vo.DesignerShopVO; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.service.IService; +import java.util.List; + public interface DesignerService extends IService { /** @@ -58,4 +62,20 @@ public interface DesignerService extends IService { * @param userId 用户ID */ void deleteByUserId(Long userId); + + /** + * 模糊搜索设计师(不区分大小写),返回设计师信息及关联商品封面列表 + * + * @param keyword 关键词(同时匹配店铺名称和所有者姓名,不区分大小写) + * @return 搜索结果列表,每条包含设计师基础信息、最近5张商品封面图(按updateTime倒序)、商品总数 + */ + List searchDesigners(String keyword); + + /** + * 根据 sellerId(即 userId)获取设计师店铺详情,供买家端店铺主页调用 + * + * @param sellerId 设计师用户ID + * @return 店铺详情 + */ + DesignerShopVO getShopDetailBySellerId(Long sellerId); } diff --git a/src/main/java/com/aida/seller/module/designer/service/DesignerServiceImpl.java b/src/main/java/com/aida/seller/module/designer/service/DesignerServiceImpl.java index 6128cfc..5d34d66 100644 --- a/src/main/java/com/aida/seller/module/designer/service/DesignerServiceImpl.java +++ b/src/main/java/com/aida/seller/module/designer/service/DesignerServiceImpl.java @@ -9,6 +9,8 @@ import com.aida.seller.module.designer.dto.DesignerDTO; import com.aida.seller.module.designer.entity.DesignerEntity; import com.aida.seller.module.designer.enums.DesignerApplyStatusEnum; import com.aida.seller.module.designer.mapper.DesignerMapper; +import com.aida.seller.module.designer.vo.DesignerSearchVO; +import com.aida.seller.module.designer.vo.DesignerShopVO; import com.aida.seller.module.listing.entity.ListingEntity; import com.aida.seller.module.listing.entity.ListingImageEntity; import com.aida.seller.module.listing.mapper.ListingImageMapper; @@ -25,8 +27,10 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.StringUtils; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import java.time.LocalDateTime; @@ -296,4 +300,95 @@ public class DesignerServiceImpl extends ServiceImpl searchDesigners(String keyword) { + // Step 1: 构造设计师模糊查询条件,同时匹配店铺名称和所有者姓名,不区分大小写 + LambdaQueryWrapper designerQuery = new LambdaQueryWrapper<>(); + + if (StringUtils.hasText(keyword)) { + designerQuery.and(wrapper -> wrapper + .apply("LOWER(shop_name) LIKE LOWER({0})", "%" + keyword + "%") + .or() + .apply("LOWER(owner_name) LIKE LOWER({0})", "%" + keyword + "%") + ); + } + + List designers = this.list(designerQuery); + if (designers.isEmpty()) { + return List.of(); + } + + // Step 2: 提取设计师的 userId 集合,用于后续按 userId 查询其关联商品 + List userIds = designers.stream() + .map(DesignerEntity::getUserId) + .collect(Collectors.toList()); + + // Step 3: 查询所有匹配设计师关联的商品,按 updateTime 倒序 + LambdaQueryWrapper listingQuery = new LambdaQueryWrapper() + .in(ListingEntity::getSellerId, userIds) + .orderByDesc(ListingEntity::getUpdateTime); + List listings = listingMapper.selectList(listingQuery); + + if (listings.isEmpty()) { + return designers.stream().map(d -> buildSearchVO(d, List.of(), 0L)) + .collect(Collectors.toList()); + } + + // Step 4: 按 sellerId 分组,统计每个设计师的商品总数 + Map listingCountMap = listings.stream() + .collect(Collectors.groupingBy( + ListingEntity::getSellerId, + Collectors.counting() + )); + + // Step 5: 按 sellerId 分组,便于后续取每个设计师的商品列表 + Map> listingsByDesigner = listings.stream() + .collect(Collectors.groupingBy(ListingEntity::getSellerId)); + + // Step 6: 组装每个设计师的搜索结果,最多取 5 个商品封面图 + return designers.stream().map(d -> { + List covers = listingsByDesigner + .getOrDefault(d.getId(), List.of()) + .stream() + .filter(l -> l.getCover() != null && !l.getCover().isBlank()) + .limit(5) + .map(l -> minioUtil.processMinioResource(l.getCover(), CommonConstants.MINIO_PATH_TIMEOUT)) + .collect(Collectors.toList()); + + long listingTotal = listingCountMap.getOrDefault(d.getId(), 0L); + return buildSearchVO(d, covers, listingTotal); + }).collect(Collectors.toList()); + } + + private DesignerSearchVO buildSearchVO(DesignerEntity entity, List covers, Long listingTotal) { + DesignerSearchVO vo = new DesignerSearchVO(); + vo.setSellerId(entity.getUserId()); + vo.setShopName(entity.getShopName()); + vo.setOwnerName(entity.getOwnerName()); + vo.setAvatar(minioUtil.processMinioResource(entity.getAvatar(), CommonConstants.MINIO_PATH_TIMEOUT)); + vo.setCovers(covers); + vo.setListingTotal(listingTotal); + return vo; + } + + @Override + public DesignerShopVO getShopDetailBySellerId(Long sellerId) { + DesignerEntity entity = this.getOne( + new LambdaQueryWrapper() + .eq(DesignerEntity::getUserId, sellerId) + .last("LIMIT 1") + ); + if (entity == null) { + throw new BusinessException("设计师不存在"); + } + DesignerShopVO vo = new DesignerShopVO(); + vo.setShopName(entity.getShopName()); + vo.setAvatar(minioUtil.processMinioResource(entity.getAvatar(), CommonConstants.MINIO_PATH_TIMEOUT)); + vo.setBrandBanner(minioUtil.processMinioResource(entity.getBrandBanner(), CommonConstants.MINIO_PATH_TIMEOUT)); + vo.setOwnerName(entity.getOwnerName()); + vo.setDescription(entity.getDescription()); + vo.setSocialLinks(entity.getSocialLinks()); + return vo; + } } diff --git a/src/main/java/com/aida/seller/module/designer/vo/DesignerSearchVO.java b/src/main/java/com/aida/seller/module/designer/vo/DesignerSearchVO.java new file mode 100644 index 0000000..f756e32 --- /dev/null +++ b/src/main/java/com/aida/seller/module/designer/vo/DesignerSearchVO.java @@ -0,0 +1,36 @@ +package com.aida.seller.module.designer.vo; + +import com.fasterxml.jackson.databind.annotation.JsonSerialize; +import com.fasterxml.jackson.databind.ser.std.ToStringSerializer; +import lombok.Data; + +import java.io.Serializable; +import java.util.List; + +/** + * 设计师搜索结果VO + */ +@Data +public class DesignerSearchVO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 用户ID */ + @JsonSerialize(using = ToStringSerializer.class) + private Long sellerId; + + /** 店铺名称 */ + private String shopName; + + /** 所有者全名 */ + private String ownerName; + + /** 店铺头像URL */ + private String avatar; + + /** 商品封面图列表(最多5张,按更新时间倒序) */ + private List covers; + + /** 该设计师的商品总数 */ + private Long listingTotal; +} diff --git a/src/main/java/com/aida/seller/module/designer/vo/DesignerShopVO.java b/src/main/java/com/aida/seller/module/designer/vo/DesignerShopVO.java new file mode 100644 index 0000000..4544b1f --- /dev/null +++ b/src/main/java/com/aida/seller/module/designer/vo/DesignerShopVO.java @@ -0,0 +1,32 @@ +package com.aida.seller.module.designer.vo; + +import lombok.Data; + +import java.io.Serializable; + +/** + * 设计师店铺详情VO,供买家端店铺主页调用 + */ +@Data +public class DesignerShopVO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** 店铺名称 */ + private String shopName; + + /** 店铺头像URL */ + private String avatar; + + /** 品牌 Banner URL */ + private String brandBanner; + + /** 所有者全名 */ + private String ownerName; + + /** 店铺简介 */ + private String description; + + /** 社交媒体链接(JSON 字符串) */ + private String socialLinks; +} diff --git a/src/main/java/com/aida/seller/module/listing/controller/ListingController.java b/src/main/java/com/aida/seller/module/listing/controller/ListingController.java index c9e2954..f23c2c7 100644 --- a/src/main/java/com/aida/seller/module/listing/controller/ListingController.java +++ b/src/main/java/com/aida/seller/module/listing/controller/ListingController.java @@ -83,4 +83,15 @@ public class ListingController { boolean needPopup = listingService.checkPopupReminder(sellerId); return Response.success(needPopup ? 1 : 0); } + + @Operation(summary = "获取店铺商品列表", description = "按 status=1、deleted=0、designFor 筛选,返回店铺已发布商品分页列表") + @GetMapping("/shop") + public Response> getShopListings( + @Parameter(description = "设计师用户ID") @RequestParam Long sellerId, + @Parameter(description = "适用性别 female/male/all") @RequestParam String designFor, + @Parameter(description = "页码") @RequestParam(defaultValue = "1") int pageNum, + @Parameter(description = "每页数量") @RequestParam(defaultValue = "10") int pageSize) { + IPage page = listingService.getShopListings(sellerId, designFor, pageNum, pageSize); + return Response.success(PageResponse.success(page)); + } } diff --git a/src/main/java/com/aida/seller/module/listing/enums/DesignForEnum.java b/src/main/java/com/aida/seller/module/listing/enums/DesignForEnum.java index 681ddad..7b5e4a9 100644 --- a/src/main/java/com/aida/seller/module/listing/enums/DesignForEnum.java +++ b/src/main/java/com/aida/seller/module/listing/enums/DesignForEnum.java @@ -11,7 +11,8 @@ import lombok.Getter; public enum DesignForEnum { MALE("male", "男性"), - FEMALE("female", "女性"); + FEMALE("female", "女性"), + ALL("all", "全部"); private final String code; private final String desc; diff --git a/src/main/java/com/aida/seller/module/listing/service/ListingService.java b/src/main/java/com/aida/seller/module/listing/service/ListingService.java index c5e8987..a0dc10a 100644 --- a/src/main/java/com/aida/seller/module/listing/service/ListingService.java +++ b/src/main/java/com/aida/seller/module/listing/service/ListingService.java @@ -71,4 +71,16 @@ public interface ListingService extends IService { * @return true需要弹窗,false不需要 */ boolean checkPopupReminder(Long sellerId); + + /** + * 获取店铺已发布商品列表,供买家端店铺主页调用 + *

按 status=1、deleted=0、sellerId、designFor 筛选,按 updateTime 倒序

+ * + * @param sellerId 设计师用户ID + * @param designFor 适用性别 female/male,all 表示不限制性别 + * @param pageNum 页码 + * @param pageSize 每页数量 + * @return 分页商品列表 + */ + IPage getShopListings(Long sellerId, String designFor, int pageNum, int pageSize); } diff --git a/src/main/java/com/aida/seller/module/listing/service/ListingServiceImpl.java b/src/main/java/com/aida/seller/module/listing/service/ListingServiceImpl.java index 910d09c..9d7d1cc 100644 --- a/src/main/java/com/aida/seller/module/listing/service/ListingServiceImpl.java +++ b/src/main/java/com/aida/seller/module/listing/service/ListingServiceImpl.java @@ -1,6 +1,7 @@ package com.aida.seller.module.listing.service; import com.aida.seller.common.constants.CommonConstants; +import com.aida.seller.common.context.UserContext; import com.aida.seller.common.exception.BusinessException; import com.aida.seller.module.listing.dto.*; import com.aida.seller.module.listing.entity.ListingEntity; @@ -298,4 +299,35 @@ public class ListingServiceImpl extends ServiceImpl getShopListings(Long sellerId, String designFor, int pageNum, int pageSize) { + Page pageParam = new Page<>(pageNum, pageSize); + LambdaQueryWrapper queryWrapper = new LambdaQueryWrapper<>(); + queryWrapper.eq(ListingEntity::getSellerId, sellerId); + DesignForEnum designForEnum = DesignForEnum.of(designFor); + if (designForEnum == null) { + throw new BusinessException("designFor 只能为 female/male/all"); + } + if (designForEnum != DesignForEnum.ALL) { + queryWrapper.eq(ListingEntity::getDesignFor, designForEnum.getCode()); + } + queryWrapper.eq(ListingEntity::getStatus, 1); + queryWrapper.eq(ListingEntity::getDeleted, 0); + queryWrapper.orderByDesc(ListingEntity::getUpdateTime); + IPage page = this.page(pageParam, queryWrapper); + + Page result = new Page<>(page.getCurrent(), page.getSize(), page.getTotal()); + boolean loggedIn = UserContext.getUserId() != null; + result.setRecords(page.getRecords().stream().map(entity -> { + ListingPageVO vo = new ListingPageVO(); + BeanUtils.copyProperties(entity, vo); + vo.setCover(minioUtil.processMinioResource(vo.getCover(), CommonConstants.MINIO_PATH_TIMEOUT)); + if (!loggedIn) { + vo.setPrice(null); + } + return vo; + }).collect(Collectors.toList())); + return result; + } } diff --git a/src/main/java/com/aida/seller/module/listing/vo/ListingPageVO.java b/src/main/java/com/aida/seller/module/listing/vo/ListingPageVO.java index 56782a3..cdf7e08 100644 --- a/src/main/java/com/aida/seller/module/listing/vo/ListingPageVO.java +++ b/src/main/java/com/aida/seller/module/listing/vo/ListingPageVO.java @@ -29,15 +29,6 @@ public class ListingPageVO implements Serializable { /** 价格 */ private BigDecimal price; - /** 销量 */ - private Integer salesVolume; - - /** 浏览量 */ - private Integer viewCount; - - /** 状态 */ - private Integer status; - - /** 创建时间(用于排序) */ - private LocalDateTime createTime; + /** 修改时间 */ + private LocalDateTime updateTime; } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index c50002e..b341ea7 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -17,7 +17,7 @@ mybatis-plus: type-aliases-package: com.aida.seller.module.*.entity global-config: db-config: - id-type: auto + id-type: assign_id logic-delete-field: deleted logic-delete-value: 1 logic-not-delete-value: 0