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

3
sl-express-ms-web-customer/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
.idea
target/
*.iml

View File

@@ -0,0 +1,13 @@
FROM openjdk:11-jdk
LABEL maintainer="研究院研发组 <research@itcast.cn>"
# 时区修改为东八区
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
WORKDIR /app
ARG JAR_FILE=target/*.jar
ADD ${JAR_FILE} app.jar
EXPOSE 8080
ENTRYPOINT ["sh","-c","java -Djava.security.egd=file:/dev/./urandom -jar $JAVA_OPTS app.jar"]

View File

@@ -0,0 +1,14 @@
# sl-express-customer使用手册
## 1、说明
customer服务作为用户端web微服务主要包括小程序对应的后端接口包含用户鉴权token生成实名认证用户数据脱敏微信绑定手机号获取下单查询订单。
主要功能:
- 提供下单、取消订单,订单相关数据查询,订单状态修改功能的转发。
- 提供热门货物,最近货物功能的转发。
- 提供地址簿功能转发。
- 提供实名认证,登录鉴权,微信绑定等。

View File

@@ -0,0 +1,166 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>com.sl-express</groupId>
<artifactId>sl-express-parent</artifactId>
<version>1.4</version>
</parent>
<groupId>com.sl-express.ms.web</groupId>
<artifactId>sl-express-ms-web-customer</artifactId>
<version>1.1-SNAPSHOT</version>
<description>用户端接口层微服务</description>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<swagger.version>2.9.2</swagger.version>
<sl-express-common.version>1.2-SNAPSHOT</sl-express-common.version>
<sl-express-ms-base-api.version>1.1-SNAPSHOT</sl-express-ms-base-api.version>
<sl-express-ms-work-api.version>1.1-SNAPSHOT</sl-express-ms-work-api.version>
<sl-express-ms-oms-api.version>1.1-SNAPSHOT</sl-express-ms-oms-api.version>
<sl-express-ms-user-api.version>1.1-SNAPSHOT</sl-express-ms-user-api.version>
<sl-express-ms-carriage-api.version>1.1-SNAPSHOT</sl-express-ms-carriage-api.version>
<sl-express-ms-transport-info-api.version>1.1-SNAPSHOT</sl-express-ms-transport-info-api.version>
<sl-express-ms-trade-api.version>1.1-SNAPSHOT</sl-express-ms-trade-api.version>
<sl-express-ms-track-api.version>1.1-SNAPSHOT</sl-express-ms-track-api.version>
</properties>
<dependencies>
<dependency>
<groupId>com.sl-express.common</groupId>
<artifactId>sl-express-common</artifactId>
<version>${sl-express-common.version}</version>
</dependency>
<dependency>
<groupId>com.sl-express.ms.base</groupId>
<artifactId>sl-express-ms-base-api</artifactId>
<version>${sl-express-ms-base-api.version}</version>
</dependency>
<dependency>
<groupId>com.sl-express.ms.work</groupId>
<artifactId>sl-express-ms-work-api</artifactId>
<version>${sl-express-ms-work-api.version}</version>
</dependency>
<dependency>
<groupId>com.sl-express.ms.oms</groupId>
<artifactId>sl-express-ms-oms-api</artifactId>
<version>${sl-express-ms-oms-api.version}</version>
</dependency>
<dependency>
<groupId>com.sl-express.ms.user</groupId>
<artifactId>sl-express-ms-user-api</artifactId>
<version>${sl-express-ms-user-api.version}</version>
</dependency>
<dependency>
<groupId>com.sl-express.ms.carriage</groupId>
<artifactId>sl-express-ms-carriage-api</artifactId>
<version>${sl-express-ms-carriage-api.version}</version>
</dependency>
<dependency>
<groupId>com.sl-express.ms.transport-info</groupId>
<artifactId>sl-express-ms-transport-info-api</artifactId>
<version>${sl-express-ms-transport-info-api.version}</version>
</dependency>
<dependency>
<groupId>com.sl-express.ms.trade</groupId>
<artifactId>sl-express-ms-trade-api</artifactId>
<version>${sl-express-ms-trade-api.version}</version>
</dependency>
<dependency>
<groupId>com.sl-express.ms.track</groupId>
<artifactId>sl-express-ms-track-api</artifactId>
<version>${sl-express-ms-track-api.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-loadbalancer</artifactId>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.3.3</version>
</dependency>
<!-- Jwt 生成token需要 Java11版本需要 低版本不需要-->
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-seata</artifactId>
</dependency>
<!-- Jwt 生成token需要 Java11版本需要 低版本不需要-->
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>repackage</goal>
<goal>build-info</goal>
</goals>
</execution>
</executions>
<configuration>
<!--指定主类-->
<mainClass>com.sl.WebCustomerApplication</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,13 @@
package com.sl;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableFeignClients
public class WebCustomerApplication {
public static void main(String[] args) {
SpringApplication.run(WebCustomerApplication.class, args);
}
}

View File

@@ -0,0 +1,34 @@
package com.sl.ms.web.customer.config;
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 CustomerWebConfig implements WebMvcConfigurer {
//拦截的时候过滤掉swagger相关路径和登录相关接口
private static final String[] EXCLUDE_PATH_PATTERNS = new String[]{"/swagger-ui.html",
"/webjars/**",
"/swagger-resources",
"/v2/api-docs",
"/user/login/**",
"/user/refresh/**"};
@Resource
private UserInterceptor userInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 用户信息拦截器
registry.addInterceptor(userInterceptor).excludePathPatterns(EXCLUDE_PATH_PATTERNS).addPathPatterns("/**");
}
}

View File

@@ -0,0 +1,23 @@
package com.sl.ms.web.customer.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.customer.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,125 @@
package com.sl.ms.web.customer.controller;
import com.sl.ms.user.domain.dto.AddressBookDTO;
import com.sl.ms.web.customer.service.AddressBookService;
import com.sl.ms.web.customer.vo.base.AddressBookVO;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* 地址簿服务
*/
@Slf4j
@Api(tags = "地址簿")
@RestController
@RequestMapping("address")
public class AddressBookController {
@Resource
private AddressBookService addressBookService;
/**
* 分页查询地址簿
* @param page 页数
* @param pageSize 页大小
* @param keyword 关键词
* @return 分页结果
*/
@ApiOperation(value = "地址簿分页查询")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", value = "当前页数", required = true, example = "1"),
@ApiImplicitParam(name = "pageSize", value = "每页条数", required = true, example = "10"),
@ApiImplicitParam(name = "keyword", value = "搜索条件", required = false, example = "17303491111"),
@ApiImplicitParam(name = "type", value = "地址薄类型 1寄件 2收件", required = false, example = "1")
})
@GetMapping("page")
public R<PageResponse<AddressBookVO>> page(Integer page, Integer pageSize, String keyword, Integer type) {
// todo
PageResponse<AddressBookVO> result = addressBookService.page(page, pageSize, keyword, type);
return R.success(result);
}
/**
* 默认地址簿
* @return 响应
*/
@PostMapping("defaultAddress")
@ApiOperation(value = "默认")
public R<AddressBookVO> defaultAddress() {
return R.success(addressBookService.defaultAddress());
}
/**
* 新增
*
* @param vo 地址信息
* @return 响应
*/
@PostMapping
@ApiOperation(value = "新增")
public R<AddressBookVO> save(@RequestBody AddressBookVO vo) {
return R.success(addressBookService.save(vo));
}
/**
* 修改
*
* @param vo 地址信息
* @return 响应
*/
@PutMapping("")
@ApiOperation(value = "修改")
public R<AddressBookVO> update(@RequestBody AddressBookVO vo) {
AddressBookVO update = addressBookService.update(vo);
return R.success(update);
}
/**
* 删除
*
* @param ids 地址ID
* @return 响应
*/
@DeleteMapping("")
@ApiOperation(value = "删除")
public R<Void> del(@RequestBody List<Long> ids) {
addressBookService.deleteById(ids);
return R.success();
}
/**
* 详情
*
* @param id 地址簿ID
* @return 地址信息
*/
@ApiOperation(value = "明细")
@ApiImplicitParam(name = "id", value = "主键", required = true)
@GetMapping("detail/{id}")
public R<AddressBookDTO> detail(@PathVariable(name = "id") Long id) {
AddressBookDTO addressBook = addressBookService.getById(id);
return R.success(addressBook);
}
/**
* 保存地址 不同步地址薄
* 下单地址
* @param addressBook 地址信息
*/
@PutMapping("/orderAddress")
@ApiOperation("下单地址保存")
public R<Void> saveOrderAddress(@RequestBody AddressBookVO addressBook) {
addressBookService.saveOrderAddressWithoutBook(addressBook);
return R.success();
}
}

View File

@@ -0,0 +1,40 @@
package com.sl.ms.web.customer.controller;
import com.sl.ms.web.customer.service.BaseService;
import com.sl.ms.web.customer.vo.base.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 lombok.extern.slf4j.Slf4j;
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
@Slf4j
@RequestMapping("/areas")
public class AreaController {
@Resource
private BaseService baseService;
@ApiOperation("根据父id获取地址信息")
@GetMapping("/children")
@ApiImplicitParams({
@ApiImplicitParam(name = "parentId", value = "行政区域父id", required = false, example = "0")
})
public R<List<AreaSimpleVO>> findChildrenAreaByParentId(@RequestParam(value = "parentId", required = false, defaultValue = "0") Long parentId) {
return R.success(baseService.findChildrenAreaByParentId(parentId));
}
}

View File

@@ -0,0 +1,85 @@
package com.sl.ms.web.customer.controller;
import com.sl.ms.web.customer.service.OmsService;
import com.sl.ms.web.customer.vo.oms.OrderCargoUpdateVO;
import com.sl.ms.web.customer.vo.oms.OrderCargoVO;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
/**
* 货品管理
*/
@RestController
@RequestMapping("order-manager/cargo")
@Api(tags = "货品管理")
@Slf4j
public class CargoController {
@Resource
private OmsService omsService;
@ApiOperation(value = "添加货物")
@PostMapping
public R<OrderCargoUpdateVO> saveOrderCargo(@RequestBody OrderCargoUpdateVO vo) {
omsService.save(vo);
return R.success();
}
@ApiOperation(value = "获取货物列表")
@ApiImplicitParams({
@ApiImplicitParam(name = "orderId", value = "订单id", required = true, example = "0")
})
@GetMapping(value = "")
public R<List<OrderCargoVO>> findAll(@RequestParam(value = "orderId") Long orderId) {
List<OrderCargoVO> all = omsService.findAll(null, orderId);
return R.success(all);
}
@ApiOperation(value = "更新货物信息")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "货物id", required = true, example = "1")
})
@PutMapping("/{id}")
public R<OrderCargoUpdateVO> updateOrderCargo(@PathVariable(name = "id") Long id, @RequestBody OrderCargoUpdateVO vo) {
omsService.update(id, vo);
return R.success();
}
@ApiOperation(value = "删除货物")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "货物id", required = true, example = "1")
})
@DeleteMapping("/{id}")
public R<OrderCargoVO> delete(@PathVariable(name = "id") Long id) {
omsService.del(id);
return R.success();
}
@ApiOperation(value = "获取常用货物列表")
@ApiImplicitParams({
@ApiImplicitParam(name = "name", value = "货物名称", example = "0")
})
@GetMapping(value = "/hot")
public R<List<OrderCargoVO>> hotGood(@RequestParam(value = "name", required = false) String name) {
List<OrderCargoVO> all = omsService.hotGood(name);
return R.success(all);
}
@ApiOperation(value = "获取最近货物列表")
@ApiImplicitParams({
@ApiImplicitParam(name = "name", value = "货物名称", example = "0")
})
@GetMapping(value = "/last")
public R<List<OrderCargoVO>> lastGood(@RequestParam(value = "name", required = false) String name) {
List<OrderCargoVO> all = omsService.lastGood(name);
return R.success(all);
}
}

