zepengdev
2025-06-14 6e0a83c55db4bae4d23a4c281946bda1d610f678
补充前次提交的遗漏内容,前次提交SHA:a6f4dd
30 files added
13 files modified
1931 ■■■■■ changed files
oying-system/src/main/java/com/oying/modules/pc/category/converter/PlatformCategoryAssembler.java 28 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/category/domain/enums/PlatformCategoryEnum.java 28 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/common/ValueUpdate.java 37 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/converter/ProductImageAssembler.java 38 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/converter/ProductLabelAssembler.java 26 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/domain/ProductImage.java 52 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/domain/ProductLabel.java 49 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductImageQueryCriteria.java 30 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductImageUpdateRequest.java 16 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductLabelQueryCriteria.java 18 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductQueryCriteria.java 2 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/domain/enums/ProductStatusEnum.java 33 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductImageMapper.java 24 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductLabelMapper.java 22 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductCustomerController.java 3 ●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/service/ProductAdminService.java 14 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/service/ProductImageService.java 98 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/service/ProductLabelService.java 86 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductAdminServiceImpl.java 115 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductImageServiceImpl.java 173 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductLabelServiceImpl.java 133 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductMerchantServiceImpl.java 149 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/view/ProductCustomerView.java 33 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/view/ProductMerchantSimpleView.java 69 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/view/ProductSimpleView.java 76 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreAssembler.java 32 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreQualificationAssembler.java 32 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreUser.java 39 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCustomerDetailDto.java 62 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreUpdateRequest.java 103 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/domain/enums/StoreCategoryEnum.java 28 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/mapper/StoreUserMapper.java 18 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCustomerController.java 25 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreMerchantController.java 16 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreQualificationCustomerController.java 6 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/service/StoreQualificationService.java 7 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreQualificationServiceImpl.java 7 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/view/CustomerStoreView.java 65 ●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/utils/BusinessHoursUtils.java 42 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/utils/ImageUtils.java 31 ●●●●● patch | view | raw | blame | history
oying-system/src/main/resources/mapper/pc/product/ProductImageMapper.xml 30 ●●●●● patch | view | raw | blame | history
oying-system/src/main/resources/mapper/pc/product/ProductLabelMapper.xml 28 ●●●●● patch | view | raw | blame | history
oying-system/src/main/resources/mapper/pc/store/StoreQualificationMapper.xml 8 ●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/category/converter/PlatformCategoryAssembler.java
New file
@@ -0,0 +1,28 @@
package com.oying.modules.pc.category.converter;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.oying.modules.pc.category.domain.PlatformCategory;
import com.oying.modules.pc.category.domain.dto.PlatformCategoryCreateRequest;
import com.oying.modules.pc.category.domain.dto.PlatformCategoryUpdateDto;
import com.oying.modules.pc.utils.ImageUtils;
public class PlatformCategoryAssembler {
    public static PlatformCategory to(PlatformCategoryCreateRequest request) {
        PlatformCategory platformCategory = new PlatformCategory();
        BeanUtil.copyProperties(request, platformCategory, CopyOptions.create().setIgnoreNullValue(true));
        platformCategory.setIconId(request.getIconUploadFileId());
        platformCategory.setIconUrl(ImageUtils.getPublicObjectUrl(request.getIconUploadFileId()));
        return platformCategory;
    }
    public static PlatformCategory to(PlatformCategoryUpdateDto updateDto) {
        PlatformCategory platformCategory = new PlatformCategory();
        BeanUtil.copyProperties(updateDto, platformCategory, CopyOptions.create().setIgnoreNullValue(true));
        platformCategory.setIconId(updateDto.getIconUploadFileId());
        platformCategory.setIconUrl(ImageUtils.getPublicObjectUrl(updateDto.getIconUploadFileId()));
        return platformCategory;
    }
}
oying-system/src/main/java/com/oying/modules/pc/category/domain/enums/PlatformCategoryEnum.java
New file
@@ -0,0 +1,28 @@
package com.oying.modules.pc.category.domain.enums;
import lombok.Getter;
@Getter
public enum PlatformCategoryEnum {
    NOT(0, "已禁用"),
    YES(1, "已启用");
    private final Integer value;
    private final String reasonPhrase;
    PlatformCategoryEnum(int value, String reasonPhrase) {
        this.value = value;
        this.reasonPhrase = reasonPhrase;
    }
    public static PlatformCategoryEnum get(Integer code) {
        for (PlatformCategoryEnum value : values()) {
            if (value.value.equals(code)) {
                return value;
            }
        }
        return null;
    }
}
oying-system/src/main/java/com/oying/modules/pc/common/ValueUpdate.java
New file
@@ -0,0 +1,37 @@
package com.oying.modules.pc.common;
import cn.hutool.core.util.ObjUtil;
import lombok.Data;
/**
 * 用于封装字段值的变化记录,支持泛型比较逻辑
 * @param <T>
 */
@Data
public class ValueUpdate<T> {
    private final T newValue;
    private final T oldValue;
    public ValueUpdate(T newValue, T oldValue) {
        this.newValue = newValue;
        this.oldValue = oldValue;
    }
    public boolean isChange() {
        return isChange(newValue, oldValue);
    }
    public boolean isChangeAndOldValueNotEmpty() {
        return isChangeAndOldValueNotEmpty(newValue, oldValue);
    }
    public static <T> boolean isChange(T newValue, T oldValue) {
        return ObjUtil.isNotEmpty(newValue) && !newValue.equals(oldValue);
    }
    public static <T> boolean isChangeAndOldValueNotEmpty(T newValue, T oldValue) {
        return ObjUtil.isNotEmpty(oldValue) && isChange(newValue, oldValue);
    }
}
oying-system/src/main/java/com/oying/modules/pc/product/converter/ProductImageAssembler.java
New file
@@ -0,0 +1,38 @@
package com.oying.modules.pc.product.converter;
import cn.hutool.core.collection.ListUtil;
import com.oying.modules.pc.product.domain.ProductImage;
import com.oying.modules.pc.product.domain.dto.ProductImageCreateRequest;
import com.oying.modules.pc.product.domain.dto.ProductImageUpdateRequest;
import com.oying.modules.pc.utils.ImageUtils;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
public class ProductImageAssembler {
    public static ProductImage to(ProductImageCreateRequest request) {
        ProductImage productImage = new ProductImage();
        productImage.setProductId(request.getProductId());
        productImage.setImageType(Optional.ofNullable(request.getImageType()).orElse("main"));
        productImage.setCloudStorageId(request.getUploadFileId());
        productImage.setImageUrl(ImageUtils.getPublicObjectUrl(request.getUploadFileId()));
        return productImage;
    }
    public static List<ProductImage> toProducts(List<ProductImageCreateRequest> requests) {
        return Optional.ofNullable(requests).orElse(ListUtil.empty()).stream().map(ProductImageAssembler::to).collect(Collectors.toList());
    }
    public static ProductImage to(ProductImageUpdateRequest request) {
        ProductImage productImage = new ProductImage();
        productImage.setImageId(request.getImageId());
        productImage.setProductId(request.getProductId());
        productImage.setImageType(request.getImageType());
        productImage.setCloudStorageId(request.getUploadFileId());
        productImage.setImageUrl(ImageUtils.getPublicObjectUrl(request.getUploadFileId()));
        return productImage;
    }
}
oying-system/src/main/java/com/oying/modules/pc/product/converter/ProductLabelAssembler.java
New file
@@ -0,0 +1,26 @@
package com.oying.modules.pc.product.converter;
import cn.hutool.core.collection.ListUtil;
import com.oying.modules.pc.product.domain.ProductImage;
import com.oying.modules.pc.product.domain.ProductLabel;
import com.oying.modules.pc.product.domain.dto.ProductImageCreateRequest;
import com.oying.modules.pc.product.domain.dto.ProductImageUpdateRequest;
import com.oying.modules.pc.product.domain.dto.ProductLabelCreateRequest;
import com.oying.modules.pc.utils.ImageUtils;
import java.util.List;
import java.util.Optional;
public class ProductLabelAssembler {
    public static ProductLabel to(ProductLabelCreateRequest request) {
        ProductLabel productLabel = new ProductLabel();
        productLabel.setProductId(request.getProductId());
        productLabel.setCategoryName(request.getCategoryName());
        productLabel.setLabelName(request.getLabelName());
        productLabel.setLabelValue(request.getLabelValue());
        productLabel.setUnit(request.getUnit());
        return productLabel;
    }
}
oying-system/src/main/java/com/oying/modules/pc/product/domain/ProductImage.java
New file
@@ -0,0 +1,52 @@
package com.oying.modules.pc.product.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.oying.base.BaseEntity;
import lombok.Getter;
import lombok.Setter;
import cn.hutool.core.bean.BeanUtil;
import io.swagger.annotations.ApiModelProperty;
import cn.hutool.core.bean.copier.CopyOptions;
import java.sql.Timestamp;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
/**
* @description /
* @author lzp
* @date 2025-05-28
**/
@Getter
@Setter
@TableName("pc_product_image")
public class ProductImage extends BaseEntity implements Serializable {
    @TableId(value = "image_id", type = IdType.AUTO)
    @ApiModelProperty(value = "商品图片ID")
    private Long imageId;
    @NotNull
    @ApiModelProperty(value = "商品ID")
    private Long productId;
    @NotNull
    @ApiModelProperty(value = "桶ID")
    private Long cloudStorageId;
    @NotBlank
    @ApiModelProperty(value = "图片类型")
    private String imageType;
    @ApiModelProperty(value = "图片地址")
    private String imageUrl;
    @ApiModelProperty(value = "排序权重")
    private Integer sortWeight;
    public void copy(ProductImage source){
        BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
    }
}
oying-system/src/main/java/com/oying/modules/pc/product/domain/ProductLabel.java
New file
@@ -0,0 +1,49 @@
package com.oying.modules.pc.product.domain;
import com.oying.base.BaseEntity;
import lombok.Getter;
import lombok.Setter;
import cn.hutool.core.bean.BeanUtil;
import io.swagger.annotations.ApiModelProperty;
import cn.hutool.core.bean.copier.CopyOptions;
import java.sql.Timestamp;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
/**
* @description /
* @author lzp
* @date 2025-05-28
**/
@Getter
@Setter
@TableName("pc_product_label")
public class ProductLabel extends BaseEntity implements Serializable {
    @TableId(value = "label_id", type = IdType.AUTO)
    @ApiModelProperty(value = "标签ID")
    private Long labelId;
    @NotNull
    @ApiModelProperty(value = "商品ID")
    private Long productId;
    @ApiModelProperty(value = "分类名称")
    private String categoryName;
    @ApiModelProperty(value = "标签名称")
    private String labelName;
    @ApiModelProperty(value = "标签值")
    private String labelValue;
    @ApiModelProperty(value = "单位")
    private String unit;
    public void copy(ProductLabel source){
        BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
    }
}
oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductImageQueryCriteria.java
New file
@@ -0,0 +1,30 @@
package com.oying.modules.pc.product.domain.dto;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
import io.swagger.annotations.ApiModelProperty;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author lzp
* @date 2025-05-28
**/
@Data
public class ProductImageQueryCriteria{
    @ApiModelProperty(value = "商品图片ID")
    private Long imageId;
    @ApiModelProperty(value = "商品ID")
    private Long productId;
    @ApiModelProperty(value = "页码", example = "1")
    private Integer page = 1;
    @ApiModelProperty(value = "每页数据量", example = "10")
    private Integer size = 10;
}
oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductImageUpdateRequest.java
New file
@@ -0,0 +1,16 @@
package com.oying.modules.pc.product.domain.dto;
import lombok.Data;
@Data
public class ProductImageUpdateRequest {
    private Long imageId;
    private Long productId;
    private Long uploadFileId;
    private String imageType;
}
oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductLabelQueryCriteria.java
New file
@@ -0,0 +1,18 @@
package com.oying.modules.pc.product.domain.dto;
import lombok.Data;
import io.swagger.annotations.ApiModelProperty;
/**
* @author lzp
* @date 2025-05-28
**/
@Data
public class ProductLabelQueryCriteria{
    @ApiModelProperty(value = "页码", example = "1")
    private Integer page = 1;
    @ApiModelProperty(value = "每页数据量", example = "10")
    private Integer size = 10;
}
oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductQueryCriteria.java
@@ -25,6 +25,8 @@
    private Long secondCategoryId;
    private Integer active;
    @ApiModelProperty(value = "页码", example = "1")
    private Integer page = 1;
