1、完善项目

2、完善合同
3、完善费用项
4、司机管理对接OCR
5、完善运输计划
6、完善临时额度
This commit is contained in:
2026-08-04 02:49:59 +08:00
387 changed files with 22482 additions and 110 deletions

View File

@@ -0,0 +1,19 @@
FROM bladex/alpine-java:openjdk17_cn_slim
ARG ACTIVE
LABEL maintainer="bladejava@qq.com"
# 设置时区为上海
ENV TZ=Asia/Shanghai
# 设置时区信息
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
COPY ./target/blade-openapi.jar /opt/app.jar
WORKDIR /opt
EXPOSE 8108
ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=/opt/logs", "-XX:ErrorFile=/opt/logs/hs_err_pid%p.log", "-Xlog:gc*:file=/opt/logs/gc.log:time,uptime,level,tags:filecount=5,filesize=50M", "-XX:MaxDirectMemorySize=512m", "-Xms1024m", "-Xmx4096m", "-jar", "app.jar"]
CMD ["--spring.profiles.active=${ACTIVE}","--logging.path=/opt/logs"]

View File

@@ -0,0 +1,17 @@
#FROM 10.38.16.129/bladex/alpine-java:openjdk17_cn_slim
#FROM registry.cn-hangzhou.aliyuncs.com/vic_person/alpine-java:openjdk17_cn_slim
FROM 10.38.16.129:80/bladex/alpine-java:openjdk17_cn_slim
ARG ACTIVE
LABEL maintainer="bladejava@qq.com"
# 设置时区为上海
ENV TZ=Asia/Shanghai
# 设置时区信息
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
COPY ./target/*.jar /opt/app.jar
ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/opt/app.jar"]
CMD ["--spring.profiles.active=${ACTIVE}"]

View File

@@ -0,0 +1,19 @@
FROM bladex/alpine-java:openjdk17_cn_slim
ARG ACTIVE
LABEL maintainer="bladejava@qq.com"
# 设置时区为上海
ENV TZ=Asia/Shanghai
# 设置时区信息
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
COPY ./target/blade-openapi.jar /opt/app.jar
WORKDIR /opt
EXPOSE 8108
ENTRYPOINT ["java", "--add-opens", "java.base/java.lang=ALL-UNNAMED", "--add-opens", "java.base/java.lang.reflect=ALL-UNNAMED", "-Djava.security.egd=file:/dev/./urandom", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:HeapDumpPath=/opt/logs", "-XX:ErrorFile=/opt/logs/hs_err_pid%p.log", "-Xlog:gc*:file=/opt/logs/gc.log:time,uptime,level,tags:filecount=5,filesize=50M", "-XX:MaxDirectMemorySize=512m", "-Xms1024m", "-Xmx1024m", "-jar", "app.jar"]
CMD ["--spring.profiles.active=${ACTIVE}","--logging.path=/opt/logs"]

View File

@@ -0,0 +1,94 @@
<?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>
<artifactId>blade-service</artifactId>
<groupId>org.springblade</groupId>
<version>${revision}</version>
</parent>
<artifactId>blade-openapi</artifactId>
<properties>
<!-- 其他依赖版本 -->
<lombok.version>1.18.30</lombok.version>
<org.mapstruct.version>1.5.5.Final</org.mapstruct.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-core-boot</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-starter-swagger</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-open-api</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-file-api</artifactId>
</dependency>
<dependency>
<groupId>org.springblade</groupId>
<artifactId>blade-mk-api</artifactId>
</dependency>
<dependency>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct</artifactId>
<version>${org.mapstruct.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>io.fabric8</groupId>
<artifactId>docker-maven-plugin</artifactId>
<configuration>
<skip>${docker.fabric.skip}</skip>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven.plugin.version}</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<encoding>UTF-8</encoding>
<compilerArgs>
<arg>-parameters</arg>
</compilerArgs>
<annotationProcessorPaths>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
<path>
<groupId>org.mapstruct</groupId>
<artifactId>mapstruct-processor</artifactId>
<version>${org.mapstruct.version}</version>
</path>
<!-- other annotation processors -->
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,48 @@
/**
* BladeX Commercial License Agreement
* Copyright (c) 2018-2099, https://bladex.cn. All rights reserved.
* <p>
* Use of this software is governed by the Commercial License Agreement
* obtained after purchasing a license from BladeX.
* <p>
* 1. This software is for development use only under a valid license
* from BladeX.
* <p>
* 2. Redistribution of this software's source code to any third party
* without a commercial license is strictly prohibited.
* <p>
* 3. Licensees may copyright their own code but cannot use segments
* from this software for such purposes. Copyright of this software
* remains with BladeX.
* <p>
* Using this software signifies agreement to this License, and the software
* must not be used for illegal purposes.
* <p>
* THIS SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY. The author is
* not liable for any claims arising from secondary or illegal development.
* <p>
* Author: Chill Zhuang (bladejava@qq.com)
*/
package org.springblade.openapi;
import org.springblade.common.utils.ObsUtil;
import org.springblade.core.cloud.client.BladeCloudApplication;
import org.springblade.core.launch.BladeApplication;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
/**
* Desk启动器
*
* @author Chill
*/
@BladeCloudApplication
@ComponentScan({"org.springblade.openapi", "org.springblade.**.feign"})
@Import(ObsUtil.class)
public class OpenApiApplication {
public static void main(String[] args) {
BladeApplication.run("blade-openapi", OpenApiApplication.class, args);
}
}