View File

@@ -0,0 +1,153 @@
package com.sl.ms.web.customer.controller;
import com.sl.ms.web.customer.service.OmsService;
import com.sl.ms.web.customer.vo.oms.*;
import com.sl.ms.web.customer.vo.oms.pay.TradeLaunchVO;
import com.sl.ms.web.customer.vo.oms.pay.TradeResponseVO;
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 lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.Map;
/**
* 订单管理
*/
@RestController
@Api(tags = "订单管理")
@RequestMapping("order-manager/order")
@Slf4j
public class OrderController {
@Resource
private OmsService omsService;
@ApiOperation(value = "获取订单分页数据")
@PostMapping("/page")
public R<PageResponse<OrderVO>> findByPage(@RequestBody OrderQueryVO vo) {
return R.success(omsService.findByPage(vo));
}
@ApiOperation(value = "获取订单详情")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "订单id", required = true, example = "1")
})
@GetMapping("/{id}")
public R<OrderVO> findOrderById(@PathVariable(name = "id") Long id) {
return R.success(omsService.findOrderDetail(id));
}
@ApiOperation(value = "更新订单")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "订单id", required = true, example = "1")
})
@PostMapping("/{id}")
public R<OrderVO> updateOrder(@PathVariable(name = "id") Long id, @RequestBody OrderVO vo) {
omsService.updateOrder(id, vo);
return R.success();
}
/**
* 预估总价
*
* @param vo 订单信息
* @return 订单总价
*/
@ApiOperation("预估总价")
@PostMapping("totalPrice")
public R<OrderCarriageVO> totalPrice(@RequestBody MailingSaveVO vo) {
OrderCarriageVO orderCarriageVO = omsService.totalPrice(vo);
return R.success(orderCarriageVO);
}
/**
* 下单
*
* @param vo 订单信息
* @return 下单成功信息
*/
@ApiOperation("下单")
@PostMapping
public R<OrderVO> mailingSave(@RequestBody MailingSaveVO vo) {
log.info("下单:{}", vo);
OrderVO orderVO = omsService.mailingSave(vo);
return R.success(orderVO);
}
/**
* 修改 下单
*
* @param vo 订单信息
* @return 结果类
*/
@ApiOperation("修改订单")
@PutMapping("/{id}")
public R<Void> update(@PathVariable("id") Long id, @RequestBody OrderVO vo) {
log.info("修改订单 id:{} params{}", id, vo);
omsService.updateOrder(id, vo);
return R.success();
}
/**
* 支付 下单
*
* @return 结果
*/
@ApiOperation("支付")
@PutMapping("/pay")
public R<TradeResponseVO> pay(@RequestBody TradeLaunchVO tradeLaunchVO) {
TradeResponseVO pay = omsService.pay(tradeLaunchVO);
return R.success(pay);
}
/**
* 取消 下单
*
* @return 结果
*/
@ApiOperation("取消")
@PutMapping("/cancel/{id}")
public R<Void> cancel(@PathVariable("id") Long id) {
log.info("客户取消订单:{}", id);
omsService.cancel(id);
return R.success();
}
/**
* 删除 下单
*
* @return 结果
*/
@ApiOperation("删除")
@PutMapping("/del/{id}")
public R<Void> del(@PathVariable("id") Long id) {
log.info("客户删除订单:{}", id);
omsService.delOrder(id);
return R.success();
}
@ApiOperation("数量统计")
@GetMapping("/count")
public R<Map<Integer, Long>> count() {
Map<Integer, Long> count = omsService.count();
return R.success(count);
}
@ApiOperation(value = "获取运单轨迹详情")
@ApiImplicitParams({
@ApiImplicitParam(name = "id", value = "运单id", required = true, example = "1")
})
@GetMapping("/track/{id}")
public R<TrackVO> findTrackById(@PathVariable(name = "id") String id) {
TrackVO track = omsService.findTrackById(id);
return R.success(track);
}
}

View File

@@ -0,0 +1,101 @@
package com.sl.ms.web.customer.controller;
import com.sl.ms.web.customer.service.MemberService;
import com.sl.ms.web.customer.vo.user.MemberVO;
import com.sl.ms.web.customer.vo.user.RealNameVerifyVO;
import com.sl.ms.web.customer.vo.user.UserLoginRequestVO;
import com.sl.ms.web.customer.vo.user.UserLoginVO;
import com.sl.transport.common.constant.Constants;
import com.sl.transport.common.util.ObjectUtil;
import com.sl.transport.common.util.UserThreadLocal;
import com.sl.transport.common.vo.R;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.io.IOException;
/**
* <p>
* 用户管理
*/
@Slf4j
@Api(tags = "用户管理")
@RestController
@RequestMapping("user")
public class UserController {
@Resource
private MemberService memberService;
/**
* C端用户登录--微信登录
*
* @param userLoginRequestVO 用户登录信息
* @return 登录结果
*/
@PostMapping("/login")
@ApiOperation("登录")
public R<UserLoginVO> login(@RequestBody UserLoginRequestVO userLoginRequestVO) throws IOException {
UserLoginVO login = memberService.login(userLoginRequestVO);
return R.success(login);
}
/**
* 刷新token校验请求头中的长令牌生成新的长短令牌
*
* @param refreshToken 原令牌
* @return 登录结果
*/
@PostMapping("/refresh")
@ApiOperation("刷新token")
public R<UserLoginVO> refresh(@RequestHeader(Constants.GATEWAY.REFRESH_TOKEN) String refreshToken) {
UserLoginVO loginVO = memberService.refresh(refreshToken);
if (ObjectUtil.isEmpty(loginVO)) {
return R.error("刷新token失败请重新登录.");
}
return R.success(loginVO);
}
@ApiOperation(value = "更新个人信息")
@PutMapping("profile")
public R<Void> update(@RequestBody MemberVO vo) {
memberService.update(vo);
return R.success();
}
@ApiOperation(value = "我的信息")
@GetMapping("profile")
public R<MemberVO> profile() {
//获取userid
Long userId = UserThreadLocal.getUserId();
MemberVO member = memberService.detail(userId);
return R.success(member);
}
@ApiOperation(value = "解除我的信息")
@DeleteMapping("profile")
public R<Void> del() {
memberService.del();
return R.success();
}
/**
* 实名认证
*
* @param verifyVo 姓名 & 身份证号
* @return 是否通过认证
*/
@ApiOperation(value = "实名认证")
@PostMapping("realNameVerify")
public R<RealNameVerifyVO> realNameVerify(@RequestBody RealNameVerifyVO verifyVo) {
RealNameVerifyVO realNameVerifyVo = memberService.realNameVerify(verifyVo);
if (realNameVerifyVo.getFlag()) {
return R.success(realNameVerifyVo);
}
return R.error(realNameVerifyVo, "身份校验未通过");
}
}

View File

@@ -0,0 +1,28 @@
package com.sl.ms.web.customer.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "sl.jwt")
@Data
public class JwtProperties {
/**
* RSA私钥base64加密后
*/
private String privateKey;
/**
* RSA公钥base64加密后
*/
private String publicKey;
/**
* 短令牌有效期时间,单位:分钟
*/
private Integer accessTtl;
/**
* 长令牌有效期时间,单位:小时
*/
private Integer refreshTtl;
}

View File

@@ -0,0 +1,66 @@
package com.sl.ms.web.customer.service;
import com.sl.ms.web.customer.vo.base.AddressBookVO;
import com.sl.transport.common.util.PageResponse;
import java.util.List;
public interface AddressBookService {
/**
* 新增地址
*
* @param vo 地址信息
* @return 地址信息
*/
AddressBookVO save(AddressBookVO vo);
/**
* 根据id查询
*
* @param id 地址簿ID
* @return 地址信息
*/
AddressBookVO getById(Long id);
/**
* 根据id修改地址
*
* @param vo 地址信息
* @return 地址信息
*/
AddressBookVO update(AddressBookVO vo);
/**
* 保存地址 不同步地址薄
* 下单地址
*
* @param vo 地址信息
*/
void saveOrderAddressWithoutBook(AddressBookVO vo);
/**
* 根据id删除地址
*
* @param ids 地址簿ID
*/
void deleteById(List<Long> ids);
/**
* 分页查询地址簿
*
* @param page 页数
* @param pageSize 页大小
* @param keyword 关键词
* @param type 地址簿类型 1寄件 2收件
* @return 分页结果
*/
PageResponse<AddressBookVO> page(Integer page, Integer pageSize, String keyword, Integer type);
/**
* 默认地址簿
*
* @return 响应
*/
AddressBookVO defaultAddress();
}

View File

@@ -0,0 +1,39 @@
package com.sl.ms.web.customer.service;
import com.sl.ms.base.domain.base.AreaDto;
import com.sl.ms.web.customer.vo.base.AreaSimpleVO;
import com.sl.ms.web.customer.vo.base.GoodsTypeVO;
import java.util.List;
/**
* 基础服务
* 文件上传 排班 工作模式 行政机构
*/
public interface BaseService {
/**
* 行政机构
* 用于地址选择 省市县三级行政机构
* 根据父行政机构节点查询子行政机构节点
*
* @param parentId 父节点ID
* @return 子节点
*/
List<AreaSimpleVO> findChildrenAreaByParentId(Long parentId);
/**
* 简要行政机构信息转换
*
* @param area 行政机构DTO
* @return 简要行政机构VO
*/
AreaSimpleVO parseArea2Vo(AreaDto area);
/**
* 根据id获取货物类型详情
*
* @param id 货物类型id
* @return 货物类型信息
*/
GoodsTypeVO fineGoodsTypeById(Long id);
}

View File

@@ -0,0 +1,76 @@
package com.sl.ms.web.customer.service;
import com.sl.ms.user.domain.dto.MemberDTO;
import com.sl.ms.web.customer.vo.user.MemberVO;
import com.sl.ms.web.customer.vo.user.RealNameVerifyVO;
import com.sl.ms.web.customer.vo.user.UserLoginRequestVO;
import com.sl.ms.web.customer.vo.user.UserLoginVO;
import java.io.IOException;
/**
* 用户管理
*/
public interface MemberService {
/**
* 详情
*
* @param userId 用户ID
* @return 用户信息
*/
MemberVO detail(Long userId);
/**
* 新增
*
* @param user 用户信息
*/
void save(MemberDTO user);
/**
* 根据openid查询用户
*
* @param openid 微信ID
* @return 用户信息
*/
MemberDTO getByOpenid(String openid);
/**
* 登录
*
* @param userLoginRequestVO 登录code
* @return 用户信息
* @throws IOException IO异常
*/
UserLoginVO login(UserLoginRequestVO userLoginRequestVO) throws IOException;
/**
* 实名认证
*
* @param verifyVo 身份证号 姓名
* @return 是否通过认证
*/
RealNameVerifyVO realNameVerify(RealNameVerifyVO verifyVo);
/**
* 删除用户
*/
void del();
/**
* 更新用户
*
* @param vo 用户
*/
void update(MemberVO vo);
/**
* 刷新token
*
* @param refreshToken 原长令牌
* @return 长/短令牌
*/
UserLoginVO refresh(String refreshToken);
}

