This commit is contained in:
shuhongfan
2023-09-04 16:40:17 +08:00
commit cf5ac25c14
8267 changed files with 1305066 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
package com.sl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@Slf4j
@EnableFeignClients
@EnableDiscoveryClient
@SpringBootApplication
public class WebCourierApplication {
public static void main(String[] args) {
SpringApplication.run(WebCourierApplication.class, args).getEnvironment();
}
}

View File

@@ -0,0 +1,39 @@
package com.sl.ms.web.courier.config;
import com.sl.transport.common.interceptor.TokenInterceptor;
import com.sl.transport.common.interceptor.UserInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import javax.annotation.Resource;
/**
* 快递员端配置拦截器
*/
@Configuration
@Slf4j
public class CourierWebConfig implements WebMvcConfigurer {
@Resource
private UserInterceptor userInterceptor;
@Resource
private TokenInterceptor tokenInterceptor;
private static final String[] EXCLUDE_PATH_PATTERNS = new String[]{
"/swagger-ui.html",
"/webjars/**",
"/swagger-resources",
"/v2/api-docs",
"/login/**"};
@Override
public void addInterceptors(InterceptorRegistry registry) {
//拦截的时候过滤掉swagger相关路径和登录相关接口
registry.addInterceptor(userInterceptor).excludePathPatterns(EXCLUDE_PATH_PATTERNS).addPathPatterns("/**");
registry.addInterceptor(tokenInterceptor).excludePathPatterns(EXCLUDE_PATH_PATTERNS).addPathPatterns("/**");
}
}

View File

@@ -0,0 +1,23 @@
package com.sl.ms.web.courier.config;
import com.sl.transport.common.properties.RealNameVerifyProperties;
import com.sl.transport.common.service.RealNameVerifyService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@Slf4j
public class RealNameVerifyConfiguration {
@Bean
@ConditionalOnMissingBean
public RealNameVerifyService realNameVerifyUtil(RealNameVerifyProperties realNameVerifyProperties) {
log.info("实名认证工具类...");
return new RealNameVerifyService(
realNameVerifyProperties.getUrl(),
realNameVerifyProperties.getAppCode());
}
}

View File

@@ -0,0 +1,20 @@
package com.sl.ms.web.courier.config;
import com.sl.transport.common.config.FeignErrorDecoder;
import com.sl.transport.common.exception.SLWebException;
import org.springframework.context.annotation.Configuration;
/**
* web调用feign失败解码器实现
*
* @author zzj
* @version 1.0
*/
@Configuration
public class WebFeignErrorDecoder extends FeignErrorDecoder {
@Override
public Exception call(int status, int code, String msg) {
return new SLWebException(msg);
}
}

View File

@@ -0,0 +1,29 @@
package com.sl.ms.web.courier.constants;
public class CourierConstants {
/**
* 订单信息字段
*/
public interface OrderInfo {
/**
* 寄/收件人姓名
*/
String NAME = "name";
/**
* 寄/收件人电话
*/
String PHONE = "phone";
/**
* 寄/收件人地址
*/
String ADDRESS = "address";
/**
* 寄/收件人坐标
*/
String LOCATION = "location";
}
}

View File

@@ -0,0 +1,35 @@
package com.sl.ms.web.courier.controller;
import com.sl.ms.web.courier.service.AreaService;
import com.sl.ms.web.courier.vo.area.AreaSimpleVO;
import com.sl.transport.common.vo.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
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 java.util.List;
@Api(tags = "地址相关接口")
@RestController
@RequestMapping("/areas")
public class AreaController {
@Resource
private AreaService areaService;
@ApiOperation("根据父id获取地址信息")
@GetMapping("/children")
@ApiImplicitParams({
@ApiImplicitParam(name = "parentId", value = "行政区域父id", example = "0")
})
public R<List<AreaSimpleVO>> findChildrenAreaByParentId(@RequestParam(value = "parentId", required = false, defaultValue = "0") Long parentId) {
return R.success(areaService.findChildrenAreaByParentId(parentId));
}
}

View File

@@ -0,0 +1,29 @@
package com.sl.ms.web.courier.controller;
import com.sl.ms.web.courier.service.LoginService;
import com.sl.ms.web.courier.vo.login.AccountLoginVO;
import com.sl.ms.web.courier.vo.login.LoginVO;
import com.sl.transport.common.vo.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@Api(tags = "登录相关接口")
@RestController
@RequestMapping("/login")
public class LoginController {
@Resource
private LoginService loginService;
@ApiOperation(value = "账号登录", notes = "登录")
@PostMapping(value = "/account")
public R<LoginVO> accountLogin(@RequestBody AccountLoginVO accountLoginVO) {
return loginService.accountLogin(accountLoginVO);
}
}

View File

@@ -0,0 +1,59 @@
package com.sl.ms.web.courier.controller;
import com.sl.ms.web.courier.service.MessageService;
import com.sl.ms.web.courier.vo.message.MessageQueryVO;
import com.sl.ms.web.courier.vo.message.MessageVO;
import com.sl.ms.web.courier.vo.message.MessagesHomeVO;
import com.sl.ms.web.courier.vo.message.NewNoticeInfoVO;
import com.sl.transport.common.util.PageResponse;
import com.sl.transport.common.vo.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@Api(tags = "消息相关接口")
@RestController
@RequestMapping("/messages")
public class MessageController {
@Resource
private MessageService messageService;
@GetMapping("/home/get")
@ApiOperation("首页相关消息")
public R<MessagesHomeVO> homeMessage() {
return R.success(messageService.homeMessage());
}
@GetMapping("/notice/new/get")
@ApiOperation("获取新系统通知信息")
public R<NewNoticeInfoVO> notice() {
return R.success(messageService.notice());
}
@PutMapping("/{id}")
@ApiOperation(value = "标记已读")
@ApiImplicitParams({@ApiImplicitParam(name = "id", value = "取派件任务id", required = true, dataTypeClass = Long.class)})
public R<Void> update2Read(@PathVariable("id") Long id) {
messageService.update2Read(id);
return R.success();
}
@PutMapping("readAll/{contentType}")
@ApiOperation(value = "全部已读")
@ApiImplicitParams({@ApiImplicitParam(name = "contentType", value = "消息类型300快递员端公告301寄件相关消息302签收相关消息303快件取消消息304派件消息", required = true, dataTypeClass = Integer.class)})
public R<Void> readAll(@PathVariable("contentType") Integer contentType) {
messageService.readAll(contentType);
return R.success();
}
@GetMapping("/page")
@ApiOperation(value = "分页查询消息列表")
public R<PageResponse<MessageVO>> page(MessageQueryVO messageQueryVO) {
return R.success(messageService.page(messageQueryVO));
}
}

View File

@@ -0,0 +1,37 @@
package com.sl.ms.web.courier.controller;
import com.sl.ms.web.courier.service.PayService;
import com.sl.ms.web.courier.vo.pay.TradeLaunchVO;
import com.sl.ms.web.courier.vo.pay.TradeResponseVO;
import com.sl.transport.common.vo.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@Api(tags = "支付相关接口")
@RestController
@RequestMapping("/pays")
public class PayController {
@Resource
private PayService payService;
@ApiOperation("获取支付qrcode")
@PostMapping("/qrCode/get")
public R<TradeResponseVO> getQrCode(@RequestBody TradeLaunchVO tradeLaunchVO) {
return R.success(payService.getQrCode(tradeLaunchVO));
}
@ApiOperation("获取支付状态")
@ApiImplicitParams({
@ApiImplicitParam(name = "productOrderNo", value = "订单号", required = true)
})
@GetMapping("/status/{productOrderNo}")
public R<Boolean> status(@PathVariable("productOrderNo") String productOrderNo) {
return R.success(payService.getStatus(productOrderNo));
}
}

View File

@@ -0,0 +1,149 @@
package com.sl.ms.web.courier.controller;
import com.sl.ms.web.courier.service.TaskService;
import com.sl.ms.web.courier.vo.task.*;
import com.sl.transport.common.util.PageResponse;
import com.sl.transport.common.vo.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
@Api(tags = "任务(取件和派件)相关接口")
@RequestMapping("/tasks")
@RestController
@Validated
public class TaskController {
@Resource
private TaskService taskService;
@ApiOperation("获取任务详情")
@GetMapping("/get/{id}")
@ApiImplicitParams({@ApiImplicitParam(name = "id", value = "派件或取件id", required = true, dataTypeClass = String.class)})
public R<TaskInfoVO> detail(@PathVariable("id") String id) {
return R.success(taskService.detail(id));
}
@ApiOperation("分页查询任务列表")
@GetMapping("/page")
public R<PageResponse<TaskVO>> pageQuery(@Valid TaskQueryVO vo) {
return R.success(taskService.pageQuery(vo));
}
@ApiOperation("取消任务")
@PostMapping("/cancel")
public R<Void> cancel(@RequestBody TasksCancelVO tasksCancelVO) {
taskService.cancel(tasksCancelVO);
return R.success();
}
@ApiOperation("删除任务")
@DeleteMapping("/{id}")
@ApiImplicitParams({@ApiImplicitParam(name = "id", value = "派件或取件id", required = true, dataTypeClass = String.class)})
public R<Void> delete(@PathVariable("id") String id) {
taskService.delete(id);
return R.success();
}
@ApiOperation("批量删除")
@DeleteMapping("/batch")
public R<Void> batchDelete(@RequestBody TaskBatchVO taskBatchVO) {
taskService.batchDelete(taskBatchVO);
return R.success();
}
@ApiOperation("批量转单")
@PostMapping("/transfer/batch")
public R<Void> batchTransfer(@RequestBody TaskBatchTransferVO taskBatchTransferVO) {
taskService.batchTransfer(taskBatchTransferVO);
return R.success();
}
@ApiOperation("身份验证")
@PostMapping("/idCard/check")
public R<RealNameVerifyVO> idCardCheck(@RequestBody TaskIdCardCheckVO taskIdCardCheckVO) {
RealNameVerifyVO realNameVerifyVO = taskService.idCardCheck(taskIdCardCheckVO);
if (realNameVerifyVO.getFlag()) {
return R.success(realNameVerifyVO);
}
return R.error(realNameVerifyVO, "身份校验未通过");
}
@ApiOperation("取件")
@PutMapping("/pickup")
public R<Void> pickup(@RequestBody TaskPickupVO taskPickupVO) {
if (taskService.pickup(taskPickupVO)) {
return R.success();
}
return R.error("身份校验未通过");
}
@ApiOperation("用户拒收")
@PutMapping("/reject/{id}")
@ApiImplicitParams({@ApiImplicitParam(name = "id", value = "派件或取件id", required = true, dataTypeClass = String.class)})
public R<Void> reject(@PathVariable("id") String id) {
taskService.reject(id);
return R.success();
}
@ApiOperation("签收")
@PutMapping("sign")
public R<Void> sign(@RequestBody TaskSignVO taskSignVO) {
taskService.sign(taskSignVO);
return R.success();
}
@ApiOperation("最近查找")
@GetMapping("/recentSearch")
public R<List<String>> recentSearch() {
return R.success(taskService.recentSearch());
}
@ApiOperation("标记为最近查找")
@GetMapping("/markRecent/{transportOrderId}")
@ApiImplicitParams({@ApiImplicitParam(name = "transportOrderId", value = "运单号", required = true, dataTypeClass = String.class)})
public R<Void> markRecent(@PathVariable("transportOrderId") String transportOrderId) {
taskService.markRecent(transportOrderId);
return R.success();
}
@ApiOperation("清空最近查找")
@DeleteMapping("/recentSearch")
public R<Void> recentSearchDeleteAll() {
taskService.recentSearchDeleteAll();
return R.success();
}
@PostMapping("calculate")
@ApiOperation("运单费用计算")
public R<CarriageVO> calculate(@RequestBody CarriageCalculateVO carriageCalculateVO) {
return R.success(taskService.calculate(carriageCalculateVO));
}
@ApiOperation("订单跟踪")
@GetMapping("/tracks/{id}")
@ApiImplicitParams({@ApiImplicitParam(name = "id", value = "运单id", required = true, dataTypeClass = String.class)})
public R<List<TransportOrderPointVO>> tracks(@PathVariable(value = "id") String id) {
return R.success(taskService.tracks(id));
}
@GetMapping("taskStatistics")
@ApiOperation("今日任务数据统计")
public R<TaskStatisticsVO> tasksStatistics() {
return R.success(taskService.taskStatistics());
}
@ApiOperation("搜索任务")
@PostMapping("/search")
public R<PageResponse<TaskVO>> search(@RequestBody TaskSearchVO taskSearchVO) {
return R.success(taskService.search(taskSearchVO));
}
}

View File

@@ -0,0 +1,32 @@
package com.sl.ms.web.courier.controller;
import com.sl.ms.web.courier.service.TrackService;
import com.sl.transport.common.vo.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PutMapping;
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;
@Api(tags = "运输轨迹相关接口")
@RestController
@RequestMapping("/track")
public class TrackController {
@Resource
private TrackService trackService;
@PutMapping("upload")
@ApiOperation(value = "快递员上报位置", notes = "快递员上报位置")
@ApiImplicitParams({
@ApiImplicitParam(name = "lng", value = "经度", required = true, dataTypeClass = Double.class),
@ApiImplicitParam(name = "lat", value = "纬度", required = true, dataTypeClass = Double.class)})
public R<Boolean> uploadLocation(@RequestParam("lng") String lng,
@RequestParam("lat") String lat) {
return R.success(trackService.uploadLocation(lng, lat));
}
}

View File

@@ -0,0 +1,53 @@
package com.sl.ms.web.courier.controller;
import com.sl.ms.web.courier.service.UserService;
import com.sl.ms.web.courier.vo.user.ServiceScopeVO;
import com.sl.ms.web.courier.vo.user.UserSimpleInfoVO;
import com.sl.ms.web.courier.vo.user.UsersInfoVO;
import com.sl.transport.common.util.PageResponse;
import com.sl.transport.common.vo.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
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;
@Api(tags = "快递员信息相关接口")
@RestController
@RequestMapping("users")
public class UserController {
@Resource
private UserService userService;
@ApiOperation("通过token获取用户信息")
@GetMapping("/get")
public R<UsersInfoVO> get() {
return R.success(userService.get());
}
@ApiOperation("获取当前用户同一个网点的其他快递员")
@GetMapping("/sameAgency")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "页码", dataTypeClass = Integer.class),
@ApiImplicitParam(name = "pageSize", value = "页面大小", dataTypeClass = Integer.class),
@ApiImplicitParam(name = "keyword", value = "关键词", dataTypeClass = String.class)
})
public R<PageResponse<UserSimpleInfoVO>> sameAgency(@RequestParam(value = "page", defaultValue = "1") Integer page,
@RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize,
@RequestParam(value = "keyword", required = false) String keyword) {
return R.success(userService.sameAgency(page, pageSize, keyword));
}
@ApiOperation(value = "获取作业范围")
@GetMapping("/scope")
public R<ServiceScopeVO> findScope() {
return R.success(userService.findScope());
}
}

View File

@@ -0,0 +1,52 @@
package com.sl.ms.web.courier.enums;
import cn.hutool.core.util.EnumUtil;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import com.sl.transport.common.enums.BaseEnum;
/**
* 排序方式
*/
public enum SortOrderEnum implements BaseEnum {
/**
* 正序
*/
POSITIVE_SEQUENCE(1, "正序"),
/**
* 倒序
*/
REVERSE_ORDER(2, "倒序");
SortOrderEnum(Integer code, String value) {
this.code = code;
this.value = value;
}
/**
* 类型编码
*/
@EnumValue
@JsonValue
private final Integer code;
/**
* 类型值
*/
private final String value;
@Override
public Integer getCode() {
return code;
}
@Override
public String getValue() {
return value;
}
public static SortOrderEnum codeOf(Integer code) {
return EnumUtil.getBy(SortOrderEnum::getCode, code);
}
}

