支持拉取行内和金综流水
This commit is contained in:
@@ -17,6 +17,7 @@ public class LsfxConstants {
|
|||||||
|
|
||||||
/** 数据渠道编码 */
|
/** 数据渠道编码 */
|
||||||
public static final String DATA_CHANNEL_ZJRCU = "ZJRCU";
|
public static final String DATA_CHANNEL_ZJRCU = "ZJRCU";
|
||||||
|
public static final String DATA_CHANNEL_JZL = "JZL";
|
||||||
|
|
||||||
/** 分析类型 */
|
/** 分析类型 */
|
||||||
public static final String ANALYSIS_TYPE = "-1";
|
public static final String ANALYSIS_TYPE = "-1";
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ public class FetchInnerFlowRequest {
|
|||||||
/** 客户身份证号 */
|
/** 客户身份证号 */
|
||||||
private String customerNo;
|
private String customerNo;
|
||||||
|
|
||||||
/** 数据渠道编码(固定值:ZJRCU) */
|
/** 数据渠道编码(ZJRCU-行内,JZL-金综) */
|
||||||
private String dataChannelCode;
|
private String dataChannelCode;
|
||||||
|
|
||||||
/** 发起请求的时间(格式:yyyyMMdd) */
|
/** 发起请求的时间(格式:yyyyMMdd) */
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import com.ruoyi.common.core.page.PageDomain;
|
|||||||
import com.ruoyi.common.core.page.TableDataInfo;
|
import com.ruoyi.common.core.page.TableDataInfo;
|
||||||
import com.ruoyi.common.core.page.TableSupport;
|
import com.ruoyi.common.core.page.TableSupport;
|
||||||
import com.ruoyi.common.utils.SecurityUtils;
|
import com.ruoyi.common.utils.SecurityUtils;
|
||||||
|
import com.ruoyi.lsfx.constants.LsfxConstants;
|
||||||
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Operation;
|
||||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
@@ -103,10 +104,10 @@ public class CcdiFileUploadController extends BaseController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提交拉取本行信息任务
|
* 提交拉取行内/金综流水任务
|
||||||
*/
|
*/
|
||||||
@PostMapping("/pull-bank-info")
|
@PostMapping("/pull-bank-info")
|
||||||
@Operation(summary = "拉取本行信息", description = "按身份证号批量提交拉取本行信息任务")
|
@Operation(summary = "拉取行内/金综流水", description = "按证件号码批量提交拉取行内/金综流水任务")
|
||||||
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
|
@PreAuthorize("@ss.hasPermi('ccdi:project:edit')")
|
||||||
public AjaxResult pullBankInfo(@RequestBody CcdiPullBankInfoSubmitDTO dto) {
|
public AjaxResult pullBankInfo(@RequestBody CcdiPullBankInfoSubmitDTO dto) {
|
||||||
if (dto == null || dto.getProjectId() == null) {
|
if (dto == null || dto.getProjectId() == null) {
|
||||||
@@ -116,7 +117,16 @@ public class CcdiFileUploadController extends BaseController {
|
|||||||
if (CollectionUtils.isEmpty(dto.getIdCards())) {
|
if (CollectionUtils.isEmpty(dto.getIdCards())) {
|
||||||
return AjaxResult.error("身份证号不能为空");
|
return AjaxResult.error("身份证号不能为空");
|
||||||
}
|
}
|
||||||
if (!StringUtils.hasText(dto.getStartDate()) || !StringUtils.hasText(dto.getEndDate())) {
|
if (!StringUtils.hasText(dto.getDataChannelCode())) {
|
||||||
|
return AjaxResult.error("流水来源不能为空");
|
||||||
|
}
|
||||||
|
String dataChannelCode = dto.getDataChannelCode().trim().toUpperCase();
|
||||||
|
if (!LsfxConstants.DATA_CHANNEL_ZJRCU.equals(dataChannelCode)
|
||||||
|
&& !LsfxConstants.DATA_CHANNEL_JZL.equals(dataChannelCode)) {
|
||||||
|
return AjaxResult.error("流水来源不支持");
|
||||||
|
}
|
||||||
|
if (LsfxConstants.DATA_CHANNEL_ZJRCU.equals(dataChannelCode)
|
||||||
|
&& (!StringUtils.hasText(dto.getStartDate()) || !StringUtils.hasText(dto.getEndDate()))) {
|
||||||
return AjaxResult.error("开始日期和结束日期不能为空");
|
return AjaxResult.error("开始日期和结束日期不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,6 +135,7 @@ public class CcdiFileUploadController extends BaseController {
|
|||||||
String batchId = fileUploadService.submitPullBankInfo(
|
String batchId = fileUploadService.submitPullBankInfo(
|
||||||
dto.getProjectId(),
|
dto.getProjectId(),
|
||||||
dto.getIdCards(),
|
dto.getIdCards(),
|
||||||
|
dataChannelCode,
|
||||||
dto.getStartDate(),
|
dto.getStartDate(),
|
||||||
dto.getEndDate(),
|
dto.getEndDate(),
|
||||||
userId,
|
userId,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import lombok.Data;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 拉取本行信息提交参数
|
* 拉取行内/金综流水提交参数
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
public class CcdiPullBankInfoSubmitDTO {
|
public class CcdiPullBankInfoSubmitDTO {
|
||||||
@@ -16,6 +16,9 @@ public class CcdiPullBankInfoSubmitDTO {
|
|||||||
/** 身份证号列表 */
|
/** 身份证号列表 */
|
||||||
private List<String> idCards;
|
private List<String> idCards;
|
||||||
|
|
||||||
|
/** 数据渠道编码:ZJRCU-行内,JZL-金综 */
|
||||||
|
private String dataChannelCode;
|
||||||
|
|
||||||
/** 开始日期 */
|
/** 开始日期 */
|
||||||
private String startDate;
|
private String startDate;
|
||||||
|
|
||||||
|
|||||||
@@ -35,10 +35,11 @@ public interface ICcdiFileUploadService {
|
|||||||
List<String> parseIdCardFile(MultipartFile file);
|
List<String> parseIdCardFile(MultipartFile file);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 提交拉取本行信息任务
|
* 提交拉取行内/金综流水任务
|
||||||
*
|
*
|
||||||
* @param projectId 项目ID
|
* @param projectId 项目ID
|
||||||
* @param idCards 身份证号列表
|
* @param idCards 身份证号列表
|
||||||
|
* @param dataChannelCode 数据渠道编码
|
||||||
* @param startDate 开始日期
|
* @param startDate 开始日期
|
||||||
* @param endDate 结束日期
|
* @param endDate 结束日期
|
||||||
* @param userId 当前登录用户ID
|
* @param userId 当前登录用户ID
|
||||||
@@ -47,6 +48,7 @@ public interface ICcdiFileUploadService {
|
|||||||
*/
|
*/
|
||||||
String submitPullBankInfo(Long projectId,
|
String submitPullBankInfo(Long projectId,
|
||||||
List<String> idCards,
|
List<String> idCards,
|
||||||
|
String dataChannelCode,
|
||||||
String startDate,
|
String startDate,
|
||||||
String endDate,
|
String endDate,
|
||||||
Long userId,
|
Long userId,
|
||||||
|
|||||||
@@ -154,6 +154,7 @@ public class CcdiFileUploadServiceImpl implements ICcdiFileUploadService {
|
|||||||
@Override
|
@Override
|
||||||
public String submitPullBankInfo(Long projectId,
|
public String submitPullBankInfo(Long projectId,
|
||||||
List<String> idCards,
|
List<String> idCards,
|
||||||
|
String dataChannelCode,
|
||||||
String startDate,
|
String startDate,
|
||||||
String endDate,
|
String endDate,
|
||||||
Long userId,
|
Long userId,
|
||||||
@@ -161,17 +162,20 @@ public class CcdiFileUploadServiceImpl implements ICcdiFileUploadService {
|
|||||||
if (projectId == null) {
|
if (projectId == null) {
|
||||||
throw new IllegalArgumentException("项目ID不能为空");
|
throw new IllegalArgumentException("项目ID不能为空");
|
||||||
}
|
}
|
||||||
if (!StringUtils.hasText(startDate) || !StringUtils.hasText(endDate)) {
|
|
||||||
throw new IllegalArgumentException("开始日期和结束日期不能为空");
|
|
||||||
}
|
|
||||||
if (idCards == null || idCards.isEmpty()) {
|
if (idCards == null || idCards.isEmpty()) {
|
||||||
throw new IllegalArgumentException("身份证号不能为空");
|
throw new IllegalArgumentException("身份证号不能为空");
|
||||||
}
|
}
|
||||||
|
String normalizedDataChannelCode = normalizePullBankInfoDataChannelCode(dataChannelCode);
|
||||||
|
|
||||||
LocalDate start = LocalDate.parse(startDate);
|
if (LsfxConstants.DATA_CHANNEL_ZJRCU.equals(normalizedDataChannelCode)) {
|
||||||
LocalDate end = LocalDate.parse(endDate);
|
if (!StringUtils.hasText(startDate) || !StringUtils.hasText(endDate)) {
|
||||||
if (start.isAfter(end)) {
|
throw new IllegalArgumentException("开始日期和结束日期不能为空");
|
||||||
throw new IllegalArgumentException("开始日期不能晚于结束日期");
|
}
|
||||||
|
LocalDate start = LocalDate.parse(startDate);
|
||||||
|
LocalDate end = LocalDate.parse(endDate);
|
||||||
|
if (start.isAfter(end)) {
|
||||||
|
throw new IllegalArgumentException("开始日期不能晚于结束日期");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
projectService.ensureProjectNotArchived(projectId, "已归档项目暂不允许上传或拉取数据");
|
projectService.ensureProjectNotArchived(projectId, "已归档项目暂不允许上传或拉取数据");
|
||||||
@@ -218,13 +222,26 @@ public class CcdiFileUploadServiceImpl implements ICcdiFileUploadService {
|
|||||||
@Override
|
@Override
|
||||||
public void afterCommit() {
|
public void afterCommit() {
|
||||||
CompletableFuture.runAsync(() -> submitPullBankInfoTasks(
|
CompletableFuture.runAsync(() -> submitPullBankInfoTasks(
|
||||||
projectId, lsfxProjectId, records, normalizedIdCards, startDate, endDate, batchId
|
projectId, lsfxProjectId, records, normalizedIdCards,
|
||||||
|
normalizedDataChannelCode, startDate, endDate, batchId
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return batchId;
|
return batchId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private String normalizePullBankInfoDataChannelCode(String dataChannelCode) {
|
||||||
|
if (!StringUtils.hasText(dataChannelCode)) {
|
||||||
|
throw new IllegalArgumentException("流水来源不能为空");
|
||||||
|
}
|
||||||
|
String normalized = dataChannelCode.trim().toUpperCase();
|
||||||
|
if (!LsfxConstants.DATA_CHANNEL_ZJRCU.equals(normalized)
|
||||||
|
&& !LsfxConstants.DATA_CHANNEL_JZL.equals(normalized)) {
|
||||||
|
throw new IllegalArgumentException("流水来源不支持");
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String deleteFileUploadRecord(Long id, Long operatorUserId) {
|
public String deleteFileUploadRecord(Long id, Long operatorUserId) {
|
||||||
CcdiFileUploadRecord record = recordMapper.selectById(id);
|
CcdiFileUploadRecord record = recordMapper.selectById(id);
|
||||||
@@ -580,6 +597,7 @@ public class CcdiFileUploadServiceImpl implements ICcdiFileUploadService {
|
|||||||
Integer lsfxProjectId,
|
Integer lsfxProjectId,
|
||||||
List<CcdiFileUploadRecord> records,
|
List<CcdiFileUploadRecord> records,
|
||||||
List<String> idCards,
|
List<String> idCards,
|
||||||
|
String dataChannelCode,
|
||||||
String startDate,
|
String startDate,
|
||||||
String endDate,
|
String endDate,
|
||||||
String batchId) {
|
String batchId) {
|
||||||
@@ -601,7 +619,7 @@ public class CcdiFileUploadServiceImpl implements ICcdiFileUploadService {
|
|||||||
while (!submitted && retryCount < 2) {
|
while (!submitted && retryCount < 2) {
|
||||||
try {
|
try {
|
||||||
CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(
|
CompletableFuture<Boolean> future = CompletableFuture.supplyAsync(
|
||||||
() -> processPullBankInfoAsync(projectId, lsfxProjectId, record, idCard, startDate, endDate),
|
() -> processPullBankInfoAsync(projectId, lsfxProjectId, record, idCard, dataChannelCode, startDate, endDate),
|
||||||
fileUploadExecutor
|
fileUploadExecutor
|
||||||
);
|
);
|
||||||
futures.add(future);
|
futures.add(future);
|
||||||
@@ -640,16 +658,23 @@ public class CcdiFileUploadServiceImpl implements ICcdiFileUploadService {
|
|||||||
Integer lsfxProjectId,
|
Integer lsfxProjectId,
|
||||||
CcdiFileUploadRecord record,
|
CcdiFileUploadRecord record,
|
||||||
String idCard,
|
String idCard,
|
||||||
|
String dataChannelCode,
|
||||||
String startDate,
|
String startDate,
|
||||||
String endDate ) {
|
String endDate ) {
|
||||||
try {
|
try {
|
||||||
|
String normalizedDataChannelCode = normalizePullBankInfoDataChannelCode(dataChannelCode);
|
||||||
FetchInnerFlowRequest request = new FetchInnerFlowRequest();
|
FetchInnerFlowRequest request = new FetchInnerFlowRequest();
|
||||||
request.setGroupId(lsfxProjectId);
|
request.setGroupId(lsfxProjectId);
|
||||||
request.setCustomerNo(idCard);
|
request.setCustomerNo(idCard);
|
||||||
request.setDataChannelCode(LsfxConstants.DEFAULT_DATA_CHANNEL_CODE);
|
request.setDataChannelCode(normalizedDataChannelCode);
|
||||||
request.setRequestDateId(Integer.parseInt(LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE)));
|
request.setRequestDateId(Integer.parseInt(LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE)));
|
||||||
request.setDataStartDateId(Integer.parseInt(startDate.replace("-", "")));
|
if (LsfxConstants.DATA_CHANNEL_JZL.equals(normalizedDataChannelCode)) {
|
||||||
request.setDataEndDateId(Integer.parseInt(endDate.replace("-", "")));
|
request.setDataStartDateId(0);
|
||||||
|
request.setDataEndDateId(0);
|
||||||
|
} else {
|
||||||
|
request.setDataStartDateId(Integer.parseInt(startDate.replace("-", "")));
|
||||||
|
request.setDataEndDateId(Integer.parseInt(endDate.replace("-", "")));
|
||||||
|
}
|
||||||
request.setUploadUserId(LsfxConstants.DEFAULT_USER_ID);
|
request.setUploadUserId(LsfxConstants.DEFAULT_USER_ID);
|
||||||
|
|
||||||
FetchInnerFlowResponse response = lsfxClient.fetchInnerFlow(request);
|
FetchInnerFlowResponse response = lsfxClient.fetchInnerFlow(request);
|
||||||
|
|||||||
@@ -88,11 +88,12 @@ class CcdiFileUploadControllerTest {
|
|||||||
CcdiPullBankInfoSubmitDTO dto = new CcdiPullBankInfoSubmitDTO();
|
CcdiPullBankInfoSubmitDTO dto = new CcdiPullBankInfoSubmitDTO();
|
||||||
dto.setProjectId(PROJECT_ID);
|
dto.setProjectId(PROJECT_ID);
|
||||||
dto.setIdCards(List.of("110101199001018888"));
|
dto.setIdCards(List.of("110101199001018888"));
|
||||||
|
dto.setDataChannelCode("ZJRCU");
|
||||||
dto.setStartDate("2026-03-01");
|
dto.setStartDate("2026-03-01");
|
||||||
dto.setEndDate("2026-03-10");
|
dto.setEndDate("2026-03-10");
|
||||||
|
|
||||||
setLoginUser(9527L, "admin");
|
setLoginUser(9527L, "admin");
|
||||||
when(fileUploadService.submitPullBankInfo(PROJECT_ID, dto.getIdCards(), "2026-03-01", "2026-03-10", 9527L, "admin"))
|
when(fileUploadService.submitPullBankInfo(PROJECT_ID, dto.getIdCards(), "ZJRCU", "2026-03-01", "2026-03-10", 9527L, "admin"))
|
||||||
.thenReturn("batch-1");
|
.thenReturn("batch-1");
|
||||||
|
|
||||||
AjaxResult result = controller.pullBankInfo(dto);
|
AjaxResult result = controller.pullBankInfo(dto);
|
||||||
@@ -100,6 +101,35 @@ class CcdiFileUploadControllerTest {
|
|||||||
assertEquals(200, result.get("code"));
|
assertEquals(200, result.get("code"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void pullBankInfo_shouldAllowJzlWithoutDateRange() {
|
||||||
|
CcdiPullBankInfoSubmitDTO dto = new CcdiPullBankInfoSubmitDTO();
|
||||||
|
dto.setProjectId(PROJECT_ID);
|
||||||
|
dto.setIdCards(List.of("110101199001018888"));
|
||||||
|
dto.setDataChannelCode("JZL");
|
||||||
|
|
||||||
|
setLoginUser(9527L, "admin");
|
||||||
|
when(fileUploadService.submitPullBankInfo(PROJECT_ID, dto.getIdCards(), "JZL", null, null, 9527L, "admin"))
|
||||||
|
.thenReturn("batch-1");
|
||||||
|
|
||||||
|
AjaxResult result = controller.pullBankInfo(dto);
|
||||||
|
|
||||||
|
assertEquals(200, result.get("code"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void pullBankInfo_shouldRejectUnsupportedDataChannelCode() {
|
||||||
|
CcdiPullBankInfoSubmitDTO dto = new CcdiPullBankInfoSubmitDTO();
|
||||||
|
dto.setProjectId(PROJECT_ID);
|
||||||
|
dto.setIdCards(List.of("110101199001018888"));
|
||||||
|
dto.setDataChannelCode("OTHER");
|
||||||
|
|
||||||
|
AjaxResult result = controller.pullBankInfo(dto);
|
||||||
|
|
||||||
|
assertEquals(500, result.get("code"));
|
||||||
|
assertEquals("流水来源不支持", result.get("msg"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void deleteFile_shouldUseCurrentLoginUserId() {
|
void deleteFile_shouldUseCurrentLoginUserId() {
|
||||||
setLoginUser(9527L, "admin");
|
setLoginUser(9527L, "admin");
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import com.ruoyi.ccdi.project.service.ICcdiBankTagService;
|
|||||||
import com.ruoyi.ccdi.project.service.ICcdiProjectService;
|
import com.ruoyi.ccdi.project.service.ICcdiProjectService;
|
||||||
import com.ruoyi.common.exception.ServiceException;
|
import com.ruoyi.common.exception.ServiceException;
|
||||||
import com.ruoyi.lsfx.client.LsfxAnalysisClient;
|
import com.ruoyi.lsfx.client.LsfxAnalysisClient;
|
||||||
|
import com.ruoyi.lsfx.constants.LsfxConstants;
|
||||||
|
import com.ruoyi.lsfx.domain.request.FetchInnerFlowRequest;
|
||||||
import com.ruoyi.lsfx.domain.request.GetBankStatementRequest;
|
import com.ruoyi.lsfx.domain.request.GetBankStatementRequest;
|
||||||
import com.ruoyi.lsfx.domain.response.CheckParseStatusResponse;
|
import com.ruoyi.lsfx.domain.response.CheckParseStatusResponse;
|
||||||
import com.ruoyi.lsfx.domain.response.DeleteFilesResponse;
|
import com.ruoyi.lsfx.domain.response.DeleteFilesResponse;
|
||||||
@@ -144,6 +146,7 @@ class CcdiFileUploadServiceImplTest {
|
|||||||
String batchId = service.submitPullBankInfo(
|
String batchId = service.submitPullBankInfo(
|
||||||
PROJECT_ID,
|
PROJECT_ID,
|
||||||
List.of("110101199001018888", "110101199001019999"),
|
List.of("110101199001018888", "110101199001019999"),
|
||||||
|
LsfxConstants.DATA_CHANNEL_ZJRCU,
|
||||||
"2026-03-01",
|
"2026-03-01",
|
||||||
"2026-03-10",
|
"2026-03-10",
|
||||||
9527L,
|
9527L,
|
||||||
@@ -171,6 +174,7 @@ class CcdiFileUploadServiceImplTest {
|
|||||||
() -> service.submitPullBankInfo(
|
() -> service.submitPullBankInfo(
|
||||||
PROJECT_ID,
|
PROJECT_ID,
|
||||||
List.of("3301"),
|
List.of("3301"),
|
||||||
|
LsfxConstants.DATA_CHANNEL_ZJRCU,
|
||||||
"2026-01-01",
|
"2026-01-01",
|
||||||
"2026-01-31",
|
"2026-01-31",
|
||||||
1L,
|
1L,
|
||||||
@@ -438,6 +442,7 @@ class CcdiFileUploadServiceImplTest {
|
|||||||
LSFX_PROJECT_ID,
|
LSFX_PROJECT_ID,
|
||||||
record,
|
record,
|
||||||
"110101199001018888",
|
"110101199001018888",
|
||||||
|
LsfxConstants.DATA_CHANNEL_ZJRCU,
|
||||||
"2026-03-01",
|
"2026-03-01",
|
||||||
"2026-03-10"
|
"2026-03-10"
|
||||||
);
|
);
|
||||||
@@ -450,6 +455,34 @@ class CcdiFileUploadServiceImplTest {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void processPullBankInfoAsync_shouldFetchJzlWithZeroDateRange() {
|
||||||
|
when(lsfxClient.fetchInnerFlow(any())).thenReturn(buildFetchInnerFlowResponse(LOG_ID));
|
||||||
|
when(lsfxClient.checkParseStatus(LSFX_PROJECT_ID, String.valueOf(LOG_ID)))
|
||||||
|
.thenReturn(buildCheckParseStatusResponse(false));
|
||||||
|
when(lsfxClient.getFileUploadStatus(any())).thenReturn(buildParsedSuccessStatusResponse());
|
||||||
|
when(lsfxClient.getBankStatement(any(GetBankStatementRequest.class)))
|
||||||
|
.thenReturn(buildEmptyBankStatementResponse());
|
||||||
|
|
||||||
|
CcdiFileUploadRecord record = buildRecord();
|
||||||
|
|
||||||
|
service.processPullBankInfoAsync(
|
||||||
|
PROJECT_ID,
|
||||||
|
LSFX_PROJECT_ID,
|
||||||
|
record,
|
||||||
|
"110101199001018888",
|
||||||
|
LsfxConstants.DATA_CHANNEL_JZL,
|
||||||
|
null,
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
|
verify(lsfxClient).fetchInnerFlow(argThat((FetchInnerFlowRequest request) ->
|
||||||
|
LsfxConstants.DATA_CHANNEL_JZL.equals(request.getDataChannelCode())
|
||||||
|
&& Integer.valueOf(0).equals(request.getDataStartDateId())
|
||||||
|
&& Integer.valueOf(0).equals(request.getDataEndDateId())
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void processFileAsync_shouldUploadToLsfxWithOriginalRecordFileName() throws IOException {
|
void processFileAsync_shouldUploadToLsfxWithOriginalRecordFileName() throws IOException {
|
||||||
when(lsfxClient.uploadFile(eq(LSFX_PROJECT_ID), any(), eq("原始流水.xlsx")))
|
when(lsfxClient.uploadFile(eq(LSFX_PROJECT_ID), any(), eq("原始流水.xlsx")))
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
# 拉取行内/金综流水后端实施计划
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
项目详情页“上传数据”中的拉取流水能力需要支持两种来源:行内流水 `ZJRCU` 与金综流水 `JZL`。流水平台仍使用原 `/getJZFileOrZjrcuFile` 接口,一次请求只传一种 `dataChannelCode`。
|
||||||
|
|
||||||
|
## 实施范围
|
||||||
|
|
||||||
|
- `CcdiPullBankInfoSubmitDTO` 增加 `dataChannelCode`。
|
||||||
|
- `CcdiFileUploadController#pullBankInfo` 校验流水来源,仅允许 `ZJRCU`、`JZL`。
|
||||||
|
- `ICcdiFileUploadService#submitPullBankInfo` 与实现类透传来源。
|
||||||
|
- `CcdiFileUploadServiceImpl#processPullBankInfoAsync` 按来源组装流水平台请求:
|
||||||
|
- `ZJRCU`:使用页面传入的开始、结束日期。
|
||||||
|
- `JZL`:`dataStartDateId=0`、`dataEndDateId=0`。
|
||||||
|
- `LsfxConstants` 增加 `DATA_CHANNEL_JZL` 常量。
|
||||||
|
|
||||||
|
## 验证计划
|
||||||
|
|
||||||
|
- 运行 `CcdiFileUploadControllerTest`,验证 Controller 透传来源与金综不要求日期。
|
||||||
|
- 运行 `CcdiFileUploadServiceImplTest`,验证金综请求传 `JZL` 与 `0/0` 日期参数。
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
# 拉取行内/金综流水前端实施计划
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
原弹窗只体现“拉取本行信息”,用户无法选择流水平台来源。新需求是在同一入口中区分拉取行内流水和拉取金综流水。
|
||||||
|
|
||||||
|
## 实施范围
|
||||||
|
|
||||||
|
- 将上传数据工具栏入口文案调整为“拉取流水”。
|
||||||
|
- 将弹窗标题调整为“拉取行内/金综流水”。
|
||||||
|
- 在弹窗中增加“流水类型”单选:
|
||||||
|
- 默认选择 `ZJRCU` 行内流水。
|
||||||
|
- 可切换为 `JZL` 金综流水。
|
||||||
|
- 两种来源均沿用证件号码批量输入能力,多个证件号按列表提交给后端。
|
||||||
|
- 行内流水保留时间跨度选择与近一年校验。
|
||||||
|
- 金综流水隐藏时间跨度,提交时 `startDate/endDate` 传空,由后端固定转换为 `0/0`。
|
||||||
|
- 类型备注按页面截图口径展示:
|
||||||
|
- 行内流水:`备注:仅支持获取近一年流水`。
|
||||||
|
- 金综流水:`备注:自动获取最近30天内授权的流水文件`。
|
||||||
|
- 提交 payload 增加 `dataChannelCode`。
|
||||||
|
|
||||||
|
## 验证计划
|
||||||
|
|
||||||
|
- 前端构建检查。
|
||||||
|
- 使用真实项目页面打开弹窗,确认默认行内、切换金综后隐藏时间跨度。
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
# 拉取行内/金综流水来源选择实施记录
|
||||||
|
|
||||||
|
## 修改内容
|
||||||
|
|
||||||
|
- 后端拉取流水提交 DTO 增加 `dataChannelCode`。
|
||||||
|
- 后端 Controller 校验流水来源,仅允许 `ZJRCU` 与 `JZL`。
|
||||||
|
- 后端 Service 透传来源到流水平台请求。
|
||||||
|
- 行内流水继续传页面日期;金综流水固定传 `dataStartDateId=0`、`dataEndDateId=0`。
|
||||||
|
- 前端上传数据页入口改为“拉取流水”,弹窗增加行内/金综单选。
|
||||||
|
- 前端选择金综流水时隐藏时间跨度,提交 `dataChannelCode=JZL`。
|
||||||
|
- 行内和金综均支持多个证件号码批量提交,沿用原 `idCards` 列表。
|
||||||
|
- 类型备注调整为截图口径,金综备注不再出现“时间参数”。
|
||||||
|
|
||||||
|
## 影响范围
|
||||||
|
|
||||||
|
- 项目详情页上传数据模块。
|
||||||
|
- `/ccdi/file-upload/pull-bank-info` 接口。
|
||||||
|
- 流水平台拉取行内/金综流水请求参数组装。
|
||||||
|
|
||||||
|
## 验证情况
|
||||||
|
|
||||||
|
- 后端单测通过:
|
||||||
|
- `mvn -pl ccdi-project -am test "-Dtest=CcdiFileUploadControllerTest,CcdiFileUploadServiceImplTest" "-Dsurefire.failIfNoSpecifiedTests=false"`
|
||||||
|
- 结果:40 个测试通过。
|
||||||
|
- 前端构建通过:
|
||||||
|
- `.nvmrc` 指向 `14.21.3`,本机 `nvm use` 未读取版本参数;按本机已验证环境使用 Node `v22.22.3`、npm `10.9.8`。
|
||||||
|
- `npm run build:prod`
|
||||||
|
- 结果:构建成功,仅存在既有资源体积告警。
|
||||||
|
- 真实页面验证通过:
|
||||||
|
- 启动真实 `ruoyi-admin.jar` 后端并访问 `http://127.0.0.1:62318/swagger-ui.html`,返回 200。
|
||||||
|
- 启动前端开发服务,实际访问地址为 `http://127.0.0.1:8089/`。
|
||||||
|
- 在真实项目详情页 `90342` 打开“拉取流水”弹窗,默认选中“拉取行内流水”并显示时间跨度。
|
||||||
|
- 切换“拉取金综流水”后,时间跨度隐藏。
|
||||||
|
- 金综备注显示为“备注:自动获取最近30天内授权的流水文件”。
|
||||||
|
- 复查行内备注显示为“备注:仅支持获取近一年流水”,金综备注未出现“时间参数”。
|
||||||
|
- 未点击“确认拉取”,未提交真实拉取任务。
|
||||||
|
- 测试结束后已停止本轮启动的前端和后端进程,端口 `8088`、`8089`、`62318` 无本轮服务监听。
|
||||||
|
|
||||||
|
## 提交前复验
|
||||||
|
|
||||||
|
- 后端单测复验通过:`CcdiFileUploadControllerTest`、`CcdiFileUploadServiceImplTest` 共 40 个测试通过。
|
||||||
|
- 前端生产构建复验通过:继续使用 Node `v22.22.3`、npm `10.9.8`,构建成功,仅存在既有资源体积告警。
|
||||||
|
- 真实页面复验通过:访问 `http://127.0.0.1:8088/ccdiProject/detail/90342`,打开“拉取流水”弹窗后默认选中“拉取行内流水”;切换“拉取金综流水”后时间跨度隐藏;两条备注与截图一致,页面未出现“时间参数”。
|
||||||
|
- 复验未点击“确定”,未提交真实拉取任务;复验结束后已停止后端 `62318` 与前端 `8088` 监听进程。
|
||||||
@@ -56,7 +56,7 @@ export function executeQualityCheck(projectId) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 拉取本行信息
|
// 解析证件号码文件
|
||||||
export function parseIdCardFile(file) {
|
export function parseIdCardFile(file) {
|
||||||
const formData = new FormData()
|
const formData = new FormData()
|
||||||
formData.append('file', file)
|
formData.append('file', file)
|
||||||
@@ -70,7 +70,7 @@ export function parseIdCardFile(file) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 拉取本行信息
|
// 拉取行内/金综流水
|
||||||
export function pullBankInfo(data) {
|
export function pullBankInfo(data) {
|
||||||
return request({
|
return request({
|
||||||
url: '/ccdi/file-upload/pull-bank-info',
|
url: '/ccdi/file-upload/pull-bank-info',
|
||||||
|
|||||||
@@ -25,7 +25,7 @@
|
|||||||
:disabled="isWriteLocked"
|
:disabled="isWriteLocked"
|
||||||
@click="handleFetchBankInfo"
|
@click="handleFetchBankInfo"
|
||||||
>
|
>
|
||||||
拉取本行信息
|
拉取流水
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
size="small"
|
size="small"
|
||||||
@@ -110,7 +110,7 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
title="拉取本行信息"
|
title="拉取行内/金综流水"
|
||||||
:visible.sync="pullBankInfoDialogVisible"
|
:visible.sync="pullBankInfoDialogVisible"
|
||||||
:close-on-click-modal="false"
|
:close-on-click-modal="false"
|
||||||
width="640px"
|
width="640px"
|
||||||
@@ -120,6 +120,24 @@
|
|||||||
:model="pullBankInfoForm"
|
:model="pullBankInfoForm"
|
||||||
label-width="100px"
|
label-width="100px"
|
||||||
>
|
>
|
||||||
|
<el-form-item label="流水类型">
|
||||||
|
<el-radio-group
|
||||||
|
v-model="pullBankInfoForm.dataChannelCode"
|
||||||
|
:disabled="isWriteLocked"
|
||||||
|
class="pull-bank-channel-group"
|
||||||
|
>
|
||||||
|
<el-radio label="ZJRCU">
|
||||||
|
<span class="pull-bank-channel-title">拉取行内流水</span>
|
||||||
|
<span class="pull-bank-channel-tip">备注:仅支持获取近一年流水</span>
|
||||||
|
</el-radio>
|
||||||
|
<el-radio label="JZL">
|
||||||
|
<span class="pull-bank-channel-title">拉取金综流水</span>
|
||||||
|
<span class="pull-bank-channel-tip">
|
||||||
|
备注:自动获取最近30天内授权的流水文件
|
||||||
|
</span>
|
||||||
|
</el-radio>
|
||||||
|
</el-radio-group>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item label="证件号码">
|
<el-form-item label="证件号码">
|
||||||
<el-input
|
<el-input
|
||||||
v-model="pullBankInfoForm.idCardText"
|
v-model="pullBankInfoForm.idCardText"
|
||||||
@@ -171,7 +189,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="时间跨度">
|
<el-form-item v-if="isZjrcuPullBankInfo" label="时间跨度">
|
||||||
<el-date-picker
|
<el-date-picker
|
||||||
class="pull-bank-range-picker"
|
class="pull-bank-range-picker"
|
||||||
v-model="pullBankInfoForm.dateRange"
|
v-model="pullBankInfoForm.dateRange"
|
||||||
@@ -309,6 +327,7 @@ export default {
|
|||||||
parsingIdCardFile: false,
|
parsingIdCardFile: false,
|
||||||
idCardFileList: [],
|
idCardFileList: [],
|
||||||
pullBankInfoForm: {
|
pullBankInfoForm: {
|
||||||
|
dataChannelCode: "ZJRCU",
|
||||||
idCardText: "",
|
idCardText: "",
|
||||||
dateRange: [],
|
dateRange: [],
|
||||||
},
|
},
|
||||||
@@ -365,6 +384,9 @@ export default {
|
|||||||
isWriteLocked() {
|
isWriteLocked() {
|
||||||
return !this.canOperate || this.isProjectTagging || this.isProjectArchived;
|
return !this.canOperate || this.isProjectTagging || this.isProjectArchived;
|
||||||
},
|
},
|
||||||
|
isZjrcuPullBankInfo() {
|
||||||
|
return this.pullBankInfoForm.dataChannelCode === "ZJRCU";
|
||||||
|
},
|
||||||
writeLockedMessage() {
|
writeLockedMessage() {
|
||||||
if (!this.canOperate) {
|
if (!this.canOperate) {
|
||||||
return "当前项目仅可查看,暂不可上传或拉取数据。";
|
return "当前项目仅可查看,暂不可上传或拉取数据。";
|
||||||
@@ -440,6 +462,7 @@ export default {
|
|||||||
},
|
},
|
||||||
resetPullBankInfoForm() {
|
resetPullBankInfoForm() {
|
||||||
this.pullBankInfoForm = {
|
this.pullBankInfoForm = {
|
||||||
|
dataChannelCode: "ZJRCU",
|
||||||
idCardText: "",
|
idCardText: "",
|
||||||
dateRange: this.buildDefaultPullBankInfoDateRange(),
|
dateRange: this.buildDefaultPullBankInfoDateRange(),
|
||||||
};
|
};
|
||||||
@@ -594,18 +617,22 @@ export default {
|
|||||||
}
|
}
|
||||||
const idCards = this.buildFinalIdCardList();
|
const idCards = this.buildFinalIdCardList();
|
||||||
const [startDate, endDate] = this.pullBankInfoForm.dateRange || [];
|
const [startDate, endDate] = this.pullBankInfoForm.dateRange || [];
|
||||||
|
const dataChannelCode = this.pullBankInfoForm.dataChannelCode;
|
||||||
|
|
||||||
if (idCards.length === 0) {
|
if (idCards.length === 0) {
|
||||||
this.$message.warning("请至少输入一个身份证号");
|
this.$message.warning("请至少输入一个身份证号");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!startDate || !endDate) {
|
if (this.isZjrcuPullBankInfo && (!startDate || !endDate)) {
|
||||||
this.$message.warning("请选择完整的时间跨度");
|
this.$message.warning("请选择完整的时间跨度");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.hasInvalidPullBankInfoDateRange([startDate, endDate])) {
|
if (
|
||||||
|
this.isZjrcuPullBankInfo &&
|
||||||
|
this.hasInvalidPullBankInfoDateRange([startDate, endDate])
|
||||||
|
) {
|
||||||
this.$message.warning("时间跨度仅支持近一年内日期,且最晚只能选择到昨天");
|
this.$message.warning("时间跨度仅支持近一年内日期,且最晚只能选择到昨天");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -616,8 +643,9 @@ export default {
|
|||||||
const payload = {
|
const payload = {
|
||||||
projectId: this.projectId,
|
projectId: this.projectId,
|
||||||
idCards,
|
idCards,
|
||||||
startDate,
|
dataChannelCode,
|
||||||
endDate,
|
startDate: this.isZjrcuPullBankInfo ? startDate : null,
|
||||||
|
endDate: this.isZjrcuPullBankInfo ? endDate : null,
|
||||||
};
|
};
|
||||||
const res = await pullBankInfo(payload);
|
const res = await pullBankInfo(payload);
|
||||||
|
|
||||||
@@ -642,11 +670,11 @@ export default {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.pullBankInfoLoading = false;
|
this.pullBankInfoLoading = false;
|
||||||
this.$message.error(
|
this.$message.error(
|
||||||
"拉取本行信息失败:" + ((error && error.message) || "未知错误")
|
"拉取流水失败:" + ((error && error.message) || "未知错误")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
/** 拉取本行信息 */
|
/** 拉取流水 */
|
||||||
handleFetchBankInfo() {
|
handleFetchBankInfo() {
|
||||||
if (this.isWriteLocked) {
|
if (this.isWriteLocked) {
|
||||||
this.showWriteLockedMessage();
|
this.showWriteLockedMessage();
|
||||||
@@ -1171,6 +1199,37 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.pull-bank-info-form {
|
.pull-bank-info-form {
|
||||||
|
.pull-bank-channel-group {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
::v-deep .el-radio {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 0;
|
||||||
|
line-height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::v-deep .el-radio__label {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: baseline;
|
||||||
|
gap: 16px;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pull-bank-channel-title {
|
||||||
|
font-size: 15px;
|
||||||
|
color: #303133;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pull-bank-channel-tip {
|
||||||
|
font-size: 13px;
|
||||||
|
color: #909399;
|
||||||
|
}
|
||||||
|
|
||||||
.pull-bank-field-tip {
|
.pull-bank-field-tip {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|||||||
Reference in New Issue
Block a user