首次提交
This commit is contained in:
+47
@@ -0,0 +1,47 @@
|
||||
######################################################################
|
||||
# Build Tools
|
||||
|
||||
.gradle
|
||||
/build/
|
||||
!gradle/wrapper/gradle-wrapper.jar
|
||||
|
||||
target/
|
||||
!.mvn/wrapper/maven-wrapper.jar
|
||||
|
||||
######################################################################
|
||||
# IDE
|
||||
|
||||
### STS ###
|
||||
.apt_generated
|
||||
.classpath
|
||||
.factorypath
|
||||
.project
|
||||
.settings
|
||||
.springBeans
|
||||
|
||||
### IntelliJ IDEA ###
|
||||
.idea
|
||||
*.iws
|
||||
*.iml
|
||||
*.ipr
|
||||
|
||||
### JRebel ###
|
||||
rebel.xml
|
||||
|
||||
### NetBeans ###
|
||||
nbproject/private/
|
||||
build/*
|
||||
nbbuild/
|
||||
dist/
|
||||
nbdist/
|
||||
.nb-gradle/
|
||||
|
||||
######################################################################
|
||||
# Others
|
||||
*.log
|
||||
*.xml.versionsBackup
|
||||
*.swp
|
||||
|
||||
!*/build/*.java
|
||||
!*/build/*.html
|
||||
!*/build/*.xml
|
||||
@@ -0,0 +1,123 @@
|
||||
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>3.2.5</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<groupId>com.nbport</groupId>
|
||||
<artifactId>zgwl-end</artifactId>
|
||||
<version>1.0.0-SNAPSHOT</version>
|
||||
<name>zgwl-end</name>
|
||||
<description>zgwl-end single module demo</description>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<properties>
|
||||
<java.version>17</java.version>
|
||||
<mybatis-plus.version>3.5.11</mybatis-plus.version>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId>
|
||||
<artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
|
||||
<version>2.2.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baomidou</groupId>
|
||||
<artifactId>mybatis-plus-jsqlparser</artifactId>
|
||||
<version>${mybatis-plus.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
<artifactId>mysql-connector-j</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.oracle.database.jdbc</groupId>
|
||||
<artifactId>ojdbc11</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-all</artifactId>
|
||||
<version>5.8.16</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>easyexcel</artifactId>
|
||||
<version>3.3.2</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.xmlbeans</groupId>
|
||||
<artifactId>xmlbeans</artifactId>
|
||||
<version>3.1.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.alibaba.fastjson2</groupId>
|
||||
<artifactId>fastjson2</artifactId>
|
||||
<version>2.0.47</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.coobird</groupId>
|
||||
<artifactId>thumbnailator</artifactId>
|
||||
<version>0.4.8</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<annotationProcessorPaths>
|
||||
<path>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.32</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
</project>
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.nbport.zgwl;
|
||||
|
||||
import org.mybatis.spring.annotation.MapperScan;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@MapperScan({
|
||||
"com.nbport.zgwl.mapper",
|
||||
"com.nbport.zgwl.partner.mapper",
|
||||
"com.nbport.zgwl.manifest.mapper"
|
||||
})
|
||||
@SpringBootApplication
|
||||
public class ZgwlEndApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(ZgwlEndApplication.class, args);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.nbport.zgwl.common;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ErrorCode implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String code;
|
||||
|
||||
private String msg;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.nbport.zgwl.common;
|
||||
|
||||
import com.nbport.zgwl.exception.ServiceErrorCodeRange;
|
||||
|
||||
public interface GlobalErrorCodeConstants {
|
||||
|
||||
ErrorCode SUCCESS = new ErrorCode("0000", "成功");
|
||||
ErrorCode ERROR = new ErrorCode("9999", "失败");
|
||||
ErrorCode USER_NOT_FOUND = new ErrorCode(ServiceErrorCodeRange.USER_NOT_FOUND, "用户不存在");
|
||||
ErrorCode USERNAME_OR_PWD_ERROR = new ErrorCode(ServiceErrorCodeRange.USERNAME_OR_PWD_ERROR, "用户名或密码错误");
|
||||
ErrorCode USER_NOT_FOUND_OR_NO_DEFAULT = new ErrorCode(ServiceErrorCodeRange.USER_NOT_FOUND, "用户不存在或多租户未配置");
|
||||
ErrorCode UNKNOWN = new ErrorCode(ServiceErrorCodeRange.DEFAULT, "未知错误");
|
||||
ErrorCode PARAMS_ERROR = new ErrorCode(ServiceErrorCodeRange.DEFAULT, "参数不正确");
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.nbport.zgwl.common;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
public class PageResult<T> implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long pageNo;
|
||||
|
||||
private Long pageSize;
|
||||
|
||||
private Long total;
|
||||
|
||||
private Long totalPage;
|
||||
|
||||
private List<T> records = new ArrayList<>();
|
||||
|
||||
public PageResult(IPage<T> page) {
|
||||
this.pageNo = page.getCurrent();
|
||||
this.pageSize = page.getSize();
|
||||
this.total = page.getTotal();
|
||||
this.totalPage = page.getPages();
|
||||
this.records = page.getRecords();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package com.nbport.zgwl.common;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonView;
|
||||
import com.nbport.zgwl.exception.ServiceErrorCodeRange;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Objects;
|
||||
|
||||
public class R<T> implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Schema(description = "响应状态码", example = "0000")
|
||||
@JsonView(Views.Public.class)
|
||||
private String code;
|
||||
|
||||
@Schema(description = "响应数据")
|
||||
@JsonView(Views.Public.class)
|
||||
private T result;
|
||||
|
||||
@Schema(description = "响应消息", example = "操作成功")
|
||||
@JsonView(Views.Public.class)
|
||||
private String message;
|
||||
|
||||
public static <T> R<T> error(R<?> result) {
|
||||
return error(result.getCode(), result.getMessage());
|
||||
}
|
||||
|
||||
public static <T> R<T> error(String code, String message) {
|
||||
if (Objects.equals(GlobalErrorCodeConstants.SUCCESS.getCode(), code)) {
|
||||
throw new ServiceException(ServiceErrorCodeRange.DEFAULT, "code 必须是错误的!");
|
||||
}
|
||||
R<T> result = new R<>();
|
||||
result.code = code;
|
||||
result.message = message;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> R<T> error(ErrorCode errorCode) {
|
||||
return error(errorCode.getCode(), errorCode.getMsg());
|
||||
}
|
||||
|
||||
public static <T> R<T> success(T data) {
|
||||
R<T> result = new R<>();
|
||||
result.code = GlobalErrorCodeConstants.SUCCESS.getCode();
|
||||
result.result = data;
|
||||
result.message = "";
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> R<T> success(String message) {
|
||||
R<T> result = new R<>();
|
||||
result.code = GlobalErrorCodeConstants.SUCCESS.getCode();
|
||||
result.result = null;
|
||||
result.message = message;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> R<T> success(String code, String message) {
|
||||
R<T> result = new R<>();
|
||||
result.code = code;
|
||||
result.result = null;
|
||||
result.message = message;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> R<T> error(String message) {
|
||||
R<T> result = new R<>();
|
||||
result.code = GlobalErrorCodeConstants.ERROR.getCode();
|
||||
result.result = null;
|
||||
result.message = message;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> R<T> success() {
|
||||
R<T> result = new R<>();
|
||||
result.code = GlobalErrorCodeConstants.SUCCESS.getCode();
|
||||
result.result = null;
|
||||
result.message = "";
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> R<T> data(String message, T data) {
|
||||
R<T> result = new R<>();
|
||||
result.code = GlobalErrorCodeConstants.SUCCESS.getCode();
|
||||
result.result = data;
|
||||
result.message = message;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> R<T> data(T data) {
|
||||
R<T> result = new R<>();
|
||||
result.code = GlobalErrorCodeConstants.SUCCESS.getCode();
|
||||
result.result = data;
|
||||
result.message = null;
|
||||
return result;
|
||||
}
|
||||
|
||||
public static boolean isSuccess(String code) {
|
||||
return Objects.equals(code, GlobalErrorCodeConstants.SUCCESS.getCode());
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public boolean isSuccess() {
|
||||
return isSuccess(code);
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public boolean isError() {
|
||||
return !isSuccess();
|
||||
}
|
||||
|
||||
public void checkError() throws ServiceException {
|
||||
if (isSuccess()) {
|
||||
return;
|
||||
}
|
||||
throw new ServiceException(code, message);
|
||||
}
|
||||
|
||||
@JsonIgnore
|
||||
public T getCheckedData() {
|
||||
checkError();
|
||||
return result;
|
||||
}
|
||||
|
||||
public static <T> R<T> error(ServiceException serviceException) {
|
||||
return error(serviceException.getCode(), serviceException.getMessage());
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public T getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setResult(T result) {
|
||||
this.result = result;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public void setMessage(String message) {
|
||||
this.message = message;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package com.nbport.zgwl.common;
|
||||
|
||||
public class Views {
|
||||
|
||||
private Views() {
|
||||
}
|
||||
|
||||
public interface Public {
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.nbport.zgwl.config;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
@Configuration
|
||||
public class MybatisPlusConfig {
|
||||
|
||||
@Value("${spring.datasource.url:}")
|
||||
private String datasourceUrl;
|
||||
|
||||
@Bean
|
||||
public MybatisPlusInterceptor mybatisPlusInterceptor() {
|
||||
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
|
||||
PaginationInnerInterceptor paginationInnerInterceptor =
|
||||
new PaginationInnerInterceptor(resolveDbType(datasourceUrl));
|
||||
paginationInnerInterceptor.setMaxLimit(500L);
|
||||
interceptor.addInnerInterceptor(paginationInnerInterceptor);
|
||||
return interceptor;
|
||||
}
|
||||
|
||||
private DbType resolveDbType(String jdbcUrl) {
|
||||
if (jdbcUrl == null) {
|
||||
return DbType.MYSQL;
|
||||
}
|
||||
String url = jdbcUrl.toLowerCase();
|
||||
if (url.startsWith("jdbc:oracle:")) {
|
||||
return DbType.ORACLE;
|
||||
}
|
||||
if (url.startsWith("jdbc:mysql:")) {
|
||||
return DbType.MYSQL;
|
||||
}
|
||||
return DbType.MYSQL;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.nbport.zgwl.contractpush.config;
|
||||
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* 推送模块基础配置
|
||||
*/
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(ContractPushProperties.class)
|
||||
public class ContractPushConfiguration {
|
||||
|
||||
@Bean
|
||||
public RestTemplate contractPushRestTemplate() {
|
||||
return new RestTemplate();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package com.nbport.zgwl.contractpush.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* 合同推送相关配置
|
||||
* 默认从 application.yml 读取测试地址
|
||||
* 生产环境可以通过 application-prod.yml 覆盖
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "contract-push")
|
||||
public class ContractPushProperties {
|
||||
|
||||
private Settlement settlement = new Settlement();
|
||||
|
||||
private DataCollection dataCollection = new DataCollection();
|
||||
|
||||
@Data
|
||||
public static class Settlement {
|
||||
|
||||
private String systemKey;
|
||||
|
||||
private String secretKey;
|
||||
|
||||
private String tokenUrl;
|
||||
|
||||
private String pushContractUrl;
|
||||
|
||||
private String approveQueryUrl;
|
||||
|
||||
private String archiveUrl;
|
||||
|
||||
private String approveViewBaseUrl;
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class DataCollection {
|
||||
|
||||
private String systemKey;
|
||||
|
||||
private String secretKey;
|
||||
|
||||
private String sysCode;
|
||||
|
||||
private String tokenUrl;
|
||||
|
||||
private String uploadUrl;
|
||||
|
||||
private String collectOppositesUrl;
|
||||
|
||||
private String collectZtbsUrl;
|
||||
|
||||
private String collectContractUrl;
|
||||
|
||||
private String collectPlanFeedbackUrl;
|
||||
|
||||
private String collectContractCloseUrl;
|
||||
|
||||
private String collectContractArchiveUrl;
|
||||
|
||||
private String queryApproveInfoUrl;
|
||||
|
||||
private String approveViewBaseUrl;
|
||||
}
|
||||
}
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
package com.nbport.zgwl.contractpush.controller;
|
||||
|
||||
import com.nbport.zgwl.common.R;
|
||||
import com.nbport.zgwl.contractpush.dto.ApproveQueryRequestDTO;
|
||||
import com.nbport.zgwl.contractpush.dto.ApproveViewUrlRequestDTO;
|
||||
import com.nbport.zgwl.contractpush.dto.PushPayloadDTO;
|
||||
import com.nbport.zgwl.contractpush.dto.PushTokenRequestDTO;
|
||||
import com.nbport.zgwl.contractpush.service.DataCollectionPushService;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RequestPart;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 数据采集推送相关接口
|
||||
* 对应《数据采集接口规范V3.0》
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/contract/push/data-collection")
|
||||
public class DataCollectionPushController {
|
||||
|
||||
private final DataCollectionPushService dataCollectionPushService;
|
||||
|
||||
public DataCollectionPushController(DataCollectionPushService dataCollectionPushService) {
|
||||
this.dataCollectionPushService = dataCollectionPushService;
|
||||
}
|
||||
|
||||
@GetMapping("/token")
|
||||
public R<Map<String, Object>> getToken(PushTokenRequestDTO requestDTO) {
|
||||
return R.success(dataCollectionPushService.getToken(requestDTO));
|
||||
}
|
||||
|
||||
@PostMapping("/upload")
|
||||
public R<Map<String, Object>> upload(@RequestPart("file") MultipartFile file,
|
||||
@RequestParam(value = "token", required = false) String token) {
|
||||
return R.success(dataCollectionPushService.upload(file, token));
|
||||
}
|
||||
|
||||
@PostMapping("/opposites")
|
||||
public R<Map<String, Object>> collectOpposites(@RequestBody PushPayloadDTO requestDTO) {
|
||||
return R.success(dataCollectionPushService.collectOpposites(requestDTO));
|
||||
}
|
||||
|
||||
@PostMapping("/ztbs")
|
||||
public R<Map<String, Object>> collectZtbs(@RequestBody PushPayloadDTO requestDTO) {
|
||||
return R.success(dataCollectionPushService.collectZtbs(requestDTO));
|
||||
}
|
||||
|
||||
@PostMapping("/contract")
|
||||
public R<Map<String, Object>> collectContract(@RequestBody PushPayloadDTO requestDTO) {
|
||||
return R.success(dataCollectionPushService.collectContract(requestDTO));
|
||||
}
|
||||
|
||||
@PostMapping("/plan-feedback")
|
||||
public R<Map<String, Object>> collectPlanFeedback(@RequestBody PushPayloadDTO requestDTO) {
|
||||
return R.success(dataCollectionPushService.collectPlanFeedback(requestDTO));
|
||||
}
|
||||
|
||||
@PostMapping("/close")
|
||||
public R<Map<String, Object>> collectContractClose(@RequestBody PushPayloadDTO requestDTO) {
|
||||
return R.success(dataCollectionPushService.collectContractClose(requestDTO));
|
||||
}
|
||||
|
||||
@PostMapping("/archive")
|
||||
public R<Map<String, Object>> collectContractArchive(@RequestBody PushPayloadDTO requestDTO) {
|
||||
return R.success(dataCollectionPushService.collectContractArchive(requestDTO));
|
||||
}
|
||||
|
||||
@PostMapping("/approve/query")
|
||||
public R<Map<String, Object>> queryApproveInfo(@RequestBody ApproveQueryRequestDTO requestDTO) {
|
||||
return R.success(dataCollectionPushService.queryApproveInfo(requestDTO));
|
||||
}
|
||||
|
||||
@PostMapping("/approve/view-url")
|
||||
public R<Map<String, Object>> buildApproveViewUrl(@RequestBody ApproveViewUrlRequestDTO requestDTO) {
|
||||
return R.success(dataCollectionPushService.buildApproveViewUrl(requestDTO));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.nbport.zgwl.contractpush.controller;
|
||||
|
||||
import com.nbport.zgwl.common.R;
|
||||
import com.nbport.zgwl.contractpush.dto.ApproveQueryRequestDTO;
|
||||
import com.nbport.zgwl.contractpush.dto.ApproveViewUrlRequestDTO;
|
||||
import com.nbport.zgwl.contractpush.dto.PushPayloadDTO;
|
||||
import com.nbport.zgwl.contractpush.dto.PushTokenRequestDTO;
|
||||
import com.nbport.zgwl.contractpush.service.SettlementPushService;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 结算平台推送相关接口
|
||||
* 对应《结算平台推送合同接口文档V9.5》
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/contract/push/settlement")
|
||||
public class SettlementPushController {
|
||||
|
||||
private final SettlementPushService settlementPushService;
|
||||
|
||||
public SettlementPushController(SettlementPushService settlementPushService) {
|
||||
this.settlementPushService = settlementPushService;
|
||||
}
|
||||
|
||||
@GetMapping("/token")
|
||||
public R<Map<String, Object>> getToken(PushTokenRequestDTO requestDTO) {
|
||||
return R.success(settlementPushService.getToken(requestDTO));
|
||||
}
|
||||
|
||||
@PostMapping("/contract")
|
||||
public R<Map<String, Object>> pushContract(@RequestBody PushPayloadDTO requestDTO) {
|
||||
return R.success(settlementPushService.pushContract(requestDTO));
|
||||
}
|
||||
|
||||
@PostMapping("/approve/query")
|
||||
public R<Map<String, Object>> queryApproveInfo(@RequestBody ApproveQueryRequestDTO requestDTO) {
|
||||
return R.success(settlementPushService.queryApproveInfo(requestDTO));
|
||||
}
|
||||
|
||||
@PostMapping("/archive")
|
||||
public R<Map<String, Object>> pushArchive(@RequestBody PushPayloadDTO requestDTO) {
|
||||
return R.success(settlementPushService.pushArchive(requestDTO));
|
||||
}
|
||||
|
||||
@PostMapping("/approve/view-url")
|
||||
public R<Map<String, Object>> buildApproveViewUrl(@RequestBody ApproveViewUrlRequestDTO requestDTO) {
|
||||
return R.success(settlementPushService.buildApproveViewUrl(requestDTO));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.nbport.zgwl.contractpush.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 审批信息查询 / 单点查看地址拼装请求
|
||||
*/
|
||||
@Data
|
||||
public class ApproveQueryRequestDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String token;
|
||||
|
||||
private String phoneNum;
|
||||
|
||||
private String contractSysId;
|
||||
|
||||
private String contractCode;
|
||||
|
||||
private String contractId;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.nbport.zgwl.contractpush.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 审批查看地址拼装参数
|
||||
*/
|
||||
@Data
|
||||
public class ApproveViewUrlRequestDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String contractId;
|
||||
|
||||
private String ivUser;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.nbport.zgwl.contractpush.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 通用推送请求体
|
||||
* token 不传时,Service 内部会自动获取
|
||||
* payload 直接放文档原始 JSON 结构即可
|
||||
*/
|
||||
@Data
|
||||
public class PushPayloadDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String token;
|
||||
|
||||
private Map<String, Object> payload = new LinkedHashMap<>();
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.nbport.zgwl.contractpush.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 获取 token 时可选覆盖默认 systemKey / secretKey
|
||||
*/
|
||||
@Data
|
||||
public class PushTokenRequestDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String systemKey;
|
||||
|
||||
private String secretKey;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.nbport.zgwl.contractpush.handler;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 推送请求加工器
|
||||
* 这里只做最基础的 token、sys_code、时间戳补全,保持逻辑简单
|
||||
*/
|
||||
@Component
|
||||
public class ContractPushRequestHandler {
|
||||
|
||||
public Map<String, Object> copyPayload(Map<String, Object> payload) {
|
||||
return payload == null ? new LinkedHashMap<>() : new LinkedHashMap<>(payload);
|
||||
}
|
||||
|
||||
public Map<String, Object> prepareSettlementPayload(Map<String, Object> payload, String token) {
|
||||
Map<String, Object> requestBody = copyPayload(payload);
|
||||
if (StrUtil.isBlank(token)) {
|
||||
throw new ServiceException("结算平台 token 不能为空");
|
||||
}
|
||||
requestBody.put("token", token);
|
||||
return requestBody;
|
||||
}
|
||||
|
||||
public Map<String, Object> prepareDataCollectionPayload(Map<String, Object> payload, String sysCode) {
|
||||
Map<String, Object> requestBody = copyPayload(payload);
|
||||
if (StrUtil.isBlank(sysCode)) {
|
||||
throw new ServiceException("数据采集 sysCode 未配置");
|
||||
}
|
||||
requestBody.put("sys_code", sysCode);
|
||||
requestBody.putIfAbsent("timeStamp", String.valueOf(System.currentTimeMillis()));
|
||||
return requestBody;
|
||||
}
|
||||
|
||||
public Map<String, String> buildDataCollectionHeaders(String token, String systemKey, boolean includeSystemKey) {
|
||||
if (StrUtil.isBlank(token)) {
|
||||
throw new ServiceException("数据采集 cj_token 不能为空");
|
||||
}
|
||||
Map<String, String> headers = new LinkedHashMap<>();
|
||||
headers.put("cj_token", token);
|
||||
if (includeSystemKey) {
|
||||
headers.put("systemKey", systemKey);
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
package com.nbport.zgwl.contractpush.service;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.nbport.zgwl.contractpush.config.ContractPushProperties;
|
||||
import com.nbport.zgwl.contractpush.dto.ApproveQueryRequestDTO;
|
||||
import com.nbport.zgwl.contractpush.dto.ApproveViewUrlRequestDTO;
|
||||
import com.nbport.zgwl.contractpush.dto.PushPayloadDTO;
|
||||
import com.nbport.zgwl.contractpush.dto.PushTokenRequestDTO;
|
||||
import com.nbport.zgwl.contractpush.handler.ContractPushRequestHandler;
|
||||
import com.nbport.zgwl.contractpush.utils.ContractPushHttpUtils;
|
||||
import com.nbport.zgwl.contractpush.utils.ContractPushUrlUtils;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 数据采集推送服务
|
||||
* 对应《数据采集接口规范V3.0》
|
||||
*/
|
||||
@Service
|
||||
public class DataCollectionPushService {
|
||||
|
||||
private final ContractPushProperties properties;
|
||||
private final ContractPushHttpUtils httpUtils;
|
||||
private final ContractPushRequestHandler requestHandler;
|
||||
|
||||
public DataCollectionPushService(ContractPushProperties properties,
|
||||
ContractPushHttpUtils httpUtils,
|
||||
ContractPushRequestHandler requestHandler) {
|
||||
this.properties = properties;
|
||||
this.httpUtils = httpUtils;
|
||||
this.requestHandler = requestHandler;
|
||||
}
|
||||
|
||||
public Map<String, Object> getToken(PushTokenRequestDTO requestDTO) {
|
||||
String systemKey = requestDTO != null && StrUtil.isNotBlank(requestDTO.getSystemKey())
|
||||
? requestDTO.getSystemKey()
|
||||
: properties.getDataCollection().getSystemKey();
|
||||
String secretKey = requestDTO != null && StrUtil.isNotBlank(requestDTO.getSecretKey())
|
||||
? requestDTO.getSecretKey()
|
||||
: properties.getDataCollection().getSecretKey();
|
||||
|
||||
Map<String, String> query = new LinkedHashMap<>();
|
||||
query.put("systemKey", systemKey);
|
||||
query.put("secretKey", secretKey);
|
||||
return httpUtils.get(properties.getDataCollection().getTokenUrl(), query);
|
||||
}
|
||||
|
||||
public Map<String, Object> upload(MultipartFile file, String token) {
|
||||
Map<String, String> headers = requestHandler.buildDataCollectionHeaders(
|
||||
resolveCollectionToken(token),
|
||||
properties.getDataCollection().getSystemKey(),
|
||||
true
|
||||
);
|
||||
return httpUtils.postMultipart(properties.getDataCollection().getUploadUrl(), file, headers);
|
||||
}
|
||||
|
||||
public Map<String, Object> collectOpposites(PushPayloadDTO requestDTO) {
|
||||
return postCollectionJson(properties.getDataCollection().getCollectOppositesUrl(), requestDTO, false);
|
||||
}
|
||||
|
||||
public Map<String, Object> collectZtbs(PushPayloadDTO requestDTO) {
|
||||
return postCollectionJson(properties.getDataCollection().getCollectZtbsUrl(), requestDTO, false);
|
||||
}
|
||||
|
||||
public Map<String, Object> collectContract(PushPayloadDTO requestDTO) {
|
||||
return postCollectionJson(properties.getDataCollection().getCollectContractUrl(), requestDTO, false);
|
||||
}
|
||||
|
||||
public Map<String, Object> collectPlanFeedback(PushPayloadDTO requestDTO) {
|
||||
return postCollectionJson(properties.getDataCollection().getCollectPlanFeedbackUrl(), requestDTO, false);
|
||||
}
|
||||
|
||||
public Map<String, Object> collectContractClose(PushPayloadDTO requestDTO) {
|
||||
return postCollectionJson(properties.getDataCollection().getCollectContractCloseUrl(), requestDTO, false);
|
||||
}
|
||||
|
||||
public Map<String, Object> collectContractArchive(PushPayloadDTO requestDTO) {
|
||||
return postCollectionJson(properties.getDataCollection().getCollectContractArchiveUrl(), requestDTO, false);
|
||||
}
|
||||
|
||||
public Map<String, Object> queryApproveInfo(ApproveQueryRequestDTO requestDTO) {
|
||||
Map<String, Object> body = new LinkedHashMap<>();
|
||||
body.put("contractCode", requestDTO == null ? null : requestDTO.getContractCode());
|
||||
body.put("contractId", requestDTO == null ? null : requestDTO.getContractId());
|
||||
body.put("phoneNum", requestDTO == null ? null : requestDTO.getPhoneNum());
|
||||
|
||||
Map<String, String> headers = requestHandler.buildDataCollectionHeaders(
|
||||
resolveCollectionToken(requestDTO == null ? null : requestDTO.getToken()),
|
||||
properties.getDataCollection().getSystemKey(),
|
||||
true
|
||||
);
|
||||
Map<String, Object> requestBody = requestHandler.prepareDataCollectionPayload(
|
||||
body,
|
||||
properties.getDataCollection().getSysCode()
|
||||
);
|
||||
return httpUtils.postJson(properties.getDataCollection().getQueryApproveInfoUrl(), requestBody, headers);
|
||||
}
|
||||
|
||||
public Map<String, Object> buildApproveViewUrl(ApproveViewUrlRequestDTO requestDTO) {
|
||||
if (requestDTO == null || StrUtil.isBlank(requestDTO.getContractId()) || StrUtil.isBlank(requestDTO.getIvUser())) {
|
||||
throw new ServiceException("contractId 和 ivUser 不能为空");
|
||||
}
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put(
|
||||
"approveViewUrl",
|
||||
ContractPushUrlUtils.buildApproveViewUrl(
|
||||
properties.getDataCollection().getApproveViewBaseUrl(),
|
||||
requestDTO.getContractId(),
|
||||
requestDTO.getIvUser()
|
||||
)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
private Map<String, Object> postCollectionJson(String url, PushPayloadDTO requestDTO, boolean includeSystemKeyHeader) {
|
||||
String token = resolveCollectionToken(requestDTO == null ? null : requestDTO.getToken());
|
||||
Map<String, String> headers = requestHandler.buildDataCollectionHeaders(
|
||||
token,
|
||||
properties.getDataCollection().getSystemKey(),
|
||||
includeSystemKeyHeader
|
||||
);
|
||||
Map<String, Object> requestBody = requestHandler.prepareDataCollectionPayload(
|
||||
requestDTO == null ? null : requestDTO.getPayload(),
|
||||
properties.getDataCollection().getSysCode()
|
||||
);
|
||||
return httpUtils.postJson(url, requestBody, headers);
|
||||
}
|
||||
|
||||
private String resolveCollectionToken(String inputToken) {
|
||||
if (StrUtil.isNotBlank(inputToken)) {
|
||||
return inputToken;
|
||||
}
|
||||
Map<String, Object> tokenResult = getToken(new PushTokenRequestDTO());
|
||||
Object data = tokenResult.get("data");
|
||||
if (data instanceof Map) {
|
||||
Object accessToken = ((Map<?, ?>) data).get("access_token");
|
||||
if (accessToken != null) {
|
||||
return String.valueOf(accessToken);
|
||||
}
|
||||
}
|
||||
throw new ServiceException("获取数据采集 token 失败");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package com.nbport.zgwl.contractpush.service;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.nbport.zgwl.contractpush.config.ContractPushProperties;
|
||||
import com.nbport.zgwl.contractpush.dto.ApproveQueryRequestDTO;
|
||||
import com.nbport.zgwl.contractpush.dto.ApproveViewUrlRequestDTO;
|
||||
import com.nbport.zgwl.contractpush.dto.PushPayloadDTO;
|
||||
import com.nbport.zgwl.contractpush.dto.PushTokenRequestDTO;
|
||||
import com.nbport.zgwl.contractpush.handler.ContractPushRequestHandler;
|
||||
import com.nbport.zgwl.contractpush.utils.ContractPushHttpUtils;
|
||||
import com.nbport.zgwl.contractpush.utils.ContractPushUrlUtils;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 结算平台推送服务
|
||||
* 对应《结算平台推送合同接口文档V9.5》
|
||||
*/
|
||||
@Service
|
||||
public class SettlementPushService {
|
||||
|
||||
private final ContractPushProperties properties;
|
||||
private final ContractPushHttpUtils httpUtils;
|
||||
private final ContractPushRequestHandler requestHandler;
|
||||
|
||||
public SettlementPushService(ContractPushProperties properties,
|
||||
ContractPushHttpUtils httpUtils,
|
||||
ContractPushRequestHandler requestHandler) {
|
||||
this.properties = properties;
|
||||
this.httpUtils = httpUtils;
|
||||
this.requestHandler = requestHandler;
|
||||
}
|
||||
|
||||
public Map<String, Object> getToken(PushTokenRequestDTO requestDTO) {
|
||||
String systemKey = requestDTO != null && StrUtil.isNotBlank(requestDTO.getSystemKey())
|
||||
? requestDTO.getSystemKey()
|
||||
: properties.getSettlement().getSystemKey();
|
||||
|
||||
Map<String, String> query = new LinkedHashMap<>();
|
||||
query.put("systemKey", systemKey);
|
||||
return httpUtils.get(properties.getSettlement().getTokenUrl(), query);
|
||||
}
|
||||
|
||||
public Map<String, Object> pushContract(PushPayloadDTO requestDTO) {
|
||||
String token = resolveSettlementToken(requestDTO == null ? null : requestDTO.getToken());
|
||||
Map<String, Object> body = requestHandler.prepareSettlementPayload(
|
||||
requestDTO == null ? null : requestDTO.getPayload(),
|
||||
token
|
||||
);
|
||||
return httpUtils.postJson(properties.getSettlement().getPushContractUrl(), body, null);
|
||||
}
|
||||
|
||||
public Map<String, Object> queryApproveInfo(ApproveQueryRequestDTO requestDTO) {
|
||||
Map<String, Object> body = new LinkedHashMap<>();
|
||||
body.put("token", resolveSettlementToken(requestDTO == null ? null : requestDTO.getToken()));
|
||||
body.put("phoneNum", requestDTO == null ? null : requestDTO.getPhoneNum());
|
||||
body.put("contractSysId", requestDTO == null ? null : requestDTO.getContractSysId());
|
||||
return httpUtils.postJson(properties.getSettlement().getApproveQueryUrl(), body, null);
|
||||
}
|
||||
|
||||
public Map<String, Object> pushArchive(PushPayloadDTO requestDTO) {
|
||||
String token = resolveSettlementToken(requestDTO == null ? null : requestDTO.getToken());
|
||||
Map<String, Object> body = requestHandler.prepareSettlementPayload(
|
||||
requestDTO == null ? null : requestDTO.getPayload(),
|
||||
token
|
||||
);
|
||||
return httpUtils.postJson(properties.getSettlement().getArchiveUrl(), body, null);
|
||||
}
|
||||
|
||||
public Map<String, Object> buildApproveViewUrl(ApproveViewUrlRequestDTO requestDTO) {
|
||||
if (requestDTO == null || StrUtil.isBlank(requestDTO.getContractId()) || StrUtil.isBlank(requestDTO.getIvUser())) {
|
||||
throw new ServiceException("contractId 和 ivUser 不能为空");
|
||||
}
|
||||
Map<String, Object> result = new LinkedHashMap<>();
|
||||
result.put(
|
||||
"approveViewUrl",
|
||||
ContractPushUrlUtils.buildApproveViewUrl(
|
||||
properties.getSettlement().getApproveViewBaseUrl(),
|
||||
requestDTO.getContractId(),
|
||||
requestDTO.getIvUser()
|
||||
)
|
||||
);
|
||||
return result;
|
||||
}
|
||||
|
||||
private String resolveSettlementToken(String inputToken) {
|
||||
if (StrUtil.isNotBlank(inputToken)) {
|
||||
return inputToken;
|
||||
}
|
||||
Map<String, Object> tokenResult = getToken(new PushTokenRequestDTO());
|
||||
Object data = tokenResult.get("data");
|
||||
if (data instanceof Map) {
|
||||
Object accessToken = ((Map<?, ?>) data).get("access_token");
|
||||
if (accessToken != null) {
|
||||
return String.valueOf(accessToken);
|
||||
}
|
||||
}
|
||||
throw new ServiceException("获取结算平台 token 失败");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.nbport.zgwl.contractpush.utils;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 最简单的 HTTP 调用工具
|
||||
* 当前只做 GET / POST JSON / POST MULTIPART 三种
|
||||
*/
|
||||
@Component
|
||||
public class ContractPushHttpUtils {
|
||||
|
||||
private final RestTemplate restTemplate;
|
||||
|
||||
public ContractPushHttpUtils(RestTemplate contractPushRestTemplate) {
|
||||
this.restTemplate = contractPushRestTemplate;
|
||||
}
|
||||
|
||||
public Map<String, Object> get(String url, Map<String, String> queryParams) {
|
||||
String finalUrl = ContractPushUrlUtils.appendQuery(url, queryParams);
|
||||
ResponseEntity<String> response = restTemplate.getForEntity(finalUrl, String.class);
|
||||
return parseResponse(response.getBody());
|
||||
}
|
||||
|
||||
public Map<String, Object> postJson(String url, Map<String, Object> body, Map<String, String> headers) {
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
|
||||
addHeaders(httpHeaders, headers);
|
||||
HttpEntity<Map<String, Object>> entity = new HttpEntity<>(body, httpHeaders);
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
|
||||
return parseResponse(response.getBody());
|
||||
}
|
||||
|
||||
public Map<String, Object> postMultipart(String url, MultipartFile file, Map<String, String> headers) {
|
||||
if (file == null || file.isEmpty()) {
|
||||
throw new ServiceException("上传文件不能为空");
|
||||
}
|
||||
|
||||
HttpHeaders httpHeaders = new HttpHeaders();
|
||||
httpHeaders.setContentType(MediaType.MULTIPART_FORM_DATA);
|
||||
addHeaders(httpHeaders, headers);
|
||||
|
||||
MultiValueMap<String, Object> formData = new LinkedMultiValueMap<>();
|
||||
formData.add("file", toByteArrayResource(file));
|
||||
|
||||
HttpEntity<MultiValueMap<String, Object>> entity = new HttpEntity<>(formData, httpHeaders);
|
||||
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
|
||||
return parseResponse(response.getBody());
|
||||
}
|
||||
|
||||
private ByteArrayResource toByteArrayResource(MultipartFile file) {
|
||||
try {
|
||||
return new ByteArrayResource(file.getBytes()) {
|
||||
@Override
|
||||
public String getFilename() {
|
||||
return file.getOriginalFilename();
|
||||
}
|
||||
};
|
||||
} catch (IOException e) {
|
||||
throw new ServiceException("读取上传文件失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void addHeaders(HttpHeaders httpHeaders, Map<String, String> headers) {
|
||||
if (headers == null || headers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
headers.forEach(httpHeaders::add);
|
||||
}
|
||||
|
||||
private Map<String, Object> parseResponse(String responseBody) {
|
||||
if (responseBody == null || responseBody.trim().isEmpty()) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
try {
|
||||
return JSON.parseObject(responseBody, new TypeReference<LinkedHashMap<String, Object>>() {
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
Map<String, Object> fallback = new LinkedHashMap<>();
|
||||
fallback.put("raw", responseBody);
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.nbport.zgwl.contractpush.utils;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.StringJoiner;
|
||||
|
||||
/**
|
||||
* URL 拼装工具
|
||||
*/
|
||||
public final class ContractPushUrlUtils {
|
||||
|
||||
private ContractPushUrlUtils() {
|
||||
}
|
||||
|
||||
public static String appendQuery(String url, Map<String, String> queryParams) {
|
||||
if (queryParams == null || queryParams.isEmpty()) {
|
||||
return url;
|
||||
}
|
||||
StringJoiner joiner = new StringJoiner("&");
|
||||
queryParams.forEach((key, value) -> {
|
||||
if (StrUtil.isNotBlank(value)) {
|
||||
joiner.add(encode(key) + "=" + encode(value));
|
||||
}
|
||||
});
|
||||
return url + (url.contains("?") ? "&" : "?") + joiner;
|
||||
}
|
||||
|
||||
public static String buildApproveViewUrl(String baseUrl, String contractId, String ivUser) {
|
||||
if (StrUtil.isBlank(baseUrl)) {
|
||||
throw new ServiceException("审批查看地址未配置");
|
||||
}
|
||||
Map<String, String> params = new LinkedHashMap<>();
|
||||
params.put("id", contractId);
|
||||
params.put("ssoToken", ivUser);
|
||||
return appendQuery(baseUrl, params);
|
||||
}
|
||||
|
||||
private static String encode(String value) {
|
||||
try {
|
||||
return URLEncoder.encode(value, "UTF-8");
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
throw new ServiceException("URL 编码失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.nbport.zgwl.controller;
|
||||
|
||||
import com.nbport.zgwl.common.R;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
import com.nbport.zgwl.service.LocalFileService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/trans/minio/file")
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Validated
|
||||
public class MinioFileController {
|
||||
|
||||
private final LocalFileService localFileService;
|
||||
|
||||
@PostMapping(value = "/uploadOutie", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
|
||||
public R<String> uploadOutie(MultipartHttpServletRequest request) {
|
||||
Map<String, MultipartFile> fileMap = request.getFileMap();
|
||||
if (CollectionUtils.isEmpty(fileMap)) {
|
||||
throw new ServiceException("请上传文件");
|
||||
}
|
||||
MultipartFile file = fileMap.values().iterator().next();
|
||||
log.info("接收到上传文件请求,fileName={}", file.getOriginalFilename());
|
||||
String relativePath = localFileService.upload(file);
|
||||
return R.success(relativePath);
|
||||
}
|
||||
|
||||
@GetMapping("/download")
|
||||
public ResponseEntity<ByteArrayResource> download(@RequestParam("fileName") String fileName) {
|
||||
log.info("接收到文件下载请求,fileName={}", fileName);
|
||||
return localFileService.download(fileName);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package com.nbport.zgwl.controller;
|
||||
|
||||
import com.nbport.zgwl.common.PageResult;
|
||||
import com.nbport.zgwl.common.R;
|
||||
import com.nbport.zgwl.dto.StudentQueryDto;
|
||||
import com.nbport.zgwl.dto.StudentSaveDto;
|
||||
import com.nbport.zgwl.entity.StudentEntity;
|
||||
import com.nbport.zgwl.entity.SysUserEntity;
|
||||
import com.nbport.zgwl.service.StudentService;
|
||||
import com.nbport.zgwl.utils.MockSecurityManager;
|
||||
import jakarta.validation.Valid;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping("/student")
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
@Validated
|
||||
public class StudentController {
|
||||
|
||||
private final StudentService studentService;
|
||||
private final MockSecurityManager securityManager;
|
||||
|
||||
@PostMapping("/list")
|
||||
public R<PageResult<Map<String, Object>>> queryList(@RequestBody StudentQueryDto queryDto) {
|
||||
SysUserEntity user = securityManager.getLoginUser();
|
||||
PageResult<Map<String, Object>> pageResult = studentService.queryList(queryDto, user);
|
||||
return R.success(pageResult);
|
||||
}
|
||||
|
||||
@GetMapping("/detail/{id}")
|
||||
public R<StudentEntity> detail(@PathVariable("id") Long id) {
|
||||
return R.success(studentService.detail(id));
|
||||
}
|
||||
|
||||
@PostMapping("/add")
|
||||
public R<String> add(@RequestBody @Valid StudentSaveDto dto) {
|
||||
log.info("新增学生请求:{}", dto);
|
||||
studentService.add(dto);
|
||||
return R.success("新增成功");
|
||||
}
|
||||
|
||||
@PostMapping("/update")
|
||||
public R<String> update(@RequestBody @Valid StudentSaveDto dto) {
|
||||
log.info("修改学生请求:{}", dto);
|
||||
studentService.update(dto);
|
||||
return R.success("修改成功");
|
||||
}
|
||||
|
||||
@PostMapping("/delete/{id}")
|
||||
public R<String> delete(@PathVariable("id") Long id) {
|
||||
studentService.delete(id);
|
||||
return R.success("删除成功");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.nbport.zgwl.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class BasePageDto implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long pageNo = 1L;
|
||||
|
||||
private Long pageSize = 15L;
|
||||
|
||||
private Sorter sorter;
|
||||
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
@Builder
|
||||
public static class Sorter implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public static final String ASC = "asc";
|
||||
|
||||
public static final String DESC = "desc";
|
||||
|
||||
private String field;
|
||||
|
||||
@Builder.Default
|
||||
private String order = ASC;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.nbport.zgwl.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class StudentQueryDto extends BasePageDto implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String studentNo;
|
||||
|
||||
private String studentName;
|
||||
|
||||
private String gender;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.nbport.zgwl.dto;
|
||||
|
||||
import jakarta.validation.constraints.Max;
|
||||
import jakarta.validation.constraints.Min;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
public class StudentSaveDto implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
|
||||
@NotBlank(message = "学号不能为空")
|
||||
private String studentNo;
|
||||
|
||||
@NotBlank(message = "姓名不能为空")
|
||||
private String studentName;
|
||||
|
||||
@NotBlank(message = "性别不能为空")
|
||||
private String gender;
|
||||
|
||||
@NotNull(message = "年龄不能为空")
|
||||
@Min(value = 1, message = "年龄不能小于 1")
|
||||
@Max(value = 120, message = "年龄不能大于 120")
|
||||
private Integer age;
|
||||
|
||||
private String phone;
|
||||
|
||||
private String address;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.nbport.zgwl.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.ToString;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@ToString
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@Accessors(chain = true)
|
||||
public class BaseEntity<T extends Model<?>> extends Model<T> implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableField(value = "create_dt", fill = FieldFill.INSERT)
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private LocalDateTime createDt;
|
||||
|
||||
@TableField(value = "update_dt", fill = FieldFill.UPDATE)
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private LocalDateTime updateDt;
|
||||
|
||||
@TableField(value = "create_by", fill = FieldFill.INSERT)
|
||||
private String createBy;
|
||||
|
||||
@TableField(value = "update_by", fill = FieldFill.UPDATE)
|
||||
private String updateBy;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.nbport.zgwl.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
@Data
|
||||
@TableName(value = "BIZ_STUDENT")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@KeySequence(value = "SEQ_BIZ_STUDENT", dbType = DbType.ORACLE)
|
||||
public class StudentEntity extends BaseEntity<StudentEntity> {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.INPUT)
|
||||
private Long id;
|
||||
|
||||
@TableField("student_no")
|
||||
private String studentNo;
|
||||
|
||||
@TableField("student_name")
|
||||
private String studentName;
|
||||
|
||||
@TableField("gender")
|
||||
private String gender;
|
||||
|
||||
@TableField("age")
|
||||
private Integer age;
|
||||
|
||||
@TableField("phone")
|
||||
private String phone;
|
||||
|
||||
@TableField("address")
|
||||
private String address;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.nbport.zgwl.entity;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
|
||||
@Data
|
||||
@TableName(value = "sys_user")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class SysUserEntity extends BaseEntity<SysUserEntity> {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "id", type = IdType.INPUT)
|
||||
private Long id;
|
||||
|
||||
@TableField("username")
|
||||
private String username;
|
||||
|
||||
@TableField("mobile_phone")
|
||||
private String mobilePhone;
|
||||
|
||||
@TableField("email")
|
||||
private String email;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.nbport.zgwl.exception;
|
||||
|
||||
public interface ServiceErrorCodeRange {
|
||||
|
||||
String DEFAULT = "A0001";
|
||||
|
||||
String USER_NOT_FOUND = "A0002";
|
||||
|
||||
String USERNAME_OR_PWD_ERROR = "A0003";
|
||||
|
||||
String DATA_NOT_FOUND = "A0004";
|
||||
|
||||
String FILE_NOT_FOUND = "A0005";
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.nbport.zgwl.exception;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public class ServiceException extends RuntimeException {
|
||||
|
||||
private final String code;
|
||||
|
||||
public ServiceException(String code, String message) {
|
||||
super(message);
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public ServiceException(String message) {
|
||||
super(message);
|
||||
this.code = ServiceErrorCodeRange.DEFAULT;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package com.nbport.zgwl.handler;
|
||||
|
||||
import com.nbport.zgwl.common.GlobalErrorCodeConstants;
|
||||
import com.nbport.zgwl.common.R;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
import jakarta.validation.ConstraintViolationException;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
@ExceptionHandler(ServiceException.class)
|
||||
public R<Void> handleServiceException(ServiceException e) {
|
||||
log.error("业务异常", e);
|
||||
return R.error(e);
|
||||
}
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public R<Void> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
|
||||
String message = e.getBindingResult().getFieldErrors().stream()
|
||||
.map(FieldError::getDefaultMessage)
|
||||
.collect(Collectors.joining(";"));
|
||||
return R.error(GlobalErrorCodeConstants.PARAMS_ERROR.getCode(), message);
|
||||
}
|
||||
|
||||
@ExceptionHandler(BindException.class)
|
||||
public R<Void> handleBindException(BindException e) {
|
||||
String message = e.getBindingResult().getFieldErrors().stream()
|
||||
.map(FieldError::getDefaultMessage)
|
||||
.collect(Collectors.joining(";"));
|
||||
return R.error(GlobalErrorCodeConstants.PARAMS_ERROR.getCode(), message);
|
||||
}
|
||||
|
||||
@ExceptionHandler(ConstraintViolationException.class)
|
||||
public R<Void> handleConstraintViolationException(ConstraintViolationException e) {
|
||||
return R.error(GlobalErrorCodeConstants.PARAMS_ERROR.getCode(), e.getMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(HttpMessageNotReadableException.class)
|
||||
public R<Void> handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
|
||||
return R.error(GlobalErrorCodeConstants.PARAMS_ERROR.getCode(), "请求体格式不正确");
|
||||
}
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public R<Void> handleException(Exception e) {
|
||||
log.error("系统异常", e);
|
||||
return R.error(GlobalErrorCodeConstants.ERROR.getCode(), e.getMessage());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.nbport.zgwl.handler;
|
||||
|
||||
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
|
||||
import org.apache.ibatis.reflection.MetaObject;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Component
|
||||
public class MyMetaObjectHandler implements MetaObjectHandler {
|
||||
|
||||
@Override
|
||||
public void insertFill(MetaObject metaObject) {
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
this.strictInsertFill(metaObject, "createDt", LocalDateTime.class, now);
|
||||
this.strictInsertFill(metaObject, "updateDt", LocalDateTime.class, now);
|
||||
this.strictInsertFill(metaObject, "createBy", String.class, "system");
|
||||
this.strictInsertFill(metaObject, "updateBy", String.class, "system");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFill(MetaObject metaObject) {
|
||||
this.strictUpdateFill(metaObject, "updateDt", LocalDateTime.class, LocalDateTime.now());
|
||||
this.strictUpdateFill(metaObject, "updateBy", String.class, "system");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.nbport.zgwl.manifest.controller;
|
||||
|
||||
import com.nbport.zgwl.common.PageResult;
|
||||
import com.nbport.zgwl.common.R;
|
||||
import com.nbport.zgwl.manifest.dto.ContractTemplateDto;
|
||||
import com.nbport.zgwl.manifest.dto.ContractTemplateQueryDto;
|
||||
import com.nbport.zgwl.manifest.dto.TemplateOrgOptionDto;
|
||||
import com.nbport.zgwl.manifest.service.ContractTemplateService;
|
||||
import com.nbport.zgwl.manifest.utils.ManifestManageConstants;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 模板管理 Controller
|
||||
*
|
||||
* 路由尽量保持简单:
|
||||
* - /list 分页
|
||||
* - /published 已发布列表
|
||||
* - /org/options 假组织选项
|
||||
* - /{id} 详情
|
||||
* - POST 新增
|
||||
* - PUT 编辑
|
||||
* - PUT /{id}/status/{status} 状态切换
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping(ManifestManageConstants.REQUEST_PREFIX)
|
||||
public class ContractTemplateController {
|
||||
|
||||
private final ContractTemplateService contractTemplateService;
|
||||
|
||||
@PostMapping("/list")
|
||||
public R<PageResult<ContractTemplateDto>> queryList(@RequestBody ContractTemplateQueryDto queryDto) {
|
||||
return R.success(contractTemplateService.queryTemplateList(queryDto));
|
||||
}
|
||||
|
||||
@GetMapping("/published")
|
||||
public R<List<ContractTemplateDto>> queryPublishedList() {
|
||||
return R.success(contractTemplateService.queryPublishedTemplates());
|
||||
}
|
||||
|
||||
@GetMapping("/org/options")
|
||||
public R<List<TemplateOrgOptionDto>> queryOrgOptions() {
|
||||
return R.success(contractTemplateService.queryOrgOptions());
|
||||
}
|
||||
|
||||
@GetMapping("/{id}")
|
||||
public R<ContractTemplateDto> getDetail(@PathVariable("id") Long id) {
|
||||
return R.success(contractTemplateService.getTemplateDetail(id));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public R<ContractTemplateDto> add(@RequestBody ContractTemplateDto template) {
|
||||
return R.success(contractTemplateService.createTemplate(template));
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public R<ContractTemplateDto> edit(@RequestBody ContractTemplateDto template) {
|
||||
return R.success(contractTemplateService.updateTemplate(template));
|
||||
}
|
||||
|
||||
@PutMapping("/{id}/status/{status}")
|
||||
public R<ContractTemplateDto> changeStatus(@PathVariable("id") Long id, @PathVariable("status") String status) {
|
||||
return R.success(contractTemplateService.changeTemplateStatus(id, status));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package com.nbport.zgwl.manifest.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@TableName(value = "CONTRACT_TEMPLATE_MANAGE")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@KeySequence(value = "SEQ_CONTRACT_TEMPLATE_MANAGE", dbType = DbType.ORACLE)
|
||||
public class ContractTemplateManage implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "ID", type = IdType.INPUT)
|
||||
private Long id;
|
||||
|
||||
@TableField("TEMPLATE_CODE")
|
||||
private String templateCode;
|
||||
|
||||
@TableField("TEMPLATE_NAME")
|
||||
private String templateName;
|
||||
|
||||
@TableField("SOURCE")
|
||||
private String source;
|
||||
|
||||
@TableField("CONTRACT_TYPE")
|
||||
private String contractType;
|
||||
|
||||
@TableField("SELF_PARTY_ROLE")
|
||||
private String selfPartyRole;
|
||||
|
||||
@TableField("VERSION")
|
||||
private String version;
|
||||
|
||||
@TableField("STATUS")
|
||||
private String status;
|
||||
|
||||
@TableField("VARIABLE_COUNT")
|
||||
private Integer variableCount;
|
||||
|
||||
@TableField("DESCRIPTION")
|
||||
private String description;
|
||||
|
||||
@TableField("USAGE_TIP")
|
||||
private String usageTip;
|
||||
|
||||
@TableField("TEMPLATE_FILE_NAME")
|
||||
private String templateFileName;
|
||||
|
||||
@TableField("TEMPLATE_FILE_PATH")
|
||||
private String templateFilePath;
|
||||
|
||||
@TableField("PUBLISH_ORG_IDS_JSON")
|
||||
private String publishOrgIdsJson;
|
||||
|
||||
@TableField("PUBLISH_ORG_NAMES_JSON")
|
||||
private String publishOrgNamesJson;
|
||||
|
||||
@TableField("VARIABLE_MAPPINGS_JSON")
|
||||
private String variableMappingsJson;
|
||||
|
||||
@TableField("CREATE_BY")
|
||||
private String createBy;
|
||||
|
||||
@TableField("CREATED_TIME")
|
||||
private LocalDateTime createdTime;
|
||||
|
||||
@TableField("UPDATED_BY")
|
||||
private String updatedBy;
|
||||
|
||||
@TableField("UPDATED_TIME")
|
||||
private LocalDateTime updatedTime;
|
||||
|
||||
@TableField("DEL_FLAG")
|
||||
private String delFlag;
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
package com.nbport.zgwl.manifest.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 合同模板对象
|
||||
*
|
||||
* 这里直接用 DTO 承载页面需要的字段,方便前后端对接。
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ContractTemplateDto implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 范本编号,保存时后端自动生成。
|
||||
*/
|
||||
private String templateCode;
|
||||
|
||||
private String templateName;
|
||||
|
||||
/**
|
||||
* 范本类型:标准模板 / 推荐文本 / 示范文本 / 对方文本
|
||||
*/
|
||||
private String source;
|
||||
|
||||
private String contractType;
|
||||
|
||||
/**
|
||||
* 我方地位:甲方 / 乙方 / 丙方
|
||||
*/
|
||||
private String selfPartyRole;
|
||||
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 状态:draft / published / disabled
|
||||
*/
|
||||
private String status;
|
||||
|
||||
private Integer variableCount;
|
||||
|
||||
private String description;
|
||||
|
||||
private String usageTip;
|
||||
|
||||
private String templateFileName;
|
||||
|
||||
/**
|
||||
* 模板文件相对路径
|
||||
*/
|
||||
private String templateFilePath;
|
||||
|
||||
/**
|
||||
* 发布范围 orgId 集合
|
||||
*/
|
||||
@Builder.Default
|
||||
private List<String> publishOrgIds = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 发布范围 orgName 集合
|
||||
*/
|
||||
@Builder.Default
|
||||
private List<String> publishOrgNames = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* 为列表直接展示准备的文本。
|
||||
*/
|
||||
private String publishScopeText;
|
||||
|
||||
@Builder.Default
|
||||
private List<TemplateVariableMappingDto> variableMappings = new ArrayList<>();
|
||||
|
||||
@Builder.Default
|
||||
private List<String> variables = new ArrayList<>();
|
||||
|
||||
private String createBy;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private LocalDateTime createdTime;
|
||||
|
||||
private String updatedBy;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private LocalDateTime updatedTime;
|
||||
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 以下两个字段只在数据库层临时承接 JSON 文本,不给页面直接使用。
|
||||
*/
|
||||
private String publishOrgIdsJson;
|
||||
|
||||
private String publishOrgNamesJson;
|
||||
|
||||
private String variableMappingsJson;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.nbport.zgwl.manifest.dto;
|
||||
|
||||
import com.nbport.zgwl.dto.BasePageDto;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 模板分页查询参数
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class ContractTemplateQueryDto extends BasePageDto implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String templateName;
|
||||
|
||||
private String contractType;
|
||||
|
||||
private String source;
|
||||
|
||||
private String status;
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.nbport.zgwl.manifest.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 发布范围组织选项
|
||||
*
|
||||
* 当前先用假数据代替真实组织表,后续内网联调时再替换成真实组织接口。
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TemplateOrgOptionDto implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String orgId;
|
||||
|
||||
private String orgName;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.nbport.zgwl.manifest.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 模板变量映射
|
||||
*
|
||||
* variableKey:Word 模板里的变量名
|
||||
* bindField:业务字段名
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class TemplateVariableMappingDto implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String id;
|
||||
|
||||
private String variableKey;
|
||||
|
||||
private String bindField;
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
package com.nbport.zgwl.manifest.handler;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
import com.nbport.zgwl.manifest.dto.ContractTemplateDto;
|
||||
import com.nbport.zgwl.manifest.dto.TemplateOrgOptionDto;
|
||||
import com.nbport.zgwl.manifest.dto.TemplateVariableMappingDto;
|
||||
import com.nbport.zgwl.manifest.utils.ManifestJsonUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 模板数据处理器
|
||||
*
|
||||
* 负责:
|
||||
* 1. 保存前清洗数据
|
||||
* 2. 保存前校验数据
|
||||
* 3. 查询后把 JSON 文本转成前端需要的列表
|
||||
*/
|
||||
@Component
|
||||
public class ContractTemplateDataHandler {
|
||||
|
||||
public void normalizeBeforeSave(ContractTemplateDto template) {
|
||||
template.setTemplateName(StrUtil.trim(template.getTemplateName()));
|
||||
template.setSource(StrUtil.trim(template.getSource()));
|
||||
template.setContractType(StrUtil.trim(template.getContractType()));
|
||||
template.setSelfPartyRole(StrUtil.trim(template.getSelfPartyRole()));
|
||||
template.setVersion(StrUtil.trim(template.getVersion()));
|
||||
template.setDescription(StrUtil.trim(template.getDescription()));
|
||||
template.setUsageTip(StrUtil.trim(template.getUsageTip()));
|
||||
template.setTemplateFileName(StrUtil.trim(template.getTemplateFileName()));
|
||||
template.setTemplateFilePath(StrUtil.trim(template.getTemplateFilePath()));
|
||||
|
||||
List<String> publishOrgIds = template.getPublishOrgIds() == null ? new ArrayList<>() : template.getPublishOrgIds();
|
||||
List<String> publishOrgNames = template.getPublishOrgNames() == null ? new ArrayList<>() : template.getPublishOrgNames();
|
||||
template.setPublishOrgIds(
|
||||
publishOrgIds.stream()
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.map(StrUtil::trim)
|
||||
.distinct()
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
template.setPublishOrgNames(
|
||||
publishOrgNames.stream()
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.map(StrUtil::trim)
|
||||
.distinct()
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
|
||||
List<TemplateVariableMappingDto> mappings = template.getVariableMappings() == null ? new ArrayList<>() : template.getVariableMappings();
|
||||
mappings = mappings.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.map(item -> new TemplateVariableMappingDto(
|
||||
StrUtil.blankToDefault(item.getId(), "var_" + System.nanoTime()),
|
||||
StrUtil.trim(item.getVariableKey()),
|
||||
StrUtil.trim(item.getBindField())
|
||||
))
|
||||
.filter(item -> StrUtil.isNotBlank(item.getVariableKey()) || StrUtil.isNotBlank(item.getBindField()))
|
||||
.collect(Collectors.toList());
|
||||
template.setVariableMappings(mappings);
|
||||
template.setVariables(
|
||||
mappings.stream()
|
||||
.map(TemplateVariableMappingDto::getVariableKey)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.distinct()
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
template.setVariableCount(template.getVariables().size());
|
||||
template.setPublishScopeText(String.join("、", template.getPublishOrgNames()));
|
||||
}
|
||||
|
||||
public void validateForSave(ContractTemplateDto template) {
|
||||
if (StrUtil.isBlank(template.getTemplateName())) {
|
||||
throw new ServiceException("范本名称不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(template.getSource())) {
|
||||
throw new ServiceException("范本类型不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(template.getContractType())) {
|
||||
throw new ServiceException("合同类型不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(template.getSelfPartyRole())) {
|
||||
throw new ServiceException("我方地位不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(template.getVersion())) {
|
||||
throw new ServiceException("版本号不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(template.getTemplateFileName()) || StrUtil.isBlank(template.getTemplateFilePath())) {
|
||||
throw new ServiceException("请先上传 Word 模板文件");
|
||||
}
|
||||
if (template.getPublishOrgIds() == null || template.getPublishOrgIds().isEmpty()) {
|
||||
throw new ServiceException("发布范围不能为空");
|
||||
}
|
||||
if (template.getVariableMappings() == null || template.getVariableMappings().isEmpty()) {
|
||||
throw new ServiceException("请至少维护一个变量映射");
|
||||
}
|
||||
for (TemplateVariableMappingDto mapping : template.getVariableMappings()) {
|
||||
if (StrUtil.isBlank(mapping.getVariableKey())) {
|
||||
throw new ServiceException("模板变量名称不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(mapping.getBindField())) {
|
||||
throw new ServiceException("模板变量【" + mapping.getVariableKey() + "】尚未绑定业务字段");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void fillUiFields(ContractTemplateDto template) {
|
||||
if (template == null) {
|
||||
return;
|
||||
}
|
||||
template.setPublishOrgIds(ManifestJsonUtils.parseStringList(template.getPublishOrgIdsJson()));
|
||||
template.setPublishOrgNames(ManifestJsonUtils.parseStringList(template.getPublishOrgNamesJson()));
|
||||
template.setVariableMappings(
|
||||
ManifestJsonUtils.parseList(
|
||||
template.getVariableMappingsJson(),
|
||||
new com.alibaba.fastjson2.TypeReference<List<TemplateVariableMappingDto>>() {
|
||||
}
|
||||
)
|
||||
);
|
||||
template.setVariables(
|
||||
template.getVariableMappings().stream()
|
||||
.map(TemplateVariableMappingDto::getVariableKey)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.distinct()
|
||||
.collect(Collectors.toList())
|
||||
);
|
||||
template.setVariableCount(template.getVariables().size());
|
||||
template.setPublishScopeText(String.join("、", template.getPublishOrgNames()));
|
||||
}
|
||||
|
||||
public void fillUiFields(List<ContractTemplateDto> templates) {
|
||||
if (templates == null) {
|
||||
return;
|
||||
}
|
||||
templates.forEach(this::fillUiFields);
|
||||
}
|
||||
|
||||
public void fillOrgNamesByIds(ContractTemplateDto template, List<TemplateOrgOptionDto> orgOptions) {
|
||||
if (template.getPublishOrgIds() == null) {
|
||||
template.setPublishOrgNames(new ArrayList<>());
|
||||
return;
|
||||
}
|
||||
List<String> names = new ArrayList<>();
|
||||
for (String orgId : template.getPublishOrgIds()) {
|
||||
TemplateOrgOptionDto option = orgOptions.stream()
|
||||
.filter(item -> Objects.equals(item.getOrgId(), orgId))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (option != null) {
|
||||
names.add(option.getOrgName());
|
||||
}
|
||||
}
|
||||
template.setPublishOrgNames(names);
|
||||
template.setPublishScopeText(String.join("、", names));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.nbport.zgwl.manifest.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.nbport.zgwl.manifest.dto.ContractTemplateDto;
|
||||
import com.nbport.zgwl.manifest.dto.ContractTemplateQueryDto;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 模板管理 Mapper
|
||||
*/
|
||||
public interface ContractTemplateMapper {
|
||||
|
||||
Long selectTemplateSeqNextVal();
|
||||
|
||||
IPage<ContractTemplateDto> selectTemplatePage(Page<ContractTemplateDto> page, @Param("query") ContractTemplateQueryDto queryDto);
|
||||
|
||||
List<ContractTemplateDto> selectPublishedTemplates();
|
||||
|
||||
ContractTemplateDto selectTemplateById(@Param("id") Long id);
|
||||
|
||||
int insertTemplate(ContractTemplateDto template);
|
||||
|
||||
int updateTemplate(ContractTemplateDto template);
|
||||
|
||||
int updateTemplateStatus(@Param("id") Long id,
|
||||
@Param("status") String status,
|
||||
@Param("updateBy") String updateBy,
|
||||
@Param("updateTime") LocalDateTime updateTime);
|
||||
|
||||
int deleteTemplateById(@Param("id") Long id,
|
||||
@Param("updateBy") String updateBy,
|
||||
@Param("updateTime") LocalDateTime updateTime,
|
||||
@Param("delFlag") String delFlag);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.nbport.zgwl.manifest.service;
|
||||
|
||||
import com.nbport.zgwl.common.PageResult;
|
||||
import com.nbport.zgwl.manifest.dto.ContractTemplateDto;
|
||||
import com.nbport.zgwl.manifest.dto.ContractTemplateQueryDto;
|
||||
import com.nbport.zgwl.manifest.dto.TemplateOrgOptionDto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 模板管理 Service
|
||||
*/
|
||||
public interface ContractTemplateService {
|
||||
|
||||
PageResult<ContractTemplateDto> queryTemplateList(ContractTemplateQueryDto queryDto);
|
||||
|
||||
List<ContractTemplateDto> queryPublishedTemplates();
|
||||
|
||||
ContractTemplateDto getTemplateDetail(Long id);
|
||||
|
||||
ContractTemplateDto createTemplate(ContractTemplateDto template);
|
||||
|
||||
ContractTemplateDto updateTemplate(ContractTemplateDto template);
|
||||
|
||||
ContractTemplateDto changeTemplateStatus(Long id, String status);
|
||||
|
||||
List<TemplateOrgOptionDto> queryOrgOptions();
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
package com.nbport.zgwl.manifest.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.nbport.zgwl.common.PageResult;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
import com.nbport.zgwl.manifest.dto.ContractTemplateDto;
|
||||
import com.nbport.zgwl.manifest.dto.ContractTemplateQueryDto;
|
||||
import com.nbport.zgwl.manifest.dto.TemplateOrgOptionDto;
|
||||
import com.nbport.zgwl.manifest.handler.ContractTemplateDataHandler;
|
||||
import com.nbport.zgwl.manifest.mapper.ContractTemplateMapper;
|
||||
import com.nbport.zgwl.manifest.utils.ManifestCodeUtils;
|
||||
import com.nbport.zgwl.manifest.utils.ManifestJsonUtils;
|
||||
import com.nbport.zgwl.manifest.utils.ManifestManageConstants;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 模板管理 Service 实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class ContractTemplateServiceImpl implements ContractTemplateService {
|
||||
|
||||
private final ContractTemplateMapper contractTemplateMapper;
|
||||
|
||||
private final ContractTemplateDataHandler contractTemplateDataHandler;
|
||||
|
||||
@Override
|
||||
public PageResult<ContractTemplateDto> queryTemplateList(ContractTemplateQueryDto queryDto) {
|
||||
Page<ContractTemplateDto> page = new Page<>(queryDto.getPageNo(), queryDto.getPageSize());
|
||||
PageResult<ContractTemplateDto> pageResult = new PageResult<>(contractTemplateMapper.selectTemplatePage(page, queryDto));
|
||||
contractTemplateDataHandler.fillUiFields(pageResult.getRecords());
|
||||
return pageResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ContractTemplateDto> queryPublishedTemplates() {
|
||||
List<ContractTemplateDto> templates = contractTemplateMapper.selectPublishedTemplates();
|
||||
contractTemplateDataHandler.fillUiFields(templates);
|
||||
return templates;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContractTemplateDto getTemplateDetail(Long id) {
|
||||
ContractTemplateDto template = contractTemplateMapper.selectTemplateById(id);
|
||||
if (template == null) {
|
||||
throw new ServiceException("模板不存在");
|
||||
}
|
||||
contractTemplateDataHandler.fillUiFields(template);
|
||||
return template;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ContractTemplateDto createTemplate(ContractTemplateDto template) {
|
||||
contractTemplateDataHandler.normalizeBeforeSave(template);
|
||||
contractTemplateDataHandler.fillOrgNamesByIds(template, queryOrgOptions());
|
||||
contractTemplateDataHandler.validateForSave(template);
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
template.setId(contractTemplateMapper.selectTemplateSeqNextVal());
|
||||
template.setTemplateCode(ManifestCodeUtils.buildTemplateCode(template.getContractType()));
|
||||
template.setCreateBy(ManifestManageConstants.DEFAULT_OPERATOR);
|
||||
template.setCreatedTime(now);
|
||||
template.setUpdatedBy(ManifestManageConstants.DEFAULT_OPERATOR);
|
||||
template.setUpdatedTime(now);
|
||||
template.setDelFlag(ManifestManageConstants.DEL_FLAG_NORMAL);
|
||||
saveJsonFields(template);
|
||||
|
||||
contractTemplateMapper.insertTemplate(template);
|
||||
return getTemplateDetail(template.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ContractTemplateDto updateTemplate(ContractTemplateDto template) {
|
||||
if (template.getId() == null) {
|
||||
throw new ServiceException("修改模板时 id 不能为空");
|
||||
}
|
||||
|
||||
ContractTemplateDto dbTemplate = contractTemplateMapper.selectTemplateById(template.getId());
|
||||
if (dbTemplate == null) {
|
||||
throw new ServiceException("模板不存在");
|
||||
}
|
||||
|
||||
contractTemplateDataHandler.normalizeBeforeSave(template);
|
||||
contractTemplateDataHandler.fillOrgNamesByIds(template, queryOrgOptions());
|
||||
contractTemplateDataHandler.validateForSave(template);
|
||||
|
||||
template.setTemplateCode(dbTemplate.getTemplateCode());
|
||||
template.setCreateBy(dbTemplate.getCreateBy());
|
||||
template.setCreatedTime(dbTemplate.getCreatedTime());
|
||||
template.setUpdatedBy(ManifestManageConstants.DEFAULT_OPERATOR);
|
||||
template.setUpdatedTime(LocalDateTime.now());
|
||||
template.setDelFlag(dbTemplate.getDelFlag());
|
||||
saveJsonFields(template);
|
||||
|
||||
contractTemplateMapper.updateTemplate(template);
|
||||
return getTemplateDetail(template.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ContractTemplateDto changeTemplateStatus(Long id, String status) {
|
||||
if (!ManifestManageConstants.STATUS_DRAFT.equals(status)
|
||||
&& !ManifestManageConstants.STATUS_PUBLISHED.equals(status)
|
||||
&& !ManifestManageConstants.STATUS_DISABLED.equals(status)) {
|
||||
throw new ServiceException("模板状态不合法");
|
||||
}
|
||||
|
||||
ContractTemplateDto dbTemplate = contractTemplateMapper.selectTemplateById(id);
|
||||
if (dbTemplate == null) {
|
||||
throw new ServiceException("模板不存在");
|
||||
}
|
||||
|
||||
contractTemplateMapper.updateTemplateStatus(
|
||||
id,
|
||||
status,
|
||||
ManifestManageConstants.DEFAULT_OPERATOR,
|
||||
LocalDateTime.now()
|
||||
);
|
||||
return getTemplateDetail(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TemplateOrgOptionDto> queryOrgOptions() {
|
||||
return List.of(
|
||||
new TemplateOrgOptionDto("ORG001", "浙港物流平台有限公司"),
|
||||
new TemplateOrgOptionDto("ORG002", "宁波舟山港集团有限公司"),
|
||||
new TemplateOrgOptionDto("ORG003", "浙江省海港投资运营集团有限公司"),
|
||||
new TemplateOrgOptionDto("ORG004", "宁波港东南物流集团有限公司")
|
||||
);
|
||||
}
|
||||
|
||||
private void saveJsonFields(ContractTemplateDto template) {
|
||||
template.setPublishOrgIdsJson(ManifestJsonUtils.toJson(template.getPublishOrgIds()));
|
||||
template.setPublishOrgNamesJson(ManifestJsonUtils.toJson(template.getPublishOrgNames()));
|
||||
template.setVariableMappingsJson(ManifestJsonUtils.toJson(template.getVariableMappings()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.nbport.zgwl.manifest.utils;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* 模板编号生成工具
|
||||
*
|
||||
* 需求里要求“范本编号自动生成”,这里采用:
|
||||
* TPL-合同类型编码-时间戳-随机数
|
||||
*
|
||||
* 例子:TPL-MM-20260522113045-128
|
||||
*/
|
||||
public final class ManifestCodeUtils {
|
||||
|
||||
private static final Map<String, String> CONTRACT_TYPE_CODE_MAP = Map.ofEntries(
|
||||
Map.entry("买卖合同", "MM"),
|
||||
Map.entry("采购合同", "CG"),
|
||||
Map.entry("销售合同", "XS"),
|
||||
Map.entry("服务合同", "FW"),
|
||||
Map.entry("框架合同", "FJ"),
|
||||
Map.entry("供用电、水、气、热力合同", "GY"),
|
||||
Map.entry("赠与合同", "ZY"),
|
||||
Map.entry("借款合同", "JK"),
|
||||
Map.entry("保证合同", "BZ"),
|
||||
Map.entry("租赁合同", "ZL"),
|
||||
Map.entry("融资租赁合同", "RZ"),
|
||||
Map.entry("保理合同", "BL"),
|
||||
Map.entry("承揽合同", "CL"),
|
||||
Map.entry("建设工程合同", "GC"),
|
||||
Map.entry("运输合同", "YS"),
|
||||
Map.entry("技术合同", "JS"),
|
||||
Map.entry("保管合同", "BG"),
|
||||
Map.entry("仓储合同", "CC"),
|
||||
Map.entry("委托合同", "WT"),
|
||||
Map.entry("物业服务合同", "WY"),
|
||||
Map.entry("行纪合同", "HJ"),
|
||||
Map.entry("中介合同", "ZJ"),
|
||||
Map.entry("合伙合同", "HH"),
|
||||
Map.entry("用工合同", "YG"),
|
||||
Map.entry("业务合同", "YW"),
|
||||
Map.entry("其他合同", "QT")
|
||||
);
|
||||
|
||||
private ManifestCodeUtils() {
|
||||
}
|
||||
|
||||
public static String buildTemplateCode(String contractType) {
|
||||
String typeCode = CONTRACT_TYPE_CODE_MAP.getOrDefault(contractType, "QT");
|
||||
String now = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
|
||||
int random = ThreadLocalRandom.current().nextInt(100, 1000);
|
||||
return "TPL-" + typeCode + "-" + now + "-" + random;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.nbport.zgwl.manifest.utils;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.TypeReference;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 模板管理 JSON 工具
|
||||
*
|
||||
* 模板的“发布范围、变量映射”等字段更适合存成 JSON 文本。
|
||||
* 这里统一做转换,避免 Service 里反复写解析代码。
|
||||
*/
|
||||
public final class ManifestJsonUtils {
|
||||
|
||||
private ManifestJsonUtils() {
|
||||
}
|
||||
|
||||
public static String toJson(Object value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return JSON.toJSONString(value);
|
||||
}
|
||||
|
||||
public static List<String> parseStringList(String json) {
|
||||
if (json == null || json.isBlank()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return JSON.parseObject(json, new TypeReference<List<String>>() {
|
||||
});
|
||||
}
|
||||
|
||||
public static <T> List<T> parseList(String json, TypeReference<List<T>> typeReference) {
|
||||
if (json == null || json.isBlank()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return JSON.parseObject(json, typeReference);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.nbport.zgwl.manifest.utils;
|
||||
|
||||
/**
|
||||
* 模板管理模块常量
|
||||
*
|
||||
* 把常量单独放这里,是为了后续迁移到内网时只改一个地方。
|
||||
*/
|
||||
public final class ManifestManageConstants {
|
||||
|
||||
private ManifestManageConstants() {
|
||||
}
|
||||
|
||||
public static final String REQUEST_PREFIX = "/manifest/manage";
|
||||
|
||||
public static final String DEFAULT_OPERATOR = "local_test";
|
||||
|
||||
public static final String DEL_FLAG_NORMAL = "0";
|
||||
|
||||
public static final String DEL_FLAG_DELETED = "2";
|
||||
|
||||
public static final String STATUS_DRAFT = "draft";
|
||||
|
||||
public static final String STATUS_PUBLISHED = "published";
|
||||
|
||||
public static final String STATUS_DISABLED = "disabled";
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.nbport.zgwl.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.nbport.zgwl.dto.StudentQueryDto;
|
||||
import com.nbport.zgwl.entity.StudentEntity;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface StudentMapper extends BaseMapper<StudentEntity> {
|
||||
|
||||
IPage<Map<String, Object>> queryList(Page<Map<String, Object>> page, @Param("query") StudentQueryDto queryDto);
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
package com.nbport.zgwl.partner.controller;
|
||||
|
||||
import com.nbport.zgwl.common.PageResult;
|
||||
import com.nbport.zgwl.common.R;
|
||||
import com.nbport.zgwl.partner.dto.PartnerManageDto;
|
||||
import com.nbport.zgwl.partner.dto.PartnerQueryDto;
|
||||
import com.nbport.zgwl.partner.service.PartnerManageService;
|
||||
import com.nbport.zgwl.partner.utils.PartnerManageConstants;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 相对方管理 Controller
|
||||
*/
|
||||
@RestController
|
||||
@RequiredArgsConstructor
|
||||
@RequestMapping(PartnerManageConstants.REQUEST_PREFIX)
|
||||
public class PartnerManageController {
|
||||
|
||||
private final PartnerManageService partnerManageService;
|
||||
|
||||
@PostMapping("/list")
|
||||
public R<PageResult<PartnerManageDto>> queryList(@RequestBody PartnerQueryDto queryDto) {
|
||||
return R.success(partnerManageService.queryPartnerList(queryDto));
|
||||
}
|
||||
|
||||
@GetMapping("/{customerSysid}")
|
||||
public R<PartnerManageDto> getInfo(@PathVariable("customerSysid") Long customerSysid) {
|
||||
return R.success(partnerManageService.selectPartnerById(customerSysid));
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public R<Long> add(@RequestBody PartnerManageDto partner) {
|
||||
return R.success(partnerManageService.insertPartner(partner));
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public R<String> edit(@RequestBody PartnerManageDto partner) {
|
||||
partnerManageService.updatePartner(partner);
|
||||
return R.success("保存成功");
|
||||
}
|
||||
|
||||
@DeleteMapping("/{customerSysids}")
|
||||
public R<String> remove(@PathVariable("customerSysids") String customerSysids) {
|
||||
List<Long> idList = Arrays.stream(customerSysids.split(","))
|
||||
.filter(item -> item != null && !item.isBlank())
|
||||
.map(Long::valueOf)
|
||||
.collect(Collectors.toList());
|
||||
partnerManageService.deletePartnerByIds(idList);
|
||||
return R.success("删除成功");
|
||||
}
|
||||
|
||||
@PostMapping("/{customerSysid}/sync")
|
||||
public R<PartnerManageDto> mockSync(@PathVariable("customerSysid") Long customerSysid) {
|
||||
return R.success(partnerManageService.mockSyncPartner(customerSysid));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
package com.nbport.zgwl.partner.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@TableName(value = "ILDM_FEE_CUSTOMER_INFO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@KeySequence(value = "SEQ_ILDM_FEE_CUSTOMER_INFO", dbType = DbType.ORACLE)
|
||||
public class IldmFeeCustomerInfo implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "CUSTOMER_SYSID", type = IdType.INPUT)
|
||||
private Long customerSysid;
|
||||
|
||||
@TableField("CUSTOMER_REGNO")
|
||||
private String customerRegno;
|
||||
|
||||
@TableField("CUSTOMER_NO")
|
||||
private String customerNo;
|
||||
|
||||
@TableField("CUSTOMER_NAME_C")
|
||||
private String customerNameC;
|
||||
|
||||
@TableField("CUSTOMER_NAME_EN")
|
||||
private String customerNameEn;
|
||||
|
||||
@TableField("CUSTOMER_SHORT_NAME")
|
||||
private String customerShortName;
|
||||
|
||||
@TableField("CUSTOMER_SHORT_NAME_EN")
|
||||
private String customerShortNameEn;
|
||||
|
||||
@TableField("CUSTOMER_TAXNO")
|
||||
private String customerTaxno;
|
||||
|
||||
@TableField("CUSTOMER_ADDRESS")
|
||||
private String customerAddress;
|
||||
|
||||
@TableField("OFFICEPHONE")
|
||||
private String officephone;
|
||||
|
||||
@TableField("CUSTOMER_BANK")
|
||||
private String customerBank;
|
||||
|
||||
@TableField("CUSTOMER_BANKACCOUNT")
|
||||
private String customerBankaccount;
|
||||
|
||||
@TableField("CUSTOMER_CHARACTER")
|
||||
private String customerCharacter;
|
||||
|
||||
@TableField("CUSTOMER_REGADDR")
|
||||
private String customerRegaddr;
|
||||
|
||||
@TableField("CUSTOMER_REGDATE")
|
||||
private LocalDate customerRegdate;
|
||||
|
||||
@TableField("CUSTOMER_NATURE")
|
||||
private String customerNature;
|
||||
|
||||
@TableField("CUSTOMER_ZIP")
|
||||
private String customerZip;
|
||||
|
||||
@TableField("CUSTOMER_1_TYPEFLAG")
|
||||
private String customer1Typeflag;
|
||||
|
||||
@TableField("CUSTOMER_2_TYPEFLAG")
|
||||
private String customer2Typeflag;
|
||||
|
||||
@TableField("CUSTOMER_3_TYPEFLAG")
|
||||
private String customer3Typeflag;
|
||||
|
||||
@TableField("CUSTOMER_4_TYPEFLAG")
|
||||
private String customer4Typeflag;
|
||||
|
||||
@TableField("PLACE_TYPE")
|
||||
private String placeType;
|
||||
|
||||
@TableField("ACTIVEFLAG")
|
||||
private String activeflag;
|
||||
|
||||
@TableField("CUSTOMER_SYSID_HT")
|
||||
private String customerSysidHt;
|
||||
|
||||
@TableField("DOWN_DATE")
|
||||
private LocalDate downDate;
|
||||
|
||||
@TableField("OPEN_FLAG")
|
||||
private String openFlag;
|
||||
|
||||
@TableField("CREATE_BY")
|
||||
private String createBy;
|
||||
|
||||
@TableField("CREATE_TIME")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@TableField("UPDATE_BY")
|
||||
private String updateBy;
|
||||
|
||||
@TableField("UPDATE_TIME")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@TableField("SYSTEM_TYPE")
|
||||
private String systemType;
|
||||
|
||||
@TableField("REMARK")
|
||||
private String remark;
|
||||
|
||||
@TableField("ORG_ID")
|
||||
private String orgId;
|
||||
|
||||
@TableField("EMAIL_ADDRESS")
|
||||
private String emailAddress;
|
||||
|
||||
@TableField("OPPOSITE_ID")
|
||||
private String oppositeId;
|
||||
|
||||
@TableField("OPPOSITE_CHARACTER")
|
||||
private String oppositeCharacter;
|
||||
|
||||
@TableField("GAT_FLAG")
|
||||
private String gatFlag;
|
||||
|
||||
@TableField("GROUP_FLAG")
|
||||
private String groupFlag;
|
||||
|
||||
@TableField("COUNTRY")
|
||||
private String country;
|
||||
|
||||
@TableField("COUNTRY_NAME")
|
||||
private String countryName;
|
||||
|
||||
@TableField("CITY")
|
||||
private String city;
|
||||
|
||||
@TableField("POSTCODE")
|
||||
private String postcode;
|
||||
|
||||
@TableField("LEGAL_PERSON_ID")
|
||||
private String legalPersonId;
|
||||
|
||||
@TableField("LEGAL_PERSON_NAME")
|
||||
private String legalPersonName;
|
||||
|
||||
@TableField("LEGAL_PERSON_ACCOUNT")
|
||||
private String legalPersonAccount;
|
||||
|
||||
@TableField("LEGAL_PERSON_CARD_ID")
|
||||
private String legalPersonCardId;
|
||||
|
||||
@TableField("WEBSITE")
|
||||
private String website;
|
||||
|
||||
@TableField("CERTIFICATE_TYPE")
|
||||
private String certificateType;
|
||||
|
||||
@TableField("CERTIFICATE_NUM")
|
||||
private String certificateNum;
|
||||
|
||||
@TableField("TIN_CODE")
|
||||
private String tinCode;
|
||||
|
||||
@TableField("ABROAD_CODE")
|
||||
private String abroadCode;
|
||||
|
||||
@TableField("REGISTERED_CAPITAL")
|
||||
private BigDecimal registeredCapital;
|
||||
|
||||
@TableField("REG_CAPITAL")
|
||||
private String regCapital;
|
||||
|
||||
@TableField("BUS_SCOPE")
|
||||
private String busScope;
|
||||
|
||||
@TableField("OPPOSITE_CODE")
|
||||
private String oppositeCode;
|
||||
|
||||
@TableField("OPPOSITE_STATUS")
|
||||
private String oppositeStatus;
|
||||
|
||||
@TableField("IS_SGAT")
|
||||
private String isSgat;
|
||||
|
||||
@TableField("IS_JTN")
|
||||
private String isJtn;
|
||||
|
||||
@TableField("NATURE_OF_ENTERPRISE_ORG")
|
||||
private String natureOfEnterpriseOrg;
|
||||
|
||||
@TableField("NATURE_OF_ENTERPRISE_ORG_LEV")
|
||||
private String natureOfEnterpriseOrgLev;
|
||||
|
||||
@TableField("RELATIVE_TYPE")
|
||||
private String relativeType;
|
||||
|
||||
@TableField("IS_DELETED")
|
||||
private String isDeleted;
|
||||
|
||||
@TableField("COMMENTS")
|
||||
private String comments;
|
||||
|
||||
@TableField("SYNC_STATUS")
|
||||
private String syncStatus;
|
||||
|
||||
@TableField("SYNC_TIME")
|
||||
private LocalDateTime syncTime;
|
||||
|
||||
@TableField("SYNC_MESSAGE")
|
||||
private String syncMessage;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package com.nbport.zgwl.partner.domain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.DbType;
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@TableName(value = "SEAL_PARTNER_CONTACT")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = false)
|
||||
@KeySequence(value = "SEQ_SEAL_PARTNER_CONTACT", dbType = DbType.ORACLE)
|
||||
public class SealPartnerContact implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@TableId(value = "ID", type = IdType.INPUT)
|
||||
private Long id;
|
||||
|
||||
@TableField("PARTNER_RECORD_ID")
|
||||
private Long partnerRecordId;
|
||||
|
||||
@TableField("CONTACT_NAME")
|
||||
private String contactName;
|
||||
|
||||
@TableField("CONTACT_PHONE")
|
||||
private String contactPhone;
|
||||
|
||||
@TableField("POSTAL_ADDRESS")
|
||||
private String postalAddress;
|
||||
|
||||
@TableField("EMAIL")
|
||||
private String email;
|
||||
|
||||
@TableField("SORT_ORDER")
|
||||
private Integer sortOrder;
|
||||
|
||||
@TableField("DEL_FLAG")
|
||||
private String delFlag;
|
||||
|
||||
@TableField("CREATE_BY")
|
||||
private String createBy;
|
||||
|
||||
@TableField("CREATE_TIME")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@TableField("UPDATE_BY")
|
||||
private String updateBy;
|
||||
|
||||
@TableField("UPDATE_TIME")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
@TableField("REMARK")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.nbport.zgwl.partner.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 相对方联系人信息
|
||||
*
|
||||
* 字段命名直接采用 seal_partner_contact 的驼峰写法。
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PartnerContactDto implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 前端渲染联系人列表时使用的临时唯一键。
|
||||
*/
|
||||
private String uid;
|
||||
|
||||
private Long partnerRecordId;
|
||||
|
||||
private String contactName;
|
||||
|
||||
private String contactPhone;
|
||||
|
||||
private String postalAddress;
|
||||
|
||||
private String email;
|
||||
|
||||
private Integer sortOrder;
|
||||
|
||||
private String delFlag;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
package com.nbport.zgwl.partner.dto;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 相对方主对象
|
||||
*
|
||||
* 字段命名直接采用 ILDM_FEE_CUSTOMER_INFO 的驼峰写法,
|
||||
* 避免再维护一套“业务语义字段”和“数据库字段”的双重命名。
|
||||
*/
|
||||
@Data
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class PartnerManageDto implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
// ============== 客户基本信息字段 ==============
|
||||
|
||||
/** 客户系统ID */
|
||||
private Long customerSysid; // 注意:数据库中是VARCHAR(64),不是Long
|
||||
|
||||
/** 客户注册号 */
|
||||
private String customerRegno;
|
||||
|
||||
/** 客户编号 */
|
||||
private String customerNo;
|
||||
|
||||
/** 公司全称 */
|
||||
private String customerNameC;
|
||||
|
||||
/** 公司英文名称 */
|
||||
private String customerNameEn;
|
||||
|
||||
/** 公司简称 */
|
||||
private String customerShortName;
|
||||
|
||||
/** 公司英文简称 */
|
||||
private String customerShortNameEn;
|
||||
|
||||
/** 统一社会信用代码 */
|
||||
private String customerTaxno;
|
||||
|
||||
/** 详细地址 */
|
||||
private String customerAddress;
|
||||
|
||||
/** 联系电话 */
|
||||
private String officephone;
|
||||
|
||||
/** 开户银行 */
|
||||
private String customerBank;
|
||||
|
||||
/** 银行账户 */
|
||||
private String customerBankaccount;
|
||||
|
||||
/** 客户性质 */
|
||||
private String customerCharacter;
|
||||
|
||||
/** 注册地址 */
|
||||
private String customerRegaddr;
|
||||
|
||||
/** 注册日期 */
|
||||
private LocalDate customerRegdate;
|
||||
|
||||
/** 客户性质分类 */
|
||||
private String customerNature;
|
||||
|
||||
/** 邮编 */
|
||||
private String customerZip;
|
||||
|
||||
/** 客户类型标识1 */
|
||||
private String customer1Typeflag;
|
||||
|
||||
/** 客户类型标识2 */
|
||||
private String customer2Typeflag;
|
||||
|
||||
/** 客户类型标识3 */
|
||||
private String customer3Typeflag;
|
||||
|
||||
/** 客户类型标识4 */
|
||||
private String customer4Typeflag;
|
||||
|
||||
/** 境内外 */
|
||||
private String placeType;
|
||||
|
||||
/** 启用标识 */
|
||||
private String activeflag;
|
||||
|
||||
/** 海铁系统客户ID */
|
||||
private String customerSysidHt;
|
||||
|
||||
/** 下载日期 */
|
||||
private LocalDate downDate;
|
||||
|
||||
/** 开户标识 */
|
||||
private String openFlag;
|
||||
|
||||
/** 业务系统类型(ht:海铁联运系统;xg:箱管系统;qc:全程物流) */
|
||||
private String systemType;
|
||||
|
||||
/** 组织体系对应的公司编码 */
|
||||
private String orgId;
|
||||
|
||||
/** 邮箱地址 */
|
||||
private String emailAddress;
|
||||
|
||||
// ============== 法务系统相关字段 ==============
|
||||
|
||||
/** 法务系统相对方ID(唯一标识) */
|
||||
private String oppositeId;
|
||||
|
||||
/** 相对方性质分类(1:境内组织,2:境内个人,3:境外组织,4:境外个人) */
|
||||
private String oppositeCharacter;
|
||||
|
||||
/** 是否涉港澳台标识(Y:是,N:否,法务业务分类用) */
|
||||
private String gatFlag;
|
||||
|
||||
/** 是否集团内(Y:是,N:否,法务业务分类用) */
|
||||
private String groupFlag;
|
||||
|
||||
/** 国家编码 */
|
||||
private String country;
|
||||
|
||||
/** 国家名称 */
|
||||
private String countryName;
|
||||
|
||||
/** 城市 */
|
||||
private String city;
|
||||
|
||||
/** 邮编 */
|
||||
private String postcode;
|
||||
|
||||
/** 法定代表人或负责人ID */
|
||||
private String legalPersonId;
|
||||
|
||||
/** 法定代表人或负责人姓名 */
|
||||
private String legalPersonName;
|
||||
|
||||
/** 法定代表人或负责人账户 */
|
||||
private String legalPersonAccount;
|
||||
|
||||
/** 法定代表人身份证号(加密存储) */
|
||||
private String legalPersonCardId;
|
||||
|
||||
/** 网站地址 */
|
||||
private String website;
|
||||
|
||||
/** 自然人证件类型(idCard:身份证,passport:护照,other:其他) */
|
||||
private String certificateType;
|
||||
|
||||
/** 自然人证件号码(加密存储) */
|
||||
private String certificateNum;
|
||||
|
||||
/** TIN码(税务识别号) */
|
||||
private String tinCode;
|
||||
|
||||
/** 境外公司活动证明编码 */
|
||||
private String abroadCode;
|
||||
|
||||
/** 注册资金(单位:元) */
|
||||
private BigDecimal registeredCapital;
|
||||
|
||||
/** 注册资本(文本描述,如:1000万人民币) */
|
||||
private String regCapital;
|
||||
|
||||
/** 经营范围 */
|
||||
private String busScope;
|
||||
|
||||
/** 相对方编码(业务分类编码) */
|
||||
private String oppositeCode;
|
||||
|
||||
/** 状态(EFFECTUAL:有效,INVALID:无效) */
|
||||
private String oppositeStatus;
|
||||
|
||||
/** 是否SGAT(1:是,0:否) */
|
||||
private String isSgat;
|
||||
|
||||
/** 是否JTN(1:是,0:否) */
|
||||
private String isJtn;
|
||||
|
||||
/** 组织性质(ZY:政府,QY:企业,QT:其他组织) */
|
||||
private String natureOfEnterpriseOrg;
|
||||
|
||||
/** 组织性质子级(GNQY:国有企业,MYQY:民营企业,WZQY:外资企业,HZQY:合资企业,GYQZHKGQY:国有全资和控股企业,QT:其他) */
|
||||
private String natureOfEnterpriseOrgLev;
|
||||
|
||||
/** 类型(client:客户,clientAndSup:客户及供应商,other:其他,Partner:合作伙伴,supplier:供应商) */
|
||||
private String relativeType;
|
||||
|
||||
/** 法务系统删除标记(Y:是,N:否,逻辑删除) */
|
||||
private String isDeleted;
|
||||
|
||||
/** 备注【法务】 */
|
||||
private String comments;
|
||||
|
||||
/** 备注 */
|
||||
private String remark;
|
||||
|
||||
// ============== 系统通用字段 ==============
|
||||
|
||||
/** 创建人 */
|
||||
private String createBy;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/** 更新人 */
|
||||
private String updateBy;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
// ============== 同步状态字段 ==============
|
||||
|
||||
/** 同步状态:unsynced/synced/failed */
|
||||
private String syncStatus;
|
||||
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private LocalDateTime syncTime;
|
||||
|
||||
/** 同步说明 */
|
||||
private String syncMessage;
|
||||
|
||||
// ============== 非数据库字段 ==============
|
||||
|
||||
/** 联系人列表 */
|
||||
@Builder.Default
|
||||
private List<PartnerContactDto> contacts = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.nbport.zgwl.partner.dto;
|
||||
|
||||
import com.nbport.zgwl.dto.BasePageDto;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 相对方列表查询参数
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class PartnerQueryDto extends BasePageDto implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String customerNameC;
|
||||
|
||||
private String relativeType;
|
||||
|
||||
private String oppositeCharacter;
|
||||
|
||||
private String groupFlag;
|
||||
|
||||
private String syncStatus;
|
||||
}
|
||||
@@ -0,0 +1,219 @@
|
||||
package com.nbport.zgwl.partner.handler;
|
||||
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.lang.Validator;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
import com.nbport.zgwl.partner.dto.PartnerContactDto;
|
||||
import com.nbport.zgwl.partner.dto.PartnerManageDto;
|
||||
import com.nbport.zgwl.partner.utils.PartnerManageConstants;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 相对方数据处理器
|
||||
*/
|
||||
@Component
|
||||
public class PartnerDataHandler {
|
||||
|
||||
public void normalizeBeforeSave(PartnerManageDto partner) {
|
||||
partner.setCustomerNameC(StrUtil.trim(partner.getCustomerNameC()));
|
||||
partner.setCustomerTaxno(StrUtil.trim(partner.getCustomerTaxno()));
|
||||
partner.setCustomerRegaddr(StrUtil.trim(partner.getCustomerRegaddr()));
|
||||
partner.setEmailAddress(StrUtil.trim(partner.getEmailAddress()));
|
||||
partner.setCountry(StrUtil.trim(partner.getCountry()));
|
||||
partner.setCountryName(StrUtil.trim(partner.getCountryName()));
|
||||
partner.setLegalPersonName(StrUtil.trim(partner.getLegalPersonName()));
|
||||
partner.setCertificateNum(StrUtil.trim(partner.getCertificateNum()));
|
||||
partner.setTinCode(StrUtil.trim(partner.getTinCode()));
|
||||
partner.setRegCapital(StrUtil.trim(partner.getRegCapital()));
|
||||
partner.setOppositeCode(StrUtil.trim(partner.getOppositeCode()));
|
||||
partner.setOppositeStatus(StrUtil.trim(partner.getOppositeStatus()));
|
||||
partner.setComments(StrUtil.trim(partner.getComments()));
|
||||
partner.setRemark(StrUtil.trim(partner.getRemark()));
|
||||
partner.setSyncMessage(StrUtil.trim(partner.getSyncMessage()));
|
||||
|
||||
if (!"QY".equals(partner.getNatureOfEnterpriseOrg())) {
|
||||
partner.setNatureOfEnterpriseOrgLev(null);
|
||||
}
|
||||
|
||||
if (!isDomesticOrg(partner)) {
|
||||
partner.setCustomerTaxno(null);
|
||||
partner.setLegalPersonName(null);
|
||||
}
|
||||
|
||||
if (!isDomesticPerson(partner) && !isForeignPerson(partner)) {
|
||||
partner.setCertificateType(null);
|
||||
partner.setCertificateNum(null);
|
||||
}
|
||||
|
||||
if (!isForeignOrg(partner)) {
|
||||
partner.setTinCode(null);
|
||||
}
|
||||
|
||||
if (!isForeignOrg(partner) && !isForeignPerson(partner)) {
|
||||
partner.setCountry(null);
|
||||
partner.setCountryName(null);
|
||||
}
|
||||
|
||||
if (!isDomesticOrg(partner) && !isForeignOrg(partner)) {
|
||||
partner.setCustomerRegaddr(null);
|
||||
partner.setRegCapital(null);
|
||||
partner.setRegisteredCapital(null);
|
||||
}
|
||||
|
||||
if (!showGatFlag(partner)) {
|
||||
partner.setGatFlag(PartnerManageConstants.GAT_FLAG_NO);
|
||||
}
|
||||
|
||||
partner.setGroupFlag(StrUtil.blankToDefault(partner.getGroupFlag(), PartnerManageConstants.GROUP_FLAG_NO));
|
||||
partner.setGatFlag(StrUtil.blankToDefault(partner.getGatFlag(), PartnerManageConstants.GAT_FLAG_NO));
|
||||
partner.setSyncStatus(StrUtil.blankToDefault(partner.getSyncStatus(), PartnerManageConstants.SYNC_STATUS_UNSYNCED));
|
||||
partner.setOppositeStatus(StrUtil.blankToDefault(partner.getOppositeStatus(), PartnerManageConstants.OPPOSITE_STATUS_EFFECTUAL));
|
||||
partner.setIsDeleted(StrUtil.blankToDefault(partner.getIsDeleted(), PartnerManageConstants.PARTNER_IS_DELETED_NORMAL));
|
||||
partner.setIsSgat(PartnerManageConstants.GAT_FLAG_YES.equals(partner.getGatFlag())
|
||||
? PartnerManageConstants.FLAG_ONE
|
||||
: PartnerManageConstants.FLAG_ZERO);
|
||||
partner.setIsJtn(PartnerManageConstants.GROUP_FLAG_YES.equals(partner.getGroupFlag())
|
||||
? PartnerManageConstants.FLAG_ONE
|
||||
: PartnerManageConstants.FLAG_ZERO);
|
||||
|
||||
List<PartnerContactDto> contacts = partner.getContacts() == null ? new ArrayList<>() : partner.getContacts();
|
||||
contacts = contacts.stream()
|
||||
.filter(Objects::nonNull)
|
||||
.peek(this::normalizeContact)
|
||||
.filter(this::hasAnyContactValue)
|
||||
.collect(Collectors.toList());
|
||||
partner.setContacts(contacts);
|
||||
}
|
||||
|
||||
public void validateForSave(PartnerManageDto partner) {
|
||||
if (StrUtil.isBlank(partner.getCustomerNameC())) {
|
||||
throw new ServiceException("公司名称不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(partner.getRelativeType())) {
|
||||
throw new ServiceException("公司类型不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(partner.getOppositeCharacter())) {
|
||||
throw new ServiceException("公司性质不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(partner.getNatureOfEnterpriseOrg())) {
|
||||
throw new ServiceException("组织性质不能为空");
|
||||
}
|
||||
if ("QY".equals(partner.getNatureOfEnterpriseOrg()) && StrUtil.isBlank(partner.getNatureOfEnterpriseOrgLev())) {
|
||||
throw new ServiceException("组织性质选择企业时,组织性质企业二级不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(partner.getGroupFlag())) {
|
||||
throw new ServiceException("是否集团内不能为空");
|
||||
}
|
||||
if (isDomesticOrg(partner) && StrUtil.isBlank(partner.getCustomerTaxno())) {
|
||||
throw new ServiceException("境内组织必须填写统一社会信用代码");
|
||||
}
|
||||
if (isDomesticPerson(partner) && StrUtil.isBlank(partner.getCertificateType())) {
|
||||
throw new ServiceException("境内个人必须选择自然人证件类型");
|
||||
}
|
||||
if (isDomesticPerson(partner) && StrUtil.isBlank(partner.getCertificateNum())) {
|
||||
throw new ServiceException("境内个人必须填写自然人证件号码");
|
||||
}
|
||||
if (isForeignOrg(partner) && StrUtil.isBlank(partner.getTinCode())) {
|
||||
throw new ServiceException("境外组织必须填写TIN号");
|
||||
}
|
||||
if (isForeignOrg(partner) && StrUtil.isBlank(partner.getCountry())) {
|
||||
throw new ServiceException("境外组织必须选择国家");
|
||||
}
|
||||
if (isForeignPerson(partner) && StrUtil.isBlank(partner.getCountry())) {
|
||||
throw new ServiceException("境外个人必须选择国家");
|
||||
}
|
||||
if (isDomesticOrg(partner) && StrUtil.isBlank(partner.getLegalPersonName())) {
|
||||
throw new ServiceException("境内组织必须填写法定代表人或负责人");
|
||||
}
|
||||
if ((isDomesticOrg(partner) || isForeignOrg(partner)) && StrUtil.isBlank(partner.getCustomerRegaddr())) {
|
||||
throw new ServiceException("组织类型必须填写注册地址");
|
||||
}
|
||||
if ((isDomesticOrg(partner) || isForeignOrg(partner)) && StrUtil.isBlank(partner.getRegCapital())) {
|
||||
throw new ServiceException("组织类型必须填写注册资本");
|
||||
}
|
||||
validateContacts(partner);
|
||||
}
|
||||
|
||||
public void fillContactUiKeys(List<PartnerContactDto> contacts) {
|
||||
if (contacts == null) {
|
||||
return;
|
||||
}
|
||||
contacts.forEach(contact -> {
|
||||
if (StrUtil.isBlank(contact.getUid())) {
|
||||
contact.setUid(contact.getId() == null ? null : String.valueOf(contact.getId()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void validateContacts(PartnerManageDto partner) {
|
||||
if (!needContacts(partner)) {
|
||||
return;
|
||||
}
|
||||
if (CollUtil.isEmpty(partner.getContacts())) {
|
||||
throw new ServiceException("组织类型至少需要维护一个联系人");
|
||||
}
|
||||
for (PartnerContactDto contact : partner.getContacts()) {
|
||||
if (StrUtil.isBlank(contact.getContactName())) {
|
||||
throw new ServiceException("联系人姓名不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(contact.getContactPhone())) {
|
||||
throw new ServiceException("联系人联系电话不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(contact.getPostalAddress())) {
|
||||
throw new ServiceException("联系人通讯地址不能为空");
|
||||
}
|
||||
if (StrUtil.isBlank(contact.getEmail())) {
|
||||
throw new ServiceException("联系人电子邮箱不能为空");
|
||||
}
|
||||
if (!Validator.isEmail(contact.getEmail())) {
|
||||
throw new ServiceException("联系人电子邮箱格式不正确");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void normalizeContact(PartnerContactDto contact) {
|
||||
contact.setContactName(StrUtil.trim(contact.getContactName()));
|
||||
contact.setContactPhone(StrUtil.trim(contact.getContactPhone()));
|
||||
contact.setPostalAddress(StrUtil.trim(contact.getPostalAddress()));
|
||||
contact.setEmail(StrUtil.trim(contact.getEmail()));
|
||||
contact.setRemark(StrUtil.trim(contact.getRemark()));
|
||||
contact.setDelFlag(PartnerManageConstants.CONTACT_DEL_FLAG_NORMAL);
|
||||
}
|
||||
|
||||
private boolean hasAnyContactValue(PartnerContactDto contact) {
|
||||
return StrUtil.isNotBlank(contact.getContactName())
|
||||
|| StrUtil.isNotBlank(contact.getContactPhone())
|
||||
|| StrUtil.isNotBlank(contact.getPostalAddress())
|
||||
|| StrUtil.isNotBlank(contact.getEmail());
|
||||
}
|
||||
|
||||
private boolean needContacts(PartnerManageDto partner) {
|
||||
return isDomesticOrg(partner) || isForeignOrg(partner);
|
||||
}
|
||||
|
||||
private boolean showGatFlag(PartnerManageDto partner) {
|
||||
return isDomesticOrg(partner) || isDomesticPerson(partner);
|
||||
}
|
||||
|
||||
private boolean isDomesticOrg(PartnerManageDto partner) {
|
||||
return "1".equals(partner.getOppositeCharacter());
|
||||
}
|
||||
|
||||
private boolean isDomesticPerson(PartnerManageDto partner) {
|
||||
return "2".equals(partner.getOppositeCharacter());
|
||||
}
|
||||
|
||||
private boolean isForeignOrg(PartnerManageDto partner) {
|
||||
return "3".equals(partner.getOppositeCharacter());
|
||||
}
|
||||
|
||||
private boolean isForeignPerson(PartnerManageDto partner) {
|
||||
return "4".equals(partner.getOppositeCharacter());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package com.nbport.zgwl.partner.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.nbport.zgwl.partner.dto.PartnerContactDto;
|
||||
import com.nbport.zgwl.partner.dto.PartnerManageDto;
|
||||
import com.nbport.zgwl.partner.dto.PartnerQueryDto;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 相对方管理 Mapper
|
||||
*/
|
||||
public interface PartnerManageMapper {
|
||||
|
||||
Long selectPartnerSeqNextVal();
|
||||
|
||||
Long selectPartnerContactSeqNextVal();
|
||||
|
||||
IPage<PartnerManageDto> selectPartnerPage(Page<PartnerManageDto> page, @Param("query") PartnerQueryDto queryDto);
|
||||
|
||||
PartnerManageDto selectPartnerById(@Param("customerSysid") Long customerSysid);
|
||||
|
||||
int insertPartner(PartnerManageDto partner);
|
||||
|
||||
int updatePartner(PartnerManageDto partner);
|
||||
|
||||
int deletePartnerByIds(@Param("customerSysids") List<Long> customerSysids,
|
||||
@Param("updateBy") String updateBy,
|
||||
@Param("updateTime") LocalDateTime updateTime,
|
||||
@Param("isDeleted") String isDeleted);
|
||||
|
||||
List<PartnerContactDto> selectPartnerContactsByPartnerIds(@Param("partnerRecordIds") List<Long> partnerRecordIds);
|
||||
|
||||
int markPartnerContactsDeletedByPartnerId(@Param("partnerRecordId") Long partnerRecordId,
|
||||
@Param("updateBy") String updateBy,
|
||||
@Param("updateTime") LocalDateTime updateTime,
|
||||
@Param("delFlag") String delFlag);
|
||||
|
||||
int markPartnerContactsDeletedByPartnerIds(@Param("partnerRecordIds") List<Long> partnerRecordIds,
|
||||
@Param("updateBy") String updateBy,
|
||||
@Param("updateTime") LocalDateTime updateTime,
|
||||
@Param("delFlag") String delFlag);
|
||||
|
||||
int batchInsertPartnerContacts(@Param("contacts") List<PartnerContactDto> contacts,
|
||||
@Param("createBy") String createBy,
|
||||
@Param("createTime") LocalDateTime createTime,
|
||||
@Param("updateBy") String updateBy,
|
||||
@Param("updateTime") LocalDateTime updateTime,
|
||||
@Param("delFlag") String delFlag);
|
||||
|
||||
int updatePartnerSyncInfo(@Param("customerSysid") Long customerSysid,
|
||||
@Param("oppositeId") String oppositeId,
|
||||
@Param("syncStatus") String syncStatus,
|
||||
@Param("syncTime") LocalDateTime syncTime,
|
||||
@Param("syncMessage") String syncMessage,
|
||||
@Param("updateBy") String updateBy,
|
||||
@Param("updateTime") LocalDateTime updateTime);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.nbport.zgwl.partner.service;
|
||||
|
||||
import com.nbport.zgwl.common.PageResult;
|
||||
import com.nbport.zgwl.partner.dto.PartnerManageDto;
|
||||
import com.nbport.zgwl.partner.dto.PartnerQueryDto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 相对方管理 Service
|
||||
*/
|
||||
public interface PartnerManageService {
|
||||
|
||||
PageResult<PartnerManageDto> queryPartnerList(PartnerQueryDto queryDto);
|
||||
|
||||
PartnerManageDto selectPartnerById(Long customerSysid);
|
||||
|
||||
Long insertPartner(PartnerManageDto partner);
|
||||
|
||||
void updatePartner(PartnerManageDto partner);
|
||||
|
||||
void deletePartnerByIds(List<Long> customerSysids);
|
||||
|
||||
PartnerManageDto mockSyncPartner(Long customerSysid);
|
||||
}
|
||||
@@ -0,0 +1,260 @@
|
||||
package com.nbport.zgwl.partner.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.nbport.zgwl.common.PageResult;
|
||||
import com.nbport.zgwl.contractpush.dto.PushPayloadDTO;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
import com.nbport.zgwl.partner.dto.PartnerContactDto;
|
||||
import com.nbport.zgwl.partner.dto.PartnerManageDto;
|
||||
import com.nbport.zgwl.partner.dto.PartnerQueryDto;
|
||||
import com.nbport.zgwl.partner.handler.PartnerDataHandler;
|
||||
import com.nbport.zgwl.partner.mapper.PartnerManageMapper;
|
||||
import com.nbport.zgwl.partner.utils.PartnerIdUtils;
|
||||
import com.nbport.zgwl.partner.utils.PartnerManageConstants;
|
||||
import com.nbport.zgwl.partner.utils.PartnerSyncPayloadBuilder;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 相对方管理 Service 实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class PartnerManageServiceImpl implements PartnerManageService {
|
||||
|
||||
private final PartnerManageMapper partnerManageMapper;
|
||||
|
||||
private final PartnerDataHandler partnerDataHandler;
|
||||
|
||||
@Override
|
||||
public PageResult<PartnerManageDto> queryPartnerList(PartnerQueryDto queryDto) {
|
||||
Page<PartnerManageDto> page = new Page<>(queryDto.getPageNo(), queryDto.getPageSize());
|
||||
PageResult<PartnerManageDto> pageResult = new PageResult<>(
|
||||
partnerManageMapper.selectPartnerPage(page, queryDto));
|
||||
attachContacts(pageResult.getRecords());
|
||||
return pageResult;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PartnerManageDto selectPartnerById(Long customerSysid) {
|
||||
PartnerManageDto partner = partnerManageMapper.selectPartnerById(customerSysid);
|
||||
if (partner == null) {
|
||||
throw new ServiceException("相对方不存在");
|
||||
}
|
||||
attachContacts(Collections.singletonList(partner));
|
||||
return partner;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long insertPartner(PartnerManageDto partner) {
|
||||
partnerDataHandler.normalizeBeforeSave(partner);
|
||||
partnerDataHandler.validateForSave(partner);
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
partner.setCustomerSysid(partnerManageMapper.selectPartnerSeqNextVal());
|
||||
partner.setOppositeCode(ensureOppositeCode(partner.getOppositeCode()));
|
||||
partner.setOppositeId(null);
|
||||
partner.setSyncStatus(PartnerManageConstants.SYNC_STATUS_UNSYNCED);
|
||||
partner.setSyncTime(null);
|
||||
partner.setSyncMessage("新增后尚未同步");
|
||||
partner.setOppositeStatus(PartnerManageConstants.OPPOSITE_STATUS_EFFECTUAL);
|
||||
partner.setCreateBy(PartnerManageConstants.DEFAULT_OPERATOR);
|
||||
partner.setCreateTime(now);
|
||||
partner.setUpdateBy(PartnerManageConstants.DEFAULT_OPERATOR);
|
||||
partner.setUpdateTime(now);
|
||||
partner.setIsDeleted(PartnerManageConstants.PARTNER_IS_DELETED_NORMAL);
|
||||
|
||||
partnerManageMapper.insertPartner(partner);
|
||||
saveContacts(partner.getCustomerSysid(), partner.getContacts(), now);
|
||||
return partner.getCustomerSysid();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updatePartner(PartnerManageDto partner) {
|
||||
if (partner.getCustomerSysid() == null) {
|
||||
throw new ServiceException("修改时 customerSysid 不能为空");
|
||||
}
|
||||
|
||||
PartnerManageDto dbPartner = partnerManageMapper.selectPartnerById(partner.getCustomerSysid());
|
||||
if (dbPartner == null) {
|
||||
throw new ServiceException("相对方不存在或已删除");
|
||||
}
|
||||
|
||||
partnerDataHandler.normalizeBeforeSave(partner);
|
||||
partnerDataHandler.validateForSave(partner);
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
partner.setOppositeCode(ensureOppositeCode(partner.getOppositeCode(), dbPartner.getOppositeCode()));
|
||||
partner.setOppositeId(dbPartner.getOppositeId());
|
||||
partner.setOppositeStatus(ensureValue(partner.getOppositeStatus(), dbPartner.getOppositeStatus(),
|
||||
PartnerManageConstants.OPPOSITE_STATUS_EFFECTUAL));
|
||||
partner.setSyncStatus(PartnerManageConstants.SYNC_STATUS_UNSYNCED);
|
||||
partner.setSyncTime(null);
|
||||
partner.setSyncMessage("信息已修改,待重新同步");
|
||||
partner.setUpdateBy(PartnerManageConstants.DEFAULT_OPERATOR);
|
||||
partner.setUpdateTime(now);
|
||||
partner.setIsDeleted(PartnerManageConstants.PARTNER_IS_DELETED_NORMAL);
|
||||
|
||||
partnerManageMapper.updatePartner(partner);
|
||||
partnerManageMapper.markPartnerContactsDeletedByPartnerId(
|
||||
partner.getCustomerSysid(),
|
||||
PartnerManageConstants.DEFAULT_OPERATOR,
|
||||
now,
|
||||
PartnerManageConstants.CONTACT_DEL_FLAG_DELETED);
|
||||
saveContacts(partner.getCustomerSysid(), partner.getContacts(), now);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deletePartnerByIds(List<Long> customerSysids) {
|
||||
if (customerSysids == null || customerSysids.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
partnerManageMapper.markPartnerContactsDeletedByPartnerIds(
|
||||
customerSysids,
|
||||
PartnerManageConstants.DEFAULT_OPERATOR,
|
||||
now,
|
||||
PartnerManageConstants.CONTACT_DEL_FLAG_DELETED);
|
||||
partnerManageMapper.deletePartnerByIds(
|
||||
customerSysids,
|
||||
PartnerManageConstants.DEFAULT_OPERATOR,
|
||||
now,
|
||||
PartnerManageConstants.PARTNER_IS_DELETED_DELETED);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public PartnerManageDto mockSyncPartner(Long customerSysid) {
|
||||
PartnerManageDto partner = partnerManageMapper.selectPartnerById(customerSysid);
|
||||
if (partner == null) {
|
||||
throw new ServiceException("相对方不存在或已删除");
|
||||
}
|
||||
|
||||
attachContacts(Collections.singletonList(partner));
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
String oppositeId = StrUtilHelper.hasText(partner.getOppositeId())
|
||||
? partner.getOppositeId()
|
||||
: PartnerIdUtils.buildGroupPartnerId();
|
||||
|
||||
PartnerSyncPayloadBuilder.buildCollectOppositesPayload(partner);
|
||||
// PushPayloadDTO payloadDTO =
|
||||
// PartnerSyncPayloadBuilder.buildCollectOppositesPayload(partner);
|
||||
// Map<String, Object> response =
|
||||
// dataCollectionPushService.collectOpposites(payloadDTO);
|
||||
String syncMessage = "本地测试模拟同步成功。TODO:后续在这里调用相对方信息采集接口 collectOpposites。";
|
||||
// // 从法务系统响应中取出返回的 oppositeId(比如 response 里有个 "jtId" 字段)
|
||||
// String oppositeIdFromLawSystem = ...; // 具体 key 看法务返回的字段名
|
||||
// String syncMessage = response.containsKey("msg")
|
||||
// ? String.valueOf(response.get("msg"))
|
||||
// : "相对方信息采集同步成功";
|
||||
|
||||
// // 回写法务返回的 oppositeId,而不是本地生成的
|
||||
partnerManageMapper.updatePartnerSyncInfo(
|
||||
customerSysid,
|
||||
oppositeId,
|
||||
PartnerManageConstants.SYNC_STATUS_SYNCED,
|
||||
now,
|
||||
syncMessage,
|
||||
PartnerManageConstants.DEFAULT_OPERATOR,
|
||||
now);
|
||||
return selectPartnerById(customerSysid);
|
||||
}
|
||||
|
||||
private void attachContacts(List<PartnerManageDto> partnerList) {
|
||||
if (partnerList == null || partnerList.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<Long> customerSysids = partnerList.stream()
|
||||
.map(PartnerManageDto::getCustomerSysid)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toList());
|
||||
if (customerSysids.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
List<PartnerContactDto> contacts = partnerManageMapper.selectPartnerContactsByPartnerIds(customerSysids);
|
||||
Map<Long, List<PartnerContactDto>> contactMap = contacts.stream()
|
||||
.collect(Collectors.groupingBy(PartnerContactDto::getPartnerRecordId));
|
||||
|
||||
partnerList.forEach(item -> {
|
||||
List<PartnerContactDto> currentContacts = contactMap.getOrDefault(item.getCustomerSysid(),
|
||||
Collections.emptyList());
|
||||
partnerDataHandler.fillContactUiKeys(currentContacts);
|
||||
item.setContacts(currentContacts);
|
||||
});
|
||||
}
|
||||
|
||||
private void saveContacts(Long customerSysid, List<PartnerContactDto> contacts, LocalDateTime now) {
|
||||
if (customerSysid == null || contacts == null || contacts.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int sortOrder = 1;
|
||||
for (PartnerContactDto contact : contacts) {
|
||||
contact.setId(partnerManageMapper.selectPartnerContactSeqNextVal());
|
||||
contact.setPartnerRecordId(customerSysid);
|
||||
contact.setSortOrder(sortOrder++);
|
||||
contact.setDelFlag(PartnerManageConstants.CONTACT_DEL_FLAG_NORMAL);
|
||||
}
|
||||
|
||||
partnerManageMapper.batchInsertPartnerContacts(
|
||||
contacts,
|
||||
PartnerManageConstants.DEFAULT_OPERATOR,
|
||||
now,
|
||||
PartnerManageConstants.DEFAULT_OPERATOR,
|
||||
now,
|
||||
PartnerManageConstants.CONTACT_DEL_FLAG_NORMAL);
|
||||
}
|
||||
|
||||
private String ensureOppositeCode(String oppositeCode) {
|
||||
return ensureOppositeCode(oppositeCode, null);
|
||||
}
|
||||
|
||||
private String ensureOppositeCode(String oppositeCode, String fallback) {
|
||||
if (StrUtilHelper.hasText(oppositeCode)) {
|
||||
return oppositeCode;
|
||||
}
|
||||
if (StrUtilHelper.hasText(fallback)) {
|
||||
return fallback;
|
||||
}
|
||||
return PartnerIdUtils.buildPartnerId();
|
||||
}
|
||||
|
||||
private String ensureValue(String value, String fallback, String defaultValue) {
|
||||
if (StrUtilHelper.hasText(value)) {
|
||||
return value;
|
||||
}
|
||||
if (StrUtilHelper.hasText(fallback)) {
|
||||
return fallback;
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* 避免为了一个判空再引入新依赖,这里保留一个最小工具。
|
||||
*/
|
||||
private static final class StrUtilHelper {
|
||||
|
||||
private StrUtilHelper() {
|
||||
}
|
||||
|
||||
private static boolean hasText(String value) {
|
||||
return value != null && !value.isBlank();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package com.nbport.zgwl.partner.utils;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* 相关方ID生成工具
|
||||
*
|
||||
* 本地相关方ID:自己系统生成,后续同步给法务系统时对应 o_id。
|
||||
* 集团相对方ID:这里先做模拟生成,后续真实联调时用法务系统回传值覆盖。
|
||||
*/
|
||||
public final class PartnerIdUtils {
|
||||
|
||||
private static final String PARTNER_PREFIX = "OPP";
|
||||
|
||||
private static final String GROUP_PREFIX = "JT";
|
||||
|
||||
private PartnerIdUtils() {
|
||||
}
|
||||
|
||||
public static String buildPartnerId() {
|
||||
return PARTNER_PREFIX + "-" + formatNow("yyyyMMddHHmmss") + "-" + randomDigits(4);
|
||||
}
|
||||
|
||||
public static String buildGroupPartnerId() {
|
||||
return GROUP_PREFIX + "-" + formatNow("yyyyMMddHHmmss") + "-" + randomDigits(4);
|
||||
}
|
||||
|
||||
private static String formatNow(String pattern) {
|
||||
return new SimpleDateFormat(pattern).format(new Date());
|
||||
}
|
||||
|
||||
private static String randomDigits(int length) {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (int i = 0; i < length; i++) {
|
||||
builder.append(ThreadLocalRandom.current().nextInt(10));
|
||||
}
|
||||
return builder.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.nbport.zgwl.partner.utils;
|
||||
|
||||
/**
|
||||
* 相对方模块常量
|
||||
*/
|
||||
public final class PartnerManageConstants {
|
||||
|
||||
private PartnerManageConstants() {
|
||||
}
|
||||
|
||||
public static final String REQUEST_PREFIX = "/partner/manage";
|
||||
|
||||
public static final String DEFAULT_OPERATOR = "local_test";
|
||||
|
||||
public static final String PARTNER_IS_DELETED_NORMAL = "N";
|
||||
|
||||
public static final String PARTNER_IS_DELETED_DELETED = "Y";
|
||||
|
||||
public static final String CONTACT_DEL_FLAG_NORMAL = "0";
|
||||
|
||||
public static final String CONTACT_DEL_FLAG_DELETED = "2";
|
||||
|
||||
public static final String OPPOSITE_STATUS_EFFECTUAL = "EFFECTUAL";
|
||||
|
||||
public static final String GAT_FLAG_YES = "Y";
|
||||
|
||||
public static final String GAT_FLAG_NO = "N";
|
||||
|
||||
public static final String GROUP_FLAG_YES = "Y";
|
||||
|
||||
public static final String GROUP_FLAG_NO = "N";
|
||||
|
||||
public static final String FLAG_ONE = "1";
|
||||
|
||||
public static final String FLAG_ZERO = "0";
|
||||
|
||||
public static final String SYNC_STATUS_UNSYNCED = "unsynced";
|
||||
|
||||
public static final String SYNC_STATUS_SYNCED = "synced";
|
||||
|
||||
public static final String SYNC_STATUS_FAILED = "failed";
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package com.nbport.zgwl.partner.utils;
|
||||
|
||||
import com.nbport.zgwl.contractpush.dto.PushPayloadDTO;
|
||||
import com.nbport.zgwl.partner.dto.PartnerContactDto;
|
||||
import com.nbport.zgwl.partner.dto.PartnerManageDto;
|
||||
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 相对方同步报文构造工具
|
||||
*/
|
||||
public final class PartnerSyncPayloadBuilder {
|
||||
|
||||
private PartnerSyncPayloadBuilder() {
|
||||
}
|
||||
|
||||
public static PushPayloadDTO buildCollectOppositesPayload(PartnerManageDto partner) {
|
||||
Map<String, Object> payload = new LinkedHashMap<>();
|
||||
payload.put("o_id", partner.getCustomerSysid() == null ? null : String.valueOf(partner.getCustomerSysid()));
|
||||
payload.put("o_name", partner.getCustomerNameC());
|
||||
payload.put("o_type", partner.getRelativeType());
|
||||
payload.put("o_nature", partner.getOppositeCharacter());
|
||||
payload.put("o_orgNature", convertOrgNature(partner.getNatureOfEnterpriseOrg()));
|
||||
payload.put("o_orgNature_2", partner.getNatureOfEnterpriseOrgLev());
|
||||
payload.put("o_GAT", PartnerManageConstants.GAT_FLAG_YES.equals(partner.getGatFlag())
|
||||
? PartnerManageConstants.FLAG_ONE
|
||||
: PartnerManageConstants.FLAG_ZERO);
|
||||
payload.put("o_isGroup", PartnerManageConstants.GROUP_FLAG_YES.equals(partner.getGroupFlag())
|
||||
? PartnerManageConstants.FLAG_ONE
|
||||
: PartnerManageConstants.FLAG_ZERO);
|
||||
payload.put("o_creditCode", partner.getCustomerTaxno());
|
||||
payload.put("o_zjType", partner.getCertificateType());
|
||||
payload.put("o_zjNo", partner.getCertificateNum());
|
||||
payload.put("o_tin", partner.getTinCode());
|
||||
payload.put("o_country", partner.getCountry());
|
||||
payload.put("o_legalPerson", partner.getLegalPersonName());
|
||||
payload.put("o_address", partner.getCustomerRegaddr());
|
||||
payload.put("o_capital", partner.getRegCapital());
|
||||
payload.put("o_creator", partner.getCreateBy());
|
||||
payload.put("o_creationTime", partner.getCreateTime() == null ? null : partner.getCreateTime().toString().replace("T", " "));
|
||||
payload.put("o_contacts", buildContactList(partner.getContacts()));
|
||||
|
||||
PushPayloadDTO requestDTO = new PushPayloadDTO();
|
||||
requestDTO.setPayload(payload);
|
||||
return requestDTO;
|
||||
}
|
||||
|
||||
private static List<Map<String, Object>> buildContactList(List<PartnerContactDto> contacts) {
|
||||
if (contacts == null) {
|
||||
return List.of();
|
||||
}
|
||||
return contacts.stream().map(item -> {
|
||||
Map<String, Object> contact = new LinkedHashMap<>();
|
||||
contact.put("name", item.getContactName());
|
||||
contact.put("phone", item.getContactPhone());
|
||||
contact.put("postalAddress", item.getPostalAddress());
|
||||
contact.put("email", item.getEmail());
|
||||
return contact;
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private static String convertOrgNature(String natureOfEnterpriseOrg) {
|
||||
if ("ZY".equals(natureOfEnterpriseOrg)) {
|
||||
return "ZF";
|
||||
}
|
||||
return natureOfEnterpriseOrg;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.nbport.zgwl.seal.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 签章平台配置类
|
||||
* 从application.yml中读取签章平台相关配置
|
||||
*
|
||||
* 在application.yml中添加如下配置:
|
||||
* seal:
|
||||
* appKey: A7C4FD32BE454B5
|
||||
* appSecret: 你的appSecret(联系浙江CA获取)
|
||||
* baseUrl: https://saasapi.certca.cn
|
||||
*
|
||||
* @author xiaofengzhou
|
||||
*/
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "seal")
|
||||
public class SealConfig {
|
||||
|
||||
/** 应用Key,由浙江CA提供,用于获取访问令牌 */
|
||||
private String appKey;
|
||||
|
||||
/** 应用密钥,由浙江CA提供,用于计算HMAC签名 */
|
||||
private String appSecret;
|
||||
|
||||
/** 签章平台API基础地址,例如 https://saasapi.certca.cn */
|
||||
private String baseUrl;
|
||||
|
||||
public String getAppKey() {
|
||||
return appKey;
|
||||
}
|
||||
|
||||
public void setAppKey(String appKey) {
|
||||
this.appKey = appKey;
|
||||
}
|
||||
|
||||
public String getAppSecret() {
|
||||
return appSecret;
|
||||
}
|
||||
|
||||
public void setAppSecret(String appSecret) {
|
||||
this.appSecret = appSecret;
|
||||
}
|
||||
|
||||
public String getBaseUrl() {
|
||||
return baseUrl;
|
||||
}
|
||||
|
||||
public void setBaseUrl(String baseUrl) {
|
||||
this.baseUrl = baseUrl;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.nbport.zgwl.seal.config;
|
||||
|
||||
import com.nbport.zgwl.seal.handler.SealWebSocketHandler;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.socket.config.annotation.EnableWebSocket;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
|
||||
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
|
||||
|
||||
/**
|
||||
* WebSocket配置类
|
||||
*
|
||||
* 配置签章平台回调的WebSocket连接端点
|
||||
* 前端通过 ws://localhost:8080/seal/ws/callback 建立连接
|
||||
*
|
||||
* 注意:
|
||||
* 1. setAllowedOrigins("*") 允许所有来源,生产环境应限制为具体域名
|
||||
* 2. WebSocket不走Spring Security的HTTP认证,需要额外考虑安全性
|
||||
*
|
||||
* @author xiaofengzhou
|
||||
*/
|
||||
@Configuration
|
||||
@EnableWebSocket
|
||||
public class SealWebSocketConfig implements WebSocketConfigurer {
|
||||
|
||||
@Autowired
|
||||
private SealWebSocketHandler sealWebSocketHandler;
|
||||
|
||||
@Override
|
||||
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
|
||||
registry.addHandler(sealWebSocketHandler, "/seal/ws/callback")
|
||||
.setAllowedOrigins("*");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
package com.nbport.zgwl.seal.controller;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.nbport.zgwl.common.R;
|
||||
import com.nbport.zgwl.seal.handler.SealWebSocketHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 签章平台回调接口控制器
|
||||
*
|
||||
* @author xiaofengzhou
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/seal/callback")
|
||||
public class SealCallbackController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SealCallbackController.class);
|
||||
|
||||
@Autowired
|
||||
private SealWebSocketHandler webSocketHandler;
|
||||
|
||||
@PostMapping("/login")
|
||||
public R<String> loginCallback(@RequestBody Map<String, Object> params) {
|
||||
log.info("收到身份认证回调: {}", JSON.toJSONString(params));
|
||||
|
||||
try {
|
||||
String requestId = (String) params.get("requestId");
|
||||
webSocketHandler.sendCallbackMessage(requestId, "login", params);
|
||||
return R.success("回调接收成功");
|
||||
} catch (Exception e) {
|
||||
log.error("处理身份认证回调失败", e);
|
||||
return R.error("回调处理失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/sign")
|
||||
public R<String> signCallback(@RequestBody Map<String, Object> params) {
|
||||
log.info("收到签署回调: {}", JSON.toJSONString(params));
|
||||
|
||||
try {
|
||||
String contractId = (String) params.get("contractId");
|
||||
String requestId = (String) params.get("requestId");
|
||||
webSocketHandler.sendCallbackMessage(requestId, "sign", params);
|
||||
webSocketHandler.sendCallbackMessage(contractId, "contract_status", params);
|
||||
return R.success("回调接收成功");
|
||||
} catch (Exception e) {
|
||||
log.error("处理签署回调失败", e);
|
||||
return R.error("回调处理失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/presign")
|
||||
public R<String> presignCallback(@RequestBody Map<String, Object> params) {
|
||||
log.info("收到预盖章回调: {}", JSON.toJSONString(params));
|
||||
|
||||
try {
|
||||
String contractId = (String) params.get("contractId");
|
||||
String requestId = (String) params.get("requestId");
|
||||
webSocketHandler.sendCallbackMessage(requestId, "presign", params);
|
||||
webSocketHandler.sendCallbackMessage(contractId, "contract_status", params);
|
||||
return R.success("回调接收成功");
|
||||
} catch (Exception e) {
|
||||
log.error("处理预盖章回调失败", e);
|
||||
return R.error("回调处理失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/trusteeship")
|
||||
public R<String> trusteeshipCallback(@RequestBody Map<String, Object> params) {
|
||||
log.info("收到托管章回调: {}", JSON.toJSONString(params));
|
||||
|
||||
try {
|
||||
String requestId = (String) params.get("requestId");
|
||||
webSocketHandler.sendCallbackMessage(requestId, "trusteeship", params);
|
||||
return R.success("回调接收成功");
|
||||
} catch (Exception e) {
|
||||
log.error("处理托管章回调失败", e);
|
||||
return R.error("回调处理失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/signQrCode")
|
||||
public R<String> signQrCodeCallback(@RequestBody Map<String, Object> params) {
|
||||
log.info("收到签名二维码回调: {}", JSON.toJSONString(params));
|
||||
|
||||
try {
|
||||
String requestId = (String) params.get("requestId");
|
||||
webSocketHandler.sendCallbackMessage(requestId, "signQrCode", params);
|
||||
return R.success("回调接收成功");
|
||||
} catch (Exception e) {
|
||||
log.error("处理签名二维码回调失败", e);
|
||||
return R.error("回调处理失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/poll/{requestId}")
|
||||
public R<Map<String, Object>> pollCallback(@PathVariable String requestId) {
|
||||
Map<String, Object> callbackData = webSocketHandler.getCallbackData(requestId);
|
||||
return R.success(callbackData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,353 @@
|
||||
package com.nbport.zgwl.seal.controller;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.nbport.zgwl.common.R;
|
||||
import com.nbport.zgwl.seal.config.SealConfig;
|
||||
import com.nbport.zgwl.seal.service.SealTokenService;
|
||||
import com.nbport.zgwl.seal.utils.SealHttpClient;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 签章平台代理控制器
|
||||
*
|
||||
* @author xiaofengzhou
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/seal/api")
|
||||
public class SealProxyController {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SealProxyController.class);
|
||||
|
||||
@Autowired
|
||||
private SealConfig sealConfig;
|
||||
|
||||
@Autowired
|
||||
private SealTokenService sealTokenService;
|
||||
|
||||
private String proxyPost(String apiPath, String requestBody) {
|
||||
String accessToken = sealTokenService.getAccessToken();
|
||||
String url = sealConfig.getBaseUrl() + apiPath;
|
||||
log.info("代理请求签章平台: {} body: {}", url, requestBody);
|
||||
return SealHttpClient.post(url, requestBody, accessToken, MediaType.APPLICATION_JSON_VALUE);
|
||||
}
|
||||
|
||||
private String proxyPost(String apiPath) {
|
||||
return proxyPost(apiPath, "{}");
|
||||
}
|
||||
|
||||
private R<Object> parseSealResponse(String responseJson) {
|
||||
try {
|
||||
JSONObject result = JSON.parseObject(responseJson);
|
||||
if (result.getBooleanValue("isSuccess")) {
|
||||
return R.success(result.get("data"));
|
||||
} else {
|
||||
return R.error(result.getString("msg"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("解析签章平台响应失败: {}", responseJson, e);
|
||||
return R.error("解析签章平台响应失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/token/getAccessToken")
|
||||
public R<Object> getAccessToken() {
|
||||
try {
|
||||
String token = sealTokenService.forceRefreshToken();
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("access_token", token);
|
||||
data.put("expires_in", 7200);
|
||||
return R.success(data);
|
||||
} catch (Exception e) {
|
||||
log.error("获取Token失败", e);
|
||||
return R.error("获取Token失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/token/clear")
|
||||
public R<String> clearToken() {
|
||||
sealTokenService.clearToken();
|
||||
return R.success("Token已清除");
|
||||
}
|
||||
|
||||
@PostMapping("/qrcode/getLoginQrCode")
|
||||
public R<Object> getLoginQrCode(@RequestBody Map<String, String> params) {
|
||||
try {
|
||||
String notifyUrl = params.get("notifyUrl");
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("notifyUrl", notifyUrl);
|
||||
String response = proxyPost("/saas/api/qrcode/getLoginQrCode", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("获取身份认证二维码失败", e);
|
||||
return R.error("获取身份认证二维码失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/contract/start")
|
||||
public R<Object> startContract(@RequestParam("file") MultipartFile file,
|
||||
@RequestParam("contractName") String contractName,
|
||||
@RequestParam(value = "description", required = false) String description) {
|
||||
try {
|
||||
String accessToken = sealTokenService.getAccessToken();
|
||||
String url = sealConfig.getBaseUrl() + "/saas/api/contract/start";
|
||||
String response = SealHttpClient.postMultipart(url, file, contractName, description, accessToken);
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("创建签署流程失败", e);
|
||||
return R.error("创建签署流程失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/qrcode/getStandardSignQrCode")
|
||||
public R<Object> getStandardSignQrCode(@RequestBody Map<String, Object> params) {
|
||||
try {
|
||||
JSONObject body = buildSignQrCodeBody(params);
|
||||
String response = proxyPost("/saas/api/qrcode/getStandardSignQrCode", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("获取标准签章二维码失败", e);
|
||||
return R.error("获取标准签章二维码失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/qrcode/getPreSignQrCode")
|
||||
public R<Object> getPreSignQrCode(@RequestBody Map<String, Object> params) {
|
||||
try {
|
||||
JSONObject body = buildPreSignBody(params);
|
||||
String response = proxyPost("/saas/api/qrcode/getPreSignQrCode", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("获取预盖章二维码失败", e);
|
||||
return R.error("获取预盖章二维码失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/qrcode/getTrusteeshipSealQrCode")
|
||||
public R<Object> getTrusteeshipSealQrCode(@RequestBody Map<String, String> params) {
|
||||
try {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("notifyUrl", params.get("notifyUrl"));
|
||||
String response = proxyPost("/saas/api/qrcode/getTrusteeshipSealQrCode", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("获取托管章二维码失败", e);
|
||||
return R.error("获取托管章二维码失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/contract/confirmSign")
|
||||
public R<Object> confirmSign(@RequestBody Map<String, Object> params) {
|
||||
try {
|
||||
JSONObject body = new JSONObject(params);
|
||||
String response = proxyPost("/saas/api/contract/confirmSign", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("托管签署失败", e);
|
||||
return R.error("托管签署失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/seal/getTimestamp")
|
||||
public R<Object> getTimestamp(@RequestBody Map<String, String> params) {
|
||||
try {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("formatPattern", params.getOrDefault("formatPattern", "yyyy-MM-dd"));
|
||||
String response = proxyPost("/saas/api/seal/getTimestamp", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("获取时间戳印章失败", e);
|
||||
return R.error("获取时间戳印章失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/contract/signTimestamp")
|
||||
public R<Object> signTimestamp(@RequestBody Map<String, Object> params) {
|
||||
try {
|
||||
JSONObject body = new JSONObject(params);
|
||||
String response = proxyPost("/saas/api/contract/signTimestamp", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("签署时间签章失败", e);
|
||||
return R.error("签署时间签章失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/seal/getCommentSeal")
|
||||
public R<Object> getCommentSeal(@RequestBody Map<String, Object> params) {
|
||||
try {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("text", params.get("text"));
|
||||
body.put("fontSize", params.get("fontSize"));
|
||||
String response = proxyPost("/saas/api/seal/getCommentSeal", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("获取批注章预览失败", e);
|
||||
return R.error("获取批注章预览失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/contract/signCommentSeal")
|
||||
public R<Object> signCommentSeal(@RequestBody Map<String, Object> params) {
|
||||
try {
|
||||
JSONObject body = new JSONObject(params);
|
||||
String response = proxyPost("/saas/api/contract/signCommentSeal", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("签署批注签章失败", e);
|
||||
return R.error("签署批注签章失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/contract/complete")
|
||||
public R<Object> completeContract(@RequestBody Map<String, String> params) {
|
||||
try {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("contractId", params.get("contractId"));
|
||||
String response = proxyPost("/saas/api/contract/complete", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("完成签署流程失败", e);
|
||||
return R.error("完成签署流程失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/contract/cancel")
|
||||
public R<Object> cancelContract(@RequestBody Map<String, String> params) {
|
||||
try {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("contractId", params.get("contractId"));
|
||||
String response = proxyPost("/saas/api/contract/cancel", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("取消签署流程失败", e);
|
||||
return R.error("取消签署流程失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/user/getUserUniqueId")
|
||||
public R<Object> getUserUniqueId(@RequestBody Map<String, String> params) {
|
||||
try {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("name", params.get("name"));
|
||||
body.put("mobile", params.get("mobile"));
|
||||
body.put("idCode", params.get("idCode"));
|
||||
String response = proxyPost("/saas/api/user/getUserUniqueId ", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户身份编码失败", e);
|
||||
return R.error("获取用户身份编码失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/seal/getSealBySignerId")
|
||||
public R<Object> getSealBySignerId(@RequestBody Map<String, Object> params) {
|
||||
try {
|
||||
JSONObject body = new JSONObject(params);
|
||||
String response = proxyPost("/saas/api/seal/getSealBySignerId", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户印章失败", e);
|
||||
return R.error("获取用户印章失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/contract/getDetail")
|
||||
public R<Object> getContractDetail(@RequestBody Map<String, String> params) {
|
||||
try {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("contractId", params.get("contractId"));
|
||||
String response = proxyPost("/saas/api/contract/getDetail", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("获取合约详情失败", e);
|
||||
return R.error("获取合约详情失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/contract/preview")
|
||||
public R<Object> previewContract(@RequestBody Map<String, String> params) {
|
||||
try {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("contractId", params.get("contractId"));
|
||||
String response = proxyPost("/saas/api/contract/preview", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("预览合约文件失败", e);
|
||||
return R.error("预览合约文件失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/contract/download")
|
||||
public R<Object> downloadContract(@RequestBody Map<String, String> params) {
|
||||
try {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("contractId", params.get("contractId"));
|
||||
String response = proxyPost("/saas/api/contract/download", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("下载合约文件失败", e);
|
||||
return R.error("下载合约文件失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/user/getUserInfos")
|
||||
public R<Object> getUserInfos(@RequestBody Map<String, String> params) {
|
||||
try {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("requestId", params.get("requestId"));
|
||||
String response = proxyPost("/api/user/getUserInfos", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户隐私数据失败", e);
|
||||
return R.error("获取用户隐私数据失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@PostMapping("/qrcode/getSignQrCode")
|
||||
public R<Object> getSignQrCode(@RequestBody Map<String, String> params) {
|
||||
try {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("notifyUrl", params.get("notifyUrl"));
|
||||
body.put("originalBase64Str", params.get("originalBase64Str"));
|
||||
String response = proxyPost("/saas/api/qrcode/getSignQrCode", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("获取签名二维码失败", e);
|
||||
return R.error("获取签名二维码失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private JSONObject buildSignQrCodeBody(Map<String, Object> params) {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("contractId", params.get("contractId"));
|
||||
body.put("notifyUrl", params.get("notifyUrl"));
|
||||
body.put("isNeedUrlLink", params.getOrDefault("isNeedUrlLink", false));
|
||||
body.put("sealConfigs", params.get("sealConfigs"));
|
||||
body.put("pagingSealConfig", params.get("pagingSealConfig"));
|
||||
return body;
|
||||
}
|
||||
|
||||
private JSONObject buildPreSignBody(Map<String, Object> params) {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("contractId", params.get("contractId"));
|
||||
body.put("notifyUrl", params.get("notifyUrl"));
|
||||
body.put("isNeedUrlLink", params.getOrDefault("isNeedUrlLink", false));
|
||||
body.put("sealConfigs", params.get("sealConfigs"));
|
||||
body.put("pagingSealConfigs", params.get("pagingSealConfigs"));
|
||||
body.put("timestampSealConfigs", params.get("timestampSealConfigs"));
|
||||
return body;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,923 @@
|
||||
package com.nbport.zgwl.seal.dto;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 签章平台API数据传输对象(DTO)
|
||||
*
|
||||
* 包含所有签章平台API的请求和响应数据结构
|
||||
* 统一管理在一个文件中,方便后续迁移和维护
|
||||
*
|
||||
* @author xiaofengzhou
|
||||
*/
|
||||
public class SealApiDTO {
|
||||
|
||||
public static class SealResponse<T> {
|
||||
private boolean isSuccess;
|
||||
private String msg;
|
||||
private int code;
|
||||
private T data;
|
||||
|
||||
public boolean isSuccess() {
|
||||
return isSuccess;
|
||||
}
|
||||
|
||||
public void setSuccess(boolean success) {
|
||||
isSuccess = success;
|
||||
}
|
||||
|
||||
public String getMsg() {
|
||||
return msg;
|
||||
}
|
||||
|
||||
public void setMsg(String msg) {
|
||||
this.msg = msg;
|
||||
}
|
||||
|
||||
public int getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(int code) {
|
||||
this.code = code;
|
||||
}
|
||||
|
||||
public T getData() {
|
||||
return data;
|
||||
}
|
||||
|
||||
public void setData(T data) {
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TokenResponseData {
|
||||
private String access_token;
|
||||
private Integer expires_in;
|
||||
|
||||
public String getAccess_token() {
|
||||
return access_token;
|
||||
}
|
||||
|
||||
public void setAccess_token(String access_token) {
|
||||
this.access_token = access_token;
|
||||
}
|
||||
|
||||
public Integer getExpires_in() {
|
||||
return expires_in;
|
||||
}
|
||||
|
||||
public void setExpires_in(Integer expires_in) {
|
||||
this.expires_in = expires_in;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ContractStartData {
|
||||
private String contractId;
|
||||
private Long fileSize;
|
||||
private Integer imageWidth;
|
||||
private Integer imageHeight;
|
||||
private String pdfUrl;
|
||||
private List<String> pdfToImageList;
|
||||
|
||||
public String getContractId() {
|
||||
return contractId;
|
||||
}
|
||||
|
||||
public void setContractId(String contractId) {
|
||||
this.contractId = contractId;
|
||||
}
|
||||
|
||||
public Long getFileSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
public void setFileSize(Long fileSize) {
|
||||
this.fileSize = fileSize;
|
||||
}
|
||||
|
||||
public Integer getImageWidth() {
|
||||
return imageWidth;
|
||||
}
|
||||
|
||||
public void setImageWidth(Integer imageWidth) {
|
||||
this.imageWidth = imageWidth;
|
||||
}
|
||||
|
||||
public Integer getImageHeight() {
|
||||
return imageHeight;
|
||||
}
|
||||
|
||||
public void setImageHeight(Integer imageHeight) {
|
||||
this.imageHeight = imageHeight;
|
||||
}
|
||||
|
||||
public String getPdfUrl() {
|
||||
return pdfUrl;
|
||||
}
|
||||
|
||||
public void setPdfUrl(String pdfUrl) {
|
||||
this.pdfUrl = pdfUrl;
|
||||
}
|
||||
|
||||
public List<String> getPdfToImageList() {
|
||||
return pdfToImageList;
|
||||
}
|
||||
|
||||
public void setPdfToImageList(List<String> pdfToImageList) {
|
||||
this.pdfToImageList = pdfToImageList;
|
||||
}
|
||||
}
|
||||
|
||||
public static class QrCodeResponseData {
|
||||
private String requestId;
|
||||
private Integer expiresIn;
|
||||
private String qrCode;
|
||||
private String urlLink;
|
||||
|
||||
public String getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
public void setRequestId(String requestId) {
|
||||
this.requestId = requestId;
|
||||
}
|
||||
|
||||
public Integer getExpiresIn() {
|
||||
return expiresIn;
|
||||
}
|
||||
|
||||
public void setExpiresIn(Integer expiresIn) {
|
||||
this.expiresIn = expiresIn;
|
||||
}
|
||||
|
||||
public String getQrCode() {
|
||||
return qrCode;
|
||||
}
|
||||
|
||||
public void setQrCode(String qrCode) {
|
||||
this.qrCode = qrCode;
|
||||
}
|
||||
|
||||
public String getUrlLink() {
|
||||
return urlLink;
|
||||
}
|
||||
|
||||
public void setUrlLink(String urlLink) {
|
||||
this.urlLink = urlLink;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SealConfigItem {
|
||||
private String sealId;
|
||||
private Float x;
|
||||
private Float y;
|
||||
private Double scale;
|
||||
private Integer pageNum;
|
||||
|
||||
public String getSealId() {
|
||||
return sealId;
|
||||
}
|
||||
|
||||
public void setSealId(String sealId) {
|
||||
this.sealId = sealId;
|
||||
}
|
||||
|
||||
public Float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(Float x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public Float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(Float y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public Double getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
public void setScale(Double scale) {
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
public Integer getPageNum() {
|
||||
return pageNum;
|
||||
}
|
||||
|
||||
public void setPageNum(Integer pageNum) {
|
||||
this.pageNum = pageNum;
|
||||
}
|
||||
}
|
||||
|
||||
public static class PagingSealConfig {
|
||||
private String sealId;
|
||||
private Double scale;
|
||||
private Integer startPage;
|
||||
private Integer endPage;
|
||||
private Integer coordinateY;
|
||||
|
||||
public String getSealId() {
|
||||
return sealId;
|
||||
}
|
||||
|
||||
public void setSealId(String sealId) {
|
||||
this.sealId = sealId;
|
||||
}
|
||||
|
||||
public Double getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
public void setScale(Double scale) {
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
public Integer getStartPage() {
|
||||
return startPage;
|
||||
}
|
||||
|
||||
public void setStartPage(Integer startPage) {
|
||||
this.startPage = startPage;
|
||||
}
|
||||
|
||||
public Integer getEndPage() {
|
||||
return endPage;
|
||||
}
|
||||
|
||||
public void setEndPage(Integer endPage) {
|
||||
this.endPage = endPage;
|
||||
}
|
||||
|
||||
public Integer getCoordinateY() {
|
||||
return coordinateY;
|
||||
}
|
||||
|
||||
public void setCoordinateY(Integer coordinateY) {
|
||||
this.coordinateY = coordinateY;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TimestampSealConfig {
|
||||
private String formatPattern;
|
||||
private Float x;
|
||||
private Float y;
|
||||
private Integer pageNum;
|
||||
private Double scale;
|
||||
private Integer width;
|
||||
private Integer height;
|
||||
|
||||
public String getFormatPattern() {
|
||||
return formatPattern;
|
||||
}
|
||||
|
||||
public void setFormatPattern(String formatPattern) {
|
||||
this.formatPattern = formatPattern;
|
||||
}
|
||||
|
||||
public Float getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
public void setX(Float x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public Float getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setY(Float y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public Integer getPageNum() {
|
||||
return pageNum;
|
||||
}
|
||||
|
||||
public void setPageNum(Integer pageNum) {
|
||||
this.pageNum = pageNum;
|
||||
}
|
||||
|
||||
public Double getScale() {
|
||||
return scale;
|
||||
}
|
||||
|
||||
public void setScale(Double scale) {
|
||||
this.scale = scale;
|
||||
}
|
||||
|
||||
public Integer getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth(Integer width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public Integer getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight(Integer height) {
|
||||
this.height = height;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SignatureResult {
|
||||
private String contractId;
|
||||
private String contractName;
|
||||
private Integer contractStatus;
|
||||
private String signatureId;
|
||||
private String signer;
|
||||
private String signatureTime;
|
||||
private List<SignatureItem> signatureList;
|
||||
|
||||
public String getContractId() {
|
||||
return contractId;
|
||||
}
|
||||
|
||||
public void setContractId(String contractId) {
|
||||
this.contractId = contractId;
|
||||
}
|
||||
|
||||
public String getContractName() {
|
||||
return contractName;
|
||||
}
|
||||
|
||||
public void setContractName(String contractName) {
|
||||
this.contractName = contractName;
|
||||
}
|
||||
|
||||
public Integer getContractStatus() {
|
||||
return contractStatus;
|
||||
}
|
||||
|
||||
public void setContractStatus(Integer contractStatus) {
|
||||
this.contractStatus = contractStatus;
|
||||
}
|
||||
|
||||
public String getSignatureId() {
|
||||
return signatureId;
|
||||
}
|
||||
|
||||
public void setSignatureId(String signatureId) {
|
||||
this.signatureId = signatureId;
|
||||
}
|
||||
|
||||
public String getSigner() {
|
||||
return signer;
|
||||
}
|
||||
|
||||
public void setSigner(String signer) {
|
||||
this.signer = signer;
|
||||
}
|
||||
|
||||
public String getSignatureTime() {
|
||||
return signatureTime;
|
||||
}
|
||||
|
||||
public void setSignatureTime(String signatureTime) {
|
||||
this.signatureTime = signatureTime;
|
||||
}
|
||||
|
||||
public List<SignatureItem> getSignatureList() {
|
||||
return signatureList;
|
||||
}
|
||||
|
||||
public void setSignatureList(List<SignatureItem> signatureList) {
|
||||
this.signatureList = signatureList;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SignatureItem {
|
||||
private String owner;
|
||||
private String signatureId;
|
||||
private String signer;
|
||||
private String signatureTime;
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public String getSignatureId() {
|
||||
return signatureId;
|
||||
}
|
||||
|
||||
public void setSignatureId(String signatureId) {
|
||||
this.signatureId = signatureId;
|
||||
}
|
||||
|
||||
public String getSigner() {
|
||||
return signer;
|
||||
}
|
||||
|
||||
public void setSigner(String signer) {
|
||||
this.signer = signer;
|
||||
}
|
||||
|
||||
public String getSignatureTime() {
|
||||
return signatureTime;
|
||||
}
|
||||
|
||||
public void setSignatureTime(String signatureTime) {
|
||||
this.signatureTime = signatureTime;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SealInfo {
|
||||
private String sealId;
|
||||
private String sealName;
|
||||
private String pictureUrl;
|
||||
private Integer sealType;
|
||||
private String owner;
|
||||
|
||||
public String getSealId() {
|
||||
return sealId;
|
||||
}
|
||||
|
||||
public void setSealId(String sealId) {
|
||||
this.sealId = sealId;
|
||||
}
|
||||
|
||||
public String getSealName() {
|
||||
return sealName;
|
||||
}
|
||||
|
||||
public void setSealName(String sealName) {
|
||||
this.sealName = sealName;
|
||||
}
|
||||
|
||||
public String getPictureUrl() {
|
||||
return pictureUrl;
|
||||
}
|
||||
|
||||
public void setPictureUrl(String pictureUrl) {
|
||||
this.pictureUrl = pictureUrl;
|
||||
}
|
||||
|
||||
public Integer getSealType() {
|
||||
return sealType;
|
||||
}
|
||||
|
||||
public void setSealType(Integer sealType) {
|
||||
this.sealType = sealType;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ContractDetail {
|
||||
private String contractId;
|
||||
private String contractName;
|
||||
private Integer status;
|
||||
private String statusName;
|
||||
private String startTime;
|
||||
private Integer fileSize;
|
||||
private List<SignatureItem> signatureList;
|
||||
private Integer imageWidth;
|
||||
private Integer imageHeight;
|
||||
private String pdfUrl;
|
||||
private List<String> pdfToImageList;
|
||||
private String downloadUrl;
|
||||
|
||||
public String getContractId() {
|
||||
return contractId;
|
||||
}
|
||||
|
||||
public void setContractId(String contractId) {
|
||||
this.contractId = contractId;
|
||||
}
|
||||
|
||||
public String getContractName() {
|
||||
return contractName;
|
||||
}
|
||||
|
||||
public void setContractName(String contractName) {
|
||||
this.contractName = contractName;
|
||||
}
|
||||
|
||||
public Integer getStatus() {
|
||||
return status;
|
||||
}
|
||||
|
||||
public void setStatus(Integer status) {
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
public String getStatusName() {
|
||||
return statusName;
|
||||
}
|
||||
|
||||
public void setStatusName(String statusName) {
|
||||
this.statusName = statusName;
|
||||
}
|
||||
|
||||
public String getStartTime() {
|
||||
return startTime;
|
||||
}
|
||||
|
||||
public void setStartTime(String startTime) {
|
||||
this.startTime = startTime;
|
||||
}
|
||||
|
||||
public Integer getFileSize() {
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
public void setFileSize(Integer fileSize) {
|
||||
this.fileSize = fileSize;
|
||||
}
|
||||
|
||||
public List<SignatureItem> getSignatureList() {
|
||||
return signatureList;
|
||||
}
|
||||
|
||||
public void setSignatureList(List<SignatureItem> signatureList) {
|
||||
this.signatureList = signatureList;
|
||||
}
|
||||
|
||||
public Integer getImageWidth() {
|
||||
return imageWidth;
|
||||
}
|
||||
|
||||
public void setImageWidth(Integer imageWidth) {
|
||||
this.imageWidth = imageWidth;
|
||||
}
|
||||
|
||||
public Integer getImageHeight() {
|
||||
return imageHeight;
|
||||
}
|
||||
|
||||
public void setImageHeight(Integer imageHeight) {
|
||||
this.imageHeight = imageHeight;
|
||||
}
|
||||
|
||||
public String getPdfUrl() {
|
||||
return pdfUrl;
|
||||
}
|
||||
|
||||
public void setPdfUrl(String pdfUrl) {
|
||||
this.pdfUrl = pdfUrl;
|
||||
}
|
||||
|
||||
public List<String> getPdfToImageList() {
|
||||
return pdfToImageList;
|
||||
}
|
||||
|
||||
public void setPdfToImageList(List<String> pdfToImageList) {
|
||||
this.pdfToImageList = pdfToImageList;
|
||||
}
|
||||
|
||||
public String getDownloadUrl() {
|
||||
return downloadUrl;
|
||||
}
|
||||
|
||||
public void setDownloadUrl(String downloadUrl) {
|
||||
this.downloadUrl = downloadUrl;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SignerIdData {
|
||||
private String signerId;
|
||||
|
||||
public String getSignerId() {
|
||||
return signerId;
|
||||
}
|
||||
|
||||
public void setSignerId(String signerId) {
|
||||
this.signerId = signerId;
|
||||
}
|
||||
}
|
||||
|
||||
public static class UserInfoData {
|
||||
private String name;
|
||||
private String mobile;
|
||||
private String code;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getMobile() {
|
||||
return mobile;
|
||||
}
|
||||
|
||||
public void setMobile(String mobile) {
|
||||
this.mobile = mobile;
|
||||
}
|
||||
|
||||
public String getCode() {
|
||||
return code;
|
||||
}
|
||||
|
||||
public void setCode(String code) {
|
||||
this.code = code;
|
||||
}
|
||||
}
|
||||
|
||||
public static class LoginCallbackData {
|
||||
private String requestId;
|
||||
private String accountId;
|
||||
private String accountType;
|
||||
private String username;
|
||||
private String entName;
|
||||
private String entCode;
|
||||
|
||||
public String getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
public void setRequestId(String requestId) {
|
||||
this.requestId = requestId;
|
||||
}
|
||||
|
||||
public String getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public void setAccountId(String accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
public String getAccountType() {
|
||||
return accountType;
|
||||
}
|
||||
|
||||
public void setAccountType(String accountType) {
|
||||
this.accountType = accountType;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getEntName() {
|
||||
return entName;
|
||||
}
|
||||
|
||||
public void setEntName(String entName) {
|
||||
this.entName = entName;
|
||||
}
|
||||
|
||||
public String getEntCode() {
|
||||
return entCode;
|
||||
}
|
||||
|
||||
public void setEntCode(String entCode) {
|
||||
this.entCode = entCode;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SignCallbackData {
|
||||
private String contractId;
|
||||
private String contractName;
|
||||
private Integer contractStatus;
|
||||
private String signer;
|
||||
private String signerId;
|
||||
private String requestId;
|
||||
|
||||
public String getContractId() {
|
||||
return contractId;
|
||||
}
|
||||
|
||||
public void setContractId(String contractId) {
|
||||
this.contractId = contractId;
|
||||
}
|
||||
|
||||
public String getContractName() {
|
||||
return contractName;
|
||||
}
|
||||
|
||||
public void setContractName(String contractName) {
|
||||
this.contractName = contractName;
|
||||
}
|
||||
|
||||
public Integer getContractStatus() {
|
||||
return contractStatus;
|
||||
}
|
||||
|
||||
public void setContractStatus(Integer contractStatus) {
|
||||
this.contractStatus = contractStatus;
|
||||
}
|
||||
|
||||
public String getSigner() {
|
||||
return signer;
|
||||
}
|
||||
|
||||
public void setSigner(String signer) {
|
||||
this.signer = signer;
|
||||
}
|
||||
|
||||
public String getSignerId() {
|
||||
return signerId;
|
||||
}
|
||||
|
||||
public void setSignerId(String signerId) {
|
||||
this.signerId = signerId;
|
||||
}
|
||||
|
||||
public String getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
public void setRequestId(String requestId) {
|
||||
this.requestId = requestId;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TrusteeshipCallbackData {
|
||||
private String requestId;
|
||||
private List<TrusteeshipSealItem> sealList;
|
||||
private String signer;
|
||||
private String signerId;
|
||||
|
||||
public String getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
public void setRequestId(String requestId) {
|
||||
this.requestId = requestId;
|
||||
}
|
||||
|
||||
public List<TrusteeshipSealItem> getSealList() {
|
||||
return sealList;
|
||||
}
|
||||
|
||||
public void setSealList(List<TrusteeshipSealItem> sealList) {
|
||||
this.sealList = sealList;
|
||||
}
|
||||
|
||||
public String getSigner() {
|
||||
return signer;
|
||||
}
|
||||
|
||||
public void setSigner(String signer) {
|
||||
this.signer = signer;
|
||||
}
|
||||
|
||||
public String getSignerId() {
|
||||
return signerId;
|
||||
}
|
||||
|
||||
public void setSignerId(String signerId) {
|
||||
this.signerId = signerId;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TrusteeshipSealItem {
|
||||
private String sealId;
|
||||
private String sealName;
|
||||
private String entName;
|
||||
private String pictureUrl;
|
||||
private String owner;
|
||||
private String ownerSubAccountId;
|
||||
private Integer sealType;
|
||||
|
||||
public String getSealId() {
|
||||
return sealId;
|
||||
}
|
||||
|
||||
public void setSealId(String sealId) {
|
||||
this.sealId = sealId;
|
||||
}
|
||||
|
||||
public String getSealName() {
|
||||
return sealName;
|
||||
}
|
||||
|
||||
public void setSealName(String sealName) {
|
||||
this.sealName = sealName;
|
||||
}
|
||||
|
||||
public String getEntName() {
|
||||
return entName;
|
||||
}
|
||||
|
||||
public void setEntName(String entName) {
|
||||
this.entName = entName;
|
||||
}
|
||||
|
||||
public String getPictureUrl() {
|
||||
return pictureUrl;
|
||||
}
|
||||
|
||||
public void setPictureUrl(String pictureUrl) {
|
||||
this.pictureUrl = pictureUrl;
|
||||
}
|
||||
|
||||
public String getOwner() {
|
||||
return owner;
|
||||
}
|
||||
|
||||
public void setOwner(String owner) {
|
||||
this.owner = owner;
|
||||
}
|
||||
|
||||
public String getOwnerSubAccountId() {
|
||||
return ownerSubAccountId;
|
||||
}
|
||||
|
||||
public void setOwnerSubAccountId(String ownerSubAccountId) {
|
||||
this.ownerSubAccountId = ownerSubAccountId;
|
||||
}
|
||||
|
||||
public Integer getSealType() {
|
||||
return sealType;
|
||||
}
|
||||
|
||||
public void setSealType(Integer sealType) {
|
||||
this.sealType = sealType;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SignQrCodeCallbackData {
|
||||
private String requestId;
|
||||
private String accountId;
|
||||
private String accountType;
|
||||
private String username;
|
||||
private String entName;
|
||||
private String entCode;
|
||||
private String signatureValue;
|
||||
|
||||
public String getRequestId() {
|
||||
return requestId;
|
||||
}
|
||||
|
||||
public void setRequestId(String requestId) {
|
||||
this.requestId = requestId;
|
||||
}
|
||||
|
||||
public String getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
|
||||
public void setAccountId(String accountId) {
|
||||
this.accountId = accountId;
|
||||
}
|
||||
|
||||
public String getAccountType() {
|
||||
return accountType;
|
||||
}
|
||||
|
||||
public void setAccountType(String accountType) {
|
||||
this.accountType = accountType;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getEntName() {
|
||||
return entName;
|
||||
}
|
||||
|
||||
public void setEntName(String entName) {
|
||||
this.entName = entName;
|
||||
}
|
||||
|
||||
public String getEntCode() {
|
||||
return entCode;
|
||||
}
|
||||
|
||||
public void setEntCode(String entCode) {
|
||||
this.entCode = entCode;
|
||||
}
|
||||
|
||||
public String getSignatureValue() {
|
||||
return signatureValue;
|
||||
}
|
||||
|
||||
public void setSignatureValue(String signatureValue) {
|
||||
this.signatureValue = signatureValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package com.nbport.zgwl.seal.handler;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.socket.CloseStatus;
|
||||
import org.springframework.web.socket.TextMessage;
|
||||
import org.springframework.web.socket.WebSocketSession;
|
||||
import org.springframework.web.socket.handler.TextWebSocketHandler;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 签章平台WebSocket处理器
|
||||
*
|
||||
* 职责:
|
||||
* 1. 管理WebSocket连接
|
||||
* 2. 接收签章平台回调后,实时推送给对应的前端页面
|
||||
* 3. 提供轮询兜底机制
|
||||
*
|
||||
* @author xiaofengzhou
|
||||
*/
|
||||
@Component
|
||||
public class SealWebSocketHandler extends TextWebSocketHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SealWebSocketHandler.class);
|
||||
|
||||
private static final ConcurrentHashMap<String, WebSocketSession> sessions = new ConcurrentHashMap<>();
|
||||
|
||||
private static final ConcurrentHashMap<String, String> requestSessionMap = new ConcurrentHashMap<>();
|
||||
|
||||
private static final ConcurrentHashMap<String, Map<String, Object>> callbackCache = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
|
||||
String sessionId = session.getId();
|
||||
sessions.put(sessionId, session);
|
||||
log.info("WebSocket连接建立: sessionId={}", sessionId);
|
||||
sendMessage(session, "{\"type\":\"connected\",\"sessionId\":\"" + sessionId + "\"}");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
|
||||
String payload = message.getPayload();
|
||||
log.debug("收到WebSocket消息: sessionId={}, payload={}", session.getId(), payload);
|
||||
|
||||
try {
|
||||
Map<String, Object> msgMap = JSON.parseObject(payload, Map.class);
|
||||
String action = (String) msgMap.get("action");
|
||||
|
||||
if ("subscribe".equals(action)) {
|
||||
String requestId = (String) msgMap.get("requestId");
|
||||
if (requestId != null) {
|
||||
requestSessionMap.put(requestId, session.getId());
|
||||
log.info("WebSocket订阅: requestId={}, sessionId={}", requestId, session.getId());
|
||||
|
||||
Map<String, Object> cached = callbackCache.get(requestId);
|
||||
if (cached != null) {
|
||||
sendCallbackToSession(session, requestId, (String) cached.get("callbackType"), cached);
|
||||
callbackCache.remove(requestId);
|
||||
}
|
||||
}
|
||||
} else if ("unsubscribe".equals(action)) {
|
||||
String requestId = (String) msgMap.get("requestId");
|
||||
if (requestId != null) {
|
||||
requestSessionMap.remove(requestId);
|
||||
log.info("WebSocket取消订阅: requestId={}", requestId);
|
||||
}
|
||||
} else if ("ping".equals(action)) {
|
||||
sendMessage(session, "{\"type\":\"pong\"}");
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("处理WebSocket消息失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
|
||||
String sessionId = session.getId();
|
||||
sessions.remove(sessionId);
|
||||
requestSessionMap.entrySet().removeIf(entry -> sessionId.equals(entry.getValue()));
|
||||
log.info("WebSocket连接关闭: sessionId={}, status={}", sessionId, status);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
|
||||
log.error("WebSocket传输错误: sessionId={}", session.getId(), exception);
|
||||
sessions.remove(session.getId());
|
||||
}
|
||||
|
||||
public void sendCallbackMessage(String requestId, String callbackType, Map<String, Object> data) {
|
||||
if (requestId == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> cacheEntry = new ConcurrentHashMap<>();
|
||||
cacheEntry.put("callbackType", callbackType);
|
||||
cacheEntry.putAll(data);
|
||||
callbackCache.put(requestId, cacheEntry);
|
||||
|
||||
String sessionId = requestSessionMap.get(requestId);
|
||||
if (sessionId != null) {
|
||||
WebSocketSession session = sessions.get(sessionId);
|
||||
if (session != null && session.isOpen()) {
|
||||
sendCallbackToSession(session, requestId, callbackType, data);
|
||||
log.info("WebSocket推送回调成功: requestId={}, callbackType={}", requestId, callbackType);
|
||||
} else {
|
||||
log.warn("WebSocket session不存在或已关闭: sessionId={}, requestId={}", sessionId, requestId);
|
||||
requestSessionMap.remove(requestId);
|
||||
}
|
||||
} else {
|
||||
log.info("没有前端订阅此requestId的回调: requestId={}, 数据已缓存供轮询使用", requestId);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendCallbackToSession(WebSocketSession session, String requestId, String callbackType, Map<String, Object> data) {
|
||||
try {
|
||||
Map<String, Object> message = new ConcurrentHashMap<>();
|
||||
message.put("type", "callback");
|
||||
message.put("requestId", requestId);
|
||||
message.put("callbackType", callbackType);
|
||||
message.put("data", data);
|
||||
sendMessage(session, JSON.toJSONString(message));
|
||||
} catch (Exception e) {
|
||||
log.error("WebSocket推送失败: sessionId={}", session.getId(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private void sendMessage(WebSocketSession session, String message) {
|
||||
try {
|
||||
if (session.isOpen()) {
|
||||
synchronized (session) {
|
||||
session.sendMessage(new TextMessage(message));
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
log.error("WebSocket发送消息失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
public Map<String, Object> getCallbackData(String requestId) {
|
||||
return callbackCache.remove(requestId);
|
||||
}
|
||||
|
||||
public int getOnlineCount() {
|
||||
return sessions.size();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
package com.nbport.zgwl.seal.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.nbport.zgwl.seal.config.SealConfig;
|
||||
import com.nbport.zgwl.seal.utils.HMacSHA256Util;
|
||||
import com.nbport.zgwl.seal.utils.SeaHttpUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
/**
|
||||
* 签章平台Token管理服务
|
||||
*
|
||||
* @author xiaofengzhou
|
||||
*/
|
||||
@Service
|
||||
public class SealTokenService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SealTokenService.class);
|
||||
|
||||
@Autowired
|
||||
private SealConfig sealConfig;
|
||||
|
||||
private volatile String cachedToken;
|
||||
|
||||
private volatile long tokenExpireTime = 0;
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private static final long TOKEN_EXPIRE_SECONDS = 7200;
|
||||
|
||||
private static final long REFRESH_BEFORE_SECONDS = 300;
|
||||
|
||||
public String getAccessToken() {
|
||||
long now = System.currentTimeMillis();
|
||||
if (cachedToken != null && now < tokenExpireTime - REFRESH_BEFORE_SECONDS * 1000) {
|
||||
return cachedToken;
|
||||
}
|
||||
|
||||
try {
|
||||
lock.lock();
|
||||
if (cachedToken != null && now < tokenExpireTime - REFRESH_BEFORE_SECONDS * 1000) {
|
||||
return cachedToken;
|
||||
}
|
||||
refreshToken();
|
||||
return cachedToken;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public String forceRefreshToken() {
|
||||
try {
|
||||
lock.lock();
|
||||
refreshToken();
|
||||
return cachedToken;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshToken() {
|
||||
try {
|
||||
String appKey = sealConfig.getAppKey();
|
||||
String appSecret = sealConfig.getAppSecret();
|
||||
long timestamp = System.currentTimeMillis();
|
||||
|
||||
JSONObject signData = new JSONObject();
|
||||
signData.put("appKey", appKey);
|
||||
signData.put("timestamp", timestamp);
|
||||
String signatureStr = JSON.toJSONString(signData);
|
||||
|
||||
String signature = HMacSHA256Util.encrypt(signatureStr, appSecret);
|
||||
log.debug("签章平台Token请求 - 签名原文: {}, 签名值: {}", signatureStr, signature);
|
||||
|
||||
JSONObject requestBody = new JSONObject();
|
||||
requestBody.put("appKey", appKey);
|
||||
requestBody.put("timestamp", timestamp);
|
||||
requestBody.put("signature", signature);
|
||||
|
||||
String url = sealConfig.getBaseUrl() + "/saas/api/token/getAccessToken";
|
||||
log.info("请求签章平台获取Token, URL: {}", url);
|
||||
String response = SeaHttpUtils.sendPost(url, requestBody.toJSONString(), MediaType.APPLICATION_JSON_VALUE);
|
||||
|
||||
JSONObject result = JSON.parseObject(response);
|
||||
if (result.getBooleanValue("isSuccess")) {
|
||||
JSONObject data = result.getJSONObject("data");
|
||||
cachedToken = data.getString("access_token");
|
||||
long expiresIn = data.getLongValue("expires_in", TOKEN_EXPIRE_SECONDS);
|
||||
tokenExpireTime = System.currentTimeMillis() + expiresIn * 1000;
|
||||
log.info("签章平台Token获取成功, 有效期: {}秒", expiresIn);
|
||||
} else {
|
||||
String msg = result.getString("msg");
|
||||
log.error("签章平台Token获取失败: {}", msg);
|
||||
throw new RuntimeException("获取签章平台Token失败: " + msg);
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
log.error("获取签章平台Token异常", e);
|
||||
throw new RuntimeException("获取签章平台Token异常: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
public void clearToken() {
|
||||
try {
|
||||
lock.lock();
|
||||
cachedToken = null;
|
||||
tokenExpireTime = 0;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.nbport.zgwl.seal.utils;
|
||||
|
||||
import javax.crypto.Mac;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* HMacSHA256签名算法工具类
|
||||
*
|
||||
* @author xiaofengzhou
|
||||
*/
|
||||
public class HMacSHA256Util {
|
||||
|
||||
public static String encrypt(String message, String appSecret) {
|
||||
final String algorithm = "HmacSHA256";
|
||||
try {
|
||||
Mac hmacSha256 = Mac.getInstance(algorithm);
|
||||
byte[] keyBytes = appSecret.getBytes(StandardCharsets.UTF_8);
|
||||
byte[] messageBytes = message.getBytes(StandardCharsets.UTF_8);
|
||||
hmacSha256.init(new SecretKeySpec(keyBytes, 0, keyBytes.length, algorithm));
|
||||
byte[] digestBytes = hmacSha256.doFinal(messageBytes);
|
||||
return byteArrayToHexString(digestBytes);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("HMacSHA256签名计算失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
private static String byteArrayToHexString(byte[] bytes) {
|
||||
StringBuilder hs = new StringBuilder();
|
||||
String stmp;
|
||||
for (int n = 0; (bytes != null) && (n < bytes.length); n++) {
|
||||
stmp = Integer.toHexString(bytes[n] & 0xFF);
|
||||
if (stmp.length() == 1) {
|
||||
hs.append('0');
|
||||
}
|
||||
hs.append(stmp);
|
||||
}
|
||||
return hs.toString().toLowerCase();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.nbport.zgwl.seal.utils;
|
||||
|
||||
/**
|
||||
* 签章平台基础HTTP工具
|
||||
*
|
||||
* 保留单独工具类名称,便于和原项目调用习惯保持一致。
|
||||
*/
|
||||
public class SeaHttpUtils {
|
||||
|
||||
private SeaHttpUtils() {
|
||||
}
|
||||
|
||||
public static String sendPost(String url, String jsonBody, String contentType) {
|
||||
return SealHttpClient.post(url, jsonBody, null, contentType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,179 @@
|
||||
package com.nbport.zgwl.seal.utils;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import javax.net.ssl.SSLContext;
|
||||
import javax.net.ssl.TrustManager;
|
||||
import javax.net.ssl.X509TrustManager;
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.PrintWriter;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 签章平台HTTP客户端工具类
|
||||
*
|
||||
* @author xiaofengzhou
|
||||
*/
|
||||
public class SealHttpClient {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(SealHttpClient.class);
|
||||
|
||||
private static final int CONNECT_TIMEOUT = 30000;
|
||||
|
||||
private static final int READ_TIMEOUT = 60000;
|
||||
|
||||
public static String post(String url, String jsonBody, String accessToken, String contentType) {
|
||||
HttpURLConnection conn = null;
|
||||
try {
|
||||
conn = createConnection(url);
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setDoOutput(true);
|
||||
conn.setDoInput(true);
|
||||
conn.setRequestProperty("Content-Type", contentType);
|
||||
conn.setRequestProperty("Accept", "application/json");
|
||||
if (StrUtil.isNotBlank(accessToken)) {
|
||||
conn.setRequestProperty("access_token", accessToken);
|
||||
}
|
||||
conn.setRequestProperty("User-Agent", "Mozilla/5.0");
|
||||
|
||||
if (jsonBody != null && !jsonBody.isEmpty()) {
|
||||
try (OutputStream os = conn.getOutputStream()) {
|
||||
byte[] input = jsonBody.getBytes(StandardCharsets.UTF_8);
|
||||
os.write(input, 0, input.length);
|
||||
}
|
||||
}
|
||||
|
||||
return readResponse(conn);
|
||||
} catch (Exception e) {
|
||||
log.error("HTTP POST请求失败, URL: {}", url, e);
|
||||
throw new RuntimeException("请求签章平台失败: " + e.getMessage(), e);
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static String postMultipart(String url, MultipartFile file, String contractName, String description, String accessToken) {
|
||||
HttpURLConnection conn = null;
|
||||
String boundary = "----WebKitFormBoundary" + UUID.randomUUID().toString().replace("-", "");
|
||||
|
||||
try {
|
||||
conn = createConnection(url);
|
||||
conn.setRequestMethod("POST");
|
||||
conn.setDoOutput(true);
|
||||
conn.setDoInput(true);
|
||||
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
|
||||
if (StrUtil.isNotBlank(accessToken)) {
|
||||
conn.setRequestProperty("access_token", accessToken);
|
||||
}
|
||||
conn.setRequestProperty("User-Agent", "Mozilla/5.0");
|
||||
|
||||
try (OutputStream os = conn.getOutputStream();
|
||||
PrintWriter writer = new PrintWriter(new OutputStreamWriter(os, StandardCharsets.UTF_8), true)) {
|
||||
addFormField(writer, boundary, "contractName", contractName);
|
||||
|
||||
if (description != null && !description.isEmpty()) {
|
||||
addFormField(writer, boundary, "description", description);
|
||||
}
|
||||
|
||||
writer.append("--").append(boundary).append("\r\n");
|
||||
writer.append("Content-Disposition: form-data; name=\"file\"; filename=\"")
|
||||
.append(file.getOriginalFilename()).append("\"\r\n");
|
||||
writer.append("Content-Type: ").append(file.getContentType()).append("\r\n\r\n");
|
||||
writer.flush();
|
||||
os.write(file.getBytes());
|
||||
os.flush();
|
||||
writer.append("\r\n");
|
||||
|
||||
writer.append("--").append(boundary).append("--\r\n");
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
return readResponse(conn);
|
||||
} catch (Exception e) {
|
||||
log.error("文件上传请求失败, URL: {}", url, e);
|
||||
throw new RuntimeException("文件上传失败: " + e.getMessage(), e);
|
||||
} finally {
|
||||
if (conn != null) {
|
||||
conn.disconnect();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void addFormField(PrintWriter writer, String boundary, String name, String value) {
|
||||
writer.append("--").append(boundary).append("\r\n");
|
||||
writer.append("Content-Disposition: form-data; name=\"")
|
||||
.append(name).append("\"\r\n\r\n");
|
||||
writer.append(value).append("\r\n");
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
private static HttpURLConnection createConnection(String urlStr) throws Exception {
|
||||
URL url = new URL(urlStr);
|
||||
HttpURLConnection conn;
|
||||
|
||||
if ("https".equalsIgnoreCase(url.getProtocol())) {
|
||||
HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection();
|
||||
SSLContext sslContext = SSLContext.getInstance("TLS");
|
||||
sslContext.init(null, new TrustManager[]{new TrustAllManager()}, new java.security.SecureRandom());
|
||||
httpsConn.setSSLSocketFactory(sslContext.getSocketFactory());
|
||||
httpsConn.setHostnameVerifier((hostname, session) -> true);
|
||||
conn = httpsConn;
|
||||
} else {
|
||||
conn = (HttpURLConnection) url.openConnection();
|
||||
}
|
||||
|
||||
conn.setConnectTimeout(CONNECT_TIMEOUT);
|
||||
conn.setReadTimeout(READ_TIMEOUT);
|
||||
return conn;
|
||||
}
|
||||
|
||||
private static String readResponse(HttpURLConnection conn) throws IOException {
|
||||
int responseCode = conn.getResponseCode();
|
||||
InputStream inputStream = responseCode >= 200 && responseCode < 300 ? conn.getInputStream() : conn.getErrorStream();
|
||||
|
||||
if (inputStream == null) {
|
||||
return "{}";
|
||||
}
|
||||
|
||||
StringBuilder response = new StringBuilder();
|
||||
try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("签章平台响应 [{}]: {}", responseCode, response);
|
||||
return response.toString();
|
||||
}
|
||||
|
||||
private static class TrustAllManager implements X509TrustManager {
|
||||
@Override
|
||||
public void checkClientTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void checkServerTrusted(X509Certificate[] chain, String authType) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public X509Certificate[] getAcceptedIssuers() {
|
||||
return new X509Certificate[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.nbport.zgwl.service;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import com.nbport.zgwl.exception.ServiceErrorCodeRange;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
import com.nbport.zgwl.utils.FileStorageUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.ByteArrayResource;
|
||||
import org.springframework.http.ContentDisposition;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.time.LocalDate;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.util.Objects;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class LocalFileService {
|
||||
|
||||
@Value("${file.local.path:${user.dir}/upload-files}")
|
||||
private String localPath;
|
||||
|
||||
public String upload(MultipartFile file) {
|
||||
if (file == null || file.isEmpty()) {
|
||||
throw new ServiceException("上传文件不能为空");
|
||||
}
|
||||
try {
|
||||
Path rootPath = Paths.get(localPath).toAbsolutePath().normalize();
|
||||
Files.createDirectories(rootPath);
|
||||
|
||||
String dateFolder = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
|
||||
String suffix = FileStorageUtils.getFileSuffix(Objects.requireNonNullElse(file.getOriginalFilename(), ""));
|
||||
String fileName = IdUtil.simpleUUID() + suffix;
|
||||
String relativePath = dateFolder + "/" + fileName;
|
||||
Path targetPath = FileStorageUtils.resolveFilePath(rootPath, relativePath);
|
||||
Files.createDirectories(targetPath.getParent());
|
||||
file.transferTo(targetPath);
|
||||
log.info("文件上传成功,targetPath={}", targetPath);
|
||||
return relativePath;
|
||||
} catch (IOException e) {
|
||||
log.error("文件上传失败", e);
|
||||
throw new ServiceException("文件上传失败");
|
||||
}
|
||||
}
|
||||
|
||||
public ResponseEntity<ByteArrayResource> download(String fileName) {
|
||||
try {
|
||||
Path rootPath = Paths.get(localPath).toAbsolutePath().normalize();
|
||||
Path filePath = FileStorageUtils.resolveFilePath(rootPath, fileName);
|
||||
if (!Files.exists(filePath) || Files.isDirectory(filePath)) {
|
||||
throw new ServiceException(ServiceErrorCodeRange.FILE_NOT_FOUND, "文件不存在");
|
||||
}
|
||||
byte[] bytes = Files.readAllBytes(filePath);
|
||||
String contentType = Files.probeContentType(filePath);
|
||||
MediaType mediaType = contentType == null ? MediaType.APPLICATION_OCTET_STREAM : MediaType.parseMediaType(contentType);
|
||||
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
headers.setContentType(mediaType);
|
||||
headers.setContentLength(bytes.length);
|
||||
headers.setContentDisposition(ContentDisposition.inline().filename(filePath.getFileName().toString()).build());
|
||||
return ResponseEntity.ok()
|
||||
.headers(headers)
|
||||
.body(new ByteArrayResource(bytes));
|
||||
} catch (IOException e) {
|
||||
log.error("文件下载失败", e);
|
||||
throw new ServiceException("文件下载失败");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package com.nbport.zgwl.service;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.nbport.zgwl.common.PageResult;
|
||||
import com.nbport.zgwl.dto.StudentQueryDto;
|
||||
import com.nbport.zgwl.dto.StudentSaveDto;
|
||||
import com.nbport.zgwl.entity.StudentEntity;
|
||||
import com.nbport.zgwl.entity.SysUserEntity;
|
||||
import com.nbport.zgwl.exception.ServiceErrorCodeRange;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
import com.nbport.zgwl.mapper.StudentMapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class StudentService {
|
||||
|
||||
private final StudentMapper studentMapper;
|
||||
|
||||
public PageResult<Map<String, Object>> queryList(StudentQueryDto queryDto, SysUserEntity user) {
|
||||
try {
|
||||
log.info("学生分页查询,user={}, queryDto={}", user, queryDto);
|
||||
Page<Map<String, Object>> page = new Page<>(queryDto.getPageNo(), queryDto.getPageSize());
|
||||
return new PageResult<>(studentMapper.queryList(page, queryDto));
|
||||
} catch (Exception e) {
|
||||
log.error("分页查询学生失败", e);
|
||||
throw new ServiceException("分页查询失败");
|
||||
}
|
||||
}
|
||||
|
||||
public StudentEntity detail(Long id) {
|
||||
StudentEntity studentEntity = studentMapper.selectById(id);
|
||||
if (studentEntity == null) {
|
||||
throw new ServiceException(ServiceErrorCodeRange.DATA_NOT_FOUND, "学生信息不存在");
|
||||
}
|
||||
return studentEntity;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void add(StudentSaveDto dto) {
|
||||
boolean exists = studentMapper.exists(new LambdaQueryWrapper<StudentEntity>()
|
||||
.eq(StudentEntity::getStudentNo, dto.getStudentNo()));
|
||||
if (exists) {
|
||||
throw new ServiceException("学号已存在");
|
||||
}
|
||||
StudentEntity entity = BeanUtil.copyProperties(dto, StudentEntity.class);
|
||||
studentMapper.insert(entity);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void update(StudentSaveDto dto) {
|
||||
if (dto.getId() == null) {
|
||||
throw new ServiceException("id 不能为空");
|
||||
}
|
||||
StudentEntity dbEntity = detail(dto.getId());
|
||||
boolean exists = studentMapper.exists(new LambdaQueryWrapper<StudentEntity>()
|
||||
.eq(StudentEntity::getStudentNo, dto.getStudentNo())
|
||||
.ne(StudentEntity::getId, dto.getId()));
|
||||
if (exists) {
|
||||
throw new ServiceException("学号已存在");
|
||||
}
|
||||
BeanUtil.copyProperties(dto, dbEntity);
|
||||
studentMapper.updateById(dbEntity);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void delete(Long id) {
|
||||
detail(id);
|
||||
studentMapper.deleteById(id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.nbport.zgwl.utils;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class FileStorageUtils {
|
||||
|
||||
private FileStorageUtils() {
|
||||
}
|
||||
|
||||
public static String getFileSuffix(String originalFilename) {
|
||||
if (StrUtil.isBlank(originalFilename) || !originalFilename.contains(".")) {
|
||||
return "";
|
||||
}
|
||||
return originalFilename.substring(originalFilename.lastIndexOf("."));
|
||||
}
|
||||
|
||||
public static Path resolveFilePath(Path rootPath, String relativePath) {
|
||||
String normalizedRelativePath = relativePath.replace("\\", "/");
|
||||
Path targetPath = rootPath.resolve(normalizedRelativePath).normalize();
|
||||
if (!targetPath.startsWith(rootPath)) {
|
||||
throw new ServiceException("非法文件路径");
|
||||
}
|
||||
return targetPath;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.nbport.zgwl.utils;
|
||||
|
||||
import com.nbport.zgwl.entity.SysUserEntity;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
public class MockSecurityManager {
|
||||
|
||||
public SysUserEntity getLoginUser() {
|
||||
SysUserEntity user = new SysUserEntity();
|
||||
user.setId(1L);
|
||||
user.setUsername("admin");
|
||||
user.setMobilePhone("13800000000");
|
||||
user.setEmail("admin@test.com");
|
||||
return user;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
spring:
|
||||
datasource:
|
||||
driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
url: jdbc:mysql://127.0.0.1:3306/zgwl_end?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&allowPublicKeyRetrieval=true
|
||||
username: root
|
||||
password: root
|
||||
@@ -0,0 +1,8 @@
|
||||
spring:
|
||||
datasource:
|
||||
driver-class-name: oracle.jdbc.OracleDriver
|
||||
url: jdbc:oracle:thin:@//127.0.0.1:1521/XEPDB1
|
||||
username: developer
|
||||
password: dev123
|
||||
hikari:
|
||||
connection-test-query: SELECT 1 FROM DUAL
|
||||
@@ -0,0 +1,64 @@
|
||||
server:
|
||||
port: 8899
|
||||
|
||||
spring:
|
||||
application:
|
||||
name: zgwl-end
|
||||
profiles:
|
||||
active: ${SPRING_PROFILES_ACTIVE:oracle}
|
||||
servlet:
|
||||
multipart:
|
||||
max-file-size: 20MB
|
||||
max-request-size: 20MB
|
||||
|
||||
mybatis-plus:
|
||||
mapper-locations: classpath*:mapper/**/*.xml
|
||||
type-aliases-package: com.nbport.zgwl.entity,com.nbport.zgwl.partner.domain,com.nbport.zgwl.manifest.domain
|
||||
configuration:
|
||||
map-underscore-to-camel-case: true
|
||||
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
|
||||
global-config:
|
||||
banner: false
|
||||
|
||||
springdoc:
|
||||
swagger-ui:
|
||||
path: /swagger-ui.html
|
||||
api-docs:
|
||||
path: /v3/api-docs
|
||||
|
||||
file:
|
||||
local:
|
||||
path: ${user.dir}/upload-files
|
||||
|
||||
seal:
|
||||
appKey: A7C4FD32BE454B5
|
||||
appSecret: 6c74358c28c149f18242bd614a101910
|
||||
baseUrl: https://saasapi.certca.cn
|
||||
|
||||
contract-push:
|
||||
settlement:
|
||||
systemKey: stamp-settlement-test-key
|
||||
secretKey: stamp-settlement-test-secret
|
||||
tokenUrl: http://10.168.53.211:8888/grcv5/serverapi/restapi/other/v1/ecp/getToken
|
||||
pushContractUrl: http://10.168.53.211:8888/grcv5/serverapi/restapi/other/v1/ecp/pushContract
|
||||
approveQueryUrl: http://10.168.53.211:8888/grcv5/serverapi/restapi/other/v1/ecp/queryInfoByContractSysId
|
||||
archiveUrl: http://10.168.53.211:8888/grcv5/serverapi/restapi/other/v1/ecp/collectContractArchive
|
||||
approveViewBaseUrl: http://10.168.53.211:8888/wp/grcv5/contractView/G_1_viewContractApprove.htm
|
||||
dataCollection:
|
||||
systemKey: stamp-collection-test-key
|
||||
secretKey: stamp-collection-test-secret
|
||||
sysCode: stamp-end-demo
|
||||
tokenUrl: http://10.168.53.211:8888/grcv5/cj/rest/dataCenter/getToken
|
||||
uploadUrl: http://10.168.53.211:8888/grcv5/cj/rest/dataCenter/upload
|
||||
collectOppositesUrl: http://10.168.53.211:8888/grcv5/cj/rest/dataCenter/collectOpposites
|
||||
collectZtbsUrl: http://10.168.53.211:8888/grcv5/cj/rest/dataCenter/collectZtbs
|
||||
collectContractUrl: http://10.168.53.211:8888/grcv5/cj/rest/dataCenter/collectContract
|
||||
collectPlanFeedbackUrl: http://10.168.53.211:8888/grcv5/cj/rest/dataCenter/collectPlanFeedback
|
||||
collectContractCloseUrl: http://10.168.53.211:8888/grcv5/cj/rest/dataCenter/collectContractClose
|
||||
collectContractArchiveUrl: http://10.168.53.211:8888/grcv5/cj/rest/dataCenter/collectContractArchive
|
||||
queryApproveInfoUrl: http://10.168.53.211:8888/grcv5/cj/rest/dataCenter/queryApproveInfo
|
||||
approveViewBaseUrl: http://10.168.53.211:8888/grcv5/wp/contractView/G_1_viewContractApprove.htm
|
||||
|
||||
logging:
|
||||
level:
|
||||
com.nbport.zgwl.mapper: debug
|
||||
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper
|
||||
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.nbport.zgwl.mapper.StudentMapper">
|
||||
|
||||
<select id="queryList" resultType="java.util.Map">
|
||||
select
|
||||
id,
|
||||
student_no as studentNo,
|
||||
student_name as studentName,
|
||||
gender,
|
||||
age,
|
||||
phone,
|
||||
address,
|
||||
create_dt as createDt,
|
||||
update_dt as updateDt,
|
||||
create_by as createBy,
|
||||
update_by as updateBy
|
||||
from BIZ_STUDENT
|
||||
<where>
|
||||
<if test="query.studentNo != null and query.studentNo != ''">
|
||||
and student_no like CONCAT(CONCAT('%', #{query.studentNo}), '%')
|
||||
</if>
|
||||
<if test="query.studentName != null and query.studentName != ''">
|
||||
and student_name like CONCAT(CONCAT('%', #{query.studentName}), '%')
|
||||
</if>
|
||||
<if test="query.gender != null and query.gender != ''">
|
||||
and gender = #{query.gender}
|
||||
</if>
|
||||
</where>
|
||||
<choose>
|
||||
<when test="query.sorter != null and query.sorter.field == 'studentNo'">
|
||||
order by student_no
|
||||
<choose>
|
||||
<when test="query.sorter.order == 'desc'">desc</when>
|
||||
<otherwise>asc</otherwise>
|
||||
</choose>
|
||||
</when>
|
||||
<when test="query.sorter != null and query.sorter.field == 'studentName'">
|
||||
order by student_name
|
||||
<choose>
|
||||
<when test="query.sorter.order == 'desc'">desc</when>
|
||||
<otherwise>asc</otherwise>
|
||||
</choose>
|
||||
</when>
|
||||
<when test="query.sorter != null and query.sorter.field == 'age'">
|
||||
order by age
|
||||
<choose>
|
||||
<when test="query.sorter.order == 'desc'">desc</when>
|
||||
<otherwise>asc</otherwise>
|
||||
</choose>
|
||||
</when>
|
||||
<otherwise>
|
||||
order by update_dt desc, create_dt desc
|
||||
</otherwise>
|
||||
</choose>
|
||||
</select>
|
||||
</mapper>
|
||||
@@ -0,0 +1,131 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.nbport.zgwl.manifest.mapper.ContractTemplateMapper">
|
||||
|
||||
<select id="selectTemplateSeqNextVal" resultType="java.lang.Long">
|
||||
select SEQ_CONTRACT_TEMPLATE_MANAGE.NEXTVAL from dual
|
||||
</select>
|
||||
|
||||
<resultMap id="ContractTemplateResult" type="com.nbport.zgwl.manifest.dto.ContractTemplateDto">
|
||||
<id property="id" column="id"/>
|
||||
<result property="templateCode" column="template_code"/>
|
||||
<result property="templateName" column="template_name"/>
|
||||
<result property="source" column="source"/>
|
||||
<result property="contractType" column="contract_type"/>
|
||||
<result property="selfPartyRole" column="self_party_role"/>
|
||||
<result property="version" column="version"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="variableCount" column="variable_count"/>
|
||||
<result property="description" column="description"/>
|
||||
<result property="usageTip" column="usage_tip"/>
|
||||
<result property="templateFileName" column="template_file_name"/>
|
||||
<result property="templateFilePath" column="template_file_path"/>
|
||||
<result property="publishOrgIdsJson" column="publish_org_ids_json"/>
|
||||
<result property="publishOrgNamesJson" column="publish_org_names_json"/>
|
||||
<result property="variableMappingsJson" column="variable_mappings_json"/>
|
||||
<result property="createBy" column="create_by"/>
|
||||
<result property="createdTime" column="created_time"/>
|
||||
<result property="updatedBy" column="updated_by"/>
|
||||
<result property="updatedTime" column="updated_time"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectTemplateColumns">
|
||||
select id, template_code, template_name, source, contract_type, self_party_role,
|
||||
version, status, variable_count, description, usage_tip,
|
||||
template_file_name, template_file_path,
|
||||
publish_org_ids_json, publish_org_names_json, variable_mappings_json,
|
||||
create_by, created_time, updated_by, updated_time, del_flag
|
||||
from contract_template_manage
|
||||
</sql>
|
||||
|
||||
<select id="selectTemplatePage" resultMap="ContractTemplateResult">
|
||||
<include refid="selectTemplateColumns"/>
|
||||
<where>
|
||||
del_flag = '0'
|
||||
<if test="query.templateName != null and query.templateName != ''">
|
||||
and template_name like CONCAT(CONCAT('%', #{query.templateName}), '%')
|
||||
</if>
|
||||
<if test="query.contractType != null and query.contractType != ''">
|
||||
and contract_type = #{query.contractType}
|
||||
</if>
|
||||
<if test="query.source != null and query.source != ''">
|
||||
and source = #{query.source}
|
||||
</if>
|
||||
<if test="query.status != null and query.status != ''">
|
||||
and status = #{query.status}
|
||||
</if>
|
||||
</where>
|
||||
order by updated_time desc, id desc
|
||||
</select>
|
||||
|
||||
<select id="selectPublishedTemplates" resultMap="ContractTemplateResult">
|
||||
<include refid="selectTemplateColumns"/>
|
||||
where del_flag = '0'
|
||||
and status = 'published'
|
||||
order by updated_time desc, id desc
|
||||
</select>
|
||||
|
||||
<select id="selectTemplateById" resultMap="ContractTemplateResult">
|
||||
<include refid="selectTemplateColumns"/>
|
||||
where id = #{id} and del_flag = '0'
|
||||
</select>
|
||||
|
||||
<insert id="insertTemplate" parameterType="com.nbport.zgwl.manifest.dto.ContractTemplateDto">
|
||||
insert into contract_template_manage
|
||||
(
|
||||
id, template_code, template_name, source, contract_type, self_party_role,
|
||||
version, status, variable_count, description, usage_tip,
|
||||
template_file_name, template_file_path,
|
||||
publish_org_ids_json, publish_org_names_json, variable_mappings_json,
|
||||
create_by, created_time, updated_by, updated_time, del_flag
|
||||
)
|
||||
values
|
||||
(
|
||||
#{id}, #{templateCode}, #{templateName}, #{source}, #{contractType}, #{selfPartyRole},
|
||||
#{version}, #{status}, #{variableCount}, #{description}, #{usageTip},
|
||||
#{templateFileName}, #{templateFilePath},
|
||||
#{publishOrgIdsJson}, #{publishOrgNamesJson}, #{variableMappingsJson},
|
||||
#{createBy}, #{createdTime}, #{updatedBy}, #{updatedTime}, #{delFlag}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="updateTemplate" parameterType="com.nbport.zgwl.manifest.dto.ContractTemplateDto">
|
||||
update contract_template_manage
|
||||
<trim prefix="set" suffixOverrides=",">
|
||||
template_name = #{templateName},
|
||||
source = #{source},
|
||||
contract_type = #{contractType},
|
||||
self_party_role = #{selfPartyRole},
|
||||
version = #{version},
|
||||
status = #{status},
|
||||
variable_count = #{variableCount},
|
||||
description = #{description},
|
||||
usage_tip = #{usageTip},
|
||||
template_file_name = #{templateFileName},
|
||||
template_file_path = #{templateFilePath},
|
||||
publish_org_ids_json = #{publishOrgIdsJson},
|
||||
publish_org_names_json = #{publishOrgNamesJson},
|
||||
variable_mappings_json = #{variableMappingsJson},
|
||||
updated_by = #{updatedBy},
|
||||
updated_time = #{updatedTime},
|
||||
</trim>
|
||||
where id = #{id} and del_flag = '0'
|
||||
</update>
|
||||
|
||||
<update id="updateTemplateStatus">
|
||||
update contract_template_manage
|
||||
set status = #{status},
|
||||
updated_by = #{updateBy},
|
||||
updated_time = #{updateTime}
|
||||
where id = #{id} and del_flag = '0'
|
||||
</update>
|
||||
|
||||
<update id="deleteTemplateById">
|
||||
update contract_template_manage
|
||||
set del_flag = #{delFlag},
|
||||
updated_by = #{updateBy},
|
||||
updated_time = #{updateTime}
|
||||
where id = #{id} and del_flag = '0'
|
||||
</update>
|
||||
</mapper>
|
||||
@@ -0,0 +1,238 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="com.nbport.zgwl.partner.mapper.PartnerManageMapper">
|
||||
|
||||
<select id="selectPartnerSeqNextVal" resultType="java.lang.Long">
|
||||
select SEQ_ILDM_FEE_CUSTOMER_INFO.NEXTVAL from dual
|
||||
</select>
|
||||
|
||||
<select id="selectPartnerContactSeqNextVal" resultType="java.lang.Long">
|
||||
select SEQ_SEAL_PARTNER_CONTACT.NEXTVAL from dual
|
||||
</select>
|
||||
|
||||
<resultMap id="PartnerManageResult" type="com.nbport.zgwl.partner.dto.PartnerManageDto">
|
||||
<id property="customerSysid" column="CUSTOMER_SYSID"/>
|
||||
<result property="customerNameC" column="CUSTOMER_NAME_C"/>
|
||||
<result property="customerTaxno" column="CUSTOMER_TAXNO"/>
|
||||
<result property="customerRegaddr" column="CUSTOMER_REGADDR"/>
|
||||
<result property="emailAddress" column="EMAIL_ADDRESS"/>
|
||||
<result property="oppositeId" column="OPPOSITE_ID"/>
|
||||
<result property="oppositeCharacter" column="OPPOSITE_CHARACTER"/>
|
||||
<result property="gatFlag" column="GAT_FLAG"/>
|
||||
<result property="groupFlag" column="GROUP_FLAG"/>
|
||||
<result property="country" column="COUNTRY"/>
|
||||
<result property="countryName" column="COUNTRY_NAME"/>
|
||||
<result property="legalPersonName" column="LEGAL_PERSON_NAME"/>
|
||||
<result property="certificateType" column="CERTIFICATE_TYPE"/>
|
||||
<result property="certificateNum" column="CERTIFICATE_NUM"/>
|
||||
<result property="tinCode" column="TIN_CODE"/>
|
||||
<result property="registeredCapital" column="REGISTERED_CAPITAL"/>
|
||||
<result property="regCapital" column="REG_CAPITAL"/>
|
||||
<result property="oppositeCode" column="OPPOSITE_CODE"/>
|
||||
<result property="oppositeStatus" column="OPPOSITE_STATUS"/>
|
||||
<result property="isSgat" column="IS_SGAT"/>
|
||||
<result property="isJtn" column="IS_JTN"/>
|
||||
<result property="natureOfEnterpriseOrg" column="NATURE_OF_ENTERPRISE_ORG"/>
|
||||
<result property="natureOfEnterpriseOrgLev" column="NATURE_OF_ENTERPRISE_ORG_LEV"/>
|
||||
<result property="relativeType" column="RELATIVE_TYPE"/>
|
||||
<result property="isDeleted" column="IS_DELETED"/>
|
||||
<result property="comments" column="COMMENTS"/>
|
||||
<result property="remark" column="REMARK"/>
|
||||
<result property="createBy" column="CREATE_BY"/>
|
||||
<result property="createTime" column="CREATE_TIME"/>
|
||||
<result property="updateBy" column="UPDATE_BY"/>
|
||||
<result property="updateTime" column="UPDATE_TIME"/>
|
||||
<result property="syncStatus" column="sync_status"/>
|
||||
<result property="syncTime" column="sync_time"/>
|
||||
<result property="syncMessage" column="sync_message"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap id="PartnerContactResult" type="com.nbport.zgwl.partner.dto.PartnerContactDto">
|
||||
<id property="id" column="id"/>
|
||||
<result property="partnerRecordId" column="partner_record_id"/>
|
||||
<result property="contactName" column="contact_name"/>
|
||||
<result property="contactPhone" column="contact_phone"/>
|
||||
<result property="postalAddress" column="postal_address"/>
|
||||
<result property="email" column="email"/>
|
||||
<result property="sortOrder" column="sort_order"/>
|
||||
<result property="delFlag" column="del_flag"/>
|
||||
<result property="remark" column="remark"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="selectPartnerColumns">
|
||||
select CUSTOMER_SYSID, CUSTOMER_NAME_C, CUSTOMER_TAXNO, CUSTOMER_REGADDR,
|
||||
EMAIL_ADDRESS, OPPOSITE_ID, OPPOSITE_CHARACTER, GAT_FLAG, GROUP_FLAG,
|
||||
COUNTRY, COUNTRY_NAME, LEGAL_PERSON_NAME, CERTIFICATE_TYPE,
|
||||
CERTIFICATE_NUM, TIN_CODE, REGISTERED_CAPITAL, REG_CAPITAL,
|
||||
OPPOSITE_CODE, OPPOSITE_STATUS, IS_SGAT, IS_JTN,
|
||||
NATURE_OF_ENTERPRISE_ORG, NATURE_OF_ENTERPRISE_ORG_LEV, RELATIVE_TYPE,
|
||||
IS_DELETED, COMMENTS, REMARK, CREATE_BY, CREATE_TIME,
|
||||
UPDATE_BY, UPDATE_TIME, sync_status, sync_time, sync_message
|
||||
from ILDM_FEE_CUSTOMER_INFO
|
||||
</sql>
|
||||
|
||||
<select id="selectPartnerPage" resultMap="PartnerManageResult">
|
||||
<include refid="selectPartnerColumns"/>
|
||||
<where>
|
||||
IS_DELETED = 'N'
|
||||
<if test="query.customerNameC != null and query.customerNameC != ''">
|
||||
and CUSTOMER_NAME_C like CONCAT(CONCAT('%', #{query.customerNameC}), '%')
|
||||
</if>
|
||||
<if test="query.relativeType != null and query.relativeType != ''">
|
||||
and RELATIVE_TYPE = #{query.relativeType}
|
||||
</if>
|
||||
<if test="query.oppositeCharacter != null and query.oppositeCharacter != ''">
|
||||
and OPPOSITE_CHARACTER = #{query.oppositeCharacter}
|
||||
</if>
|
||||
<if test="query.groupFlag != null and query.groupFlag != ''">
|
||||
and GROUP_FLAG = #{query.groupFlag}
|
||||
</if>
|
||||
<if test="query.syncStatus != null and query.syncStatus != ''">
|
||||
and sync_status = #{query.syncStatus}
|
||||
</if>
|
||||
</where>
|
||||
order by CREATE_TIME desc, CUSTOMER_SYSID desc
|
||||
</select>
|
||||
|
||||
<select id="selectPartnerById" resultMap="PartnerManageResult">
|
||||
<include refid="selectPartnerColumns"/>
|
||||
where CUSTOMER_SYSID = #{customerSysid}
|
||||
and IS_DELETED = 'N'
|
||||
</select>
|
||||
|
||||
<insert id="insertPartner" parameterType="com.nbport.zgwl.partner.dto.PartnerManageDto">
|
||||
insert into ILDM_FEE_CUSTOMER_INFO
|
||||
(
|
||||
CUSTOMER_SYSID, CUSTOMER_NAME_C, CUSTOMER_TAXNO, CUSTOMER_REGADDR, EMAIL_ADDRESS,
|
||||
OPPOSITE_ID, OPPOSITE_CHARACTER, GAT_FLAG, GROUP_FLAG, COUNTRY,
|
||||
COUNTRY_NAME, LEGAL_PERSON_NAME, CERTIFICATE_TYPE, CERTIFICATE_NUM,
|
||||
TIN_CODE, REGISTERED_CAPITAL, REG_CAPITAL, OPPOSITE_CODE,
|
||||
OPPOSITE_STATUS, IS_SGAT, IS_JTN, NATURE_OF_ENTERPRISE_ORG,
|
||||
NATURE_OF_ENTERPRISE_ORG_LEV, RELATIVE_TYPE, IS_DELETED, COMMENTS,
|
||||
REMARK, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME,
|
||||
sync_status, sync_time, sync_message
|
||||
)
|
||||
values
|
||||
(
|
||||
#{customerSysid}, #{customerNameC}, #{customerTaxno}, #{customerRegaddr}, #{emailAddress},
|
||||
#{oppositeId}, #{oppositeCharacter}, #{gatFlag}, #{groupFlag}, #{country},
|
||||
#{countryName}, #{legalPersonName}, #{certificateType}, #{certificateNum},
|
||||
#{tinCode}, #{registeredCapital}, #{regCapital}, #{oppositeCode},
|
||||
#{oppositeStatus}, #{isSgat}, #{isJtn}, #{natureOfEnterpriseOrg},
|
||||
#{natureOfEnterpriseOrgLev}, #{relativeType}, #{isDeleted}, #{comments},
|
||||
#{remark}, #{createBy}, #{createTime}, #{updateBy}, #{updateTime},
|
||||
#{syncStatus}, #{syncTime}, #{syncMessage}
|
||||
)
|
||||
</insert>
|
||||
|
||||
<update id="updatePartner" parameterType="com.nbport.zgwl.partner.dto.PartnerManageDto">
|
||||
update ILDM_FEE_CUSTOMER_INFO
|
||||
<trim prefix="set" suffixOverrides=",">
|
||||
CUSTOMER_NAME_C = #{customerNameC},
|
||||
CUSTOMER_TAXNO = #{customerTaxno},
|
||||
CUSTOMER_REGADDR = #{customerRegaddr},
|
||||
EMAIL_ADDRESS = #{emailAddress},
|
||||
OPPOSITE_CHARACTER = #{oppositeCharacter},
|
||||
GAT_FLAG = #{gatFlag},
|
||||
GROUP_FLAG = #{groupFlag},
|
||||
COUNTRY = #{country},
|
||||
COUNTRY_NAME = #{countryName},
|
||||
LEGAL_PERSON_NAME = #{legalPersonName},
|
||||
CERTIFICATE_TYPE = #{certificateType},
|
||||
CERTIFICATE_NUM = #{certificateNum},
|
||||
TIN_CODE = #{tinCode},
|
||||
REGISTERED_CAPITAL = #{registeredCapital},
|
||||
REG_CAPITAL = #{regCapital},
|
||||
OPPOSITE_CODE = #{oppositeCode},
|
||||
OPPOSITE_STATUS = #{oppositeStatus},
|
||||
IS_SGAT = #{isSgat},
|
||||
IS_JTN = #{isJtn},
|
||||
NATURE_OF_ENTERPRISE_ORG = #{natureOfEnterpriseOrg},
|
||||
NATURE_OF_ENTERPRISE_ORG_LEV = #{natureOfEnterpriseOrgLev},
|
||||
RELATIVE_TYPE = #{relativeType},
|
||||
COMMENTS = #{comments},
|
||||
REMARK = #{remark},
|
||||
UPDATE_BY = #{updateBy},
|
||||
UPDATE_TIME = #{updateTime},
|
||||
sync_status = #{syncStatus},
|
||||
sync_time = #{syncTime},
|
||||
sync_message = #{syncMessage},
|
||||
</trim>
|
||||
where CUSTOMER_SYSID = #{customerSysid}
|
||||
and IS_DELETED = 'N'
|
||||
</update>
|
||||
|
||||
<update id="deletePartnerByIds">
|
||||
update ILDM_FEE_CUSTOMER_INFO
|
||||
set IS_DELETED = #{isDeleted},
|
||||
UPDATE_BY = #{updateBy},
|
||||
UPDATE_TIME = #{updateTime}
|
||||
where CUSTOMER_SYSID in
|
||||
<foreach collection="customerSysids" item="customerSysid" open="(" separator="," close=")">
|
||||
#{customerSysid}
|
||||
</foreach>
|
||||
</update>
|
||||
|
||||
<select id="selectPartnerContactsByPartnerIds" resultMap="PartnerContactResult">
|
||||
select id, partner_record_id, contact_name, contact_phone, postal_address,
|
||||
email, sort_order, del_flag, remark
|
||||
from SEAL_PARTNER_CONTACT
|
||||
where del_flag = '0'
|
||||
and partner_record_id in
|
||||
<foreach collection="partnerRecordIds" item="partnerRecordId" open="(" separator="," close=")">
|
||||
#{partnerRecordId}
|
||||
</foreach>
|
||||
order by partner_record_id asc, sort_order asc, id asc
|
||||
</select>
|
||||
|
||||
<update id="markPartnerContactsDeletedByPartnerId">
|
||||
update SEAL_PARTNER_CONTACT
|
||||
set del_flag = #{delFlag},
|
||||
update_by = #{updateBy},
|
||||
update_time = #{updateTime}
|
||||
where partner_record_id = #{partnerRecordId}
|
||||
and del_flag = '0'
|
||||
</update>
|
||||
|
||||
<update id="markPartnerContactsDeletedByPartnerIds">
|
||||
update SEAL_PARTNER_CONTACT
|
||||
set del_flag = #{delFlag},
|
||||
update_by = #{updateBy},
|
||||
update_time = #{updateTime}
|
||||
where partner_record_id in
|
||||
<foreach collection="partnerRecordIds" item="partnerRecordId" open="(" separator="," close=")">
|
||||
#{partnerRecordId}
|
||||
</foreach>
|
||||
and del_flag = '0'
|
||||
</update>
|
||||
|
||||
<insert id="batchInsertPartnerContacts">
|
||||
INSERT ALL
|
||||
<foreach collection="contacts" item="item">
|
||||
INTO SEAL_PARTNER_CONTACT
|
||||
(
|
||||
id, partner_record_id, contact_name, contact_phone, postal_address, email,
|
||||
sort_order, del_flag, create_by, create_time, update_by, update_time, remark
|
||||
)
|
||||
VALUES
|
||||
(
|
||||
#{item.id}, #{item.partnerRecordId}, #{item.contactName}, #{item.contactPhone},
|
||||
#{item.postalAddress}, #{item.email}, #{item.sortOrder},
|
||||
#{delFlag}, #{createBy}, #{createTime}, #{updateBy}, #{updateTime}, #{item.remark}
|
||||
)
|
||||
</foreach>
|
||||
SELECT 1 FROM DUAL
|
||||
</insert>
|
||||
|
||||
<update id="updatePartnerSyncInfo">
|
||||
update ILDM_FEE_CUSTOMER_INFO
|
||||
set OPPOSITE_ID = #{oppositeId},
|
||||
sync_status = #{syncStatus},
|
||||
sync_time = #{syncTime},
|
||||
sync_message = #{syncMessage},
|
||||
UPDATE_BY = #{updateBy},
|
||||
UPDATE_TIME = #{updateTime}
|
||||
where CUSTOMER_SYSID = #{customerSysid}
|
||||
and IS_DELETED = 'N'
|
||||
</update>
|
||||
</mapper>
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
After Width: | Height: | Size: 548 KiB |
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,25 @@
|
||||
CREATE DATABASE IF NOT EXISTS zgwl_end DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
|
||||
|
||||
USE zgwl_end;
|
||||
|
||||
DROP TABLE IF EXISTS BIZ_STUDENT;
|
||||
CREATE TABLE BIZ_STUDENT (
|
||||
id BIGINT NOT NULL COMMENT '主键ID',
|
||||
student_no VARCHAR(64) NOT NULL COMMENT '学号',
|
||||
student_name VARCHAR(64) NOT NULL COMMENT '姓名',
|
||||
gender VARCHAR(16) NOT NULL COMMENT '性别',
|
||||
age INT NOT NULL COMMENT '年龄',
|
||||
phone VARCHAR(32) DEFAULT NULL COMMENT '手机号',
|
||||
address VARCHAR(255) DEFAULT NULL COMMENT '地址',
|
||||
create_dt DATETIME DEFAULT NULL COMMENT '创建时间',
|
||||
update_dt DATETIME DEFAULT NULL COMMENT '更新时间',
|
||||
create_by VARCHAR(64) DEFAULT NULL COMMENT '创建人',
|
||||
update_by VARCHAR(64) DEFAULT NULL COMMENT '更新人',
|
||||
PRIMARY KEY (id),
|
||||
UNIQUE KEY uk_student_no (student_no)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='学生表';
|
||||
|
||||
INSERT INTO BIZ_STUDENT (id, student_no, student_name, gender, age, phone, address, create_dt, update_dt, create_by, update_by) VALUES
|
||||
(1925800000000000001, 'S2024001', '张三', '男', 20, '13800001111', '宁波市鄞州区', NOW(), NOW(), 'system', 'system'),
|
||||
(1925800000000000002, 'S2024002', '李四', '女', 21, '13800002222', '宁波市北仑区', NOW(), NOW(), 'system', 'system'),
|
||||
(1925800000000000003, 'S2024003', '王五', '男', 22, '13800003333', '宁波市镇海区', NOW(), NOW(), 'system', 'system');
|
||||
@@ -0,0 +1,68 @@
|
||||
-- =============================================
|
||||
-- Oracle version for zgwl_end.sql
|
||||
-- Execute with: sqlplus developer/dev123@localhost/XEPDB1 @zgwl_end_oracle.sql
|
||||
-- =============================================
|
||||
|
||||
WHENEVER SQLERROR EXIT SQL.SQLCODE;
|
||||
|
||||
BEGIN
|
||||
EXECUTE IMMEDIATE 'DROP TABLE BIZ_STUDENT';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLCODE != -942 THEN
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
/
|
||||
|
||||
BEGIN
|
||||
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_BIZ_STUDENT';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLCODE != -2289 THEN
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
/
|
||||
|
||||
CREATE TABLE BIZ_STUDENT (
|
||||
ID NUMBER(19) NOT NULL,
|
||||
STUDENT_NO VARCHAR2(64 CHAR) NOT NULL,
|
||||
STUDENT_NAME VARCHAR2(64 CHAR) NOT NULL,
|
||||
GENDER VARCHAR2(16 CHAR) NOT NULL,
|
||||
AGE NUMBER(10) NOT NULL,
|
||||
PHONE VARCHAR2(32 CHAR),
|
||||
ADDRESS VARCHAR2(255 CHAR),
|
||||
CREATE_DT TIMESTAMP(6),
|
||||
UPDATE_DT TIMESTAMP(6),
|
||||
CREATE_BY VARCHAR2(64 CHAR),
|
||||
UPDATE_BY VARCHAR2(64 CHAR),
|
||||
CONSTRAINT PK_BIZ_STUDENT PRIMARY KEY (ID),
|
||||
CONSTRAINT UK_BIZ_STUDENT_NO UNIQUE (STUDENT_NO)
|
||||
);
|
||||
|
||||
COMMENT ON TABLE BIZ_STUDENT IS '学生表';
|
||||
COMMENT ON COLUMN BIZ_STUDENT.ID IS '主键ID';
|
||||
COMMENT ON COLUMN BIZ_STUDENT.STUDENT_NO IS '学号';
|
||||
COMMENT ON COLUMN BIZ_STUDENT.STUDENT_NAME IS '姓名';
|
||||
COMMENT ON COLUMN BIZ_STUDENT.GENDER IS '性别';
|
||||
COMMENT ON COLUMN BIZ_STUDENT.AGE IS '年龄';
|
||||
COMMENT ON COLUMN BIZ_STUDENT.PHONE IS '手机号';
|
||||
COMMENT ON COLUMN BIZ_STUDENT.ADDRESS IS '地址';
|
||||
COMMENT ON COLUMN BIZ_STUDENT.CREATE_DT IS '创建时间';
|
||||
COMMENT ON COLUMN BIZ_STUDENT.UPDATE_DT IS '更新时间';
|
||||
COMMENT ON COLUMN BIZ_STUDENT.CREATE_BY IS '创建人';
|
||||
COMMENT ON COLUMN BIZ_STUDENT.UPDATE_BY IS '更新人';
|
||||
|
||||
INSERT INTO BIZ_STUDENT (ID, STUDENT_NO, STUDENT_NAME, GENDER, AGE, PHONE, ADDRESS, CREATE_DT, UPDATE_DT, CREATE_BY, UPDATE_BY) VALUES
|
||||
(1925800000000000001, 'S2024001', '张三', '男', 20, '13800001111', '宁波市鄞州区', SYSTIMESTAMP, SYSTIMESTAMP, 'system', 'system');
|
||||
INSERT INTO BIZ_STUDENT (ID, STUDENT_NO, STUDENT_NAME, GENDER, AGE, PHONE, ADDRESS, CREATE_DT, UPDATE_DT, CREATE_BY, UPDATE_BY) VALUES
|
||||
(1925800000000000002, 'S2024002', '李四', '女', 21, '13800002222', '宁波市北仑区', SYSTIMESTAMP, SYSTIMESTAMP, 'system', 'system');
|
||||
INSERT INTO BIZ_STUDENT (ID, STUDENT_NO, STUDENT_NAME, GENDER, AGE, PHONE, ADDRESS, CREATE_DT, UPDATE_DT, CREATE_BY, UPDATE_BY) VALUES
|
||||
(1925800000000000003, 'S2024003', '王五', '男', 22, '13800003333', '宁波市镇海区', SYSTIMESTAMP, SYSTIMESTAMP, 'system', 'system');
|
||||
|
||||
CREATE SEQUENCE SEQ_BIZ_STUDENT
|
||||
START WITH 1925800000000000004
|
||||
INCREMENT BY 1
|
||||
NOCACHE
|
||||
NOCYCLE;
|
||||
@@ -0,0 +1,37 @@
|
||||
-- =============================================
|
||||
-- 合同模板管理模块数据表
|
||||
-- 执行方式:在 MySQL 中直接执行本文件
|
||||
-- =============================================
|
||||
|
||||
USE zgwl_end;
|
||||
|
||||
DROP TABLE IF EXISTS `contract_template_manage`;
|
||||
|
||||
CREATE TABLE `contract_template_manage` (
|
||||
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`template_code` VARCHAR(64) NOT NULL COMMENT '范本编号,后端自动生成',
|
||||
`template_name` VARCHAR(200) NOT NULL COMMENT '范本名称',
|
||||
`source` VARCHAR(32) NOT NULL COMMENT '范本类型:标准模板/推荐文本/示范文本/对方文本',
|
||||
`contract_type` VARCHAR(64) NOT NULL COMMENT '合同类型',
|
||||
`self_party_role` VARCHAR(16) NOT NULL COMMENT '我方地位:甲方/乙方/丙方',
|
||||
`version` VARCHAR(32) NOT NULL COMMENT '版本号',
|
||||
`status` VARCHAR(20) NOT NULL DEFAULT 'draft' COMMENT '状态:draft/published/disabled',
|
||||
`variable_count` INT NOT NULL DEFAULT 0 COMMENT '变量数量',
|
||||
`description` VARCHAR(1000) DEFAULT NULL COMMENT '范本描述',
|
||||
`usage_tip` VARCHAR(1000) DEFAULT NULL COMMENT '使用提示',
|
||||
`template_file_name` VARCHAR(255) NOT NULL COMMENT '模板文件名称',
|
||||
`template_file_path` VARCHAR(500) NOT NULL COMMENT '模板文件相对路径',
|
||||
`publish_org_ids_json` TEXT DEFAULT NULL COMMENT '发布范围 orgId JSON 数组',
|
||||
`publish_org_names_json` TEXT DEFAULT NULL COMMENT '发布范围 orgName JSON 数组',
|
||||
`variable_mappings_json` LONGTEXT DEFAULT NULL COMMENT '变量映射 JSON 数组',
|
||||
`create_by` VARCHAR(64) DEFAULT NULL COMMENT '创建人',
|
||||
`created_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`updated_by` VARCHAR(64) DEFAULT NULL COMMENT '更新人',
|
||||
`updated_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`del_flag` CHAR(1) NOT NULL DEFAULT '0' COMMENT '删除标记:0存在 2删除',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_template_code` (`template_code`),
|
||||
KEY `idx_template_name` (`template_name`),
|
||||
KEY `idx_contract_type` (`contract_type`),
|
||||
KEY `idx_status` (`status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='合同模板管理表';
|
||||
@@ -0,0 +1,85 @@
|
||||
-- =============================================
|
||||
-- Oracle version for zgwl_manifest_tables.sql
|
||||
-- Execute with: sqlplus developer/dev123@localhost/XEPDB1 @zgwl_manifest_tables_oracle.sql
|
||||
-- =============================================
|
||||
|
||||
WHENEVER SQLERROR EXIT SQL.SQLCODE;
|
||||
|
||||
BEGIN
|
||||
EXECUTE IMMEDIATE 'DROP TABLE CONTRACT_TEMPLATE_MANAGE';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLCODE != -942 THEN
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
/
|
||||
|
||||
BEGIN
|
||||
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_CONTRACT_TEMPLATE_MANAGE';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLCODE != -2289 THEN
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
/
|
||||
|
||||
CREATE TABLE CONTRACT_TEMPLATE_MANAGE (
|
||||
ID NUMBER(19) NOT NULL,
|
||||
TEMPLATE_CODE VARCHAR2(64 CHAR) NOT NULL,
|
||||
TEMPLATE_NAME VARCHAR2(200 CHAR) NOT NULL,
|
||||
SOURCE VARCHAR2(32 CHAR) NOT NULL,
|
||||
CONTRACT_TYPE VARCHAR2(64 CHAR) NOT NULL,
|
||||
SELF_PARTY_ROLE VARCHAR2(16 CHAR) NOT NULL,
|
||||
VERSION VARCHAR2(32 CHAR) NOT NULL,
|
||||
STATUS VARCHAR2(20 CHAR) DEFAULT 'draft' NOT NULL,
|
||||
VARIABLE_COUNT NUMBER(10) DEFAULT 0 NOT NULL,
|
||||
DESCRIPTION VARCHAR2(1000 CHAR),
|
||||
USAGE_TIP VARCHAR2(1000 CHAR),
|
||||
TEMPLATE_FILE_NAME VARCHAR2(255 CHAR) NOT NULL,
|
||||
TEMPLATE_FILE_PATH VARCHAR2(500 CHAR) NOT NULL,
|
||||
PUBLISH_ORG_IDS_JSON CLOB,
|
||||
PUBLISH_ORG_NAMES_JSON CLOB,
|
||||
VARIABLE_MAPPINGS_JSON CLOB,
|
||||
CREATE_BY VARCHAR2(64 CHAR),
|
||||
CREATED_TIME TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP,
|
||||
UPDATED_BY VARCHAR2(64 CHAR),
|
||||
UPDATED_TIME TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP,
|
||||
DEL_FLAG CHAR(1 CHAR) DEFAULT '0' NOT NULL,
|
||||
CONSTRAINT PK_CONTRACT_TEMPLATE_MANAGE PRIMARY KEY (ID),
|
||||
CONSTRAINT UK_TEMPLATE_CODE UNIQUE (TEMPLATE_CODE)
|
||||
);
|
||||
|
||||
CREATE INDEX IDX_TEMPLATE_NAME ON CONTRACT_TEMPLATE_MANAGE (TEMPLATE_NAME);
|
||||
CREATE INDEX IDX_CONTRACT_TYPE ON CONTRACT_TEMPLATE_MANAGE (CONTRACT_TYPE);
|
||||
CREATE INDEX IDX_STATUS ON CONTRACT_TEMPLATE_MANAGE (STATUS);
|
||||
|
||||
COMMENT ON TABLE CONTRACT_TEMPLATE_MANAGE IS '合同模板管理表';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.ID IS '主键ID';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.TEMPLATE_CODE IS '范本编号,后端自动生成';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.TEMPLATE_NAME IS '范本名称';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.SOURCE IS '范本类型:标准模板/推荐文本/示范文本/对方文本';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.CONTRACT_TYPE IS '合同类型';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.SELF_PARTY_ROLE IS '我方地位:甲方/乙方/丙方';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.VERSION IS '版本号';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.STATUS IS '状态:draft/published/disabled';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.VARIABLE_COUNT IS '变量数量';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.DESCRIPTION IS '范本描述';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.USAGE_TIP IS '使用提示';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.TEMPLATE_FILE_NAME IS '模板文件名称';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.TEMPLATE_FILE_PATH IS '模板文件相对路径';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.PUBLISH_ORG_IDS_JSON IS '发布范围 orgId JSON 数组';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.PUBLISH_ORG_NAMES_JSON IS '发布范围 orgName JSON 数组';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.VARIABLE_MAPPINGS_JSON IS '变量映射 JSON 数组';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.CREATE_BY IS '创建人';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.CREATED_TIME IS '创建时间';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.UPDATED_BY IS '更新人';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.UPDATED_TIME IS '更新时间';
|
||||
COMMENT ON COLUMN CONTRACT_TEMPLATE_MANAGE.DEL_FLAG IS '删除标记:0存在 2删除';
|
||||
|
||||
CREATE SEQUENCE SEQ_CONTRACT_TEMPLATE_MANAGE
|
||||
START WITH 1
|
||||
INCREMENT BY 1
|
||||
NOCACHE
|
||||
NOCYCLE;
|
||||
@@ -0,0 +1,137 @@
|
||||
-- =============================================
|
||||
-- 相对方管理模块数据表
|
||||
-- 执行方式:在 MySQL 中直接执行本文件
|
||||
-- =============================================
|
||||
|
||||
USE zgwl_end;
|
||||
|
||||
DROP TABLE IF EXISTS `seal_partner_contact`;
|
||||
DROP TABLE IF EXISTS `ILDM_FEE_CUSTOMER_INFO`;
|
||||
|
||||
CREATE TABLE `ILDM_FEE_CUSTOMER_INFO` (
|
||||
`CUSTOMER_SYSID` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '客户系统ID',
|
||||
`CUSTOMER_REGNO` VARCHAR(64) DEFAULT NULL COMMENT '客户注册号',
|
||||
`CUSTOMER_NO` VARCHAR(64) DEFAULT NULL COMMENT '客户编号',
|
||||
`CUSTOMER_NAME_C` VARCHAR(200) DEFAULT NULL COMMENT '公司全称',
|
||||
`CUSTOMER_NAME_EN` VARCHAR(200) DEFAULT NULL COMMENT '公司英文名称',
|
||||
`CUSTOMER_SHORT_NAME` VARCHAR(100) DEFAULT NULL COMMENT '公司简称',
|
||||
`CUSTOMER_SHORT_NAME_EN` VARCHAR(100) DEFAULT NULL COMMENT '公司英文简称',
|
||||
`CUSTOMER_TAXNO` VARCHAR(50) DEFAULT NULL COMMENT '统一社会信用代码',
|
||||
`CUSTOMER_ADDRESS` VARCHAR(200) DEFAULT NULL COMMENT '详细地址',
|
||||
`OFFICEPHONE` VARCHAR(20) DEFAULT NULL COMMENT '联系电话',
|
||||
`CUSTOMER_BANK` VARCHAR(100) DEFAULT NULL COMMENT '开户银行',
|
||||
`CUSTOMER_BANKACCOUNT` VARCHAR(50) DEFAULT NULL COMMENT '银行账户',
|
||||
`CUSTOMER_CHARACTER` VARCHAR(50) DEFAULT NULL COMMENT '客户性质',
|
||||
`CUSTOMER_REGADDR` VARCHAR(200) DEFAULT NULL COMMENT '注册地址',
|
||||
`CUSTOMER_REGDATE` DATE DEFAULT NULL COMMENT '注册日期',
|
||||
`CUSTOMER_NATURE` VARCHAR(50) DEFAULT NULL COMMENT '客户性质分类',
|
||||
`CUSTOMER_ZIP` VARCHAR(20) DEFAULT NULL COMMENT '邮编',
|
||||
`CUSTOMER_1_TYPEFLAG` VARCHAR(10) DEFAULT NULL COMMENT '客户类型标识1',
|
||||
`CUSTOMER_2_TYPEFLAG` VARCHAR(10) DEFAULT NULL COMMENT '客户类型标识2',
|
||||
`CUSTOMER_3_TYPEFLAG` VARCHAR(10) DEFAULT NULL COMMENT '客户类型标识3',
|
||||
`CUSTOMER_4_TYPEFLAG` VARCHAR(10) DEFAULT NULL COMMENT '客户类型标识4',
|
||||
`PLACE_TYPE` VARCHAR(10) DEFAULT NULL COMMENT '境内外',
|
||||
`ACTIVEFLAG` VARCHAR(10) DEFAULT NULL COMMENT '启用标识',
|
||||
`CUSTOMER_SYSID_HT` VARCHAR(64) DEFAULT NULL COMMENT '海铁系统客户ID',
|
||||
`DOWN_DATE` DATE DEFAULT NULL COMMENT '下载日期',
|
||||
`OPEN_FLAG` VARCHAR(10) DEFAULT NULL COMMENT '开户标识',
|
||||
`CREATE_BY` VARCHAR(64) DEFAULT NULL COMMENT '创建人',
|
||||
`CREATE_TIME` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`UPDATE_BY` VARCHAR(64) DEFAULT NULL COMMENT '更新人',
|
||||
`UPDATE_TIME` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`SYSTEM_TYPE` VARCHAR(20) DEFAULT NULL COMMENT '业务系统类型(ht:海铁联运系统;xg:箱管系统;qc:全程物流)',
|
||||
`REMARK` VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||
`ORG_ID` VARCHAR(64) DEFAULT NULL COMMENT '组织体系对应的公司编码',
|
||||
`EMAIL_ADDRESS` VARCHAR(100) DEFAULT NULL COMMENT '邮箱地址',
|
||||
`OPPOSITE_ID` VARCHAR(64) DEFAULT NULL COMMENT '法务系统相对方ID(唯一标识)',
|
||||
`OPPOSITE_CHARACTER` VARCHAR(10) DEFAULT NULL COMMENT '相对方性质分类(1:境内组织,2:境内个人,3:境外组织,4:境外个人)',
|
||||
`GAT_FLAG` VARCHAR(2) DEFAULT NULL COMMENT '是否涉港澳台标识(Y:是,N:否,法务业务分类用)',
|
||||
`GROUP_FLAG` VARCHAR(2) DEFAULT NULL COMMENT '是否集团内(Y:是,N:否,法务业务分类用)',
|
||||
`COUNTRY` VARCHAR(20) DEFAULT NULL COMMENT '国家编码',
|
||||
`COUNTRY_NAME` VARCHAR(50) DEFAULT NULL COMMENT '国家名称',
|
||||
`CITY` VARCHAR(50) DEFAULT NULL COMMENT '城市',
|
||||
`POSTCODE` VARCHAR(20) DEFAULT NULL COMMENT '邮编',
|
||||
`LEGAL_PERSON_ID` VARCHAR(64) DEFAULT NULL COMMENT '法定代表人或负责人ID',
|
||||
`LEGAL_PERSON_NAME` VARCHAR(50) DEFAULT NULL COMMENT '法定代表人或负责人姓名',
|
||||
`LEGAL_PERSON_ACCOUNT` VARCHAR(64) DEFAULT NULL COMMENT '法定代表人或负责人账户',
|
||||
`LEGAL_PERSON_CARD_ID` VARCHAR(100) DEFAULT NULL COMMENT '法定代表人身份证号(加密存储)',
|
||||
`WEBSITE` VARCHAR(200) DEFAULT NULL COMMENT '网站地址',
|
||||
`CERTIFICATE_TYPE` VARCHAR(20) DEFAULT NULL COMMENT '自然人证件类型(idCard:身份证,passport:护照,other:其他)',
|
||||
`CERTIFICATE_NUM` VARCHAR(100) DEFAULT NULL COMMENT '自然人证件号码(加密存储)',
|
||||
`TIN_CODE` VARCHAR(50) DEFAULT NULL COMMENT 'TIN码(税务识别号)',
|
||||
`ABROAD_CODE` VARCHAR(50) DEFAULT NULL COMMENT '境外公司活动证明编码',
|
||||
`REGISTERED_CAPITAL` DECIMAL(20,2) DEFAULT NULL COMMENT '注册资金(单位:元)',
|
||||
`REG_CAPITAL` VARCHAR(100) DEFAULT NULL COMMENT '注册资本(文本描述,如:1000万人民币)',
|
||||
`BUS_SCOPE` TEXT COMMENT '经营范围',
|
||||
`OPPOSITE_CODE` VARCHAR(64) DEFAULT NULL COMMENT '相对方编码(业务分类编码)',
|
||||
`OPPOSITE_STATUS` VARCHAR(20) DEFAULT 'EFFECTUAL' COMMENT '状态(EFFECTUAL:有效,INVALID:无效)',
|
||||
`IS_SGAT` VARCHAR(2) DEFAULT '0' COMMENT '是否SGAT(1:是,0:否)',
|
||||
`IS_JTN` VARCHAR(2) DEFAULT '0' COMMENT '是否JTN(1:是,0:否)',
|
||||
`NATURE_OF_ENTERPRISE_ORG` VARCHAR(10) DEFAULT NULL COMMENT '组织性质(ZY:政府,QY:企业,QT:其他组织)',
|
||||
`NATURE_OF_ENTERPRISE_ORG_LEV` VARCHAR(20) DEFAULT NULL COMMENT '组织性质子级(GNQY:国有企业,MYQY:民营企业,WZQY:外资企业,HZQY:合资企业,GYQZHKGQY:国有全资和控股企业,QT:其他)',
|
||||
`RELATIVE_TYPE` VARCHAR(30) DEFAULT NULL COMMENT '类型(client:客户,clientAndSup:客户及供应商,other:其他,Partner:合作伙伴,supplier:供应商)',
|
||||
`IS_DELETED` VARCHAR(2) DEFAULT 'N' COMMENT '法务系统删除标记(Y:是,N:否,逻辑删除)',
|
||||
`COMMENTS` VARCHAR(500) DEFAULT NULL COMMENT '备注【法务】',
|
||||
`sync_status` VARCHAR(20) NOT NULL DEFAULT 'unsynced' COMMENT '同步状态:unsynced/synced/failed',
|
||||
`sync_time` DATETIME DEFAULT NULL COMMENT '最后同步时间',
|
||||
`sync_message` VARCHAR(500) DEFAULT NULL COMMENT '同步说明',
|
||||
PRIMARY KEY (`CUSTOMER_SYSID`),
|
||||
KEY `idx_customer_no` (`CUSTOMER_NO`),
|
||||
KEY `idx_opposite_id` (`OPPOSITE_ID`),
|
||||
KEY `idx_customer_taxno` (`CUSTOMER_TAXNO`),
|
||||
KEY `idx_system_type` (`SYSTEM_TYPE`),
|
||||
KEY `idx_create_time` (`CREATE_TIME`),
|
||||
KEY `idx_sync_status` (`sync_status`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='客户/相对方信息表';
|
||||
|
||||
CREATE TABLE `seal_partner_contact` (
|
||||
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',
|
||||
`partner_record_id` BIGINT(20) NOT NULL COMMENT '关联相对方主表 CUSTOMER_SYSID',
|
||||
`contact_name` VARCHAR(50) NOT NULL COMMENT '联系人姓名',
|
||||
`contact_phone` VARCHAR(20) NOT NULL COMMENT '联系电话',
|
||||
`postal_address` VARCHAR(100) NOT NULL COMMENT '通讯地址',
|
||||
`email` VARCHAR(50) NOT NULL COMMENT '电子邮箱',
|
||||
`sort_order` INT(11) NOT NULL DEFAULT 1 COMMENT '排序号',
|
||||
`del_flag` CHAR(1) NOT NULL DEFAULT '0' COMMENT '删除标记:0存在 2删除',
|
||||
`create_by` VARCHAR(64) DEFAULT NULL COMMENT '创建人',
|
||||
`create_time` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
`update_by` VARCHAR(64) DEFAULT NULL COMMENT '更新人',
|
||||
`update_time` DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
|
||||
`remark` VARCHAR(500) DEFAULT NULL COMMENT '备注',
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `idx_partner_record_id` (`partner_record_id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='相对方联系人表';
|
||||
|
||||
INSERT INTO `ILDM_FEE_CUSTOMER_INFO`
|
||||
(`CUSTOMER_SYSID`, `CUSTOMER_NAME_C`, `CUSTOMER_TAXNO`, `CUSTOMER_REGADDR`, `CREATE_BY`, `CREATE_TIME`, `UPDATE_BY`, `UPDATE_TIME`,
|
||||
`EMAIL_ADDRESS`, `OPPOSITE_ID`, `OPPOSITE_CHARACTER`, `GAT_FLAG`, `GROUP_FLAG`, `COUNTRY`, `COUNTRY_NAME`,
|
||||
`LEGAL_PERSON_NAME`, `REG_CAPITAL`, `OPPOSITE_CODE`, `OPPOSITE_STATUS`, `IS_SGAT`, `IS_JTN`,
|
||||
`NATURE_OF_ENTERPRISE_ORG`, `NATURE_OF_ENTERPRISE_ORG_LEV`, `RELATIVE_TYPE`, `IS_DELETED`,
|
||||
`COMMENTS`, `sync_status`, `sync_time`, `sync_message`)
|
||||
VALUES
|
||||
(1, '宁波港船务货运代理有限公司', '91330201MA2ABCDE9X', '宁波市北仑区明州西路188号', 'local_test', '2026-05-20 09:12:33', 'local_test', '2026-05-20 09:15:10',
|
||||
'zhoujingli@example.com', 'JT-10256', '1', 'N', 'N', NULL, NULL,
|
||||
'李四', '5000万元', 'OPP-202605210001', 'EFFECTUAL', '0', '0',
|
||||
'QY', 'GNQY', 'supplier', 'N',
|
||||
'本地初始化测试数据', 'synced', '2026-05-20 09:15:10', '已按数据采集接口规范同步到法务系统'),
|
||||
(2, '王小明', NULL, NULL, 'local_test', '2026-05-20 14:20:05', 'local_test', '2026-05-20 14:20:05',
|
||||
NULL, NULL, '2', 'N', 'N', NULL, NULL,
|
||||
NULL, NULL, 'OPP-202605210002', 'EFFECTUAL', '0', '0',
|
||||
'QT', NULL, 'client', 'N',
|
||||
'个人类型测试数据', 'unsynced', NULL, '新增后尚未同步'),
|
||||
(3, 'Ocean Energy Pte. Ltd.', NULL, '88 Harbour Street, London', 'local_test', '2026-05-18 11:08:22', 'local_test', '2026-05-18 11:10:40',
|
||||
'alice.brown@ocean-energy.com', 'JT-10888', '3', 'N', 'N', 'GJ826', '英国',
|
||||
NULL, 'USD 2,000,000', 'OPP-202605210003', 'EFFECTUAL', '0', '0',
|
||||
'QY', 'WZQY', 'Partner', 'N',
|
||||
'境外组织测试数据', 'failed', '2026-05-18 11:10:40', '法务系统返回:注册地址长度超限,请修正后重试');
|
||||
|
||||
INSERT INTO `seal_partner_contact`
|
||||
(`id`, `partner_record_id`, `contact_name`, `contact_phone`, `postal_address`, `email`,
|
||||
`sort_order`, `del_flag`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`)
|
||||
VALUES
|
||||
(1, 1, '周经理', '15757460062', '宁波市北仑区明州西路188号A座', 'zhoujingli@example.com',
|
||||
1, '0', 'local_test', '2026-05-20 09:12:33', 'local_test', '2026-05-20 09:12:33', '主联系人'),
|
||||
(2, 3, 'Alice Brown', '+44-20-8899-0001', '88 Harbour Street, London', 'alice.brown@ocean-energy.com',
|
||||
1, '0', 'local_test', '2026-05-18 11:08:22', 'local_test', '2026-05-18 11:08:22', '海外主联系人'),
|
||||
(3, 3, 'Tom Lee', '+44-20-8899-0002', '88 Harbour Street, London', 'tom.lee@ocean-energy.com',
|
||||
2, '0', 'local_test', '2026-05-18 11:08:22', 'local_test', '2026-05-18 11:08:22', '备用联系人');
|
||||
@@ -0,0 +1,264 @@
|
||||
-- =============================================
|
||||
-- Oracle version for zgwl_partner_tables.sql
|
||||
-- Execute with: sqlplus developer/dev123@localhost/XEPDB1 @zgwl_partner_tables_oracle.sql
|
||||
-- =============================================
|
||||
|
||||
WHENEVER SQLERROR EXIT SQL.SQLCODE;
|
||||
|
||||
BEGIN
|
||||
EXECUTE IMMEDIATE 'DROP TABLE SEAL_PARTNER_CONTACT';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLCODE != -942 THEN
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
/
|
||||
|
||||
BEGIN
|
||||
EXECUTE IMMEDIATE 'DROP TABLE ILDM_FEE_CUSTOMER_INFO';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLCODE != -942 THEN
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
/
|
||||
|
||||
BEGIN
|
||||
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_SEAL_PARTNER_CONTACT';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLCODE != -2289 THEN
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
/
|
||||
|
||||
BEGIN
|
||||
EXECUTE IMMEDIATE 'DROP SEQUENCE SEQ_ILDM_FEE_CUSTOMER_INFO';
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
IF SQLCODE != -2289 THEN
|
||||
RAISE;
|
||||
END IF;
|
||||
END;
|
||||
/
|
||||
|
||||
CREATE TABLE ILDM_FEE_CUSTOMER_INFO (
|
||||
CUSTOMER_SYSID NUMBER(19) NOT NULL,
|
||||
CUSTOMER_REGNO VARCHAR2(64 CHAR),
|
||||
CUSTOMER_NO VARCHAR2(64 CHAR),
|
||||
CUSTOMER_NAME_C VARCHAR2(200 CHAR),
|
||||
CUSTOMER_NAME_EN VARCHAR2(200 CHAR),
|
||||
CUSTOMER_SHORT_NAME VARCHAR2(100 CHAR),
|
||||
CUSTOMER_SHORT_NAME_EN VARCHAR2(100 CHAR),
|
||||
CUSTOMER_TAXNO VARCHAR2(50 CHAR),
|
||||
CUSTOMER_ADDRESS VARCHAR2(200 CHAR),
|
||||
OFFICEPHONE VARCHAR2(20 CHAR),
|
||||
CUSTOMER_BANK VARCHAR2(100 CHAR),
|
||||
CUSTOMER_BANKACCOUNT VARCHAR2(50 CHAR),
|
||||
CUSTOMER_CHARACTER VARCHAR2(50 CHAR),
|
||||
CUSTOMER_REGADDR VARCHAR2(200 CHAR),
|
||||
CUSTOMER_REGDATE DATE,
|
||||
CUSTOMER_NATURE VARCHAR2(50 CHAR),
|
||||
CUSTOMER_ZIP VARCHAR2(20 CHAR),
|
||||
CUSTOMER_1_TYPEFLAG VARCHAR2(10 CHAR),
|
||||
CUSTOMER_2_TYPEFLAG VARCHAR2(10 CHAR),
|
||||
CUSTOMER_3_TYPEFLAG VARCHAR2(10 CHAR),
|
||||
CUSTOMER_4_TYPEFLAG VARCHAR2(10 CHAR),
|
||||
PLACE_TYPE VARCHAR2(10 CHAR),
|
||||
ACTIVEFLAG VARCHAR2(10 CHAR),
|
||||
CUSTOMER_SYSID_HT VARCHAR2(64 CHAR),
|
||||
DOWN_DATE DATE,
|
||||
OPEN_FLAG VARCHAR2(10 CHAR),
|
||||
CREATE_BY VARCHAR2(64 CHAR),
|
||||
CREATE_TIME TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP,
|
||||
UPDATE_BY VARCHAR2(64 CHAR),
|
||||
UPDATE_TIME TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP,
|
||||
SYSTEM_TYPE VARCHAR2(20 CHAR),
|
||||
REMARK VARCHAR2(500 CHAR),
|
||||
ORG_ID VARCHAR2(64 CHAR),
|
||||
EMAIL_ADDRESS VARCHAR2(100 CHAR),
|
||||
OPPOSITE_ID VARCHAR2(64 CHAR),
|
||||
OPPOSITE_CHARACTER VARCHAR2(10 CHAR),
|
||||
GAT_FLAG VARCHAR2(2 CHAR),
|
||||
GROUP_FLAG VARCHAR2(2 CHAR),
|
||||
COUNTRY VARCHAR2(20 CHAR),
|
||||
COUNTRY_NAME VARCHAR2(50 CHAR),
|
||||
CITY VARCHAR2(50 CHAR),
|
||||
POSTCODE VARCHAR2(20 CHAR),
|
||||
LEGAL_PERSON_ID VARCHAR2(64 CHAR),
|
||||
LEGAL_PERSON_NAME VARCHAR2(50 CHAR),
|
||||
LEGAL_PERSON_ACCOUNT VARCHAR2(64 CHAR),
|
||||
LEGAL_PERSON_CARD_ID VARCHAR2(100 CHAR),
|
||||
WEBSITE VARCHAR2(200 CHAR),
|
||||
CERTIFICATE_TYPE VARCHAR2(20 CHAR),
|
||||
CERTIFICATE_NUM VARCHAR2(100 CHAR),
|
||||
TIN_CODE VARCHAR2(50 CHAR),
|
||||
ABROAD_CODE VARCHAR2(50 CHAR),
|
||||
REGISTERED_CAPITAL NUMBER(20, 2),
|
||||
REG_CAPITAL VARCHAR2(100 CHAR),
|
||||
BUS_SCOPE CLOB,
|
||||
OPPOSITE_CODE VARCHAR2(64 CHAR),
|
||||
OPPOSITE_STATUS VARCHAR2(20 CHAR) DEFAULT 'EFFECTUAL',
|
||||
IS_SGAT VARCHAR2(2 CHAR) DEFAULT '0',
|
||||
IS_JTN VARCHAR2(2 CHAR) DEFAULT '0',
|
||||
NATURE_OF_ENTERPRISE_ORG VARCHAR2(10 CHAR),
|
||||
NATURE_OF_ENTERPRISE_ORG_LEV VARCHAR2(20 CHAR),
|
||||
RELATIVE_TYPE VARCHAR2(30 CHAR),
|
||||
IS_DELETED VARCHAR2(2 CHAR) DEFAULT 'N',
|
||||
COMMENTS VARCHAR2(500 CHAR),
|
||||
SYNC_STATUS VARCHAR2(20 CHAR) DEFAULT 'unsynced' NOT NULL,
|
||||
SYNC_TIME TIMESTAMP(6),
|
||||
SYNC_MESSAGE VARCHAR2(500 CHAR),
|
||||
CONSTRAINT PK_ILDM_FEE_CUSTOMER_INFO PRIMARY KEY (CUSTOMER_SYSID)
|
||||
);
|
||||
|
||||
CREATE INDEX IDX_CUSTOMER_NO ON ILDM_FEE_CUSTOMER_INFO (CUSTOMER_NO);
|
||||
CREATE INDEX IDX_OPPOSITE_ID ON ILDM_FEE_CUSTOMER_INFO (OPPOSITE_ID);
|
||||
CREATE INDEX IDX_CUSTOMER_TAXNO ON ILDM_FEE_CUSTOMER_INFO (CUSTOMER_TAXNO);
|
||||
CREATE INDEX IDX_SYSTEM_TYPE ON ILDM_FEE_CUSTOMER_INFO (SYSTEM_TYPE);
|
||||
CREATE INDEX IDX_CREATE_TIME ON ILDM_FEE_CUSTOMER_INFO (CREATE_TIME);
|
||||
CREATE INDEX IDX_SYNC_STATUS ON ILDM_FEE_CUSTOMER_INFO (SYNC_STATUS);
|
||||
|
||||
COMMENT ON TABLE ILDM_FEE_CUSTOMER_INFO IS '客户/相对方信息表';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.CUSTOMER_SYSID IS '客户系统ID';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.CUSTOMER_NAME_C IS '公司全称';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.CUSTOMER_TAXNO IS '统一社会信用代码';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.CUSTOMER_REGADDR IS '注册地址';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.EMAIL_ADDRESS IS '邮箱地址';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.OPPOSITE_ID IS '法务系统相对方ID(唯一标识)';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.OPPOSITE_CHARACTER IS '相对方性质分类';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.GAT_FLAG IS '是否涉港澳台标识';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.GROUP_FLAG IS '是否集团内';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.COUNTRY IS '国家编码';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.COUNTRY_NAME IS '国家名称';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.LEGAL_PERSON_NAME IS '法定代表人或负责人姓名';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.CERTIFICATE_TYPE IS '自然人证件类型';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.CERTIFICATE_NUM IS '自然人证件号码';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.TIN_CODE IS 'TIN码(税务识别号)';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.REGISTERED_CAPITAL IS '注册资金(单位:元)';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.REG_CAPITAL IS '注册资本';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.OPPOSITE_CODE IS '相对方编码';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.OPPOSITE_STATUS IS '状态(EFFECTUAL:有效,INVALID:无效)';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.IS_SGAT IS '是否SGAT(1:是,0:否)';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.IS_JTN IS '是否JTN(1:是,0:否)';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.NATURE_OF_ENTERPRISE_ORG IS '组织性质';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.NATURE_OF_ENTERPRISE_ORG_LEV IS '组织性质子级';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.RELATIVE_TYPE IS '类型';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.IS_DELETED IS '法务系统删除标记';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.COMMENTS IS '备注【法务】';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.SYNC_STATUS IS '同步状态';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.SYNC_TIME IS '最后同步时间';
|
||||
COMMENT ON COLUMN ILDM_FEE_CUSTOMER_INFO.SYNC_MESSAGE IS '同步说明';
|
||||
|
||||
CREATE TABLE SEAL_PARTNER_CONTACT (
|
||||
ID NUMBER(19) NOT NULL,
|
||||
PARTNER_RECORD_ID NUMBER(19) NOT NULL,
|
||||
CONTACT_NAME VARCHAR2(50 CHAR) NOT NULL,
|
||||
CONTACT_PHONE VARCHAR2(20 CHAR) NOT NULL,
|
||||
POSTAL_ADDRESS VARCHAR2(100 CHAR) NOT NULL,
|
||||
EMAIL VARCHAR2(50 CHAR) NOT NULL,
|
||||
SORT_ORDER NUMBER(10) DEFAULT 1 NOT NULL,
|
||||
DEL_FLAG CHAR(1 CHAR) DEFAULT '0' NOT NULL,
|
||||
CREATE_BY VARCHAR2(64 CHAR),
|
||||
CREATE_TIME TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP,
|
||||
UPDATE_BY VARCHAR2(64 CHAR),
|
||||
UPDATE_TIME TIMESTAMP(6) DEFAULT CURRENT_TIMESTAMP,
|
||||
REMARK VARCHAR2(500 CHAR),
|
||||
CONSTRAINT PK_SEAL_PARTNER_CONTACT PRIMARY KEY (ID)
|
||||
);
|
||||
|
||||
CREATE INDEX IDX_PARTNER_RECORD_ID ON SEAL_PARTNER_CONTACT (PARTNER_RECORD_ID);
|
||||
|
||||
COMMENT ON TABLE SEAL_PARTNER_CONTACT IS '相对方联系人表';
|
||||
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.ID IS '主键ID';
|
||||
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.PARTNER_RECORD_ID IS '关联相对方主表 CUSTOMER_SYSID';
|
||||
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.CONTACT_NAME IS '联系人姓名';
|
||||
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.CONTACT_PHONE IS '联系电话';
|
||||
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.POSTAL_ADDRESS IS '通讯地址';
|
||||
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.EMAIL IS '电子邮箱';
|
||||
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.SORT_ORDER IS '排序号';
|
||||
COMMENT ON COLUMN SEAL_PARTNER_CONTACT.DEL_FLAG IS '删除标记:0存在 2删除';
|
||||
|
||||
INSERT INTO ILDM_FEE_CUSTOMER_INFO
|
||||
(CUSTOMER_SYSID, CUSTOMER_NAME_C, CUSTOMER_TAXNO, CUSTOMER_REGADDR, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME,
|
||||
EMAIL_ADDRESS, OPPOSITE_ID, OPPOSITE_CHARACTER, GAT_FLAG, GROUP_FLAG, COUNTRY, COUNTRY_NAME,
|
||||
LEGAL_PERSON_NAME, REG_CAPITAL, OPPOSITE_CODE, OPPOSITE_STATUS, IS_SGAT, IS_JTN,
|
||||
NATURE_OF_ENTERPRISE_ORG, NATURE_OF_ENTERPRISE_ORG_LEV, RELATIVE_TYPE, IS_DELETED,
|
||||
COMMENTS, SYNC_STATUS, SYNC_TIME, SYNC_MESSAGE)
|
||||
VALUES
|
||||
(1, '宁波港船务货运代理有限公司', '91330201MA2ABCDE9X', '宁波市北仑区明州西路188号', 'local_test',
|
||||
TO_TIMESTAMP('2026-05-20 09:12:33', 'YYYY-MM-DD HH24:MI:SS'),
|
||||
'local_test', TO_TIMESTAMP('2026-05-20 09:15:10', 'YYYY-MM-DD HH24:MI:SS'),
|
||||
'zhoujingli@example.com', 'JT-10256', '1', 'N', 'N', NULL, NULL,
|
||||
'李四', '5000万元', 'OPP-202605210001', 'EFFECTUAL', '0', '0',
|
||||
'QY', 'GNQY', 'supplier', 'N',
|
||||
'本地初始化测试数据', 'synced', TO_TIMESTAMP('2026-05-20 09:15:10', 'YYYY-MM-DD HH24:MI:SS'), '已按数据采集接口规范同步到法务系统');
|
||||
|
||||
INSERT INTO ILDM_FEE_CUSTOMER_INFO
|
||||
(CUSTOMER_SYSID, CUSTOMER_NAME_C, CUSTOMER_TAXNO, CUSTOMER_REGADDR, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME,
|
||||
EMAIL_ADDRESS, OPPOSITE_ID, OPPOSITE_CHARACTER, GAT_FLAG, GROUP_FLAG, COUNTRY, COUNTRY_NAME,
|
||||
LEGAL_PERSON_NAME, REG_CAPITAL, OPPOSITE_CODE, OPPOSITE_STATUS, IS_SGAT, IS_JTN,
|
||||
NATURE_OF_ENTERPRISE_ORG, NATURE_OF_ENTERPRISE_ORG_LEV, RELATIVE_TYPE, IS_DELETED,
|
||||
COMMENTS, SYNC_STATUS, SYNC_TIME, SYNC_MESSAGE)
|
||||
VALUES
|
||||
(2, '王小明', NULL, NULL, 'local_test',
|
||||
TO_TIMESTAMP('2026-05-20 14:20:05', 'YYYY-MM-DD HH24:MI:SS'),
|
||||
'local_test', TO_TIMESTAMP('2026-05-20 14:20:05', 'YYYY-MM-DD HH24:MI:SS'),
|
||||
NULL, NULL, '2', 'N', 'N', NULL, NULL,
|
||||
NULL, NULL, 'OPP-202605210002', 'EFFECTUAL', '0', '0',
|
||||
'QT', NULL, 'client', 'N',
|
||||
'个人类型测试数据', 'unsynced', NULL, '新增后尚未同步');
|
||||
|
||||
INSERT INTO ILDM_FEE_CUSTOMER_INFO
|
||||
(CUSTOMER_SYSID, CUSTOMER_NAME_C, CUSTOMER_TAXNO, CUSTOMER_REGADDR, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME,
|
||||
EMAIL_ADDRESS, OPPOSITE_ID, OPPOSITE_CHARACTER, GAT_FLAG, GROUP_FLAG, COUNTRY, COUNTRY_NAME,
|
||||
LEGAL_PERSON_NAME, REG_CAPITAL, OPPOSITE_CODE, OPPOSITE_STATUS, IS_SGAT, IS_JTN,
|
||||
NATURE_OF_ENTERPRISE_ORG, NATURE_OF_ENTERPRISE_ORG_LEV, RELATIVE_TYPE, IS_DELETED,
|
||||
COMMENTS, SYNC_STATUS, SYNC_TIME, SYNC_MESSAGE)
|
||||
VALUES
|
||||
(3, 'Ocean Energy Pte. Ltd.', NULL, '88 Harbour Street, London', 'local_test',
|
||||
TO_TIMESTAMP('2026-05-18 11:08:22', 'YYYY-MM-DD HH24:MI:SS'),
|
||||
'local_test', TO_TIMESTAMP('2026-05-18 11:10:40', 'YYYY-MM-DD HH24:MI:SS'),
|
||||
'alice.brown@ocean-energy.com', 'JT-10888', '3', 'N', 'N', 'GJ826', '英国',
|
||||
NULL, 'USD 2,000,000', 'OPP-202605210003', 'EFFECTUAL', '0', '0',
|
||||
'QY', 'WZQY', 'Partner', 'N',
|
||||
'境外组织测试数据', 'failed', TO_TIMESTAMP('2026-05-18 11:10:40', 'YYYY-MM-DD HH24:MI:SS'), '法务系统返回:注册地址长度超限,请修正后重试');
|
||||
|
||||
INSERT INTO SEAL_PARTNER_CONTACT
|
||||
(ID, PARTNER_RECORD_ID, CONTACT_NAME, CONTACT_PHONE, POSTAL_ADDRESS, EMAIL,
|
||||
SORT_ORDER, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK)
|
||||
VALUES
|
||||
(1, 1, '周经理', '15757460062', '宁波市北仑区明州西路188号A座', 'zhoujingli@example.com',
|
||||
1, '0', 'local_test', TO_TIMESTAMP('2026-05-20 09:12:33', 'YYYY-MM-DD HH24:MI:SS'),
|
||||
'local_test', TO_TIMESTAMP('2026-05-20 09:12:33', 'YYYY-MM-DD HH24:MI:SS'), '主联系人');
|
||||
|
||||
INSERT INTO SEAL_PARTNER_CONTACT
|
||||
(ID, PARTNER_RECORD_ID, CONTACT_NAME, CONTACT_PHONE, POSTAL_ADDRESS, EMAIL,
|
||||
SORT_ORDER, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK)
|
||||
VALUES
|
||||
(2, 3, 'Alice Brown', '+44-20-8899-0001', '88 Harbour Street, London', 'alice.brown@ocean-energy.com',
|
||||
1, '0', 'local_test', TO_TIMESTAMP('2026-05-18 11:08:22', 'YYYY-MM-DD HH24:MI:SS'),
|
||||
'local_test', TO_TIMESTAMP('2026-05-18 11:08:22', 'YYYY-MM-DD HH24:MI:SS'), '海外主联系人');
|
||||
|
||||
INSERT INTO SEAL_PARTNER_CONTACT
|
||||
(ID, PARTNER_RECORD_ID, CONTACT_NAME, CONTACT_PHONE, POSTAL_ADDRESS, EMAIL,
|
||||
SORT_ORDER, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK)
|
||||
VALUES
|
||||
(3, 3, 'Tom Lee', '+44-20-8899-0002', '88 Harbour Street, London', 'tom.lee@ocean-energy.com',
|
||||
2, '0', 'local_test', TO_TIMESTAMP('2026-05-18 11:08:22', 'YYYY-MM-DD HH24:MI:SS'),
|
||||
'local_test', TO_TIMESTAMP('2026-05-18 11:08:22', 'YYYY-MM-DD HH24:MI:SS'), '备用联系人');
|
||||
|
||||
CREATE SEQUENCE SEQ_ILDM_FEE_CUSTOMER_INFO
|
||||
START WITH 4
|
||||
INCREMENT BY 1
|
||||
NOCACHE
|
||||
NOCYCLE;
|
||||
|
||||
CREATE SEQUENCE SEQ_SEAL_PARTNER_CONTACT
|
||||
START WITH 4
|
||||
INCREMENT BY 1
|
||||
NOCACHE
|
||||
NOCYCLE;
|
||||
Reference in New Issue
Block a user