View File

@@ -0,0 +1,52 @@
package com.sl.ms.web.courier.enums;
import cn.hutool.core.util.EnumUtil;
import com.baomidou.mybatisplus.annotation.EnumValue;
import com.fasterxml.jackson.annotation.JsonValue;
import com.sl.transport.common.enums.BaseEnum;
/**
* 任务信息相关
*/
public enum TaskInformationEnum implements BaseEnum {
/**
* 1任务关联寄件人信息
*/
SEND(1, "任务关联寄件人信息"),
/**
* 2任务关联收件人信息
*/
RECEIVE(2, "任务关联收件人信息");
TaskInformationEnum(Integer code, String value) {
this.code = code;
this.value = value;
}
/**
* 类型编码
*/
@EnumValue
@JsonValue
private final Integer code;
/**
* 类型值
*/
private final String value;
@Override
public Integer getCode() {
return code;
}
@Override
public String getValue() {
return value;
}
public static TaskInformationEnum codeOf(Integer code) {
return EnumUtil.getBy(TaskInformationEnum::getCode, code);
}
}

View File

@@ -0,0 +1,82 @@
package com.sl.ms.web.courier.enums;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
/**
* 任务状态对应前端的任务列表tap
*/
public enum TaskStatus {
/**
* 1待取件
*/
WAITING_PICKUP(1, "待取件"),
/**
* 2已取件
*/
COMPLETE_PICKUP(2, "已取件"),
/**
* 3已取消
*/
CANCELED(3, "已取消"),
/**
* 4待派件
*/
WAITING_DISPATCH(4, "待派件"),
/**
* 5已签收
*/
COMPLETE_DISPATCH(5, "已签收");
TaskStatus(Integer code, String value) {
this.code = code;
this.value = value;
}
/**
* 类型编码
*/
private final Integer code;
/**
* 类型值
*/
private final String value;
public Integer getCode() {
return code;
}
public String getValue() {
return value;
}
/**
* 循环变量
*/
private static final Map<Integer, TaskStatus> LOOKUP = new HashMap<>();
//静态初始化
static {
for (TaskStatus statusEnum : EnumSet.allOf(TaskStatus.class)) {
LOOKUP.put(statusEnum.code, statusEnum);
}
}
/**
* 根据code获取枚举项
*
* @param code 值
* @return 值
*/
public static TaskStatus lookup(Integer code) {
return LOOKUP.get(code);
}
}

View File

@@ -0,0 +1,9 @@
package com.sl.ms.web.courier.service;
import com.sl.ms.web.courier.vo.area.AreaSimpleVO;
import java.util.List;
public interface AreaService {
List<AreaSimpleVO> findChildrenAreaByParentId(Long parentId);
}

View File

@@ -0,0 +1,17 @@
package com.sl.ms.web.courier.service;
import com.sl.ms.web.courier.vo.login.AccountLoginVO;
import com.sl.ms.web.courier.vo.login.LoginVO;
import com.sl.transport.common.vo.R;
public interface LoginService {
/**
* 根据用户名和密码进行登录
*
* @param accountLoginVO 登录信息
* @return token
*/
R<LoginVO> accountLogin(AccountLoginVO accountLoginVO);
}

View File

@@ -0,0 +1,45 @@
package com.sl.ms.web.courier.service;
import com.sl.ms.web.courier.vo.message.MessageQueryVO;
import com.sl.ms.web.courier.vo.message.MessageVO;
import com.sl.ms.web.courier.vo.message.MessagesHomeVO;
import com.sl.ms.web.courier.vo.message.NewNoticeInfoVO;
import com.sl.transport.common.util.PageResponse;
public interface MessageService {
/**
* 首页相关消息
*
* @return 首页消息对象
*/
MessagesHomeVO homeMessage();
/**
* 获取新系统通知信息
*
* @return 新系统通知消息
*/
NewNoticeInfoVO notice();
/**
* 标记已读
*
* @param id 消息id
*/
void update2Read(Long id);
/**
* 全部已读
*
* @param contentType 消息类型300快递员端公告301寄件相关消息302签收相关消息303快件取消消息304派件消息
*/
void readAll(Integer contentType);
/**
* 分页查询消息列表
*
* @param messageQueryVO 消息查询对象
* @return 分页数据
*/
PageResponse<MessageVO> page(MessageQueryVO messageQueryVO);
}

View File

@@ -0,0 +1,22 @@
package com.sl.ms.web.courier.service;
import com.sl.ms.web.courier.vo.pay.TradeLaunchVO;
import com.sl.ms.web.courier.vo.pay.TradeResponseVO;
public interface PayService {
/**
* 获取支付qrcode
*
* @param tradeLaunchVO 支付发起对象
* @return 支付二维码相关数据
*/
TradeResponseVO getQrCode(TradeLaunchVO tradeLaunchVO);
/**
* 获取支付状态
*
* @param productOrderNo 订单号
* @return 是否支付成功
*/
boolean getStatus(String productOrderNo);
}

View File

@@ -0,0 +1,134 @@
package com.sl.ms.web.courier.service;
import com.sl.ms.web.courier.vo.task.*;
import com.sl.transport.common.util.PageResponse;
import java.util.List;
public interface TaskService {
/**
* 计算运费
*
* @param calculateVO 运费计算对象
* @return 运费 体积 重量
*/
CarriageVO calculate(CarriageCalculateVO calculateVO);
/**
* 分页查询任务列表
*
* @param vo 取/派件查询模型
* @return 任务列表
*/
PageResponse<TaskVO> pageQuery(TaskQueryVO vo);
/**
* 任务详情
*
* @param id 任务id
* @return 任务详情
*/
TaskInfoVO detail(String id);
/**
* 身份验证
*
* @param taskIdCardCheckVO 身份信息
* @return 是否通过验证
*/
RealNameVerifyVO idCardCheck(TaskIdCardCheckVO taskIdCardCheckVO);
/**
* 取件
*
* @param taskPickupVO 取件对象
* @return 是否成功
*/
boolean pickup(TaskPickupVO taskPickupVO);
/**
* 批量转单
*
* @param taskBatchTransferVO 转单对象
*/
void batchTransfer(TaskBatchTransferVO taskBatchTransferVO);
/**
* 取消任务
*
* @param tasksCancelVO 取消任务对象
*/
void cancel(TasksCancelVO tasksCancelVO);
/**
* 删除任务(逻辑删除)
*
* @param id 任务id
*/
void delete(String id);
/**
* 批量删除任务
*
* @param taskBatchVO 任务id列表
*/
void batchDelete(TaskBatchVO taskBatchVO);
/**
* 签收任务
*
* @param taskSignVO 签收对象
*/
void sign(TaskSignVO taskSignVO);
/**
* 拒收任务
*
* @param id 任务id
*/
void reject(String id);
/**
* 运单跟踪
*
* @param id 运单id
* @return 运单跟踪信息
*/
List<TransportOrderPointVO> tracks(String id);
/**
* 今日任务数据统计
*
* @return 今日任务统计数据
*/
TaskStatisticsVO taskStatistics();
/**
* 展示最近查找运单号
*
* @return 最近查找运单号
*/
List<String> recentSearch();
/**
* 标记为最近查找
*
* @param transportOrderId 运单号
*/
void markRecent(String transportOrderId);
/**
* 清空最近查找
*/
void recentSearchDeleteAll();
/**
* 搜索任务
*
* @param taskSearchVO 搜索条件
* @return 分页结果
*/
PageResponse<TaskVO> search(TaskSearchVO taskSearchVO);
}

View File

@@ -0,0 +1,13 @@
package com.sl.ms.web.courier.service;
public interface TrackService {
/**
* 快递员上报位置
*
* @param lng 经度
* @param lat 纬度
* @return 是否成功
*/
Boolean uploadLocation(String lng, String lat);
}

View File

@@ -0,0 +1,33 @@
package com.sl.ms.web.courier.service;
import com.sl.ms.web.courier.vo.user.ServiceScopeVO;
import com.sl.ms.web.courier.vo.user.UserSimpleInfoVO;
import com.sl.ms.web.courier.vo.user.UsersInfoVO;
import com.sl.transport.common.util.PageResponse;
public interface UserService {
/**
* 通过token获取用户信息
*
* @return 用户信息
*/
UsersInfoVO get();
/**
* 查询今天同网点有排班的其他快递员列表
*
* @param page 页码
* @param pageSize 页面大小
* @param keyword 关键词
* @return 快递员列表
*/
PageResponse<UserSimpleInfoVO> sameAgency(Integer page, Integer pageSize, String keyword);
/**
* 获取作业范围
*
* @return 作业范围数据
*/
ServiceScopeVO findScope();
}

View File

@@ -0,0 +1,36 @@
package com.sl.ms.web.courier.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.sl.ms.base.api.common.AreaFeign;
import com.sl.ms.base.domain.base.AreaDto;
import com.sl.ms.web.courier.service.AreaService;
import com.sl.ms.web.courier.vo.area.AreaSimpleVO;
import com.sl.transport.common.util.BeanUtil;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Service
public class AreaServiceImpl implements AreaService {
@Resource
private AreaFeign areaFeign;
@Override
public List<AreaSimpleVO> findChildrenAreaByParentId(Long parentId) {
List<AreaDto> areas = areaFeign.findChildren(parentId);
if (CollUtil.isEmpty(areas)) {
return Collections.emptyList();
}
List<AreaSimpleVO> areaSimpleVOS = new ArrayList<>();
areas.forEach(area -> {
AreaSimpleVO areaSimpleVO = BeanUtil.toBean(area, AreaSimpleVO.class);
areaSimpleVOS.add(areaSimpleVO);
});
return areaSimpleVOS;
}
}

View File

@@ -0,0 +1,39 @@
package com.sl.ms.web.courier.service.impl;
import com.itheima.auth.sdk.AuthTemplate;
import com.itheima.auth.sdk.common.Result;
import com.itheima.auth.sdk.dto.LoginDTO;
import com.sl.ms.web.courier.service.LoginService;
import com.sl.ms.web.courier.vo.login.AccountLoginVO;
import com.sl.ms.web.courier.vo.login.LoginVO;
import com.sl.transport.common.vo.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
@Slf4j
public class LoginServiceImpl implements LoginService {
@Resource
private AuthTemplate authTemplate;
/**
* 根据用户名和密码进行登录
*
* @param accountLoginVO 登录信息
* @return token
*/
@Override
public R<LoginVO> accountLogin(AccountLoginVO accountLoginVO) {
//账号密码登录
Result<LoginDTO> loginResult = authTemplate.opsForLogin().token(accountLoginVO.getAccount(), accountLoginVO.getPassword());
//校验登录是否成功
if (loginResult.getCode() != Result.success().getCode()) {
return R.error(loginResult.getMsg());
}
return R.success(new LoginVO(loginResult.getData().getToken().getToken()));
}
}

View File