View File

@@ -0,0 +1,53 @@
package org.springblade.openapi.resultcode;
import lombok.AllArgsConstructor;
import lombok.Getter;
import org.springblade.core.tool.api.IResultCode;
/**
*
* 业务自定义返回码
* 定义规则:
* 统一格式:[2位服务码][2位模块码][2位功能码][3位错误码]
* <p>
* xx xx xx xx
* |__服务码 |__模块 |__功能 |___错误码
* 业务自定义返回码
* * 定义规则:
* * 统一格式:[2位服务码][2位模块码][2位功能码][3位错误码]
* * <p>
* * xx xx xx xx
* * |__服务码 |__模块 |__功能 |___错误码
* *
服务码:
业务基础服务 10
订单服务 20
仓储服务 30
首页/通告服务 40
系统管理服务 50
开放接口服务 60
* @author vic
* @date 2024/9/12 2:09PM
* @description OrderResultCode
*/
@Getter
@AllArgsConstructor
public enum OpenApiResultCode implements IResultCode {
;
/**
* code编码
*/
final int code;
/**
* 中文信息描述
*/
final String message;
}

View File

@@ -0,0 +1,134 @@
package org.springblade.openapi.wps;
import com.alibaba.fastjson2.JSON;
import io.swagger.v3.oas.annotations.Hidden;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springblade.common.utils.ObsUtil;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.file.feign.IFileClient;
import org.springblade.file.pojo.vo.AttachmentDetailVO;
import org.springblade.openapi.wps.convert.WpsFileConvert;
import org.springblade.openapi.wps.api.IApi4Wps;
import org.springblade.openapi.wps.constant.WpsConstant;
import org.springblade.openapi.wps.exception.Api4WpsException;
import org.springblade.openapi.wps.pojo.dto.Api4WpsFileInfoDTO;
import org.springblade.openapi.wps.pojo.enums.Api4WpsError;
import org.springblade.openapi.wps.util.TokenUtils;
import org.springblade.openapi.wps.pojo.vo.*;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Locale;
/**
* @author bfhuange
* @date 2024/10/30
*/
@Slf4j
@Hidden
@AllArgsConstructor
@RestController
public class Api4Wps implements IApi4Wps {
/**
* 图片扩展名列表
*/
private static final List<String> IMAGE_EXT = List.of("bmp", "jpeg", "jpg", "png", "gif");
private final IFileClient fileClient;
private final WpsFileConvert convert;
@Override
public Api4WpsFileInfoVO getFileInfo(String fileId, String token, Api4WpsFileInfoDTO param) {
log.info("wps回调查询文件信息 参数 fileId{} token{} param{}", fileId, token, JSON.toJSONString(param));
long id = Func.toLong(fileId);
if (id <= 0L) {
throw new Api4WpsException(Api4WpsError.NOT_EXISTS);
}
if (token == null) {
throw new Api4WpsException(Api4WpsError.PERMISSION_DENIED);
}
R<AttachmentDetailVO> result = fileClient.getAttachmentDetail(id);
if (result == null || !result.isSuccess() || result.getData() == null || result.getData().getId() == null) {
log.warn("wps回调查询文件信息 查询附件失败 {}", JSON.toJSONString(result));
throw new Api4WpsException(Api4WpsError.NOT_EXISTS);
}
// 附件
AttachmentDetailVO attachment = result.getData();
Api4WpsFileVO fileVO = convert.attachment2file(attachment);
// 用户信息
Api4WpsUserVO user = TokenUtils.getWpsUser(token);
if (user == null) {
// 用户信息为空token过期了
throw new Api4WpsException(Api4WpsError.SESSION_EXPIRED);
}
// 用户不为空,添加水印
boolean isImage = isImage(attachment.getAttachmentName());
log.info("附件名:{} 是否图片:{}", attachment.getAttachmentName(), isImage);
if (!isImage) {
// 不是图片才加水印
Api4WpsWatermarkVO watermark = new Api4WpsWatermarkVO();
watermark.setType(WpsConstant.YES);
watermark.setValue(user.getName());
watermark.setHorizontal(100);
watermark.setVertical(200);
fileVO.setWatermark(watermark);
}
Api4WpsFileInfoVO fileInfoVO = new Api4WpsFileInfoVO();
fileInfoVO.setUser(user);
fileInfoVO.setFile(fileVO);
// 缓存时间
fileInfoVO.setAttrs(new Api4WpsAttrsVO(WpsConstant.FILE_INFO_DEFAULT_CACHE_TIME));
log.info("wps回调查询文件信息 返回结果:{}", JSON.toJSONString(fileInfoVO));
return fileInfoVO;
}
@Override
public Api4WpsFileInfoVO getFileSave(String fileId, String saveType, String token, MultipartFile file, Api4WpsFileInfoDTO param) {
try {
log.info("wps回调-上传文件新版本 参数 fileId{} token{} param{}", fileId, token, JSON.toJSONString(param));
long id = Func.toLong(fileId);
if (id == 0L) {
return null;
}
R<AttachmentDetailVO> result = fileClient.getAttachmentDetail(id);
if (result == null || !result.isSuccess()) {
log.warn("wps回调-上传文件新版本 查询附件失败 {}", JSON.toJSONString(result));
return null;
}
// 附件
AttachmentDetailVO attachment = result.getData();
Api4WpsFileVO fileVO = convert.attachment2file(attachment);
fileVO.setVersion(2);
ObsUtil.putObject(attachment.getObjectKey(), file.getInputStream());
Api4WpsFileInfoVO fileInfoVO = new Api4WpsFileInfoVO();
fileInfoVO.setFile(fileVO);
return fileInfoVO;
}catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* 是否图片类型
* @param fileName
* @return
*/
public boolean isImage(String fileName) {
if (fileName == null) {
return false;
}
int index = fileName.lastIndexOf(".");
if (index < 0 || index +1 >= fileName.length() ) {
return false;
}
String extName = fileName.substring(index + 1).toLowerCase(Locale.getDefault());
return IMAGE_EXT.contains(extName);
}
}

View File

@@ -0,0 +1,37 @@
package org.springblade.openapi.wps.convert;
import org.mapstruct.*;
import org.springblade.openapi.wps.pojo.vo.Api4WpsFileVO;
import org.springblade.file.pojo.vo.AttachmentDetailVO;
import java.util.Date;
/**
* @author bfhuange
* @date 2024/10/30
*/
@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE)
public interface WpsFileConvert {
@Mapping(source = "attachmentName", target = "name")
@Mapping(source = "url", target = "downloadUrl")
@Mapping(source = "size", target = "size", qualifiedByName = "long2int")
@Mapping(source = "createUser", target = "creator")
@Mapping(source = "createTime", target = "createTime", qualifiedByName = "date2int")
@Mapping(source = "updateUser", target = "modifier")
@Mapping(source = "updateTime", target = "modifyTime", qualifiedByName = "date2int")
Api4WpsFileVO attachment2file(AttachmentDetailVO attachment);
@Named("date2int")
default Integer date2int(Date date) {
if (date == null) {
return null;
}
return Math.toIntExact(date.getTime() / 1000);
}
@Named("long2int")
default Integer long2int(long size) {
return Math.toIntExact(size);
}
}