oying-system/src/main/java/com/oying/modules/pc/product/domain/enums/ProductStatusEnum.java
New file
@@ -0,0 +1,33 @@
package com.oying.modules.pc.product.domain.enums;
import lombok.Getter;
@Getter
public enum ProductStatusEnum {
    DRAFT(1000, "创建中"),
    PENDING(1001, "待审核"),
    UNDER_REVIEW(1002, "审核中"),
    REJECTED(1003, "拒绝"),
    APPROVED(1004, "同意"),
    AVAILABLE(2100, "在售"),
    NO_AVAILABLE(2101, "停售"),
    BANNED(3000, "禁止售卖");
    private final Integer value;
    private final String reasonPhrase;
    ProductStatusEnum(int value, String reasonPhrase) {
        this.value = value;
        this.reasonPhrase = reasonPhrase;
    }
    public static ProductStatusEnum get(Integer code) {
        for (ProductStatusEnum value : values()) {
            if (value.value.equals(code)) {
                return value;
            }
        }
        return null;
    }
}
oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductImageMapper.java
New file
@@ -0,0 +1,24 @@
package com.oying.modules.pc.product.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.oying.modules.pc.product.domain.ProductImage;
import com.oying.modules.pc.product.domain.dto.ProductImageQueryCriteria;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * @author lzp
 * @date 2025-05-28
 **/
@Mapper
public interface ProductImageMapper extends BaseMapper<ProductImage> {
    IPage<ProductImage> findAll(@Param("criteria") ProductImageQueryCriteria criteria, Page<Object> page);
    List<ProductImage> findAll(@Param("criteria") ProductImageQueryCriteria criteria);
}
oying-system/src/main/java/com/oying/modules/pc/product/mapper/ProductLabelMapper.java
New file
@@ -0,0 +1,22 @@
package com.oying.modules.pc.product.mapper;
import com.oying.modules.pc.product.domain.ProductLabel;
import com.oying.modules.pc.product.domain.dto.ProductLabelQueryCriteria;
import java.util.List;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
/**
* @author lzp
* @date 2025-05-28
**/
@Mapper
public interface ProductLabelMapper extends BaseMapper<ProductLabel> {
    IPage<ProductLabel> findAll(@Param("criteria") ProductLabelQueryCriteria criteria, Page<Object> page);
    List<ProductLabel> findAll(@Param("criteria") ProductLabelQueryCriteria criteria);
}
oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductCustomerController.java
@@ -63,7 +63,7 @@
        PageResult<ProductCustomerView> viewPageResult = new PageResult<>(
                productList.stream().map(i -> {
                    ProductCustomerView view = new ProductCustomerView();
                    BeanUtils.copyProperties(i, view);
                    BeanUtil.copyProperties(i, view);
                    return view;
                }).collect(Collectors.toList()),
                productPageResult.getTotalElements());