@@ -0,0 +1,223 @@
package com.sl.ms.web.courier.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.sl.ms.base.api.common.MessageFeign;
import com.sl.ms.base.domain.base.LatestMessageDTO;
import com.sl.ms.base.domain.base.MessageDTO;
import com.sl.ms.base.domain.base.MessageQueryDTO;
import com.sl.ms.base.domain.constants.MessageConstants;
import com.sl.ms.base.domain.enums.MessageBussinessTypeEnum;
import com.sl.ms.base.domain.enums.MessageContentTypeEnum;
import com.sl.ms.web.courier.service.MessageService;
import com.sl.ms.web.courier.vo.message.MessageQueryVO;
import com.sl.ms.web.courier.vo.message.MessageVO;
import com.sl.ms.web.courier.vo.message.MessagesHomeVO;
import com.sl.ms.web.courier.vo.message.NewNoticeInfoVO;
import com.sl.ms.work.api.PickupDispatchTaskFeign;
import com.sl.transport.common.exception.SLWebException;
import com.sl.transport.common.util.PageResponse;
import com.sl.transport.common.util.UserThreadLocal;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
public class MessageServiceImpl implements MessageService {
@Resource
private MessageFeign messageFeign;
@Resource
private PickupDispatchTaskFeign pickupDispatchTaskFeign;
/**
* 首页相关消息
*
* @return 首页消息对象
*/
@Override
public MessagesHomeVO homeMessage() {
MessagesHomeVO messagesHomeVO = new MessagesHomeVO();
//构件查询条件
MessageQueryDTO messageQueryDTO = new MessageQueryDTO();
messageQueryDTO.setBussinessType(MessageBussinessTypeEnum.COURIER.getCode());
messageQueryDTO.setUserId(UserThreadLocal.get().getUserId());
messageQueryDTO.setIsRead(MessageConstants.UNREAD);
//查询未读消息数量
Integer noReadRes = messageFeign.countType(messageQueryDTO);
messagesHomeVO.setUnRead(ObjectUtil.notEqual(noReadRes, 0));
messagesHomeVO.setNewsNum(noReadRes);
//查询最新未读消息
if (ObjectUtil.equal(noReadRes, 0)) {
return messagesHomeVO;
}
LatestMessageDTO latestMessageDTO = messageFeign.latestMessage(messageQueryDTO);
messagesHomeVO.setMinutes((int) Duration.between(latestMessageDTO.getCreated(), LocalDateTime.now()).toMinutes());
messagesHomeVO.setContentType(latestMessageDTO.getContentType());
assembleRecentMsg(messagesHomeVO, latestMessageDTO.getContentType());
return messagesHomeVO;
}
/**
* 封装消息类型对应的内容
*
* @param messagesHomeVO 首页消息相关模型
* @param contentType 消息类型
*/
private static void assembleRecentMsg(MessagesHomeVO messagesHomeVO, Integer contentType) {
switch (MessageContentTypeEnum.codeOf(contentType)) {
//公告消息
case COURIER_BULLETIN:
messagesHomeVO.setRecentMsg(MessageConstants.MessageTitle.BULLETIN);
break;
//取件消息
case COURIER_PICKUP:
messagesHomeVO.setRecentMsg(MessageConstants.MessageTitle.PICKUP);
break;
//签收相关消息
case COURIER_SIGN:
messagesHomeVO.setRecentMsg(MessageConstants.MessageTitle.SIGN);
break;
//快件取消相关消息
case COURIER_CANCEL:
messagesHomeVO.setRecentMsg(MessageConstants.MessageTitle.CANCEL);
break;
//派件相关消息
case COURIER_DISPATCH:
messagesHomeVO.setRecentMsg(MessageConstants.MessageTitle.DISPATCH);
break;
default:
throw new SLWebException("Unexpected value: " + contentType);
}
}
/**
* 获取新系统通知信息
*
* @return 新系统通知消息
*/
@Override
public NewNoticeInfoVO notice() {
//统计未读消息
NewNoticeInfoVO newNoticeInfoVO = this.unreadMessageStatistics();
//构件查询条件
MessageQueryDTO dto = new MessageQueryDTO();
dto.setUserId(UserThreadLocal.getUserId());
dto.setBussinessType(MessageBussinessTypeEnum.COURIER.getCode());
//获取寄件相关最新消息
dto.setContentType(MessageContentTypeEnum.COURIER_PICKUP.getCode());
LatestMessageDTO pickupDTO = messageFeign.latestMessage(dto);
//获取签收相关最新消息
dto.setContentType(MessageContentTypeEnum.COURIER_SIGN.getCode());
LatestMessageDTO signDTO = messageFeign.latestMessage(dto);
//获取快件取消相关最新消息
dto.setContentType(MessageContentTypeEnum.COURIER_CANCEL.getCode());
LatestMessageDTO cancelDTO = messageFeign.latestMessage(dto);
//获取派件相关最新消息
dto.setContentType(MessageContentTypeEnum.COURIER_DISPATCH.getCode());
LatestMessageDTO dispatchDTO = messageFeign.latestMessage(dto);
//组装最新消息时间
newNoticeInfoVO.setNewSendNoticeTime(ObjectUtil.isNotEmpty(pickupDTO) ? pickupDTO.getCreated() : null);
newNoticeInfoVO.setNewReceiveNoticeTime(ObjectUtil.isNotEmpty(signDTO) ? signDTO.getCreated() : null);
newNoticeInfoVO.setNewCancelNoticeTime(ObjectUtil.isNotEmpty(cancelDTO) ? cancelDTO.getCreated() : null);
newNoticeInfoVO.setNewDispatchNoticeTime(ObjectUtil.isNotEmpty(dispatchDTO) ? dispatchDTO.getCreated() : null);
return newNoticeInfoVO;
}
/**
* 按照消息类型统计未读消息数量
*
* @return 未读消息通知
*/
private NewNoticeInfoVO unreadMessageStatistics() {
//1.构建查询条件
MessageQueryDTO dto = new MessageQueryDTO();
dto.setUserId(UserThreadLocal.getUserId());
dto.setBussinessType(MessageBussinessTypeEnum.COURIER.getCode());
dto.setIsRead(MessageConstants.UNREAD);
//2.分页查询
List<MessageDTO> list = messageFeign.list(dto);
//3.组装新未读消息数据
NewNoticeInfoVO newNoticeInfoVO = new NewNoticeInfoVO();
if (ObjectUtil.isNotEmpty(list)) {
//按照消息类型统计数量
Map<Integer, Long> contentTypeMap = list.stream().collect(Collectors.groupingBy(MessageDTO::getContentType, Collectors.counting()));
newNoticeInfoVO.setHaveNewSendNotice(convertLong2Int(contentTypeMap.get(MessageContentTypeEnum.COURIER_PICKUP.getCode())) > 0);
newNoticeInfoVO.setHaveNewReceiveNotice(convertLong2Int(contentTypeMap.get(MessageContentTypeEnum.COURIER_SIGN.getCode())) > 0);
newNoticeInfoVO.setHaveNewCancelNotice(convertLong2Int(contentTypeMap.get(MessageContentTypeEnum.COURIER_CANCEL.getCode())) > 0);
newNoticeInfoVO.setHaveNewDispatchNotice(convertLong2Int(contentTypeMap.get(MessageContentTypeEnum.COURIER_DISPATCH.getCode())) > 0);
}
return newNoticeInfoVO;
}
/**
* 类型转换Long-->int
*
* @param number Long类型
* @return int类型
*/
private int convertLong2Int(Long number) {
return Math.toIntExact(number == null ? 0 : number);
}
/**
* 标记已读
*
* @param id 消息id
*/
@Override
public void update2Read(Long id) {
messageFeign.update2Read(id);
}
/**
* 全部已读
*
* @param contentType 消息类型300快递员端公告301寄件相关消息302签收相关消息303快件取消消息304派件消息
*/
@Override
public void readAll(Integer contentType) {
Long userId = UserThreadLocal.get().getUserId();
messageFeign.readAll(userId, contentType);
}
/**
* 分页查询消息列表
*
* @param messageQueryVO 消息查询对象
* @return 分页数据
*/
@Override
public PageResponse<MessageVO> page(MessageQueryVO messageQueryVO) {
//1.构造查询条件
MessageQueryDTO messageQueryDTO = BeanUtil.toBean(messageQueryVO, MessageQueryDTO.class);
messageQueryDTO.setBussinessType(MessageBussinessTypeEnum.COURIER.getCode());
messageQueryDTO.setUserId(UserThreadLocal.getUserId());
//2.分页查询
PageResponse<MessageDTO> pageResponse = messageFeign.page(messageQueryDTO);
if (ObjectUtil.isEmpty(pageResponse.getItems())) {
return new PageResponse<>();
}
//3.组装分页结果
return PageResponse.of(pageResponse, MessageVO.class);
}
}

View File

@@ -0,0 +1,107 @@
package com.sl.ms.web.courier.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.sl.ms.oms.api.OrderFeign;
import com.sl.ms.oms.dto.OrderDTO;
import com.sl.ms.oms.enums.OrderPaymentStatus;
import com.sl.ms.trade.api.NativePayFeign;
import com.sl.ms.trade.api.TradingFeign;
import com.sl.ms.trade.domain.TradingDTO;
import com.sl.ms.trade.domain.request.NativePayDTO;
import com.sl.ms.trade.domain.response.NativePayResponseDTO;
import com.sl.ms.trade.enums.PayChannelEnum;
import com.sl.ms.trade.enums.TradingStateEnum;
import com.sl.ms.web.courier.service.PayService;
import com.sl.ms.web.courier.vo.pay.TradeLaunchVO;
import com.sl.ms.web.courier.vo.pay.TradeResponseVO;
import com.sl.transport.common.exception.SLWebException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class PayServiceImpl implements PayService {
@Resource
private NativePayFeign nativePayFeign;
@Resource
private TradingFeign tradingFeign;
@Resource
private OrderFeign orderFeign;
@Value("${sl.wechat.enterpriseId}")
private Long wechatEnterpriseId;
@Value("${sl.ali.enterpriseId}")
private Long aliEnterpriseId;
/**
* 获取支付qrcode
*
* @param tradeLaunchVO 支付发起对象
* @return 支付二维码相关数据
*/
@Override
public TradeResponseVO getQrCode(TradeLaunchVO tradeLaunchVO) {
// 1.判断是否已支付,已支付则不能获取支付二维码
OrderDTO orderDTO = orderFeign.findById(Long.valueOf(tradeLaunchVO.getProductOrderNo()));
if (ObjectUtil.equal(orderDTO.getPaymentStatus(), OrderPaymentStatus.PAID.getStatus())) {
throw new SLWebException("订单已完成支付");
}
//2.未支付则查询是否有和订单绑定的未支付交易单(同支付渠道)
PayChannelEnum payChannelEnum = PayChannelEnum.codeOf(tradeLaunchVO.getPayMethod());
String payChannel = payChannelEnum.toString();
Long enterpriseId = ObjectUtil.equal(payChannelEnum, PayChannelEnum.ALI_PAY) ? aliEnterpriseId : wechatEnterpriseId;
//3.如果已有,则对比数据库中和入参中的支付渠道是否相同
//3.1.如果相同,则使用已有交易号获取支付二维码
TradeResponseVO tradeResponseVO = new TradeResponseVO();
if (ObjectUtil.isNotEmpty(orderDTO.getTradingOrderNo()) && ObjectUtil.equal(payChannel, orderDTO.getTradingChannel())) {
String qrCode = nativePayFeign.queryQrCode(orderDTO.getTradingOrderNo());
tradeResponseVO.setQrCode(qrCode);
tradeResponseVO.setTradingOrderNo(orderDTO.getTradingOrderNo());
return tradeResponseVO;
}
//3.2.如果不同,则重新生成支付二维码
//3.2.1.类型转换
NativePayDTO nativePayDTO = BeanUtil.toBean(tradeLaunchVO, NativePayDTO.class);
nativePayDTO.setTradingChannel(payChannelEnum);
nativePayDTO.setEnterpriseId(enterpriseId);
//3.2.2.调用feign获取支付二维码
NativePayResponseDTO nativePayResponseDTO = nativePayFeign.createDownLineTrading(nativePayDTO);
//3.2.3.将交易单号和支付渠道更新到订单表
orderDTO.setTradingOrderNo(nativePayResponseDTO.getTradingOrderNo());
orderDTO.setTradingChannel(payChannel);
orderFeign.updateById(orderDTO.getId(), orderDTO);
//3.2.4.将dto转为vo响应
return BeanUtil.toBean(nativePayResponseDTO, TradeResponseVO.class);
}
/**
* 获取支付状态
*
* @param productOrderNo 订单号
* @return 是否支付成功
*/
@Override
public boolean getStatus(String productOrderNo) {
//1.根据订单id查询交易数据
TradingDTO tradingDTO = tradingFeign.queryTrading(Long.valueOf(productOrderNo), null);
//2.判断是否已结算
//2.1如果已经结算,则修改订单支付状态
if (ObjectUtil.equal(tradingDTO.getTradingState(), TradingStateEnum.YJS)) {
OrderDTO orderDTO = new OrderDTO();
orderDTO.setId(tradingDTO.getProductOrderNo());
orderDTO.setPaymentStatus(OrderPaymentStatus.PAID.getStatus());
orderFeign.updateById(tradingDTO.getProductOrderNo(), orderDTO);
}
//2.2如果未结算直接返回支付结果
return ObjectUtil.equal(tradingDTO.getTradingState(), TradingStateEnum.YJS);
}
}

View File