View File

@@ -0,0 +1,156 @@
package com.sl.ms.web.customer.service;
import com.sl.ms.oms.dto.OrderDTO;
import com.sl.ms.web.customer.vo.oms.*;
import com.sl.ms.web.customer.vo.oms.pay.TradeLaunchVO;
import com.sl.ms.web.customer.vo.oms.pay.TradeResponseVO;
import com.sl.transport.common.util.PageResponse;
import java.util.List;
import java.util.Map;
/**
* 订单服务
*/
public interface OmsService {
/**
* 根据ID查询
*
* @param id 订单ID
* @return 订单VO
*/
OrderVO findOrderSimple(Long id);
/**
* 根据ID查询详情
*
* @param id 订单ID
* @return 订单VO
*/
OrderVO findOrderDetail(Long id);
/**
* 更新
*
* @param id 订单ID
* @param vo 订单VO
*/
void updateOrder(Long id, OrderVO vo);
/**
* 删除订单
*
* @param id 货物id
*/
void delOrder(Long id);
/**
* 分页查询
*
* @param vo 订单查询VO
* @return 订单VO
*/
PageResponse<OrderVO> findByPage(OrderQueryVO vo);
/**
* 获取货物列表
*
* @param tranOrderId 运单id
* @param orderId 订单id
* @return 货物列表
*/
List<OrderCargoVO> findAll(Long tranOrderId,
Long orderId);
/**
* 添加货物
*
* @param vo 货物信息
*/
void save(OrderCargoUpdateVO vo);
/**
* 更新货物信息
*
* @param id 货物id
* @param vo 货物信息
*/
void update(Long id, OrderCargoUpdateVO vo);
/**
* 删除货物信息
*
* @param id 货物id
*/
void del(Long id);
/**
* 常用货物
*
* @param name 货物名称
* @return 常用货物
*/
List<OrderCargoVO> hotGood(String name);
/**
* 统计
*
* @return 统计结果
*/
Map<Integer, Long> count();
/**
* 下单
*
* @param vo 下单信息
* @return 下单结果
*/
OrderVO mailingSave(MailingSaveVO vo);
/**
* 支付
*
* @param tradeLaunchVO 订单号
* @return 预支付编号 签名数据
*/
TradeResponseVO pay(TradeLaunchVO tradeLaunchVO);
/**
* 取消订单
*
* @param id 订单号
*/
void cancel(Long id);
/**
* 预估总价
*
* @param mailingSaveVO 订单信息
* @return 预估信息
*/
OrderCarriageVO totalPrice(MailingSaveVO mailingSaveVO);
/**
* 最近寄递
*
* @param name 名称
* @return 订单货品
*/
List<OrderCargoVO> lastGood(String name);
/**
* 批量转换
* @param orderDTOList dto列表
* @return vo列表
*/
List<OrderVO> batchParseOrderDTO2Vo(List<OrderDTO> orderDTOList);
/**
* 运单轨迹
*
* @param id 运单ID
* @return 轨迹
*/
TrackVO findTrackById(String id);
}

View File

@@ -0,0 +1,36 @@
package com.sl.ms.web.customer.service;
import com.sl.ms.web.customer.vo.user.UserLoginVO;
import java.util.Map;
/**
* 用户登录令牌的处理
*/
public interface TokenService {
/**
* 生成短令牌
*
* @param claims token中存储的数据
* @return 短令牌
*/
String createAccessToken(Map<String, Object> claims);
/**
* 生成长令牌
*
* @param claims token中存储的数据
* @return 长令牌
*/
String createRefreshToken(Map<String, Object> claims);
/**
* 刷新token
*
* @param refreshToken 原长令牌,需要否则校验其合法性以及可用性
* @return 登录对象,包含长短令牌
*/
UserLoginVO refreshToken(String refreshToken);
}

View File

@@ -0,0 +1,25 @@
package com.sl.ms.web.customer.service;
import cn.hutool.json.JSONObject;
import java.io.IOException;
public interface WechatService {
/**
* 获取openid
*
* @param code 登录凭证
* @return 唯一标识
* @throws IOException IO异常
*/
JSONObject getOpenid(String code) throws IOException;
/**
* 获取手机号
*
* @param code 手机号凭证
* @return 唯一标识
* @throws IOException IO异常
*/
String getPhone(String code) throws IOException;
}

View File

@@ -0,0 +1,176 @@
package com.sl.ms.web.customer.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.user.api.AddressBookFeign;
import com.sl.ms.user.domain.dto.AddressBookDTO;
import com.sl.ms.user.domain.enums.AddressBookShowStatus;
import com.sl.ms.web.customer.service.AddressBookService;
import com.sl.ms.web.customer.vo.base.AddressBookVO;
import com.sl.ms.web.customer.vo.base.AreaSimpleVO;
import com.sl.transport.common.util.BeanUtil;
import com.sl.transport.common.util.ObjectUtil;
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.util.*;
import java.util.stream.Collectors;
@Service
@Slf4j
public class AddressBookServiceImpl implements AddressBookService {
@Resource
private AddressBookFeign addressBookFeign;
@Resource
private AreaFeign areaFeign;
/**
* 新增地址
*
* @param vo 地址信息
* @return 地址信息
*/
@Override
public AddressBookVO save(AddressBookVO vo) {
AddressBookDTO addressBookDTO = BeanUtil.toBean(vo, AddressBookDTO.class);
addressBookDTO.setUserId(UserThreadLocal.getUserId());
if (ObjectUtil.isEmpty(addressBookDTO.getIsDefault())) {
addressBookDTO.setIsDefault(0);
}
AddressBookDTO save = addressBookFeign.save(addressBookDTO);
return BeanUtil.toBean(save, AddressBookVO.class);
}
/**
* 根据id查询
*
* @param id 地址簿ID
* @return 地址信息
*/
@Override
public AddressBookVO getById(Long id) {
AddressBookDTO addressBook = addressBookFeign.detail(id);
Set<Long> areaSet = new HashSet<>(Arrays.asList(addressBook.getProvinceId(), addressBook.getCityId(), addressBook.getCountyId()));
List<AreaDto> result = areaFeign.findBatch(new ArrayList<>(areaSet));
Map<Long, AreaDto> areaMap = result.stream().collect(Collectors.toMap(AreaDto::getId, area -> area));
return BeanUtil.toBean(addressBook, AddressBookVO.class, (dto, vo) -> {
parseDTO2VO(vo, areaMap);
});
}
/**
* 简要行政机构信息转换
*
* @param area 行政机构DTO
* @return 简要行政机构VO
*/
public AreaSimpleVO parseArea2Vo(AreaDto area) {
return BeanUtil.toBean(area, AreaSimpleVO.class);
}
/**
* 转换
*
* @param addressBookVO vo
* @param areaMap 行政机构map
* @return vo
*/
private AddressBookVO parseDTO2VO(AddressBookVO addressBookVO, Map<Long, AreaDto> areaMap) {
addressBookVO.setProvince(parseArea2Vo(areaMap.get(addressBookVO.getProvinceId())));
addressBookVO.setCity(parseArea2Vo(areaMap.get(addressBookVO.getCityId())));
addressBookVO.setCounty(parseArea2Vo(areaMap.get(addressBookVO.getCountyId())));
return addressBookVO;
}
/**
* 根据id修改地址
*
* @param vo 地址信息
* @return 地址信息
*/
@Override
public AddressBookVO update(AddressBookVO vo) {
AddressBookDTO addressBookDTO = BeanUtil.toBean(vo, AddressBookDTO.class);
//获取userid
addressBookDTO.setUserId(UserThreadLocal.getUserId());
if (ObjectUtil.isEmpty(addressBookDTO.getIsDefault())) {
addressBookDTO.setIsDefault(0);
}
AddressBookDTO update = addressBookFeign.update(addressBookDTO.getId(), addressBookDTO);
return BeanUtil.toBean(update, AddressBookVO.class);
}
/**
* 保存地址 不同步地址薄
* 下单地址
*
* @param vo 地址信息
*/
@Override
public void saveOrderAddressWithoutBook(AddressBookVO vo) {
AddressBookDTO addressBookDTO = BeanUtil.toBean(vo, AddressBookDTO.class);
addressBookDTO.setIsShow(AddressBookShowStatus.NOT_SHOW_STATUS.getCode());
addressBookDTO.setUserId(UserThreadLocal.getUserId());
addressBookFeign.save(addressBookDTO);
}
/**
* 根据id删除地址
*
* @param ids 地址簿ID
*/
@Override
public void deleteById(List<Long> ids) {
ids.forEach(id -> addressBookFeign.del(id));
}
/**
* 分页查询地址簿
*
* @param page 页数
* @param pageSize 页大小
* @param keyword 关键词
* @param type 地址簿类型 1寄件 2收件
* @return 分页结果
*/
@Override
public PageResponse<AddressBookVO> page(Integer page, Integer pageSize, String keyword, Integer type) {
//获取userid
Long userId = UserThreadLocal.getUserId();
PageResponse<AddressBookDTO> result = addressBookFeign.page(page, pageSize, userId, keyword, type);
Set<Long> areaSet = new HashSet<>();
areaSet.addAll(result.getItems().stream().map(AddressBookDTO::getProvinceId).collect(Collectors.toSet()));
areaSet.addAll(result.getItems().stream().map(AddressBookDTO::getCityId).collect(Collectors.toSet()));
areaSet.addAll(result.getItems().stream().map(AddressBookDTO::getCountyId).collect(Collectors.toSet()));
List<AreaDto> areaDtoList = areaFeign.findBatch(new ArrayList<>(areaSet));
Map<Long, AreaDto> areaMap = areaDtoList.stream().collect(Collectors.toMap(AreaDto::getId, area -> area));
return PageResponse.of(result, AddressBookVO.class, (dto, vo) -> parseDTO2VO(vo, areaMap));
}
/**
* 默认地址簿
*
* @return 响应
*/
@Override
public AddressBookVO defaultAddress() {
PageResponse<AddressBookVO> page = page(0, 100, null, null);
if (CollUtil.isEmpty(page.getItems())) {
return null;
}
List<AddressBookVO> addressBookVOS = page.getItems().stream().filter(v -> v.getIsDefault().equals(1)).collect(Collectors.toList());
if (CollUtil.isNotEmpty(addressBookVOS)) {
return addressBookVOS.get(0);
}
return null;
}
}

View File

