Kaynağa Gözat

完成校内配送费相关业务逻辑

codingliang 9 ay önce
ebeveyn
işleme
60d3aa914b
22 değiştirilmiş dosya ile 790 ekleme ve 49 silme
  1. 14 0
      db/update_250913.sql
  2. 63 0
      src/main/java/com/sqx/modules/address/controller/AdminInsideAddressController.java
  3. 12 7
      src/main/java/com/sqx/modules/address/controller/app/AddressController.java
  4. 30 0
      src/main/java/com/sqx/modules/address/controller/app/InsideAddressController.java
  5. 21 0
      src/main/java/com/sqx/modules/address/dao/InsideAddressDao.java
  6. 37 0
      src/main/java/com/sqx/modules/address/dto/AddressAddDTO.java
  7. 68 0
      src/main/java/com/sqx/modules/address/dto/InsideAddressDTO.java
  8. 23 10
      src/main/java/com/sqx/modules/address/entity/Address.java
  9. 69 0
      src/main/java/com/sqx/modules/address/entity/InsideAddress.java
  10. 34 0
      src/main/java/com/sqx/modules/address/query/InsideAddressQuery.java
  11. 57 0
      src/main/java/com/sqx/modules/address/service/InsideAddressService.java
  12. 65 5
      src/main/java/com/sqx/modules/address/service/impl/AddressServiceImpl.java
  13. 103 0
      src/main/java/com/sqx/modules/address/service/impl/InsideAddressServiceImpl.java
  14. 8 0
      src/main/java/com/sqx/modules/address/validator/FullAddressGroup.java
  15. 8 0
      src/main/java/com/sqx/modules/address/validator/InsideAddressGroup.java
  16. 34 0
      src/main/java/com/sqx/modules/address/vo/InsideAddressShortVO.java
  17. 61 0
      src/main/java/com/sqx/modules/address/vo/InsideAddressVO.java
  18. 3 0
      src/main/java/com/sqx/modules/errand/entity/TbIndent.java
  19. 8 1
      src/main/java/com/sqx/modules/errand/service/impl/TbIndentServiceImpl.java
  20. 3 18
      src/main/java/com/sqx/modules/order/entity/TbOrder.java
  21. 24 8
      src/main/java/com/sqx/modules/order/service/impl/AppAppOrderServiceImpl.java
  22. 45 0
      src/main/resources/mapper/address/InsideAddressDao.xml

+ 14 - 0
db/update_250913.sql

@@ -0,0 +1,14 @@
+-- address 新增内部地址id
+alter table address add inside_address_id bigint comment '内部地址id' after lat;
+
+-- 新增系统配置 是否开启校内地址 1是,0否
+INSERT INTO common_info (id, create_at, max, min, type, value, condition_from) VALUES (442, '2025-09-14 11:34:00', null, '是否开启校内地址', 442, '1', 'xitong');
+
+-- 修改表:tb_indent[跑腿订单]
+-- 添加字段:
+ALTER TABLE tb_indent ADD COLUMN `inside_delivery_fee` DECIMAL(24,6) NOT NULL DEFAULT 0 COMMENT '校内跑腿费;' AFTER indent_money;
+/* --------------- 修改表 --------------- */
+-- 修改表:tb_order[订单主表]
+-- 添加字段:
+ALTER TABLE tb_order ADD COLUMN `inside_delivery_fee` DECIMAL(24,6) NOT NULL DEFAULT 0 COMMENT '校内配送费;' AFTER errand_money;
+

+ 63 - 0
src/main/java/com/sqx/modules/address/controller/AdminInsideAddressController.java

@@ -0,0 +1,63 @@
+package com.sqx.modules.address.controller;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.sqx.common.exception.SqxException;
+import com.sqx.common.utils.PageUtils;
+import com.sqx.common.utils.Result;
+import com.sqx.modules.address.dto.InsideAddressDTO;
+import com.sqx.modules.address.query.InsideAddressQuery;
+import com.sqx.modules.address.service.InsideAddressService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.validation.Valid;
+import java.util.List;
+
+
+@RestController
+@Api(value = "管理端-内部地址", tags = {"管理端-内部地址"})
+@RequestMapping(value = "admin/inside-address")
+@RequiredArgsConstructor
+public class AdminInsideAddressController {
+
+    private final InsideAddressService insideAddressService;
+
+    @GetMapping("pages")
+    @ApiModelProperty(name = "分页查询内部地址列表")
+    public Result pages(@Valid InsideAddressQuery query) {
+        PageUtils pageUtils = insideAddressService.pages(query);
+        return Result.success().put("data", pageUtils);
+    }
+
+    @PostMapping
+    @ApiModelProperty(name = "新增内部地址")
+    public Result add(@Valid InsideAddressDTO insideAddressDTO) {
+        insideAddressService.addInsideAddress(insideAddressDTO);
+        return Result.success();
+    }
+
+    @PutMapping
+    @ApiModelProperty(name = "更新内部地址")
+    public Result update(@Valid InsideAddressDTO insideAddressDTO) {
+        if (ObjectUtil.isNull(insideAddressDTO.getId())) {
+            throw new SqxException("id不能为空");
+        }
+        insideAddressService.updateInsideAddress(insideAddressDTO);
+        return Result.success();
+    }
+
+    @DeleteMapping
+    @ApiModelProperty(name = "删除内部地址")
+    public Result delete(@RequestBody List<Long> ids) {
+        insideAddressService.deleteByIds(ids);
+        return Result.success();
+    }
+}