View File

@@ -0,0 +1,34 @@
package org.springblade.openapi.wps.exception;
import lombok.Getter;
import org.springblade.openapi.wps.pojo.enums.Api4WpsError;
/**
* wps回调接口异常
* @author bfhuange
* @since 2024/11/26
*/
@Getter
public class Api4WpsException extends RuntimeException {
/**
* 错误枚举
*/
private final Api4WpsError error;
/**
* 消息
*/
private final String message;
public Api4WpsException(Api4WpsError error) {
super(error.getMessage());
this.error = error;
this.message = error.getMessage();
}
public Api4WpsException(Api4WpsError error, String message) {
super(message);
this.error = error;
this.message = message;
}
}

View File

@@ -0,0 +1,27 @@
package org.springblade.openapi.wps.exception;
import lombok.extern.slf4j.Slf4j;
import org.springblade.openapi.wps.pojo.enums.Api4WpsError;
import org.springblade.openapi.wps.pojo.vo.Api4WpsErrorVO;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* wps 回调接口异常处理
* @author bfhuange
* @since 2024/11/26
*/
@Slf4j
@RestControllerAdvice
public class Api4WpsExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(Api4WpsException.class)
public Api4WpsErrorVO handleException(Api4WpsException exception) {
log.error("wps 回调接口异常:{}", exception.getMessage(), exception);
Api4WpsError error = exception.getError();
return new Api4WpsErrorVO(error.getCode(), error.getMessage(), exception.getMessage());
}
}

