细节修改

This commit is contained in:
2026-07-08 08:36:44 +08:00
parent 4433646003
commit f18a173d25
14 changed files with 206 additions and 62 deletions
@@ -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
* 参数:fileMultipartFile
*
* 对应前端功能:签署准备页面的"上传带水印合同"区域
*/
@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);
@@ -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();
}