@@ -0,0 +1,90 @@
package com.sl.ms.web.customer.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import com.google.common.collect.Lists;
import com.sl.ms.base.api.common.AreaFeign;
import com.sl.ms.base.api.common.GoodsTypeFeign;
import com.sl.ms.base.domain.base.AreaDto;
import com.sl.ms.base.domain.base.GoodsTypeDto;
import com.sl.ms.web.customer.service.BaseService;
import com.sl.ms.web.customer.vo.base.AreaSimpleVO;
import com.sl.ms.web.customer.vo.base.GoodsTypeVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* 基础服务
* 文件上传 排班 工作模式 行政机构 车型 货物类型
*/
@Slf4j
@Service
public class BaseServiceImpl implements BaseService {
@Resource
private AreaFeign areaFeign;
@Resource
private GoodsTypeFeign goodsTypeFeign;
/**
* 行政机构
* 用于地址选择 省市县三级行政机构
* 根据父行政机构节点查询子行政机构节点
*
* @param parentId 父节点ID
* @return 子节点
*/
@Override
public List<AreaSimpleVO> findChildrenAreaByParentId(Long parentId) {
List<AreaDto> areas = areaFeign.findChildren(parentId);
if (CollUtil.isEmpty(areas)) {
return Lists.newArrayList();
}
List<AreaSimpleVO> areaSimpleVOS = new ArrayList<>();
areas.forEach(area -> {
AreaSimpleVO areaSimpleVO = BeanUtil.toBean(area, AreaSimpleVO.class);
areaSimpleVOS.add(areaSimpleVO);
});
return areaSimpleVOS;
}
/**
* 简要行政机构信息转换
*
* @param area 行政机构DTO
* @return 简要行政机构VO
*/
@Override
public AreaSimpleVO parseArea2Vo(AreaDto area) {
return BeanUtil.toBean(area, AreaSimpleVO.class);
}
/**
* 根据id获取货物类型详情
*
* @param id 货物类型id
* @return 货物类型信息
*/
@Override
public GoodsTypeVO fineGoodsTypeById(Long id) {
GoodsTypeDto dto = goodsTypeFeign.fineById(id);
return parseGoodsTypeDto2Vo(dto);
}
/**
* 货物类型转换
*
* @param dto 货物类型DTO
* @return 货物类型VO
*/
public GoodsTypeVO parseGoodsTypeDto2Vo(GoodsTypeDto dto) {
return BeanUtil.toBean(dto, GoodsTypeVO.class);
}
}

View File

@@ -0,0 +1,242 @@
package com.sl.ms.web.customer.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.DesensitizedUtil;
import cn.hutool.core.util.IdcardUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import com.sl.ms.base.domain.enums.StatusEnum;
import com.sl.ms.user.api.MemberFeign;
import com.sl.ms.user.domain.dto.MemberDTO;
import com.sl.ms.web.customer.service.MemberService;
import com.sl.ms.web.customer.service.TokenService;
import com.sl.ms.web.customer.service.WechatService;
import com.sl.ms.web.customer.vo.user.MemberVO;
import com.sl.ms.web.customer.vo.user.RealNameVerifyVO;
import com.sl.ms.web.customer.vo.user.UserLoginRequestVO;
import com.sl.ms.web.customer.vo.user.UserLoginVO;
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.ObjectUtil;
import com.sl.transport.common.util.UserThreadLocal;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.Map;
/**
* 用户管理
*/
@Slf4j
@Service
public class MemberServiceImpl implements MemberService {
@Resource
private MemberFeign memberFeign;
@Resource
private TokenService tokenService;
@Resource
private WechatService wechatService;
@Resource
private RealNameVerifyService realNameVerifyService;
//实名认证默认关闭
@Value("${real-name-registration.enable}")
private String realNameVerify;
@Override
public MemberVO detail(Long userId) {
log.info("查找用户信息:{}", userId);
MemberDTO member = memberFeign.detail(userId);
log.info("查找用户信息:{} Result:{}", userId, member);
MemberVO memberVO = BeanUtil.toBean(member, MemberVO.class);
memberVO.setName(DesensitizedUtil.chineseName(memberVO.getName()));
memberVO.setIdCardNo(DesensitizedUtil.idCardNum(memberVO.getIdCardNo(), 6, 4));
return memberVO;
}
/**
* 新增
*
* @param user 用户信息
*/
@Override
public void save(MemberDTO user) {
memberFeign.save(user);
}
/**
* 根据openid查询用户
*
* @param openid 微信ID
* @return 用户信息
*/
@Override
public MemberDTO getByOpenid(String openid) {
return memberFeign.detailByOpenId(openid);
}
/**
* 登录
*
* @param userLoginRequestVO 登录code
* @return 用户信息
*/
@Override
public UserLoginVO login(UserLoginRequestVO userLoginRequestVO) throws IOException {
// 1 调用微信开放平台小程序的api根据code获取openid
JSONObject jsonObject = wechatService.getOpenid(userLoginRequestVO.getCode());
// 2 若code不正确则获取不到openid响应失败
if (ObjectUtil.isNotEmpty(jsonObject.getInt("errcode"))) {
throw new SLWebException(jsonObject.getStr("errmsg"));
}
String openid = jsonObject.getStr("openid");
/*
* 3 根据openid从数据库查询用户
* 3.1 如果为新用户此处返回为null
* 3.2 如果为已经登录过的老用户此处返回为user对象 包含openId,phone,unionId等字段
*/
MemberDTO user = getByOpenid(openid);
/*
* 4 构造用户数据设置openId,unionId
* 4.1 如果user为null则为新用户需要构建新的user对象并设置openId,unionId
* 4.2 如果user不为null则为老用户无需设置openId,unionId
*/
user = ObjectUtil.isNotEmpty(user) ? user : MemberDTO.builder()
// openId
.openId(openid)
// 平台唯一ID
.authId(jsonObject.getStr("unionid"))
.build();
// 5 调用微信开放平台小程序的api获取微信绑定的手机号
String phone = wechatService.getPhone(userLoginRequestVO.getPhoneCode());
/*
* 6 新用户绑定手机号或者老用户更新手机号
* 6.1 如果user.getPhone()为null则为新用户需要设置手机号并保存数据库
* 6.2 如果user.getPhone()不为null但是与微信获取到的手机号不一样 则表示用户改了微信绑定的手机号,需要设置手机号,并保存数据库
* 以上俩种情况,都需要重新设置手机号,并保存数据库
*/
if (ObjectUtil.notEqual(user.getPhone(), phone)) {
user.setPhone(phone);
save(user);
}
// 7 如果为新用户查询数据库获取用户ID
if (ObjectUtil.isEmpty(user.getId())) {
user = getByOpenid(openid);
}
// 8 将用户ID存入token
Map<String, Object> claims = MapUtil.<String, Object>builder()
.put(Constants.GATEWAY.USER_ID, user.getId()).build();
// 9 封装用户信息和双token响应结果
return UserLoginVO
.builder()
.openid(openid)
.accessToken(this.tokenService.createAccessToken(claims))
.refreshToken(this.tokenService.createRefreshToken(claims))
.binding(StatusEnum.NORMAL.getCode())
.build();
}
/**
* 实名认证
*
* @param vo 身份证号 姓名
* @return 是否通过认证
*/
@Override
public RealNameVerifyVO realNameVerify(RealNameVerifyVO vo) {
if (!ObjectUtil.isEmpty(vo.getFlag()) && !vo.getFlag()) {
// 删除实名认证
// 保存用户表
MemberDTO memberDTO = MemberDTO
.builder()
.id(UserThreadLocal.getUserId())
.idCardNoVerify(StatusEnum.DISABLED.getCode())
.build();
save(memberDTO);
vo.setFlag(true);
return 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)) {
try {
if (!realNameVerifyService.realNameVerify(vo.getName(), vo.getIdCard())) {
// 不通过
return realNameVerifyVO;
}
} catch (IOException e) {
throw new SLWebException("实名认证方法执行失败");
}
}
realNameVerifyVO.setFlag(true);
// 保存用户表
MemberDTO memberDTO = MemberDTO
.builder()
.id(UserThreadLocal.getUserId())
.name(vo.getName())
.idCardNo(vo.getIdCard())
.idCardNoVerify(StatusEnum.NORMAL.getCode())
.build();
save(memberDTO);
return realNameVerifyVO;
}
/**
* 删除用户
*/
@Override
public void del() {
Long userId = UserThreadLocal.getUserId();
memberFeign.del(userId);
}
/**
* 更新用户
*
* @param vo 用户
*/
@Override
public void update(MemberVO vo) {
Long userId = UserThreadLocal.getUserId();
MemberDTO memberDTO = BeanUtil.toBean(vo, MemberDTO.class);
memberDTO.setId(userId);
memberFeign.update(userId, memberDTO);
}
@Override
public UserLoginVO refresh(String refreshToken) {
return this.tokenService.refreshToken(refreshToken);
}
}

View File

