Просмотр исходного кода

feat(phase1): Product 实体/Mapper/DTO/Service 实现

User 3 месяцев назад
Родитель
Сommit
69b897f59e

+ 53 - 0
zxyj-backend/src/main/java/com/zxyj/dto/ProductDTO.java

@@ -0,0 +1,53 @@
+package com.zxyj.dto;
+
+import com.zxyj.entity.Product;
+import lombok.Data;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class ProductDTO {
+    private Long id;
+    private String name;
+    private String description;
+    private String intro;
+    private String coverImage;
+    private String images;
+    private BigDecimal price;
+    private BigDecimal memberPrice;
+    private Integer stock;
+    private Integer salesCount;
+    private String productType;
+    private Long vendorId;
+    private String vendorName;
+    private String status;
+    private String domain;
+    private String memberEligible;
+    private Date createdAt;
+    private Date updatedAt;
+
+    public static ProductDTO from(Product p) {
+        if (p == null) return null;
+        ProductDTO d = new ProductDTO();
+        d.id = p.getId();
+        d.name = p.getName();
+        d.description = p.getDescription();
+        d.intro = p.getIntro();
+        d.coverImage = p.getCoverImage();
+        d.images = p.getImages();
+        d.price = p.getPrice();
+        d.memberPrice = p.getMemberPrice();
+        d.stock = p.getStock();
+        d.salesCount = p.getSalesCount();
+        d.productType = p.getProductType();
+        d.vendorId = p.getVendorId();
+        d.vendorName = p.getVendorName();
+        d.status = p.getStatus();
+        d.domain = p.getDomain();
+        d.memberEligible = p.getMemberEligible();
+        d.createdAt = p.getCreatedAt();
+        d.updatedAt = p.getUpdatedAt();
+        return d;
+    }
+}

+ 13 - 0
zxyj-backend/src/main/java/com/zxyj/dto/ProductListQueryDTO.java

@@ -0,0 +1,13 @@
+package com.zxyj.dto;
+
+import lombok.Data;
+
+@Data
+public class ProductListQueryDTO {
+    private Integer page = 1;
+    private Integer size = 10;
+    private String productType;
+    private String domain;
+    private Long vendorId;
+    private String keyword;
+}

+ 40 - 0
zxyj-backend/src/main/java/com/zxyj/entity/Product.java

@@ -0,0 +1,40 @@
+package com.zxyj.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+@TableName("products")
+public class Product implements Serializable {
+
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    private String name;
+    private String description;
+    private String intro;
+    private String coverImage;
+    private String images;
+    private BigDecimal price;
+    private Integer stock;
+    private Integer salesCount;
+    private String productType;
+    private Long vendorId;
+    private String vendorName;
+    private String status;
+    private String rejectReason;
+    private BigDecimal memberPrice;
+    private String memberEligible;
+    private String domain;
+    private String externalSource;
+    private String externalId;
+    private String externalData;
+    private Date createdAt;
+    private Date updatedAt;
+}

+ 9 - 0
zxyj-backend/src/main/java/com/zxyj/mapper/ProductMapper.java

@@ -0,0 +1,9 @@
+package com.zxyj.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zxyj.entity.Product;
+import org.apache.ibatis.annotations.Mapper;
+
+@Mapper
+public interface ProductMapper extends BaseMapper<Product> {
+}

+ 186 - 0
zxyj-backend/src/main/java/com/zxyj/service/ProductService.java

