());
+ return selectCount(new QueryWrapper<>());
}
default Long selectCount(String field, Object value) {
diff --git a/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java
new file mode 100644
index 000000000..7950a2f96
--- /dev/null
+++ b/yudao-framework/yudao-spring-boot-starter-mybatis/src/main/java/cn/iocoder/yudao/framework/mybatis/core/query/MPJLambdaWrapperX.java
@@ -0,0 +1,313 @@
+package cn.iocoder.yudao.framework.mybatis.core.query;
+
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.iocoder.yudao.framework.common.util.collection.ArrayUtils;
+import com.baomidou.mybatisplus.core.toolkit.support.SFunction;
+import com.github.yulichang.toolkit.MPJWrappers;
+import com.github.yulichang.wrapper.MPJLambdaWrapper;
+import org.springframework.util.StringUtils;
+
+import java.util.Collection;
+import java.util.function.Consumer;
+
+/**
+ * 拓展 MyBatis Plus Join QueryWrapper 类,主要增加如下功能:
+ *
+ * 1. 拼接条件的方法,增加 xxxIfPresent 方法,用于判断值不存在的时候,不要拼接到条件中。
+ *
+ * @param 数据类型
+ */
+public class MPJLambdaWrapperX extends MPJLambdaWrapper {
+
+ public MPJLambdaWrapperX likeIfPresent(SFunction column, String val) {
+ MPJWrappers.lambdaJoin().like(column, val);
+ if (StringUtils.hasText(val)) {
+ return (MPJLambdaWrapperX) super.like(column, val);
+ }
+ return this;
+ }
+
+ public MPJLambdaWrapperX inIfPresent(SFunction column, Collection> values) {
+ if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) {
+ return (MPJLambdaWrapperX) super.in(column, values);
+ }
+ return this;
+ }
+
+ public MPJLambdaWrapperX inIfPresent(SFunction column, Object... values) {
+ if (ObjectUtil.isAllNotEmpty(values) && !ArrayUtil.isEmpty(values)) {
+ return (MPJLambdaWrapperX) super.in(column, values);
+ }
+ return this;
+ }
+
+ public MPJLambdaWrapperX eqIfPresent(SFunction column, Object val) {
+ if (ObjectUtil.isNotEmpty(val)) {
+ return (MPJLambdaWrapperX) super.eq(column, val);
+ }
+ return this;
+ }
+
+ public MPJLambdaWrapperX neIfPresent(SFunction column, Object val) {
+ if (ObjectUtil.isNotEmpty(val)) {
+ return (MPJLambdaWrapperX) super.ne(column, val);
+ }
+ return this;
+ }
+
+ public MPJLambdaWrapperX gtIfPresent(SFunction column, Object val) {
+ if (val != null) {
+ return (MPJLambdaWrapperX) super.gt(column, val);
+ }
+ return this;
+ }
+
+ public MPJLambdaWrapperX geIfPresent(SFunction column, Object val) {
+ if (val != null) {
+ return (MPJLambdaWrapperX) super.ge(column, val);
+ }
+ return this;
+ }
+
+ public MPJLambdaWrapperX ltIfPresent(SFunction column, Object val) {
+ if (val != null) {
+ return (MPJLambdaWrapperX) super.lt(column, val);
+ }
+ return this;
+ }
+
+ public MPJLambdaWrapperX leIfPresent(SFunction column, Object val) {
+ if (val != null) {
+ return (MPJLambdaWrapperX) super.le(column, val);
+ }
+ return this;
+ }
+
+ public MPJLambdaWrapperX betweenIfPresent(SFunction column, Object val1, Object val2) {
+ if (val1 != null && val2 != null) {
+ return (MPJLambdaWrapperX) super.between(column, val1, val2);
+ }
+ if (val1 != null) {
+ return (MPJLambdaWrapperX) ge(column, val1);
+ }
+ if (val2 != null) {
+ return (MPJLambdaWrapperX) le(column, val2);
+ }
+ return this;
+ }
+
+ public MPJLambdaWrapperX betweenIfPresent(SFunction column, Object[] values) {
+ Object val1 = ArrayUtils.get(values, 0);
+ Object val2 = ArrayUtils.get(values, 1);
+ return betweenIfPresent(column, val1, val2);
+ }
+
+ // ========== 重写父类方法,方便链式调用 ==========
+
+ @Override
+ public MPJLambdaWrapperX eq(boolean condition, SFunction column, Object val) {
+ super.eq(condition, column, val);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX eq(SFunction column, Object val) {
+ super.eq(column, val);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX orderByDesc(SFunction column) {
+ //noinspection unchecked
+ super.orderByDesc(true, column);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX last(String lastSql) {
+ super.last(lastSql);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX in(SFunction column, Collection> coll) {
+ super.in(column, coll);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectAll(Class> clazz) {
+ super.selectAll(clazz);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectAll(Class> clazz, String prefix) {
+ super.selectAll(clazz, prefix);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectAs(SFunction column, String alias) {
+ super.selectAs(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectAs(String column, SFunction alias) {
+ super.selectAs(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectAs(SFunction column, SFunction alias) {
+ super.selectAs(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectAs(String index, SFunction column, SFunction alias) {
+ super.selectAs(index, column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectAsClass(Class source, Class> tag) {
+ super.selectAsClass(source, tag);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectSub(Class clazz, Consumer> consumer, SFunction alias) {
+ super.selectSub(clazz, consumer, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectSub(Class clazz, String st, Consumer> consumer, SFunction alias) {
+ super.selectSub(clazz, st, consumer, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectCount(SFunction column) {
+ super.selectCount(column);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectCount(Object column, String alias) {
+ super.selectCount(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectCount(Object column, SFunction alias) {
+ super.selectCount(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectCount(SFunction column, String alias) {
+ super.selectCount(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectCount(SFunction column, SFunction alias) {
+ super.selectCount(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectSum(SFunction column) {
+ super.selectSum(column);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectSum(SFunction column, String alias) {
+ super.selectSum(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectSum(SFunction column, SFunction alias) {
+ super.selectSum(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectMax(SFunction column) {
+ super.selectMax(column);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectMax(SFunction column, String alias) {
+ super.selectMax(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectMax(SFunction column, SFunction alias) {
+ super.selectMax(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectMin(SFunction column) {
+ super.selectMin(column);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectMin(SFunction column, String alias) {
+ super.selectMin(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectMin(SFunction column, SFunction alias) {
+ super.selectMin(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectAvg(SFunction column) {
+ super.selectAvg(column);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectAvg(SFunction column, String alias) {
+ super.selectAvg(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectAvg(SFunction column, SFunction alias) {
+ super.selectAvg(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectLen(SFunction column) {
+ super.selectLen(column);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectLen(SFunction column, String alias) {
+ super.selectLen(column, alias);
+ return this;
+ }
+
+ @Override
+ public MPJLambdaWrapperX selectLen(SFunction column, SFunction alias) {
+ super.selectLen(column, alias);
+ return this;
+ }
+
+}
diff --git a/yudao-module-mall/pom.xml b/yudao-module-mall/pom.xml
index 14d51a403..bb6417277 100644
--- a/yudao-module-mall/pom.xml
+++ b/yudao-module-mall/pom.xml
@@ -23,7 +23,7 @@
yudao-module-product-api
yudao-module-product-biz
yudao-module-trade-api
-
+ yudao-module-trade-biz
diff --git a/yudao-module-mall/yudao-module-trade-biz/Dockerfile b/yudao-module-mall/yudao-module-trade-biz/Dockerfile
new file mode 100644
index 000000000..872f55c16
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/Dockerfile
@@ -0,0 +1,19 @@
+## AdoptOpenJDK 停止发布 OpenJDK 二进制,而 Eclipse Temurin 是它的延伸,提供更好的稳定性
+## 感谢复旦核博士的建议!灰子哥,牛皮!
+FROM eclipse-temurin:8-jre
+
+## 创建目录,并使用它作为工作目录
+RUN mkdir -p /yudao-module-trade-biz
+WORKDIR /yudao-module-trade-biz
+## 将后端项目的 Jar 文件,复制到镜像中
+COPY ./target/yudao-module-trade-biz.jar app.jar
+
+## 设置 TZ 时区
+## 设置 JAVA_OPTS 环境变量,可通过 docker run -e "JAVA_OPTS=" 进行覆盖
+ENV TZ=Asia/Shanghai JAVA_OPTS="-Xms512m -Xmx512m"
+
+## 暴露后端项目的 48080 端口
+EXPOSE 48102
+
+## 启动后端项目
+CMD java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar app.jar
diff --git a/yudao-module-mall/yudao-module-trade-biz/pom.xml b/yudao-module-mall/yudao-module-trade-biz/pom.xml
new file mode 100644
index 000000000..4ec5a4e5d
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/pom.xml
@@ -0,0 +1,153 @@
+
+
+
+ cn.iocoder.cloud
+ yudao-module-mall
+ ${revision}
+
+ 4.0.0
+ yudao-module-trade-biz
+ jar
+
+ ${project.artifactId}
+
+ trade 模块,主要实现交易相关功能
+ 例如:订单、退款、购物车等功能。
+
+
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-bootstrap
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-env
+
+
+
+
+ cn.iocoder.cloud
+ yudao-module-trade-api
+ ${revision}
+
+
+ cn.iocoder.cloud
+ yudao-module-product-api
+ ${revision}
+
+
+ cn.iocoder.cloud
+ yudao-module-pay-api
+ ${revision}
+
+
+ cn.iocoder.cloud
+ yudao-module-promotion-api
+ ${revision}
+
+
+ cn.iocoder.cloud
+ yudao-module-member-api
+ ${revision}
+
+
+ cn.iocoder.cloud
+ yudao-module-system-api
+ ${revision}
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-biz-operatelog
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-biz-tenant
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-biz-ip
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-web
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-security
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-biz-pay
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-mybatis
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-redis
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-rpc
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-config
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-job
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-test
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-excel
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-biz-dict
+
+
+
+
+ cn.iocoder.cloud
+ yudao-spring-boot-starter-monitor
+
+
+
+
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/TradeServerApplication.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/TradeServerApplication.java
new file mode 100644
index 000000000..be59b7804
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/TradeServerApplication.java
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.trade;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+/**
+ * 项目的启动类
+ *
+ * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ * 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ *
+ * @author 芋道源码
+ */
+@SpringBootApplication
+public class TradeServerApplication {
+
+ public static void main(String[] args) {
+ // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+
+ SpringApplication.run(TradeServerApplication.class, args);
+
+ // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ // 如果你碰到启动的问题,请认真阅读 https://cloud.iocoder.cn/quick-start/ 文章
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java
new file mode 100644
index 000000000..3cb7bbae7
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/order/TradeOrderApiImpl.java
@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.trade.api.order;
+
+import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
+import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
+import org.springframework.stereotype.Service;
+import org.springframework.validation.annotation.Validated;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 订单 API 接口实现类
+ *
+ * @author HUIHUI
+ */
+@Service
+@Validated
+public class TradeOrderApiImpl implements TradeOrderApi {
+
+ @Resource
+ private TradeOrderUpdateService tradeOrderUpdateService;
+ @Resource
+ private TradeOrderQueryService tradeOrderQueryService;
+
+ @Override
+ public List getOrderList(Collection ids) {
+ return TradeOrderConvert.INSTANCE.convertList04(tradeOrderQueryService.getOrderList(ids));
+ }
+
+ @Override
+ public TradeOrderRespDTO getOrder(Long id) {
+ return TradeOrderConvert.INSTANCE.convert(tradeOrderQueryService.getOrder(id));
+ }
+
+ @Override
+ public void cancelPaidOrder(Long userId, Long orderId) {
+ tradeOrderUpdateService.cancelPaidOrder(userId, orderId);
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java
new file mode 100644
index 000000000..5b0e37dcc
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/api/package-info.java
@@ -0,0 +1 @@
+package cn.iocoder.yudao.module.trade.api;
\ No newline at end of file
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/AfterSaleController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/AfterSaleController.java
new file mode 100644
index 000000000..8dfa55f3a
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/AfterSaleController.java
@@ -0,0 +1,146 @@
+package cn.iocoder.yudao.module.trade.controller.admin.aftersale;
+
+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.operatelog.core.annotations.OperateLog;
+import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.pay.api.notify.dto.PayRefundNotifyReqDTO;
+import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.*;
+import cn.iocoder.yudao.module.trade.convert.aftersale.AfterSaleConvert;
+import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.aftersale.AfterSaleLogDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
+import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleLogService;
+import cn.iocoder.yudao.module.trade.service.aftersale.AfterSaleService;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.annotation.security.PermitAll;
+import javax.validation.Valid;
+import java.util.List;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
+import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
+
+@Tag(name = "管理后台 - 售后订单")
+@RestController
+@RequestMapping("/trade/after-sale")
+@Validated
+@Slf4j
+public class AfterSaleController {
+
+ @Resource
+ private AfterSaleService afterSaleService;
+ @Resource
+ private TradeOrderQueryService tradeOrderQueryService;
+ @Resource
+ private AfterSaleLogService afterSaleLogService;
+ @Resource
+ private MemberUserApi memberUserApi;
+
+ @GetMapping("/page")
+ @Operation(summary = "获得售后订单分页")
+ @PreAuthorize("@ss.hasPermission('trade:after-sale:query')")
+ public CommonResult> getAfterSalePage(@Valid AfterSalePageReqVO pageVO) {
+ // 查询售后
+ PageResult pageResult = afterSaleService.getAfterSalePage(pageVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(PageResult.empty());
+ }
+
+ // 查询会员
+ Map memberUsers = memberUserApi.getUserMap(
+ convertSet(pageResult.getList(), AfterSaleDO::getUserId));
+ return success(AfterSaleConvert.INSTANCE.convertPage(pageResult, memberUsers));
+ }
+
+ @GetMapping("/get-detail")
+ @Operation(summary = "获得售后订单详情")
+ @Parameter(name = "id", description = "售后编号", required = true, example = "1")
+ @PreAuthorize("@ss.hasPermission('trade:after-sale:query')")
+ public CommonResult getOrderDetail(@RequestParam("id") Long id) {
+ // 查询订单
+ AfterSaleDO afterSale = afterSaleService.getAfterSale(id);
+ if (afterSale == null) {
+ return success(null);
+ }
+
+ // 查询订单
+ TradeOrderDO order = tradeOrderQueryService.getOrder(afterSale.getOrderId());
+ // 查询订单项
+ TradeOrderItemDO orderItem = tradeOrderQueryService.getOrderItem(afterSale.getOrderItemId());
+ // 拼接数据
+ MemberUserRespDTO user = memberUserApi.getUser(afterSale.getUserId()).getCheckedData();
+ List logs = afterSaleLogService.getAfterSaleLogList(afterSale.getId());
+ return success(AfterSaleConvert.INSTANCE.convert(afterSale, order, orderItem, user, logs));
+ }
+
+ @PutMapping("/agree")
+ @Operation(summary = "同意售后")
+ @Parameter(name = "id", description = "售后编号", required = true, example = "1")
+ @PreAuthorize("@ss.hasPermission('trade:after-sale:agree')")
+ public CommonResult agreeAfterSale(@RequestParam("id") Long id) {
+ afterSaleService.agreeAfterSale(getLoginUserId(), id);
+ return success(true);
+ }
+
+ @PutMapping("/disagree")
+ @Operation(summary = "拒绝售后")
+ @PreAuthorize("@ss.hasPermission('trade:after-sale:disagree')")
+ public CommonResult disagreeAfterSale(@RequestBody AfterSaleDisagreeReqVO confirmReqVO) {
+ afterSaleService.disagreeAfterSale(getLoginUserId(), confirmReqVO);
+ return success(true);
+ }
+
+ @PutMapping("/receive")
+ @Operation(summary = "确认收货")
+ @Parameter(name = "id", description = "售后编号", required = true, example = "1")
+ @PreAuthorize("@ss.hasPermission('trade:after-sale:receive')")
+ public CommonResult receiveAfterSale(@RequestParam("id") Long id) {
+ afterSaleService.receiveAfterSale(getLoginUserId(), id);
+ return success(true);
+ }
+
+ @PutMapping("/refuse")
+ @Operation(summary = "拒绝收货")
+ @Parameter(name = "id", description = "售后编号", required = true, example = "1")
+ @PreAuthorize("@ss.hasPermission('trade:after-sale:receive')")
+ public CommonResult refuseAfterSale(AfterSaleRefuseReqVO refuseReqVO) {
+ afterSaleService.refuseAfterSale(getLoginUserId(), refuseReqVO);
+ return success(true);
+ }
+
+ @PutMapping("/refund")
+ @Operation(summary = "确认退款")
+ @Parameter(name = "id", description = "售后编号", required = true, example = "1")
+ @PreAuthorize("@ss.hasPermission('trade:after-sale:refund')")
+ public CommonResult refundAfterSale(@RequestParam("id") Long id) {
+ afterSaleService.refundAfterSale(getLoginUserId(), getClientIP(), id);
+ return success(true);
+ }
+
+ @PostMapping("/update-refunded")
+ @Operation(summary = "更新售后订单为已退款") // 由 pay-module 支付服务,进行回调,可见 PayNotifyJob
+ @PermitAll // 无需登录,安全由 PayDemoOrderService 内部校验实现
+ @OperateLog(enable = false) // 禁用操作日志,因为没有操作人
+ public CommonResult updateAfterRefund(@RequestBody PayRefundNotifyReqDTO notifyReqDTO) {
+ // 目前业务逻辑,不需要做任何事情
+ // 当然,退款会有小概率会失败的情况,可以监控失败状态,进行告警
+ log.info("[updateAfterRefund][notifyReqDTO({})]", notifyReqDTO);
+ return success(true);
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.http b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.http
new file mode 100644
index 000000000..81cb35cbf
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/TradeAfterSaleController.http
@@ -0,0 +1,33 @@
+### 获得交易售后分页 => 成功
+GET {{baseUrl}}/trade/after-sale/page?pageNo=1&pageSize=10
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
+
+### 同意售后 => 成功
+PUT {{baseUrl}}/trade/after-sale/agree?id=7
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
+Content-Type: application/json
+
+### 拒绝售后 => 成功
+PUT {{baseUrl}}/trade/after-sale/disagree
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
+Content-Type: application/json
+
+{
+ "id": 6,
+ "auditReason": "阿巴巴"
+}
+
+### 确认退款 => 成功
+PUT {{baseUrl}}/trade/after-sale/refund?id=6
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
+Content-Type: application/json
+
+### 确认收货 => 成功
+PUT {{baseUrl}}/trade/after-sale/receive?id=7
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
+Content-Type: application/json
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleBaseVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleBaseVO.java
new file mode 100644
index 000000000..ae7bd395c
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleBaseVO.java
@@ -0,0 +1,119 @@
+package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+/**
+* 交易售后 Base VO,提供给添加、修改、详细的子 VO 使用
+* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+*/
+@Data
+public class AfterSaleBaseVO {
+
+ @Schema(description = "售后流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "202211190847450020500077")
+ @NotNull(message = "售后流水号不能为空")
+ private String no;
+
+ @Schema(description = "售后状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
+ @NotNull(message = "售后状态不能为空")
+ private Integer status;
+
+ @Schema(description = "售后类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "20")
+ @NotNull(message = "售后类型不能为空")
+ private Integer type;
+
+ @Schema(description = "售后方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
+ @NotNull(message = "售后方式不能为空")
+ private Integer way;
+
+ @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "30337")
+ @NotNull(message = "用户编号不能为空")
+ private Long userId;
+
+ @Schema(description = "申请原因", requiredMode = Schema.RequiredMode.REQUIRED, example = "不喜欢")
+ @NotNull(message = "申请原因不能为空")
+ private String applyReason;
+
+ @Schema(description = "补充描述", example = "你说的对")
+ private String applyDescription;
+
+ @Schema(description = "补充凭证图片", example = "https://www.iocoder.cn/1.png")
+ private List applyPicUrls;
+
+ @Schema(description = "订单编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18078")
+ @NotNull(message = "订单编号不能为空")
+ private Long orderId;
+
+ @Schema(description = "订单流水号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2022111917190001")
+ @NotNull(message = "订单流水号不能为空")
+ private String orderNo;
+
+ @Schema(description = "订单项编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "572")
+ @NotNull(message = "订单项编号不能为空")
+ private Long orderItemId;
+
+ @Schema(description = "商品 SPU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2888")
+ @NotNull(message = "商品 SPU 编号不能为空")
+ private Long spuId;
+
+ @Schema(description = "商品 SPU 名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+ @NotNull(message = "商品 SPU 名称不能为空")
+ private String spuName;
+
+ @Schema(description = "商品 SKU 编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "15657")
+ @NotNull(message = "商品 SKU 编号不能为空")
+ private Long skuId;
+
+ @Schema(description = "商品图片", example = "https://www.iocoder.cn/2.png")
+ private String picUrl;
+
+ @Schema(description = "购买数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20012")
+ @NotNull(message = "购买数量不能为空")
+ private Integer count;
+
+ @Schema(description = "审批时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime auditTime;
+
+ @Schema(description = "审批人", example = "30835")
+ private Long auditUserId;
+
+ @Schema(description = "审批备注", example = "不香")
+ private String auditReason;
+
+ @Schema(description = "退款金额,单位:分", requiredMode = Schema.RequiredMode.REQUIRED, example = "18077")
+ @NotNull(message = "退款金额,单位:分不能为空")
+ private Integer refundPrice;
+
+ @Schema(description = "支付退款编号", example = "10271")
+ private Long payRefundId;
+
+ @Schema(description = "退款时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime refundTime;
+
+ @Schema(description = "退货物流公司编号", example = "10")
+ private Long logisticsId;
+
+ @Schema(description = "退货物流单号", example = "610003952009")
+ private String logisticsNo;
+
+ @Schema(description = "退货时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime deliveryTime;
+
+ @Schema(description = "收货时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime receiveTime;
+
+ @Schema(description = "收货备注", example = "不喜欢")
+ private String receiveReason;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleDetailRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleDetailRespVO.java
new file mode 100644
index 000000000..3f220770b
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleDetailRespVO.java
@@ -0,0 +1,52 @@
+package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo;
+
+import cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log.AfterSaleLogRespVO;
+import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
+import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
+import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderBaseVO;
+import cn.iocoder.yudao.module.trade.controller.admin.order.vo.TradeOrderItemBaseVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - 售后订单的详情 Response VO")
+@Data
+public class AfterSaleDetailRespVO extends AfterSaleBaseVO {
+
+ @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+
+
+ /**
+ * 订单基本信息
+ */
+ private TradeOrderBaseVO order;
+ /**
+ * 订单项列表
+ */
+ private OrderItem orderItem;
+
+ /**
+ * 用户信息
+ */
+ private MemberUserRespVO user;
+
+ /**
+ * 售后日志
+ */
+ private List logs;
+
+ @Schema(description = "管理后台 - 交易订单的详情的订单项目")
+ @Data
+ public static class OrderItem extends TradeOrderItemBaseVO {
+
+ /**
+ * 属性数组
+ */
+ private List properties;
+
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleDisagreeReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleDisagreeReqVO.java
new file mode 100644
index 000000000..6fa511acd
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleDisagreeReqVO.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 交易售后拒绝 Request VO")
+@Data
+public class AfterSaleDisagreeReqVO {
+
+ @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "售后编号不能为空")
+ private Long id;
+
+ @Schema(description = "审批备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜")
+ @NotEmpty(message = "审批备注不能为空")
+ private String auditReason;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSalePageReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSalePageReqVO.java
new file mode 100644
index 000000000..f74c84b8f
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSalePageReqVO.java
@@ -0,0 +1,49 @@
+package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleStatusEnum;
+import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleTypeEnum;
+import cn.iocoder.yudao.module.trade.enums.aftersale.AfterSaleWayEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 交易售后分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class AfterSalePageReqVO extends PageParam {
+
+ @Schema(description = "售后流水号", example = "202211190847450020500077")
+ private String no;
+
+ @Schema(description = "售后状态", example = "10")
+ @InEnum(value = AfterSaleStatusEnum.class, message = "售后状态必须是 {value}")
+ private Integer status;
+
+ @Schema(description = "售后类型", example = "20")
+ @InEnum(value = AfterSaleTypeEnum.class, message = "售后类型必须是 {value}")
+ private Integer type;
+
+ @Schema(description = "售后方式", example = "10")
+ @InEnum(value = AfterSaleWayEnum.class, message = "售后方式必须是 {value}")
+ private Integer way;
+
+ @Schema(description = "订单编号", example = "18078")
+ private String orderNo;
+
+ @Schema(description = "商品 SPU 名称", example = "李四")
+ private String spuName;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleRefuseReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleRefuseReqVO.java
new file mode 100644
index 000000000..6dfced4d8
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleRefuseReqVO.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 交易售后拒绝收货 Request VO")
+@Data
+public class AfterSaleRefuseReqVO {
+
+ @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ @NotNull(message = "售后编号不能为空")
+ private Long id;
+
+ @Schema(description = "收货备注", requiredMode = Schema.RequiredMode.REQUIRED, example = "你猜")
+ @NotNull(message = "收货备注不能为空")
+ private String refuseMemo;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleRespPageItemVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleRespPageItemVO.java
new file mode 100644
index 000000000..3e76405e9
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/AfterSaleRespPageItemVO.java
@@ -0,0 +1,35 @@
+package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo;
+
+import cn.iocoder.yudao.module.trade.controller.admin.base.member.user.MemberUserRespVO;
+import cn.iocoder.yudao.module.trade.controller.admin.base.product.property.ProductPropertyValueDetailRespVO;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+import java.util.List;
+
+@Schema(description = "管理后台 - 交易售后分页的每一条记录 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class AfterSaleRespPageItemVO extends AfterSaleBaseVO {
+
+ @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "27630")
+ private Long id;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+ /**
+ * 商品属性数组
+ */
+ private List properties;
+
+ /**
+ * 用户信息
+ */
+ private MemberUserRespVO user;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/log/AfterSaleLogRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/log/AfterSaleLogRespVO.java
new file mode 100644
index 000000000..f33dcf373
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/aftersale/vo/log/AfterSaleLogRespVO.java
@@ -0,0 +1,42 @@
+package cn.iocoder.yudao.module.trade.controller.admin.aftersale.vo.log;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 交易售后日志 Response VO")
+@Data
+public class AfterSaleLogRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20669")
+ private Long id;
+
+ @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "22634")
+ @NotNull(message = "用户编号不能为空")
+ private Long userId;
+
+ @Schema(description = "用户类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
+ @NotNull(message = "用户类型不能为空")
+ private Integer userType;
+
+ @Schema(description = "售后编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "3023")
+ @NotNull(message = "售后编号不能为空")
+ private Long afterSaleId;
+
+ @Schema(description = "售后状态(之前)", example = "2")
+ private Integer beforeStatus;
+
+ @Schema(description = "售后状态(之后)", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "售后状态(之后)不能为空")
+ private Integer afterStatus;
+
+ @Schema(description = "操作明细", requiredMode = Schema.RequiredMode.REQUIRED, example = "维权完成,退款金额:¥37776.00")
+ @NotNull(message = "操作明细不能为空")
+ private String content;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/member/package-info.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/member/package-info.java
new file mode 100644
index 000000000..f874e482d
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/member/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * 占位符,可忽略
+ */
+package cn.iocoder.yudao.module.trade.controller.admin.base.member;
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/member/user/MemberUserRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/member/user/MemberUserRespVO.java
new file mode 100644
index 000000000..2d7c3512d
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/member/user/MemberUserRespVO.java
@@ -0,0 +1,19 @@
+package cn.iocoder.yudao.module.trade.controller.admin.base.member.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 会员用户 Response VO")
+@Data
+public class MemberUserRespVO {
+
+ @Schema(description = "用户 ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long id;
+
+ @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋道源码")
+ private String nickname;
+
+ @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png")
+ private String avatar;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/package-info.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/package-info.java
new file mode 100644
index 000000000..0baa83e49
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * 放置该模块通用的 VO 类
+ */
+package cn.iocoder.yudao.module.trade.controller.admin.base;
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/product/property/ProductPropertyValueDetailRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/product/property/ProductPropertyValueDetailRespVO.java
new file mode 100644
index 000000000..3d6d3b061
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/base/product/property/ProductPropertyValueDetailRespVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.trade.controller.admin.base.product.property;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Schema(description = "管理后台 - 商品属性值的明细 Response VO")
+@Data
+public class ProductPropertyValueDetailRespVO {
+
+ @Schema(description = "属性的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ private Long propertyId;
+
+ @Schema(description = "属性的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "颜色")
+ private String propertyName;
+
+ @Schema(description = "属性值的编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long valueId;
+
+ @Schema(description = "属性值的名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "红色")
+ private String valueName;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageRecordController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageRecordController.java
new file mode 100644
index 000000000..ff9bd5285
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageRecordController.java
@@ -0,0 +1,66 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordPageReqVO;
+import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record.BrokerageRecordRespVO;
+import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageRecordConvert;
+import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageRecordDO;
+import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.Map;
+import java.util.Set;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "管理后台 - 佣金记录")
+@RestController
+@RequestMapping("/trade/brokerage-record")
+@Validated
+public class BrokerageRecordController {
+
+ @Resource
+ private BrokerageRecordService brokerageRecordService;
+
+ @Resource
+ private MemberUserApi memberUserApi;
+
+ @GetMapping("/get")
+ @Operation(summary = "获得佣金记录")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')")
+ public CommonResult getBrokerageRecord(@RequestParam("id") Integer id) {
+ BrokerageRecordDO brokerageRecord = brokerageRecordService.getBrokerageRecord(id);
+ return success(BrokerageRecordConvert.INSTANCE.convert(brokerageRecord));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得佣金记录分页")
+ @PreAuthorize("@ss.hasPermission('trade:brokerage-record:query')")
+ public CommonResult> getBrokerageRecordPage(@Valid BrokerageRecordPageReqVO pageVO) {
+ PageResult pageResult = brokerageRecordService.getBrokerageRecordPage(pageVO);
+
+ // 查询用户信息
+ Set userIds = convertSet(pageResult.getList(), BrokerageRecordDO::getUserId);
+ userIds.addAll(convertList(pageResult.getList(), BrokerageRecordDO::getSourceUserId));
+ Map userMap = memberUserApi.getUserMap(userIds);
+ // 拼接数据
+ return success(BrokerageRecordConvert.INSTANCE.convertPage(pageResult, userMap));
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageUserController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageUserController.java
new file mode 100644
index 000000000..0f1224d30
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageUserController.java
@@ -0,0 +1,111 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user.*;
+import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageUserConvert;
+import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageUserDO;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordBizTypeEnum;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageRecordStatusEnum;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
+import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageRecordService;
+import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageUserService;
+import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageWithdrawService;
+import cn.iocoder.yudao.module.trade.service.brokerage.bo.UserBrokerageSummaryRespBO;
+import cn.iocoder.yudao.module.trade.service.brokerage.bo.BrokerageWithdrawSummaryRespBO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.Map;
+import java.util.Set;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "管理后台 - 分销用户")
+@RestController
+@RequestMapping("/trade/brokerage-user")
+@Validated
+public class BrokerageUserController {
+
+ @Resource
+ private BrokerageUserService brokerageUserService;
+ @Resource
+ private BrokerageRecordService brokerageRecordService;
+ @Resource
+ private BrokerageWithdrawService brokerageWithdrawService;
+
+ @Resource
+ private MemberUserApi memberUserApi;
+
+ @PutMapping("/update-bind-user")
+ @Operation(summary = "修改推广员")
+ @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-bind-user')")
+ public CommonResult updateBindUser(@Valid @RequestBody BrokerageUserUpdateBrokerageUserReqVO updateReqVO) {
+ brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), updateReqVO.getBindUserId());
+ return success(true);
+ }
+
+ @PutMapping("/clear-bind-user")
+ @Operation(summary = "清除推广员")
+ @PreAuthorize("@ss.hasPermission('trade:brokerage-user:clear-bind-user')")
+ public CommonResult clearBindUser(@Valid @RequestBody BrokerageUserClearBrokerageUserReqVO updateReqVO) {
+ brokerageUserService.updateBrokerageUserId(updateReqVO.getId(), null);
+ return success(true);
+ }
+
+ @PutMapping("/update-brokerage-enable")
+ @Operation(summary = "修改推广资格")
+ @PreAuthorize("@ss.hasPermission('trade:brokerage-user:update-brokerage-enable')")
+ public CommonResult updateBrokerageEnabled(@Valid @RequestBody BrokerageUserUpdateBrokerageEnabledReqVO updateReqVO) {
+ brokerageUserService.updateBrokerageUserEnabled(updateReqVO.getId(), updateReqVO.getEnabled());
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得分销用户")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')")
+ public CommonResult getBrokerageUser(@RequestParam("id") Long id) {
+ BrokerageUserDO brokerageUser = brokerageUserService.getBrokerageUser(id);
+ BrokerageUserRespVO respVO = BrokerageUserConvert.INSTANCE.convert(brokerageUser);
+ return success(BrokerageUserConvert.INSTANCE.copyTo(memberUserApi.getUser(id).getCheckedData(), respVO));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得分销用户分页")
+ @PreAuthorize("@ss.hasPermission('trade:brokerage-user:query')")
+ public CommonResult> getBrokerageUserPage(@Valid BrokerageUserPageReqVO pageVO) {
+ // 分页查询
+ PageResult pageResult = brokerageUserService.getBrokerageUserPage(pageVO);
+
+ // 查询用户信息
+ Set userIds = convertSet(pageResult.getList(), BrokerageUserDO::getId);
+ Map userMap = memberUserApi.getUserMap(userIds);
+ // 合计分佣的推广订单
+ Map brokerageOrderSummaryMap = brokerageRecordService.getUserBrokerageSummaryMapByUserId(
+ userIds, BrokerageRecordBizTypeEnum.ORDER.getType(), BrokerageRecordStatusEnum.SETTLEMENT.getStatus());
+ // 合计分佣的推广用户
+ // TODO @疯狂:转成 map 批量读取
+ Map brokerageUserCountMap = convertMap(userIds,
+ userId -> userId,
+ userId -> brokerageUserService.getBrokerageUserCountByBindUserId(userId, null));
+ // 合计分佣的提现
+ // TODO @疯狂:如果未来支持了打款这个动作,可能 status 会不对;
+ Map withdrawMap = brokerageWithdrawService.getWithdrawSummaryMapByUserId(
+ userIds, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS);
+ // 拼接返回
+ return success(BrokerageUserConvert.INSTANCE.convertPage(pageResult, userMap, brokerageUserCountMap,
+ brokerageOrderSummaryMap, withdrawMap));
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageWithdrawController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageWithdrawController.java
new file mode 100644
index 000000000..609cfa433
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/BrokerageWithdrawController.java
@@ -0,0 +1,78 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawRejectReqVO;
+import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawPageReqVO;
+import cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw.BrokerageWithdrawRespVO;
+import cn.iocoder.yudao.module.trade.convert.brokerage.BrokerageWithdrawConvert;
+import cn.iocoder.yudao.module.trade.dal.dataobject.brokerage.BrokerageWithdrawDO;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
+import cn.iocoder.yudao.module.trade.service.brokerage.BrokerageWithdrawService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.Map;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "管理后台 - 佣金提现")
+@RestController
+@RequestMapping("/trade/brokerage-withdraw")
+@Validated
+public class BrokerageWithdrawController {
+
+ @Resource
+ private BrokerageWithdrawService brokerageWithdrawService;
+
+ @Resource
+ private MemberUserApi memberUserApi;
+
+ @PutMapping("/approve")
+ @Operation(summary = "通过申请")
+ @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')")
+ public CommonResult approveBrokerageWithdraw(@RequestParam("id") Integer id) {
+ brokerageWithdrawService.auditBrokerageWithdraw(id, BrokerageWithdrawStatusEnum.AUDIT_SUCCESS, "");
+ return success(true);
+ }
+
+ @PutMapping("/reject")
+ @Operation(summary = "驳回申请")
+ @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:audit')")
+ public CommonResult rejectBrokerageWithdraw(@Valid @RequestBody BrokerageWithdrawRejectReqVO reqVO) {
+ brokerageWithdrawService.auditBrokerageWithdraw(reqVO.getId(), BrokerageWithdrawStatusEnum.AUDIT_FAIL, reqVO.getAuditReason());
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得佣金提现")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:query')")
+ public CommonResult getBrokerageWithdraw(@RequestParam("id") Integer id) {
+ BrokerageWithdrawDO brokerageWithdraw = brokerageWithdrawService.getBrokerageWithdraw(id);
+ return success(BrokerageWithdrawConvert.INSTANCE.convert(brokerageWithdraw));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得佣金提现分页")
+ @PreAuthorize("@ss.hasPermission('trade:brokerage-withdraw:query')")
+ public CommonResult> getBrokerageWithdrawPage(@Valid BrokerageWithdrawPageReqVO pageVO) {
+ // 分页查询
+ PageResult pageResult = brokerageWithdrawService.getBrokerageWithdrawPage(pageVO);
+
+ // 拼接信息
+ Map userMap = memberUserApi.getUserMap(
+ convertSet(pageResult.getList(), BrokerageWithdrawDO::getUserId));
+ return success(BrokerageWithdrawConvert.INSTANCE.convertPage(pageResult, userMap));
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordBaseVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordBaseVO.java
new file mode 100644
index 000000000..0c53f99fb
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordBaseVO.java
@@ -0,0 +1,65 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+/**
+ * 佣金记录 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
+@Data
+public class BrokerageRecordBaseVO {
+
+ @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "25973")
+ @NotNull(message = "用户编号不能为空")
+ private Long userId;
+
+ @Schema(description = "业务编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23353")
+ @NotEmpty(message = "业务编号不能为空")
+ private String bizId;
+
+ @Schema(description = "业务类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "业务类型不能为空")
+ private Integer bizType;
+
+ @Schema(description = "标题", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotEmpty(message = "标题不能为空")
+ private String title;
+
+ @Schema(description = "金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "28731")
+ @NotNull(message = "金额不能为空")
+ private Integer price;
+
+ @Schema(description = "当前总佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "13226")
+ @NotNull(message = "当前总佣金不能为空")
+ private Integer totalPrice;
+
+ @Schema(description = "说明", requiredMode = Schema.RequiredMode.REQUIRED, example = "你说的对")
+ @NotNull(message = "说明不能为空")
+ private String description;
+
+ @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "状态不能为空")
+ private Integer status;
+
+ @Schema(description = "冻结时间(天)", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "冻结时间(天)不能为空")
+ private Integer frozenDays;
+
+ @Schema(description = "解冻时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime unfreezeTime;
+
+ @Schema(description = "来源用户等级")
+ private Integer sourceUserLevel;
+
+ @Schema(description = "来源用户编号")
+ private Long sourceUserId;
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordPageReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordPageReqVO.java
new file mode 100644
index 000000000..36c4744e8
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordPageReqVO.java
@@ -0,0 +1,36 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record;
+
+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;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 佣金记录分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BrokerageRecordPageReqVO extends PageParam {
+
+ @Schema(description = "用户编号", example = "25973")
+ private Long userId;
+
+ @Schema(description = "业务类型", example = "1")
+ private Integer bizType;
+
+ @Schema(description = "状态", example = "1")
+ private Integer status;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+ @Schema(description = "用户类型", example = "1")
+ private Integer sourceUserLevel;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordRespVO.java
new file mode 100644
index 000000000..224ecf1e5
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/record/BrokerageRecordRespVO.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.record;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 佣金记录 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BrokerageRecordRespVO extends BrokerageRecordBaseVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "28896")
+ private Integer id;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+
+ // ========== 用户信息 ==========
+
+ @Schema(description = "用户头像", example = "https://www.iocoder.cn/xxx.png")
+ private String userAvatar;
+ @Schema(description = "用户昵称", example = "李四")
+ private String userNickname;
+
+
+ // ========== 来源用户信息 ==========
+
+ @Schema(description = "来源用户头像", example = "https://www.iocoder.cn/xxx.png")
+ private String sourceUserAvatar;
+ @Schema(description = "来源用户昵称", example = "李四")
+ private String sourceUserNickname;
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserBaseVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserBaseVO.java
new file mode 100644
index 000000000..05e5935b0
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserBaseVO.java
@@ -0,0 +1,43 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+/**
+ * 分销用户 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
+@Data
+public class BrokerageUserBaseVO {
+
+ @Schema(description = "推广员编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4587")
+ @NotNull(message = "推广员编号不能为空")
+ private Long bindUserId;
+
+ @Schema(description = "推广员绑定时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime bindUserTime;
+
+ @Schema(description = "推广资格", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "推广资格不能为空")
+ private Boolean brokerageEnabled;
+
+ @Schema(description = "成为分销员时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime brokerageTime;
+
+ @Schema(description = "可用佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "11089")
+ @NotNull(message = "可用佣金不能为空")
+ private Integer price;
+
+ @Schema(description = "冻结佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "30916")
+ @NotNull(message = "冻结佣金不能为空")
+ private Integer frozenPrice;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserClearBrokerageUserReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserClearBrokerageUserReqVO.java
new file mode 100644
index 000000000..5a05c56ce
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserClearBrokerageUserReqVO.java
@@ -0,0 +1,18 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.ToString;
+
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 分销用户 - 清除推广员 Request VO")
+@Data
+@ToString(callSuper = true)
+public class BrokerageUserClearBrokerageUserReqVO {
+
+ @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
+ @NotNull(message = "用户编号不能为空")
+ private Long id;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserPageReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserPageReqVO.java
new file mode 100644
index 000000000..cb0ce8954
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserPageReqVO.java
@@ -0,0 +1,37 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user;
+
+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;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 分销用户分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BrokerageUserPageReqVO extends PageParam {
+
+ @Schema(description = "推广员编号", example = "4587")
+ private Long bindUserId;
+
+ @Schema(description = "推广资格", example = "true")
+ private Boolean brokerageEnabled;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+ @Schema(description = "用户等级", example = "1") // 注意,这了不是用户的会员等级,而是过滤推广的层级
+ private Integer level;
+
+ @Schema(description = "绑定时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] bindUserTime;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserRespVO.java
new file mode 100644
index 000000000..3f5fe258f
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserRespVO.java
@@ -0,0 +1,45 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 分销用户 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BrokerageUserRespVO extends BrokerageUserBaseVO {
+
+ @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
+ private Long id;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+ // ========== 用户信息 ==========
+
+ @Schema(description = "用户头像", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/xxx.png")
+ private String avatar;
+ @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+ private String nickname;
+
+ // ========== 推广信息 ========== 注意:是包括 1 + 2 级的数据
+
+ @Schema(description = "推广用户数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
+ private Integer brokerageUserCount;
+ @Schema(description = "推广订单数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
+ private Integer brokerageOrderCount;
+ @Schema(description = "推广订单金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
+ private Integer brokerageOrderPrice;
+
+ // ========== 提现信息 ==========
+
+ @Schema(description = "已提现金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
+ private Integer withdrawPrice;
+ @Schema(description = "已提现次数", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
+ private Integer withdrawCount;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserUpdateBrokerageEnabledReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserUpdateBrokerageEnabledReqVO.java
new file mode 100644
index 000000000..d097855a2
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserUpdateBrokerageEnabledReqVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.ToString;
+
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 分销用户 - 修改推广员 Request VO")
+@Data
+@ToString(callSuper = true)
+public class BrokerageUserUpdateBrokerageEnabledReqVO {
+
+ @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
+ @NotNull(message = "用户编号不能为空")
+ private Long id;
+
+ @Schema(description = "推广资格", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "推广资格不能为空")
+ private Boolean enabled;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserUpdateBrokerageUserReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserUpdateBrokerageUserReqVO.java
new file mode 100644
index 000000000..56391c4d5
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/user/BrokerageUserUpdateBrokerageUserReqVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.user;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.ToString;
+
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 分销用户 - 修改推广员 Request VO")
+@Data
+@ToString(callSuper = true)
+public class BrokerageUserUpdateBrokerageUserReqVO {
+
+ @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "20019")
+ @NotNull(message = "用户编号不能为空")
+ private Long id;
+
+ @Schema(description = "推广员编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "4587")
+ @NotNull(message = "推广员编号不能为空")
+ private Long bindUserId;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawBaseVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawBaseVO.java
new file mode 100644
index 000000000..8aca8a2bb
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawBaseVO.java
@@ -0,0 +1,68 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import javax.validation.constraints.NotNull;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+/**
+ * 佣金提现 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
+@Data
+public class BrokerageWithdrawBaseVO {
+
+ @Schema(description = "用户编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "11436")
+ @NotNull(message = "用户编号不能为空")
+ private Long userId;
+
+ @Schema(description = "提现金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "18781")
+ @NotNull(message = "提现金额不能为空")
+ private Integer price;
+
+ @Schema(description = "提现手续费", requiredMode = Schema.RequiredMode.REQUIRED, example = "11417")
+ @NotNull(message = "提现手续费不能为空")
+ private Integer feePrice;
+
+ @Schema(description = "当前总佣金", requiredMode = Schema.RequiredMode.REQUIRED, example = "18576")
+ @NotNull(message = "当前总佣金不能为空")
+ private Integer totalPrice;
+
+ @Schema(description = "提现类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "提现类型不能为空")
+ private Integer type;
+
+ @Schema(description = "真实姓名", example = "赵六")
+ private String name;
+
+ @Schema(description = "账号", example = "88677912132")
+ private String accountNo;
+
+ @Schema(description = "银行名称", example = "1")
+ private String bankName;
+
+ @Schema(description = "开户地址", example = "海淀支行")
+ private String bankAddress;
+
+ @Schema(description = "收款码", example = "https://www.iocoder.cn")
+ private String accountQrCodeUrl;
+
+ @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "状态不能为空")
+ private Integer status;
+
+ @Schema(description = "审核驳回原因", example = "不对")
+ private String auditReason;
+
+ @Schema(description = "审核时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime auditTime;
+
+ @Schema(description = "备注", example = "随便")
+ private String remark;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawPageReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawPageReqVO.java
new file mode 100644
index 000000000..b18ff74af
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawPageReqVO.java
@@ -0,0 +1,47 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw;
+
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawStatusEnum;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 佣金提现分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BrokerageWithdrawPageReqVO extends PageParam {
+
+ @Schema(description = "用户编号", example = "11436")
+ private Long userId;
+
+ @Schema(description = "提现类型", example = "1")
+ @InEnum(value = BrokerageWithdrawTypeEnum.class, message = "提现类型必须是 {value}")
+ private Integer type;
+
+ @Schema(description = "真实姓名", example = "赵六")
+ private String name;
+
+ @Schema(description = "账号", example = "886779132")
+ private String accountNo;
+
+ @Schema(description = "银行名称", example = "1")
+ private String bankName;
+
+ @Schema(description = "状态", example = "1")
+ @InEnum(value = BrokerageWithdrawStatusEnum.class, message = "状态必须是 {value}")
+ private Integer status;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRejectReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRejectReqVO.java
new file mode 100644
index 000000000..23e6c28e5
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRejectReqVO.java
@@ -0,0 +1,23 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.ToString;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 驳回申请 Request VO")
+@Data
+@ToString(callSuper = true)
+public class BrokerageWithdrawRejectReqVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161")
+ @NotNull(message = "编号不能为空")
+ private Integer id;
+
+ @Schema(description = "审核驳回原因", example = "不对")
+ @NotEmpty(message = "审核驳回原因不能为空")
+ private String auditReason;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRespVO.java
new file mode 100644
index 000000000..de74bb4f6
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/brokerage/vo/withdraw/BrokerageWithdrawRespVO.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.trade.controller.admin.brokerage.vo.withdraw;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 佣金提现 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class BrokerageWithdrawRespVO extends BrokerageWithdrawBaseVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "7161")
+ private Integer id;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+ @Schema(description = "用户昵称", requiredMode = Schema.RequiredMode.REQUIRED, example = "芋艿")
+ private String userNickname;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/TradeConfigController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/TradeConfigController.java
new file mode 100644
index 000000000..5e0558fbf
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/TradeConfigController.java
@@ -0,0 +1,53 @@
+package cn.iocoder.yudao.module.trade.controller.admin.config;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigRespVO;
+import cn.iocoder.yudao.module.trade.controller.admin.config.vo.TradeConfigSaveReqVO;
+import cn.iocoder.yudao.module.trade.convert.config.TradeConfigConvert;
+import cn.iocoder.yudao.module.trade.dal.dataobject.config.TradeConfigDO;
+import cn.iocoder.yudao.module.trade.service.config.TradeConfigService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 交易中心配置")
+@RestController
+@RequestMapping("/trade/config")
+@Validated
+public class TradeConfigController {
+
+ @Resource
+ private TradeConfigService tradeConfigService;
+
+ @Value("${yudao.tencent-lbs-key}")
+ private String tencentLbsKey;
+
+ @PutMapping("/save")
+ @Operation(summary = "更新交易中心配置")
+ @PreAuthorize("@ss.hasPermission('trade:config:save')")
+ public CommonResult updateConfig(@Valid @RequestBody TradeConfigSaveReqVO updateReqVO) {
+ tradeConfigService.saveTradeConfig(updateReqVO);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得交易中心配置")
+ @PreAuthorize("@ss.hasPermission('trade:config:query')")
+ public CommonResult getConfig() {
+ TradeConfigDO config = tradeConfigService.getTradeConfig();
+ TradeConfigRespVO configVO = TradeConfigConvert.INSTANCE.convert(config);
+ if (configVO != null) {
+ configVO.setTencentLbsKey(tencentLbsKey);
+ }
+ return success(configVO);
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigBaseVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigBaseVO.java
new file mode 100644
index 000000000..1507e2b8f
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigBaseVO.java
@@ -0,0 +1,104 @@
+package cn.iocoder.yudao.module.trade.controller.admin.config.vo;
+
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageBindModeEnum;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageEnabledConditionEnum;
+import cn.iocoder.yudao.module.trade.enums.brokerage.BrokerageWithdrawTypeEnum;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.PositiveOrZero;
+import java.util.List;
+
+/**
+ * 交易中心配置 Base VO,提供给添加、修改、详细的子 VO 使用
+ * 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+ */
+@Data
+public class TradeConfigBaseVO {
+
+ // ========== 售后相关 ==========
+
+ @Schema(description = "售后的退款理由", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotEmpty(message = "售后的退款理由不能为空")
+ private List afterSaleRefundReasons;
+
+ @Schema(description = "售后的退货理由", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotEmpty(message = "售后的退货理由不能为空")
+ private List afterSaleReturnReasons;
+
+ // ========== 配送相关 ==========
+
+ /**
+ * 是否启用全场包邮
+ */
+ @Schema(description = "是否启用全场包邮", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+ @NotNull(message = "是否启用全场包邮不能为空")
+ private Boolean deliveryExpressFreeEnabled;
+
+ @Schema(description = "全场包邮的最小金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
+ @NotNull(message = "全场包邮的最小金额不能为空")
+ @PositiveOrZero(message = "全场包邮的最小金额不能是负数")
+ private Integer deliveryExpressFreePrice;
+
+ @Schema(description = "是否开启自提", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+ @NotNull(message = "是否开启自提不能为空")
+ private Boolean deliveryPickUpEnabled;
+
+ // ========== 分销相关 ==========
+
+ @Schema(description = "是否启用分佣", requiredMode = Schema.RequiredMode.REQUIRED, example = "true")
+ @NotNull(message = "是否启用分佣不能为空")
+ private Boolean brokerageEnabled;
+
+ @Schema(description = "分佣模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @NotNull(message = "分佣模式不能为空")
+ @InEnum(value = BrokerageEnabledConditionEnum.class, message = "分佣模式必须是 {value}")
+ private Integer brokerageEnabledCondition;
+
+ @Schema(description = "分销关系绑定模式", requiredMode = Schema.RequiredMode.REQUIRED, example = "0")
+ @NotNull(message = "分销关系绑定模式不能为空")
+ @InEnum(value = BrokerageBindModeEnum.class, message = "分销关系绑定模式必须是 {value}")
+ private Integer brokerageBindMode;
+
+ @Schema(description = "分销海报图地址数组", requiredMode = Schema.RequiredMode.REQUIRED, example = "[https://www.iocoder.cn/yudao.jpg]")
+ private List brokeragePosterUrls;
+
+ @Schema(description = "一级返佣比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
+ @NotNull(message = "一级返佣比例不能为空")
+ @Range(min = 0, max = 100, message = "一级返佣比例必须在 0 - 100 之间")
+ private Integer brokerageFirstPercent;
+
+ @Schema(description = "二级返佣比例", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
+ @NotNull(message = "二级返佣比例不能为空")
+ @Range(min = 0, max = 100, message = "二级返佣比例必须在 0 - 100 之间")
+ private Integer brokerageSecondPercent;
+
+ @Schema(description = "用户提现最低金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
+ @NotNull(message = "用户提现最低金额不能为空")
+ @PositiveOrZero(message = "用户提现最低金额不能是负数")
+ private Integer brokerageWithdrawMinPrice;
+
+ @Schema(description = "用户提现手续费百分比", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
+ @NotNull(message = "用户提现手续费百分比不能为空")
+ @PositiveOrZero(message = "用户提现手续费百分比不能是负数")
+ private Integer brokerageWithdrawFeePercent;
+
+ @Schema(description = "提现银行", requiredMode = Schema.RequiredMode.REQUIRED, example = "[0, 1]")
+ @NotEmpty(message = "提现银行不能为空")
+ private List brokerageBankNames;
+
+ @Schema(description = "佣金冻结时间(天)", requiredMode = Schema.RequiredMode.REQUIRED, example = "7")
+ @NotNull(message = "佣金冻结时间(天)不能为空")
+ @PositiveOrZero(message = "佣金冻结时间不能是负数")
+ private Integer brokerageFrozenDays;
+
+ @Schema(description = "提现方式", requiredMode = Schema.RequiredMode.REQUIRED, example = "[0, 1]")
+ @NotEmpty(message = "提现方式不能为空")
+ @InEnum(value = BrokerageWithdrawTypeEnum.class, message = "提现方式必须是 {value}")
+ private List brokerageWithdrawTypes;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigRespVO.java
new file mode 100644
index 000000000..5ded00ace
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigRespVO.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.trade.controller.admin.config.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Schema(description = "管理后台 - 交易中心配置 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class TradeConfigRespVO extends TradeConfigBaseVO {
+
+ @Schema(description = "自增主键", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "腾讯地图 KEY", requiredMode = Schema.RequiredMode.REQUIRED, example = "123456")
+ private String tencentLbsKey;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigSaveReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigSaveReqVO.java
new file mode 100644
index 000000000..03a0c41df
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/config/vo/TradeConfigSaveReqVO.java
@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.module.trade.controller.admin.config.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Schema(description = "管理后台 - 交易中心配置更新 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class TradeConfigSaveReqVO extends TradeConfigBaseVO {
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressController.java
new file mode 100644
index 000000000..12236abba
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressController.java
@@ -0,0 +1,96 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
+import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
+import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express.*;
+import cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressConvert;
+import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
+import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletResponse;
+import javax.validation.Valid;
+import java.io.IOException;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum.EXPORT;
+
+@Tag(name = "管理后台 - 快递公司")
+@RestController
+@RequestMapping("/trade/delivery/express")
+@Validated
+public class DeliveryExpressController {
+
+ @Resource
+ private DeliveryExpressService deliveryExpressService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建快递公司")
+ @PreAuthorize("@ss.hasPermission('trade:delivery:express:create')")
+ public CommonResult createDeliveryExpress(@Valid @RequestBody DeliveryExpressCreateReqVO createReqVO) {
+ return success(deliveryExpressService.createDeliveryExpress(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新快递公司")
+ @PreAuthorize("@ss.hasPermission('trade:delivery:express:update')")
+ public CommonResult updateDeliveryExpress(@Valid @RequestBody DeliveryExpressUpdateReqVO updateReqVO) {
+ deliveryExpressService.updateDeliveryExpress(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除快递公司")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('trade:delivery:express:delete')")
+ public CommonResult deleteDeliveryExpress(@RequestParam("id") Long id) {
+ deliveryExpressService.deleteDeliveryExpress(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得快递公司")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('trade:delivery:express:query')")
+ public CommonResult getDeliveryExpress(@RequestParam("id") Long id) {
+ DeliveryExpressDO deliveryExpress = deliveryExpressService.getDeliveryExpress(id);
+ return success(DeliveryExpressConvert.INSTANCE.convert(deliveryExpress));
+ }
+
+ @GetMapping("/list-all-simple")
+ @Operation(summary = "获取快递公司精简信息列表", description = "主要用于前端的下拉选项")
+ public CommonResult> getSimpleDeliveryExpressList() {
+ List list = deliveryExpressService.getDeliveryExpressListByStatus(CommonStatusEnum.ENABLE.getStatus());
+ return success(DeliveryExpressConvert.INSTANCE.convertList1(list));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得快递公司分页")
+ @PreAuthorize("@ss.hasPermission('trade:delivery:express:query')")
+ public CommonResult> getDeliveryExpressPage(@Valid DeliveryExpressPageReqVO pageVO) {
+ PageResult pageResult = deliveryExpressService.getDeliveryExpressPage(pageVO);
+ return success(DeliveryExpressConvert.INSTANCE.convertPage(pageResult));
+ }
+
+ @GetMapping("/export-excel")
+ @Operation(summary = "导出快递公司 Excel")
+ @PreAuthorize("@ss.hasPermission('trade:delivery:express:export')")
+ @OperateLog(type = EXPORT)
+ public void exportDeliveryExpressExcel(@Valid DeliveryExpressExportReqVO exportReqVO,
+ HttpServletResponse response) throws IOException {
+ List list = deliveryExpressService.getDeliveryExpressList(exportReqVO);
+ // 导出 Excel
+ List dataList = DeliveryExpressConvert.INSTANCE.convertList02(list);
+ ExcelUtils.write(response, "快递公司.xls", "数据", DeliveryExpressExcelVO.class, dataList);
+ }
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressTemplateController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressTemplateController.java
new file mode 100644
index 000000000..5dc83682a
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryExpressTemplateController.java
@@ -0,0 +1,90 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery;
+
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate.*;
+import cn.iocoder.yudao.module.trade.convert.delivery.DeliveryExpressTemplateConvert;
+import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressTemplateDO;
+import cn.iocoder.yudao.module.trade.service.delivery.DeliveryExpressTemplateService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.Collection;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 快递运费模板")
+@RestController
+@RequestMapping("/trade/delivery/express-template")
+@Validated
+public class DeliveryExpressTemplateController {
+
+ @Resource
+ private DeliveryExpressTemplateService deliveryExpressTemplateService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建快递运费模板")
+ @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:create')")
+ public CommonResult createDeliveryExpressTemplate(@Valid @RequestBody DeliveryExpressTemplateCreateReqVO createReqVO) {
+ return success(deliveryExpressTemplateService.createDeliveryExpressTemplate(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新快递运费模板")
+ @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:update')")
+ public CommonResult updateDeliveryExpressTemplate(@Valid @RequestBody DeliveryExpressTemplateUpdateReqVO updateReqVO) {
+ deliveryExpressTemplateService.updateDeliveryExpressTemplate(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除快递运费模板")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:delete')")
+ public CommonResult deleteDeliveryExpressTemplate(@RequestParam("id") Long id) {
+ deliveryExpressTemplateService.deleteDeliveryExpressTemplate(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得快递运费模板")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:query')")
+ public CommonResult getDeliveryExpressTemplate(@RequestParam("id") Long id) {
+ return success(deliveryExpressTemplateService.getDeliveryExpressTemplate(id));
+ }
+
+ @GetMapping("/list")
+ @Operation(summary = "获得快递运费模板列表")
+ @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
+ @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:query')")
+ public CommonResult> getDeliveryExpressTemplateList(@RequestParam("ids") Collection ids) {
+ List list = deliveryExpressTemplateService.getDeliveryExpressTemplateList(ids);
+ return success(DeliveryExpressTemplateConvert.INSTANCE.convertList(list));
+ }
+
+ @GetMapping("/list-all-simple")
+ @Operation(summary = "获取快递模版精简信息列表", description = "主要用于前端的下拉选项")
+ public CommonResult> getSimpleTemplateList() {
+ // 获取运费模版列表,只要开启状态的
+ List list = deliveryExpressTemplateService.getDeliveryExpressTemplateList();
+ // 排序后,返回给前端
+ return success(DeliveryExpressTemplateConvert.INSTANCE.convertList1(list));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得快递运费模板分页")
+ @PreAuthorize("@ss.hasPermission('trade:delivery:express-template:query')")
+ public CommonResult> getDeliveryExpressTemplatePage(@Valid DeliveryExpressTemplatePageReqVO pageVO) {
+ PageResult pageResult = deliveryExpressTemplateService.getDeliveryExpressTemplatePage(pageVO);
+ return success(DeliveryExpressTemplateConvert.INSTANCE.convertPage(pageResult));
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryPickUpStoreController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryPickUpStoreController.java
new file mode 100644
index 000000000..4235d6ef5
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/DeliveryPickUpStoreController.java
@@ -0,0 +1,91 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.pojo.CommonResult;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup.*;
+import cn.iocoder.yudao.module.trade.convert.delivery.DeliveryPickUpStoreConvert;
+import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryPickUpStoreDO;
+import cn.iocoder.yudao.module.trade.service.delivery.DeliveryPickUpStoreService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import java.util.Collection;
+import java.util.List;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+
+@Tag(name = "管理后台 - 自提门店")
+@RestController
+@RequestMapping("/trade/delivery/pick-up-store")
+@Validated
+public class DeliveryPickUpStoreController {
+
+ @Resource
+ private DeliveryPickUpStoreService deliveryPickUpStoreService;
+
+ @PostMapping("/create")
+ @Operation(summary = "创建自提门店")
+ @PreAuthorize("@ss.hasPermission('trade:delivery:pick-up-store:create')")
+ public CommonResult createDeliveryPickUpStore(@Valid @RequestBody DeliveryPickUpStoreCreateReqVO createReqVO) {
+ return success(deliveryPickUpStoreService.createDeliveryPickUpStore(createReqVO));
+ }
+
+ @PutMapping("/update")
+ @Operation(summary = "更新自提门店")
+ @PreAuthorize("@ss.hasPermission('trade:delivery:pick-up-store:update')")
+ public CommonResult updateDeliveryPickUpStore(@Valid @RequestBody DeliveryPickUpStoreUpdateReqVO updateReqVO) {
+ deliveryPickUpStoreService.updateDeliveryPickUpStore(updateReqVO);
+ return success(true);
+ }
+
+ @DeleteMapping("/delete")
+ @Operation(summary = "删除自提门店")
+ @Parameter(name = "id", description = "编号", required = true)
+ @PreAuthorize("@ss.hasPermission('trade:delivery:pick-up-store:delete')")
+ public CommonResult deleteDeliveryPickUpStore(@RequestParam("id") Long id) {
+ deliveryPickUpStoreService.deleteDeliveryPickUpStore(id);
+ return success(true);
+ }
+
+ @GetMapping("/get")
+ @Operation(summary = "获得自提门店")
+ @Parameter(name = "id", description = "编号", required = true, example = "1024")
+ @PreAuthorize("@ss.hasPermission('trade:delivery:pick-up-store:query')")
+ public CommonResult getDeliveryPickUpStore(@RequestParam("id") Long id) {
+ DeliveryPickUpStoreDO deliveryPickUpStore = deliveryPickUpStoreService.getDeliveryPickUpStore(id);
+ return success(DeliveryPickUpStoreConvert.INSTANCE.convert(deliveryPickUpStore));
+ }
+
+ @GetMapping("/list-all-simple")
+ @Operation(summary = "获得自提门店精简信息列表")
+ public CommonResult> getSimpleDeliveryPickUpStoreList() {
+ List list = deliveryPickUpStoreService.getDeliveryPickUpStoreListByStatus(
+ CommonStatusEnum.ENABLE.getStatus());
+ return success(DeliveryPickUpStoreConvert.INSTANCE.convertList1(list));
+ }
+
+ @GetMapping("/list")
+ @Operation(summary = "获得自提门店列表")
+ @Parameter(name = "ids", description = "编号列表", required = true, example = "1024,2048")
+ @PreAuthorize("@ss.hasPermission('trade:delivery:pick-up-store:query')")
+ public CommonResult> getDeliveryPickUpStoreList(@RequestParam("ids") Collection ids) {
+ List list = deliveryPickUpStoreService.getDeliveryPickUpStoreList(ids);
+ return success(DeliveryPickUpStoreConvert.INSTANCE.convertList(list));
+ }
+
+ @GetMapping("/page")
+ @Operation(summary = "获得自提门店分页")
+ @PreAuthorize("@ss.hasPermission('trade:delivery:pick-up-store:query')")
+ public CommonResult> getDeliveryPickUpStorePage(@Valid DeliveryPickUpStorePageReqVO pageVO) {
+ PageResult pageResult = deliveryPickUpStoreService.getDeliveryPickUpStorePage(pageVO);
+ return success(DeliveryPickUpStoreConvert.INSTANCE.convertPage(pageResult));
+ }
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressBaseVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressBaseVO.java
new file mode 100644
index 000000000..cc7b8bedd
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressBaseVO.java
@@ -0,0 +1,34 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+* 快递公司 Base VO,提供给添加、修改、详细的子 VO 使用
+* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+*/
+@Data
+public class DeliveryExpressBaseVO {
+
+ @Schema(description = "快递公司编码", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "快递公司编码不能为空")
+ private String code;
+
+ @Schema(description = "快递公司名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+ @NotNull(message = "快递公司名称不能为空")
+ private String name;
+
+ @Schema(description = "快递公司logo")
+ private String logo;
+
+ @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "排序不能为空")
+ private Integer sort;
+
+ @Schema(description = "状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "状态不能为空")
+ private Integer status;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressCreateReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressCreateReqVO.java
new file mode 100644
index 000000000..a9ba8a7cb
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressCreateReqVO.java
@@ -0,0 +1,12 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express;
+
+import lombok.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+@Schema(description = "管理后台 - 快递公司创建 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DeliveryExpressCreateReqVO extends DeliveryExpressBaseVO {
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressExcelVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressExcelVO.java
new file mode 100644
index 000000000..c84a3a189
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressExcelVO.java
@@ -0,0 +1,39 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express;
+
+import cn.iocoder.yudao.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.yudao.framework.excel.core.convert.DictConvert;
+import cn.iocoder.yudao.module.system.enums.DictTypeConstants;
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 快递公司 Excel VO
+ */
+@Data
+public class DeliveryExpressExcelVO {
+
+ @ExcelProperty("编号")
+ private Long id;
+
+ @ExcelProperty("快递公司编码")
+ private String code;
+
+ @ExcelProperty("快递公司名称")
+ private String name;
+
+ @ExcelProperty("快递公司 logo")
+ private String logo;
+
+ @ExcelProperty("排序")
+ private Integer sort;
+
+ @ExcelProperty(value = "状态", converter = DictConvert.class)
+ @DictFormat(DictTypeConstants.COMMON_STATUS)
+ private Integer status;
+
+ @ExcelProperty("创建时间")
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressExportReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressExportReqVO.java
new file mode 100644
index 000000000..c601721e8
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressExportReqVO.java
@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 快递公司 Excel 导出 Request VO")
+@Data
+public class DeliveryExpressExportReqVO {
+
+ @Schema(description = "快递公司编码")
+ private String code;
+
+ @Schema(description = "快递公司名称", example = "李四")
+ private String name;
+
+ @Schema(description = "状态(0正常 1停用)", example = "1")
+ private Integer status;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressPageReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressPageReqVO.java
new file mode 100644
index 000000000..4a000f319
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressPageReqVO.java
@@ -0,0 +1,31 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 快递公司分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DeliveryExpressPageReqVO extends PageParam {
+
+ @Schema(description = "快递公司编码")
+ private String code;
+
+ @Schema(description = "快递公司名称", example = "李四")
+ private String name;
+
+ @Schema(description = "状态(0正常 1停用)", example = "1")
+ private Integer status;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressRespVO.java
new file mode 100644
index 000000000..cc314d105
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressRespVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 快递公司 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DeliveryExpressRespVO extends DeliveryExpressBaseVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6592")
+ private Long id;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressSimpleRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressSimpleRespVO.java
new file mode 100644
index 000000000..b97cc2317
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressSimpleRespVO.java
@@ -0,0 +1,24 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 快递公司精简信息 Response VO")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class DeliveryExpressSimpleRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6592")
+ @NotNull(message = "编号不能为空")
+ private Long id;
+
+ @Schema(description = "快递公司名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "顺丰速运")
+ @NotNull(message = "快递公司名称不能为空")
+ private String name;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressUpdateReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressUpdateReqVO.java
new file mode 100644
index 000000000..e51366ded
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/express/DeliveryExpressUpdateReqVO.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.express;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 快递公司更新 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DeliveryExpressUpdateReqVO extends DeliveryExpressBaseVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "6592")
+ @NotNull(message = "编号不能为空")
+ private Long id;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateBaseVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateBaseVO.java
new file mode 100644
index 000000000..3be8ffc3b
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateBaseVO.java
@@ -0,0 +1,27 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+* 快递运费模板 Base VO,提供给添加、修改、详细的子 VO 使用
+* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+*/
+@Data
+public class DeliveryExpressTemplateBaseVO {
+
+ @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "王五")
+ @NotNull(message = "模板名称不能为空")
+ private String name;
+
+ @Schema(description = "配送计费方式 1:按件 2:按重量 3:按体积", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "配送计费方式 1:按件 2:按重量 3:按体积不能为空")
+ private Integer chargeMode;
+
+ @Schema(description = "排序", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "排序不能为空")
+ private Integer sort;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateChargeBaseVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateChargeBaseVO.java
new file mode 100644
index 000000000..efb15c894
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateChargeBaseVO.java
@@ -0,0 +1,38 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * 快递运费模板运费设置 Base VO,提供给添加运费模板使用
+ */
+@Data
+public class DeliveryExpressTemplateChargeBaseVO {
+
+ @Schema(description = "编号", example = "6592", hidden = true) // 由于想简单一点,复用这个 VO 在更新操作,所以 hidden 为 false
+ private Long id;
+
+ @Schema(description = "区域编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,120000]")
+ @NotEmpty(message = "区域编号列表不能为空")
+ private List areaIds;
+
+ @Schema(description = "首件数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
+ @NotNull(message = "首件数量不能为空")
+ private Double startCount;
+
+ @Schema(description = "起步价", requiredMode = Schema.RequiredMode.REQUIRED, example = "1000")
+ @NotNull(message = "起步价不能为空")
+ private Integer startPrice;
+
+ @Schema(description = "续件数量", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
+ @NotNull(message = "续件数量不能为空")
+ private Double extraCount;
+
+ @Schema(description = "额外价", requiredMode = Schema.RequiredMode.REQUIRED, example = "2000")
+ @NotNull(message = "额外价不能为空")
+ private Integer extraPrice;
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateCreateReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateCreateReqVO.java
new file mode 100644
index 000000000..c5eeaebc9
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateCreateReqVO.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.Valid;
+import java.util.List;
+
+@Schema(description = "管理后台 - 快递运费模板创建 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DeliveryExpressTemplateCreateReqVO extends DeliveryExpressTemplateBaseVO {
+
+ @Schema(description = "区域运费列表")
+ @Valid
+ private List charges;
+
+ @Schema(description = "包邮区域列表")
+ @Valid
+ private List frees;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateDetailRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateDetailRespVO.java
new file mode 100644
index 000000000..272ab59a0
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateDetailRespVO.java
@@ -0,0 +1,25 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.util.List;
+
+@Schema(description = "管理后台 - 快递运费模板的详细 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DeliveryExpressTemplateDetailRespVO extends DeliveryExpressTemplateBaseVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "371")
+ private Long id;
+
+ @Schema(description = "运费模板运费设置", requiredMode = Schema.RequiredMode.REQUIRED)
+ private List charges;
+
+ @Schema(description = "运费模板包邮区域", requiredMode = Schema.RequiredMode.REQUIRED)
+ private List frees;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateFreeBaseVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateFreeBaseVO.java
new file mode 100644
index 000000000..b3e0f12b5
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateFreeBaseVO.java
@@ -0,0 +1,28 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * 快递运费模板包邮 Base VO,提供给添加运费模板使用
+ */
+@Data
+public class DeliveryExpressTemplateFreeBaseVO {
+
+ @Schema(description = "区域编号列表", requiredMode = Schema.RequiredMode.REQUIRED, example = "[1,120000]")
+ @NotEmpty(message = "区域编号列表不能为空")
+ private List areaIds;
+
+ @Schema(description = "包邮金额", requiredMode = Schema.RequiredMode.REQUIRED, example = "5000")
+ @NotNull(message = "包邮金额不能为空")
+ private Integer freePrice;
+
+ @Schema(description = "包邮件数", requiredMode = Schema.RequiredMode.REQUIRED, example = "5")
+ @NotNull(message = "包邮件数不能为空")
+ private Integer freeCount;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplatePageReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplatePageReqVO.java
new file mode 100644
index 000000000..ea1e4ab3e
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplatePageReqVO.java
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate;
+
+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;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 快递运费模板分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DeliveryExpressTemplatePageReqVO extends PageParam {
+
+ @Schema(description = "模板名称", example = "王五")
+ private String name;
+
+ @Schema(description = "配送计费方式 1:按件 2:按重量 3:按体积")
+ private Integer chargeMode;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateRespVO.java
new file mode 100644
index 000000000..19a8c1621
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateRespVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 快递运费模板 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DeliveryExpressTemplateRespVO extends DeliveryExpressTemplateBaseVO {
+
+ @Schema(description = "编号,自增", requiredMode = Schema.RequiredMode.REQUIRED, example = "371")
+ private Long id;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateSimpleRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateSimpleRespVO.java
new file mode 100644
index 000000000..074cc5337
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateSimpleRespVO.java
@@ -0,0 +1,21 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+
+@Schema(description = "管理后台 - 模版精简信息 Response VO")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class DeliveryExpressTemplateSimpleRespVO {
+
+ @Schema(description = "模版编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
+ private Long id;
+
+ @Schema(description = "模板名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "测试模版")
+ private String name;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateUpdateReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateUpdateReqVO.java
new file mode 100644
index 000000000..4c1774524
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/expresstemplate/DeliveryExpressTemplateUpdateReqVO.java
@@ -0,0 +1,30 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.expresstemplate;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+@Schema(description = "管理后台 - 快递运费模板更新 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DeliveryExpressTemplateUpdateReqVO extends DeliveryExpressTemplateBaseVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "371")
+ @NotNull(message = "编号不能为空")
+ private Long id;
+
+ @Schema(description = "区域运费列表")
+ @Valid
+ private List charges;
+
+ @Schema(description = "包邮区域列表")
+ @Valid
+ private List frees;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreBaseVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreBaseVO.java
new file mode 100644
index 000000000..6a4ab1141
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreBaseVO.java
@@ -0,0 +1,68 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import cn.iocoder.yudao.framework.common.validation.Mobile;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.time.LocalTime;
+
+/**
+* 自提门店 Base VO,提供给添加、修改、详细的子 VO 使用
+* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
+*/
+@Data
+public class DeliveryPickUpStoreBaseVO {
+
+ @Schema(description = "门店名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+ @NotBlank(message = "门店名称不能为空")
+ private String name;
+
+ @Schema(description = "门店简介", example = "我是门店简介")
+ private String introduction;
+
+ @Schema(description = "门店手机", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601892312")
+ @NotBlank(message = "门店手机不能为空")
+ @Mobile
+ private String phone;
+
+ @Schema(description = "区域编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18733")
+ @NotNull(message = "区域编号不能为空")
+ private Integer areaId;
+
+ @Schema(description = "门店详细地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "复旦大学路 188 号")
+ @NotBlank(message = "门店详细地址不能为空")
+ private String detailAddress;
+
+ @Schema(description = "门店 logo", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.png")
+ @NotBlank(message = "门店 logo 不能为空")
+ private String logo;
+
+ @Schema(description = "营业开始时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "营业开始时间不能为空")
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm")
+ private LocalTime openingTime;
+
+ @Schema(description = "营业结束时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ @NotNull(message = "营业结束时间不能为空")
+ @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "HH:mm")
+ private LocalTime closingTime;
+
+ @Schema(description = "纬度", requiredMode = Schema.RequiredMode.REQUIRED, example = "5.88")
+ @NotNull(message = "纬度不能为空")
+ private Double latitude;
+
+ @Schema(description = "经度", requiredMode = Schema.RequiredMode.REQUIRED, example = "6.99")
+ @NotNull(message = "经度不能为空")
+ private Double longitude;
+
+ @Schema(description = "门店状态", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
+ @NotNull(message = "门店状态不能为空")
+ @InEnum(CommonStatusEnum.class)
+ private Integer status;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreCreateReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreCreateReqVO.java
new file mode 100644
index 000000000..2185a2a55
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreCreateReqVO.java
@@ -0,0 +1,14 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import javax.validation.constraints.*;
+
+@Schema(description = "管理后台 - 自提门店创建 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DeliveryPickUpStoreCreateReqVO extends DeliveryPickUpStoreBaseVO {
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStorePageReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStorePageReqVO.java
new file mode 100644
index 000000000..45f0c87b9
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStorePageReqVO.java
@@ -0,0 +1,40 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup;
+
+import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
+import cn.iocoder.yudao.framework.common.validation.InEnum;
+import lombok.*;
+
+import java.time.LocalTime;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.yudao.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_HOUR_MINUTE_SECOND;
+import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 自提门店分页 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DeliveryPickUpStorePageReqVO extends PageParam {
+
+ @Schema(description = "门店名称", example = "李四")
+ private String name;
+
+ @Schema(description = "门店手机")
+ private String phone;
+
+ @Schema(description = "区域编号", example = "18733")
+ private Integer areaId;
+
+ @Schema(description = "门店状态", example = "1")
+ @InEnum(CommonStatusEnum.class)
+ private Integer status;
+
+ @Schema(description = "创建时间")
+ @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+ private LocalDateTime[] createTime;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreRespVO.java
new file mode 100644
index 000000000..5b5bd0d0c
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreRespVO.java
@@ -0,0 +1,22 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 自提门店 Response VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DeliveryPickUpStoreRespVO extends DeliveryPickUpStoreBaseVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23128")
+ private Long id;
+
+ @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+ private LocalDateTime createTime;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreSimpleRespVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreSimpleRespVO.java
new file mode 100644
index 000000000..c12fc9fc3
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreSimpleRespVO.java
@@ -0,0 +1,32 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Schema(description = "管理后台 - 自提门店精简信息 Response VO")
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class DeliveryPickUpStoreSimpleRespVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23128")
+ private Long id;
+
+ @Schema(description = "门店名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "李四")
+ private String name;
+
+ @Schema(description = "门店手机", requiredMode = Schema.RequiredMode.REQUIRED, example = "15601892312")
+ private String phone;
+
+ @Schema(description = "区域编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "18733")
+ private Integer areaId;
+
+ @Schema(description = "区域名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "xx市")
+ private String areaName;
+
+ @Schema(description = "门店详细地址", requiredMode = Schema.RequiredMode.REQUIRED, example = "复旦大学路 188 号")
+ private String detailAddress;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreUpdateReqVO.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreUpdateReqVO.java
new file mode 100644
index 000000000..2b0548d9d
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/delivery/vo/pickup/DeliveryPickUpStoreUpdateReqVO.java
@@ -0,0 +1,20 @@
+package cn.iocoder.yudao.module.trade.controller.admin.delivery.vo.pickup;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+import javax.validation.constraints.NotNull;
+
+@Schema(description = "管理后台 - 自提门店更新 Request VO")
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+public class DeliveryPickUpStoreUpdateReqVO extends DeliveryPickUpStoreBaseVO {
+
+ @Schema(description = "编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "23128")
+ @NotNull(message = "编号不能为空")
+ private Long id;
+
+}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.http b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.http
new file mode 100644
index 000000000..0bf8812b2
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.http
@@ -0,0 +1,9 @@
+### 获得交易订单分页 => 成功
+GET {{baseUrl}}/trade/order/page?pageNo=1&pageSize=10
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
+
+### 获得交易订单分页 => 成功
+GET {{baseUrl}}/trade/order/get-detail?id=21
+Authorization: Bearer {{token}}
+tenant-id: {{adminTenentId}}
diff --git a/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java
new file mode 100644
index 000000000..cf352c4a7
--- /dev/null
+++ b/yudao-module-mall/yudao-module-trade-biz/src/main/java/cn/iocoder/yudao/module/trade/controller/admin/order/TradeOrderController.java
@@ -0,0 +1,168 @@
+package cn.iocoder.yudao.module.trade.controller.admin.order;
+
+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.module.member.api.user.MemberUserApi;
+import cn.iocoder.yudao.module.member.api.user.dto.MemberUserRespDTO;
+import cn.iocoder.yudao.module.trade.controller.admin.order.vo.*;
+import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
+import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderLogDO;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderLogService;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderQueryService;
+import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
+
+@Tag(name = "管理后台 - 交易订单")
+@RestController
+@RequestMapping("/trade/order")
+@Validated
+@Slf4j
+public class TradeOrderController {
+
+ @Resource
+ private TradeOrderUpdateService tradeOrderUpdateService;
+ @Resource
+ private TradeOrderQueryService tradeOrderQueryService;
+ @Resource
+ private TradeOrderLogService tradeOrderLogService;
+
+ @Resource
+ private MemberUserApi memberUserApi;
+
+ @GetMapping("/page")
+ @Operation(summary = "获得交易订单分页")
+ @PreAuthorize("@ss.hasPermission('trade:order:query')")
+ public CommonResult> getOrderPage(TradeOrderPageReqVO reqVO) {
+ // 查询订单
+ PageResult pageResult = tradeOrderQueryService.getOrderPage(reqVO);
+ if (CollUtil.isEmpty(pageResult.getList())) {
+ return success(PageResult.empty());
+ }
+
+ // 查询用户信息
+ Set userIds = CollUtil.unionDistinct(convertList(pageResult.getList(), TradeOrderDO::getUserId),
+ convertList(pageResult.getList(), TradeOrderDO::getBrokerageUserId, Objects::nonNull));
+ Map userMap = memberUserApi.getUserMap(userIds);
+ // 查询订单项
+ List orderItems = tradeOrderQueryService.getOrderItemListByOrderId(
+ convertSet(pageResult.getList(), TradeOrderDO::getId));
+ // 最终组合
+ return success(TradeOrderConvert.INSTANCE.convertPage(pageResult, orderItems, userMap));
+ }
+
+ @GetMapping("/summary")
+ @Operation(summary = "获得交易订单统计")
+ @PreAuthorize("@ss.hasPermission('trade:order:query')")
+ public CommonResult getOrderSummary(TradeOrderPageReqVO reqVO) {
+ return success(tradeOrderQueryService.getOrderSummary(reqVO));
+ }
+
+ @GetMapping("/get-detail")
+ @Operation(summary = "获得交易订单详情")
+ @Parameter(name = "id", description = "订单编号", required = true, example = "1")
+ @PreAuthorize("@ss.hasPermission('trade:order:query')")
+ public CommonResult getOrderDetail(@RequestParam("id") Long id) {
+ // 查询订单
+ TradeOrderDO order = tradeOrderQueryService.getOrder(id);
+ if (order == null) {
+ return success(null);
+ }
+ // 查询订单项
+ List orderItems = tradeOrderQueryService.getOrderItemListByOrderId(id);
+
+ // 拼接数据
+ MemberUserRespDTO user = memberUserApi.getUser(order.getUserId()).getCheckedData();
+ MemberUserRespDTO brokerageUser = order.getBrokerageUserId() != null ?
+ memberUserApi.getUser(order.getBrokerageUserId()).getCheckedData() : null;
+ List orderLogs = tradeOrderLogService.getOrderLogListByOrderId(id);
+ return success(TradeOrderConvert.INSTANCE.convert(order, orderItems, orderLogs, user, brokerageUser));
+ }
+
+ @GetMapping("/get-express-track-list")
+ @Operation(summary = "获得交易订单的物流轨迹")
+ @Parameter(name = "id", description = "交易订单编号")
+ @PreAuthorize("@ss.hasPermission('trade:order:query')")
+ public CommonResult> getOrderExpressTrackList(@RequestParam("id") Long id) {
+ return success(TradeOrderConvert.INSTANCE.convertList02(
+ tradeOrderQueryService.getExpressTrackList(id)));
+ }
+
+ @PutMapping("/delivery")
+ @Operation(summary = "订单发货")
+ @PreAuthorize("@ss.hasPermission('trade:order:update')")
+ public CommonResult deliveryOrder(@RequestBody TradeOrderDeliveryReqVO deliveryReqVO) {
+ tradeOrderUpdateService.deliveryOrder(deliveryReqVO);
+ return success(true);
+ }
+
+ @PutMapping("/update-remark")
+ @Operation(summary = "订单备注")
+ @PreAuthorize("@ss.hasPermission('trade:order:update')")
+ public CommonResult updateOrderRemark(@RequestBody TradeOrderRemarkReqVO reqVO) {
+ tradeOrderUpdateService.updateOrderRemark(reqVO);
+ return success(true);
+ }
+
+ @PutMapping("/update-price")
+ @Operation(summary = "订单调价")
+ @PreAuthorize("@ss.hasPermission('trade:order:update')")
+ public CommonResult updateOrderPrice(@RequestBody TradeOrderUpdatePriceReqVO reqVO) {
+ tradeOrderUpdateService.updateOrderPrice(reqVO);
+ return success(true);
+ }
+
+ @PutMapping("/update-address")
+ @Operation(summary = "修改订单收货地址")
+ @PreAuthorize("@ss.hasPermission('trade:order:update')")
+ public CommonResult updateOrderAddress(@RequestBody TradeOrderUpdateAddressReqVO reqVO) {
+ tradeOrderUpdateService.updateOrderAddress(reqVO);
+ return success(true);
+ }
+
+ @PutMapping("/pick-up-by-id")
+ @Operation(summary = "订单核销")
+ @Parameter(name = "id", description = "交易订单编号")
+ @PreAuthorize("@ss.hasPermission('trade:order:pick-up')")
+ public CommonResult