zepengdev
2025-07-19 f6239d1029da4c51ba3b2cec790f7399a210a3df
feat: 优化商品和店铺
14 files modified
130 ■■■■ changed files
oying-system/src/main/java/com/oying/modules/pc/product/domain/Product.java 3 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductAuditData.java 6 ●●●●● 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/dto/ProductRevisionRecord.java 18 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductAuditController.java 2 ●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductController.java 14 ●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductMerchantController.java 10 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/service/ProductAuditService.java 8 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductAuditServiceImpl.java 9 ●●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductMerchantServiceImpl.java 34 ●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreAuditData.java 1 ●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCategoryMerchantController.java 14 ●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreMerchantServiceImpl.java 3 ●●●●● patch | view | raw | blame | history
oying-system/src/main/resources/mapper/pc/product/ProductMapper.xml 6 ●●●● patch | view | raw | blame | history
oying-system/src/main/java/com/oying/modules/pc/product/domain/Product.java
@@ -58,6 +58,9 @@
    @ApiModelProperty(value = "状态")
    private Integer status;
    @ApiModelProperty(value = "上架状态")
    private Integer shelfStatus;
    @NotBlank
    @ApiModelProperty(value = "主图片")
    private String mainImageId;
oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductAuditData.java
@@ -1,5 +1,6 @@
package com.oying.modules.pc.product.domain.dto;
import com.oying.modules.pc.product.domain.Product;
import com.oying.modules.pc.store.domain.Store;
import com.oying.modules.pc.store.domain.dto.StoreRevisionRecord;
import lombok.Data;
@@ -7,7 +8,8 @@
@Data
public class ProductAuditData {
    private Store store;
    private StoreRevisionRecord revisionRecord;
    private Product originalStore;
    private Product product;
    private ProductRevisionRecord revisionRecord;
}
oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductQueryCriteria.java
@@ -21,6 +21,8 @@
    private Integer status;
    private Integer shelfStatus;
    private Long categoryId;
    private Long secondCategoryId;
oying-system/src/main/java/com/oying/modules/pc/product/domain/dto/ProductRevisionRecord.java
@@ -10,23 +10,5 @@
@Data
public class ProductRevisionRecord {
    @ApiModelProperty(value = "店铺ID")
    private Long storeId;
    @ApiModelProperty(value = "店铺名称")
    private String storeName;
    @ApiModelProperty(value = "资质")
    private List<StoreQualification> qualifications = new ArrayList<>();
    @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/product/rest/ProductAuditController.java
@@ -54,7 +54,7 @@
        return ResponseEntity.noContent().build();
    }
    @PostMapping(value = "/verdict")
    @PutMapping(value = "/verdict")
    @ApiOperation("处理审核")
    public ResponseEntity<?> submitAuditVerdict(@RequestBody ProductAudit resources) {
        auditService.processVerdict(resources);
oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductController.java
@@ -76,7 +76,7 @@
        return ResponseEntity.ok(R.success(pageResult));
    }
    @GetMapping(value = "/{productId}}")
    @GetMapping(value = "/{productId}")
    @ApiOperation("查询商品")
    // @PreAuthorize("@el.check('product:list')")
    public ResponseEntity<?> getProduct(@PathVariable Long productId) {
@@ -87,8 +87,8 @@
        return ResponseEntity.ok(R.success(product));
    }
    @GetMapping(value = "/{productId}}/details")
    @ApiOperation("查询商品")
    @GetMapping(value = "/{productId}/details")
    @ApiOperation("查询商品详情")
    // @PreAuthorize("@el.check('product:list')")
    public ResponseEntity<?> getProductDetails(@PathVariable Long productId) {
        Product product = productService.getById(productId);
@@ -99,16 +99,16 @@
        return ResponseEntity.ok(R.success(product));
    }
    @GetMapping(value = "/{productId}}/images")
    @ApiOperation("查询商品")
    @GetMapping(value = "/{productId}/images")
    @ApiOperation("查询商品图片")
    // @PreAuthorize("@el.check('product:list')")
    public ResponseEntity<?> getProductImages(@PathVariable Long productId) {
        return ResponseEntity.ok(R.success(productImageService.queryImagesByProductId(productId)));
    }
    @GetMapping(value = "/{productId}}/labels")
    @ApiOperation("查询商品")
    @GetMapping(value = "/{productId}/labels")
    @ApiOperation("查询商品标签信息")
    // @PreAuthorize("@el.check('product:list')")
    public ResponseEntity<?> getProductLabels(@PathVariable Long productId) {
        return ResponseEntity.ok(R.success(productLabelService.queryLabelsByProductId(productId)));
oying-system/src/main/java/com/oying/modules/pc/product/rest/ProductMerchantController.java
@@ -124,6 +124,16 @@
        return ResponseEntity.noContent().build();
    }
    @PostMapping(value = "/delete")
    @Log("批量删除商品")
    @ApiOperation("批量删除商品")
    //@PreAuthorize("@el.check('merchant:product:batchDel') " +
    //        "and @storeMerchantOwnershipService.check(#storeId)")
    public ResponseEntity<?> delProduct(@ApiParam(value = "传ID数组[]") @RequestBody List<Long> ids) {
        productMerchantService.batchDelete(ids);
        return ResponseEntity.noContent().build();
    }
    @PutMapping(value = "/{productId}/on")
    @Log("上架商品")
    @ApiOperation("上架商品")
