细节修改
This commit is contained in:
@@ -23,7 +23,9 @@ 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.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -354,6 +356,23 @@ public class ContractLaunchController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 上传法务水印合同文件。
|
||||
*
|
||||
* 当法务审批回调未返回带水印的合同文件时,允许用户手动上传。
|
||||
* 上传后的文件路径替换 contractTextFilePath,供后续在线签订使用。
|
||||
*
|
||||
* 请求方式:multipart/form-data
|
||||
* 参数:file(MultipartFile)
|
||||
*
|
||||
* 对应前端功能:签署准备页面的"上传带水印合同"区域
|
||||
*/
|
||||
@PostMapping("/{id}/watermark/upload")
|
||||
public R<ContractLaunchDto> uploadWatermarkFile(@PathVariable("id") Long id,
|
||||
@RequestParam("file") MultipartFile file) {
|
||||
return R.success(contractLaunchService.uploadWatermarkFile(id, file));
|
||||
}
|
||||
|
||||
/**
|
||||
* 合同归档。
|
||||
*
|
||||
|
||||
@@ -185,13 +185,13 @@ public class ContractLaunchDto implements Serializable {
|
||||
private String pushUrl;
|
||||
|
||||
/** 是否重大合同(1:是, 0:否) */
|
||||
private Integer isMajorContract;
|
||||
private String isMajorContract;
|
||||
|
||||
/** 是否公开招标(1:是, 0:否) */
|
||||
private Integer isOpenBidding;
|
||||
private String isOpenBidding;
|
||||
|
||||
/** 是否列入当年预算(1:是, 0:否) */
|
||||
private Integer isYearBudget;
|
||||
private String isYearBudget;
|
||||
|
||||
/** 是否共享(1:是, 0:否) */
|
||||
private String isShare;
|
||||
|
||||
@@ -9,6 +9,7 @@ import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackDto;
|
||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchLawCallbackSampleDto;
|
||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchQueryDto;
|
||||
import com.nbport.zgwl.contractlaunch.dto.ContractLaunchSealDto;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@@ -65,6 +66,9 @@ public interface ContractLaunchService {
|
||||
/** 相对方确认已签署完成 */
|
||||
Map<String, Object> confirmCounterparty(Long id, Long partyId);
|
||||
|
||||
/** 上传法务水印合同文件(当审批回调未带回水印文件时,手动上传代替) */
|
||||
ContractLaunchDto uploadWatermarkFile(Long id, MultipartFile file);
|
||||
|
||||
/** 模拟合同采集(调用数据采集 collectContract 接口,TODO:替换为真实调用) */
|
||||
ContractLaunchDto mockCollect(Long id);
|
||||
|
||||
|
||||
+63
-39
@@ -41,10 +41,12 @@ import com.nbport.zgwl.service.LocalFileService;
|
||||
import com.nbport.zgwl.entity.SysUserEntity;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
import com.nbport.zgwl.utils.AdminSecurityManage;
|
||||
import com.nbport.zgwl.utils.FileStorageUtils;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
@@ -499,7 +501,8 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
contract.setSealContractId(sealDto.getSealContractId() == null || sealDto.getSealContractId().isBlank() ? contract.getSealContractId() : sealDto.getSealContractId());
|
||||
contract.setSealContractStatus(sealDto.getSealContractStatus());
|
||||
contract.setSignedFileName(sealDto.getSignedFileName());
|
||||
contract.setSignedFilePath(resolveSignedFilePath(sealDto));
|
||||
String signedFilePath = resolveSignedFilePath(sealDto);
|
||||
contract.setSignedFilePath(signedFilePath);
|
||||
contract.setSignedFileUrl(sealDto.getSignedFileUrl() != null && !sealDto.getSignedFileUrl().isBlank()
|
||||
? sealDto.getSignedFileUrl()
|
||||
: (isExternalUrl(sealDto.getSignedFilePath()) ? sealDto.getSignedFilePath() : null));
|
||||
@@ -514,7 +517,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
contract.setUpdateBy(currentUser.getUsername());
|
||||
contract.setUpdateTime(completedTime);
|
||||
contractLaunchMapper.updateContract(contract);
|
||||
saveSignedFile(id, sealDto, currentUser.getUsername());
|
||||
saveSignedFile(id, signedFilePath, sealDto, currentUser.getUsername());
|
||||
// 区分在线签署完成和线下签署上传两种场景记录日志
|
||||
boolean isOfflineUpload = sealDto.getSignedOfflineReason() != null && !sealDto.getSignedOfflineReason().isBlank();
|
||||
if (isOfflineUpload) {
|
||||
@@ -556,6 +559,29 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
* dataCollectionPushService.collectContract(requestDTO);
|
||||
*/
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public ContractLaunchDto uploadWatermarkFile(Long id, MultipartFile file) {
|
||||
ContractLaunchDto contract = getDetail(id);
|
||||
if (!ContractLaunchConstants.STATUS_PENDING_SIGN.equals(contract.getStatus())) {
|
||||
throw new ServiceException("仅待签署状态的合同可上传水印文件");
|
||||
}
|
||||
String relativePath = localFileService.upload(file);
|
||||
contract.setContractTextFileName(file.getOriginalFilename());
|
||||
contract.setContractTextFilePath(relativePath);
|
||||
String suffix = FileStorageUtils.getFileSuffix(file.getOriginalFilename());
|
||||
contract.setContractTextFileType(suffix.startsWith(".") ? suffix.substring(1) : suffix);
|
||||
contract.setContractTextFileSize(file.getSize());
|
||||
contract.setUpdateBy(adminSecurityManage.getUser().getUsername());
|
||||
contract.setUpdateTime(LocalDateTime.now());
|
||||
contractLaunchMapper.updateContract(contract);
|
||||
insertLog(id, ContractLaunchConstants.ACTION_SEAL_UPLOAD,
|
||||
"上传水印合同文件", ContractLaunchConstants.ACTION_STATUS_SUCCESS,
|
||||
"手动上传带法务水印的合同文件: " + file.getOriginalFilename(), null,
|
||||
adminSecurityManage.getUser());
|
||||
return getDetail(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存采集信息(用印+签订信息)。
|
||||
*
|
||||
@@ -1171,8 +1197,8 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
}
|
||||
|
||||
/** 保存签署文件到 file 子表(先删旧签署文件,再插入新的) */
|
||||
private void saveSignedFile(Long contractId, ContractLaunchSealDto sealDto, String operator) {
|
||||
if (sealDto.getSignedFilePath() == null || sealDto.getSignedFilePath().isBlank()) {
|
||||
private void saveSignedFile(Long contractId, String signedFilePath, ContractLaunchSealDto sealDto, String operator) {
|
||||
if (signedFilePath == null || signedFilePath.isBlank()) {
|
||||
return;
|
||||
}
|
||||
contractLaunchMapper.deleteFileByContractIdAndCategory(contractId, ContractLaunchConstants.FILE_CATEGORY_SIGNED, operator);
|
||||
@@ -1183,7 +1209,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
fileDto.setFileName(sealDto.getSignedFileName() == null || sealDto.getSignedFileName().isBlank()
|
||||
? "已签署合同文件"
|
||||
: sealDto.getSignedFileName());
|
||||
fileDto.setFilePath(sealDto.getSignedFilePath());
|
||||
fileDto.setFilePath(signedFilePath);
|
||||
fileDto.setFileType(sealDto.getSignedFileType());
|
||||
fileDto.setFileSize(sealDto.getSignedFileSize());
|
||||
fileDto.setSortOrder(1);
|
||||
@@ -1243,10 +1269,10 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
contract.setIsElectron("1");
|
||||
}
|
||||
if (contract.getIsOpenBidding() == null) {
|
||||
contract.setIsOpenBidding(0);
|
||||
contract.setIsOpenBidding("0");
|
||||
}
|
||||
if (contract.getIsYearBudget() == null) {
|
||||
contract.setIsYearBudget(0);
|
||||
contract.setIsYearBudget("0");
|
||||
}
|
||||
if (contract.getPaymentDirection() == null || contract.getPaymentDirection().isBlank()) {
|
||||
contract.setPaymentDirection("0");
|
||||
@@ -1490,7 +1516,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
if (!isSingleAgreement(contract) && !hasCounterparty) {
|
||||
throw new ServiceException("至少维护一个相对方");
|
||||
}
|
||||
if (Integer.valueOf(1).equals(contract.getIsOpenBidding())
|
||||
if ("1".equals(contract.getIsOpenBidding())
|
||||
&& (contract.getBiddingNo() == null || contract.getBiddingNo().isBlank())) {
|
||||
throw new ServiceException("公开招标时必须填写关联招标号");
|
||||
}
|
||||
@@ -1561,8 +1587,8 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
payload.put("mainContractCode", contract.getMainContractCode());
|
||||
payload.put("periodExplain", contract.getPeriodExplain());
|
||||
payload.put("valuationMode", contract.getValuationMode());
|
||||
payload.put("isMajorContract", contract.getIsMajorContract() == null ? 0 : contract.getIsMajorContract());
|
||||
payload.put("sealType", contract.getSealType());
|
||||
payload.put("isMajorContract", contract.getIsMajorContract() == null ? "0" : contract.getIsMajorContract());
|
||||
payload.put("sealType", "YWZ".equals(contract.getSealType()) ? "QT" : contract.getSealType());
|
||||
payload.put("creatorPhone", contract.getCreatorPhone());
|
||||
// dateType 仅在固定期限时传递,无固定期限不传
|
||||
if ("0".equals(contract.getContractPeriodType())) {
|
||||
@@ -1587,9 +1613,9 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
payload.put("contractPeriod", contract.getContractPeriodType());
|
||||
payload.put("contractAmount", contract.getContractAmount());
|
||||
payload.put("isSgat", contract.getIsSgat());
|
||||
payload.put("isOpenBidding", contract.getIsOpenBidding() == null ? 0 : contract.getIsOpenBidding());
|
||||
payload.put("isOpenBidding", contract.getIsOpenBidding() == null ? "0" : contract.getIsOpenBidding());
|
||||
payload.put("pushUrl", contract.getPushUrl());
|
||||
payload.put("isYearBudget", contract.getIsYearBudget() == null ? 0 : contract.getIsYearBudget());
|
||||
payload.put("isYearBudget", contract.getIsYearBudget() == null ? "0" : contract.getIsYearBudget());
|
||||
payload.put("isShare", contract.getIsShare());
|
||||
payload.put("assistDepartmentName", contract.getAssistDepartmentName());
|
||||
payload.put("contractNature", contract.getContractNature());
|
||||
@@ -1679,18 +1705,18 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
payload.put("c_qyztGAT", contract.getIsSgat());
|
||||
payload.put("c_qyztSW", contract.getContractNature());
|
||||
payload.put("c_executor", contract.getExecutorAccount());
|
||||
payload.put("c_openBidding", contract.getIsOpenBidding() == null ? "0" : String.valueOf(contract.getIsOpenBidding()));
|
||||
payload.put("c_openBidding", contract.getIsOpenBidding() == null ? "0" : contract.getIsOpenBidding());
|
||||
// 关联招标号:公开招标选是时必填
|
||||
if (Integer.valueOf(1).equals(contract.getIsOpenBidding()) && contract.getBiddingNo() != null) {
|
||||
if ("1".equals(contract.getIsOpenBidding()) && contract.getBiddingNo() != null) {
|
||||
payload.put("c_biddingNo", contract.getBiddingNo());
|
||||
} else {
|
||||
payload.put("c_biddingNo", null);
|
||||
}
|
||||
// c_currentBudget 仅在收支方向为付款(1)时传,与 V3.0 文档一致
|
||||
if ("1".equals(contract.getPaymentDirection())) {
|
||||
payload.put("c_currentBudget", contract.getIsYearBudget() == null ? "0" : String.valueOf(contract.getIsYearBudget()));
|
||||
payload.put("c_currentBudget", contract.getIsYearBudget() == null ? "0" : contract.getIsYearBudget());
|
||||
}
|
||||
payload.put("c_major", contract.getIsMajorContract() == null ? "0" : String.valueOf(contract.getIsMajorContract()));
|
||||
payload.put("c_major", contract.getIsMajorContract() == null ? "0" : contract.getIsMajorContract());
|
||||
payload.put("c_signMethod", contract.getSealType());
|
||||
// payload.put("c_authAttachs", buildCollectionFilePayloadList(contract, ContractLaunchConstants.FILE_CATEGORY_AUTH));
|
||||
payload.put("c_creator", contract.getInitiator());
|
||||
@@ -1787,6 +1813,10 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
*/
|
||||
private void applyLawWatermarkFile(ContractLaunchDto contract, ContractLaunchLawCallbackFileDto watermarkFile) {
|
||||
if (watermarkFile == null || watermarkFile.getFilePath() == null || watermarkFile.getFilePath().isBlank()) {
|
||||
contract.setContractTextFileName(null);
|
||||
contract.setContractTextFilePath(null);
|
||||
contract.setContractTextFileType(null);
|
||||
contract.setContractTextFileSize(null);
|
||||
return;
|
||||
}
|
||||
contract.setContractTextFileName(trim(watermarkFile.getFileName()));
|
||||
@@ -1911,7 +1941,7 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
log.info("签章文件为外部URL,先通过签章API获取新下载地址: {}", filePath);
|
||||
String token = sealTokenService.getAccessToken();
|
||||
// 通过签章API获取服务端可用的下载URL
|
||||
String freshUrl = fetchSealDownloadUrl(sealDto.getSealContractId(), token, filePath);
|
||||
String freshUrl = fetchSealDownloadUrl(sealDto.getSealContractId(), token);
|
||||
log.info("获取到签章下载地址: {}", freshUrl);
|
||||
String localPath = localFileService.downloadFromUrl(freshUrl, token);
|
||||
log.info("签章文件已下载到本地: {}", localPath);
|
||||
@@ -1923,30 +1953,24 @@ public class ContractLaunchServiceImpl implements ContractLaunchService {
|
||||
/**
|
||||
* 通过签章平台API获取下载URL(服务端IP绑定的新URL)
|
||||
*/
|
||||
private String fetchSealDownloadUrl(String sealContractId, String token, String fallbackUrl) {
|
||||
try {
|
||||
String apiUrl = sealConfig.getBaseUrl() + "/saas/api/contract/download";
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("contractId", sealContractId);
|
||||
String response = SealHttpClient.post(apiUrl, body.toJSONString(), token, "application/json");
|
||||
log.info("签章平台下载API响应: {}", response);
|
||||
JSONObject result = JSON.parseObject(response);
|
||||
if (result != null && result.getBooleanValue("isSuccess")) {
|
||||
Object dataObj = result.get("data");
|
||||
log.info("签章平台data类型: {}, 值: {}", dataObj != null ? dataObj.getClass().getSimpleName() : "null", dataObj);
|
||||
if (dataObj instanceof JSONObject) {
|
||||
String url = ((JSONObject) dataObj).getString("downloadUrl");
|
||||
if (url != null && !url.isBlank()) return url;
|
||||
} else if (dataObj instanceof String && !((String) dataObj).isBlank()) {
|
||||
return (String) dataObj;
|
||||
}
|
||||
} else {
|
||||
log.warn("签章平台下载API返回失败: {}", response);
|
||||
private String fetchSealDownloadUrl(String sealContractId, String token) {
|
||||
String apiUrl = sealConfig.getBaseUrl() + "/saas/api/contract/download";
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("contractId", sealContractId);
|
||||
String response = SealHttpClient.post(apiUrl, body.toJSONString(), token, "application/json");
|
||||
log.info("签章平台下载API响应: {}", response);
|
||||
JSONObject result = JSON.parseObject(response);
|
||||
if (result != null && result.getBooleanValue("isSuccess")) {
|
||||
Object dataObj = result.get("data");
|
||||
log.info("签章平台data类型: {}, 值: {}", dataObj != null ? dataObj.getClass().getSimpleName() : "null", dataObj);
|
||||
if (dataObj instanceof JSONObject) {
|
||||
String url = ((JSONObject) dataObj).getString("downloadUrl");
|
||||
if (url != null && !url.isBlank()) return url;
|
||||
} else if (dataObj instanceof String && !((String) dataObj).isBlank()) {
|
||||
return (String) dataObj;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("通过签章API获取下载URL失败,使用原始URL: {}", e.getMessage());
|
||||
}
|
||||
return fallbackUrl;
|
||||
throw new ServiceException("签章平台下载接口返回失败,无法获取签署文件下载地址");
|
||||
}
|
||||
|
||||
private boolean isExternalUrl(String path) {
|
||||
|
||||
@@ -63,6 +63,8 @@ public final class ContractLaunchConstants {
|
||||
public static final String ACTION_SEAL_CALLBACK = "seal_callback";
|
||||
/** 线下签署文件上传 */
|
||||
public static final String ACTION_SEAL_UPLOAD = "seal_upload";
|
||||
/** 签章平台二维码生成(等待扫码确认) */
|
||||
public static final String ACTION_SEAL_QRCODE = "seal_qrcode";
|
||||
|
||||
public static final String ACTION_STATUS_SUCCESS = "success";
|
||||
public static final String ACTION_STATUS_FAILED = "failed";
|
||||
|
||||
@@ -12,6 +12,8 @@ import com.nbport.zgwl.contractpush.utils.ContractPushUrlUtils;
|
||||
import com.nbport.zgwl.exception.ServiceException;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Base64;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -26,6 +28,9 @@ public class SettlementPushService {
|
||||
private final ContractPushHttpUtils httpUtils;
|
||||
private final ContractPushRequestHandler requestHandler;
|
||||
|
||||
private volatile String cachedToken;
|
||||
private volatile long tokenExpireTime;
|
||||
|
||||
public SettlementPushService(ContractPushProperties properties,
|
||||
ContractPushHttpUtils httpUtils,
|
||||
ContractPushRequestHandler requestHandler) {
|
||||
@@ -91,19 +96,48 @@ public class SettlementPushService {
|
||||
return result;
|
||||
}
|
||||
|
||||
/** 获取结算平台 token,优先用入参,没有则自动调用 getToken 接口获取 */
|
||||
/** 获取结算平台 token,优先用入参,没有则使用缓存或自动调用 getToken 接口获取 */
|
||||
private String resolveSettlementToken(String inputToken) {
|
||||
if (StrUtil.isNotBlank(inputToken)) {
|
||||
return inputToken;
|
||||
}
|
||||
if (cachedToken != null && System.currentTimeMillis() < tokenExpireTime) {
|
||||
return cachedToken;
|
||||
}
|
||||
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);
|
||||
String token = String.valueOf(accessToken);
|
||||
cachedToken = token;
|
||||
tokenExpireTime = parseJwtExp(token);
|
||||
return token;
|
||||
}
|
||||
}
|
||||
throw new ServiceException("获取结算平台 token 失败");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** 从 JWT token 中解析 exp 作为过期时间,解析失败则兜底 50 分钟 */
|
||||
private long parseJwtExp(String token) {
|
||||
long defaultTtl = 50 * 60 * 1000L;
|
||||
try {
|
||||
String[] parts = token.split("\\.");
|
||||
if (parts.length < 2) return System.currentTimeMillis() + defaultTtl;
|
||||
byte[] decoded = Base64.getUrlDecoder().decode(parts[1]);
|
||||
String json = new String(decoded, StandardCharsets.UTF_8);
|
||||
int expIdx = json.indexOf("\"exp\"");
|
||||
if (expIdx < 0) return System.currentTimeMillis() + defaultTtl;
|
||||
int colonIdx = json.indexOf(':', expIdx);
|
||||
int commaIdx = json.indexOf(',', colonIdx);
|
||||
int braceIdx = json.indexOf('}', colonIdx);
|
||||
int end = commaIdx > 0 && commaIdx < braceIdx ? commaIdx : braceIdx;
|
||||
long exp = Long.parseLong(json.substring(colonIdx + 1, end).trim());
|
||||
return exp * 1000 - 60_000;
|
||||
} catch (Exception e) {
|
||||
return System.currentTimeMillis() + defaultTtl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ 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.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@@ -71,4 +72,10 @@ public class ContractTemplateController {
|
||||
public R<ContractTemplateDto> changeStatus(@PathVariable("id") Long id, @PathVariable("status") String status) {
|
||||
return R.success(contractTemplateService.changeTemplateStatus(id, status));
|
||||
}
|
||||
|
||||
@DeleteMapping("/{id}")
|
||||
public R<Void> delete(@PathVariable("id") Long id) {
|
||||
contractTemplateService.deleteTemplate(id);
|
||||
return R.success();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,9 @@ public interface ContractTemplateService {
|
||||
/** 切换模板状态 */
|
||||
ContractTemplateDto changeTemplateStatus(Long id, String status);
|
||||
|
||||
/** 删除模板(逻辑删除) */
|
||||
void deleteTemplate(Long id);
|
||||
|
||||
/** 获取发布范围组织选项 */
|
||||
List<TemplateOrgOptionDto> queryOrgOptions();
|
||||
}
|
||||
|
||||
@@ -158,6 +158,22 @@ public class ContractTemplateServiceImpl implements ContractTemplateService {
|
||||
return getTemplateDetail(id);
|
||||
}
|
||||
|
||||
/** 删除模板(逻辑删除) */
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteTemplate(Long id) {
|
||||
ContractTemplateDto dbTemplate = contractTemplateMapper.selectTemplateById(id);
|
||||
if (dbTemplate == null) {
|
||||
throw new ServiceException("模板不存在");
|
||||
}
|
||||
contractTemplateMapper.deleteTemplateById(
|
||||
id,
|
||||
ManifestManageConstants.DEFAULT_OPERATOR,
|
||||
LocalDateTime.now(),
|
||||
ManifestManageConstants.DEL_FLAG_DELETED
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取发布范围组织选项(扁平列表,供发布范围下拉使用)
|
||||
* 数据来源于组织树,平铺所有节点
|
||||
|
||||
@@ -32,8 +32,7 @@ public class PartnerManageDto implements Serializable {
|
||||
// ============== 客户基本信息字段 ==============
|
||||
|
||||
/** 客户系统ID */
|
||||
private Long customerSysid; // 注意:数据库中是VARCHAR(64),不是Long
|
||||
|
||||
private Long customerSysid;
|
||||
/** 客户注册号 */
|
||||
private String customerRegno;
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -246,10 +247,12 @@ public class PartnerManageServiceImpl implements PartnerManageService {
|
||||
|
||||
LocalDateTime now = LocalDateTime.now();
|
||||
|
||||
|
||||
// 构造批量报文(法务接口要求 JSON 数组 [{...},{...}])
|
||||
List<Map<String, Object>> batchPayload = PartnerSyncPayloadBuilder.buildCollectOppositesBatchPayload(partners);
|
||||
log.info("法务系统批量同步参数,共 {} 条: {}", partners.size(), JsonUtils.toJson(batchPayload));
|
||||
|
||||
|
||||
// TODO: 真实联调时打开以下调用
|
||||
// PushPayloadDTO requestDTO = new PushPayloadDTO();
|
||||
// requestDTO.setPayload(Map.of("opposites", batchPayload)); // 或直接传 List,取决于 collectOpposites 签名
|
||||
@@ -288,6 +291,8 @@ public class PartnerManageServiceImpl implements PartnerManageService {
|
||||
successCount++;
|
||||
}
|
||||
|
||||
|
||||
|
||||
return successCount;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ public final class PartnerSyncPayloadBuilder {
|
||||
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_country", partner.getCountryName());
|
||||
payload.put("o_legalPerson", partner.getLegalPersonName());
|
||||
payload.put("o_address", partner.getCustomerRegaddr());
|
||||
payload.put("o_capital", partner.getRegCapital());
|
||||
|
||||
@@ -81,7 +81,7 @@ public class SealProxyController {
|
||||
String token = sealTokenService.forceRefreshToken();
|
||||
Map<String, Object> data = new HashMap<>();
|
||||
data.put("access_token", token);
|
||||
data.put("expires_in", 7200);
|
||||
data.put("expires_in", sealTokenService.getCachedExpiresIn());
|
||||
return R.success(data);
|
||||
} catch (Exception e) {
|
||||
log.error("获取Token失败", e);
|
||||
@@ -125,7 +125,7 @@ public class SealProxyController {
|
||||
logPayload.put("response", response);
|
||||
sealLogService.logSealAction(null, ContractLaunchConstants.ACTION_SEAL_CREATE,
|
||||
"创建签署流程",
|
||||
result.getCode() != null && "0000".equals(String.valueOf(result.getCode()))
|
||||
result.isSuccess()
|
||||
? ContractLaunchConstants.ACTION_STATUS_SUCCESS
|
||||
: ContractLaunchConstants.ACTION_STATUS_FAILED,
|
||||
"在签章平台创建签署流程,合同名称: " + contractName,
|
||||
@@ -148,7 +148,15 @@ public class SealProxyController {
|
||||
try {
|
||||
JSONObject body = buildSignQrCodeBody(params);
|
||||
String response = proxyPost("/saas/api/qrcode/getStandardSignQrCode", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
R<Object> result = parseSealResponse(response);
|
||||
if (result.isSuccess()) {
|
||||
String sealContractId = extractContractId(params);
|
||||
Long contractId = sealLogService.findContractIdBySealContractId(sealContractId);
|
||||
sealLogService.logSealAction(contractId, ContractLaunchConstants.ACTION_SEAL_QRCODE,
|
||||
"标准签章", ContractLaunchConstants.ACTION_STATUS_PENDING,
|
||||
"标准签章二维码已生成,等待扫码确认,签章平台合同ID: " + sealContractId, params);
|
||||
}
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("获取标准签章二维码失败", e);
|
||||
return R.error("获取标准签章二维码失败: " + e.getMessage());
|
||||
@@ -160,7 +168,15 @@ public class SealProxyController {
|
||||
try {
|
||||
JSONObject body = buildPreSignBody(params);
|
||||
String response = proxyPost("/saas/api/qrcode/getPreSignQrCode", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
R<Object> result = parseSealResponse(response);
|
||||
if (result.isSuccess()) {
|
||||
String sealContractId = extractContractId(params);
|
||||
Long contractId = sealLogService.findContractIdBySealContractId(sealContractId);
|
||||
sealLogService.logSealAction(contractId, ContractLaunchConstants.ACTION_SEAL_QRCODE,
|
||||
"预盖章", ContractLaunchConstants.ACTION_STATUS_PENDING,
|
||||
"预盖章二维码已生成,等待扫码确认,签章平台合同ID: " + sealContractId, params);
|
||||
}
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("获取预盖章二维码失败", e);
|
||||
return R.error("获取预盖章二维码失败: " + e.getMessage());
|
||||
@@ -173,7 +189,15 @@ public class SealProxyController {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("notifyUrl", params.get("notifyUrl"));
|
||||
String response = proxyPost("/saas/api/qrcode/getTrusteeshipSealQrCode", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
R<Object> result = parseSealResponse(response);
|
||||
if (result.isSuccess()) {
|
||||
String sealContractId = extractContractId(params);
|
||||
Long contractId = sealLogService.findContractIdBySealContractId(sealContractId);
|
||||
sealLogService.logSealAction(contractId, ContractLaunchConstants.ACTION_SEAL_QRCODE,
|
||||
"托管章", ContractLaunchConstants.ACTION_STATUS_PENDING,
|
||||
"托管章二维码已生成,等待扫码确认" + (sealContractId != null ? ",签章平台合同ID: " + sealContractId : ""), params);
|
||||
}
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("获取托管章二维码失败", e);
|
||||
return R.error("获取托管章二维码失败: " + e.getMessage());
|
||||
@@ -191,7 +215,7 @@ public class SealProxyController {
|
||||
Long contractId = sealLogService.findContractIdBySealContractId(sealContractId);
|
||||
sealLogService.logSealAction(contractId, ContractLaunchConstants.ACTION_SEAL_SIGN,
|
||||
"托管签署",
|
||||
result.getCode() != null && "0000".equals(String.valueOf(result.getCode()))
|
||||
result.isSuccess()
|
||||
? ContractLaunchConstants.ACTION_STATUS_SUCCESS
|
||||
: ContractLaunchConstants.ACTION_STATUS_FAILED,
|
||||
"执行托管签署,签章平台合同ID: " + sealContractId,
|
||||
@@ -234,7 +258,7 @@ public class SealProxyController {
|
||||
Long contractId = sealLogService.findContractIdBySealContractId(sealContractId);
|
||||
sealLogService.logSealAction(contractId, ContractLaunchConstants.ACTION_SEAL_TIMESTAMP,
|
||||
"时间戳签章",
|
||||
result.getCode() != null && "0000".equals(String.valueOf(result.getCode()))
|
||||
result.isSuccess()
|
||||
? ContractLaunchConstants.ACTION_STATUS_SUCCESS
|
||||
: ContractLaunchConstants.ACTION_STATUS_FAILED,
|
||||
"执行时间戳签章,签章平台合同ID: " + sealContractId,
|
||||
@@ -278,7 +302,7 @@ public class SealProxyController {
|
||||
Long contractId = sealLogService.findContractIdBySealContractId(sealContractId);
|
||||
sealLogService.logSealAction(contractId, ContractLaunchConstants.ACTION_SEAL_COMMENT,
|
||||
"批注签章",
|
||||
result.getCode() != null && "0000".equals(String.valueOf(result.getCode()))
|
||||
result.isSuccess()
|
||||
? ContractLaunchConstants.ACTION_STATUS_SUCCESS
|
||||
: ContractLaunchConstants.ACTION_STATUS_FAILED,
|
||||
"执行批注签章,签章平台合同ID: " + sealContractId,
|
||||
@@ -309,7 +333,7 @@ public class SealProxyController {
|
||||
Long contractId = sealLogService.findContractIdBySealContractId(sealContractId);
|
||||
sealLogService.logSealAction(contractId, ContractLaunchConstants.ACTION_SEAL_COMPLETE,
|
||||
"完成签署流程",
|
||||
result.getCode() != null && "0000".equals(String.valueOf(result.getCode()))
|
||||
result.isSuccess()
|
||||
? ContractLaunchConstants.ACTION_STATUS_SUCCESS
|
||||
: ContractLaunchConstants.ACTION_STATUS_FAILED,
|
||||
"在签章平台完结签署流程,签章平台合同ID: " + sealContractId,
|
||||
@@ -340,7 +364,7 @@ public class SealProxyController {
|
||||
Long contractId = sealLogService.findContractIdBySealContractId(sealContractId);
|
||||
sealLogService.logSealAction(contractId, ContractLaunchConstants.ACTION_SEAL_CANCEL,
|
||||
"取消签署流程",
|
||||
result.getCode() != null && "0000".equals(String.valueOf(result.getCode()))
|
||||
result.isSuccess()
|
||||
? ContractLaunchConstants.ACTION_STATUS_SUCCESS
|
||||
: ContractLaunchConstants.ACTION_STATUS_FAILED,
|
||||
"在签章平台取消签署流程,签章平台合同ID: " + sealContractId,
|
||||
@@ -366,7 +390,7 @@ public class SealProxyController {
|
||||
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());
|
||||
String response = proxyPost("/saas/api/user/getUserUniqueId", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户身份编码失败", e);
|
||||
@@ -430,7 +454,7 @@ public class SealProxyController {
|
||||
try {
|
||||
JSONObject body = new JSONObject();
|
||||
body.put("requestId", params.get("requestId"));
|
||||
String response = proxyPost("/api/user/getUserInfos", body.toJSONString());
|
||||
String response = proxyPost("/saas/api/user/getUserInfos", body.toJSONString());
|
||||
return parseSealResponse(response);
|
||||
} catch (Exception e) {
|
||||
log.error("获取用户隐私数据失败", e);
|
||||
|
||||
@@ -30,6 +30,8 @@ public class SealTokenService {
|
||||
|
||||
private volatile long tokenExpireTime = 0;
|
||||
|
||||
private volatile long cachedExpiresIn;
|
||||
|
||||
private final ReentrantLock lock = new ReentrantLock();
|
||||
|
||||
private static final long TOKEN_EXPIRE_SECONDS = 7200;
|
||||
@@ -91,9 +93,9 @@ public class SealTokenService {
|
||||
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);
|
||||
cachedExpiresIn = data.getLongValue("expires_in", TOKEN_EXPIRE_SECONDS);
|
||||
tokenExpireTime = System.currentTimeMillis() + cachedExpiresIn * 1000;
|
||||
log.info("签章平台Token获取成功, 有效期: {}秒", cachedExpiresIn);
|
||||
} else {
|
||||
String msg = result.getString("msg");
|
||||
log.error("签章平台Token获取失败: {}", msg);
|
||||
@@ -107,11 +109,16 @@ public class SealTokenService {
|
||||
}
|
||||
}
|
||||
|
||||
public long getCachedExpiresIn() {
|
||||
return cachedExpiresIn;
|
||||
}
|
||||
|
||||
public void clearToken() {
|
||||
try {
|
||||
lock.lock();
|
||||
cachedToken = null;
|
||||
tokenExpireTime = 0;
|
||||
cachedExpiresIn = 0;
|
||||
} finally {
|
||||
lock.unlock();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user