@@ -0,0 +1,622 @@
package com.sl.ms.web.customer.service.impl;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.google.zxing.BarcodeFormat;
import com.sl.ms.base.api.common.AreaFeign;
import com.sl.ms.base.domain.base.AreaDto;
import com.sl.ms.oms.api.CargoFeign;
import com.sl.ms.oms.api.GoodFeign;
import com.sl.ms.oms.api.OrderFeign;
import com.sl.ms.oms.dto.*;
import com.sl.ms.oms.enums.MailType;
import com.sl.ms.oms.enums.OrderPaymentStatus;
import com.sl.ms.oms.enums.OrderStatus;
import com.sl.ms.track.api.TrackFeign;
import com.sl.ms.track.domain.dto.TrackDTO;
import com.sl.ms.track.domain.enums.TrackStatusEnum;
import com.sl.ms.trade.api.JsapiPayFeign;
import com.sl.ms.trade.domain.request.JsapiPayDTO;
import com.sl.ms.trade.domain.response.JsapiPayResponseDTO;
import com.sl.ms.trade.enums.PayChannelEnum;
import com.sl.ms.user.api.MemberFeign;
import com.sl.ms.user.domain.dto.MemberDTO;
import com.sl.ms.web.customer.service.BaseService;
import com.sl.ms.web.customer.service.MemberService;
import com.sl.ms.web.customer.service.OmsService;
import com.sl.ms.web.customer.vo.base.GoodsTypeVO;
import com.sl.ms.web.customer.vo.oms.*;
import com.sl.ms.web.customer.vo.oms.pay.TradeLaunchVO;
import com.sl.ms.web.customer.vo.oms.pay.TradeResponseVO;
import com.sl.ms.web.customer.vo.user.MemberVO;
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.enums.pickupDispatchtask.PickupDispatchTaskCancelReason;
import com.sl.ms.work.domain.enums.pickupDispatchtask.PickupDispatchTaskStatus;
import com.sl.ms.work.domain.enums.pickupDispatchtask.PickupDispatchTaskType;
import com.sl.transport.common.exception.SLWebException;
import com.sl.transport.common.util.PageResponse;
import com.sl.transport.common.util.UserThreadLocal;
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.stereotype.Service;
import javax.annotation.Resource;
import java.awt.image.BufferedImage;
import java.util.*;
import java.util.stream.Collectors;
/**
* 订单服务
* 对应 订单微服务
*/
@Slf4j
@Service
public class OmsServiceImpl implements OmsService {
@Resource
private OrderFeign orderFeign;
@Resource
private AreaFeign areaFeign;
@Resource
private CargoFeign cargoFeign;
@Resource
private GoodFeign goodFeign;
@Resource
private BaseService baseService;
@Resource
private TransportInfoFeign transportInfoFeign;
@Resource
private MemberService memberService;
@Resource
private PickupDispatchTaskFeign pickupDispatchTaskFeign;
@Resource
private JsapiPayFeign jsapiPayFeign;
@Resource
private MemberFeign memberFeign;
@Resource
private TransportOrderFeign transportOrderFeign;
@Value("${sl.wechat.enterpriseId}")
private Long enterpriseId;
@Resource
private TrackFeign trackFeign;
/**
* 根据ID查询
* 简要订单信息
*
* @param id 订单ID
* @return 订单VO
*/
@Override
public OrderVO findOrderSimple(Long id) {
OrderDTO orderDTO = orderFeign.findById(id);
if (ObjectUtil.isEmpty(orderDTO)) {
return null;
}
return parseOrderDTO2Vo(orderDTO);
}
/**
* 根据ID查询详情
* 后台详情页面
*
* @param id 订单ID
* @return 订单VO
*/
@Override
public OrderVO findOrderDetail(Long id) {
OrderVO vo = findOrderSimple(id);
// 电子存根
String barcodeBase64 = getBarcodeBase64(vo.getTransportOrderId());
vo.setBarCode(barcodeBase64);
return vo;
}
/**
* 补充运单信息
*
* @param vo 订单
*/
private void appendTransportOrder(OrderVO vo) {
try {
// 补充运单信息
TransportOrderDTO transportOrderDTO = transportOrderFeign.findByOrderId(vo.getId());
if (ObjectUtil.isNotEmpty(transportOrderDTO)) {
vo.setTransportOrderId(transportOrderDTO.getId());
}
} catch (Exception e) {
log.info("没有运单信息 vo {}", vo);
}
}
/**
* 电子存根条形码
*
* @param contents 内容
* @return 条形码图片地址
*/
private String getBarcodeBase64(String contents) {
if (ObjectUtil.isEmpty(contents)) {
return null;
}
BufferedImage image = QrCodeUtil.generate(contents, BarcodeFormat.CODE_39, 900, 150);
return ImgUtil.toBase64DataUri(image, ImgUtil.IMAGE_TYPE_PNG);
}
/**
* 运单跟踪
*
* @param id 运单id
* @return 运单跟踪信息
*/
public List<TransportOrderPointVO> tracks(String id) {
if (ObjectUtil.isEmpty(id)) {
return new ArrayList<>();
}
try {
//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());
} catch (Exception e) {
log.info("没有运单信息 vo {}", id);
}
return Collections.emptyList();
}
/**
* 分页查询
*
* @param vo 订单查询VO
* @return 订单VO
*/
@Override
public PageResponse<OrderVO> findByPage(OrderQueryVO vo) {
log.info("获取订单分页数据:{}", vo);
OrderDTO dto = BeanUtil.toBean(vo, OrderDTO.class);
//获取userid
Long userId = UserThreadLocal.getUserId();
if (MailType.SEND.getCode().equals(vo.getMailType())) {
// 我寄的
dto.setMemberId(userId);
} else if (MailType.RECEIVE.getCode().equals(vo.getMailType())) {
// 我收的 通过收件人手机号查询
MemberVO member = memberService.detail(userId);
if (member == null || StringUtils.isEmpty(member.getPhone())) {
throw new SLWebException("暂无收件订单");
}
String phone = member.getPhone();
dto.setReceiverPhone(phone);
} else {
// 所有
dto.setMailType(MailType.ALL.getCode());
dto.setMemberId(userId);
MemberVO member = memberService.detail(userId);
if (ObjectUtil.isNotEmpty(member) && StringUtils.isNotEmpty(member.getPhone())) {
String phone = member.getPhone();
dto.setReceiverPhone(phone);
}
}
PageResponse<OrderDTO> orderPage = orderFeign.findByPage(dto);
//加工数据
return PageResponse.of(orderPage, this::batchParseOrderDTO2Vo);
}
/**
* 更新
*
* @param id 订单ID
* @param vo 订单VO
*/
@Override
public void updateOrder(Long id, OrderVO vo) {
OrderDTO orderDTO = parseOrderVo2DTO(vo);
orderDTO.setMemberId(UserThreadLocal.getUserId());
orderFeign.updateById(id, orderDTO);
}
@Override
public void delOrder(Long id) {
OrderDTO orderDTO = new OrderDTO();
orderDTO.setStatus(OrderStatus.DEL.getCode());
orderFeign.updateById(id, orderDTO);
}
/**
* 获取货物列表
*
* @param tranOrderId 运单id
* @param orderId 订单id
* @return 货物列表
*/
@Override
public List<OrderCargoVO> findAll(Long tranOrderId, Long orderId) {
log.info("Manager --- 获取货物列表");
List<OrderCargoDTO> cargoDtoList = cargoFeign.findAll(null, orderId);
log.info("Manager --- cargoFeign.findAll result:{}", cargoDtoList);
return parseCarGoDTO2VO(cargoDtoList);
}
/**
* 添加货物
*
* @param vo 货物信息
*/
@Override
public void save(OrderCargoUpdateVO vo) {
OrderCargoDTO orderCargoDto = BeanUtil.toBean(vo, OrderCargoDTO.class);
orderCargoDto.setId(null);
cargoFeign.save(orderCargoDto);
}
/**
* 更新货物信息
*
* @param id 货物id
* @param vo 货物信息
*/
@Override
public void update(Long id, OrderCargoUpdateVO vo) {
vo.setId(id);
cargoFeign.update(id, BeanUtil.toBean(vo, OrderCargoDTO.class));
}
/**
* 删除货物信息
*
* @param id 货物id
*/
@Override
public void del(Long id) {
cargoFeign.del(id);
}
/**
* 常用货物
*
* @param name 货物名称
* @return 常用货物
*/
@Override
public List<OrderCargoVO> hotGood(String name) {
List<OrderCargoDTO> cargoDtoList = goodFeign.list(name);
return parseCarGoDTO2VO(cargoDtoList);
}
/**
* 统计
*/
@Override
public Map<Integer, Long> count() {
Long userId = UserThreadLocal.getUserId();
return orderFeign.count(userId).stream().collect(Collectors.toMap(OrderStatusCountDTO::getStatusCode, OrderStatusCountDTO::getCount));
}
/**
* 下单
*
* @param mailingSaveVO 下单信息
* @return 下单结果
*/
@Override
public OrderVO mailingSave(MailingSaveVO mailingSaveVO) {
//获取userid
Long userId = UserThreadLocal.getUserId();
// 寄件人收件人 地址 电话 名称 有一个不同则可以寄件
if (ObjectUtil.equal(mailingSaveVO.getSendAddress(), mailingSaveVO.getReceiptAddress())) {
throw new SLWebException("您的寄件人收件人地址相同,请重新填写");
}
MailingSaveDTO mailingSaveDTO = BeanUtil.toBean(mailingSaveVO, MailingSaveDTO.class);
mailingSaveDTO.setMemberId(userId);
OrderDTO orderDTO = orderFeign.mailingSave(mailingSaveDTO);
return parseOrderDTO2Vo(orderDTO);
}
/**
* 支付
*
* @param tradeLaunchVO 订单号
* @return 预支付编号 签名数据
*/
@Override
public TradeResponseVO pay(TradeLaunchVO tradeLaunchVO) {
try {
// 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());
JsapiPayDTO jsapiPayDTO = BeanUtil.toBean(tradeLaunchVO, JsapiPayDTO.class);
jsapiPayDTO.setTradingChannel(payChannelEnum);
Long userId = UserThreadLocal.getUserId();
MemberDTO detail = memberFeign.detail(userId);
jsapiPayDTO.setOpenId(detail.getOpenId());
jsapiPayDTO.setEnterpriseId(enterpriseId);
jsapiPayDTO.setMemo("神领物流订单");
//3.2.2.调用feign
JsapiPayResponseDTO jsapiTrading = jsapiPayFeign.createJsapiTrading(jsapiPayDTO);
//3.2.3.将交易单号和支付渠道更新到订单表
orderDTO.setTradingOrderNo(jsapiTrading.getTradingOrderNo());
orderDTO.setTradingChannel(jsapiTrading.getTradingChannel());
orderFeign.updateById(orderDTO.getId(), orderDTO);
//3.2.4.将dto转为vo响应
return BeanUtil.toBean(jsapiTrading, TradeResponseVO.class);
} catch (Exception e) {
throw new SLWebException("支付失败");
}
}
/**
* 取消订单
*
* @param id 订单号
*/
@GlobalTransactional
@Override
public void cancel(Long id) {
// 更新订单
orderFeign.updateStatus(ListUtil.of(id), OrderStatus.CANCELLED.getCode());
//查询取派件任务
List<PickupDispatchTaskDTO> pickupDispatchTaskDTOS = pickupDispatchTaskFeign.findByOrderId(id, PickupDispatchTaskType.PICKUP);
if (CollUtil.isEmpty(pickupDispatchTaskDTOS)) {
// 暂未生成取件任务
log.info("{}订单暂无取派件任务", id);
return;
}
//更新取件任务
PickupDispatchTaskDTO taskDTO = pickupDispatchTaskDTOS.get(0);
taskDTO.setStatus(PickupDispatchTaskStatus.CANCELLED);//取消状态
taskDTO.setCancelReason(PickupDispatchTaskCancelReason.CANCEL_BY_USER);//取消原因
pickupDispatchTaskFeign.updateStatus(taskDTO);
}
/**
* 预估总价
*
* @param mailingSaveVO 订单信息
* @return 预估信息
*/
@Override
public OrderCarriageVO totalPrice(MailingSaveVO mailingSaveVO) {
log.info("预估总价:{}", mailingSaveVO);
MailingSaveDTO mailingSaveDTO = BeanUtil.toBean(mailingSaveVO, MailingSaveDTO.class);
OrderCarriageDTO orderCarriageDTO = orderFeign.totalPrice(mailingSaveDTO);
log.info("返回结果:{}", orderCarriageDTO);
return BeanUtil.toBean(orderCarriageDTO, OrderCarriageVO.class);
}
/**
* 货品转换
*
* @param cargoDtoList 货品DTO
* @return 货品VO
*/
private List<OrderCargoVO> parseCarGoDTO2VO(List<OrderCargoDTO> cargoDtoList) {
return cargoDtoList.stream().map(orderCargoDto -> {
OrderCargoVO vo = BeanUtil.toBean(orderCargoDto, OrderCargoVO.class);
if (ObjectUtil.isNotEmpty(orderCargoDto.getGoodsTypeId())) {
GoodsTypeVO goodsTypeVO = baseService.fineGoodsTypeById(orderCargoDto.getGoodsTypeId());
log.info("Manager --- goodsTypeFeign.fineById result:{}", goodsTypeVO);
vo.setGoodsType(goodsTypeVO);
}
return vo;
}).collect(Collectors.toList());
}
/**
* 最近寄递
*
* @param name 名称
* @return 订单货品信息
*/
@Override
public List<OrderCargoVO> lastGood(String name) {
Long userId = UserThreadLocal.getUserId();
List<OrderCargoDTO> list = cargoFeign.list(name, userId);
return parseCarGoDTO2VO(list);
}
/**
* 更新订单转换
*
* @param vo 订单VO
* @return 订单DTO
*/
private OrderDTO parseOrderVo2DTO(OrderVO vo) {
OrderDTO dto = BeanUtil.toBean(vo, OrderDTO.class);
if (ObjectUtil.isNotEmpty(vo.getSenderProvince())) {
dto.setSenderProvinceId(vo.getSenderProvince().getId());
}
if (ObjectUtil.isNotEmpty(vo.getSenderCity())) {
dto.setSenderCityId(vo.getSenderCity().getId());
}
if (ObjectUtil.isNotEmpty(vo.getSenderCounty())) {
dto.setSenderCountyId(vo.getSenderCounty().getId());
}
if (ObjectUtil.isNotEmpty(vo.getReceiverProvince())) {
dto.setReceiverProvinceId(vo.getReceiverProvince().getId());
}
if (ObjectUtil.isNotEmpty(vo.getReceiverCity())) {
dto.setReceiverCityId(vo.getReceiverCity().getId());
}
if (ObjectUtil.isNotEmpty(vo.getReceiverCounty())) {
dto.setReceiverCountyId(vo.getReceiverCounty().getId());
}
return dto;
}
/**
* 转换订单
* 包含订单信息和运单信息
*
* @param dto 订单DTO
* @return 订单VO
*/
private OrderVO parseOrderDTO2Vo(OrderDTO dto) {
OrderVO vo = BeanUtil.toBean(dto, OrderVO.class);
if (dto.getId() != null) {
List<OrderCargoDTO> cargos = cargoFeign.findAll(null, dto.getId());
log.info("货品信息:{}", cargos);
List<OrderCargoVO> orderCargoVOS = parseCarGoDTO2VO(cargos);
vo.setOrderCargoVOS(orderCargoVOS);
}
Set<Long> areaIdSet = new HashSet<>();
areaIdSet.add(dto.getReceiverProvinceId());
areaIdSet.add(dto.getReceiverCityId());
areaIdSet.add(dto.getReceiverCountyId());
areaIdSet.add(dto.getSenderProvinceId());
areaIdSet.add(dto.getSenderCityId());
areaIdSet.add(dto.getSenderCountyId());
List<AreaDto> areaDtoList = areaFeign.findBatch(new ArrayList<>(areaIdSet));
Map<Long, AreaDto> areaMap = areaDtoList.stream().collect(Collectors.toMap(AreaDto::getId, v -> v));
if (ObjectUtil.isNotEmpty(dto.getSenderProvinceId())) {
AreaDto result = areaMap.get(dto.getSenderProvinceId());
vo.setSenderProvince(baseService.parseArea2Vo(result));
}
if (ObjectUtil.isNotEmpty(dto.getSenderCityId())) {
AreaDto result = areaMap.get(dto.getSenderCityId());
vo.setSenderCity(baseService.parseArea2Vo(result));
}
if (ObjectUtil.isNotEmpty(dto.getSenderCountyId())) {
AreaDto result = areaMap.get(dto.getSenderCountyId());
vo.setSenderCounty(baseService.parseArea2Vo(result));
}
if (ObjectUtil.isNotEmpty(dto.getReceiverProvinceId())) {
AreaDto result = areaMap.get(dto.getReceiverProvinceId());
vo.setReceiverProvince(baseService.parseArea2Vo(result));
}
if (ObjectUtil.isNotEmpty(dto.getReceiverCityId())) {
AreaDto result = areaMap.get(dto.getReceiverCityId());
vo.setReceiverCity(baseService.parseArea2Vo(result));
}
if (ObjectUtil.isNotEmpty(dto.getReceiverCountyId())) {
AreaDto result = areaMap.get(dto.getReceiverCountyId());
vo.setReceiverCounty(baseService.parseArea2Vo(result));
}
// 运单ID
appendTransportOrder(vo);
// 运单信息流
List<TransportOrderPointVO> tracks = tracks(vo.getTransportOrderId());
vo.setTransportOrderPointVOS(tracks);
return vo;
}
@Override
public List<OrderVO> batchParseOrderDTO2Vo(List<OrderDTO> orderDTOList) {
if (CollUtil.isEmpty(orderDTOList)) {
return new ArrayList<>();
}
Set<Long> areaIdSet = new HashSet<>();
orderDTOList.parallelStream().forEach(v -> {
areaIdSet.add(v.getReceiverProvinceId());
areaIdSet.add(v.getReceiverCityId());
areaIdSet.add(v.getReceiverCountyId());
areaIdSet.add(v.getSenderProvinceId());
areaIdSet.add(v.getSenderCityId());
areaIdSet.add(v.getSenderCountyId());
});
List<AreaDto> areaDtoList = areaFeign.findBatch(new ArrayList<>(areaIdSet));
Map<Long, AreaDto> areaMap = areaDtoList.stream().collect(Collectors.toMap(AreaDto::getId, vo -> vo));
Map<Long, String> transportOrderIdMap = transportOrderFeign.findByOrderIds(orderDTOList.parallelStream().map(OrderDTO::getId).collect(Collectors.toList()).toArray(Long[]::new)).parallelStream().collect(Collectors.toMap(TransportOrderDTO::getOrderId, TransportOrderDTO::getId));
return orderDTOList.parallelStream().map(dto -> {
OrderVO vo = BeanUtil.toBean(dto, OrderVO.class);
if (ObjectUtil.isNotEmpty(dto.getSenderProvinceId())) {
AreaDto result = areaMap.get(dto.getSenderProvinceId());
vo.setSenderProvince(baseService.parseArea2Vo(result));
}
if (ObjectUtil.isNotEmpty(dto.getSenderCityId())) {
AreaDto result = areaMap.get(dto.getSenderCityId());
vo.setSenderCity(baseService.parseArea2Vo(result));
}
if (ObjectUtil.isNotEmpty(dto.getSenderCountyId())) {
AreaDto result = areaMap.get(dto.getSenderCountyId());
vo.setSenderCounty(baseService.parseArea2Vo(result));
}
if (ObjectUtil.isNotEmpty(dto.getReceiverProvinceId())) {
AreaDto result = areaMap.get(dto.getReceiverProvinceId());
vo.setReceiverProvince(baseService.parseArea2Vo(result));
}
if (ObjectUtil.isNotEmpty(dto.getReceiverCityId())) {
AreaDto result = areaMap.get(dto.getReceiverCityId());
vo.setReceiverCity(baseService.parseArea2Vo(result));
}
if (ObjectUtil.isNotEmpty(dto.getReceiverCountyId())) {
AreaDto result = areaMap.get(dto.getReceiverCountyId());
vo.setReceiverCounty(baseService.parseArea2Vo(result));
}
// 运单ID
vo.setTransportOrderId(transportOrderIdMap.get(vo.getId()));
return vo;
}).collect(Collectors.toList());
}
/**
* 运单轨迹
*
* @param id 运单ID
* @return 轨迹
*/
@Override
public TrackVO findTrackById(String id) {
TrackDTO trackDTO = trackFeign.queryByTransportOrderId(id);
TrackVO trackVO = BeanUtil.toBean(trackDTO, TrackVO.class);
trackVO.setStatus(trackDTO.getStatus().getCode());
if (ObjectUtil.isNotEmpty(trackDTO.getType()) && trackDTO.getStatus().equals(TrackStatusEnum.NEW)) {
trackVO.setStatus(trackDTO.getType().getCode());
}
return trackVO;
}
}

