Jelajahi Sumber

Merge remote-tracking branch 'origin/feature/mall_product' into feature/mall_product

# Conflicts:
#	yudao-module-member/yudao-module-member-biz/pom.xml
xiaqing 1 tahun lalu
induk
melakukan
0200fa6e53
27 mengubah file dengan 482 tambahan dan 39 penghapusan
  1. 1 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppProductCommentController.java
  2. 3 3
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentStatisticsRespVO.java
  3. 12 2
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/AppFavoriteController.java
  4. 19 0
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoriteBatchReqVO.java
  5. 1 1
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoriteReqVO.java
  6. 1 2
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/comment/ProductCommentConvert.java
  7. 1 3
      yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java
  8. 39 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleCategoryController.java
  9. 90 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleController.java
  10. 14 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/article/AppArticlePageReqVO.java
  11. 49 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/article/AppArticleRespVO.java
  12. 26 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/category/AppArticleCategoryRespVO.java
  13. 38 4
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponController.java
  14. 36 6
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponTemplateController.java
  15. 18 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponPageReqVO.java
  16. 45 0
      yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponRespVO.java
  17. 5 0
      yudao-module-member/yudao-module-member-biz/pom.xml
  18. 1 2
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressBaseVO.java
  19. 7 5
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressRespVO.java
  20. 1 1
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressUpdateReqVO.java
  21. 9 3
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/address/AddressConvert.java
  22. 1 1
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/address/MemberAddressDO.java
  23. 1 1
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/address/AddressMapper.java
  24. 4 4
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/address/AddressServiceImpl.java
  25. 34 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/ip/AppAreaController.java
  26. 23 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/ip/vo/AppAreaNodeRespVO.java
  27. 3 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/ip/AreaConvert.java

+ 1 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/AppProductCommentController.java

@@ -85,7 +85,7 @@ public class AppProductCommentController {
     }
 
     // TODO 芋艿:需要搞下