@@ -0,0 +1,989 @@
package com.sl.ms.web.courier.service.impl;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.itheima.auth.sdk.dto.UserDTO;
import com.sl.ms.base.api.common.AreaFeign;
import com.sl.ms.base.api.common.MQFeign;
import com.sl.ms.base.api.common.MessageFeign;
import com.sl.ms.base.domain.base.AreaDto;
import com.sl.ms.base.domain.base.MessageAddDTO;
import com.sl.ms.base.domain.constants.MessageConstants;
import com.sl.ms.base.domain.enums.MessageBussinessTypeEnum;
import com.sl.ms.base.domain.enums.MessageContentTypeEnum;
import com.sl.ms.carriage.appi.CarriageFeign;
import com.sl.ms.carriage.domain.dto.CarriageDTO;
import com.sl.ms.carriage.domain.dto.WaybillDTO;
import com.sl.ms.oms.api.CargoFeign;
import com.sl.ms.oms.api.OrderFeign;
import com.sl.ms.oms.dto.OrderCargoDTO;
import com.sl.ms.oms.dto.OrderDTO;
import com.sl.ms.oms.dto.OrderPickupDTO;
import com.sl.ms.oms.enums.OrderStatus;
import com.sl.ms.search.api.CourierTaskFeign;
import com.sl.ms.search.domain.dto.CourierTaskDTO;
import com.sl.ms.search.domain.dto.CourierTaskPageQueryDTO;
import com.sl.ms.user.api.MemberFeign;
import com.sl.ms.user.domain.dto.MemberDTO;
import com.sl.ms.user.domain.enums.MemberIdCardVerifyStatus;
import com.sl.ms.web.courier.constants.CourierConstants;
import com.sl.ms.web.courier.enums.SortOrderEnum;
import com.sl.ms.web.courier.enums.TaskInformationEnum;
import com.sl.ms.web.courier.enums.TaskStatus;
import com.sl.ms.web.courier.service.TaskService;
import com.sl.ms.web.courier.vo.task.*;
import com.sl.ms.work.api.PickupDispatchTaskFeign;
import com.sl.ms.work.api.TransportOrderFeign;
import com.sl.ms.work.domain.dto.PickupDispatchTaskDTO;
import com.sl.ms.work.domain.dto.TransportOrderDTO;
import com.sl.ms.work.domain.dto.request.PickupDispatchTaskPageQueryDTO;
import com.sl.ms.work.domain.dto.response.PickupDispatchTaskStatisticsDTO;
import com.sl.ms.work.domain.enums.pickupDispatchtask.*;
import com.sl.ms.work.domain.enums.transportorder.TransportOrderStatus;
import com.sl.transport.common.constant.Constants;
import com.sl.transport.common.exception.SLWebException;
import com.sl.transport.common.service.RealNameVerifyService;
import com.sl.transport.common.util.*;
import com.sl.transport.common.vo.CourierMsg;
import com.sl.transport.common.vo.TransportInfoMsg;
import com.sl.transport.common.vo.TransportOrderStatusMsg;
import com.sl.transport.info.api.TransportInfoFeign;
import com.sl.transport.info.domain.TransportInfoDTO;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
@Service
@Slf4j
public class TaskServiceImpl implements TaskService {
@Resource
private PickupDispatchTaskFeign pickupDispatchTaskFeign;
@Resource
private CarriageFeign carriageFeign;
@Resource
private AreaFeign areaFeign;
@Resource
private OrderFeign orderFeign;
@Resource
private CargoFeign cargoFeign;
@Resource
private TransportOrderFeign transportOrderFeign;
@Resource
private MemberFeign memberFeign;
@Resource
private MessageFeign messageFeign;
@Resource
private TransportInfoFeign transportInfoFeign;
@Resource
private StringRedisTemplate stringRedisTemplate;
@Resource
private RealNameVerifyService realNameVerifyService;
@Resource
private MQFeign mqFeign;
@Resource
private CourierTaskFeign courierTaskFeign;
/**
* 实名认证开关,默认关闭
*/
@Value("${real-name-registration.enable}")
private String realNameVerify;
/**
* 计算运费
*
* @param calculateVO 运费计算对象
* @return 运费 体积 重量
*/
@Override
public CarriageVO calculate(CarriageCalculateVO calculateVO) {
//1.根据县级id获取市级地址id
List<AreaDto> areaDtos = areaFeign.findBatch(Arrays.asList(calculateVO.getReceiverCountyId(), calculateVO.getSenderCountyId()));
if (CollUtil.isEmpty(areaDtos)) {
throw new SLWebException("地址未找到");
}
Map<Long, Long> areaCountyIdAndCityIdMap = areaDtos.stream().collect(Collectors.toMap(AreaDto::getId, AreaDto::getParentId));
//2.将市级id作为运费计算条件
WaybillDTO waybillDTO = BeanUtil.toBean(calculateVO, WaybillDTO.class, (calculate, waybill) -> {
waybill.setReceiverCityId(areaCountyIdAndCityIdMap.get(calculate.getReceiverCountyId()));
waybill.setSenderCityId(areaCountyIdAndCityIdMap.get(calculate.getSenderCountyId()));
});
//3.调用接口,计算运费
CarriageDTO carriageDTO = carriageFeign.compute(waybillDTO);
log.info("计算结果:{}", carriageDTO);
return BeanUtil.toBean(carriageDTO, CarriageVO.class, (carriage, carriageVO) -> {
carriageVO.setFreight(String.valueOf(carriage.getExpense()));
carriageVO.setWeight(BigDecimal.valueOf(carriage.getComputeWeight()));
carriageVO.setFirstWeight(carriage.getFirstWeight());
carriageVO.setContinuousWeight(carriage.getContinuousWeight());
});
}
/**
* 将取派件任务封装为VO
*
* @param taskDTO 取派件任务
* @return 任务返回结果
*/
private TaskVO getTaskVO(PickupDispatchTaskDTO taskDTO, Map<Long, OrderDTO> orderMap) {
TaskVO taskVO = BeanUtil.toBean(taskDTO, TaskVO.class);
taskVO.setCancelReason(ObjectUtil.isEmpty(taskDTO.getCancelReason()) ? null : taskDTO.getCancelReason().getValue());
//为taskVO封装订单和运单数据
this.assembleTaskVO(taskVO, orderMap);
return taskVO;
}
/**
* 为taskVO封装订单和运单数据
*
* @param taskVO 取派件任务
*/
private void assembleTaskVO(TaskVO taskVO, Map<Long, OrderDTO> orderMap) {
//根据订单id查询订单
OrderDTO orderDTO = orderMap.get(taskVO.getOrderId());
if (orderDTO == null) {
String msg = CharSequenceUtil.format("id为{}的取派件任务查不到订单信息", taskVO.getId());
throw new SLWebException(msg);
}
taskVO.setAmount(orderDTO.getAmount().doubleValue());//运费
taskVO.setPaymentStatus(orderDTO.getPaymentStatus());
taskVO.setPaymentMethod(orderDTO.getPaymentMethod());
//判断取派件任务需要获取的是寄件人信息还是收件人信息
//拒签情况下,同一个订单会产生两个派件任务。正常派件任务是派给收件人,拒签后的派件任务是派给寄件人
//通过TaskInformationEnum设置取寄件人信息还是收件人信息。只有是正常的派件任务是目标是收件人其余均是寄件人
TaskInformationEnum flag = TaskInformationEnum.SEND;
if (PickupDispatchTaskType.DISPATCH.equals(taskVO.getTaskType())) {
List<PickupDispatchTaskDTO> pickupDispatchTaskDTOS = pickupDispatchTaskFeign.findByOrderId(taskVO.getOrderId(), taskVO.getTaskType());
//pickupDispatchTaskDTOS是按创建时间正序排序的第一条数据是正常的派件任务
if (pickupDispatchTaskDTOS.get(0).getId().equals(taskVO.getId())) {
flag = TaskInformationEnum.RECEIVE;
}
}
//vo设置姓名、电话、地址、坐标
Map<String, String> taskInformation = this.getNameAndPhoneAndAddress(flag, orderDTO);
taskVO.setName(taskInformation.get(CourierConstants.OrderInfo.NAME));
taskVO.setPhone(taskInformation.get(CourierConstants.OrderInfo.PHONE));
taskVO.setAddress(taskInformation.get(CourierConstants.OrderInfo.ADDRESS));
taskVO.setLocation(taskInformation.get(CourierConstants.OrderInfo.LOCATION));
//获取运单信息:取件任务新任务状态和已取消状态不查运单
if (ObjectUtil.equal(PickupDispatchTaskType.DISPATCH, taskVO.getTaskType()) || ObjectUtil.equal(PickupDispatchTaskStatus.COMPLETED, taskVO.getStatus())) {
TransportOrderDTO transportOrderDTO = transportOrderFeign.findByOrderId(taskVO.getOrderId());
taskVO.setTransportOrderId(transportOrderDTO.getId());//运单id
}
}
/**
* 根据任务类型,筛选出姓名、电话、地址、坐标
*
* @param taskInformationEnum 任务信息相关
* @param orderDTO 订单信息
* @return 姓名、电话、地址、坐标
*/
private Map<String, String> getNameAndPhoneAndAddress(TaskInformationEnum taskInformationEnum, OrderDTO orderDTO) {
String address;
String location;
Map<String, String> taskInformation = new HashMap<>();
switch (taskInformationEnum) {
case SEND: //任务关联寄件人信息
//寄/收件人姓名
taskInformation.put(CourierConstants.OrderInfo.NAME, orderDTO.getSenderName());
//寄/收件人电话
taskInformation.put(CourierConstants.OrderInfo.PHONE, orderDTO.getSenderPhone());
//根据id查询省、市、区名称并拼接为完整地址
address = getDetailAddress(orderDTO.getSenderProvinceId(), orderDTO.getSenderCityId(), orderDTO.getSenderCountyId(), orderDTO.getSenderAddress());
//获取寄/收件人坐标
location = orderFeign.findOrderLocationByOrderId(orderDTO.getId()).getSendLocation();
break;
case RECEIVE://2任务关联收件人信息
//寄/收件人姓名
taskInformation.put(CourierConstants.OrderInfo.NAME, orderDTO.getReceiverName());
//寄/收件人电话
taskInformation.put(CourierConstants.OrderInfo.PHONE, orderDTO.getReceiverPhone());
//根据id查询省、市、区名称并拼接为完整地址
address = getDetailAddress(orderDTO.getReceiverProvinceId(), orderDTO.getReceiverCityId(), orderDTO.getReceiverCountyId(), orderDTO.getReceiverAddress());
//获取寄件人坐标
location = orderFeign.findOrderLocationByOrderId(orderDTO.getId()).getReceiveLocation();
break;
default:
throw new SLWebException("Unexpected taskType:" + taskInformationEnum);
}
//寄/收件人地址、坐标
taskInformation.put(CourierConstants.OrderInfo.ADDRESS, address);
taskInformation.put(CourierConstants.OrderInfo.LOCATION, location);
return taskInformation;
}
/**
* 根据省市县id和具体地址拼接为完整地址
*
* @param provinceId 省id
* @param cityId 市id
* @param countyId 区/县id
* @param address 具体地址
* @return 完整地址
*/
private String getDetailAddress(Long provinceId, Long cityId, Long countyId, String address) {
List<AreaDto> areaList = areaFeign.findBatch(List.of(provinceId, cityId, countyId));
Map<Long, String> areaMap = areaList.stream().collect(Collectors.toMap(AreaDto::getId, AreaDto::getName, (key, value) -> value));
return CharSequenceUtil.strBuilder(areaMap.get(provinceId), areaMap.get(cityId), areaMap.get(countyId), address).toString();
}
/**
* 条件查询取派件任务列表
*
* @param vo 查询条件
* @return 取派件任务列表
*/
private List<PickupDispatchTaskDTO> getPickupDispatchTaskList(TaskQueryVO vo) {
//构造查询条件
PickupDispatchTaskPageQueryDTO taskDTO = new PickupDispatchTaskPageQueryDTO();
taskDTO.setPage(1);
taskDTO.setPageSize(999);
taskDTO.setCourierId(UserThreadLocal.getUserId()); //快递员ID
if (ObjectUtil.isNotEmpty(vo.getTaskStatus())) {
this.setTskTypeAndStatus(vo);//根据页面tap设置任务类型和状态
}
taskDTO.setTaskType(PickupDispatchTaskType.codeOf(vo.getTaskType()));
taskDTO.setStatus(vo.getStatus() == null ? null : PickupDispatchTaskStatus.codeOf(vo.getStatus()));
taskDTO.setIsDeleted(PickupDispatchTaskIsDeleted.NOT_DELETED);
//根据类型、状态、快递员ID查询任务列表
return pickupDispatchTaskFeign.findByPage(taskDTO).getItems();
}
/**
* 根据页面tap设置任务类型和状态
*
* @param vo 任务查询对象
*/
private void setTskTypeAndStatus(TaskQueryVO vo) {
switch (TaskStatus.lookup(vo.getTaskStatus())) {
case WAITING_PICKUP: //1待取件
vo.setTaskType(PickupDispatchTaskType.PICKUP.getCode());//任务类型1为取件任务2为派件任务
vo.setStatus(PickupDispatchTaskStatus.NEW.getCode());//任务状态1为待执行、2为进行中、3为待确认、4为已完成、5为已取消
break;
case COMPLETE_PICKUP: //2已取件
vo.setTaskType(PickupDispatchTaskType.PICKUP.getCode());//任务类型1为取件任务2为派件任务
vo.setStatus(PickupDispatchTaskStatus.COMPLETED.getCode());//任务状态1为待执行、2为进行中、3为待确认、4为已完成、5为已取消
break;
case CANCELED: //3已取消
vo.setTaskType(PickupDispatchTaskType.PICKUP.getCode());//任务类型1为取件任务2为派件任务
vo.setStatus(PickupDispatchTaskStatus.CANCELLED.getCode());//任务状态1为待执行、2为进行中、3为待确认、4为已完成、5为已取消
break;
case WAITING_DISPATCH://4待派件
vo.setTaskType(PickupDispatchTaskType.DISPATCH.getCode());//任务类型1为取件任务2为派件任务
vo.setStatus(PickupDispatchTaskStatus.NEW.getCode());//任务状态1为待执行、2为进行中、3为待确认、4为已完成、5为已取消
break;
case COMPLETE_DISPATCH://5已签收
vo.setTaskType(PickupDispatchTaskType.DISPATCH.getCode());//任务类型1为取件任务2为派件任务
vo.setStatus(PickupDispatchTaskStatus.COMPLETED.getCode());//任务状态1为待执行、2为进行中、3为待确认、4为已完成、5为已取消
break;
default:
throw new SLWebException("Unexpected taskStatus:" + vo);
}
}
/**
* 分页查询任务列表
*
* @param vo 取/派件查询模型
* @return 任务列表
*/
@Override
public PageResponse<TaskVO> pageQuery(TaskQueryVO vo) {
//1.条件查询取派件任务列表
List<PickupDispatchTaskDTO> taskDTOList = this.getPickupDispatchTaskList(vo);
if (CollUtil.isEmpty(taskDTOList)) {
return new PageResponse<>();
}
//dto转换为vo
List<TaskVO> taskList = taskDTOList.stream().map(taskDTO -> {
TaskVO taskVO = BeanUtil.toBean(taskDTO, TaskVO.class);
taskVO.setCancelReason(ObjectUtil.isEmpty(taskDTO.getCancelReason()) ? null : taskDTO.getCancelReason().getValue());
return taskVO;
}).collect(Collectors.toList());
//2.设置任务时间
this.setTaskTime(vo.getStatus(), taskList);
//3.按日期过滤任务
taskList = taskList.stream().filter(task -> task.getTaskTime().isAfter(vo.getDateTime()) && task.getTaskTime().isBefore(vo.getDateTime().plusDays(1))).collect(Collectors.toList());
if (CollUtil.isEmpty(taskList)) {
return new PageResponse<>();
}
//4.全部取派中不展示已取消的任务即入参任务状态为null的情况,过滤掉已取消任务
if (ObjectUtil.isEmpty(vo.getStatus())) {
taskList = taskList.stream().filter(task -> ObjectUtil.notEqual(task.getStatus(), PickupDispatchTaskStatus.CANCELLED)).collect(Collectors.toList());
}
//5.过滤超时任务
if (Boolean.TRUE.equals(vo.getFilterOverTime())) {
taskList = filterTaskList(taskList);
if (CollUtil.isEmpty(taskList)) {
return new PageResponse<>();
}
}
//6.为taskVO封装订单和运单数据
List<String> orderIds = taskList.stream().map(task -> task.getOrderId().toString()).collect(Collectors.toList());
List<OrderDTO> orderDTOS = orderFeign.findByIds(orderIds);
Map<Long, OrderDTO> orderMap = orderDTOS.stream().collect(Collectors.toMap(OrderDTO::getId, order -> order));
taskList.forEach(taskVO -> assembleTaskVO(taskVO, orderMap));
//7.计算距离:待取件和待派件需要计算距离
this.computeDistance(vo.getLongitude(), vo.getLatitude(), taskList);
//8.排序
taskList = sortTaskList(vo, taskList);
//9.分页
int startPosition = (vo.getPage() - 1) * vo.getPageSize();//起始位置
long pageCounts = taskList.size();//总条目数
long pages = (long) Math.ceil(pageCounts * 1.0 / vo.getPageSize());//总页数
//根据起始位置和页面大小取当前页面数据列表
taskList = taskList.stream().skip(startPosition).limit(vo.getPageSize()).collect(Collectors.toList());
//10.是否超时:待取件和待派件需要标记超时
if (ObjectUtil.equal(vo.getStatus(), 1)) {
taskList.forEach(x -> x.setIsDelay(LocalDateTime.now().isAfter(x.getEstimatedEndTime())));
}
//11.分页结果封装
return PageResponse.of(taskList, vo.getPage(), vo.getPageSize(), pages, pageCounts);
}
/**
* 设置任务时间
*
* @param status 取派件任务状态
* @param taskList 任务列表
*/
private void setTaskTime(Integer status, List<TaskVO> taskList) {
if (ObjectUtil.isEmpty(status)) {
taskList.forEach(x -> x.setTaskTime(x.getCreated()));
} else {
switch (PickupDispatchTaskStatus.codeOf(status)) {
//新任务
case NEW:
taskList.forEach(x -> x.setTaskTime(x.getEstimatedStartTime()));
break;
//已完成
case COMPLETED:
taskList.forEach(x -> x.setTaskTime(x.getActualEndTime()));
break;
//已取消
case CANCELLED:
taskList.forEach(x -> x.setTaskTime(x.getCancelTime()));
break;
default:
throw new SLWebException("Unexpected taskStatus:" + status);
}
}
}
/**
* 计算距离
*
* @param longitude 经度
* @param latitude 纬度
* @param taskList 任务列表
*/
private void computeDistance(Double longitude, Double latitude, List<TaskVO> taskList) {
taskList.forEach(x -> {
if (x.getStatus().equals(PickupDispatchTaskStatus.NEW)) {
//获取快递员与收件人之间的距离单位km,保留1位小数
double distance = LocationUtils.getDistance(longitude, latitude, x.getLocation());
distance = NumberUtil.round(distance / 1000, 1).doubleValue();
x.setDistance(distance);
}
});
}
/**
* 过滤即将超时任务
*
* @param taskList 任务列表
* @return 过滤后任务列表
*/
private List<TaskVO> filterTaskList(List<TaskVO> taskList) {
taskList = taskList.stream().filter(taskVO -> {
LocalDateTime deadlineTime = taskVO.getEstimatedEndTime();//截止时间
return LocalDateTime.now().isAfter(deadlineTime);
}).collect(Collectors.toList());
return taskList;
}
/**
* 根据距离或时间对列表排序
*
* @param vo 排序字段
* @param taskList 未排序列表
* @return 已排序列表
*/
private List<TaskVO> sortTaskList(TaskQueryVO vo, List<TaskVO> taskList) {
if (ObjectUtil.isNotEmpty(vo.getOrderDistance()) && vo.getOrderDistance().equals(SortOrderEnum.POSITIVE_SEQUENCE.getCode())) {
//按距离正序
return CollUtil.sort(taskList, Comparator.comparing(TaskVO::getDistance));
} else if (ObjectUtil.isNotEmpty(vo.getOrderDistance()) && vo.getOrderDistance().equals(SortOrderEnum.REVERSE_ORDER.getCode())) {
//按距离倒序
return CollUtil.sort(taskList, Comparator.comparing(TaskVO::getDistance).reversed());
} else if (ObjectUtil.isNotEmpty(vo.getOrderTime()) && vo.getOrderTime().equals(SortOrderEnum.POSITIVE_SEQUENCE.getCode())) {
//按时间正序
return CollUtil.sort(taskList, Comparator.comparing(TaskVO::getTaskTime));
} else {
//默认按时间倒序
return CollUtil.sort(taskList, Comparator.comparing(TaskVO::getTaskTime).reversed());
}
}
/**
* 任务详情
*
* @param id 任务id
* @return 任务详情
*/
@Override
public TaskInfoVO detail(String id) {
//查询取派件任务相关联信息
PickupDispatchTaskDTO taskDTO = pickupDispatchTaskFeign.findById(Long.valueOf(id));//取派件任务信息
log.info("取派件任务为:{}", taskDTO);
OrderDTO orderDTO = orderFeign.findById(taskDTO.getOrderId());//订单信息
OrderCargoDTO orderCargoDto = cargoFeign.findByOrderId(orderDTO.getId());//货物信息
MemberDTO memberDto = memberFeign.detail(orderDTO.getMemberId());//用户信息
//组装响应数据
TaskInfoVO vo = BeanUtil.toBean(taskDTO, TaskInfoVO.class);
vo.setId(id);//任务id
vo.setOrderId(String.valueOf(taskDTO.getOrderId()));//订单id
vo.setSenderName(orderDTO.getSenderName());//寄件人姓名
vo.setReceiverName(orderDTO.getReceiverName());//收件人姓名
vo.setSenderPhone(orderDTO.getSenderPhone());//寄件人电话
vo.setReceiverPhone(orderDTO.getReceiverPhone());//收件人电话
vo.setGoodsType(orderCargoDto.getName());//物品类型名称
vo.setWeight(orderCargoDto.getWeight());//重量
vo.setVolume(orderCargoDto.getVolume());//体积
vo.setFreight(String.valueOf(orderDTO.getAmount()));//金额
vo.setRemark(taskDTO.getMark());//备注
vo.setPaymentMethod(orderDTO.getPaymentMethod());//付款方式,1寄付2到付
vo.setPaymentStatus(orderDTO.getPaymentStatus());//付款状态,1未付2已付
vo.setSignRecipient(ObjectUtil.isEmpty(taskDTO.getSignRecipient()) ? null : taskDTO.getSignRecipient().getCode());//签收人1-本人2-代收
vo.setIdCardNoVerify(memberDto.getIdCardNoVerify());//身份证号是否验证0未验证 1验证通过 2验证未通过
vo.setIdCardNo(DesensitizedUtil.idCardNum(memberDto.getIdCardNo(), 6, 4));//身份证号脱敏
//获取运单信息:取件任务新任务状态和已取消状态不查运单,只查派件任务和完成状态的运单
if (ObjectUtil.equal(PickupDispatchTaskType.DISPATCH, taskDTO.getTaskType()) || ObjectUtil.equal(PickupDispatchTaskStatus.COMPLETED, taskDTO.getStatus())) {
TransportOrderDTO transportOrderDTO = transportOrderFeign.findByOrderId(orderDTO.getId());
vo.setTransportOrderId(transportOrderDTO.getId());//运单id
}
//根据id查询省、市、区名称并拼接为完整地址
String senderAddress = getDetailAddress(orderDTO.getSenderProvinceId(), orderDTO.getSenderCityId(), orderDTO.getSenderCountyId(), orderDTO.getSenderAddress());
String receiverAddress = getDetailAddress(orderDTO.getReceiverProvinceId(), orderDTO.getReceiverCityId(), orderDTO.getReceiverCountyId(), orderDTO.getReceiverAddress());
vo.setSenderAddress(senderAddress);//寄件人地址
vo.setReceiverAddress(receiverAddress);//收件人地址
vo.setSenderCountyId(orderDTO.getSenderCountyId());//寄件地址id这里指的是区/县的地址ID
vo.setReceiverCountyId(orderDTO.getReceiverCountyId());//收件地址id这里指的是区/县的地址ID
return vo;
}
/**
* 身份验证
*
* @param vo 身份信息
* @return 是否通过验证
*/
@Override
public RealNameVerifyVO idCardCheck(TaskIdCardCheckVO vo) {
RealNameVerifyVO realNameVerifyVO = new RealNameVerifyVO();
realNameVerifyVO.setName(DesensitizedUtil.chineseName(vo.getName()));
realNameVerifyVO.setIdCard(DesensitizedUtil.idCardNum(vo.getIdCard(), 6, 4));
realNameVerifyVO.setSex(IdcardUtil.getGenderByIdCard(vo.getIdCard()));
realNameVerifyVO.setFlag(false);
//1.校验身份证号规则
if (!IdcardUtil.isValidCard(vo.getIdCard())) {
return realNameVerifyVO;
}
//2.实名认证(校验身份证号和姓名的一致性)
//实名认证收费,免费次数有限,请慎重使用
if (Boolean.parseBoolean(realNameVerify)) {
log.info("用户开始进行实名认证,姓名:{},身份证号:{}", vo.getName(), vo.getIdCard());
try {
if (!realNameVerifyService.realNameVerify(vo.getName(), vo.getIdCard())) {
return realNameVerifyVO;
}
} catch (IOException e) {
throw new SLWebException("实名认证方法执行失败");
}
}
realNameVerifyVO.setFlag(true);
return realNameVerifyVO;
}
/**
* 取件
*
* @param vo 取件对象
* @return 是否成功
*/
@Override
@GlobalTransactional
public boolean pickup(TaskPickupVO vo) {
log.info("取件信息:{}", vo);
//1.根据任务id查询取派件任务
PickupDispatchTaskDTO taskDTO = pickupDispatchTaskFeign.findById(Long.valueOf(vo.getId()));
if (ObjectUtil.notEqual(taskDTO.getStatus(), PickupDispatchTaskStatus.NEW)) {
throw new SLWebException("快递必须是未取状态!");
}
Long orderId = taskDTO.getOrderId();
//2.根据订单id查询订单
OrderDTO orderDB = orderFeign.findById(orderId);
//3.身份校验:先查询用户信息,若已实名认证直接放行;未实名认证必须进行认证
MemberDTO memberDto = memberFeign.detail(orderDB.getMemberId());//用户信息
if (!memberDto.getIdCardNoVerify().equals(MemberIdCardVerifyStatus.SUCCESS.getCode())) {
if (CharSequenceUtil.hasBlank(vo.getIdCard(), vo.getName())) {
throw new SLWebException("用户未实名认证,必须输入身份证号和姓名!");
}
TaskIdCardCheckVO taskIdCardCheckVO = BeanUtil.toBean(vo, TaskIdCardCheckVO.class);
RealNameVerifyVO realNameVerifyVO = idCardCheck(taskIdCardCheckVO);
if (Boolean.FALSE.equals(realNameVerifyVO.getFlag())) {
return false;
}
}
log.info("取件动作-身份校验通过");
//4.更新取派件任务
PickupDispatchTaskDTO pickupDispatchTaskDTO = pickupDispatchTaskFeign.findById(Long.valueOf(vo.getId()));
pickupDispatchTaskDTO.setStatus(PickupDispatchTaskStatus.COMPLETED);//任务状态
pickupDispatchTaskFeign.updateStatus(pickupDispatchTaskDTO);
//5.获取快递员信息
UserDTO userDTO = AuthTemplateThreadLocal.get().opsForUser().getUserById(UserThreadLocal.getUserId()).getData();
//6.构建更新订单消息数据
OrderPickupDTO orderPickupDTO = BeanUtil.toBean(vo, OrderPickupDTO.class);
orderPickupDTO.setId(orderId);
String orderPickupJson = JSONUtil.toJsonStr(orderPickupDTO);
//6.1更新订单相关信息
orderFeign.orderPickup(orderPickupDTO);
//7.发送取件成功的消息
String msg = CourierMsg.builder().orderId(orderId).courierId(userDTO.getId()).courierName(userDTO.getName()).courierMobile(userDTO.getMobile()).created(System.currentTimeMillis())
//更新订单消息放到扩展信息中,需要的业务再处理,不需要的忽略即可
.info(orderPickupJson).build().toJson();
this.mqFeign.sendMsg(Constants.MQ.Exchanges.COURIER, Constants.MQ.RoutingKeys.COURIER_PICKUP, msg);
return true;
}
/**
* 批量转单
*
* @param dto 转单对象
*/
@Override
public void batchTransfer(TaskBatchTransferVO dto) {
//1.获取当前用户id
Long userId = UserThreadLocal.getUserId();
//2.根据任务ids查询任务列表
List<Long> idList = dto.getIdList().stream().map(Long::valueOf).collect(Collectors.toList());
//3.批量修改取派件任务快递员id
pickupDispatchTaskFeign.updateCourierId(idList, userId, Long.valueOf(dto.getAnotherCourierId()));
}
/**
* 取消任务
*
* @param vo 取消任务对象
*/
@Override
@GlobalTransactional
public void cancel(TasksCancelVO vo) {
//1.更新任务
PickupDispatchTaskDTO taskDTO = pickupDispatchTaskFeign.findById(Long.valueOf(vo.getId()));
taskDTO.setStatus(PickupDispatchTaskStatus.CANCELLED);//取消状态
taskDTO.setCancelReason(vo.getReason());//取消原因
taskDTO.setCancelReasonDescription(vo.getReasonDesc());//取消原因具体描述
pickupDispatchTaskFeign.updateStatus(taskDTO);
//2.存储签收消息
//2.1查询订单详情
OrderDTO orderDTO = orderFeign.findById(taskDTO.getOrderId());
//2.2组装消息内容
Map<String, String> stringMap = this.getNameAndPhoneAndAddress(TaskInformationEnum.codeOf(taskDTO.getTaskType().getCode()), orderDTO);
String content = CharSequenceUtil.format("地址:{},寄件人:{},电话:{}", stringMap.get(CourierConstants.OrderInfo.ADDRESS), stringMap.get(CourierConstants.OrderInfo.NAME), stringMap.get(CourierConstants.OrderInfo.ADDRESS));
//2.2构建消息对象
MessageAddDTO messageAddDTO = MessageAddDTO.builder()
.title(MessageConstants.MessageTitle.CANCEL)
.content(content)
.bussinessType(MessageBussinessTypeEnum.COURIER.getCode())
.userId(taskDTO.getCourierId())
.contentType(MessageContentTypeEnum.COURIER_CANCEL.getCode())
.relevantId(taskDTO.getId())
.createUser(UserThreadLocal.getUserId())
.updateUser(UserThreadLocal.getUserId())
.build();
messageFeign.add(messageAddDTO);
}
/**
* 删除任务(逻辑删除)
*
* @param id 任务id
*/
@Override
public void delete(String id) {
//1.逻辑删除
pickupDispatchTaskFeign.deleteByIds(Collections.singletonList(Long.valueOf(id)));
}
/**
* 批量删除任务
*
* @param taskBatchVO 任务id列表
*/
@Override
public void batchDelete(TaskBatchVO taskBatchVO) {
//1.将id转换为long类型形成列表
List<Long> ids = taskBatchVO.getIdList().stream().map(Long::valueOf).collect(Collectors.toList());
//2.批量逻辑删除
pickupDispatchTaskFeign.deleteByIds(ids);
}
/**
* 签收任务
*
* @param vo 签收对象
*/
@Override
public void sign(TaskSignVO vo) {
//1.更新任务
PickupDispatchTaskDTO taskDTO = pickupDispatchTaskFeign.findById(Long.valueOf(vo.getId()));
if (ObjectUtil.notEqual(taskDTO.getSignStatus(), PickupDispatchTaskSignStatus.NOT_SIGNED)) {
throw new SLWebException("快递已签收/拒收");
}
taskDTO.setStatus(PickupDispatchTaskStatus.COMPLETED);//任务状态
taskDTO.setSignStatus(PickupDispatchTaskSignStatus.RECEIVED);//签收状态(1为已签收2为拒收)
taskDTO.setSignRecipient(SignRecipientEnum.codeOf(vo.getSignRecipient()));//签收人1-本人2-代收
pickupDispatchTaskFeign.updateStatus(taskDTO);
//2.更新订单
OrderDTO orderDTO = orderFeign.findById(taskDTO.getOrderId());
orderDTO.setStatus(OrderStatus.RECEIVED.getCode());
orderFeign.updateById(taskDTO.getOrderId(), orderDTO);
//3.存储签收消息
//判断派件任务需要获取的是寄件人信息还是收件人信息
//拒签情况下,同一个订单会产生两个派件任务。正常派件任务是派给收件人,拒签后的派件任务是派给寄件人
//通过TaskInformationEnum设置取寄件人信息还是收件人信息。只有是正常的派件任务是目标是收件人其余均是寄件人
TaskInformationEnum flag = TaskInformationEnum.SEND;
List<PickupDispatchTaskDTO> pickupDispatchTaskDTOS = pickupDispatchTaskFeign.findByOrderId(taskDTO.getOrderId(), PickupDispatchTaskType.DISPATCH);
//pickupDispatchTaskDTOS是按创建时间正序排序的第一条数据是正常的派件任务
if (pickupDispatchTaskDTOS.get(0).getId().equals(taskDTO.getId())) {
flag = TaskInformationEnum.RECEIVE;
}
//3.1组装消息内容
Map<String, String> stringMap = this.getNameAndPhoneAndAddress(flag, orderDTO);
String content = CharSequenceUtil.format("地址:{},收件人:{},电话:{}", stringMap.get(CourierConstants.OrderInfo.ADDRESS), stringMap.get(CourierConstants.OrderInfo.NAME), stringMap.get(CourierConstants.OrderInfo.PHONE));
//3.2构建消息对象
MessageAddDTO messageAddDTO = MessageAddDTO.builder()
.title(MessageConstants.MessageTitle.SIGN)
.content(content)
.bussinessType(MessageBussinessTypeEnum.COURIER.getCode())
.userId(taskDTO.getCourierId())
.contentType(MessageContentTypeEnum.COURIER_SIGN.getCode())
.relevantId(taskDTO.getId())
.createUser(UserThreadLocal.getUserId())
.updateUser(UserThreadLocal.getUserId())
.build();
messageFeign.add(messageAddDTO);
//4.发送运单跟踪消息
//4.1获取快递员信息
UserDTO userDTO = AuthTemplateThreadLocal.get().opsForUser().getUserById(UserThreadLocal.getUserId()).getData();
String info = CharSequenceUtil.format("您的快递已签收,如有疑问请联系快递员【{},电话{}】,感谢您使用神领快递,期待再次为您服务", userDTO.getName(), userDTO.getMobile());
//4.2查询运单
TransportOrderDTO transportOrderDTO = transportOrderFeign.findByOrderId(orderDTO.getId());
//4.3构建消息实体类
TransportInfoMsg transportInfoMsg = TransportInfoMsg.builder().transportOrderId(transportOrderDTO.getId())//运单id
.status("已签收")//消息状态
.info(info)//消息详情
.created(DateUtil.current())//创建时间
.build();
//4.4发送消息
this.mqFeign.sendMsg(Constants.MQ.Exchanges.TRANSPORT_INFO, Constants.MQ.RoutingKeys.TRANSPORT_INFO_APPEND, transportInfoMsg.toJson());
//5.发送完成轨迹消息
TransportOrderStatusMsg transportOrderStatusMsg = TransportOrderStatusMsg.builder()
.idList(List.of(transportOrderDTO.getId()))
.build();
this.mqFeign.sendMsg(Constants.MQ.Exchanges.TRANSPORT_ORDER_DELAYED, Constants.MQ.RoutingKeys.TRANSPORT_ORDER_UPDATE_STATUS_PREFIX + "RECEIVED", transportOrderStatusMsg.toJson());
}
/**
* 拒收任务
*
* @param id 任务id
*/
@Override
public void reject(String id) {
//1.状态校验
PickupDispatchTaskDTO taskDTO = pickupDispatchTaskFeign.findById(Long.valueOf(id));
if (ObjectUtil.notEqual(taskDTO.getSignStatus(), PickupDispatchTaskSignStatus.NOT_SIGNED)) {
throw new SLWebException("快递已签收/拒收");
}
TransportOrderDTO transportOrderDTO = transportOrderFeign.findByOrderId(taskDTO.getOrderId());
if (ObjectUtil.equal(transportOrderDTO.getIsRejection(), true)) {
throw new SLWebException("快递已被收件人拒收,不能再次拒收!");
}
//2.更新任务
taskDTO.setStatus(PickupDispatchTaskStatus.COMPLETED);//任务状态
taskDTO.setSignStatus(PickupDispatchTaskSignStatus.REJECTION);//签收状态(1为已签收2为拒收)
taskDTO.setActualEndTime(LocalDateTime.now());//实际完成时间
pickupDispatchTaskFeign.updateStatus(taskDTO);
//3.更新订单
OrderDTO orderDTO = orderFeign.findById(taskDTO.getOrderId());
orderDTO.setStatus(OrderStatus.REJECTION.getCode());
orderFeign.updateById(taskDTO.getOrderId(), orderDTO);
//4.更新运单状态为 拒收
transportOrderFeign.updateStatus(transportOrderDTO.getId(), TransportOrderStatus.REJECTED);
//5.发送运单跟踪消息
//5.1获取快递员信息
UserDTO userDTO = AuthTemplateThreadLocal.get().opsForUser().getUserById(UserThreadLocal.getUserId()).getData();
String info = CharSequenceUtil.format("您的快递已拒收,快递将返回到网点,如有疑问请电联快递员【联系人{},电话:{}】", userDTO.getName(), userDTO.getMobile());
//5.2构建消息实体类
TransportInfoMsg transportInfoMsg = TransportInfoMsg.builder().transportOrderId(transportOrderDTO.getId()).status("已拒收").info(info).created(DateUtil.current()).build();
//5.3发送消息
this.mqFeign.sendMsg(Constants.MQ.Exchanges.TRANSPORT_INFO, Constants.MQ.RoutingKeys.TRANSPORT_INFO_APPEND, transportInfoMsg.toJson());
}
/**
* 运单跟踪
*
* @param id 运单id
* @return 运单跟踪信息
*/
@Override
public List<TransportOrderPointVO> tracks(String id) {
//1.调用transport-info接口获取相关运单的追踪信息
TransportInfoDTO transportInfoDTO = transportInfoFeign.queryByTransportOrderId(id);
if (ObjectUtil.hasEmpty(transportInfoDTO, transportInfoDTO.getInfoList())) {
return Collections.emptyList();
}
//2.解析运单追踪信息封装到vo
return transportInfoDTO.getInfoList().stream().map(x -> {
TransportOrderPointVO vo = BeanUtil.toBean(x, TransportOrderPointVO.class);
vo.setCreated(LocalDateTimeUtil.of(x.getCreated()));
return vo;
}).collect(Collectors.toList());
}
/**
* 今日任务数据统计
*
* @return 今日任务统计数据
*/
@Override
public TaskStatisticsVO taskStatistics() {
//1.当前用户id
Long userId = UserThreadLocal.getUserId();
//2.当前用户任务统计
PickupDispatchTaskStatisticsDTO taskStatisticsDTO = pickupDispatchTaskFeign.todayTasksStatistics(userId);
return BeanUtil.toBean(taskStatisticsDTO, TaskStatisticsVO.class);
}
/**
* 最近查找redis存取前缀
*/
private static final String RECENT_SEARCH_PREFIX = "RECENT_SEARCH:";
/**
* 展示最近查找运单号
*
* @return 最近查找运单号
*/
@Override
public List<String> recentSearch() {
//1.构建redisKey
Long userId = UserThreadLocal.get().getUserId();
String redisKey = RECENT_SEARCH_PREFIX + userId;
//2.查找所有
List<String> jsonList = stringRedisTemplate.opsForList().range(redisKey, 0, -1);
if (jsonList == null) {
return new ArrayList<>();
}
//3.json转为对象
List<RecentSearchVO> list = jsonList.stream().map(json -> JSONUtil.toBean(json, RecentSearchVO.class)).collect(Collectors.toList());
//4.过滤1个月以内的运单号并返回
return list.stream().filter(vo -> vo.getCreated().plusMonths(1).isAfter(LocalDateTime.now())).map(RecentSearchVO::getTransportOrderId).collect(Collectors.toList());
}
/**
* 标记为最近查找
*
* @param transportOrderId 运单号
*/
@Override
public void markRecent(String transportOrderId) {
//1.构建redisKey
Long userId = UserThreadLocal.get().getUserId();
String redisKey = RECENT_SEARCH_PREFIX + userId;
//2.构建新增对象
RecentSearchVO recentSearchVO = RecentSearchVO.builder().transportOrderId(transportOrderId).created(LocalDateTime.now()).build();
//3.查询当前运单id在redis中存储位置
List<String> jsonList = stringRedisTemplate.opsForList().range(redisKey, 0, -1);
//4.1如果redis为空直接新增
if (jsonList == null) {
//新增一条元素
stringRedisTemplate.opsForList().leftPush(redisKey, JSONUtil.toJsonStr(recentSearchVO));
} else {
//4.2如果redis不为空需要判断运单号是否已经存储到redis
List<RecentSearchVO> recentSearchList = jsonList.stream().map(json -> JSONUtil.toBean(json, RecentSearchVO.class)).collect(Collectors.toList());
List<String> transportOrderIds = recentSearchList.stream().map(RecentSearchVO::getTransportOrderId).collect(Collectors.toList());
//匹配运单号,匹配不到返回-1匹配到返回索引位置
int index = transportOrderIds.indexOf(transportOrderId);
if (ObjectUtil.equal(index, -1) && ObjectUtil.equal(jsonList.size(), 10)) {
//4.2.1如果redis中不存在该运单id且数据已满10条需要先删除最后一条
stringRedisTemplate.opsForList().rightPop(redisKey);
} else if (ObjectUtil.notEqual(index, -1)) {
//4.2.2如果redis中存在该运单id则先删除该项数据
String jsonStr = JSONUtil.toJsonStr(recentSearchList.get(index));
stringRedisTemplate.opsForList().remove(redisKey, 0, jsonStr);
}
//新增一条元素
stringRedisTemplate.opsForList().leftPush(redisKey, JSONUtil.toJsonStr(recentSearchVO));
}
}
/**
* 清空最近查找
*/
@Override
public void recentSearchDeleteAll() {
//1.构建redisKey
Long userId = UserThreadLocal.get().getUserId();
String redisKey = RECENT_SEARCH_PREFIX + userId;
//2.清空所有
stringRedisTemplate.delete(redisKey);
}
/**
* 搜索任务
*
* @param taskSearchVO 搜索条件
* @return 分页结果
*/
@Override
public PageResponse<TaskVO> search(TaskSearchVO taskSearchVO) {
//1.构建查询对象
Long userId = UserThreadLocal.get().getUserId();
CourierTaskPageQueryDTO courierTaskPageQueryDTO = BeanUtil.toBean(taskSearchVO, CourierTaskPageQueryDTO.class);
courierTaskPageQueryDTO.setCourierId(userId);
//2.搜索微服务查询
PageResponse<CourierTaskDTO> pageResponse = courierTaskFeign.pageQuery(courierTaskPageQueryDTO);
if (ObjectUtil.isEmpty(pageResponse.getItems())) {
return new PageResponse<>();
}
//3.根据取派件id列表查询取派件任务
List<Long> courierTaskIds = pageResponse.getItems().stream().map(CourierTaskDTO::getId).collect(Collectors.toList());
List<PickupDispatchTaskDTO> pickupDispatchTaskDTOS = pickupDispatchTaskFeign.findByIds(courierTaskIds);
//4.将订单、运单相关数据封装
List<String> orderIds = pickupDispatchTaskDTOS.stream().map(task -> task.getOrderId().toString()).collect(Collectors.toList());
List<OrderDTO> orderDTOS = orderFeign.findByIds(orderIds);
Map<Long, OrderDTO> orderMap = orderDTOS.stream().collect(Collectors.toMap(OrderDTO::getId, order -> order));
List<TaskVO> taskVOList = pickupDispatchTaskDTOS.stream().map(task -> getTaskVO(task, orderMap)).collect(Collectors.toList());
//5.设置任务时间
this.setTaskTime(taskSearchVO.getStatus(), taskVOList);
//6.计算距离:待取件和待派件需要计算距离
this.computeDistance(taskSearchVO.getLongitude(), taskSearchVO.getLatitude(), taskVOList);
//7.按照任务时间排序
CollUtil.sort(taskVOList, Comparator.comparing(TaskVO::getTaskTime));
//8.分页结果封装
return PageResponse.of(taskVOList, pageResponse.getPage(), pageResponse.getPageSize(), pageResponse.getPages(), pageResponse.getCounts());
}
}