View File

@@ -0,0 +1,84 @@
package com.sl.ms.web.customer.service.impl;
import cn.hutool.core.date.DateField;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SecureUtil;
import com.sl.ms.web.customer.properties.JwtProperties;
import com.sl.ms.web.customer.service.TokenService;
import com.sl.ms.web.customer.vo.user.UserLoginVO;
import com.sl.transport.common.util.JwtUtils;
import com.sl.transport.common.util.ObjectUtil;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.time.Duration;
import java.util.Map;
@Service
public class TokenServiceImpl implements TokenService {
@Resource
private JwtProperties jwtProperties;
@Resource
private StringRedisTemplate stringRedisTemplate;
public static final String REDIS_REFRESH_TOKEN_PREFIX = "SL_CUSTOMER_REFRESH_TOKEN_";
@Override
public String createAccessToken(Map<String, Object> claims) {
//生成短令牌的有效期时间单位为:分钟
return JwtUtils.createToken(claims, jwtProperties.getPrivateKey(), jwtProperties.getAccessTtl(),
DateField.MINUTE);
}
@Override
public String createRefreshToken(Map<String, Object> claims) {
//生成长令牌的有效期时间单位为:小时
Integer ttl = jwtProperties.getRefreshTtl();
String refreshToken = JwtUtils.createToken(claims, jwtProperties.getPrivateKey(), ttl);
//长令牌只能使用一次需要将其存储到redis中变成有状态的
String redisKey = this.getRedisRefreshToken(refreshToken);
this.stringRedisTemplate.opsForValue().set(redisKey, refreshToken, Duration.ofHours(ttl));
return refreshToken;
}
@Override
public UserLoginVO refreshToken(String refreshToken) {
if (StrUtil.isEmpty(refreshToken)) {
return null;
}
Map<String, Object> originClaims = JwtUtils.checkToken(refreshToken, this.jwtProperties.getPublicKey());
if (ObjectUtil.isEmpty(originClaims)) {
//token无效
return null;
}
//通过redis校验原token是否使用过来确保token只能使用一次
String redisKey = this.getRedisRefreshToken(refreshToken);
Boolean bool = this.stringRedisTemplate.hasKey(redisKey);
if (ObjectUtil.notEqual(bool, Boolean.TRUE)) {
//原token过期或已经使用过
return null;
}
//删除原token
this.stringRedisTemplate.delete(redisKey);
//重新生成长短令牌
String newRefreshToken = this.createRefreshToken(originClaims);
String accessToken = this.createAccessToken(originClaims);
return UserLoginVO.builder()
.accessToken(accessToken)
.refreshToken(newRefreshToken)
.build();
}
private String getRedisRefreshToken(String refreshToken) {
//md5是为了缩短key的长度
return REDIS_REFRESH_TOKEN_PREFIX + SecureUtil.md5(refreshToken);
}
}

View File

@@ -0,0 +1,109 @@
package com.sl.ms.web.customer.service.impl;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.sl.ms.web.customer.service.WechatService;
import com.sl.transport.common.exception.SLWebException;
import com.sl.transport.common.util.ObjectUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.Map;
@Service
@Slf4j
public class WechatServiceImpl implements WechatService {
// 登录
private static final String REQUEST_URL = "https://api.weixin.qq.com/sns/jscode2session?grant_type=authorization_code";
// 获取token
private static final String TOKEN_URL = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
// 获取手机号
private static final String PHONE_REQUEST_URL = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=";
@Value("${sl.wechat.appid}")
private String appId;
@Value("${sl.wechat.secret}")
private String secret;
/**
* 获取openid
* @param code 登录凭证
* @return 唯一标识
*/
@Override
public JSONObject getOpenid(String code) {
Map<String, Object> requestUrlParam = getAppConfig();
// 小程序端授权后的code 登录临时凭证
requestUrlParam.put("js_code", code);
// 发送post请求读取调用微信接口获取openid用户唯一标识
String result = HttpUtil.get(REQUEST_URL, requestUrlParam);
log.info("getOpenid result:{}", result);
// {"session_key":"QbEw1Bp2OpkeCQ36gXvPRg==","openid":"oV4KY1Exd7NebGjfbYK7_KTPeNm4"}
return JSONUtil.parseObj(result);
}
/**
* 获取服务端调用凭证 token
* @return token
*/
public String getToken() {
Map<String, Object> requestUrlParam = getAppConfig();
String result = HttpUtil.get(TOKEN_URL, requestUrlParam);
log.info("getToken result:{}", result);
JSONObject jsonObject = JSONUtil.parseObj(result);
//若code不正确则获取不到openid响应失败
if (ObjectUtil.isNotEmpty(jsonObject.getInt("errcode"))) {
throw new SLWebException(jsonObject.getStr("errmsg"));
}
return jsonObject.getStr("access_token");
}
/**
* 获取手机号
*
* @param code 手机号凭证
* @return 唯一标识
*/
@Override
public String getPhone(String code) {
// 获取服务端调用凭证 token
String token = getToken();
// 增加请求token
String url = PHONE_REQUEST_URL + token;
Map<String, String> map = new HashMap<>();
// 小程序端授权后的手机号临时凭证
map.put("code", code);
// 发送post请求读取调用微信接口获取手机号
String result = HttpUtil.post(url, JSONUtil.toJsonStr(map));
log.info("getPhone result:{}", result);
JSONObject jsonObject = JSONUtil.parseObj(result);
if (jsonObject.getInt("errcode") != 0) {
//若code不正确则获取不到phone响应失败
throw new SLWebException(jsonObject.getStr("errmsg"));
}
return jsonObject.getJSONObject("phone_info").getStr("purePhoneNumber");
}
/**
* 获取应用配置
* @return 参数集合
*/
private Map<String, Object> getAppConfig() {
Map<String, Object> requestUrlParam = new HashMap<>();
// 小程序appId开发者后台获取
requestUrlParam.put("appid", appId);
// 小程序secret开发者后台获取
requestUrlParam.put("secret", secret);
return requestUrlParam;
}
}