@@ -76,6 +76,7 @@
    public ResponseEntity<?> getProductDetails(@PathVariable Long productId) {
        Product product = productService.getById(productId);
        ProductCustomerView customerView = new ProductCustomerView();
        BeanUtil.copyProperties(product, customerView);
        if (ObjUtil.isNotEmpty(product)) {
            customerView.setImages(productImageService.queryImagesByProductId(productId).stream().map(i -> {
                ProductImageCustomerView imageCustomerView = new ProductImageCustomerView();
oying-system/src/main/java/com/oying/modules/pc/product/service/ProductAdminService.java
New file
@@ -0,0 +1,14 @@
package com.oying.modules.pc.product.service;
import com.oying.modules.pc.product.domain.dto.ProductMerchantCreateRequest;
import com.oying.modules.pc.product.domain.dto.ProductMerchantUpdateRequest;
import java.util.List;
public interface ProductAdminService {
    void create(ProductMerchantCreateRequest request);
    void update(ProductMerchantUpdateRequest request);
    void delete(List<Long> ids);
}
oying-system/src/main/java/com/oying/modules/pc/product/service/ProductImageService.java
New file
@@ -0,0 +1,98 @@
package com.oying.modules.pc.product.service;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.oying.modules.pc.product.domain.ProductImage;
import com.oying.modules.pc.product.domain.dto.ProductImageCreateRequest;
import com.oying.modules.pc.product.domain.dto.ProductImageQueryCriteria;
import com.oying.modules.pc.product.domain.dto.ProductImageUpdateRequest;
import com.oying.utils.PageResult;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
 * @author lzp
 * @description 服务接口
 * @date 2025-05-28
 **/
public interface ProductImageService extends IService<ProductImage> {
    /**
     * 查询数据分页
     *
     * @param criteria 条件
     * @param page     分页参数
     * @return PageResult
     */
    PageResult<ProductImage> queryAll(ProductImageQueryCriteria criteria, Page<Object> page);
    /**
     * 查询所有数据不分页
     *
     * @param criteria 条件参数
     * @return List<ProductImageDto>
     */
    List<ProductImage> queryAll(ProductImageQueryCriteria criteria);
    /**
     * 查询多条ID关联数据
     *
     * @param ids /
     * @return List<ProductImage>
     */
    List<ProductImage> queryBatchIds(List<Long> ids);
    /**
     * 查询商品的所有图片
     *
     * @param productId /
     * @return List<ProductImage>
     */
    List<ProductImage> queryImagesByProductId(Long productId);
    /**
     * 创建
     *
     * @param request /
     */
    void create(ProductImageCreateRequest request);
    /**
     * 批量创建
     *
     * @param requests /
     */
    void batchCreate(List<ProductImageCreateRequest> requests);
    /**
     * 编辑
     *
     * @param request /
     */
    void update(ProductImageUpdateRequest request);
    /**
     * 编辑
     *
     * @param requests /
     */
    void batchUpdate(List<ProductImageUpdateRequest> requests);
    /**
     * 多选删除
     *
     * @param ids /
     */
    void deleteAll(List<Long> ids);
    /**
     * 导出数据
     *
     * @param all      待导出的数据
     * @param response /
     * @throws IOException /
     */
    void download(List<ProductImage> all, HttpServletResponse response) throws IOException;
}
oying-system/src/main/java/com/oying/modules/pc/product/service/ProductLabelService.java
New file
@@ -0,0 +1,86 @@
package com.oying.modules.pc.product.service;
import com.oying.modules.pc.product.domain.ProductLabel;
import com.oying.modules.pc.product.domain.dto.ProductLabelQueryCriteria;
import java.util.Map;
import java.util.List;
import java.io.IOException;
import javax.servlet.http.HttpServletResponse;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.oying.utils.PageResult;
/**
* @description 服务接口
* @author lzp
* @date 2025-05-28
**/
public interface ProductLabelService extends IService<ProductLabel> {
    /**
    * 查询数据分页
    * @param criteria 条件
    * @param page 分页参数
    * @return PageResult
    */
    PageResult<ProductLabel> queryAll(ProductLabelQueryCriteria criteria, Page<Object> page);
    /**
    * 查询所有数据不分页
    * @param criteria 条件参数
    * @return List<ProductLabel>
    */
    List<ProductLabel> queryAll(ProductLabelQueryCriteria criteria);
    /**
     * 查询
     * @param ids /
     * @return List<ProductLabel>
     */
    List<ProductLabel> queryBatchIds(List<Long> ids);
    /**
     * 查询商品的所有标签
     * @param productId /
     * @return List<ProductLabel>
     */
    List<ProductLabel> queryLabelsByProductId(Long productId);
    /**
    * 创建
    * @param resources /
    */
    void create(ProductLabel resources);
    /**
     * 批量创建
     * @param resources /
     */
    void batchCreate(List<ProductLabel> resources);
    /**
    * 编辑
    * @param resources /
    */
    void update(ProductLabel resources);
    /**
     * 编辑
     * @param resources /
     */
    void batchUpdate(List<ProductLabel> resources);
    /**
    * 多选删除
    * @param ids /
    */
    void deleteAll(List<Long> ids);
    /**
    * 导出数据
    * @param all 待导出的数据
    * @param response /
    * @throws IOException /
    */
    void download(List<ProductLabel> all, HttpServletResponse response) throws IOException;
}
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductAdminServiceImpl.java
New file
@@ -0,0 +1,115 @@
package com.oying.modules.pc.product.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjUtil;
import com.oying.exception.EntityExistException;
import com.oying.exception.EntityNotFoundException;
import com.oying.modules.pc.product.converter.ProductImageAssembler;
import com.oying.modules.pc.product.converter.ProductLabelAssembler;
import com.oying.modules.pc.product.domain.Product;
import com.oying.modules.pc.product.domain.ProductImage;
import com.oying.modules.pc.product.domain.ProductLabel;
import com.oying.modules.pc.product.domain.dto.ProductImageCreateRequest;
import com.oying.modules.pc.product.domain.dto.ProductMerchantCreateRequest;
import com.oying.modules.pc.product.domain.dto.ProductMerchantUpdateRequest;
import com.oying.modules.pc.product.domain.enums.ProductStatusEnum;
import com.oying.modules.pc.product.service.ProductAdminService;
import com.oying.modules.pc.product.service.ProductImageService;
import com.oying.modules.pc.product.service.ProductLabelService;
import com.oying.modules.pc.product.service.ProductService;
import com.oying.modules.pc.utils.ImageUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class ProductAdminServiceImpl implements ProductAdminService {
    private final ProductService productService;
    private final ProductImageService productImageService;
    private final ProductLabelService productLabelService;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(ProductMerchantCreateRequest request) {
        Product product = new Product();
        BeanUtils.copyProperties(request, product);
        request.getImages().stream().findFirst().map(ProductImageCreateRequest::getUploadFileId)
                .ifPresent(id -> {
                    product.setMainImageId(id.toString());
                    product.setMainImageUrl(ImageUtils.getPublicObjectUrl(id));
                });
        product.setStatus(ProductStatusEnum.DRAFT.getValue());
        productService.create(product);
        List<ProductImage> productImages = request.getImages().stream().map(i -> {
            i.setProductId(product.getProductId());
            return ProductImageAssembler.to(i);
        }).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(productImages)) {
            productImageService.saveBatch(productImages);
        }
        List<ProductLabel> productLabels = request.getLabels().stream().map(i -> {
            i.setProductId(product.getProductId());
            return ProductLabelAssembler.to(i);
        }).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(productLabels)) {
            productLabelService.saveBatch(productLabels);
        }
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(ProductMerchantUpdateRequest request) {
        Product existingProduct = this.findOrThrow(request.getProductId());
        this.processImagesUpdate(request);
        this.processLabelsUpdate(request);
        BeanUtils.copyProperties(request, existingProduct);
        productService.update(existingProduct);
    }
    @Transactional
    @Override
    public void delete(List<Long> ids) {
        productService.deleteAll(ids);
    }
    private Product findOrThrow(Long productId) {
        Product existingProduct = productService.getById(productId);
        if (ObjUtil.isEmpty(existingProduct)) {
            throw new EntityNotFoundException(Product.class, "id", Optional.ofNullable(productId).map(Object::toString).orElse("null"));
        }
        return existingProduct;
    }
    private void processImagesUpdate(ProductMerchantUpdateRequest request) {
        if (CollectionUtil.isNotEmpty(request.getDeletedImageIds())) {
            productImageService.deleteAll(request.getDeletedImageIds());
        }
        if (CollectionUtil.isNotEmpty(request.getUpdatedImages())) {
            productImageService.batchUpdate(request.getUpdatedImages());
        }
        if (CollectionUtil.isNotEmpty(request.getNewImages())) {
            productImageService.batchCreate(request.getNewImages());
        }
    }
    private void processLabelsUpdate(ProductMerchantUpdateRequest request) {
        if (CollectionUtil.isNotEmpty(request.getDeletedLabelIds())) {
            productLabelService.deleteAll(request.getDeletedLabelIds());
        }
        if (CollectionUtil.isNotEmpty(request.getUpdatedLabels())) {
            productLabelService.batchUpdate(request.getUpdatedLabels());
        }
        if (CollectionUtil.isNotEmpty(request.getNewLabels())) {
            productLabelService.batchCreate(request.getNewLabels());
        }
    }
}
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductImageServiceImpl.java
New file
@@ -0,0 +1,173 @@
package com.oying.modules.pc.product.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.oying.exception.EntityExistException;
import com.oying.exception.EntityNotFoundException;
import com.oying.modules.pc.common.ValueUpdate;
import com.oying.modules.pc.product.converter.ProductImageAssembler;
import com.oying.modules.pc.product.domain.ProductImage;
import com.oying.modules.pc.product.domain.dto.ProductImageCreateRequest;
import com.oying.modules.pc.product.domain.dto.ProductImageQueryCriteria;
import com.oying.modules.pc.product.domain.dto.ProductImageUpdateRequest;
import com.oying.modules.pc.product.mapper.ProductImageMapper;
import com.oying.modules.pc.product.service.ProductImageService;
import com.oying.modules.pc.store.domain.StoreQualification;
import com.oying.service.BucketStorageService;
import com.oying.utils.FileUtil;
import com.oying.utils.PageResult;
import com.oying.utils.PageUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
/**
 * @author lzp
 * @description 服务实现
 * @date 2025-05-28
 **/
@Service
@RequiredArgsConstructor
public class ProductImageServiceImpl extends ServiceImpl<ProductImageMapper, ProductImage> implements ProductImageService {
    private final ProductImageMapper productImageMapper;
    private final BucketStorageService bucketStorageService;
    @Override
    public PageResult<ProductImage> queryAll(ProductImageQueryCriteria criteria, Page<Object> page) {
        return PageUtil.toPage(productImageMapper.findAll(criteria, page));
    }
    @Override
    public List<ProductImage> queryAll(ProductImageQueryCriteria criteria) {
        return productImageMapper.findAll(criteria);
    }
    @Override
    public List<ProductImage> queryBatchIds(List<Long> ids) {
        LambdaQueryWrapper<ProductImage> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.in(ProductImage::getImageId, ids);
        return productImageMapper.selectList(lambdaQueryWrapper);
    }
    @Override
    public List<ProductImage> queryImagesByProductId(Long productId) {
        if (productId == null) {
            return ListUtil.empty();
        }
        LambdaQueryWrapper<ProductImage> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProductImage::getProductId, productId);
        return productImageMapper.selectList(wrapper);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(ProductImageCreateRequest request) {
        productImageMapper.insert(ProductImageAssembler.to(request));
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchCreate(List<ProductImageCreateRequest> requests) {
        this.saveBatch(ProductImageAssembler.toProducts(requests));
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(ProductImageUpdateRequest request) {
        Long updatedImageId = request.getImageId();
        ProductImage existingProductImage = this.getById(updatedImageId);
        if (ObjUtil.isEmpty(existingProductImage)) {
            throw new EntityNotFoundException(ProductImage.class, "imageId", Optional.ofNullable(updatedImageId).map(Object::toString).orElse("null"));
        }
        // 新的图片数据
        ProductImage newProductImage = ProductImageAssembler.to(request);
        // 新的图片数据
        ValueUpdate<Long> cloudStorageUpdate = new ValueUpdate<>(newProductImage.getCloudStorageId(), existingProductImage.getCloudStorageId());
        // 填充新的数据
        existingProductImage.copy(newProductImage);
        productImageMapper.updateById(existingProductImage);
        // 删除旧图片原纪录
        if (cloudStorageUpdate.isChangeAndOldValueNotEmpty()) {
            bucketStorageService.deleteAll(ListUtil.toList(cloudStorageUpdate.getOldValue()));
        }
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchUpdate(List<ProductImageUpdateRequest> requests) {
        List<Long> updatedIds = requests.stream().map(ProductImageUpdateRequest::getImageId).collect(Collectors.toList());
        List<ProductImage> existingProductImages = this.queryBatchIds(updatedIds);
        if (CollectionUtil.isEmpty(existingProductImages)) {
            throw new EntityNotFoundException(ProductImage.class, "imageIds", updatedIds.toString());
        }
        Map<Long, ProductImageUpdateRequest> requestMap = requests.stream().collect(Collectors.toMap(
                                ProductImageUpdateRequest::getImageId,
                                productImageUpdateRequest -> productImageUpdateRequest
                        )
                );
        List<Long> deleteCloudStorageIds = existingProductImages.stream().filter(i -> {
            Long newCloudStorageId = requestMap.get(i.getImageId()).getUploadFileId();
            return ValueUpdate.isChangeAndOldValueNotEmpty(newCloudStorageId, i.getCloudStorageId());
        }).map(ProductImage::getImageId).collect(Collectors.toList());
        // 填充新的数据
        for (ProductImage existingProductImage : existingProductImages) {
            ProductImage newProductImage = ProductImageAssembler.to(requestMap.get(existingProductImage.getImageId()));
            existingProductImage.copy(newProductImage);
        }
        this.updateBatchById(existingProductImages);
        // 删除旧图片原纪录
        if (CollectionUtil.isNotEmpty(deleteCloudStorageIds)) {
            bucketStorageService.deleteAll(deleteCloudStorageIds);
        }
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(List<Long> ids) {
        List<ProductImage> existingProductImages = this.queryBatchIds(ids);
        if (CollectionUtil.isEmpty(existingProductImages)) {
            throw new EntityNotFoundException(ProductImage.class, "productImageIds", ids.toString());
        }
        productImageMapper.deleteBatchIds(ids);
        // 删除图片原纪录
        List<Long> deleteCloudStorageIds = existingProductImages.stream().map(ProductImage::getCloudStorageId).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(deleteCloudStorageIds)) {
            bucketStorageService.deleteAll(deleteCloudStorageIds);
        }
    }
    @Override
    public void download(List<ProductImage> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (ProductImage productImage : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("商品ID", productImage.getProductId());
            map.put("桶ID", productImage.getCloudStorageId());
            map.put("图片key", productImage.getImageType());
            map.put("图片地址", productImage.getImageUrl());
            map.put("排序权重", productImage.getSortWeight());
            map.put("创建人", productImage.getCreateBy());
            map.put("创建日期", productImage.getCreateTime());
            map.put("修改人", productImage.getUpdateBy());
            map.put("修改时间", productImage.getUpdateTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }
}
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductLabelServiceImpl.java
New file
@@ -0,0 +1,133 @@
package com.oying.modules.pc.product.service.impl;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.oying.exception.EntityExistException;
import com.oying.exception.EntityNotFoundException;
import com.oying.modules.pc.product.domain.ProductLabel;
import com.oying.modules.pc.product.domain.dto.ProductLabelQueryCriteria;
import com.oying.modules.pc.product.mapper.ProductLabelMapper;
import com.oying.modules.pc.product.service.ProductLabelService;
import com.oying.utils.FileUtil;
import com.oying.utils.PageResult;
import com.oying.utils.PageUtil;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
 * @author lzp
 * @description 服务实现
 * @date 2025-05-28
 **/
@Service
@RequiredArgsConstructor
public class ProductLabelServiceImpl extends ServiceImpl<ProductLabelMapper, ProductLabel> implements ProductLabelService {
    private final ProductLabelMapper productLabelMapper;
    @Override
    public PageResult<ProductLabel> queryAll(ProductLabelQueryCriteria criteria, Page<Object> page) {
        return PageUtil.toPage(productLabelMapper.findAll(criteria, page));
    }
    @Override
    public List<ProductLabel> queryAll(ProductLabelQueryCriteria criteria) {
        return productLabelMapper.findAll(criteria);
    }
    @Override
    public List<ProductLabel> queryBatchIds(List<Long> ids) {
        LambdaQueryWrapper<ProductLabel> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(ProductLabel::getLabelId, ids);
        return productLabelMapper.selectList(wrapper);
    }
    @Override
    public List<ProductLabel> queryLabelsByProductId(Long productId) {
        if (productId == null) {
            return ListUtil.empty();
        }
        LambdaQueryWrapper<ProductLabel> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ProductLabel::getProductId, productId);
        return productLabelMapper.selectList(wrapper);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(ProductLabel resources) {
        productLabelMapper.insert(resources);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchCreate(List<ProductLabel> resources) {
        this.saveBatch(resources);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(ProductLabel resources) {
        ProductLabel productLabel = getById(resources.getLabelId());
        productLabel.copy(resources);
        productLabelMapper.updateById(productLabel);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchUpdate(List<ProductLabel> resources) {
        List<Long> updateIds = resources.stream().map(ProductLabel::getLabelId).collect(Collectors.toList());
        List<ProductLabel> existingProductLabels = this.queryBatchIds(updateIds);
        if (ObjUtil.isEmpty(existingProductLabels)) {
            throw new EntityNotFoundException(ProductLabel.class, "labelId", updateIds.toString());
        }
        Map<Long, ProductLabel> longProductLabelMap = resources.stream()
                .collect(Collectors.toMap(
                        ProductLabel::getLabelId,
                        productLabel -> productLabel)
                );
        for (ProductLabel existingProductLabel : existingProductLabels) {
            existingProductLabel.copy(longProductLabelMap.get(existingProductLabel.getLabelId()));
        }
        this.updateBatchById(existingProductLabels);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteAll(List<Long> ids) {
        productLabelMapper.deleteBatchIds(ids);
    }
    @Override
    public void download(List<ProductLabel> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (ProductLabel productLabel : all) {
            Map<String, Object> map = new LinkedHashMap<>();
            map.put("商品ID", productLabel.getProductId());
            map.put(" categoryName", productLabel.getCategoryName());
            map.put("标签名称", productLabel.getLabelName());
            map.put("标签值", productLabel.getLabelValue());
            map.put("创建人", productLabel.getCreateBy());
            map.put("创建时间", productLabel.getCreateTime());
            map.put("修改人", productLabel.getUpdateBy());
            map.put("修改时间", productLabel.getUpdateTime());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }
}
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductMerchantServiceImpl.java
New file
@@ -0,0 +1,149 @@
package com.oying.modules.pc.product.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.oying.exception.EntityExistException;
import com.oying.exception.EntityNotFoundException;
import com.oying.modules.pc.product.converter.ProductImageAssembler;
import com.oying.modules.pc.product.converter.ProductLabelAssembler;
import com.oying.modules.pc.product.domain.Product;
import com.oying.modules.pc.product.domain.ProductImage;
import com.oying.modules.pc.product.domain.ProductLabel;
import com.oying.modules.pc.product.domain.dto.ProductImageCreateRequest;
import com.oying.modules.pc.product.domain.dto.ProductLabelCreateRequest;
import com.oying.modules.pc.product.domain.dto.ProductMerchantCreateRequest;
import com.oying.modules.pc.product.domain.dto.ProductMerchantUpdateRequest;
import com.oying.modules.pc.product.domain.enums.ProductStatusEnum;
import com.oying.modules.pc.product.service.ProductImageService;
import com.oying.modules.pc.product.service.ProductLabelService;
import com.oying.modules.pc.product.service.ProductMerchantService;
import com.oying.modules.pc.product.service.ProductService;
import com.oying.modules.pc.utils.ImageUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class ProductMerchantServiceImpl implements ProductMerchantService {
    private final ProductService productService;
    private final ProductImageService productImageService;
    private final ProductLabelService productLabelService;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(ProductMerchantCreateRequest request) {
        Product product = new Product();
        BeanUtils.copyProperties(request, product);
        request.getImages().stream().findFirst().map(ProductImageCreateRequest::getUploadFileId)
                .ifPresent(id -> {
                    product.setMainImageId(id.toString());
                    product.setMainImageUrl(ImageUtils.getPublicObjectUrl(id));
                });
        product.setStatus(ProductStatusEnum.DRAFT.getValue());
        productService.create(product);
        List<ProductImage> productImages = request.getImages().stream().map(i -> {
            i.setProductId(product.getProductId());
            return ProductImageAssembler.to(i);
        }).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(productImages)) {
            productImageService.saveBatch(productImages);
        }
        List<ProductLabel> productLabels = request.getLabels().stream().map(i -> {
            i.setProductId(product.getProductId());
            return ProductLabelAssembler.to(i);
        }).collect(Collectors.toList());
        if (CollectionUtil.isNotEmpty(productLabels)) {
            productLabelService.saveBatch(productLabels);
        }
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(ProductMerchantUpdateRequest request) {
        Product existingProduct = this.findOrThrow(request.getProductId());
        this.processImagesUpdate(request);
        this.processLabelsUpdate(request);
        BeanUtils.copyProperties(request, existingProduct);
        productService.update(existingProduct);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateImages(ProductMerchantUpdateRequest request) {
        this.findOrThrow(request.getProductId());
        this.processImagesUpdate(request);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateLabels(ProductMerchantUpdateRequest request) {
        this.findOrThrow(request.getProductId());
        this.processImagesUpdate(request);
    }
    @Transactional
    @Override
    public void batchDelete(List<Long> ids) {
        productService.deleteAll(ids);
    }
    @Override
    public void putOnShelf(Long productId) {
        LambdaUpdateWrapper<Product> wrapper = new LambdaUpdateWrapper<Product>()
                .eq(Product::getProductId, productId)
                .set(Product::getStatus, ProductStatusEnum.AVAILABLE.getValue());
        productService.update(wrapper);
    }
    @Override
    public void takeOffShelf(Long productId) {
        LambdaUpdateWrapper<Product> wrapper = new LambdaUpdateWrapper<Product>()
                .eq(Product::getProductId, productId)
                .set(Product::getStatus, ProductStatusEnum.NO_AVAILABLE.getValue());
        productService.update(wrapper);
    }
    private Product findOrThrow(Long productId) {
        Product existingProduct = productService.getById(productId);
        if (ObjUtil.isEmpty(existingProduct)) {
            throw new EntityNotFoundException(Product.class, "id", Optional.ofNullable(productId).map(Object::toString).orElse("null"));
        }
        return existingProduct;
    }
    private void processImagesUpdate(ProductMerchantUpdateRequest request) {
        if (CollectionUtil.isNotEmpty(request.getDeletedImageIds())) {
            productImageService.deleteAll(request.getDeletedImageIds());
        }
        if (CollectionUtil.isNotEmpty(request.getUpdatedImages())) {
            productImageService.batchUpdate(request.getUpdatedImages());
        }
        if (CollectionUtil.isNotEmpty(request.getNewImages())) {
            List<ProductImageCreateRequest> newImages = request.getNewImages().stream().peek(i->{i.setProductId(request.getProductId());}).collect(Collectors.toList());
            productImageService.batchCreate(newImages);
        }
    }
    private void processLabelsUpdate(ProductMerchantUpdateRequest request) {
        if (CollectionUtil.isNotEmpty(request.getDeletedLabelIds())) {
            productLabelService.deleteAll(request.getDeletedLabelIds());
        }
        if (CollectionUtil.isNotEmpty(request.getUpdatedLabels())) {
            productLabelService.batchUpdate(request.getUpdatedLabels());
        }
        if (CollectionUtil.isNotEmpty(request.getNewLabels())) {
            List<ProductLabel> newLabels = request.getNewLabels().stream().peek(i->{i.setProductId(request.getProductId());}).collect(Collectors.toList());
            productLabelService.batchCreate(newLabels);
        }
    }
}
oying-system/src/main/java/com/oying/modules/pc/product/view/ProductCustomerView.java
@@ -27,6 +27,12 @@
    @ApiModelProperty(value = "店铺ID")
    private Long storeId;
    @ApiModelProperty(value = "条形码")
    private String barcode;
    @ApiModelProperty(value = "商品名称")
    private String name;
    @ApiModelProperty(value = "商品标题")
    private String title;
@@ -42,6 +48,33 @@
    @ApiModelProperty(value = "销售价格")
    private BigDecimal price;
    @ApiModelProperty(value = "库存数量")
    private Integer stockQuantity;
    @ApiModelProperty(value = "起售数量")
    private Integer minPurchaseQuantity;
    @ApiModelProperty(value = "重量(单位:g)")
    private Integer weight;
    @ApiModelProperty(value = "宽度(单位:厘米)")
    private Integer width;
    @ApiModelProperty(value = "长度(单位:厘米)")
    private Integer length;
    @ApiModelProperty(value = "高度(单位:厘米)")
    private Integer height;
    @ApiModelProperty(value = "是否支持退货")
    private Integer returns;
    @ApiModelProperty(value = "是否支持自提")
    private Integer selfPickup;
    @ApiModelProperty(value = "版本号")
    private Long version;
    @ApiModelProperty(value = "月销售量")
    private Integer monthlySales = 0;
oying-system/src/main/java/com/oying/modules/pc/product/view/ProductMerchantSimpleView.java
@@ -1,5 +1,6 @@
package com.oying.modules.pc.product.view;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@@ -12,11 +13,73 @@
@Data
public class ProductMerchantSimpleView {
    @ApiModelProperty(value = "ID")
    private Long productId;
    @ApiModelProperty(value = "店铺ID")
    private Long storeId;
    @ApiModelProperty(value = "条形码")
    private String barcode;
    @ApiModelProperty(value = "商品名称")
    private String name;
    private BigDecimal price;
    private Integer stockQuantity;
    private Integer sold;
    @ApiModelProperty(value = "商品标题")
    private String title;
    @ApiModelProperty(value = "一级分类ID")
    private Long categoryId;
    @ApiModelProperty(value = "二级分类ID")
    private Long secondCategoryId;
    @ApiModelProperty(value = "状态")
    private Integer status;
    @ApiModelProperty(value = "主图片")
    private String mainImageId;
    @ApiModelProperty(value = "主图地址")
    private String mainImageUrl;
    @ApiModelProperty(value = "商品描述")
    private String description;
    @ApiModelProperty(value = "销售价格")
    private BigDecimal price;
    @ApiModelProperty(value = "库存数量")
    private Integer stockQuantity;
    @ApiModelProperty(value = "起售数量")
    private Integer minPurchaseQuantity;
    @ApiModelProperty(value = "预警库存")
    private Integer warnStock;
    @ApiModelProperty(value = "重量(单位:g)")
    private Integer weight;
    @ApiModelProperty(value = "宽度(单位:厘米)")
    private Integer width;
    @ApiModelProperty(value = "长度(单位:厘米)")
    private Integer length;
    @ApiModelProperty(value = "高度(单位:厘米)")
    private Integer height;
    @ApiModelProperty(value = "是否支持退货")
    private Integer returns;
    @ApiModelProperty(value = "是否支持自提")
    private Integer selfPickup;
    @ApiModelProperty(value = "是否删除")
    private Integer deletedFlag;
    @ApiModelProperty(value = "版本号")
    private Long version;
}
oying-system/src/main/java/com/oying/modules/pc/product/view/ProductSimpleView.java
@@ -1,5 +1,8 @@
package com.oying.modules.pc.product.view;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
@@ -7,15 +10,76 @@
 * @author lzp
 * @date 2025-04-25
 */
@Data
public class ProductSimpleView {
    @ApiModelProperty(value = "商品ID")
    private Long productId;
    private String productTitle;
    private String mainImage;
    private BigDecimal price;
    private BigDecimal originalPrice;  // 原价(用于显示划线价)
    //private Double rating;           // 评分
    //private Integer monthlySales;    // 月销量
    @ApiModelProperty(value = "店铺ID")
    private Long storeId;
    @ApiModelProperty(value = "条形码")
    private String barcode;
    @ApiModelProperty(value = "商品名称")
    private String name;
    @ApiModelProperty(value = "商品标题")
    private String title;
    @ApiModelProperty(value = "一级分类ID")
    private Long categoryId;
    @ApiModelProperty(value = "二级分类ID")
    private Long secondCategoryId;
    @ApiModelProperty(value = "状态")
    private Integer status;
    @ApiModelProperty(value = "主图片")
    private String mainImageId;
    @ApiModelProperty(value = "主图地址")
    private String mainImageUrl;
    @ApiModelProperty(value = "商品描述")
    private String description;
    @ApiModelProperty(value = "销售价格")
    private BigDecimal price;
    @ApiModelProperty(value = "库存数量")
    private Integer stockQuantity;
    @ApiModelProperty(value = "起售数量")
    private Integer minPurchaseQuantity;
    @ApiModelProperty(value = "预警库存")
    private Integer warnStock;
    @ApiModelProperty(value = "重量(单位:g)")
    private Integer weight;
    @ApiModelProperty(value = "宽度(单位:厘米)")
    private Integer width;
    @ApiModelProperty(value = "长度(单位:厘米)")
    private Integer length;
    @ApiModelProperty(value = "高度(单位:厘米)")
    private Integer height;
    @ApiModelProperty(value = "是否支持退货")
    private Integer returns;
    @ApiModelProperty(value = "是否支持自提")
    private Integer selfPickup;
    @ApiModelProperty(value = "是否删除")
    private Integer deletedFlag;
    @ApiModelProperty(value = "版本号")
    private Long version;
}
oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreAssembler.java
New file
@@ -0,0 +1,32 @@
package com.oying.modules.pc.store.converter;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.oying.modules.pc.store.domain.Store;
import com.oying.modules.pc.store.domain.dto.StoreCreateRequest;
import com.oying.modules.pc.store.domain.dto.StoreUpdateRequest;
import com.oying.modules.pc.utils.ImageUtils;
import com.oying.utils.SecurityUtils;
public class StoreAssembler {
    public static Store to(StoreCreateRequest request) {
        Store store = new Store();
        BeanUtil.copyProperties(request, store, CopyOptions.create().setIgnoreNullValue(true));
        store.setMerchantId(SecurityUtils.getCurrentUserId());
        Long logoUploadFileId = request.getLogoUploadFileId();
        store.setLogoImageId(logoUploadFileId);
        store.setLogoImageUrl(ImageUtils.getPublicObjectUrl(logoUploadFileId));
        Long coverUploadFileId = request.getCoverUploadFileId();
        store.setCoverImageId(coverUploadFileId);
        store.setCoverImageUrl(ImageUtils.getPublicObjectUrl(coverUploadFileId));
        return store;
    }
    public static Store to(StoreUpdateRequest request) {
        Store store = new Store();
        BeanUtil.copyProperties(request, store, CopyOptions.create().setIgnoreNullValue(true));
        return store;
    }
}
oying-system/src/main/java/com/oying/modules/pc/store/converter/StoreQualificationAssembler.java
New file
@@ -0,0 +1,32 @@
package com.oying.modules.pc.store.converter;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import com.oying.modules.pc.store.domain.StoreQualification;
import com.oying.modules.pc.store.domain.dto.StoreQualificationCreateRequest;
import com.oying.modules.pc.store.domain.dto.StoreQualificationUpdateRequest;
import com.oying.modules.pc.utils.ImageUtils;
public class StoreQualificationAssembler {
    public static StoreQualification to(StoreQualificationCreateRequest request) {
        StoreQualification storeQualification = new StoreQualification();
        BeanUtil.copyProperties(request, storeQualification, CopyOptions.create().setIgnoreNullValue(true));
        storeQualification.setQualificationType(request.getType());
        Long imageUploadFileId = request.getImageUploadFileId();
        storeQualification.setQualificationImageId(imageUploadFileId);
        storeQualification.setQualificationImageUrl(ImageUtils.getPublicObjectUrl(imageUploadFileId));
        return storeQualification;
    }
    public static StoreQualification to(StoreQualificationUpdateRequest request) {
        StoreQualification storeQualification = new StoreQualification();
        BeanUtil.copyProperties(request, storeQualification, CopyOptions.create().setIgnoreNullValue(true));
        storeQualification.setQualificationType(request.getType());
        Long imageUploadFileId = request.getImageUploadFileId();
        storeQualification.setQualificationImageId(imageUploadFileId);
        storeQualification.setQualificationImageUrl(ImageUtils.getPublicObjectUrl(imageUploadFileId));
        return storeQualification;
    }
}
oying-system/src/main/java/com/oying/modules/pc/store/domain/StoreUser.java
New file
@@ -0,0 +1,39 @@
package com.oying.modules.pc.store.domain;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.oying.base.BaseEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import java.io.Serializable;
import com.baomidou.mybatisplus.annotation.TableName;
/**
* @author lzp
* @date 2025-06-05
**/
@Getter
@Setter
@TableName("sys_user_store")
public class StoreUser extends BaseEntity implements Serializable {
    @ApiModelProperty(value = "店铺ID")
    private Long storeId;
    @ApiModelProperty(value = "用户ID")
    private Long userId;
    @ApiModelProperty(value = "角色类型")
    private String roleType;
    @ApiModelProperty(value = "权限集(备用)")
    private String permissions;
    public void copy(StoreUser source){
        BeanUtil.copyProperties(source,this, CopyOptions.create().setIgnoreNullValue(true));
    }
}
oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreCustomerDetailDto.java
@@ -1,28 +1,80 @@
package com.oying.modules.pc.store.domain.dto;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalTime;
@Data
public class StoreCustomerDetailDto {
    @ApiModelProperty(value = "店铺ID")
    private Long storeId;
    @ApiModelProperty(value = "商户ID")
    private Long merchantId;
    @ApiModelProperty(value = "平台类目")
    private Long platformCategoryId;
    @ApiModelProperty(value = "店铺类型:1-自营 2-加盟 3-第三方")
    private Integer storeType;
    @ApiModelProperty(value = "店铺名称")
    private String storeName;
    @ApiModelProperty(value = "状态")
    private Integer status;
    @ApiModelProperty(value = "店铺logo图片Url")
    private String logoImageUrl;
    @ApiModelProperty(value = "店铺封面图Url")
    private String coverImageUrl;
    @ApiModelProperty(value = "店铺描述")
    private String description;
    private String address;
    @ApiModelProperty(value = "联系电话")
    private String contactPhone;
    @ApiModelProperty(value = "营业开始时间")
    private LocalTime openTime;
    @ApiModelProperty(value = "营业结束时间")
    private LocalTime closeTime;
    private String businessHours;
    private String contactPhone;
    @ApiModelProperty(value = "详细地址")
    private String address;
    private Double score;
    @ApiModelProperty(value = "经度")
    private Double longitude;
    private Integer deliveryDuration;
    @ApiModelProperty(value = "纬度")
    private Double latitude;
    private Integer monthlySales;
    @ApiModelProperty(value = "营业半径(米)")
    private Integer radius;
    @ApiModelProperty(value = "是否支持退货")
    private Integer returns;
    @ApiModelProperty(value = "是否支持自提")
    private Integer selfPickup;
    @TableField(exist = false)
    @ApiModelProperty(value = "评分")
    private Double score = 0d;
    @TableField(exist = false)
    @ApiModelProperty(value = "配送距离")
    private Integer deliveryDuration = 0;
    @TableField(exist = false)
    @ApiModelProperty(value = "月销售量")
    private Integer monthlySales = 0;
}
oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreUpdateRequest.java
New file
@@ -0,0 +1,103 @@
package com.oying.modules.pc.store.domain.dto;
import com.oying.modules.pc.product.domain.Product;
import com.oying.modules.pc.store.domain.StoreQualification;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.List;
/**
 * @author lzp
 * @date 2025-04-21
 **/
@Getter
@Setter
public class StoreUpdateRequest implements Serializable {
    @ApiModelProperty(value = "店铺ID")
    private Long storeId;
    @ApiModelProperty(value = "商户ID")
    private Long merchantId;
    @ApiModelProperty(value = "平台类目")
    private Long platformCategoryId;
    @ApiModelProperty(value = "店铺类型")
    private Integer storeType;
    @ApiModelProperty(value = "店铺名称")
    private String storeName;
    @ApiModelProperty(value = "状态")
    private Integer status;
    @ApiModelProperty(value = "店铺logo图片")
    private Long logoImageId;
    @ApiModelProperty(value = "店铺logo图片Url")
    private String logoImageUrl;
    @ApiModelProperty(value = "店铺封面图")
    private Long coverImageId;
    @ApiModelProperty(value = "店铺封面图Url")
    private String coverImageUrl;
    @ApiModelProperty(value = "店铺描述")
    private String description;
    @ApiModelProperty(value = "配送费用")
    private BigDecimal deliveryFee;
    @ApiModelProperty(value = "起送金额")
    private BigDecimal deliveryMinimum;
    @ApiModelProperty(value = "联系电话")
    private String contactPhone;
    @ApiModelProperty(value = "营业开始时间")
    private LocalTime openTime;
    @ApiModelProperty(value = "营业结束时间")
    private LocalTime closeTime;
    @ApiModelProperty(value = "详细地址")
    private String address;
    @ApiModelProperty(value = "经度")
    private Double longitude;
    @ApiModelProperty(value = "纬度")
    private Double latitude;
    @ApiModelProperty(value = "营业半径(米)")
    private Integer radius;
    @ApiModelProperty(value = "是否支持退货")
    private Integer returns;
    @ApiModelProperty(value = "是否支持自提")
    private Integer selfPickup;
    @ApiModelProperty(value = "版本号")
    private Long version;
    @ApiModelProperty(value = "删除的资质")
    private List<Long> deletedQualificationIds = new ArrayList<>();
    @ApiModelProperty(value = "修改的资质")
    private List<StoreQualificationUpdateRequest> updatedQualifications = new ArrayList<>();
    @ApiModelProperty(value = "新增的资质")
    private List<StoreQualification> newQualifications = new ArrayList<>();
}
oying-system/src/main/java/com/oying/modules/pc/store/domain/enums/StoreCategoryEnum.java
New file
@@ -0,0 +1,28 @@
package com.oying.modules.pc.store.domain.enums;
import lombok.Getter;
@Getter
public enum StoreCategoryEnum {
    NOT(0, "已禁用"),
    YES(1, "已启用");
    private final Integer value;
    private final String reasonPhrase;
    StoreCategoryEnum(int value, String reasonPhrase) {
        this.value = value;
        this.reasonPhrase = reasonPhrase;
    }
    public static StoreCategoryEnum get(Integer code) {
        for (StoreCategoryEnum value : values()) {
            if (value.value.equals(code)) {
                return value;
            }
        }
        return null;
    }
}
oying-system/src/main/java/com/oying/modules/pc/store/mapper/StoreUserMapper.java
New file
@@ -0,0 +1,18 @@
package com.oying.modules.pc.store.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.oying.modules.pc.store.domain.StoreUser;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
/**
* @author lzp
* @date 2025-06-05
**/
@Mapper
public interface StoreUserMapper extends BaseMapper<StoreUser> {
    @Insert("INSERT INTO sys_user_store(store_id, user_id, role_type, create_by, permissions, create_time, update_by, update_time) VALUES(#{storeId}, #{userId}, #{roleType}, #{permissions}, #{createBy}, #{createTime}, #{updateBy}, #{updateTime})")
    int insert(StoreUser storeUser);
}
oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCustomerController.java
@@ -1,5 +1,6 @@
package com.oying.modules.pc.store.rest;
import cn.hutool.core.util.ObjUtil;
import com.oying.modules.pc.product.domain.Product;
import com.oying.modules.pc.product.domain.dto.ProductQueryCriteria;
import com.oying.modules.pc.product.domain.enums.ProductStatusEnum;
@@ -12,6 +13,7 @@
import com.oying.modules.pc.store.service.StoreQualificationService;
import com.oying.modules.pc.store.service.StoreQueryService;
import com.oying.modules.pc.store.service.StoreService;
import com.oying.modules.pc.store.view.CustomerStoreView;
import com.oying.modules.pc.utils.BusinessHoursUtils;
import com.oying.utils.PageResult;
import com.oying.utils.R;
@@ -57,19 +59,22 @@
    @GetMapping(value = "/{storeId}")
    @ApiOperation("查询店铺")
    public ResponseEntity<?> getStoreDetailsById(@PathVariable("storeId") Long storeId) {
    public ResponseEntity<?> getStoreById(@PathVariable("storeId") Long storeId) {
        Store store = storeService.getById(storeId);
        //store.setQualifications(this.getQualificationsByStoreId(store.getStoreId()));
        StoreCustomerDetailDto storeDto = new StoreCustomerDetailDto();
        BeanUtils.copyProperties(store, storeDto);
        storeDto.setBusinessHours(BusinessHoursUtils.formatBusinessHours(store.getOpenTime(), store.getCloseTime()));
        return ResponseEntity.ok(R.success(storeDto));
        CustomerStoreView view = new CustomerStoreView();
        BeanUtils.copyProperties(store, view);
        view.setBusinessHours(BusinessHoursUtils.formatBusinessHours(store.getOpenTime(), store.getCloseTime()));
        return ResponseEntity.ok(R.success(view));
    }
    private List<StoreQualification> getQualificationsByStoreId(Long storeId) {
        StoreQualificationQueryCriteria criteria = new StoreQualificationQueryCriteria();
        criteria.setStoreId(storeId);
        return storeQualificationService.queryAll(criteria);
    @GetMapping(value = "/{storeId}/details")
    @ApiOperation("查询店铺")
    public ResponseEntity<?> getStoreDetailsById(@PathVariable("storeId") Long storeId) {
        Store store = storeService.getById(storeId);
        if (ObjUtil.isNotEmpty(store)) {
            store.setQualifications(storeQualificationService.queryByStoreId(storeId));
        }
        return ResponseEntity.ok(R.success(store));
    }
    private List<Product> getProductsByStoreId(Long storeId) {
oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreMerchantController.java
@@ -3,8 +3,10 @@
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import com.oying.modules.pc.store.domain.dto.StoreUpdateRequest;
import com.oying.modules.pc.store.service.StoreQualificationService;
import com.oying.utils.R;
import com.oying.modules.pc.store.domain.Store;
import com.oying.modules.pc.store.domain.dto.StoreCreateRequest;
@@ -43,6 +45,7 @@
    private final StoreService storeService;
    private final StoreCreateService storeCreateService;
    private final StoreQualificationService storeQualificationService;
    @GetMapping(value = "/list")
    @ApiOperation("查询所有店铺")
@@ -68,13 +71,24 @@
    @GetMapping(value = "/{storeId}")
    @ApiOperation("查询店铺")
    //@PreAuthorize("@el.check('merchant:store:getById')")
    public ResponseEntity<?> getById(@PathVariable Long storeId) {
    public ResponseEntity<?> getStoreById(@PathVariable Long storeId) {
        Store store = storeService.getById(storeId);
        StoreMerchantView view = new StoreMerchantView();
        BeanUtils.copyProperties(store, view);
        return ResponseEntity.ok(R.success(view));
    }
    @GetMapping(value = "/{storeId}/details")
    @ApiOperation("查询店铺")
    //@PreAuthorize("@el.check('merchant:store:getById')")
    public ResponseEntity<?> getStoreDetailsById(@PathVariable Long storeId) {
        Store store = storeService.getById(storeId);
        if (ObjUtil.isNotEmpty(store)) {
            store.setQualifications(storeQualificationService.queryByStoreId(storeId));
        }
        return ResponseEntity.ok(R.success(store));
    }
    @PostMapping
    @ApiOperation("创建店铺")
    //@PreAuthorize("@el.check('merchant:store:create')")
oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreQualificationCustomerController.java
@@ -1,5 +1,7 @@
package com.oying.modules.pc.store.rest;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjUtil;
import com.oying.utils.R;
@@ -34,14 +36,14 @@
    @GetMapping("/list")
    @ApiOperation("查询店铺资质")
    //@PreAuthorize("@el.check('customer:storeQualification:list')")
    public ResponseEntity<?> getQualifications(@PathVariable Long storeId) {
    public ResponseEntity<?> getQualificationsByStoreId(@PathVariable Long storeId) {
        StoreQualificationQueryCriteria criteria = new StoreQualificationQueryCriteria();
        criteria.setStoreId(storeId);
        List<StoreQualification> qualificationList = storeQualificationService.queryAll(criteria);
        List<CustomerStoreQualificationView> viewList = Optional.ofNullable(qualificationList).orElse(ListUtil.empty())
                .stream().map(i -> {
                    CustomerStoreQualificationView view = new CustomerStoreQualificationView();
                    BeanUtils.copyProperties(i, view);
                    BeanUtil.copyProperties(i, view, CopyOptions.create().setIgnoreNullValue(true));
                    view.setType(i.getQualificationType());
                    view.setName(i.getQualificationName());
                    view.setImageUrl(i.getQualificationImageUrl());
oying-system/src/main/java/com/oying/modules/pc/store/service/StoreQualificationService.java
@@ -40,6 +40,13 @@
    List<StoreQualification> queryBatchIds(List<Long> ids);
    /**
     * 查询
     * @param storeId 条件参数
     * @return List<StoreQualification>
     */
    List<StoreQualification> queryByStoreId(Long storeId);
    /**
    * 创建
    * @param resources /
    */
oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreQualificationServiceImpl.java
@@ -57,6 +57,13 @@
    }
    @Override
    public List<StoreQualification> queryByStoreId(Long storeId) {
        LambdaQueryWrapper<StoreQualification> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StoreQualification::getStoreId, storeId);
        return storeQualificationMapper.selectList(wrapper);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(StoreQualification resources) {
        storeQualificationMapper.insert(resources);
oying-system/src/main/java/com/oying/modules/pc/store/view/CustomerStoreView.java
@@ -1,28 +1,79 @@
package com.oying.modules.pc.store.view;
import com.baomidou.mybatisplus.annotation.TableField;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import java.time.LocalTime;
@Data
public class CustomerStoreView {
    private String name;
    @ApiModelProperty(value = "店铺ID")
    private Long storeId;
    private String logoUrl;
    @ApiModelProperty(value = "商户ID")
    private Long merchantId;
    @ApiModelProperty(value = "平台类目")
    private Long platformCategoryId;
    @ApiModelProperty(value = "店铺类型:1-自营 2-加盟 3-第三方")
    private Integer storeType;
    @ApiModelProperty(value = "店铺名称")
    private String storeName;
    @ApiModelProperty(value = "状态")
    private Integer status;
    @ApiModelProperty(value = "店铺logo图片Url")
    private String logoImageUrl;
    @ApiModelProperty(value = "店铺封面图Url")
    private String coverImageUrl;
    @ApiModelProperty(value = "店铺描述")
    private String description;
    private String address;
    @ApiModelProperty(value = "联系电话")
    private String contactPhone;
    @ApiModelProperty(value = "营业开始时间")
    private LocalTime openTime;
    @ApiModelProperty(value = "营业结束时间")
    private LocalTime closeTime;
    private String businessHours;
    private String contactPhone;
    @ApiModelProperty(value = "详细地址")
    private String address;
    private Integer score;
    @ApiModelProperty(value = "经度")
    private Double longitude;
    private Integer deliveryDuration;
    @ApiModelProperty(value = "纬度")
    private Double latitude;
    private Integer monthlySales;
    @ApiModelProperty(value = "营业半径(米)")
    private Integer radius;
    @ApiModelProperty(value = "是否支持退货")
    private Integer returns;
    @ApiModelProperty(value = "是否支持自提")
    private Integer selfPickup;
    @ApiModelProperty(value = "评分")
    private Double score = 0d;
    @ApiModelProperty(value = "配送距离")
    private Integer deliveryDuration = 0;
    @ApiModelProperty(value = "月销售量")
    private Integer monthlySales = 0;
}
oying-system/src/main/java/com/oying/modules/pc/utils/BusinessHoursUtils.java
New file
@@ -0,0 +1,42 @@
package com.oying.modules.pc.utils;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;
import java.time.format.DateTimeFormatter;
public class BusinessHoursUtils {
    // 时间格式
    private static final DateTimeFormatter DEFAULT_FORMATTER = DateTimeFormatter.ofPattern("HH:mm");
    /**
     * 拼接营业时间,如果时间为 null,则返回 "Closed"
     *
     * @param openTime  开始时间
     * @param closeTime 结束时间
     * @return 格式化的营业时间字符串,如 "8:00-22:00"
     */
    public static String formatBusinessHours(LocalTime openTime, LocalTime closeTime) {
        if (openTime == null || closeTime == null) {
            return "Closed";
        }
        return openTime.format(DEFAULT_FORMATTER) + "-" + closeTime.format(DEFAULT_FORMATTER);
    }
    // 示例调用
    public static void main(String[] args) {
        // LocalDateTime localDateTime = LocalDateTime.of(2025, Month.MAY, 10, 8, 0, 0);
        // LocalDateTime localDateTime2 = LocalDateTime.of(2025, Month.MAY, 10, 22, 0, 0);
        LocalTime openTime = LocalTime.of(8, 0);
        LocalTime closeTime =  LocalTime.of(22, 0);
        // 正常情况 → "8:00-22:00"
        System.out.println(formatBusinessHours(openTime, closeTime));
        // 如果时间为 null → "Closed"
        System.out.println(formatBusinessHours(null, null));
    }
}
oying-system/src/main/java/com/oying/modules/pc/utils/ImageUtils.java
New file
@@ -0,0 +1,31 @@
package com.oying.modules.pc.utils;
import com.oying.domain.BucketStorage;
import com.oying.exception.EntityNotFoundException;
import com.oying.service.BucketStorageService;
import com.oying.utils.ObsProperties;
import com.oying.utils.ObsUtils;
import com.oying.utils.SpringBeanHolder;
import java.util.Optional;
public class ImageUtils {
    private final static ObsProperties properties = SpringBeanHolder.getBean(ObsProperties.class);
    private final static BucketStorageService bucketStorageService = SpringBeanHolder.getBean(BucketStorageService.class);
    public static String getPublicObjectUrl(String path) {
        return ObsUtils.getPublicObjectUrl(properties, path);
    }
    public static String getPublicObjectUrl(Long storageId) {
        return Optional.ofNullable(storageId).map(v -> {
            BucketStorage bucketStorage = bucketStorageService.getById(storageId);
            String path = Optional.ofNullable(bucketStorage)
                    .map(BucketStorage::getPath)
                    .orElseThrow(() -> new EntityNotFoundException(BucketStorage.class, "bucketStorageId", storageId.toString()));
            return getPublicObjectUrl(path);
        }).orElse(null);
    }
}
oying-system/src/main/resources/mapper/pc/product/ProductImageMapper.xml
New file
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.oying.modules.pc.product.mapper.ProductImageMapper">
    <resultMap id="BaseResultMap" type="com.oying.modules.pc.product.domain.ProductImage">
        <id column="image_id" property="imageId"/>
        <result column="product_id" property="productId"/>
        <result column="cloud_storage_id" property="cloudStorageId"/>
        <result column="image_type" property="imageType"/>
        <result column="image_url" property="imageUrl"/>
        <result column="sort_weight" property="sortWeight"/>
        <result column="create_by" property="createBy"/>
        <result column="create_time" property="createTime"/>
        <result column="update_by" property="updateBy"/>
        <result column="update_time" property="updateTime"/>
    </resultMap>
    <sql id="Base_Column_List">
        image_id, product_id, cloud_storage_id, image_type, image_url, sort_weight, create_by, create_time, update_by, update_time
    </sql>
    <select id="findAll" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from pc_product_image
        <where>
        </where>
        order by image_id desc
    </select>
</mapper>
oying-system/src/main/resources/mapper/pc/product/ProductLabelMapper.xml
New file
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.oying.modules.pc.product.mapper.ProductLabelMapper">
    <resultMap id="BaseResultMap" type="com.oying.modules.pc.product.domain.ProductLabel">
        <id column="label_id" property="labelId"/>
        <result column="product_id" property="productId"/>
        <result column="category_name" property="categoryName"/>
        <result column="label_name" property="labelName"/>
        <result column="label_value" property="labelValue"/>
        <result column="create_by" property="createBy"/>
        <result column="create_time" property="createTime"/>
        <result column="update_by" property="updateBy"/>
        <result column="update_time" property="updateTime"/>
    </resultMap>
    <sql id="Base_Column_List">
        label_id, product_id, category_name, label_name, label_value, create_by, create_time, update_by, update_time
    </sql>
    <select id="findAll" resultMap="BaseResultMap">
        select
        <include refid="Base_Column_List"/>
        from pc_product_label
        <where>
        </where>
        order by label_id desc
    </select>
</mapper>
oying-system/src/main/resources/mapper/pc/store/StoreQualificationMapper.xml
@@ -8,6 +8,7 @@
        <result column="qualification_number" property="qualificationNumber"/>
        <result column="qualification_name" property="qualificationName"/>
        <result column="qualification_image_id" property="qualificationImageId"/>
        <result column="qualification_image_url" property="qualificationImageUrl"/>
        <result column="start_date" property="startDate"/>
        <result column="end_date" property="endDate"/>
        <result column="status" property="status"/>
@@ -18,8 +19,8 @@
    </resultMap>
    <sql id="Base_Column_List">
        qualification_id, store_id, qualification_type, qualification_number, qualification_name, qualification_image_id, start_date, end_date, status,
        create_by, create_time, update_by, update_time
        qualification_id, store_id, qualification_type, qualification_number, qualification_name, qualification_image_id, qualification_image_url,
        start_date, end_date, status, create_by, create_time, update_by, update_time
    </sql>
    <select id="findAll" resultMap="BaseResultMap">
@@ -27,6 +28,9 @@
        <include refid="Base_Column_List"/>
        from pc_store_qualification
        <where>
            <if test="criteria.qualificationId != null">
                and qualification_id = #{criteria.qualificationId}
            </if>
            <if test="criteria.storeId != null">
                and store_id = #{criteria.storeId}
            </if>