+ 12 - 7
src/main/java/com/sqx/modules/address/controller/app/AddressController.java

@@ -2,6 +2,7 @@ package com.sqx.modules.address.controller.app;
 
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.sqx.common.exception.SqxException;
 import com.sqx.common.utils.Result;
 import com.sqx.modules.address.entity.Address;
 import com.sqx.modules.address.service.AddressService;
@@ -13,7 +14,12 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestAttribute;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 import java.util.HashMap;
 import java.util.Map;
@@ -21,7 +27,6 @@ import java.util.Map;
 @RestController
 @Api(value = "用户端-地址", tags = {"用户端-地址"})
 @RequestMapping(value = "/app/address")
-@Slf4j
 public class AddressController {
 
     @Autowired
@@ -93,10 +98,9 @@ public class AddressController {
                 JSONObject result = jsonObject.getJSONObject("result");
                 JSONObject adInfo = result.getJSONObject("ad_info");
                 return Result.success().put("data", adInfo);
-            } else {
-                log.error("转换失败!!!原因:" + jsonObject.getString("message"));
             }
-            return Result.error("获取定位失败!");
+
+            throw new SqxException(jsonObject.getString("message"));
         }else{
             String value = commonInfoService.findOne(417).getValue();
             String url="http://api.tianditu.gov.cn/geocoder";
@@ -123,8 +127,9 @@ public class AddressController {
                 jsonObject1.put("district",county);
                 return Result.success().put("data", jsonObject1);
             }
-            return Result.error("获取定位失败!");
+
+            throw new SqxException("获取定位失败!");
         }
     }
 
-}
+}

+ 30 - 0
src/main/java/com/sqx/modules/address/controller/app/InsideAddressController.java

@@ -0,0 +1,30 @@
+package com.sqx.modules.address.controller.app;
+
+import com.sqx.common.utils.Result;
+import com.sqx.modules.address.service.InsideAddressService;
+import com.sqx.modules.address.vo.InsideAddressShortVO;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+@Api(value = "用户端-内部地址", tags = {"用户端-内部地址"})
+@RequestMapping(value = "app/inside-address")
+@RequiredArgsConstructor
+public class InsideAddressController {
+
+    private final InsideAddressService insideAddressService;
+
+    @ApiModelProperty(name = "根据站点id查询内部地址列表")
+    @GetMapping("list/{stationId}")
+    public Result listByStationId(@PathVariable("stationId") Long stationId) {
+        List<InsideAddressShortVO> list = insideAddressService.listByStationId(stationId);
+        return Result.success().put("data", list);
+    }
+}

+ 21 - 0
src/main/java/com/sqx/modules/address/dao/InsideAddressDao.java

@@ -0,0 +1,21 @@
+package com.sqx.modules.address.dao;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.sqx.modules.address.entity.InsideAddress;
+import com.sqx.modules.address.query.InsideAddressQuery;
+import com.sqx.modules.address.vo.InsideAddressVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * 内部地址 dao
+ * @author codingliang
+ * @date 2025-09-13
+ */
+@Mapper
+public interface InsideAddressDao extends BaseMapper<InsideAddress> {
+
+    IPage<InsideAddressVO> selectPages(@Param("page") Page<InsideAddress> page, @Param("query") InsideAddressQuery query);
+}

+ 37 - 0
src/main/java/com/sqx/modules/address/dto/AddressAddDTO.java

@@ -0,0 +1,37 @@
+package com.sqx.modules.address.dto;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+
+/**
+ * 用户根据内部地址新增地址DTO
+ * @author codingliang
+ * @date 2025-09-13
+ */
+@Data
+public class AddressAddDTO {
+
+    @ApiModelProperty(value = "用户名称")
+    @NotBlank(message = "用户名称不能为空")
+    private String userName;
+
+    @ApiModelProperty(value = "手机号")
+    @NotBlank(message = "手机号不能为空")
+    private String phone;
+
+    @ApiModelProperty(value = "内部地址id")
+    @NotNull(message = "内部地址id不能为空")
+    private Long insideAddressId;
+
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+    @ApiModelProperty("默认地址 0:非默认  1:默认")
+    @NotNull(message = "默认地址不能为空")
+    @Pattern(regexp = "0|1", message = "默认地址格式错误")
+    private Integer addressDefault;
+}

+ 68 - 0
src/main/java/com/sqx/modules/address/dto/InsideAddressDTO.java