View File

@@ -0,0 +1,97 @@
package com.sl.ms.web.customer.vo.base;
import com.sl.ms.user.domain.dto.AddressBookDTO;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.time.LocalDateTime;
/**
* 地址簿
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class AddressBookVO extends AddressBookDTO {
private Long id;
/**
* 用户id
*/
@ApiModelProperty("用户id")
private Long userId;
/**
* 名字
*/
@ApiModelProperty("名字")
private String name;
/**
* 手机号
*/
@ApiModelProperty("手机号")
private String phoneNumber;
/**
* 分机号
*/
@ApiModelProperty("分机号")
private String extensionNumber;
/**
* 省id
*/
@ApiModelProperty("省ID")
private Long provinceId;
/**
* 市id
*/
@ApiModelProperty("市ID")
private Long cityId;
/**
* 区域id
*/
@ApiModelProperty("区ID")
private Long countyId;
/**
* 详细地址
*/
@ApiModelProperty("详细地址")
private String address;
/**
* 公司名称
*/
@ApiModelProperty("公司名称")
private String companyName;
/**
* 是否默认 1默认
*/
@ApiModelProperty("是否默认 1默认")
private Integer isDefault;
@ApiModelProperty(value = "所属省份")
private AreaSimpleVO province;
@ApiModelProperty(value = "所属城市")
private AreaSimpleVO city;
@ApiModelProperty(value = "所属区县")
private AreaSimpleVO county;
/**
* 地址簿类型 1寄件 2收件
*/
@ApiModelProperty(value = " 地址簿类型 1寄件 2收件")
private Integer type;
/**
* 创建时间
*/
@ApiModelProperty("创建时间")
private LocalDateTime created;
/**
* 更新时间
*/
@ApiModelProperty("更新时间")
private LocalDateTime updated;
}

View File

@@ -0,0 +1,25 @@
package com.sl.ms.web.customer.vo.base;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
import java.util.Map;
@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;
@ApiModelProperty(value = "多边形经纬度坐标集合")
private List<List<Map<String, String>>> mutiPoints;
}

View File

@@ -0,0 +1,32 @@
package com.sl.ms.web.customer.vo.base;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* GoodsTypeVo
*/
@Data
@ApiModel(value = "货物类型信息")
public class GoodsTypeVO {
@ApiModelProperty(value = "id")
private Long id;
@ApiModelProperty(value = "货物类型名称")
private String name;
@ApiModelProperty(value = "默认重量,单位:千克")
private BigDecimal defaultWeight = new BigDecimal("0.0");
@ApiModelProperty(value = "默认体积,单位:方")
private BigDecimal defaultVolume = new BigDecimal("0.0");
@ApiModelProperty(value = "说明")
private String remark;
@ApiModelProperty("状态 0禁用 1正常")
private Integer status;
}

View File

@@ -0,0 +1,77 @@
package com.sl.ms.web.customer.vo.oms;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import java.math.BigDecimal;
@Data
public class MailingSaveVO {
@ApiModelProperty("发件方地址簿id")
private Long sendAddress;
@ApiModelProperty("收件方地址簿id")
private Long receiptAddress;
@ApiModelProperty("取件时间")
private String pickUpTime;
@ApiModelProperty("取件方式")
private Integer pickupType;
@ApiModelProperty("付款方式,1.预结2到付")
private Integer payMethod;
@ApiModelProperty("物品类型")
private String goodsType;
@ApiModelProperty("物品名称")
private String goodsName;
@ApiModelProperty("物品数量")
private Integer goodNum;
/**
* 货品总体积 m^3
*/
@ApiModelProperty("货品总体积")
private BigDecimal totalVolume;
/**
* 货品总重量 kg
*/
@ApiModelProperty("货品总重量")
private BigDecimal totalWeight;
/**
* 长单位cm
*/
@ApiModelProperty(value = "单位cm")
@Min(value = 1, message = "长度最小为1")
@Max(value = 999, message = "长度最大为999")
private Integer measureLong;
/**
* 宽单位cm
*/
@ApiModelProperty(value = "单位cm")
@Min(value = 1, message = "宽度最小为1")
@Max(value = 999, message = "宽度最大为999")
private Integer measureWidth;
/**
* 高单位cm
*/
@ApiModelProperty(value = "单位cm")
@Min(value = 1, message = "高度最小为1")
@Max(value = 999, message = "高度最大为999")
private Integer measureHigh;
/**
* 备注
*/
@ApiModelProperty("备注")
private String mark;
}

View File

@@ -0,0 +1,16 @@
package com.sl.ms.web.customer.vo.oms;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Data
public class MarkerPointVO {
@ApiModelProperty("精度")
private Double lng;
@ApiModelProperty("纬度")
private Double lat;
}

View File

@@ -0,0 +1,56 @@
package com.sl.ms.web.customer.vo.oms;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NonNull;
import java.math.BigDecimal;
/**
* 货品总重量
*/
@Data
public class OrderCargoUpdateVO {
@ApiModelProperty(value = "id")
private Long id;
@NonNull
@ApiModelProperty(value = "订单信息")
private Long orderId;
@ApiModelProperty(value = "货物类型信息")
private Long goodsTypeId;
@ApiModelProperty(value = "运单id")
private String tranOrderId;
@ApiModelProperty(value = "货物名称")
private String name;
@ApiModelProperty(value = "货物单位")
private String unit;
@ApiModelProperty(value = "货品货值")
private BigDecimal cargoValue = new BigDecimal("0.0");
@ApiModelProperty(value = "货品条码")
private String cargoBarcode;
@ApiModelProperty(value = "货品数量")
private Integer quantity;
@ApiModelProperty(value = "货品体积")
private BigDecimal volume = new BigDecimal("0.0");
@ApiModelProperty(value = "货品重量")
private BigDecimal weight = new BigDecimal("0.0");
@ApiModelProperty(value = "货品备注")
private String remark;
@ApiModelProperty(value = "货品总体积")
private BigDecimal totalVolume = new BigDecimal("0.0");
@ApiModelProperty(value = "货品总重量")
private BigDecimal totalWeight = new BigDecimal("0.0");
}

View File

@@ -0,0 +1,52 @@
package com.sl.ms.web.customer.vo.oms;
import com.sl.ms.web.customer.vo.base.GoodsTypeVO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
/**
* 货品总重量
*/
@Data
@ApiModel(value = "货物信息")
public class OrderCargoVO {
@ApiModelProperty(value = "id")
private Long id;
@ApiModelProperty(value = "货物类型信息")
private GoodsTypeVO goodsType;
@ApiModelProperty(value = "货物名称")
private String name;
@ApiModelProperty(value = "货物单位")
private String unit;
@ApiModelProperty(value = "货品货值")
private BigDecimal cargoValue;
@ApiModelProperty(value = "货品条码")
private String cargoBarcode;
@ApiModelProperty(value = "货品数量")
private Integer quantity;
@ApiModelProperty(value = "货品体积")
private BigDecimal volume;
@ApiModelProperty(value = "货品重量")
private BigDecimal weight;
@ApiModelProperty(value = "货品备注")
private String remark;
@ApiModelProperty(value = "货品总体积")
private BigDecimal totalVolume;
@ApiModelProperty(value = "货品总重量")
private BigDecimal totalWeight;
}

View File

@@ -0,0 +1,95 @@
package com.sl.ms.web.customer.vo.oms;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.DecimalMin;
import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotNull;
import java.time.LocalDateTime;
import java.util.List;
@Data
public class OrderCarriageVO {
/**
* 运费模板id
*/
@ApiModelProperty(value = "主键")
private Long id;
/**
* 模板类型1-同城寄2-省内寄3-经济区互寄4-跨省
*/
@ApiModelProperty(value = "模板类型1-同城寄2-省内寄3-经济区互寄4-跨省", required = true)
@Max(value = 4, message = "类型值必须是1、2、3、4")
@Min(value = 1, message = "类型值必须是1、2、3、4")
@NotNull(message = "模板类型不能为空")
private Integer templateType;
/**
* 运送类型1-普快2-特快
*/
@ApiModelProperty(value = "运送类型1-普快2-特快", required = true)
@Max(value = 2, message = "类型值必须是1、2")
@Min(value = 1, message = "类型值必须是1、2")
@NotNull(message = "运送类型不能为空")
private Integer transportType;
/**
* 关联城市1-全国2-京津冀3-江浙沪4-川渝5-黑吉辽
*/
@ApiModelProperty(value = "关联城市1-全国2-京津冀3-江浙沪4-川渝5-黑吉辽", required = true)
@NotNull(message = "关联城市不能为空")
private List<String> associatedCityList;
/**
* 首重价格
*/
@ApiModelProperty(value = "首重价格", required = true)
@DecimalMin(value = "0.1", message = "首重价格必须大于0")
@NotNull(message = "首重价格不能为空")
private Double firstWeight;
/**
* 续重价格
*/
@ApiModelProperty(value = "续重价格", required = true)
@DecimalMin(value = "0.1", message = "续重价格必须大于0")
@NotNull(message = "续重价格不能为空")
private Double continuousWeight;
/**
* 基础运费
*/
@ApiModelProperty(value = "基础运费")
private Double baseFreight;
/**
* 轻抛系数
*/
@ApiModelProperty(value = "轻抛系数", required = true)
@Min(value = 1, message = "轻抛系数必须大于0")
@NotNull(message = "轻抛系数不能为空")
private Integer lightThrowingCoefficient;
/**
* 创建时间
*/
@ApiModelProperty(value = "创建时间")
private LocalDateTime created;
/**
* 更新时间
*/
@ApiModelProperty(value = "更新时间")
private LocalDateTime updated;
@ApiModelProperty(value = "运费")
private Double expense;
@ApiModelProperty(value = "计算重量")
private Double computeWeight;
}

View File

@@ -0,0 +1,21 @@
package com.sl.ms.web.customer.vo.oms;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel("订单轨迹参数")
public class OrderLocusVO {
@ApiModelProperty("业务id")
private String businessId;
@ApiModelProperty("开始时间")
private String ge___time;
@ApiModelProperty("结束时间")
private String le___time;
@ApiModelProperty("运输任务id")
private String transportTaskId;
}

View File