View File

@@ -0,0 +1,33 @@
package org.springblade.openapi.wps.util;
import io.jsonwebtoken.Claims;
import org.springblade.core.launch.constant.TokenConstant;
import org.springblade.core.secure.utils.AuthUtil;
import org.springblade.core.tool.utils.Func;
import org.springblade.core.tool.utils.StringUtil;
import org.springblade.openapi.wps.pojo.vo.Api4WpsUserVO;
/**
* @author bfhuange
* @date 2024/10/30
*/
public class TokenUtils {
/**
* 获取wps需要的用户信息
* @param token
* @return
*/
public static Api4WpsUserVO getWpsUser(String token) {
if (StringUtil.isBlank(token)) {
return null;
}
Claims claims = AuthUtil.parseJWT(token);
if (claims == null) {
return null;
}
String userId = Func.toStr(claims.get(TokenConstant.USER_ID));
String nickName = Func.toStr(claims.get(TokenConstant.NICK_NAME));
return new Api4WpsUserVO(userId, nickName);
}
}

View File

@@ -0,0 +1,6 @@
#spring:
# cloud:
# nacos:
# username: nacos
# password: ${NACOS_PASSWORD:gr30wIs5%Hi7keQj}
# server-addr: ${NACOS_ADDR:10.38.16.127:8848}

View File

@@ -0,0 +1,6 @@
#spring:
# cloud:
# nacos:
# username: nacos
# password: rWrMrVTWyf%ekjuw
# server-addr: ${NACOS_ADDR:192.168.0.242:8848}

View File

@@ -0,0 +1,8 @@
#server:
# port: 38108
#spring:
# cloud:
# nacos:
# username: nacos
# password: gr30wIs5%Hi7keQj
# server-addr: ${NACOS_ADDR:10.38.16.127:8848}

View File

@@ -0,0 +1,54 @@
server:
port: 8108
#数据源配置
spring:
datasource:
url: ${blade.datasource.dev.url}
username: ${blade.datasource.dev.username}
password: ${blade.datasource.dev.password}
cloud:
nacos:
config:
shared-configs:
- data-id: third-party-api.yaml
refresh: true
#第三方接口本地默认配置Nacos third-party-api.yaml 可覆盖
thirdParty:
ocr:
baseUrl: ${OCR_BASE_URL:http://127.0.0.1:8080}
baseOtherUrl: ${OCR_BASE_OTHER_URL:http://127.0.0.1:8080}
wps:
baseUrl: ${WPS_BASE_URL:http://127.0.0.1:8080}
oa:
baseUrl: ${OA_BASE_URL:http://127.0.0.1:8080}
track:
baseUrl: ${TRACK_BASE_URL:http://127.0.0.1:8080}
mk:
baseUrl: ${MK_BASE_URL:http://127.0.0.1:8080}
#spring:
# application:
# name: blade-openapi
# cloud:
# nacos:
# discovery:
# namespace: ${spring.profiles.active}
# # 不注册到nacos
# #registerEnabled: false
# config:
# # 文件后缀名
# file-extension: yaml
# namespace: ${spring.profiles.active}
# shared-configs:
# - data-id: blade.yaml
# refresh: true
# - data-id: blade-${spring.profiles.active}.yaml
# refresh: true
# - data-id: third-party-api.yaml
# refresh: true
# extension-configs:
# - data-id: ${spring.application.name}-dynamictp.yaml
# group: DEFAULT_GROUP
# refresh: true # 必须配置,负责自动刷新不生效