@@ -0,0 +1,186 @@
+package com.zxyj.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.zxyj.common.Result;
+import com.zxyj.dto.ProductDTO;
+import com.zxyj.dto.ProductListQueryDTO;
+import com.zxyj.entity.Product;
+import com.zxyj.entity.User;
+import com.zxyj.mapper.ProductMapper;
+import com.zxyj.mapper.UserMapper;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+@Service
+public class ProductService {
+
+    @Resource
+    private ProductMapper productMapper;
+
+    @Resource
+    private UserMapper userMapper;
+
+    public Result<Map<String, Object>> list(ProductListQueryDTO query) {
+        Page<Product> page = new Page<>(query.getPage(), query.getSize());
+        LambdaQueryWrapper<Product> wrapper = new LambdaQueryWrapper<Product>()
+            .eq(Product::getStatus, "on_shelf")
+            .orderByDesc(Product::getCreatedAt);
+        if (query.getProductType() != null && !query.getProductType().isEmpty()) {
+            wrapper.eq(Product::getProductType, query.getProductType());
+        }
+        if (query.getDomain() != null && !query.getDomain().isEmpty()) {
+            wrapper.eq(Product::getDomain, query.getDomain());
+        }
+        if (query.getKeyword() != null && !query.getKeyword().isEmpty()) {
+            wrapper.like(Product::getName, query.getKeyword());
+        }
+        IPage<Product> result = productMapper.selectPage(page, wrapper);
+        List<ProductDTO> records = result.getRecords().stream()
+            .map(ProductDTO::from)
+            .collect(Collectors.toList());
+        Map<String, Object> data = new HashMap<>();
+        data.put("records", records);
+        data.put("total", result.getTotal());
+        data.put("page", result.getCurrent());
+        data.put("size", result.getSize());
+        return Result.success(data);
+    }
+
+    public Result<ProductDTO> detail(Long id) {
+        Product product = productMapper.selectById(id);
+        if (product == null) {
+            return Result.error("商品不存在");
+        }
+        if (!"on_shelf".equals(product.getStatus()) && !"approved".equals(product.getStatus())) {
+            return Result.error("商品未上架");
+        }
+        return Result.success(ProductDTO.from(product));
+    }
+
+    public Result<ProductDTO> create(Product product, Long vendorId) {
+        if (vendorId == null) {
+            return Result.error("请先登录");
+        }
+        User vendor = userMapper.selectById(vendorId);
+        if (vendor == null || !"approved".equals(vendor.getVendorStatus())) {
+            return Result.error("仅审核通过的服务商可发布商品");
+        }
+        product.setVendorId(vendorId);
+        product.setVendorName(vendor.getNickname() != null ? vendor.getNickname() : vendor.getRealName());
+        product.setStatus("pending");
+        product.setCreatedAt(new Date());
+        product.setUpdatedAt(new Date());
+        productMapper.insert(product);
+        return Result.success(ProductDTO.from(product));
+    }
+
+    public Result<ProductDTO> update(Product product, Long vendorId) {
+        Product existing = productMapper.selectById(product.getId());
+        if (existing == null) {
+            return Result.error("商品不存在");
+        }
+        if (!existing.getVendorId().equals(vendorId)) {
+            return Result.error("无权修改此商品");
+        }
+        product.setStatus("pending");
+        product.setUpdatedAt(new Date());
+        productMapper.updateById(product);
+        return Result.success(ProductDTO.from(productMapper.selectById(product.getId())));
+    }
+
+    public Result<List<ProductDTO>> myProducts(Long vendorId) {
+        List<Product> list = productMapper.selectList(
+            new LambdaQueryWrapper<Product>()
+                .eq(Product::getVendorId, vendorId)
+                .orderByDesc(Product::getCreatedAt)
+        );
+        List<ProductDTO> dtos = list.stream().map(ProductDTO::from).collect(Collectors.toList());
+        return Result.success(dtos);
+    }
+
+    public Result<String> shelve(Long productId, Long vendorId, String action) {
+        Product product = productMapper.selectById(productId);
+        if (product == null) {
+            return Result.error("商品不存在");
+        }
+        if (!product.getVendorId().equals(vendorId)) {
+            return Result.error("无权操作");
+        }
+        if (!"approved".equals(product.getStatus())) {
+            return Result.error("商品未通过审核,无法上下架");
+        }
+        if ("shelve".equals(action)) {
+            product.setStatus("on_shelf");
+        } else if ("unshelve".equals(action)) {
+            product.setStatus("off_shelf");
+        } else {
+            return Result.error("操作类型错误");
+        }
+        product.setUpdatedAt(new Date());
+        productMapper.updateById(product);
+        return Result.success("操作成功");
+    }
+
+    public Result<String> review(Long productId, String action, String rejectReason) {
+        Product product = productMapper.selectById(productId);
+        if (product == null) {
+            return Result.error("商品不存在");
+        }
+        if (!"pending".equals(product.getStatus())) {
+            return Result.error("仅待审核商品可审核");
+        }
+        if ("approve".equals(action)) {
+            product.setStatus("approved");
+            product.setRejectReason(null);
+        } else if ("reject".equals(action)) {
+            product.setStatus("rejected");
+            product.setRejectReason(rejectReason != null ? rejectReason : "不符合规范");
+        } else {
+            return Result.error("操作类型错误");
+        }
+        product.setUpdatedAt(new Date());
+        productMapper.updateById(product);
+        return Result.success("操作成功");
+    }
+
+    public Result<List<ProductDTO>> pendingReview() {
+        List<Product> list = productMapper.selectList(
+            new LambdaQueryWrapper<Product>()
+                .eq(Product::getStatus, "pending")
+                .orderByAsc(Product::getCreatedAt)
+        );
+        List<ProductDTO> dtos = list.stream().map(ProductDTO::from).collect(Collectors.toList());
+        return Result.success(dtos);
+    }
+
+    public Result<List<ProductDTO>> adminList(String status) {
+        LambdaQueryWrapper<Product> wrapper = new LambdaQueryWrapper<Product>()
+            .orderByDesc(Product::getCreatedAt);
+        if (status != null && !status.isEmpty()) {
+            wrapper.eq(Product::getStatus, status);
+        }
+        List<Product> list = productMapper.selectList(wrapper);
+        List<ProductDTO> dtos = list.stream().map(ProductDTO::from).collect(Collectors.toList());
+        return Result.success(dtos);
+    }
+
+    public boolean decreaseStock(Long productId, Integer quantity) {
+        Product product = productMapper.selectById(productId);
+        if (product == null || product.getStock() < quantity) {
+            return false;
+        }
+        product.setStock(product.getStock() - quantity);
+        product.setSalesCount((product.getSalesCount() != null ? product.getSalesCount() : 0) + quantity);
+        product.setUpdatedAt(new Date());
+        productMapper.updateById(product);
+        return true;
+    }
+}