@@ -0,0 +1,68 @@
+package com.sqx.modules.address.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 内部地址
+ * @author codingliang
+ * @date 2025-09-13
+ */
+@Data
+@ApiModel(value = "内部地址")
+public class InsideAddressDTO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(name = "id,修改时不能为空")
+    private Long id;
+
+    @ApiModelProperty(name = "站点id")
+    @NotNull(message = "站点id不能为空")
+    private Long stationId;
+
+    @ApiModelProperty(name = "配送费用")
+    @NotNull(message = "配送费用不能为空")
+    @Min(value = 0, message = "配送费用不能小于0")
+    private Double deliveryFee;
+
+    @ApiModelProperty(name = "省份")
+    @NotBlank(message = "省份不能为空")
+    private String province;
+
+    @ApiModelProperty(name = "城市")
+    @NotBlank(message = "城市不能为空")
+    private String city;
+
+    @ApiModelProperty(name = "区县")
+    @NotBlank(message = "区县不能为空")
+    private String district;
+
+    @ApiModelProperty(name = "地址详情")
+    @NotBlank(message = "地址详情不能为空")
+    private String addressDetail;
+
+    @ApiModelProperty(name = "经度")
+    @NotNull(message = "经度不能为空")
+    private Double lng;
+
+    @ApiModelProperty(name = "维度")
+    @NotNull(message = "维度不能为空")
+    private Double lat;
+
+    @ApiModelProperty(name = "启用状态;1启用、0禁用")
+    @NotBlank(message = "启用状态不能为空")
+    @Pattern(regexp = "0|1", message = "启用状态只能为0或1")
+    private String status;
+
+    @ApiModelProperty(name = "排序")
+    @NotNull(message = "排序不能为空")
+    private Integer sort;
+}

+ 23 - 10
src/main/java/com/sqx/modules/address/entity/Address.java

@@ -1,11 +1,18 @@
 package com.sqx.modules.address.entity;
 
 import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
+import com.sqx.modules.address.validator.FullAddressGroup;
+import com.sqx.modules.address.validator.InsideAddressGroup;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
 
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
 import java.io.Serializable;
+import java.math.BigDecimal;
 
 @Data
 public class Address implements Serializable {
@@ -13,57 +20,63 @@ public class Address implements Serializable {
     private static final long serialVersionUID = 1L;
 
     @TableId(type = IdType.AUTO)
-
     @ApiModelProperty("主键id")
     private Long addressId;
 
-
     @ApiModelProperty("用户id")
     private Long userId;
 
-
     @ApiModelProperty("用户姓名")
+    @NotBlank(message = "用户姓名不能为空", groups = {FullAddressGroup.class, InsideAddressGroup.class})
     private String userName;
 
-
     @ApiModelProperty("用户电话")
+    @NotBlank(message = "用户电话不能为空", groups = {FullAddressGroup.class, InsideAddressGroup.class})
     private String userPhone;
 
-
     @ApiModelProperty("用户地址")
+    @NotBlank(message = "省份不能为空", groups = {FullAddressGroup.class})
     private String province;
 
     @ApiModelProperty("用户地址")
+    @NotBlank(message = "城市不能为空", groups = {FullAddressGroup.class})
     private String city;
 
     @ApiModelProperty("用户地址")
+    @NotBlank(message = "区县不能为空", groups = {FullAddressGroup.class})
     private String district;
 
-
     @ApiModelProperty("用户详细地址(用户手动输入的地址)")
+    @NotBlank(message = "详细地址不能为空", groups = {FullAddressGroup.class})
     private String addressDetail;
 
     @ApiModelProperty("经度")
+    @NotNull(message = "经度不能为空", groups = {FullAddressGroup.class})
     private Double lng;
 
     @ApiModelProperty("维度")
+    @NotNull(message = "纬度不能为空", groups = {FullAddressGroup.class})
     private Double lat;
 
+    @ApiModelProperty("内部地址id,当用户选择使用内部地址时,该字段不能为空")
+    @NotNull(message = "内部地址id不能为空", groups = {InsideAddressGroup.class})
+    private Long insideAddressId;
 
     @ApiModelProperty("创建时间")
     private String createTime;
 
-
     @ApiModelProperty("是否删除(0:未删除;1:删除)")
     private Integer deleteFlag;
 
-
     @ApiModelProperty("默认地址 0:非默认  1:默认")
+    @NotNull(message = "默认地址不能为空", groups = {FullAddressGroup.class, InsideAddressGroup.class})
+    @Pattern(regexp = "0|1", message = "默认地址只能为0或1")
     private Integer addressDefault;
 
-
     @ApiModelProperty("修改时间")
     private String updateTime;
 
-    public Address() {}
+    @ApiModelProperty("校内地址配送费")
+    @TableField(exist = false)
+    private BigDecimal insideDeliveryFee;
 }

+ 69 - 0
src/main/java/com/sqx/modules/address/entity/InsideAddress.java

@@ -0,0 +1,69 @@
+package com.sqx.modules.address.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * 内部地址
+ * @author codingliang
+ * @date 2025-09-13
+ */
+@Data
+@ApiModel(value = "内部地址")
+@TableName("inside_address")
+public class InsideAddress implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(name = "id")
+    @TableId(type = IdType.AUTO)
+    private Long id;
+
+    @ApiModelProperty(name = "删除标识;0未删除、1已删除")
+    @TableLogic(value = "0", delval = "1")
+    private String delFlag;
+
+    @ApiModelProperty(name = "创建时间")
+    private Date createTime;
+
+    @ApiModelProperty(name = "更新时间")
+    private Date updateTime;
+
+    @ApiModelProperty(name = "站点id")
+    private Long stationId;
+
+    @ApiModelProperty(name = "配送费用")
+    private BigDecimal deliveryFee;
+
+    @ApiModelProperty(name = "省份")
+    private String province;
+
+    @ApiModelProperty(name = "城市")
+    private String city;
+
+    @ApiModelProperty(name = "区县")
+    private String district;
+
+    @ApiModelProperty(name = "地址详情")
+    private String addressDetail;
+
+    @ApiModelProperty(name = "经度")
+    private Double lng;
+
+    @ApiModelProperty(name = "维度")
+    private Double lat;
+
+    @ApiModelProperty(name = "启用状态;1启用、0禁用")
+    private String status;
+
+    @ApiModelProperty(name = "排序")
+    private Integer sort;
+}