oying-system/src/main/java/com/oying/modules/pc/product/service/ProductAuditService.java
@@ -43,6 +43,14 @@
    ProductAudit getByProductId(Long productId);
    /**
     * 是否有待审记录
     *
     * @param productId 必须的参数,不能为null
     * @return 查询到的结果
     */
    boolean hasPendingByStoreId(Long productId);
    /**
     * 创建
     *
     * @param resources /
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductAuditServiceImpl.java
@@ -10,6 +10,7 @@
import com.oying.modules.pc.product.events.ProductAuditVerdictEvent;
import com.oying.modules.pc.product.mapper.ProductAuditMapper;
import com.oying.modules.pc.product.service.ProductAuditService;
import com.oying.modules.pc.store.domain.StoreAudit;
import com.oying.utils.FileUtil;
import com.oying.utils.PageResult;
import com.oying.utils.PageUtil;
@@ -56,6 +57,14 @@
    }
    @Override
    public boolean hasPendingByStoreId(Long productId) {
        LambdaQueryWrapper<ProductAudit> wrapper = new LambdaQueryWrapper<ProductAudit>()
                .eq(ProductAudit::getProductId, productId)
                .eq(ProductAudit::getStatus, AuditStatusEnum.PENDING.getValue());
        return productAuditMapper.selectCount(wrapper) > 0;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(ProductAudit resources) {
        productAuditMapper.insert(resources);
oying-system/src/main/java/com/oying/modules/pc/product/service/impl/ProductMerchantServiceImpl.java
@@ -2,6 +2,7 @@
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.oying.exception.BadRequestException;
import com.oying.exception.EntityNotFoundException;
@@ -12,6 +13,7 @@
import com.oying.modules.pc.product.domain.ProductAudit;
import com.oying.modules.pc.product.domain.ProductImage;
import com.oying.modules.pc.product.domain.ProductLabel;
import com.oying.modules.pc.product.domain.dto.ProductAuditData;
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;
@@ -76,7 +78,7 @@
    @Transactional(rollbackFor = Exception.class)
    public void update(ProductMerchantUpdateRequest request) {
        Product existingProduct = this.findOrThrow(request.getProductId());
        this.validateApprovedStatus(existingProduct.getStatus());
        this.validateApprovedStatus(existingProduct.getShelfStatus());
        this.processImagesUpdate(request);
        this.processLabelsUpdate(request);
        BeanUtils.copyProperties(request, existingProduct);
@@ -87,7 +89,7 @@
    @Transactional(rollbackFor = Exception.class)
    public void updateImages(ProductMerchantUpdateRequest request) {
        Product existingProduct = this.findOrThrow(request.getProductId());
        this.validateApprovedStatus(existingProduct.getStatus());
        this.validateApprovedStatus(existingProduct.getShelfStatus());
        this.findOrThrow(request.getProductId());
        this.processImagesUpdate(request);
    }
@@ -96,7 +98,7 @@
    @Transactional(rollbackFor = Exception.class)
    public void updateLabels(ProductMerchantUpdateRequest request) {
        Product existingProduct = this.findOrThrow(request.getProductId());
        this.validateApprovedStatus(existingProduct.getStatus());
        this.validateApprovedStatus(existingProduct.getShelfStatus());
        this.findOrThrow(request.getProductId());
        this.processImagesUpdate(request);
    }
@@ -109,10 +111,22 @@
    @Override
    public void putOnShelf(Long productId) {
        Product existingProduct = productService.getById(productId);
        if (ProductStatusEnum.AVAILABLE.getValue().equals(existingProduct.getShelfStatus())) {
            throw new BadRequestException("商品已上架");
        }
        if (productAuditService.hasPendingByStoreId(productId)) {
            throw new BadRequestException("已在审核中");
        }
        ProductAudit audit = new ProductAudit();
        audit.setProductId(productId);
        audit.setType(ProductChangeTypeEnum.PUT_ON_SHELF.name());
        audit.setStatus(AuditStatusEnum.PENDING.getValue());
        ProductAuditData auditData = new ProductAuditData();
        auditData.setOriginalStore(existingProduct);
        audit.setData(JSON.toJSONString(auditData));
        productAuditService.create(audit);
        LambdaUpdateWrapper<Product> wrapper = new LambdaUpdateWrapper<Product>()
                .eq(Product::getProductId, productId)
@@ -122,9 +136,14 @@
    @Override
    public void takeOffShelf(Long productId) {
        Product existingProduct = productService.getById(productId);
        if (ProductStatusEnum.NO_AVAILABLE.getValue().equals(existingProduct.getShelfStatus())) {
            return;
        }
        LambdaUpdateWrapper<Product> wrapper = new LambdaUpdateWrapper<Product>()
                .eq(Product::getProductId, productId)
                .set(Product::getStatus, ProductStatusEnum.NO_AVAILABLE.getValue());
                .set(Product::getStatus, ProductStatusEnum.NO_AVAILABLE.getValue())
                .set(Product::getShelfStatus, ProductStatusEnum.NO_AVAILABLE.getValue());
        productService.update(wrapper);
    }
@@ -179,11 +198,14 @@
    private void handlePutOnShelfAuditEvent(ProductAudit audit) {
        AuditStatusEnum auditStatus = AuditStatusEnum.get(audit.getStatus());
        if (AuditStatusEnum.APPROVED.equals(auditStatus)) {
            Product existingProduct = productService.getById(audit.getProductId());
        if (AuditStatusEnum.APPROVED.equals(auditStatus)) {
            existingProduct.setStatus(ProductStatusEnum.AVAILABLE.getValue());
            existingProduct.setShelfStatus(ProductStatusEnum.AVAILABLE.getValue());
        } else {
            existingProduct.setStatus(auditStatus.getValue());
            productService.updateById(existingProduct);
        }
        productService.updateById(existingProduct);
    }
    private void validateApprovedStatus(Integer status) {
oying-system/src/main/java/com/oying/modules/pc/store/domain/dto/StoreAuditData.java
@@ -6,6 +6,7 @@
@Data
public class StoreAuditData {
    private Store originalStore;
    private Store store;
    private StoreRevisionRecord revisionRecord;
oying-system/src/main/java/com/oying/modules/pc/store/rest/StoreCategoryMerchantController.java
@@ -126,10 +126,20 @@
    @DeleteMapping
    @Log("删除店铺类目")
    @ApiOperation("删除店铺类目")
    @PreAuthorize("@el.check('storeCategory:del')" +
            " and @storeMerchantOwnershipService.check(#storeId)")
    /*@PreAuthorize("@el.check('storeCategory:del')" +
            " and @storeMerchantOwnershipService.check(#storeId)")*/
    public ResponseEntity<?> deleteStoreCategory(@ApiParam(value = "传ID数组[]") @RequestBody List<Long> ids) {
        storeCategoryService.deleteAll(ids);
        return ResponseEntity.noContent().build();
    }
    @PostMapping(value = "/delete")
    @Log("删除店铺类目")
    @ApiOperation("删除店铺类目")
    /*@PreAuthorize("@el.check('storeCategory:del')" +
            " and @storeMerchantOwnershipService.check(#storeId)")*/
    public ResponseEntity<?> delStoreCategory(@ApiParam(value = "传ID数组[]") @RequestBody List<Long> ids) {
        storeCategoryService.deleteAll(ids);
        return ResponseEntity.noContent().build();
    }
}
oying-system/src/main/java/com/oying/modules/pc/store/service/impl/StoreMerchantServiceImpl.java
@@ -65,6 +65,8 @@
            BeanUtil.copyProperties(request, existingStore, CopyOptions.create().setIgnoreNullValue(true));
            storeService.update(existingStore, true);
        } else if (AuditStatusEnum.APPROVED.equals(existingStatus)) {
            Store originalStore = new Store();
            BeanUtil.copyProperties(existingStore, originalStore, CopyOptions.create().setIgnoreNullValue(true));
            Store newStore = new Store();
            newStore.setQualifications(ListUtil.of());
            BeanUtil.copyProperties(request, newStore, CopyOptions.create().setIgnoreNullValue(true));
@@ -95,6 +97,7 @@
            StoreRevisionRecord revisionRecord = new StoreRevisionRecord();
            BeanUtil.copyProperties(request, revisionRecord, CopyOptions.create().setIgnoreNullValue(true));
            StoreAuditData auditData = new StoreAuditData();
            auditData.setOriginalStore(originalStore);
            auditData.setStore(newStore);
            auditData.setRevisionRecord(revisionRecord);
            this.createLatestModification(request.getStoreId(), StoreChangeTypeEnum.STORE_UPDATE, auditData);
oying-system/src/main/resources/mapper/pc/product/ProductMapper.xml
@@ -11,6 +11,7 @@
        <result column="category_id" property="categoryId"/>
        <result column="second_category_id" property="secondCategoryId"/>
        <result column="status" property="status"/>
        <result column="shelf_status" property="shelfStatus"/>
        <result column="main_image_id" property="mainImageId"/>
        <result column="main_image_Url" property="mainImageUrl"/>
        <result column="description" property="description"/>
@@ -33,7 +34,7 @@
    </resultMap>
    <sql id="Base_Column_List">
        product_id, store_id, code, barcode, name, title, category_id, second_category_id, status, main_image_id, main_image_url, description, price, stock_quantity, min_purchase_quantity, warn_stock, weight, width, length, height, returns, self_pickup, deleted_flag, create_by, create_time, update_by, update_time, version
        product_id, store_id, code, barcode, name, title, category_id, second_category_id, status, shelf_status, main_image_id, main_image_url, description, price, stock_quantity, min_purchase_quantity, warn_stock, weight, width, length, height, returns, self_pickup, deleted_flag, create_by, create_time, update_by, update_time, version
    </sql>
    <select id="findAll" resultMap="BaseResultMap">
@@ -56,6 +57,9 @@
            <if test="criteria.status != null">
                and status = #{criteria.status}
            </if>
            <if test="criteria.shelfStatus != null">
                and shelf_status = #{criteria.shelfStatus}
            </if>
            <if test="criteria.active != null">
                and active = #{criteria.active}
            </if>