View File

@@ -0,0 +1,67 @@
package com.sl.ms.web.courier.service.impl;
import cn.hutool.core.collection.CollUtil;
import com.sl.ms.track.api.TrackFeign;
import com.sl.ms.web.courier.service.TrackService;
import com.sl.ms.work.api.PickupDispatchTaskFeign;
import com.sl.ms.work.api.TransportOrderFeign;
import com.sl.ms.work.domain.dto.PickupDispatchTaskDTO;
import com.sl.ms.work.domain.dto.TransportOrderDTO;
import com.sl.ms.work.domain.dto.request.PickupDispatchTaskPageQueryDTO;
import com.sl.ms.work.domain.enums.pickupDispatchtask.PickupDispatchTaskStatus;
import com.sl.ms.work.domain.enums.pickupDispatchtask.PickupDispatchTaskType;
import com.sl.transport.common.util.PageResponse;
import com.sl.transport.common.util.UserThreadLocal;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;
@Service
public class TrackServiceImpl implements TrackService {
@Resource
private TrackFeign trackFeign;
@Resource
private PickupDispatchTaskFeign pickupDispatchTaskFeign;
@Resource
private TransportOrderFeign transportOrderFeign;
/**
* 快递员上报位置
*
* @param lng 经度
* @param lat 纬度
*/
@Override
public Boolean uploadLocation(String lng, String lat) {
//1. 获取当前用户id
Long userId = UserThreadLocal.getUserId();
//2. 根据快递员id查询关联的新建状态派件任务
PickupDispatchTaskPageQueryDTO pageQueryDTO = PickupDispatchTaskPageQueryDTO.builder()
.page(1)
.pageSize(999)
.courierId(userId)
//新建取件任务时,还未生成运单,所以只查询新建的派件任务。也只能上报派件任务的快递员位置
.taskType(PickupDispatchTaskType.DISPATCH)
.status(PickupDispatchTaskStatus.NEW)
.build();
PageResponse<PickupDispatchTaskDTO> pageResponse = pickupDispatchTaskFeign.findByPage(pageQueryDTO);
if (CollUtil.isEmpty(pageResponse.getItems())) {
return true;
}
//3. 从取派件任务中提取订单号
Long[] orderIds = pageResponse.getItems().parallelStream().map(PickupDispatchTaskDTO::getOrderId).toArray(Long[]::new);
//4. 根据订单id查询运单
List<TransportOrderDTO> transportOrderDTOS = transportOrderFeign.findByOrderIds(orderIds);
//5. 从运单中提取运单号
List<String> transportOrderIds = transportOrderDTOS.parallelStream().map(TransportOrderDTO::getId).collect(Collectors.toList());
//6. 上报位置
return trackFeign.uploadFromCourier(transportOrderIds, Double.parseDouble(lng), Double.parseDouble(lat));
}
}