-    @GetMapping("/getCommentStatistics")
+    @GetMapping("/statistics")
     @Operation(summary = "获得商品的评价统计")
     public CommonResult<AppCommentStatisticsRespVO> getCommentStatistics(@Valid @RequestParam("spuId") Long spuId) {
         return success(productCommentService.getCommentStatistics(spuId, Boolean.TRUE));

+ 3 - 3
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/comment/vo/AppCommentStatisticsRespVO.java

@@ -9,9 +9,6 @@ import lombok.ToString;
 @ToString(callSuper = true)
 public class AppCommentStatisticsRespVO {
 
-    @Schema(description = "所有评论数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15721")
-    private Long allCount;
-
     @Schema(description = "好评数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15721")
     private Long goodCount;
 
@@ -21,4 +18,7 @@ public class AppCommentStatisticsRespVO {
     @Schema(description = "差评数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "15721")
     private Long negativeCount;
 
+    @Schema(description = "总平均分", requiredMode = Schema.RequiredMode.REQUIRED, example = "3.55")
+    private Double scores;
+
 }

+ 12 - 2
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/AppFavoriteController.java

@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
 import cn.iocoder.yudao.framework.common.pojo.PageResult;
 import cn.iocoder.yudao.framework.security.core.annotations.PreAuthenticated;
+import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoriteBatchReqVO;
 import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoritePageReqVO;
 import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoriteReqVO;
 import cn.iocoder.yudao.module.product.controller.app.favorite.vo.AppFavoriteRespVO;
@@ -43,15 +44,24 @@ public class AppFavoriteController {
     }
 
     @DeleteMapping(value = "/delete")
-    @Operation(summary = "取消商品收藏")
+    @Operation(summary = "取消单个商品收藏")
     @PreAuthenticated
     public CommonResult<Boolean> deleteFavorite(@RequestBody @Valid AppFavoriteReqVO reqVO) {
         productFavoriteService.deleteFavorite(getLoginUserId(), reqVO.getSpuId());
         return success(Boolean.TRUE);
     }
 
+    @DeleteMapping(value = "/delete-list")
+    @Operation(summary = "取消多个商品收藏")
+    @PreAuthenticated
+    public CommonResult<Boolean> deleteFavoriteList(@RequestBody @Valid AppFavoriteBatchReqVO reqVO) {
+        // todo @jason:待实现
+//        productFavoriteService.deleteFavorite(getLoginUserId(), reqVO.getSpuId());
+        return success(Boolean.TRUE);
+    }
+
     @GetMapping(value = "/page")
-    @Operation(summary = "分页获取商品收藏列表")
+    @Operation(summary = "获得商品收藏分页")
     @PreAuthenticated
     public CommonResult<PageResult<AppFavoriteRespVO>> getFavoritePage(AppFavoritePageReqVO reqVO) {
         PageResult<ProductFavoriteDO> favoritePage = productFavoriteService.getFavoritePage(getLoginUserId(), reqVO);

+ 19 - 0
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoriteBatchReqVO.java

@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.product.controller.app.favorite.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import java.util.List;
+
+import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
+
+@Schema(description = "用户 APP - 商品收藏的批量 Request VO") // 用于收藏、取消收藏、获取收藏
+@Data
+public class AppFavoriteBatchReqVO {
+
+    @Schema(description = "商品 SPU 编号数组", requiredMode = REQUIRED, example = "29502")
+    @NotEmpty(message = "商品 SPU 编号数组不能为空")
+    private List<Long> spuIds;
+
+}

+ 1 - 1
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/controller/app/favorite/vo/AppFavoriteReqVO.java

@@ -7,7 +7,7 @@ import javax.validation.constraints.NotNull;
 
 import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
 
-@Schema(description = "用户 APP - 商品收藏 Request VO") // 用于收藏、取消收藏、获取收藏
+@Schema(description = "用户 APP - 商品收藏的单个 Request VO") // 用于收藏、取消收藏、获取收藏
 @Data
 public class AppFavoriteReqVO {
 

+ 1 - 2
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/convert/comment/ProductCommentConvert.java

@@ -33,11 +33,10 @@ public interface ProductCommentConvert {
     ProductCommentRespVO convert(ProductCommentDO bean);
 
     // TODO @puhui999:这里貌似字段对上,就不用 mapping 了;可以测试下看看哈
-    @Mapping(target = "allCount", source = "allCount")
     @Mapping(target = "goodCount", source = "goodCount")
     @Mapping(target = "mediocreCount", source = "mediocreCount")
     @Mapping(target = "negativeCount", source = "negativeCount")
-    AppCommentStatisticsRespVO convert(Long allCount, Long goodCount, Long mediocreCount, Long negativeCount);
+    AppCommentStatisticsRespVO convert(Long goodCount, Long mediocreCount, Long negativeCount);
 
     List<ProductCommentRespVO> convertList(List<ProductCommentDO> list);
 

+ 1 - 3
yudao-module-mall/yudao-module-product-biz/src/main/java/cn/iocoder/yudao/module/product/service/comment/ProductCommentServiceImpl.java

@@ -135,15 +135,13 @@ public class ProductCommentServiceImpl implements ProductCommentService {
     @Override
     public AppCommentStatisticsRespVO getCommentStatistics(Long spuId, Boolean visible) {
         return ProductCommentConvert.INSTANCE.convert(
-                // 查询商品 id = spuId 的所有评论数量
-                productCommentMapper.selectCountBySpuId(spuId, visible, null),
                 // 查询商品 id = spuId 的所有好评数量
                 productCommentMapper.selectCountBySpuId(spuId, visible, AppCommentPageReqVO.GOOD_COMMENT),
                 // 查询商品 id = spuId 的所有中评数量
                 productCommentMapper.selectCountBySpuId(spuId, visible, AppCommentPageReqVO.MEDIOCRE_COMMENT),
                 // 查询商品 id = spuId 的所有差评数量
                 productCommentMapper.selectCountBySpuId(spuId, visible, AppCommentPageReqVO.NEGATIVE_COMMENT)
-        );
+        ).setScores(3.0); // TODO @puhui999:这里要实现下;;
     }
 
     @Override

+ 39 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleCategoryController.java

@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.promotion.controller.app.article;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.promotion.controller.app.article.vo.category.AppArticleCategoryRespVO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "用户 APP - 文章分类")
+@RestController
+@RequestMapping("/promotion/article-category")
+@Validated
+public class AppArticleCategoryController {
+
+    @RequestMapping("/list")
+    @Operation(summary = "获得文章分类列表")
+    // TODO @芋艿:swagger 注解
+    public CommonResult<List<AppArticleCategoryRespVO>> getArticleCategoryList() {
+        List<AppArticleCategoryRespVO> appArticleRespVOList = new ArrayList<>();
+        Random random = new Random();
+        for (int i = 0; i < 10; i++) {
+            AppArticleCategoryRespVO appArticleRespVO = new AppArticleCategoryRespVO();
+            appArticleRespVO.setId((long) (i + 1));
+            appArticleRespVO.setName("分类 - " + i);
+            appArticleRespVO.setPicUrl("https://www.iocoder.cn/" + (i + 1) + ".png");
+            appArticleRespVOList.add(appArticleRespVO);
+        }
+        return success(appArticleRespVOList);
+    }
+
+}

+ 90 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/AppArticleController.java

@@ -0,0 +1,90 @@
+package cn.iocoder.yudao.module.promotion.controller.app.article;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.promotion.controller.app.article.vo.article.AppArticlePageReqVO;
+import cn.iocoder.yudao.module.promotion.controller.app.article.vo.article.AppArticleRespVO;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "用户 APP - 文章")
+@RestController
+@RequestMapping("/promotion/article")
+@Validated
+public class AppArticleController {
+
+    @RequestMapping("/list")
+    // TODO @芋艿:swagger 注解
+    public CommonResult<List<AppArticleRespVO>> getArticleList(@RequestParam(value = "recommendHot", required = false) Boolean recommendHot,
+                                                               @RequestParam(value = "recommendBanner", required = false) Boolean recommendBanner) {
+        List<AppArticleRespVO> appArticleRespVOList = new ArrayList<>();
+        Random random = new Random();
+        for (int i = 0; i < 10; i++) {
+            AppArticleRespVO appArticleRespVO = new AppArticleRespVO();
+            appArticleRespVO.setId((long) (i + 1));
+            appArticleRespVO.setTitle("芋道源码 - " + i + "模块");
+            appArticleRespVO.setAuthor("芋道源码");
+            appArticleRespVO.setCategoryId((long) random.nextInt(10000));
+            appArticleRespVO.setPicUrl("https://www.iocoder.cn/" + (i + 1) + ".png");
+            appArticleRespVO.setIntroduction("我是简介");
+            appArticleRespVO.setDescription("我是详细");
+            appArticleRespVO.setCreateTime(LocalDateTime.now());
+            appArticleRespVO.setBrowseCount(random.nextInt(10000));
+            appArticleRespVO.setSpuId((long) random.nextInt(10000));
+            appArticleRespVOList.add(appArticleRespVO);
+        }
+        return success(appArticleRespVOList);
+    }
+
+    @RequestMapping("/page")
+    // TODO @芋艿:swagger 注解
+    public CommonResult<PageResult<AppArticleRespVO>> getArticlePage(AppArticlePageReqVO pageReqVO) {
+        List<AppArticleRespVO> appArticleRespVOList = new ArrayList<>();
+        Random random = new Random();
+        for (int i = 0; i < 10; i++) {
+            AppArticleRespVO appArticleRespVO = new AppArticleRespVO();
+            appArticleRespVO.setId((long) (i + 1));
+            appArticleRespVO.setTitle("芋道源码 - " + i + "模块");
+            appArticleRespVO.setAuthor("芋道源码");
+            appArticleRespVO.setCategoryId((long) random.nextInt(10000));
+            appArticleRespVO.setPicUrl("https://www.iocoder.cn/" + (i + 1) + ".png");
+            appArticleRespVO.setIntroduction("我是简介");
+            appArticleRespVO.setDescription("我是详细");
+            appArticleRespVO.setCreateTime(LocalDateTime.now());
+            appArticleRespVO.setBrowseCount(random.nextInt(10000));
+            appArticleRespVO.setSpuId((long) random.nextInt(10000));
+            appArticleRespVOList.add(appArticleRespVO);
+        }
+        return success(new PageResult<>(appArticleRespVOList, 10L));
+    }
+
+    @RequestMapping("/get")
+    // TODO @芋艿:swagger 注解
+    public CommonResult<AppArticleRespVO> getArticlePage(@RequestParam("id") Long id) {
+        Random random = new Random();
+        AppArticleRespVO appArticleRespVO = new AppArticleRespVO();
+        appArticleRespVO.setId((long) (1));
+        appArticleRespVO.setTitle("芋道源码 - " + 0 + "模块");
+        appArticleRespVO.setAuthor("芋道源码");
+        appArticleRespVO.setCategoryId((long) random.nextInt(10000));
+        appArticleRespVO.setPicUrl("https://www.iocoder.cn/" + (0 + 1) + ".png");
+        appArticleRespVO.setIntroduction("我是简介");
+        appArticleRespVO.setDescription("我是详细");
+        appArticleRespVO.setCreateTime(LocalDateTime.now());
+        appArticleRespVO.setBrowseCount(random.nextInt(10000));
+        appArticleRespVO.setSpuId((long) random.nextInt(10000));
+        appArticleRespVO.setSpuId(633L);
+        return success(appArticleRespVO);
+    }
+
+}

+ 14 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/article/AppArticlePageReqVO.java

@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.module.promotion.controller.app.article.vo.article;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "应用 App - 文章的分页 Request VO")
+@Data
+public class AppArticlePageReqVO extends PageParam {
+
+    @Schema(description = "分类编号", example = "2048")
+    private Long categoryId;
+
+}

+ 49 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/article/AppArticleRespVO.java

@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.promotion.controller.app.article.vo.article;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "应用 App - 文章 Response VO")
+@Data
+public class AppArticleRespVO {
+
+    @Schema(description = "文章编号", required = true, example = "1")
+    private Long id;
+
+    @Schema(description = "文章标题", required = true, example = "芋道源码 - 促销模块")
+    private String title;
+
+    @Schema(description = "文章作者", required = true, example = "芋道源码")
+    private String author;
+
+    @Schema(description = "分类编号", required = true, example = "2048")
+    private Long categoryId;
+
+    @Schema(description = "图文封面", required = true, example = "https://www.iocoder.cn/1.png")
+    private String picUrl;
+
+    @Schema(description = "文章简介", required = true, example = "我是简介")
+    private String introduction;
+
+    @Schema(description = "文章内容", required = true, example = "我是详细")
+    private String description;
+
+    @Schema(description = "发布时间", required = true)
+    private LocalDateTime createTime;
+
+    @Schema(description = "浏览量", required = true, example = "1024")
+    private Integer browseCount;
+
+    @Schema(description = "关联的商品 SPU 编号", example = "1024")
+    private Long spuId;
+
+// TODO 芋艿:下面 2 个字段,后端要存储,前端不用返回;
+//    @Schema(description = "是否热卖推荐", required = true, example = "true")
+//    private Boolean recommendHot;
+//
+//    @Schema(description = "是否 Banner 推荐", required = true, example = "true")
+//    private Boolean recommendBanner;
+
+}

+ 26 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/article/vo/category/AppArticleCategoryRespVO.java

@@ -0,0 +1,26 @@
+package cn.iocoder.yudao.module.promotion.controller.app.article.vo.category;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "应用 App - 文章分类 Response VO")
+@Data
+public class AppArticleCategoryRespVO {
+
+    @Schema(description = "分类编号", required = true, example = "1")
+    private Long id;
+
+    @Schema(description = "分类名称", required = true, example = "技术")
+    private String name;
+
+    @Schema(description = "分类图标", required = true, example = "https://www.iocoder.cn/1.png")
+    private String picUrl;
+
+    // TODO 芋艿:下面 2 个字段,后端要存储,前端不用返回;
+//    @Schema(description = "状态", required = true, example = "1")
+//    private Integer status;
+//
+//    @Schema(description = "排序", required = true, example = "1024")
+//    private Integer sort;
+
+}

+ 38 - 4
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponController.java

@@ -1,14 +1,19 @@
 package cn.iocoder.yudao.module.promotion.controller.app.coupon;
 
 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponPageReqVO;
+import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon.AppCouponRespVO;
 import cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.template.AppCouponTemplatePageReqVO;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.validation.annotation.Validated;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
 
 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
 
@@ -25,4 +30,33 @@ public class AppCouponController {
         return success(1L);
     }
 
+    // TODO 芋艿:待实现
+    @GetMapping("/page")
+    @Operation(summary = "优惠劵列表", description = "我的优惠劵")
+    public CommonResult<PageResult<AppCouponRespVO>> takeCoupon(AppCouponPageReqVO pageReqVO) {
+        List<AppCouponRespVO> list = new ArrayList<>();
+        Random random = new Random();
+        for (int i = 0; i < 10; i++) {
+            AppCouponRespVO vo = new AppCouponRespVO();
+            vo.setId(i + 1L);
+            vo.setName("优惠劵" + (i + 1));
+            vo.setStatus(pageReqVO.getStatus());
+            vo.setUsePrice(random.nextInt(100) * 100);
+            vo.setValidStartTime(LocalDateTime.now().plusDays(random.nextInt(10)));
+            vo.setValidEndTime(LocalDateTime.now().plusDays(random.nextInt(20) + 10));
+            vo.setDiscountType(random.nextInt(2) + 1);
+            if (vo.getDiscountType() == 1) {
+                vo.setDiscountPercent(null);
+                vo.setDiscountPrice(random.nextInt(50) * 100);
+                vo.setDiscountLimitPrice(null);
+            } else {
+                vo.setDiscountPercent(random.nextInt(90) + 10);
+                vo.setDiscountPrice(null);
+                vo.setDiscountLimitPrice(random.nextInt(200) * 100);
+            }
+            list.add(vo);
+        }
+        return success(new PageResult<>(list, 20L));
+    }
+
 }