@@ -0,0 +1,81 @@
package com.sl.ms.web.customer.vo.oms;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class OrderQueryVO {
@ApiModelProperty(value = "页码")
private Integer page;
@ApiModelProperty(value = "页尺寸")
private Integer pageSize;
@ApiModelProperty(value = "取件类型1为网点自寄2为上门取件")
private Integer pickupType;
@ApiModelProperty(value = "下单时间")
@JsonFormat(
pattern = "yyyy-MM-dd HH:mm:ss"
)
private LocalDateTime createTime;
@ApiModelProperty(value = "收件人详细地址")
private String receiverAddress;
@ApiModelProperty(value = "收件人姓名")
private String receiverName;
@ApiModelProperty(value = "收件人电话")
private String receiverPhone;
@ApiModelProperty("发件人省份id")
private Long senderProvinceId;
@ApiModelProperty("发件人城市id")
private Long senderCityId;
@ApiModelProperty("发件人区域id")
private Long senderCountyId;
@ApiModelProperty("收件人省份id")
private Long receiverProvinceId;
@ApiModelProperty("收件人城市id")
private Long receiverCityId;
@ApiModelProperty("收件人区域id")
private Long receiverCountyId;
@ApiModelProperty(value = "发件人详细地址")
private String senderAddress;
@ApiModelProperty(value = "发件人姓名")
private String senderName;
@ApiModelProperty(value = "发件人电话")
private String senderPhone;
@ApiModelProperty(value = "付款方式,1.预结2到付")
private Integer paymentMethod;
@ApiModelProperty(value = "付款状态,1.未付2已付")
private Integer paymentStatus;
@ApiModelProperty(value = "金额")
private BigDecimal amount;
@ApiModelProperty(value = "下单类型 1 寄件用户 2收件用户")
private Integer mailType;
@ApiModelProperty(value = "订单状态: 23000为待取件,23001为已取件23002为网点自寄" +
"23003为网点入库23004为待装车23005为运输中23006为网点出库23007为待派送" +
"23008为派送中23009为已签收23010为拒收230011为已取消")
private Integer status;
@ApiModelProperty(value = "搜索关键词")
private String keyword;
}

View File

@@ -0,0 +1,142 @@
package com.sl.ms.web.customer.vo.oms;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.sl.ms.web.customer.vo.base.AreaSimpleVO;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;
@Data
@ApiModel(value = "订单信息")
public class OrderVO {
@ApiModelProperty(value = "id")
private Long id;
@ApiModelProperty(value = "货品集合")
private List<OrderCargoVO> orderCargoVOS;
@ApiModelProperty(value = "订单类型1为同城订单2为城际订单")
private Integer orderType;
@ApiModelProperty(value = "取件类型1为网点自寄2为上门取件")
private Integer pickupType;
@ApiModelProperty(value = "下单时间")
@JsonFormat(
pattern = "yyyy-MM-dd HH:mm:ss"
)
private LocalDateTime createTime;
@ApiModelProperty(value = "客户id")
private Long memberId;
@ApiModelProperty(value = "收件人省份")
private AreaSimpleVO receiverProvince;
@ApiModelProperty(value = "收件人城市")
private AreaSimpleVO receiverCity;
@ApiModelProperty(value = "收件人区县")
private AreaSimpleVO receiverCounty;
@ApiModelProperty(value = "收件人详细地址")
private String receiverAddress;
@ApiModelProperty(value = "收件人姓名")
private String receiverName;
@ApiModelProperty(value = "收件人电话")
private String receiverPhone;
@ApiModelProperty(value = "发件人省份")
private AreaSimpleVO senderProvince;
@ApiModelProperty(value = "发件人城市")
private AreaSimpleVO senderCity;
@ApiModelProperty(value = "发件人区县")
private AreaSimpleVO senderCounty;
@ApiModelProperty(value = "发件人详细地址")
private String senderAddress;
@ApiModelProperty(value = "发件人姓名")
private String senderName;
@ApiModelProperty(value = "发件人电话")
private String senderPhone;
@ApiModelProperty(value = "付款方式,1.预结2到付")
private Integer paymentMethod;
@ApiModelProperty(value = "付款状态,1.未付2已付")
private Integer paymentStatus;
@ApiModelProperty(value = "金额")
private BigDecimal amount = new BigDecimal("0.0");
/**
* 首重价格
*/
@ApiModelProperty(value = "首重价格")
private Double firstWeight;
/**
* 续重价格
*/
@ApiModelProperty(value = "续重价格")
private Double continuousWeight;
/**
* 基础运费
*/
@ApiModelProperty(value = "基础运费")
private Double baseFreight;
@ApiModelProperty(value = "预计到达时间")
@JsonFormat(
pattern = "yyyy-MM-dd HH:mm:ss"
)
private LocalDateTime estimatedArrivalTime;
@ApiModelProperty(value = "距离,单位:米")
private Double distance;
/**
* 订单状态: 22000已关闭, 23000为待取件,23001为已取件23002为网点自寄23003为网点入库
* 23004为待装车23005为运输中23006为网点出库23007为待派送23008为派送中
* 23009为已签收23010为拒收230011为已取消
*/
@ApiModelProperty(value = "订单状态: 22000已关闭,23000为待取件,23001为已取件23002为网点自寄" +
"23003为网点入库23004为待装车23005为运输中23006为网点出库23007为待派送" +
"23008为派送中23009为已签收23010为拒收230011为已取消")
private Integer status;
@ApiModelProperty(value = "页码")
private Integer page;
@ApiModelProperty(value = "页尺寸")
private Integer pageSize;
@ApiModelProperty(value = "运单ID")
private String transportOrderId;
@ApiModelProperty(value = "条形码内容 base64编码 png格式")
private String barCode;
@ApiModelProperty(value = "运单信息流")
List<TransportOrderPointVO> transportOrderPointVOS;
/**
* 预计取件时间
*/
@ApiModelProperty(value = "预计取件时间")
private LocalDateTime estimatedStartTime;
@ApiModelProperty(value = "更新时间")
private LocalDateTime updated;
}

View File

@@ -0,0 +1,50 @@
package com.sl.ms.web.customer.vo.oms;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
* @author zzj
* @version 1.0
*/
@Data
public class TrackVO {
/**
* 运单id
*/
private String transportOrderId;
/**
* 轨迹坐标点列表
*/
private List<MarkerPointVO> pointList;
/**
* 距离,单位:米
*/
private Double distance;
/**
* 最新的位置坐标x经度y纬度
*/
private MarkerPointVO lastPoint;
/**
* 状态
*/
@ApiModelProperty(value = "轨迹状态4 COMPLETE, 3 COURIER, 2 DRIVER, 1 NEW")
private Integer status;
/**
* 创建时间
*/
private Long created;
/**
* 更新时间
*/
private Long updated;
}

View File

@@ -0,0 +1,21 @@
package com.sl.ms.web.customer.vo.oms;
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,32 @@
package com.sl.ms.web.customer.vo.oms.pay;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.DecimalMin;
import java.math.BigDecimal;
@AllArgsConstructor
@NoArgsConstructor
@Builder
@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,22 @@
package com.sl.ms.web.customer.vo.oms.pay;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel("支付相关数据" )
public class TradeResponseVO {
@ApiModelProperty(value = "交易系统订单号【对于三方来说:商户订单】")
private Long tradingOrderNo;
@ApiModelProperty(value = "支付渠道【支付宝、微信、现金、免单挂账】")
private String tradingChannel;
@ApiModelProperty(value = "统一下单返回信息,预支付编号")
private String placeOrderMsg;
@ApiModelProperty(value = "统一下单返回信息json【用于生产二维码、Android ios唤醒支付等】")
private String placeOrderJson;
}

View File

@@ -0,0 +1,43 @@
package com.sl.ms.web.customer.vo.user;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 用户信息DTO
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class MemberVO {
/**
* 性别
*/
@ApiModelProperty("性别,1-男0-女")
private Integer sex;
/**
* 生日
*/
@ApiModelProperty("生日,1995-09-01")
private String birthday;
/**
* 身份证号是否认证 1认证
*/
private Integer idCardNoVerify;
/**
* 手机号
*/
private String phone;
/**
* 姓名
*/
private String name;
/**
* 身份证号
*/
private String idCardNo;
}

View File

@@ -0,0 +1,22 @@
package com.sl.ms.web.customer.vo.user;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@ApiModel("实名认证")
@Data
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,17 @@
package com.sl.ms.web.customer.vo.user;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
/**
* C端用户登录
*/
@Data
public class UserLoginRequestVO {
@ApiModelProperty("登录临时凭证")
private String code;
@ApiModelProperty("手机号临时凭证")
private String phoneCode;
}

View File

@@ -0,0 +1,24 @@
package com.sl.ms.web.customer.vo.user;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserLoginVO {
@ApiModelProperty("微信唯一标识符")
private String openid;
@ApiModelProperty("短令牌,有效期较短")
private String accessToken;
@ApiModelProperty("长令牌,有效期较长")
private String refreshToken;
@ApiModelProperty("是否绑定手机号 0否 1是")
private Integer binding;
}

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,25 @@
server:
port: 18091
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

View File

@@ -0,0 +1,24 @@
server:
port: 18091
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

View File

@@ -0,0 +1,24 @@
server:
port: 18091
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

View File

@@ -0,0 +1,24 @@
server:
port: 18091
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

View File

@@ -0,0 +1,23 @@
application:
version: v1.0
logging:
config: classpath:logback-spring.xml
spring:
application:
name: sl-express-ms-web-customer
profiles:
active: local
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.customer.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,19 @@
package com.sl.ms.web.customer.service.impl;
import cn.hutool.crypto.asymmetric.RSA;
import org.junit.jupiter.api.Test;
/**
* @author zzj
* @version 1.0
*/
public class JwtTest {
@Test
public void testRSA(){
RSA rsa = new RSA();
System.out.println("私钥:" + rsa.getPrivateKeyBase64());
System.out.println("公钥:" + rsa.getPublicKeyBase64());
}
}

View File

@@ -0,0 +1,66 @@
package com.sl.ms.web.customer.service.impl;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.extra.qrcode.QrCodeUtil;
import com.google.zxing.BarcodeFormat;
import com.sl.ms.user.api.MemberFeign;
import com.sl.ms.web.customer.vo.oms.TrackVO;
import com.sl.ms.web.customer.vo.oms.pay.TradeLaunchVO;
import com.sl.ms.web.customer.vo.oms.pay.TradeResponseVO;
import com.sl.transport.common.util.UserThreadLocal;
import com.sl.transport.common.vo.AuthUserInfo;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
import java.awt.image.BufferedImage;
import java.io.File;
import java.math.BigDecimal;
@Slf4j
@SpringBootTest
class OmsServiceImplTest {
@Test
void getBarcode() {
BufferedImage image = QrCodeUtil.generate("SL1000000000610", BarcodeFormat.CODE_39, 900, 150);
ImgUtil.write(image, new File("d:/qrcode.png"));
String s = ImgUtil.toBase64DataUri(image, ImgUtil.IMAGE_TYPE_PNG);
log.info(s);
}
@Resource
private OmsServiceImpl omsService;
@Mock
private MemberFeign memberFeign;
@Test
void tracks() {
omsService.tracks(null);
}
@Test
void pay() {
TradeLaunchVO tradeLaunchVO = TradeLaunchVO.builder()
// .enterpriseId("1561414331")
.payMethod(2)
.productOrderNo("1552194476668968961")
.tradingAmount(new BigDecimal("0.1"))
.build();
AuthUserInfo authUserInfo = new AuthUserInfo();
authUserInfo.setUserId(1551748948868157442L);
UserThreadLocal.set(authUserInfo);
TradeResponseVO pay = omsService.pay(tradeLaunchVO);
log.info(pay + "");
}
@Test
public void testName() {
TrackVO sl1000000001164 = omsService.findTrackById("SL1000000001164");
log.info(sl1000000001164 + "");
}
}

View File

@@ -0,0 +1,28 @@
package com.sl.ms.web.customer.service.impl;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import javax.annotation.Resource;
@SpringBootTest
class WechatServiceImplTest {
@Resource
WechatServiceImpl wechatService;
@Test
void getOpenid() {
wechatService.getOpenid("091LmxGa1w2kAD0KCAFa1VzCvm2LmxGB");
}
@Test
void getToken() {
wechatService.getToken();
}
@Test
void getPhone() {
wechatService.getPhone("98b024c7236c108003a5ebc2c7ea59be30636059395899389f82960d07e85fcc");
}
}