View File

@@ -0,0 +1,130 @@
package com.sl.ms.web.courier.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.ObjectUtil;
import com.itheima.auth.sdk.dto.UserDTO;
import com.sl.ms.base.api.common.WorkSchedulingFeign;
import com.sl.ms.base.domain.base.WorkSchedulingDTO;
import com.sl.ms.base.domain.enums.WorkUserTypeEnum;
import com.sl.ms.scope.api.ServiceScopeFeign;
import com.sl.ms.scope.dto.ServiceScopeDTO;
import com.sl.ms.web.courier.service.UserService;
import com.sl.ms.web.courier.vo.user.ServiceScopeVO;
import com.sl.ms.web.courier.vo.user.UserSimpleInfoVO;
import com.sl.ms.web.courier.vo.user.UsersInfoVO;
import com.sl.transport.common.util.AuthTemplateThreadLocal;
import com.sl.transport.common.util.PageResponse;
import com.sl.transport.common.util.UserThreadLocal;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.stream.Collectors;
@Service
@Slf4j
public class UserServiceImpl implements UserService {
@Resource
private WorkSchedulingFeign workSchedulingFeign;
@Resource
private ServiceScopeFeign serviceScopeFeign;
/**
* 通过token获取用户信息
*
* @return 用户信息
*/
@Override
public UsersInfoVO get() {
//获取快递员详细信息
UserDTO userDTO = AuthTemplateThreadLocal.get().opsForUser().getUserById(UserThreadLocal.getUserId()).getData();
WorkSchedulingDTO workSchedulingDTO = workSchedulingFeign.currentSchedule(userDTO.getId());
//组装vo
UsersInfoVO vo = BeanUtil.toBean(userDTO, UsersInfoVO.class);
vo.setPhone(userDTO.getMobile());//手机号码
vo.setAgencyName(userDTO.getOrgName());//所在网点
if (ObjectUtil.isNotEmpty(workSchedulingDTO) && ObjectUtil.notEqual(workSchedulingDTO.getWorkPatternId(), 0L)) {
vo.setStartTime(LocalDateTime.of(LocalDate.now(), LocalTime.MIN).plusMinutes(workSchedulingDTO.getWorkStartMinute1()));//上班时间
vo.setEndTime(LocalDateTime.of(LocalDate.now(), LocalTime.MIN).plusMinutes(workSchedulingDTO.getWorkEndMinute1()));//下班时间
}
return vo;
}
/**
* 查询今天同网点有排班的其他快递员列表
*
* @param page 页码
* @param pageSize 页面大小
* @param keyword 关键词
* @return 快递员列表
*/
@Override
public PageResponse<UserSimpleInfoVO> sameAgency(Integer page, Integer pageSize, String keyword) {
//1.获取快递员详细信息
UserDTO userDTO = AuthTemplateThreadLocal.get().opsForUser().getUserById(UserThreadLocal.getUserId()).getData();
log.info("快递员详细信息:{}", userDTO);
//2.获取同网点今天有排班的员工
List<WorkSchedulingDTO> workSchedulingDTOList = workSchedulingFeign.monthScheduleByAgencyId(userDTO.getOrgId());
log.info("同网点今天有排班的员工位数:{}", CollUtil.isEmpty(workSchedulingDTOList) ? 0 : workSchedulingDTOList.size());
if (ObjectUtil.isEmpty(workSchedulingDTOList)) {
return new PageResponse<>();
}
//4.筛选出今天同网点的有排班的其他快递员并封装为vo
List<UserSimpleInfoVO> userSimpleInfoVOList = workSchedulingDTOList.stream()
.filter(x -> ObjectUtil.equal(x.getUserType().intValue(), WorkUserTypeEnum.COURIER.getCode())//快递员角色
&& ObjectUtil.notEqual(x.getUserId(), userDTO.getId()))//不是当前快递员
.map(x -> BeanUtil.toBean(x, UserSimpleInfoVO.class))
.collect(Collectors.toList());
log.info("今天同网点的有排班的其他快递员位数:{}", CollUtil.isEmpty(userSimpleInfoVOList) ? 0 : userSimpleInfoVOList.size());
if (ObjectUtil.isEmpty(userSimpleInfoVOList)) {
return new PageResponse<>();
}
//5.根据关键词筛选
if (CharSequenceUtil.isNotBlank(keyword)) {
userSimpleInfoVOList = userSimpleInfoVOList.stream()
.filter(x -> x.getEmployeeNumber().contains(keyword)
|| x.getName().contains(keyword))
.collect(Collectors.toList());
}
//6.进行分页
int startPosition = (page - 1) * pageSize;//起始位置
long pageCounts = userSimpleInfoVOList.size();//总条目数
long pages = (long) Math.ceil(pageCounts * 1.0 / pageSize);//总页数
//6.1根据起始位置和页面大小取当前页面数据列表
userSimpleInfoVOList = userSimpleInfoVOList.stream()
.skip(startPosition)
.limit(pageSize)
.collect(Collectors.toList());
//6.2.返回分页结果
return PageResponse.<UserSimpleInfoVO>builder()
.items(userSimpleInfoVOList)//数据列表
.pages(pages)//总条目数
.counts(pageCounts)//总页数
.build();
}
/**
* 获取作业范围
*
* @return 作业范围数据
*/
@Override
public ServiceScopeVO findScope() {
ServiceScopeDTO serviceScopeDTO = serviceScopeFeign.queryServiceScope(UserThreadLocal.getUserId(), 2);
return BeanUtil.toBean(serviceScopeDTO, ServiceScopeVO.class);
}
}