+ 36 - 6
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/AppCouponTemplateController.java

@@ -34,14 +34,15 @@ public class AppCouponTemplateController {
 
     // TODO 芋艿:待实现
     @GetMapping("/list")
-    @Operation(summary = "获得优惠劵模版列表") // 目前主要给商品详情使用
+    @Operation(summary = "获得优惠劵模版列表")
     @Parameters({
-            @Parameter(name = "spuId", description = "商品 SPU 编号", required = true),
+            @Parameter(name = "spuId", description = "商品 SPU 编号"), // 目前主要给商品详情使用
             @Parameter(name = "useType", description = "使用类型"),
             @Parameter(name = "count", description = "数量", required = true)
     })
-    public CommonResult<List<AppCouponTemplateRespVO>> getCouponTemplateList(@RequestParam("spuId") Long spuId,
-                                                                             @RequestParam(value = "useType", required = false) Integer useType) {
+    public CommonResult<List<AppCouponTemplateRespVO>> getCouponTemplateList(@RequestParam(value = "spuId", required = false) Long spuId,
+                                                                             @RequestParam(value = "useType", required = false) Integer useType,
+                                                                             @RequestParam(value = "count", required = false, defaultValue = "10") Integer count) {
         List<AppCouponTemplateRespVO> list = new ArrayList<>();
         Random random = new Random();
         for (int i = 0; i < 10; i++) {
@@ -74,11 +75,40 @@ public class AppCouponTemplateController {
         return success(list);
     }
 
-    // TODO 芋艿:待实现
+    // TODO 芋艿:待实现;和 getCouponTemplateList 类似
     @GetMapping("/page")
     @Operation(summary = "获得优惠劵模版分页")
     public CommonResult<PageResult<AppCouponTemplateRespVO>> getCouponTemplatePage(AppCouponTemplatePageReqVO pageReqVO) {
-        return null;
+        List<AppCouponTemplateRespVO> list = new ArrayList<>();
+        Random random = new Random();
+        for (int i = 0; i < 10; i++) {
+            AppCouponTemplateRespVO vo = new AppCouponTemplateRespVO();
+            vo.setId(i + 1L);
+            vo.setName("优惠劵" + (i + 1));
+            vo.setTakeLimitCount(random.nextInt(10) + 1);
+            vo.setUsePrice(random.nextInt(100) * 100);
+            vo.setValidityType(random.nextInt(2) + 1);
+            if (vo.getValidityType() == 1) {
+                vo.setValidStartTime(LocalDateTime.now().plusDays(random.nextInt(10)));
+                vo.setValidEndTime(LocalDateTime.now().plusDays(random.nextInt(20) + 10));
+            } else {
+                vo.setFixedStartTerm(random.nextInt(10));
+                vo.setFixedEndTerm(random.nextInt(10) + vo.getFixedStartTerm() + 1);
+            }
+            vo.setDiscountType(random.nextInt(2) + 1);
+            if (vo.getDiscountType() == 1) {
+                vo.setDiscountPercent(null);
+                vo.setDiscountPrice(random.nextInt(50) * 100);
+                vo.setDiscountLimitPrice(null);
+            } else {
+                vo.setDiscountPercent(random.nextInt(90) + 10);
+                vo.setDiscountPrice(null);
+                vo.setDiscountLimitPrice(random.nextInt(200) * 100);
+            }
+            vo.setTakeStatus(random.nextBoolean());
+            list.add(vo);
+        }
+        return success(new PageResult<>(list, 20L));
     }
 
 }

+ 18 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponPageReqVO.java

@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Schema(description = "用户 App - 优惠劵分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class AppCouponPageReqVO extends PageParam {
+
+    @Schema(description = "优惠劵状态", example = "1")
+    private Integer status;
+
+}

+ 45 - 0
yudao-module-mall/yudao-module-promotion-biz/src/main/java/cn/iocoder/yudao/module/promotion/controller/app/coupon/vo/coupon/AppCouponRespVO.java

@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.promotion.controller.app.coupon.vo.coupon;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.Min;
+import java.time.LocalDateTime;
+
+@Schema(description = "用户 App - 优惠劵 Response VO")
+@Data
+public class AppCouponRespVO {
+
+    @Schema(description = "优惠劵编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Long id;
+
+    @Schema(description = "优惠劵名", requiredMode = Schema.RequiredMode.REQUIRED, example = "春节送送送")
+    private String name;
+
+    @Schema(description = "优惠劵状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") // 参见 CouponStatusEnum 枚举
+    private Integer status;
+
+    @Schema(description = "是否设置满多少金额可用", requiredMode = Schema.RequiredMode.REQUIRED, example = "100")
+    // 单位:分;0 - 不限制
+    private Integer usePrice;
+
+    @Schema(description = "固定日期 - 生效开始时间")
+    private LocalDateTime validStartTime;
+
+    @Schema(description = "固定日期 - 生效结束时间")
+    private LocalDateTime validEndTime;
+
+    @Schema(description = "优惠类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+    private Integer discountType;
+
+    @Schema(description = "折扣百分比", example = "80") //  例如说,80% 为 80
+    private Integer discountPercent;
+
+    @Schema(description = "优惠金额", example = "10")
+    @Min(value = 0, message = "优惠金额需要大于等于 0")
+    private Integer discountPrice;
+
+    @Schema(description = "折扣上限", example = "100") // 单位:分,仅在 discountType 为 PERCENT 使用
+    private Integer discountLimitPrice;
+
+}

+ 5 - 0
yudao-module-member/yudao-module-member-biz/pom.xml

@@ -89,6 +89,11 @@
             <artifactId>yudao-spring-boot-starter-excel</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>cn.iocoder.boot</groupId>
+            <artifactId>yudao-spring-boot-starter-biz-ip</artifactId>
+        </dependency>
+
     </dependencies>
 
 </project>

+ 1 - 2
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressBaseVO.java

@@ -2,7 +2,6 @@ package cn.iocoder.yudao.module.member.controller.app.address.vo;
 import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.Data;
 
-import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 
 // TODO 芋艿:example 缺失
@@ -31,6 +30,6 @@ public class AppAddressBaseVO {
 
     @Schema(description = "是否默认地址", requiredMode = Schema.RequiredMode.REQUIRED)
     @NotNull(message = "是否默认地址不能为空")
-    private Boolean defaulted;
+    private Boolean defaultStatus;
 
 }

+ 7 - 5
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressRespVO.java

@@ -1,7 +1,9 @@
 package cn.iocoder.yudao.module.member.controller.app.address.vo;
+
 import io.swagger.v3.oas.annotations.media.Schema;
-import lombok.*;
-import java.time.LocalDateTime;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
 
 @Schema(description = "用户 APP - 用户收件地址 Response VO")
 @Data
@@ -9,10 +11,10 @@ import java.time.LocalDateTime;
 @ToString(callSuper = true)
 public class AppAddressRespVO extends AppAddressBaseVO {
 
-    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
     private Long id;
 
-    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
-    private LocalDateTime createTime;
+    @Schema(description = "地区名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "上海上海市普陀区")
+    private String areaName;
 
 }

+ 1 - 1
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/controller/app/address/vo/AppAddressUpdateReqVO.java

@@ -9,7 +9,7 @@ import javax.validation.constraints.*;
 @ToString(callSuper = true)
 public class AppAddressUpdateReqVO extends AppAddressBaseVO {
 
-    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
     @NotNull(message = "编号不能为空")
     private Long id;
 

+ 9 - 3
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/convert/address/AddressConvert.java

@@ -1,12 +1,14 @@
 package cn.iocoder.yudao.module.member.convert.address;
 
-import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
 import cn.iocoder.yudao.module.member.api.address.dto.AddressRespDTO;
 import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressCreateReqVO;
 import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressRespVO;
 import cn.iocoder.yudao.module.member.controller.app.address.vo.AppAddressUpdateReqVO;
 import cn.iocoder.yudao.module.member.dal.dataobject.address.MemberAddressDO;
 import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.Named;
 import org.mapstruct.factory.Mappers;
 
 import java.util.List;
@@ -25,12 +27,16 @@ public interface AddressConvert {
 
     MemberAddressDO convert(AppAddressUpdateReqVO bean);
 
+    @Mapping(source = "areaId", target = "areaName",  qualifiedByName = "convertAreaIdToAreaName")
     AppAddressRespVO convert(MemberAddressDO bean);
 
     List<AppAddressRespVO> convertList(List<MemberAddressDO> list);
 
-    PageResult<AppAddressRespVO> convertPage(PageResult<MemberAddressDO> page);
-
     AddressRespDTO convert02(MemberAddressDO bean);
 
+    @Named("convertAreaIdToAreaName")
+    default String convertAreaIdToAreaName(Integer areaId) {
+        return AreaUtils.format(areaId);
+    }
+
 }

+ 1 - 1
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/dataobject/address/MemberAddressDO.java

@@ -49,6 +49,6 @@ public class MemberAddressDO extends BaseDO {
      *
      * true - 默认收件地址
      */
-    private Boolean defaulted;
+    private Boolean defaultStatus;
 
 }

+ 1 - 1
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/dal/mysql/address/AddressMapper.java

@@ -16,7 +16,7 @@ public interface AddressMapper extends BaseMapperX<MemberAddressDO> {
 
     default List<MemberAddressDO> selectListByUserIdAndDefaulted(Long userId, Boolean defaulted) {
         return selectList(new LambdaQueryWrapperX<MemberAddressDO>().eq(MemberAddressDO::getUserId, userId)
-                .eqIfPresent(MemberAddressDO::getDefaulted, defaulted));
+                .eqIfPresent(MemberAddressDO::getDefaultStatus, defaulted));
     }
 
 }

+ 4 - 4
yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/address/AddressServiceImpl.java

@@ -32,9 +32,9 @@ public class AddressServiceImpl implements AddressService {
     @Transactional(rollbackFor = Exception.class)
     public Long createAddress(Long userId, AppAddressCreateReqVO createReqVO) {
         // 如果添加的是默认收件地址,则将原默认地址修改为非默认
-        if (Boolean.TRUE.equals(createReqVO.getDefaulted())) {
+        if (Boolean.TRUE.equals(createReqVO.getDefaultStatus())) {
             List<MemberAddressDO> addresses = addressMapper.selectListByUserIdAndDefaulted(userId, true);
-            addresses.forEach(address -> addressMapper.updateById(new MemberAddressDO().setId(address.getId()).setDefaulted(false)));
+            addresses.forEach(address -> addressMapper.updateById(new MemberAddressDO().setId(address.getId()).setDefaultStatus(false)));
         }
 
         // 插入
@@ -52,10 +52,10 @@ public class AddressServiceImpl implements AddressService {
         validAddressExists(userId, updateReqVO.getId());
 
         // 如果修改的是默认收件地址,则将原默认地址修改为非默认
-        if (Boolean.TRUE.equals(updateReqVO.getDefaulted())) {
+        if (Boolean.TRUE.equals(updateReqVO.getDefaultStatus())) {
             List<MemberAddressDO> addresses = addressMapper.selectListByUserIdAndDefaulted(userId, true);
             addresses.stream().filter(u -> !u.getId().equals(updateReqVO.getId())) // 排除自己
-                    .forEach(address -> addressMapper.updateById(new MemberAddressDO().setId(address.getId()).setDefaulted(false)));
+                    .forEach(address -> addressMapper.updateById(new MemberAddressDO().setId(address.getId()).setDefaultStatus(false)));
         }
 
         // 更新

+ 34 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/ip/AppAreaController.java

@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.system.controller.app.ip;
+
+import cn.hutool.core.lang.Assert;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.ip.core.Area;
+import cn.iocoder.yudao.framework.ip.core.utils.AreaUtils;
+import cn.iocoder.yudao.module.system.controller.app.ip.vo.AppAreaNodeRespVO;
+import cn.iocoder.yudao.module.system.convert.ip.AreaConvert;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "用户 App - 地区")
+@RestController
+@RequestMapping("/system/area")
+@Validated
+public class AppAreaController {
+
+    @GetMapping("/tree")
+    @Operation(summary = "获得地区树")
+    public CommonResult<List<AppAreaNodeRespVO>> getAreaTree() {
+        Area area = AreaUtils.getArea(Area.ID_CHINA);
+        Assert.notNull(area, "获取不到中国");
+        return success(AreaConvert.INSTANCE.convertList3(area.getChildren()));
+    }
+
+}

+ 23 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/app/ip/vo/AppAreaNodeRespVO.java

@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.system.controller.app.ip.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "用户 App - 地区节点 Response VO")
+@Data
+public class AppAreaNodeRespVO {
+
+    @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "110000")
+    private Integer id;
+
+    @Schema(description = "名字", requiredMode = Schema.RequiredMode.REQUIRED, example = "北京")
+    private String name;
+
+    /**
+     * 子节点
+     */
+    private List<AppAreaNodeRespVO> children;
+
+}

+ 3 - 0
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/convert/ip/AreaConvert.java

@@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.ip.core.Area;
 import cn.iocoder.yudao.framework.ip.core.enums.AreaTypeEnum;
 import cn.iocoder.yudao.module.system.controller.admin.ip.vo.AreaNodeRespVO;
 import cn.iocoder.yudao.module.system.controller.admin.ip.vo.AreaNodeSimpleRespVO;
+import cn.iocoder.yudao.module.system.controller.app.ip.vo.AppAreaNodeRespVO;
 import org.mapstruct.Mapper;
 import org.mapstruct.Mapping;
 import org.mapstruct.factory.Mappers;
@@ -27,4 +28,6 @@ public interface AreaConvert {
         return Objects.equals(AreaTypeEnum.DISTRICT.getType(), type);
     }
 
+    List<AppAreaNodeRespVO> convertList3(List<Area> list);
+
 }