+ 34 - 0
src/main/java/com/sqx/modules/address/query/InsideAddressQuery.java

@@ -0,0 +1,34 @@
+package com.sqx.modules.address.query;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.sqx.common.query.PageQuery;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * 内部地址查询
+ * @author codingliang
+ * @date 2025-09-13
+ */
+@Data
+public class InsideAddressQuery extends PageQuery {
+
+    @ApiModelProperty("地址详情")
+    private String addressDetail;
+
+    @ApiModelProperty("状态")
+    private String status;
+
+    @ApiModelProperty("站点id")
+    private Long stationId;
+
+    @ApiModelProperty("查询开始时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date startTime;
+
+    @ApiModelProperty("查询结束时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date endTime;
+}

+ 57 - 0
src/main/java/com/sqx/modules/address/service/InsideAddressService.java

@@ -0,0 +1,57 @@
+package com.sqx.modules.address.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.sqx.common.utils.PageUtils;
+import com.sqx.modules.address.dto.AddressAddDTO;
+import com.sqx.modules.address.dto.InsideAddressDTO;
+import com.sqx.modules.address.entity.InsideAddress;
+import com.sqx.modules.address.query.InsideAddressQuery;
+import com.sqx.modules.address.vo.InsideAddressShortVO;
+
+import java.util.List;
+
+/**
+ * @author codingliang
+ * @date 2025-09-13
+ */
+public interface InsideAddressService extends IService<InsideAddress> {
+
+    /**
+     * 分页查询
+     * @param query 分页查询参数
+     * @return 分页数据
+     */
+    PageUtils pages(InsideAddressQuery query);
+
+    /**
+     * 新增内部地址
+     * @param insideAddressDTO 内部地址
+     */
+    void addInsideAddress(InsideAddressDTO insideAddressDTO);
+
+    /**
+     * 更新内部地址
+     * @param insideAddressDTO 内部地址
+     */
+    void updateInsideAddress(InsideAddressDTO insideAddressDTO);
+
+    /**
+     * 删除内部地址
+     * @param ids 内部地址id列表
+     */
+    void deleteByIds(List<Long> ids);
+
+    /**
+     * 根据站点id查询内部地址列表 (精简信息)
+     * @param stationId 站点id
+     * @return 内部地址列表(精简信息)
+     */
+    List<InsideAddressShortVO> listByStationId(Long stationId);
+
+    /**
+     * 从内部地址添加地址
+     * @param userId 用户id
+     * @param insideAddressDTO 内部地址
+     */
+    void addAddressFromInsideAddress(Long userId, AddressAddDTO insideAddressDTO);
+}

+ 65 - 5
src/main/java/com/sqx/modules/address/service/impl/AddressServiceImpl.java

@@ -1,14 +1,25 @@
 package com.sqx.modules.address.service.impl;
 
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sqx.common.exception.SqxException;
+import com.sqx.common.utils.Constant;
 import com.sqx.common.utils.PageUtils;
 import com.sqx.common.utils.Result;
+import com.sqx.common.validator.ValidatorUtils;
 import com.sqx.modules.address.dao.AddressDao;
 import com.sqx.modules.address.entity.Address;
+import com.sqx.modules.address.entity.InsideAddress;
 import com.sqx.modules.address.service.AddressService;
-import org.springframework.beans.factory.annotation.Autowired;
+import com.sqx.modules.address.service.InsideAddressService;
+import com.sqx.modules.address.validator.FullAddressGroup;
+import com.sqx.modules.address.validator.InsideAddressGroup;
+import com.sqx.modules.common.entity.CommonInfo;
+import com.sqx.modules.common.service.CommonInfoService;
+import lombok.RequiredArgsConstructor;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
@@ -16,26 +27,31 @@ import java.text.SimpleDateFormat;
 import java.util.Date;
 
 @Service
+@RequiredArgsConstructor
 public class AddressServiceImpl extends ServiceImpl<AddressDao, Address> implements AddressService {
 
-    @Autowired
-    private AddressDao addressDao;
+    private final InsideAddressService insideAddressService;
+    private final CommonInfoService commonInfoService;
 
     @Override
     public Result selectAddressList(Long userId, Integer page, Integer limit) {
         Page<Address> pages=new Page<>(page,limit);
-        PageUtils pageUtils = new PageUtils(addressDao.selectAddressList(pages, userId));
+        PageUtils pageUtils = new PageUtils(baseMapper.selectAddressList(pages, userId));
         return Result.success().put("data", pageUtils);
     }
 
     @Transactional
     @Override
     public Result insertAddress(Address address) {
+        // 校验地址参数
+        validateAddress(address);
+
         String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
         address.setCreateTime(format);
         address.setUpdateTime(format);
         address.setDeleteFlag(0);
-        //如果该条地址不是默认地址,则直接添加
+
+        // 如果该条地址不是默认地址,则直接添加
         if(address.getAddressDefault()==0){
             baseMapper.insert(address);
             return Result.success();
@@ -54,6 +70,9 @@ public class AddressServiceImpl extends ServiceImpl<AddressDao, Address> impleme
     @Transactional
     @Override
     public Result updateAddress(Address address) {
+        // 校验地址参数
+        validateAddress(address);
+
         String format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date());
         address.setUpdateTime(format);
         //如果该条地址不是默认地址,则直接修改
@@ -73,6 +92,16 @@ public class AddressServiceImpl extends ServiceImpl<AddressDao, Address> impleme
     @Override
     public Result selectAddressById(Long addressId) {
         Address address = baseMapper.selectById(addressId);
+
+        if(ObjectUtil.isNull(address)){
+            throw new SqxException("地址不存在");
+        }
+
+        if (ObjectUtil.isNotNull(address.getInsideAddressId())) {
+            InsideAddress insideAddress = insideAddressService.getById(address.getInsideAddressId());
+            address.setInsideDeliveryFee(insideAddress.getDeliveryFee());
+        }
+
         return Result.success().put("data", address);
     }
 
@@ -84,11 +113,42 @@ public class AddressServiceImpl extends ServiceImpl<AddressDao, Address> impleme
 
     @Override
     public Result searchAddress(Long userId, Integer page, Integer limit, String impotr) {
+        CommonInfo insideAddressSe = commonInfoService.findOne(442);
+
         Page<Address> pages = new Page<>(page, limit);
         PageUtils pageUtils = new PageUtils(baseMapper.selectPage(pages, new QueryWrapper<Address>()
                 .like("address_detail", impotr)
                 .eq("user_id", userId)
+                // 开启校内地址,则只查询校内的地址
+                .isNotNull(
+                    ObjectUtil.isNotNull(insideAddressSe) && StrUtil.equals(Constant.YES, insideAddressSe.getValue()),
+                    "inside_address_id"
+                )
                 .orderByDesc("create_time")));
         return Result.success().put("data", pageUtils);
     }
+
+    /**
+     * 校验地址参数
+     * @param address 地址参数
+     */
+    private void validateAddress(Address address) {
+        if (ObjectUtil.isNull(address.getInsideAddressId())) {
+            ValidatorUtils.validateEntity(address, InsideAddressGroup.class);
+
+            InsideAddress insideAddress = insideAddressService.getById(address.getInsideAddressId());
+            if (ObjectUtil.isNull(insideAddress)) {
+                throw new SqxException("无效的内部地址id");
+            }
+
+            address.setProvince(insideAddress.getProvince());
+            address.setCity(insideAddress.getCity());
+            address.setDistrict(insideAddress.getDistrict());
+            address.setAddressDetail(insideAddress.getAddressDetail());
+            address.setLng(insideAddress.getLng());
+            address.setLat(insideAddress.getLat());
+        } else {
+            ValidatorUtils.validateEntity(address, FullAddressGroup.class);
+        }
+    }
 }

+ 103 - 0
src/main/java/com/sqx/modules/address/service/impl/InsideAddressServiceImpl.java

@@ -0,0 +1,103 @@
+package com.sqx.modules.address.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.sqx.common.exception.SqxException;
+import com.sqx.common.utils.Constant;
+import com.sqx.common.utils.PageUtils;
+import com.sqx.modules.address.dao.InsideAddressDao;
+import com.sqx.modules.address.dto.AddressAddDTO;
+import com.sqx.modules.address.dto.InsideAddressDTO;
+import com.sqx.modules.address.entity.InsideAddress;
+import com.sqx.modules.address.query.InsideAddressQuery;
+import com.sqx.modules.address.service.InsideAddressService;
+import com.sqx.modules.address.vo.InsideAddressShortVO;
+import com.sqx.modules.address.vo.InsideAddressVO;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author codingliang
+ * @date 2025-09-13
+ */
+@Service
+public class InsideAddressServiceImpl extends ServiceImpl<InsideAddressDao, InsideAddress> implements InsideAddressService {
+
+    @Override
+    public PageUtils pages(InsideAddressQuery query) {
+        Page<InsideAddress> page = new Page<>(query.getPage(), query.getLimit());
+        IPage<InsideAddressVO> data = baseMapper.selectPages(page, query);
+        return new PageUtils(data);
+    }
+
+    @Override
+    public void addInsideAddress(InsideAddressDTO insideAddressDTO) {
+        // 地址详情不能重复
+        checkAddressUnique(insideAddressDTO);
+
+        // 新增内部地址
+        InsideAddress insideAddress = new InsideAddress();
+        BeanUtil.copyProperties(insideAddressDTO, insideAddress);
+        insideAddress.setDelFlag(Constant.NO);
+        insideAddress.setCreateTime(new Date());
+        insideAddress.setUpdateTime(new Date());
+        baseMapper.insert(insideAddress);
+    }
+
+    @Override
+    public void updateInsideAddress(InsideAddressDTO insideAddressDTO) {
+        // 地址详情不能重复
+        checkAddressUnique(insideAddressDTO);
+
+        // 更新内部地址
+        InsideAddress insideAddress = new InsideAddress();
+        BeanUtil.copyProperties(insideAddressDTO, insideAddress);
+        insideAddress.setUpdateTime(new Date());
+        baseMapper.updateById(insideAddress);
+    }
+
+    @Override
+    @Transactional
+    public void deleteByIds(List<Long> ids) {
+        removeByIds(ids);
+    }
+
+    @Override
+    public List<InsideAddressShortVO> listByStationId(Long stationId) {
+        List<InsideAddress> list = baseMapper.selectList(new LambdaQueryWrapper<InsideAddress>()
+                .eq(InsideAddress::getStationId, stationId)
+                .eq(InsideAddress::getStatus, Constant.YES)
+                .orderByAsc(InsideAddress::getSort));
+
+        List<InsideAddressShortVO> vos = list.stream().map(item -> {
+            InsideAddressShortVO vo = new InsideAddressShortVO();
+            BeanUtil.copyProperties(item, vo);
+            return vo;
+        }).collect(Collectors.toList());
+
+        return vos;
+    }
+
+    @Override
+    public void addAddressFromInsideAddress(Long userId, AddressAddDTO insideAddressDTO) {
+
+    }
+
+    private void checkAddressUnique(InsideAddressDTO insideAddressDTO) {
+        long count = baseMapper.selectCount(new LambdaQueryWrapper<InsideAddress>()
+                .eq(InsideAddress::getAddressDetail, insideAddressDTO.getAddressDetail())
+                .ne(ObjectUtil.isNotNull(insideAddressDTO.getId()), InsideAddress::getId, insideAddressDTO.getId()));
+        if (count > 0) {
+            throw new SqxException("地址详情不能重复");
+        }
+    }
+}

+ 8 - 0
src/main/java/com/sqx/modules/address/validator/FullAddressGroup.java

@@ -0,0 +1,8 @@
+package com.sqx.modules.address.validator;
+
+/**
+ * 完整地址校验组
+ * 包含:userName、userPhone、province、city、district、addressDetail、lng、lat、addressDefault
+ */
+public interface FullAddressGroup {
+}

+ 8 - 0
src/main/java/com/sqx/modules/address/validator/InsideAddressGroup.java

@@ -0,0 +1,8 @@
+package com.sqx.modules.address.validator;
+
+/**
+ * 内部地址校验组
+ * 包含:userName、userPhone、insideAddressId、addressDefault
+ */
+public interface InsideAddressGroup {
+}

+ 34 - 0
src/main/java/com/sqx/modules/address/vo/InsideAddressShortVO.java

@@ -0,0 +1,34 @@
+package com.sqx.modules.address.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 内部地址
+ * @author codingliang
+ * @date 2025-09-13
+ */
+@Data
+@ApiModel(value = "内部地址")
+public class InsideAddressShortVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(name = "id")
+    private Long id;
+
+    @ApiModelProperty(name = "站点id")
+    private Long stationId;
+
+    @ApiModelProperty(name = "配送费用")
+    private Double deliveryFee;
+
+    @ApiModelProperty(name = "地址详情")
+    private String addressDetail;
+
+    @ApiModelProperty(name = "排序")
+    private Integer sort;
+}

+ 61 - 0
src/main/java/com/sqx/modules/address/vo/InsideAddressVO.java

@@ -0,0 +1,61 @@
+package com.sqx.modules.address.vo;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 内部地址
+ * @author codingliang
+ * @date 2025-09-13
+ */
+@Data
+@ApiModel(value = "内部地址")
+public class InsideAddressVO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    @ApiModelProperty(name = "id")
+    private Long id;
+
+    @ApiModelProperty(name = "创建时间")
+    private Date createTime;
+
+    @ApiModelProperty(name = "更新时间")
+    private Date updateTime;
+
+    @ApiModelProperty(name = "站点id")
+    private Long stationId;
+
+    @ApiModelProperty(name = "站点名称")
+    private String stationName;
+
+    @ApiModelProperty(name = "配送费用")
+    private Double deliveryFee;
+
+    @ApiModelProperty(name = "省份")
+    private String province;
+
+    @ApiModelProperty(name = "城市")
+    private String city;
+
+    @ApiModelProperty(name = "区县")
+    private String district;
+
+    @ApiModelProperty(name = "地址详情")
+    private String addressDetail;
+
+    @ApiModelProperty(name = "经度")
+    private Double lng;
+
+    @ApiModelProperty(name = "维度")
+    private Double lat;
+
+    @ApiModelProperty(name = "启用状态;1启用、0禁用")
+    private String status;
+
+    @ApiModelProperty(name = "排序")
+    private Integer sort;
+}

+ 3 - 0
src/main/java/com/sqx/modules/errand/entity/TbIndent.java

@@ -108,6 +108,9 @@ public class TbIndent implements Serializable {
     @ApiModelProperty("跑腿费")
     private BigDecimal errandMoney;
 
+    @ApiModelProperty("校内跑腿费")
+    private BigDecimal insideDeliveryFee;
+
     @ApiModelProperty("商品详情")
     private String productDetails;
 

+ 8 - 1
src/main/java/com/sqx/modules/errand/service/impl/TbIndentServiceImpl.java

@@ -329,9 +329,16 @@ public class TbIndentServiceImpl extends ServiceImpl<TbIndentDao, TbIndent> impl
             //骑手最终可得金额
             errandMoney = errandMoney.subtract(platformMoney);
         }
+
+        // 校内跑腿费
+        tbIndent.setInsideDeliveryFee(order.getInsideDeliveryFee());
         tbIndent.setErrandMoney(errandMoney);
-        tbIndent.setRiderMoney(errandMoney);
+
+        // 骑手收入 = 跑腿费 + 校内跑腿费
+        tbIndent.setRiderMoney(errandMoney.add(tbIndent.getInsideDeliveryFee()));
+
         tbIndent.setPlatformMoney(platformMoney);
+
         // 配送订单,直接改为2
         if (goodsShop.getAutoSendOrder() == 0) {
             tbIndent.setIndentState("2");

+ 3 - 18
src/main/java/com/sqx/modules/order/entity/TbOrder.java

@@ -23,88 +23,73 @@ public class TbOrder implements Serializable {
     @ApiModelProperty("order_id")
     private Long orderId;
 
-
     @ApiModelProperty("优惠券id")
     @TableField(value = "coupon_id")
     private Long couponId;
 
-
     @ApiModelProperty("用户id")
     private Long userId;
 
-
     @ApiModelProperty("用户名")
     private String userName;
 
-
     @ApiModelProperty("手机号")
     private String phone;
 
-
     @ApiModelProperty("地址id")
     private Long addressId;
 
-
     @ApiModelProperty("地址信息")
     private String address;
 
-
     @ApiModelProperty("订单号")
     private String orderNumber;
 
-
     @ApiModelProperty("是否支付 0未支付 1已支付")
     private Integer isPay;
 
-
     @ApiModelProperty("下单时间")
     private String createTime;
 
     @ApiModelProperty("最后一次修改订单状态时间")
     private String updateTime;
 
-
     @ApiModelProperty("支付时间")
     private String payTime;
 
-
     @ApiModelProperty("支付方式  1微信支付  2余额支付  3支付宝支付")
     private Integer payType;
 
-
     @ApiModelProperty("取餐号码")
     private String orderCode;
 
-
     @ApiModelProperty("订单类型 1上门 2外卖")
     private Integer orderType;
 
     @ApiModelProperty("订单类型拓展 1上门 2骑手配送 3商家配送")
     private Integer orderTypeExtra;
 
-
     @ApiModelProperty("订单父id")
     private Long parentId;
 
-
     @ApiModelProperty("打包费")
     private BigDecimal packMoney;
 
-
     @ApiModelProperty("跑腿费")
     private BigDecimal errandMoney;
 
     @ApiModelProperty("跑腿费达到商家满减要求 商家承担配送费")
     private String errandMoneyIsShop;
 
+    @ApiModelProperty("内部配送费")
+    private BigDecimal insideDeliveryFee;
+
     @ApiModelProperty("订单状态 0待结算 1待支付 2直接购买(未支付) 7商家待接单 8商家拒绝接单 6制作中  3待取餐/派送中 4已完成 5已取消 13外卖待接单")
     private Integer status;
 
-
     @ApiModelProperty("是否开启自动派单 0开启 1关闭")
     private Integer autoSendOrder;
 
-
     @ApiModelProperty("是否删除该订单 0未删除 1删除")
     private Integer deleteFlag;
 

+ 24 - 8
src/main/java/com/sqx/modules/order/service/impl/AppAppOrderServiceImpl.java

@@ -35,7 +35,9 @@ import com.sqx.modules.activity.service.ActivityPartRecordService;
 import com.sqx.modules.activity.service.ActivityService;
 import com.sqx.modules.activity.vo.OrderSuitActivityVO;
 import com.sqx.modules.address.entity.Address;
+import com.sqx.modules.address.entity.InsideAddress;
 import com.sqx.modules.address.service.AddressService;
+import com.sqx.modules.address.service.InsideAddressService;
 import com.sqx.modules.app.dao.UserBrowseDao;
 import com.sqx.modules.app.dao.UserDao;
 import com.sqx.modules.app.dao.UserMoneyDao;
@@ -51,7 +53,6 @@ import com.sqx.modules.common.service.CommonInfoService;
 import com.sqx.modules.coupon.dao.TbCouponUserDao;
 import com.sqx.modules.coupon.entity.TbCouponUser;
 import com.sqx.modules.datacentre.entity.SysUserShop;
-import com.sqx.modules.errand.dao.TbIndentDao;
 import com.sqx.modules.errand.entity.TbIndent;
 import com.sqx.modules.errand.entity.TbIndentSmsSendLog;
 import com.sqx.modules.errand.service.TbIndentService;
@@ -184,8 +185,6 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
     @Autowired
     private UserMoneyService userMoneyService;
     @Autowired
-    private TbIndentDao tbIndentDao;
-    @Autowired
     private UserBrowseDao userBrowseDao;
     @Autowired
     private PayDetailsDao payDetailsDao;
@@ -214,16 +213,16 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
     private UserIntegralDao userIntegralDao;
     @Autowired
     private UserIntegralDetailsDao userIntegralDetailsDao;
-
     @Autowired
     private EvaluateRiderService evaluateRiderService;
     @Autowired
     private ShopTypeService shopTypeService;
-
     @Autowired
     private GoodsShopService goodsShopService;
 
     @Resource
+    private InsideAddressService insideAddressService;
+    @Resource
     private RedissonClient redissonClient;
 
     private final static String RHT_PAY_BASE_URL = "https://api.ekbuyclub.com";
@@ -1018,7 +1017,7 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
     }
 
     /**
-     * 计算店铺收益 店铺订单收益=订单应付金额+订单使用的优惠券金额-跑腿费用
+     * 计算店铺收益 店铺订单收益=订单应付金额+订单使用的优惠券金额-跑腿费用-校内配送费用
      *
      * @param order     订单信息
      * @param goodsShop 店铺信息
@@ -1032,6 +1031,8 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
             sumMoney = sumMoney.subtract(goodsShop.getErrandMoney());
         }
 
+        sumMoney = sumMoney.subtract(order.getInsideDeliveryFee());
+
         BigDecimal shopMoney = sumMoney.multiply(shopRate);
         order.setShopIncomeMoney(shopMoney.setScale(2, BigDecimal.ROUND_DOWN));
 
@@ -1108,6 +1109,12 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
                 throw new SqxException("超出商家配送范围,无法点餐!");
             }
 
+            Long insideAddressId = address.getInsideAddressId();
+            if (ObjectUtil.isNotNull(insideAddressId)) {
+                InsideAddress insideAddress = insideAddressService.getById(insideAddressId);
+                order.setInsideDeliveryFee(insideAddress.getDeliveryFee());
+            }
+
             // 店铺是否开启配送费满减 0是 1否
             Integer enableFullReductionFlag = goodsShop.getEnableFullReductionFlag() != null ? goodsShop.getEnableFullReductionFlag() : 1;
             // 店铺跑腿费
@@ -1141,6 +1148,9 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
 
             order.setErrandMoney(shopErrandMoney);
 
+            // 支付金额加入内部配送费
+            order.setPayMoney(order.getPayMoney().add(order.getInsideDeliveryFee()));
+
             // 判断订单金额是否大于最低起送金额
             if (goodsShop.getMinimumDelivery() == null) {
                 goodsShop.setMinimumDelivery(BigDecimal.valueOf(0));
@@ -1165,8 +1175,7 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
             order.setErrandMoney(BigDecimal.ZERO);
         }
 
-        log.info("preOrder==>[{}],订单跑腿费计算结束,跑腿费[{}],当前订单应付总价[{}]",
-                order.getOrderId(), order.getErrandMoney(), order.getPayMoney());
+        log.info("preOrder==>[{}],订单跑腿费计算结束,跑腿费[{}],校内配送费[{}],当前订单应付总价[{}]", order.getOrderId(), order.getErrandMoney(), order.getInsideDeliveryFee(), order.getPayMoney());
     }
 
     /**
@@ -1775,6 +1784,9 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
                 sumMoney = sumMoney.subtract(goodsShop.getErrandMoney());
             }
 
+            // 再减去校内配送费
+            sumMoney = sumMoney.subtract(tbOrder.getInsideDeliveryFee());
+
             BigDecimal shopMoney = sumMoney.multiply(shopRate);
             shopMoney = (shopMoney.setScale(2, BigDecimal.ROUND_DOWN));
             tbOrder.setShopIncomeMoney(shopMoney);
@@ -2086,6 +2098,9 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
             }
         }
 
+        // 再减去校内配送费
+        sumMoney = sumMoney.subtract(tbOrder.getInsideDeliveryFee());
+
         // 店铺收入
         BigDecimal shopMoney = sumMoney.multiply(shopRate);
         shopMoney = shopMoney.setScale(2, BigDecimal.ROUND_DOWN);
@@ -2158,6 +2173,7 @@ public class AppAppOrderServiceImpl extends ServiceImpl<AppOrderDao, TbOrder> im
             contentBuffer.append("跑腿费:").append(errandMoney.setScale(2, BigDecimal.ROUND_DOWN)).append("(").append(tbOrder.getErrandMoneyIsShop()).append(")").append(",");
         }
 
+        contentBuffer.append("特殊地址跑腿费:").append(tbOrder.getInsideDeliveryFee().setScale(2, BigDecimal.ROUND_DOWN)).append(",");
         contentBuffer.append("平台服务费:").append(pingRate.setScale(2, BigDecimal.ROUND_DOWN)).append(",");
         contentBuffer.append("短信服务费:").append(smsSendMoney.setScale(2, BigDecimal.ROUND_DOWN)).append(",");
         contentBuffer.append("到账金额:").append(shopMoney.setScale(2, BigDecimal.ROUND_DOWN));

+ 45 - 0
src/main/resources/mapper/address/InsideAddressDao.xml

@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.sqx.modules.address.dao.InsideAddressDao">
+
+    <select id="selectPages" resultType="com.sqx.modules.address.vo.InsideAddressVO">
+        SELECT
+            a.id,
+            a.create_time AS createTime,
+            a.update_time AS updateTime,
+            a.station_id AS stationId,
+            rs.station_name AS stationName,
+            a.delivery_fee AS deliveryFee,
+            a.province,
+            a.city,
+            a.district,
+            a.address_detail AS addressDetail,
+            a.lng,
+            a.lat,
+            a.status,
+            a.sort
+        FROM
+            inside_address a
+        LEFT JOIN
+            rider_station rs ON a.station_id = rs.id
+        WHERE
+            a.del_flag = '0'
+        <if test="query.addressDetail != null and query.addressDetail != ''">
+            AND a.address_detail LIKE CONCAT('%', #{query.addressDetail}, '%')
+        </if>
+        <if test="query.status != null and query.status != ''">
+            AND a.status = #{query.status}
+        </if>
+        <if test="query.stationId != null">
+            AND a.station_id = #{query.stationId}
+        </if>
+        <if test="query.startTime != null">
+            AND a.create_time &gt;= #{query.startTime}
+        </if>
+        <if test="query.endTime != null">
+            AND a.create_time &lt;= #{query.endTime}
+        </if>
+        ORDER BY
+            a.sort
+    </select>
+</mapper>