View File

@@ -0,0 +1,19 @@
package com.sl.ms.web.courier.vo.area;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "行政区域简要信息")
public class AreaSimpleVO {
@ApiModelProperty(value = "id")
private Long id;
@ApiModelProperty(value = "行政名称")
private String name;
@ApiModelProperty(value = "经度")
private String lng;
@ApiModelProperty(value = "纬度")
private String lat;
}

View File

@@ -0,0 +1,19 @@
package com.sl.ms.web.courier.vo.login;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@ApiModel("账号登录")
@Data
public class AccountLoginVO {
@ApiModelProperty(value = "登录账号", required = true)
@NotNull(message = "登录账号不能为空")
private String account;
@ApiModelProperty(value = "登录密码", required = true)
@NotNull(message = "登录密码不能为空")
private String password;
}

View File

@@ -0,0 +1,16 @@
package com.sl.ms.web.courier.vo.login;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@ApiModel("登录返回信息")
@NoArgsConstructor
@AllArgsConstructor
public class LoginVO {
@ApiModelProperty("用户登录token")
private String token;
}

View File

@@ -0,0 +1,23 @@
package com.sl.ms.web.courier.vo.message;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
@ApiModel("消息分页查询")
public class MessageQueryVO {
@ApiModelProperty("消息类型300快递员端公告301寄件相关消息302签收相关消息303快件取消消息,304:派件相关消息")
private Integer contentType;
@ApiModelProperty(value = "页码", example = "1",required = true)
@NotNull(message = "页码不能为空!")
private Integer page;
@ApiModelProperty(value = "页面大小", example = "10",required = true)
@NotNull(message = "页面大小不能为空")
private Integer pageSize;
}

View File

@@ -0,0 +1,41 @@
package com.sl.ms.web.courier.vo.message;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDateTime;
@ApiModel("消息列表")
@Data
public class MessageVO {
@ApiModelProperty("消息id")
private Long id;
@ApiModelProperty("消息标题")
private String title;
@ApiModelProperty("消息内容")
private String content;
@ApiModelProperty(value = "1用户端2司机端3快递员端4后台管理系统")
private Integer bussinessType;
@ApiModelProperty("消息接受者")
private Long userId;
@ApiModelProperty("消息类型300快递员端公告301寄件相关消息302签收相关消息303快件取消消息200司机端公告201司机端系统通知")
private Integer contentType;
@ApiModelProperty("消息是否已读0未读1已读")
private Integer isRead;
@ApiModelProperty("读时间")
private LocalDateTime readTime;
@ApiModelProperty("相关id")
private Long relevantId;
@ApiModelProperty("创建时间")
private LocalDateTime created;
}

View File

@@ -0,0 +1,24 @@
package com.sl.ms.web.courier.vo.message;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel("首页消息相关模型")
@Data
public class MessagesHomeVO {
@ApiModelProperty("多少分钟前的订单")
private Integer minutes;
@ApiModelProperty("当前是否有未读消息")
private Boolean unRead;
@ApiModelProperty("新消息")
private int newsNum;
@ApiModelProperty("最新信息")
private String recentMsg;
@ApiModelProperty("消息类型300快递员端公告301寄件相关消息302签收相关消息303快件取消消息")
private Integer contentType;
}

View File

@@ -0,0 +1,35 @@
package com.sl.ms.web.courier.vo.message;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@ApiModel("新系统通知信息")
public class NewNoticeInfoVO {
@ApiModelProperty("是否有新的寄件消息")
private Boolean haveNewSendNotice;
@ApiModelProperty("新寄件消息时间")
private LocalDateTime newSendNoticeTime;
@ApiModelProperty("是否有新的签收消息")
private Boolean haveNewReceiveNotice;
@ApiModelProperty("新签收消息时间")
private LocalDateTime newReceiveNoticeTime;
@ApiModelProperty("是否有快件取消消息")
private Boolean haveNewCancelNotice;
@ApiModelProperty("新快件取消消息时间")
private LocalDateTime newCancelNoticeTime;
@ApiModelProperty("是否有派件消息")
private Boolean haveNewDispatchNotice;
@ApiModelProperty("新派件消息时间")
private LocalDateTime newDispatchNoticeTime;
}

View File

@@ -0,0 +1,25 @@
package com.sl.ms.web.courier.vo.pay;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.DecimalMin;
import java.math.BigDecimal;
@Data
@ApiModel("支付发起对象")
public class TradeLaunchVO {
@ApiModelProperty(value = "订单号", required = true)
private String productOrderNo;
@ApiModelProperty(value = "支付渠道,1-支付宝2-微信支付;默认为2", required = true, example = "2")
private Integer payMethod = 2;
@ApiModelProperty(value = "交易金额,单位:元", required = true)
@DecimalMin("0.01")
private BigDecimal tradingAmount;
@ApiModelProperty(value = "备注,如:运费", required = true)
private String memo = "金额";
}

View File

@@ -0,0 +1,15 @@
package com.sl.ms.web.courier.vo.pay;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel("支付二维码相关数据")
public class TradeResponseVO {
@ApiModelProperty(value = "二维码base64数据")
private String qrCode;
@ApiModelProperty(value = "交易系统订单号【对于三方来说:商户订单】")
private Long tradingOrderNo;
}

View File

@@ -0,0 +1,48 @@
package com.sl.ms.web.courier.vo.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@Data
@ApiModel("运费计算条件")
public class CarriageCalculateVO {
@ApiModelProperty(value = "寄件地址id这里指的是区/县的地址ID", required = true)
@NotNull(message = "寄件地址没有选择")
private Long senderCountyId;
@ApiModelProperty(value = "收件地址id这里指的是区/县的地址ID", required = true)
@NotNull(message = "收件地址没有选择")
private Long receiverCountyId;
@ApiModelProperty(value = "重量单位kg", required = true)
@NotNull(message = "运费不能为空")
@Min(value = 0L, message = "重点不能小于0")
private BigDecimal weight;
@ApiModelProperty(value = "单位cm")
@Min(value = 1, message = "长度最小为1")
@Max(value = 999, message = "长度最大为999")
private Integer measureLong;
@ApiModelProperty(value = "单位cm")
@Min(value = 1, message = "宽度最小为1")
@Max(value = 999, message = "宽度最大为999")
private Integer measureWidth;
@ApiModelProperty(value = "单位cm")
@Min(value = 1, message = "高度最小为1")
@Max(value = 999, message = "高度最大为999")
private Integer measureHigh;
@ApiModelProperty(value = "体积单位cm^3", required = true)
@Min(value = 1, message = "体积最小为1")
@Max(value = 99000000, message = "体积最大为999m^3")
private Integer volume;
}

View File

@@ -0,0 +1,26 @@
package com.sl.ms.web.courier.vo.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@Data
@ApiModel("运单费用查询结果")
public class CarriageVO {
@ApiModelProperty("重量")
private BigDecimal weight;
@ApiModelProperty("运费合计")
private String freight;
@ApiModelProperty(value = "首重价格", required = true)
private Double firstWeight;
@ApiModelProperty(value = "续重价格", required = true)
private Double continuousWeight;
}

View File

@@ -0,0 +1,23 @@
package com.sl.ms.web.courier.vo.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@ApiModel("实名认证结果")
public class RealNameVerifyVO {
@ApiModelProperty("姓名")
private String name;
@ApiModelProperty("身份证号")
private String idCard;
@ApiModelProperty("性别,1-男0-女")
private Integer sex;
@ApiModelProperty("是否通过实名认证")
private Boolean flag;
}

View File

@@ -0,0 +1,25 @@
package com.sl.ms.web.courier.vo.task;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class RecentSearchVO {
/**
* 运单id
*/
private String transportOrderId;
/**
* 创建时间
*/
private LocalDateTime created;
}

View File

@@ -0,0 +1,16 @@
package com.sl.ms.web.courier.vo.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel("批量转单")
public class TaskBatchTransferVO {
@ApiModelProperty("被转单快递员id")
private String anotherCourierId;
@ApiModelProperty("任务id列表")
private List<String> idList;
}

View File

@@ -0,0 +1,14 @@
package com.sl.ms.web.courier.vo.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
@Data
@ApiModel("任务id列表")
public class TaskBatchVO {
@ApiModelProperty(value = "id列表", required = true)
private List<String> idList;
}

View File

@@ -0,0 +1,19 @@
package com.sl.ms.web.courier.vo.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
@ApiModel("身份验证")
public class TaskIdCardCheckVO {
@ApiModelProperty(value = "姓名", required = true)
@NotBlank(message = "请输入您的姓名!")
private String name;
@ApiModelProperty(value = "身份证号", required = true)
@NotBlank(message = "请输入您的身份证号!")
private String idCard;
}

View File

@@ -0,0 +1,90 @@
package com.sl.ms.web.courier.vo.task;
import com.sl.ms.work.domain.enums.pickupDispatchtask.PickupDispatchTaskAssignedStatus;
import com.sl.ms.work.domain.enums.pickupDispatchtask.PickupDispatchTaskSignStatus;
import com.sl.ms.work.domain.enums.pickupDispatchtask.PickupDispatchTaskStatus;
import com.sl.ms.work.domain.enums.pickupDispatchtask.PickupDispatchTaskType;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
@ApiModel("任务详细新消息")
public class TaskInfoVO {
@ApiModelProperty("任务id")
private String id;
@ApiModelProperty("订单号")
private String orderId;
@ApiModelProperty("运单id")
private String transportOrderId;
@ApiModelProperty(value = "任务类型1为取件任务2为派件任务")
private PickupDispatchTaskType taskType;
@ApiModelProperty("任务状态1为新任务、2为已完成、3为已取消")
private PickupDispatchTaskStatus status;
@ApiModelProperty("任务分配状态(2已分配3待人工分配)")
private PickupDispatchTaskAssignedStatus assignedStatus;
@ApiModelProperty(value = "签收状态(1为已签收2为拒收)")
private PickupDispatchTaskSignStatus signStatus;
@ApiModelProperty("寄件人姓名")
private String senderName;
@ApiModelProperty("寄件人手机号")
private String senderPhone;
@ApiModelProperty("寄件人详细地址")
private String senderAddress;
@ApiModelProperty("收件人姓名")
private String receiverName;
@ApiModelProperty("收件人手机号")
private String receiverPhone;
@ApiModelProperty("收件人地址")
private String receiverAddress;
@ApiModelProperty("物品类型")
private String goodsType;
@ApiModelProperty("重量单位kg")
private BigDecimal weight;
@ApiModelProperty("体积,单位:立方米")
private BigDecimal volume;
@ApiModelProperty("运费合计")
private String freight;
@ApiModelProperty("备注")
private String remark;
@ApiModelProperty("付款方式,1寄付2到付")
private Integer paymentMethod;
@ApiModelProperty("付款状态,1未付2已付")
private Integer paymentStatus;
@ApiModelProperty("签收人1本人2代收")
private Integer signRecipient;
@ApiModelProperty(value = "寄件地址id这里指的是区/县的地址ID")
private Long senderCountyId;
@ApiModelProperty(value = "收件地址id这里指的是区/县的地址ID")
private Long receiverCountyId;
@ApiModelProperty(value = "身份证号是否验证0未验证 1验证通过 2验证未通过")
private Integer idCardNoVerify;
@ApiModelProperty(value = "身份证号")
private String idCardNo;
}

View File

@@ -0,0 +1,38 @@
package com.sl.ms.web.courier.vo.task;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sl.transport.common.util.DateUtils;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@ApiModel("取件派件任务模型")
public class TaskListVO {
@ApiModelProperty("取件派件任务id")
private String id;
@ApiModelProperty("运单id")
private Long transportOrderId;
@ApiModelProperty("任务类型:1:代表取件2派件")
private Integer type;
@ApiModelProperty("任务时间,如果是取件理解为取件开始时间,如果是派件理解为派件时间,主要用来排序")
@JsonFormat(pattern = DateUtils.DEFAULT_DATE_TIME_FORMAT, timezone = DateUtils.TIME_ZONE_8)
private LocalDateTime taskTime;
@ApiModelProperty("地址,这里不带省市区")
private String addressDetail;
@ApiModelProperty("寄件人")
private String senderName;
@ApiModelProperty("收件人")
private String receiverName;
@ApiModelProperty("距离,单位公里,待取件或者待派送才会计算距离")
private Double distance;
@ApiModelProperty("取件预约时间,格式05-03 10:00 至 11:00")
private String appointmentTime;
@ApiModelProperty("手机号")
private String phone;
@ApiModelProperty("取件超时时间或派件超时时间,可用于筛选即将要超时的订单")
@JsonFormat(pattern = DateUtils.DEFAULT_DATE_TIME_FORMAT, timezone = DateUtils.TIME_ZONE_8)
private LocalDateTime overTime;
}

View File

@@ -0,0 +1,45 @@
package com.sl.ms.web.courier.vo.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.NotNull;
import java.math.BigDecimal;
@Data
@ApiModel("取件模型")
public class TaskPickupVO {
@ApiModelProperty(value = "取件任务id", required = true)
private String id;
@ApiModelProperty(value = "物品名称")
private String goodName;
@ApiModelProperty(value = "体积单位m^3", required = true)
private BigDecimal volume;
@ApiModelProperty(value = "重量单位kg", required = true)
private BigDecimal weight;
@ApiModelProperty("备注")
private String remark;
@ApiModelProperty(value = "付款方式,1.寄付2到付", required = true)
@NotNull(message = "付款方式不能为空!")
@Range(min = 1, max = 2, message = "付款方式只能取1或2")
private Integer payMethod;
@ApiModelProperty(value = "金额", required = true)
@NotNull(message = "金额不能为空!")
@DecimalMin(value = "0.01", message = "金额必须>=0.01")
private BigDecimal amount;
@ApiModelProperty("身份证号")
private String idCard;
@ApiModelProperty(value = "姓名")
private String name;
}

View File

@@ -0,0 +1,57 @@
package com.sl.ms.web.courier.vo.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.hibernate.validator.constraints.Range;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
@Data
@ApiModel("任务查询对象")
public class TaskQueryVO {
@ApiModelProperty(value = "经度", required = true, example = "116.372809")
@NotNull(message = "经度不能为空!")
private Double longitude;
@ApiModelProperty(value = "纬度", required = true, example = "40.062595")
@NotNull(message = "纬度不能为空!")
private Double latitude;
@ApiModelProperty(value = "页码", required = true)
@NotNull(message = "页码不能为空!")
private Integer page;
@ApiModelProperty(value = "页面大小", required = true)
@NotNull(message = "页面大小不能为空!")
private Integer pageSize;
@ApiModelProperty(value = "任务状态1待取件2已取件3已取消4待派件5已签收")
private Integer taskStatus;
@ApiModelProperty(value = "任务类型1为取件任务2为派件任务")
@Range(min = 1, max = 2, message = "任务类型取值范围1-2")
private Integer taskType;
@ApiModelProperty(value = "任务状态1为新任务、2为已完成、3为已取消")
@Range(min = 1, max = 3, message = "任务状态取值范围1-3")
private Integer status;
@ApiModelProperty(value = "距离排序1升序2降序")
@Range(min = 1, max = 2, message = "距离排序取值范围1-2")
private Integer orderDistance;
@ApiModelProperty(value = "时间排序1升序2降序")
@Range(min = 1, max = 2, message = "时间排序取值范围1-2")
private Integer orderTime;
@ApiModelProperty(value = "过滤超时")
private Boolean filterOverTime = false;
@ApiModelProperty(value = "日期,格式2022-06-23 00:00:00", required = true)
@NotNull(message = "日期不能为空!")
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime dateTime;
}

View File

@@ -0,0 +1,33 @@
package com.sl.ms.web.courier.vo.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotBlank;
@Data
@ApiModel("快递员搜索")
public class TaskSearchVO {
@ApiModelProperty(value = "页码", example = "1", required = true)
private Integer page = 1;
@ApiModelProperty(value = "页面大小", example = "10", required = true)
private Integer pgeSize = 10;
@ApiModelProperty(value = "关键词;可以是运单号、手机号、姓名、地址等字段", required = true)
@NotBlank(message = "关键词不能为空!")
private String keyword;
@ApiModelProperty(value = "任务类型1-取件2-派件")
private Integer taskType;
@ApiModelProperty(value = "任务状态1-新任务2-已完成3-已取消")
private Integer status;
@ApiModelProperty(value = "经度", required = true, example = "116.372809")
private Double longitude;
@ApiModelProperty(value = "纬度", required = true, example = "40.062595")
private Double latitude;
}

View File

@@ -0,0 +1,20 @@
package com.sl.ms.web.courier.vo.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
@ApiModel("签收模型")
public class TaskSignVO {
@ApiModelProperty(value = "派件任务id", required = true)
@NotNull(message = "派件任务id不能为空")
private String id;
@ApiModelProperty(value = "签收人1本人2代收", required = true)
@NotNull(message = "签收人不能为空!")
private Integer signRecipient;
}

View File

@@ -0,0 +1,36 @@
package com.sl.ms.web.courier.vo.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel("各类任务数量统计")
@Data
public class TaskStatisticsVO {
@ApiModelProperty("取件任务数量")
private Integer pickupNum = 0;
@ApiModelProperty("取件--待取件数量")
private Integer newPickUpNum = 0;
@ApiModelProperty("取件--已取件数量")
private Integer completePickUpNum = 0;
@ApiModelProperty("取件--取消数量")
private Integer cancelPickUpNum = 0;
@ApiModelProperty("派件任务数量")
private Integer dispatchNum = 0;
@ApiModelProperty("派件--待派件数量")
private Integer newDispatchNum = 0;
@ApiModelProperty("派件--已签收数量")
private Integer signedNum = 0;
@ApiModelProperty("派件--取消数量")
private Integer cancelDispatchNum = 0;
@ApiModelProperty("超时任务数量")
private Integer overTimeNum = 0;
}

View File

@@ -0,0 +1,94 @@
package com.sl.ms.web.courier.vo.task;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sl.ms.work.domain.enums.pickupDispatchtask.PickupDispatchTaskStatus;
import com.sl.ms.work.domain.enums.pickupDispatchtask.PickupDispatchTaskType;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@ApiModel("任务列表模型")
public class TaskVO {
@ApiModelProperty("取件派件任务id")
private Long id;
@ApiModelProperty("订单id")
private Long orderId;
@ApiModelProperty("运单id")
private String transportOrderId;
@ApiModelProperty(value = "任务类型1为取件任务2为派件任务")
private PickupDispatchTaskType taskType;
@ApiModelProperty(value = "任务状态1为待执行、2为已完成、3为已取消")
private PickupDispatchTaskStatus status;
@ApiModelProperty(value = "签收状态(1为已签收2为拒收)")
private Integer signStatus;
@ApiModelProperty(value = "付款方式,1寄付2到付")
private Integer paymentMethod;
@ApiModelProperty(value = "付款状态,1未付2已付")
private Integer paymentStatus;
@ApiModelProperty("寄/收件人姓名")
private String name;
@ApiModelProperty("寄/收件人电话")
private String phone;
@ApiModelProperty("寄/收件人地址")
private String address;
@ApiModelProperty("距离,单位公里,待取件或者待派送才会计算距离")
private Double distance;
@ApiModelProperty("运费")
private Double amount;
@ApiModelProperty("预计取/派件开始时间")
private LocalDateTime estimatedStartTime;
@ApiModelProperty("实际开始时间")
private LocalDateTime actualStartTime;
@ApiModelProperty("预计完成时间")
private LocalDateTime estimatedEndTime;
@ApiModelProperty("实际完成时间")
private LocalDateTime actualEndTime;
@ApiModelProperty("取消时间")
private LocalDateTime cancelTime;
@ApiModelProperty(value = "任务时间")
private LocalDateTime taskTime;
@ApiModelProperty("备注")
private String mark;
@ApiModelProperty("取消原因")
private String cancelReason;
@ApiModelProperty("取消原因描述")
private String cancelReasonDescription;
@ApiModelProperty("经纬度")
private String location;
@ApiModelProperty("是否超时")
private Boolean isDelay;
@ApiModelProperty("任务创建时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime created;
@ApiModelProperty("任务更新时间")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updated;
}

View File

@@ -0,0 +1,23 @@
package com.sl.ms.web.courier.vo.task;
import com.sl.ms.work.domain.enums.pickupDispatchtask.PickupDispatchTaskCancelReason;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
@Data
@ApiModel("订单取消")
public class TasksCancelVO {
@ApiModelProperty(value = "任务id", required = true)
@NotNull(message = "任务id不能为空")
private String id;
@ApiModelProperty(value = "取消原因", required = true)
@NotNull(message = "取消原因不能为空!")
private PickupDispatchTaskCancelReason reason;
@ApiModelProperty("原因描述")
private String reasonDesc;
}

View File

@@ -0,0 +1,21 @@
package com.sl.ms.web.courier.vo.task;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDateTime;
@Data
@ApiModel("订单跟踪")
public class TransportOrderPointVO {
@ApiModelProperty("创建时间")
private LocalDateTime created;
@ApiModelProperty(value = "详细信息", example = "您的快件已到达【北京通州分拣中心】", required = true)
private String info;
@ApiModelProperty(value = "状态", example = "运输中", required = true)
private String status;
}

View File

@@ -0,0 +1,33 @@
package com.sl.ms.web.courier.vo.user;
import com.sl.ms.scope.dto.Coordinate;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
import java.util.List;
@Data
@ApiModel(value = "业务范围信息")
public class ServiceScopeVO {
@ApiModelProperty(value = "业务id可以是机构或快递员", required = true)
@NotNull(message = "bid不能为空")
private Long bid;
@ApiModelProperty(value = "类型1-机构2-快递员", required = true)
@NotNull(message = "type不能为空")
private Integer type;
@ApiModelProperty(value = "多边形坐标点至少3个坐标点首尾坐标必须相同", required = true)
@Size(min = 3, message = "坐标列表至少3个坐标点")
private List<Coordinate> polygon;
@ApiModelProperty(value = "创建时间")
private Long created;
@ApiModelProperty(value = "更新时间")
private Long updated;
}

View File

@@ -0,0 +1,18 @@
package com.sl.ms.web.courier.vo.user;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel("用户简单信息")
public class UserSimpleInfoVO {
@ApiModelProperty("雇员编号")
private String employeeNumber;
@ApiModelProperty("用户id")
private String userId;
@ApiModelProperty("姓名")
private String name;
}

View File

@@ -0,0 +1,44 @@
package com.sl.ms.web.courier.vo.user;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
@Data
@ApiModel("用户相关信息")
public class UsersInfoVO {
@ApiModelProperty("用户id")
private String id;
@ApiModelProperty("姓名")
private String name;
@ApiModelProperty("账号")
private String account;
@ApiModelProperty("头像")
private String avatar;
@ApiModelProperty("手机号码")
private String phone;
@ApiModelProperty("显示星级")
private Integer starLevel;
@ApiModelProperty("所在网点")
private String agencyName;
@ApiModelProperty("上班时间")
private LocalDateTime startTime;
@ApiModelProperty("下班时间")
private LocalDateTime endTime;
@ApiModelProperty("专属二维码")
private String exclusiveQrCodeUrl;
}

View File

@@ -0,0 +1,7 @@
_ ${spring.application.name} ${application.version}
___ | | ___ __ __ _ __ _ __ ___ ___ ___ Port: ${server.port}
/ __|| | _____ / _ \\ \/ /| '_ \ | '__|/ _ \/ __|/ __| Pid: ${pid} Profile(s): ${AnsiColor.GREEN}${spring.profiles.active}${AnsiColor.DEFAULT}
\__ \| ||_____|| __/ > < | |_) || | | __/\__ \\__ \
|___/|_| \___|/_/\_\| .__/ |_| \___||___/|___/ https://sl-express.itheima.net/
|_|

View File

@@ -0,0 +1,28 @@
server:
port: 18090
tomcat:
uri-encoding: UTF-8
threads:
max: 1000
min-spare: 30
spring:
cloud:
nacos:
username: nacos
password: nacos
server-addr: 192.168.150.101:8848
discovery:
namespace: ecae68ba-7b43-4473-a980-4ddeb6157bdc
ip: 192.168.150.1
config:
namespace: ecae68ba-7b43-4473-a980-4ddeb6157bdc
shared-configs: #共享配置
- data-id: shared-spring-seata.yml
group: SHARED_GROUP
refresh: false
- data-id: shared-spring-redis.yml
group: SHARED_GROUP
refresh: false
- data-id: shared-spring-authority.yml
group: SHARED_GROUP
refresh: false

View File

@@ -0,0 +1,27 @@
server:
port: 18090
tomcat:
uri-encoding: UTF-8
threads:
max: 1000
min-spare: 30
spring:
cloud:
nacos:
username: nacos
password: vO5/dZ9,iL
server-addr: nacos-service.yjy-public-slwl-java-prod.svc.cluster.local:8848
discovery:
namespace: 92312ba8-1119-440f-81af-c29618df303b
config:
namespace: 92312ba8-1119-440f-81af-c29618df303b
shared-configs: #共享配置
- data-id: shared-spring-seata.yml
group: SHARED_GROUP
refresh: false
- data-id: shared-spring-redis.yml
group: SHARED_GROUP
refresh: false
- data-id: shared-spring-authority.yml
group: SHARED_GROUP
refresh: false

View File

@@ -0,0 +1,27 @@
server:
port: 18090
tomcat:
uri-encoding: UTF-8
threads:
max: 1000
min-spare: 30
spring:
cloud:
nacos:
username: nacos
password: nacos
server-addr: 192.168.150.101:8848
discovery:
namespace: ecae68ba-7b43-4473-a980-4ddeb6157bdc
config:
namespace: ecae68ba-7b43-4473-a980-4ddeb6157bdc
shared-configs: #共享配置
- data-id: shared-spring-seata.yml
group: SHARED_GROUP
refresh: false
- data-id: shared-spring-redis.yml
group: SHARED_GROUP
refresh: false
- data-id: shared-spring-authority.yml
group: SHARED_GROUP
refresh: false

View File

@@ -0,0 +1,27 @@
server:
port: 18090
tomcat:
uri-encoding: UTF-8
threads:
max: 1000
min-spare: 30
spring:
cloud:
nacos:
username: nacos
password: nacos
server-addr: nacos-service.yjy-public-slwl-java.svc.cluster.local:8848
discovery:
namespace: 92312ba8-1119-440f-81af-c29618df303b
config:
namespace: 92312ba8-1119-440f-81af-c29618df303b
shared-configs: #共享配置
- data-id: shared-spring-seata.yml
group: SHARED_GROUP
refresh: false
- data-id: shared-spring-redis.yml
group: SHARED_GROUP
refresh: false
- data-id: shared-spring-authority.yml
group: SHARED_GROUP
refresh: false

View File

@@ -0,0 +1,27 @@
application:
version: v1.0
logging:
config: classpath:logback-spring.xml
spring:
application:
name: sl-express-ms-web-courier
profiles:
active: local
main:
allow-bean-definition-overriding: true
mvc:
pathmatch:
#解决异常swagger Failed to start bean 'documentationPluginsBootstrapper'; nested exception is java.lang.NullPointerException
#因为Springfox使用的路径匹配是基于AntPathMatcher的而Spring Boot 2.6.X使用的是PathPatternMatcher
matching-strategy: ant_path_matcher
sl:
swagger:
package-path: com.sl.ms.web.courier.controller
title: 神领物流 - 快递员端接口文档
description: 该服务用于快递员端
contact-name: 传智教育·研究院
contact-url: http://www.itcast.cn/
contact-email: yjy@itcast.cn
version: ${application.version}

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--scan: 当此属性设置为true时配置文件如果发生改变将会被重新加载默认值为true。-->
<!--scanPeriod: 设置监测配置文件是否有修改的时间间隔如果没有给出时间单位默认单位是毫秒。当scan为true时此属性生效。默认的时间间隔为1分钟。-->
<!--debug: 当此属性设置为true时将打印出logback内部日志信息实时查看logback运行状态。默认值为false。-->
<configuration debug="false" scan="false" scanPeriod="60 seconds">
<springProperty scope="context" name="appName" source="spring.application.name"/>
<!--文件名-->
<property name="logback.appname" value="${appName}"/>
<!--文件位置-->
<property name="logback.logdir" value="/data/logs"/>
<!-- 定义控制台输出 -->
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
<layout class="ch.qos.logback.classic.PatternLayout">
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} - [%thread] - %-5level - %logger{50} - %msg%n</pattern>
</layout>
</appender>
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>DEBUG</level>
</filter>
<File>${logback.logdir}/${logback.appname}/${logback.appname}.log</File>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${logback.logdir}/${logback.appname}/${logback.appname}.%d{yyyy-MM-dd}.log.zip</FileNamePattern>
<maxHistory>90</maxHistory>
</rollingPolicy>
<encoder>
<charset>UTF-8</charset>
<pattern>%d [%thread] %-5level %logger{36} %line - %msg%n</pattern>
</encoder>
</appender>
<!--evel:用来设置打印级别大小写无关TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF-->
<!--不能设置为INHERITED或者同义词NULL。默认是DEBUG。-->
<root level="INFO">
<appender-ref ref="stdout"/>
</root>
</configuration>

View File

@@ -0,0 +1,26 @@
package com.sl.base.service.api;
import com.sl.ms.base.api.common.WorkPatternFeign;
import com.sl.ms.base.domain.base.WorkPatternDTO;
import com.sl.ms.base.domain.base.WorkPatternQueryDTO;
import com.sl.transport.common.util.PageResponse;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.web.WebAppConfiguration;
@SpringBootTest
@Slf4j
@WebAppConfiguration
public class WorkPatternFeignTest {
@Autowired
private WorkPatternFeign workPatternFeign;
@Test
public void test(){
// WorkPatternDTO workPatternDTO = workPatternFeign.getById(2L);
PageResponse<WorkPatternDTO> list = workPatternFeign.list(new WorkPatternQueryDTO());
log.info("workPatternDTO : {}", list);
}
}