新增图谱功能及验收清单
This commit is contained in:
@@ -0,0 +1,78 @@
|
||||
package com.ruoyi.ccdi.project.controller;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiFundGraphEdgeDetailQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiFundGraphManualEdgeSaveDTO;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiFundGraphQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphEdgeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphNodeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphStatementVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphVO;
|
||||
import com.ruoyi.ccdi.project.service.ICcdiFundGraphService;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import com.ruoyi.common.core.page.PageDomain;
|
||||
import com.ruoyi.common.core.page.TableDataInfo;
|
||||
import com.ruoyi.common.core.page.TableSupport;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
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 com.ruoyi.common.utils.SecurityUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 资金流图谱Controller
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/ccdi/project/fund-graph")
|
||||
@Tag(name = "资金流图谱")
|
||||
public class CcdiFundGraphController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private ICcdiFundGraphService fundGraphService;
|
||||
|
||||
@GetMapping("/search")
|
||||
@Operation(summary = "查询资金流图谱主体")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult searchSubjects(CcdiFundGraphQueryDTO queryDTO) {
|
||||
List<CcdiFundGraphNodeVO> subjects = fundGraphService.searchSubjects(queryDTO);
|
||||
return AjaxResult.success(subjects);
|
||||
}
|
||||
|
||||
@GetMapping("/graph")
|
||||
@Operation(summary = "查询一层资金流图谱")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getGraph(CcdiFundGraphQueryDTO queryDTO) {
|
||||
CcdiFundGraphVO graph = fundGraphService.getFundGraph(queryDTO);
|
||||
return AjaxResult.success(graph);
|
||||
}
|
||||
|
||||
@GetMapping("/edge-detail")
|
||||
@Operation(summary = "查询资金边流水明细")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public TableDataInfo getEdgeDetail(CcdiFundGraphEdgeDetailQueryDTO queryDTO) {
|
||||
PageDomain pageDomain = TableSupport.buildPageRequest();
|
||||
Page<CcdiFundGraphStatementVO> page = new Page<>(pageDomain.getPageNum(), pageDomain.getPageSize());
|
||||
Page<CcdiFundGraphStatementVO> result = fundGraphService.getEdgeDetails(page, queryDTO);
|
||||
return getDataTable(result.getRecords(), result.getTotal());
|
||||
}
|
||||
|
||||
@PostMapping("/manual-edge")
|
||||
@Operation(summary = "新增手工资金流向")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult saveManualEdge(@RequestBody CcdiFundGraphManualEdgeSaveDTO saveDTO) {
|
||||
try {
|
||||
CcdiFundGraphEdgeVO edge = fundGraphService.saveManualEdge(saveDTO, SecurityUtils.getUsername());
|
||||
return AjaxResult.success(edge);
|
||||
} catch (IllegalArgumentException e) {
|
||||
return AjaxResult.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.ruoyi.ccdi.project.controller;
|
||||
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiRelationGraphQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiRelationGraphSuspectedEnterpriseQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphNodeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphSuspectedEnterpriseVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphVO;
|
||||
import com.ruoyi.ccdi.project.service.ICcdiRelationGraphService;
|
||||
import com.ruoyi.common.core.controller.BaseController;
|
||||
import com.ruoyi.common.core.domain.AjaxResult;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 关系图谱Controller
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/ccdi/project/relation-graph")
|
||||
@Tag(name = "关系图谱")
|
||||
public class CcdiRelationGraphController extends BaseController {
|
||||
|
||||
@Resource
|
||||
private ICcdiRelationGraphService relationGraphService;
|
||||
|
||||
@GetMapping("/search")
|
||||
@Operation(summary = "查询关系图谱主体")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult searchSubjects(CcdiRelationGraphQueryDTO queryDTO) {
|
||||
List<CcdiRelationGraphNodeVO> subjects = relationGraphService.searchSubjects(queryDTO);
|
||||
return AjaxResult.success(subjects);
|
||||
}
|
||||
|
||||
@GetMapping("/graph")
|
||||
@Operation(summary = "查询一层关系图谱")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getGraph(CcdiRelationGraphQueryDTO queryDTO) {
|
||||
CcdiRelationGraphVO graph = relationGraphService.getRelationGraph(queryDTO);
|
||||
return AjaxResult.success(graph);
|
||||
}
|
||||
|
||||
@GetMapping("/suspected-enterprises")
|
||||
@Operation(summary = "查询关系图谱疑似同名企业")
|
||||
@PreAuthorize("@ss.hasPermi('ccdi:project:query')")
|
||||
public AjaxResult getSuspectedEnterprises(CcdiRelationGraphSuspectedEnterpriseQueryDTO queryDTO) {
|
||||
CcdiRelationGraphSuspectedEnterpriseVO result = relationGraphService.getSuspectedEnterprises(queryDTO);
|
||||
return AjaxResult.success(result);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.ruoyi.ccdi.project.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 资金流图谱边明细查询条件
|
||||
*/
|
||||
@Data
|
||||
public class CcdiFundGraphEdgeDetailQueryDTO {
|
||||
|
||||
/** 项目ID:历史字段,资金流图谱不按项目过滤 */
|
||||
private Long projectId;
|
||||
|
||||
/** 身份证号、员工姓名或本方户名 */
|
||||
private String keyword;
|
||||
|
||||
/** 主体节点object_key;复用图谱公共SQL片段时兼容条件判断 */
|
||||
private String objectKey;
|
||||
|
||||
/** 边起点 */
|
||||
private String fromKey;
|
||||
|
||||
/** 边终点 */
|
||||
private String toKey;
|
||||
|
||||
/** 方向:1支出,2收入 */
|
||||
private String direction;
|
||||
|
||||
/** 交易开始时间 */
|
||||
private String transactionStartTime;
|
||||
|
||||
/** 交易结束时间 */
|
||||
private String transactionEndTime;
|
||||
|
||||
/** 最小金额 */
|
||||
private BigDecimal amountMin;
|
||||
|
||||
/** 最大金额 */
|
||||
private BigDecimal amountMax;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.ruoyi.ccdi.project.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 手工资金流向保存参数。
|
||||
*/
|
||||
@Data
|
||||
public class CcdiFundGraphManualEdgeSaveDTO {
|
||||
|
||||
/** 起点主体object_key;为空时默认使用当前查询中心 */
|
||||
private String fromObjectKey;
|
||||
|
||||
/** 起点主体名称 */
|
||||
private String fromName;
|
||||
|
||||
/** 终点主体object_key;已有节点时传入 */
|
||||
private String toObjectKey;
|
||||
|
||||
/** 终点主体名称;新建主体时必填 */
|
||||
private String toName;
|
||||
|
||||
/** 终点主体身份证号/证件号;有值时按md5(trim(idNo))复用主体 */
|
||||
private String toIdNo;
|
||||
|
||||
/** 手工录入汇总金额 */
|
||||
private BigDecimal amount;
|
||||
|
||||
/** 手工录入笔数 */
|
||||
private Integer transactionCount;
|
||||
|
||||
/** 方向:1支出,2收入 */
|
||||
private String direction;
|
||||
|
||||
/** 资金流向关系说明 */
|
||||
private String relationDesc;
|
||||
|
||||
/** 来源说明 */
|
||||
private String sourceDesc;
|
||||
|
||||
/** 分析备注 */
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.ruoyi.ccdi.project.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 资金流图谱查询条件
|
||||
*/
|
||||
@Data
|
||||
public class CcdiFundGraphQueryDTO {
|
||||
|
||||
/** 项目ID:历史字段,资金流图谱不按项目过滤 */
|
||||
private Long projectId;
|
||||
|
||||
/** 身份证号、员工姓名或本方户名 */
|
||||
private String keyword;
|
||||
|
||||
/** 主体节点object_key;节点穿透时直接使用 */
|
||||
private String objectKey;
|
||||
|
||||
/** 交易开始时间 */
|
||||
private String transactionStartTime;
|
||||
|
||||
/** 交易结束时间 */
|
||||
private String transactionEndTime;
|
||||
|
||||
/** 最小金额 */
|
||||
private BigDecimal amountMin;
|
||||
|
||||
/** 最大金额 */
|
||||
private BigDecimal amountMax;
|
||||
|
||||
/** 最小汇总金额,默认1000 */
|
||||
private BigDecimal minTotalAmount;
|
||||
|
||||
/** 方向:1支出,2收入 */
|
||||
private String direction;
|
||||
|
||||
/** 返回边数量上限 */
|
||||
private Integer limit;
|
||||
|
||||
/** 预留追溯层级,一期固定按一层处理 */
|
||||
private Integer depth;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.ruoyi.ccdi.project.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 关系图谱查询条件
|
||||
*/
|
||||
@Data
|
||||
public class CcdiRelationGraphQueryDTO {
|
||||
|
||||
/** 项目ID:历史字段,关系图谱不按项目过滤 */
|
||||
private Long projectId;
|
||||
|
||||
/** 身份证号、姓名、统一社会信用代码或节点object_key */
|
||||
private String keyword;
|
||||
|
||||
/** 节点object_key;节点穿透时直接使用 */
|
||||
private String objectKey;
|
||||
|
||||
/** 返回边数量上限 */
|
||||
private Integer limit;
|
||||
|
||||
/** 预留追溯层级,一期固定按一层处理 */
|
||||
private Integer depth;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.ruoyi.ccdi.project.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 关系图谱疑似企业查询条件
|
||||
*/
|
||||
@Data
|
||||
public class CcdiRelationGraphSuspectedEnterpriseQueryDTO {
|
||||
|
||||
/** 姓名 */
|
||||
private String personName;
|
||||
|
||||
/** 证件号 */
|
||||
private String certNo;
|
||||
|
||||
/** 出生日期,yyyy-MM-dd */
|
||||
private String birthDate;
|
||||
|
||||
/** 返回数量上限 */
|
||||
private Integer limit;
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.ruoyi.ccdi.project.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 资金流图谱汇总边
|
||||
*/
|
||||
@Data
|
||||
public class CcdiFundGraphEdgeVO {
|
||||
|
||||
private String edgeKey;
|
||||
|
||||
private String fromKey;
|
||||
|
||||
private String toKey;
|
||||
|
||||
private String fromObjectKey;
|
||||
|
||||
private String toObjectKey;
|
||||
|
||||
private String fromName;
|
||||
|
||||
private String toName;
|
||||
|
||||
private BigDecimal totalAmount;
|
||||
|
||||
private Long transactionCount;
|
||||
|
||||
private String firstTrxDate;
|
||||
|
||||
private String lastTrxDate;
|
||||
|
||||
private String direction;
|
||||
|
||||
private String familyRelationType;
|
||||
|
||||
private String sourceType;
|
||||
|
||||
private String relationDesc;
|
||||
|
||||
private String sourceDesc;
|
||||
|
||||
private String remark;
|
||||
|
||||
private Integer depth;
|
||||
|
||||
private Boolean canTrace;
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package com.ruoyi.ccdi.project.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 资金流图谱节点
|
||||
*/
|
||||
@Data
|
||||
public class CcdiFundGraphNodeVO {
|
||||
|
||||
private String nodeKey;
|
||||
|
||||
private String objectKey;
|
||||
|
||||
private String nodeName;
|
||||
|
||||
private String idNo;
|
||||
|
||||
private String cinocsno;
|
||||
|
||||
private String idnoType;
|
||||
|
||||
private String staffId;
|
||||
|
||||
private String sourceType;
|
||||
|
||||
private String nodeType;
|
||||
|
||||
private String identityType;
|
||||
|
||||
private String relationType;
|
||||
|
||||
private Long accountCount;
|
||||
|
||||
private String createdTime;
|
||||
|
||||
private String updatedTime;
|
||||
|
||||
private Boolean canExpand;
|
||||
|
||||
private Integer depth;
|
||||
|
||||
private BigDecimal totalAmount;
|
||||
|
||||
private Long transactionCount;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.ruoyi.ccdi.project.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 资金流图谱边对应流水明细
|
||||
*/
|
||||
@Data
|
||||
public class CcdiFundGraphStatementVO {
|
||||
|
||||
private Long bankStatementId;
|
||||
|
||||
private String trxDate;
|
||||
|
||||
private String leAccountNo;
|
||||
|
||||
private String leAccountName;
|
||||
|
||||
private String customerAccountName;
|
||||
|
||||
private String customerAccountNo;
|
||||
|
||||
private String cashType;
|
||||
|
||||
private String userMemo;
|
||||
|
||||
private BigDecimal amount;
|
||||
|
||||
private String direction;
|
||||
|
||||
private String familyRelationType;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.ruoyi.ccdi.project.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 资金流图谱结果
|
||||
*/
|
||||
@Data
|
||||
public class CcdiFundGraphVO {
|
||||
|
||||
private CcdiFundGraphNodeVO centerNode;
|
||||
|
||||
private List<CcdiFundGraphNodeVO> nodes = new ArrayList<>();
|
||||
|
||||
private List<CcdiFundGraphEdgeVO> edges = new ArrayList<>();
|
||||
|
||||
private BigDecimal totalAmount = BigDecimal.ZERO;
|
||||
|
||||
private Long transactionCount = 0L;
|
||||
|
||||
private Integer maxDepth = 1;
|
||||
|
||||
private Boolean traceReserved = true;
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.ruoyi.ccdi.project.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 关系图谱边
|
||||
*/
|
||||
@Data
|
||||
public class CcdiRelationGraphEdgeVO {
|
||||
|
||||
private String objectKey;
|
||||
|
||||
private String fromKey;
|
||||
|
||||
private String toKey;
|
||||
|
||||
private String fromObjectKey;
|
||||
|
||||
private String toObjectKey;
|
||||
|
||||
private String fromName;
|
||||
|
||||
private String toName;
|
||||
|
||||
private String edgeTable;
|
||||
|
||||
private String relationType;
|
||||
|
||||
private String companyName;
|
||||
|
||||
private String stockName;
|
||||
|
||||
private String stockType;
|
||||
|
||||
private String stockPercent;
|
||||
|
||||
private String shouldCapi;
|
||||
|
||||
private String shouldCapiValue;
|
||||
|
||||
private String shouldCapiUnit;
|
||||
|
||||
private String shoudDate;
|
||||
|
||||
private String pKeyNo;
|
||||
|
||||
private String operName;
|
||||
|
||||
private String operKeyNo;
|
||||
|
||||
private String personId;
|
||||
|
||||
private String relationName;
|
||||
|
||||
private String relationCertNo;
|
||||
|
||||
private String gender;
|
||||
|
||||
private String birthDate;
|
||||
|
||||
private String relationCertType;
|
||||
|
||||
private String mobilePhone1;
|
||||
|
||||
private String mobilePhone2;
|
||||
|
||||
private String wechatNo1;
|
||||
|
||||
private String wechatNo2;
|
||||
|
||||
private String wechatNo3;
|
||||
|
||||
private String contactAddress;
|
||||
|
||||
private BigDecimal annualIncome;
|
||||
|
||||
private String relationDesc;
|
||||
|
||||
private String status;
|
||||
|
||||
private String effectiveDate;
|
||||
|
||||
private String invalidDate;
|
||||
|
||||
private String remark;
|
||||
|
||||
private String dataSource;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.ruoyi.ccdi.project.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 关系图谱节点
|
||||
*/
|
||||
@Data
|
||||
public class CcdiRelationGraphNodeVO {
|
||||
|
||||
private String objectKey;
|
||||
|
||||
private String nodeKey;
|
||||
|
||||
private String nodeName;
|
||||
|
||||
private String idNumber;
|
||||
|
||||
private String subjectType;
|
||||
|
||||
private String sourceType;
|
||||
|
||||
private String detailRefType;
|
||||
|
||||
private String detailRefKey;
|
||||
|
||||
private String createdTime;
|
||||
|
||||
private String updatedTime;
|
||||
|
||||
private Boolean canExpand;
|
||||
|
||||
private Integer depth;
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.ruoyi.ccdi.project.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 关系图谱疑似企业明细
|
||||
*/
|
||||
@Data
|
||||
public class CcdiRelationGraphSuspectedEnterpriseItemVO {
|
||||
|
||||
private String candidateKeyNo;
|
||||
|
||||
private String personName;
|
||||
|
||||
private String companyId;
|
||||
|
||||
private String companyName;
|
||||
|
||||
private String creditCode;
|
||||
|
||||
private String enterpriseStatus;
|
||||
|
||||
private String industryName;
|
||||
|
||||
private String relationType;
|
||||
|
||||
private String stockPercent;
|
||||
|
||||
/** 企业成立日期或当前可用的工商关系日期 */
|
||||
private String establishDate;
|
||||
|
||||
private Integer ageAtEstablish;
|
||||
|
||||
private String matchReason;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.ruoyi.ccdi.project.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 关系图谱疑似企业结果
|
||||
*/
|
||||
@Data
|
||||
public class CcdiRelationGraphSuspectedEnterpriseVO {
|
||||
|
||||
/** 是否因同名候选过多被拦截 */
|
||||
private Boolean blocked = false;
|
||||
|
||||
/** 拦截或空结果说明 */
|
||||
private String message;
|
||||
|
||||
/** 同名工商keyno数量 */
|
||||
private Integer sameNameKeyNoCount = 0;
|
||||
|
||||
/** 表格明细 */
|
||||
private List<CcdiRelationGraphSuspectedEnterpriseItemVO> rows = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.ruoyi.ccdi.project.domain.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 关系图谱结果
|
||||
*/
|
||||
@Data
|
||||
public class CcdiRelationGraphVO {
|
||||
|
||||
private CcdiRelationGraphNodeVO centerNode;
|
||||
|
||||
private List<CcdiRelationGraphNodeVO> nodes = new ArrayList<>();
|
||||
|
||||
private List<CcdiRelationGraphEdgeVO> edges = new ArrayList<>();
|
||||
|
||||
private Long edgeCount = 0L;
|
||||
|
||||
private Integer maxDepth = 1;
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.ruoyi.ccdi.project.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiFundGraphEdgeDetailQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiFundGraphManualEdgeSaveDTO;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiFundGraphQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphEdgeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphNodeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphStatementVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 资金流图谱Mapper
|
||||
*/
|
||||
@Mapper
|
||||
public interface CcdiFundGraphMapper {
|
||||
|
||||
List<CcdiFundGraphNodeVO> selectFundGraphSubjects(@Param("query") CcdiFundGraphQueryDTO query);
|
||||
|
||||
List<CcdiFundGraphEdgeVO> selectFundGraphEdges(@Param("query") CcdiFundGraphQueryDTO query);
|
||||
|
||||
List<CcdiFundGraphEdgeVO> selectFundGraphManualEdges(@Param("query") CcdiFundGraphQueryDTO query);
|
||||
|
||||
int countSubjectByObjectKey(@Param("objectKey") String objectKey);
|
||||
|
||||
int insertManualSubject(
|
||||
@Param("objectKey") String objectKey,
|
||||
@Param("idNo") String idNo,
|
||||
@Param("name") String name
|
||||
);
|
||||
|
||||
int insertManualEdge(
|
||||
@Param("objectKey") String objectKey,
|
||||
@Param("dto") CcdiFundGraphManualEdgeSaveDTO dto,
|
||||
@Param("operator") String operator
|
||||
);
|
||||
|
||||
Page<CcdiFundGraphStatementVO> selectFundGraphEdgeDetails(
|
||||
Page<CcdiFundGraphStatementVO> page,
|
||||
@Param("query") CcdiFundGraphEdgeDetailQueryDTO query
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.ruoyi.ccdi.project.mapper;
|
||||
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiRelationGraphQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphEdgeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphNodeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphSuspectedEnterpriseItemVO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 关系图谱Mapper
|
||||
*/
|
||||
@Mapper
|
||||
public interface CcdiRelationGraphMapper {
|
||||
|
||||
List<CcdiRelationGraphNodeVO> selectRelationGraphSubjects(@Param("query") CcdiRelationGraphQueryDTO query);
|
||||
|
||||
List<CcdiRelationGraphNodeVO> selectRelationGraphNodesByKeys(@Param("objectKeys") List<String> objectKeys);
|
||||
|
||||
List<CcdiRelationGraphEdgeVO> selectRelationGraphEdges(@Param("query") CcdiRelationGraphQueryDTO query);
|
||||
|
||||
int countSuspectedEnterpriseKeyNos(@Param("personName") String personName);
|
||||
|
||||
List<CcdiRelationGraphSuspectedEnterpriseItemVO> selectSuspectedEnterprises(@Param("personName") String personName,
|
||||
@Param("limit") Integer limit);
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package com.ruoyi.ccdi.project.service;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiFundGraphEdgeDetailQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiFundGraphManualEdgeSaveDTO;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiFundGraphQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphEdgeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphNodeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphStatementVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 资金流图谱Service接口
|
||||
*/
|
||||
public interface ICcdiFundGraphService {
|
||||
|
||||
List<CcdiFundGraphNodeVO> searchSubjects(CcdiFundGraphQueryDTO queryDTO);
|
||||
|
||||
CcdiFundGraphVO getFundGraph(CcdiFundGraphQueryDTO queryDTO);
|
||||
|
||||
Page<CcdiFundGraphStatementVO> getEdgeDetails(
|
||||
Page<CcdiFundGraphStatementVO> page,
|
||||
CcdiFundGraphEdgeDetailQueryDTO queryDTO
|
||||
);
|
||||
|
||||
CcdiFundGraphEdgeVO saveManualEdge(CcdiFundGraphManualEdgeSaveDTO saveDTO, String operator);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.ruoyi.ccdi.project.service;
|
||||
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiRelationGraphQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiRelationGraphSuspectedEnterpriseQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphNodeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphSuspectedEnterpriseVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphVO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 关系图谱Service接口
|
||||
*/
|
||||
public interface ICcdiRelationGraphService {
|
||||
|
||||
List<CcdiRelationGraphNodeVO> searchSubjects(CcdiRelationGraphQueryDTO queryDTO);
|
||||
|
||||
CcdiRelationGraphVO getRelationGraph(CcdiRelationGraphQueryDTO queryDTO);
|
||||
|
||||
CcdiRelationGraphSuspectedEnterpriseVO getSuspectedEnterprises(CcdiRelationGraphSuspectedEnterpriseQueryDTO queryDTO);
|
||||
}
|
||||
@@ -0,0 +1,366 @@
|
||||
package com.ruoyi.ccdi.project.service.impl;
|
||||
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiFundGraphEdgeDetailQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiFundGraphManualEdgeSaveDTO;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiFundGraphQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphEdgeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphNodeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphStatementVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphVO;
|
||||
import com.ruoyi.ccdi.project.mapper.CcdiFundGraphMapper;
|
||||
import com.ruoyi.ccdi.project.service.ICcdiFundGraphService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.DigestUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* 资金流图谱Service实现
|
||||
*/
|
||||
@Service
|
||||
public class CcdiFundGraphServiceImpl implements ICcdiFundGraphService {
|
||||
|
||||
private static final int DEFAULT_LIMIT = 20;
|
||||
private static final int MAX_LIMIT = 100;
|
||||
private static final BigDecimal DEFAULT_MIN_TOTAL_AMOUNT = new BigDecimal("1000");
|
||||
private static final Comparator<CcdiFundGraphEdgeVO> EDGE_COMPARATOR = Comparator
|
||||
.comparing(CcdiFundGraphServiceImpl::safeAmount, Comparator.reverseOrder())
|
||||
.thenComparing(CcdiFundGraphServiceImpl::safeTransactionCount, Comparator.reverseOrder())
|
||||
.thenComparing(CcdiFundGraphServiceImpl::safeDateText, Comparator.reverseOrder())
|
||||
.thenComparing(edge -> normalizeSortText(edge == null ? null : edge.getEdgeKey()));
|
||||
|
||||
@Resource
|
||||
private CcdiFundGraphMapper fundGraphMapper;
|
||||
|
||||
@Override
|
||||
public List<CcdiFundGraphNodeVO> searchSubjects(CcdiFundGraphQueryDTO queryDTO) {
|
||||
CcdiFundGraphQueryDTO query = normalizeGraphQuery(queryDTO);
|
||||
if (isBlank(query.getKeyword()) && isBlank(query.getObjectKey())) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return fundGraphMapper.selectFundGraphSubjects(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CcdiFundGraphVO getFundGraph(CcdiFundGraphQueryDTO queryDTO) {
|
||||
CcdiFundGraphQueryDTO query = normalizeGraphQuery(queryDTO);
|
||||
CcdiFundGraphNodeVO centerNode = resolveCenterNode(query);
|
||||
if (centerNode == null || isBlank(centerNode.getObjectKey())) {
|
||||
return new CcdiFundGraphVO();
|
||||
}
|
||||
|
||||
query.setObjectKey(centerNode.getObjectKey());
|
||||
List<CcdiFundGraphEdgeVO> edges = new ArrayList<>();
|
||||
List<CcdiFundGraphEdgeVO> realEdges = fundGraphMapper.selectFundGraphEdges(query);
|
||||
if (realEdges != null) {
|
||||
edges.addAll(realEdges);
|
||||
}
|
||||
List<CcdiFundGraphEdgeVO> manualEdges = fundGraphMapper.selectFundGraphManualEdges(query);
|
||||
if (manualEdges != null) {
|
||||
edges.addAll(manualEdges);
|
||||
}
|
||||
edges = sortAndLimitEdges(edges, query.getLimit());
|
||||
CcdiFundGraphVO graph = new CcdiFundGraphVO();
|
||||
graph.setCenterNode(centerNode);
|
||||
graph.setEdges(edges);
|
||||
graph.setNodes(buildNodes(centerNode, edges));
|
||||
graph.setTransactionCount(edges.stream()
|
||||
.map(CcdiFundGraphEdgeVO::getTransactionCount)
|
||||
.filter(item -> item != null)
|
||||
.reduce(0L, Long::sum));
|
||||
graph.setTotalAmount(edges.stream()
|
||||
.map(CcdiFundGraphEdgeVO::getTotalAmount)
|
||||
.filter(item -> item != null)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add));
|
||||
graph.setMaxDepth(1);
|
||||
graph.setTraceReserved(true);
|
||||
return graph;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<CcdiFundGraphStatementVO> getEdgeDetails(
|
||||
Page<CcdiFundGraphStatementVO> page,
|
||||
CcdiFundGraphEdgeDetailQueryDTO queryDTO
|
||||
) {
|
||||
CcdiFundGraphEdgeDetailQueryDTO query = normalizeDetailQuery(queryDTO);
|
||||
if (isBlank(query.getFromKey()) || isBlank(query.getToKey())) {
|
||||
return page;
|
||||
}
|
||||
return fundGraphMapper.selectFundGraphEdgeDetails(page, query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CcdiFundGraphEdgeVO saveManualEdge(CcdiFundGraphManualEdgeSaveDTO saveDTO, String operator) {
|
||||
CcdiFundGraphManualEdgeSaveDTO dto = normalizeManualEdge(saveDTO);
|
||||
String fromObjectKey = dto.getFromObjectKey();
|
||||
String toObjectKey = resolveManualToObjectKey(dto);
|
||||
dto.setToObjectKey(toObjectKey);
|
||||
|
||||
String edgeObjectKey = md5("MANUAL_EDGE|" + fromObjectKey + "|" + toObjectKey + "|" + dto.getDirection()
|
||||
+ "|" + UUID.randomUUID());
|
||||
fundGraphMapper.insertManualEdge(edgeObjectKey, dto, normalizeText(operator));
|
||||
|
||||
CcdiFundGraphEdgeVO edge = new CcdiFundGraphEdgeVO();
|
||||
edge.setEdgeKey(edgeObjectKey);
|
||||
edge.setFromKey(toSubjectKey(fromObjectKey));
|
||||
edge.setToKey(toSubjectKey(toObjectKey));
|
||||
edge.setFromObjectKey(fromObjectKey);
|
||||
edge.setToObjectKey(toObjectKey);
|
||||
edge.setFromName(dto.getFromName());
|
||||
edge.setToName(dto.getToName());
|
||||
edge.setTotalAmount(dto.getAmount());
|
||||
edge.setTransactionCount(dto.getTransactionCount() == null ? 1L : dto.getTransactionCount().longValue());
|
||||
edge.setDirection(dto.getDirection());
|
||||
edge.setRelationDesc(dto.getRelationDesc());
|
||||
edge.setSourceDesc(dto.getSourceDesc());
|
||||
edge.setRemark(dto.getRemark());
|
||||
edge.setSourceType("MANUAL");
|
||||
edge.setDepth(1);
|
||||
edge.setCanTrace(false);
|
||||
return edge;
|
||||
}
|
||||
|
||||
private CcdiFundGraphNodeVO resolveCenterNode(CcdiFundGraphQueryDTO query) {
|
||||
if (isBlank(query.getObjectKey()) && isBlank(query.getKeyword())) {
|
||||
return null;
|
||||
}
|
||||
List<CcdiFundGraphNodeVO> subjects = fundGraphMapper.selectFundGraphSubjects(query);
|
||||
if (subjects == null || subjects.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return subjects.get(0);
|
||||
}
|
||||
|
||||
private List<CcdiFundGraphNodeVO> buildNodes(CcdiFundGraphNodeVO centerNode, List<CcdiFundGraphEdgeVO> edges) {
|
||||
Map<String, CcdiFundGraphNodeVO> nodeMap = new LinkedHashMap<>();
|
||||
Map<String, CcdiFundGraphNodeVO> subjectCache = new LinkedHashMap<>();
|
||||
subjectCache.put(centerNode.getObjectKey(), centerNode);
|
||||
addNode(nodeMap, centerNode, centerNode.getNodeKey(), centerNode.getObjectKey(), centerNode.getNodeName(),
|
||||
centerNode.getRelationType(), centerNode.getCanExpand(), BigDecimal.ZERO, 0L);
|
||||
|
||||
for (CcdiFundGraphEdgeVO edge : edges) {
|
||||
String centerObjectKey = centerNode.getObjectKey();
|
||||
String fromRelationType = centerObjectKey != null && centerObjectKey.equals(edge.getFromObjectKey())
|
||||
? null
|
||||
: edge.getFamilyRelationType();
|
||||
String toRelationType = centerObjectKey != null && centerObjectKey.equals(edge.getToObjectKey())
|
||||
? null
|
||||
: edge.getFamilyRelationType();
|
||||
addNode(nodeMap, lookupSubject(edge.getFromObjectKey(), subjectCache), edge.getFromKey(),
|
||||
edge.getFromObjectKey(), edge.getFromName(), fromRelationType, true, edge.getTotalAmount(),
|
||||
edge.getTransactionCount());
|
||||
addNode(nodeMap, lookupSubject(edge.getToObjectKey(), subjectCache), edge.getToKey(),
|
||||
edge.getToObjectKey(), edge.getToName(), toRelationType, edge.getCanTrace(),
|
||||
edge.getTotalAmount(), edge.getTransactionCount());
|
||||
}
|
||||
return List.copyOf(nodeMap.values());
|
||||
}
|
||||
|
||||
private CcdiFundGraphNodeVO lookupSubject(String objectKey, Map<String, CcdiFundGraphNodeVO> subjectCache) {
|
||||
if (isBlank(objectKey)) {
|
||||
return null;
|
||||
}
|
||||
if (subjectCache.containsKey(objectKey)) {
|
||||
return subjectCache.get(objectKey);
|
||||
}
|
||||
CcdiFundGraphQueryDTO query = new CcdiFundGraphQueryDTO();
|
||||
query.setObjectKey(objectKey);
|
||||
query.setLimit(DEFAULT_LIMIT);
|
||||
List<CcdiFundGraphNodeVO> subjects = fundGraphMapper.selectFundGraphSubjects(query);
|
||||
CcdiFundGraphNodeVO subject = subjects == null || subjects.isEmpty() ? null : subjects.get(0);
|
||||
subjectCache.put(objectKey, subject);
|
||||
return subject;
|
||||
}
|
||||
|
||||
private String resolveManualToObjectKey(CcdiFundGraphManualEdgeSaveDTO dto) {
|
||||
if (!isBlank(dto.getToObjectKey())) {
|
||||
ensureManualSubject(dto.getToObjectKey(), dto.getToIdNo(), dto.getToName());
|
||||
return dto.getToObjectKey();
|
||||
}
|
||||
String objectKey = !isBlank(dto.getToIdNo())
|
||||
? md5(dto.getToIdNo())
|
||||
: md5("MANUAL_NODE|" + dto.getToName() + "|" + UUID.randomUUID());
|
||||
dto.setToObjectKey(objectKey);
|
||||
ensureManualSubject(objectKey, dto.getToIdNo(), dto.getToName());
|
||||
return objectKey;
|
||||
}
|
||||
|
||||
private void ensureManualSubject(String objectKey, String idNo, String name) {
|
||||
if (fundGraphMapper.countSubjectByObjectKey(objectKey) > 0) {
|
||||
return;
|
||||
}
|
||||
fundGraphMapper.insertManualSubject(objectKey, normalizeText(idNo), normalizeText(name));
|
||||
}
|
||||
|
||||
private CcdiFundGraphManualEdgeSaveDTO normalizeManualEdge(CcdiFundGraphManualEdgeSaveDTO saveDTO) {
|
||||
CcdiFundGraphManualEdgeSaveDTO dto = saveDTO == null ? new CcdiFundGraphManualEdgeSaveDTO() : saveDTO;
|
||||
dto.setFromObjectKey(normalizeText(dto.getFromObjectKey()));
|
||||
dto.setFromName(normalizeText(dto.getFromName()));
|
||||
dto.setToObjectKey(normalizeText(dto.getToObjectKey()));
|
||||
dto.setToName(normalizeText(dto.getToName()));
|
||||
dto.setToIdNo(normalizeText(dto.getToIdNo()));
|
||||
dto.setDirection(normalizeText(dto.getDirection()));
|
||||
dto.setRelationDesc(normalizeText(dto.getRelationDesc()));
|
||||
dto.setSourceDesc(normalizeText(dto.getSourceDesc()));
|
||||
dto.setRemark(normalizeText(dto.getRemark()));
|
||||
if (isBlank(dto.getFromObjectKey())) {
|
||||
throw new IllegalArgumentException("起点主体不能为空");
|
||||
}
|
||||
if (isBlank(dto.getToObjectKey()) && isBlank(dto.getToName())) {
|
||||
throw new IllegalArgumentException("终点主体不能为空");
|
||||
}
|
||||
if (isBlank(dto.getDirection())) {
|
||||
dto.setDirection("1");
|
||||
}
|
||||
if (dto.getAmount() == null) {
|
||||
dto.setAmount(BigDecimal.ZERO);
|
||||
}
|
||||
if (dto.getTransactionCount() == null || dto.getTransactionCount() <= 0) {
|
||||
dto.setTransactionCount(1);
|
||||
}
|
||||
return dto;
|
||||
}
|
||||
|
||||
private void addNode(
|
||||
Map<String, CcdiFundGraphNodeVO> nodeMap,
|
||||
CcdiFundGraphNodeVO subject,
|
||||
String nodeKey,
|
||||
String objectKey,
|
||||
String nodeName,
|
||||
String relationType,
|
||||
Boolean canExpand,
|
||||
BigDecimal edgeAmount,
|
||||
Long edgeCount
|
||||
) {
|
||||
if (isBlank(nodeKey)) {
|
||||
return;
|
||||
}
|
||||
CcdiFundGraphNodeVO node = nodeMap.computeIfAbsent(nodeKey, key -> {
|
||||
CcdiFundGraphNodeVO item = new CcdiFundGraphNodeVO();
|
||||
item.setNodeKey(key);
|
||||
item.setObjectKey(objectKey);
|
||||
item.setNodeName(subject != null && !isBlank(subject.getNodeName())
|
||||
? subject.getNodeName()
|
||||
: (isBlank(nodeName) ? "未知主体" : nodeName));
|
||||
item.setIdNo(subject == null ? null : subject.getIdNo());
|
||||
item.setCinocsno(subject == null ? null : subject.getCinocsno());
|
||||
item.setIdnoType(subject == null ? null : subject.getIdnoType());
|
||||
item.setStaffId(subject == null ? null : subject.getStaffId());
|
||||
item.setSourceType(subject == null ? null : subject.getSourceType());
|
||||
item.setNodeType(subject != null && !isBlank(subject.getNodeType()) ? subject.getNodeType() : "PERSON");
|
||||
item.setIdentityType(subject != null && !isBlank(subject.getIdentityType()) ? subject.getIdentityType() : "IDNO");
|
||||
item.setRelationType(relationType);
|
||||
item.setAccountCount(subject == null ? 0L : subject.getAccountCount());
|
||||
item.setCreatedTime(subject == null ? null : subject.getCreatedTime());
|
||||
item.setUpdatedTime(subject == null ? null : subject.getUpdatedTime());
|
||||
item.setCanExpand(Boolean.TRUE.equals(canExpand));
|
||||
item.setDepth(1);
|
||||
item.setTotalAmount(BigDecimal.ZERO);
|
||||
item.setTransactionCount(0L);
|
||||
return item;
|
||||
});
|
||||
if (isBlank(node.getObjectKey())) {
|
||||
node.setObjectKey(objectKey);
|
||||
}
|
||||
if (isBlank(node.getRelationType())) {
|
||||
node.setRelationType(relationType);
|
||||
}
|
||||
if (Boolean.TRUE.equals(canExpand)) {
|
||||
node.setCanExpand(true);
|
||||
}
|
||||
node.setTotalAmount(node.getTotalAmount().add(edgeAmount == null ? BigDecimal.ZERO : edgeAmount));
|
||||
node.setTransactionCount(node.getTransactionCount() + (edgeCount == null ? 0L : edgeCount));
|
||||
}
|
||||
|
||||
private CcdiFundGraphQueryDTO normalizeGraphQuery(CcdiFundGraphQueryDTO queryDTO) {
|
||||
CcdiFundGraphQueryDTO query = queryDTO == null ? new CcdiFundGraphQueryDTO() : queryDTO;
|
||||
query.setKeyword(normalizeText(query.getKeyword()));
|
||||
query.setObjectKey(normalizeText(query.getObjectKey()));
|
||||
query.setTransactionStartTime(normalizeText(query.getTransactionStartTime()));
|
||||
query.setTransactionEndTime(normalizeText(query.getTransactionEndTime()));
|
||||
query.setDirection(normalizeText(query.getDirection()));
|
||||
if (query.getMinTotalAmount() == null) {
|
||||
query.setMinTotalAmount(DEFAULT_MIN_TOTAL_AMOUNT);
|
||||
}
|
||||
query.setLimit(normalizeLimit(query.getLimit()));
|
||||
query.setDepth(1);
|
||||
return query;
|
||||
}
|
||||
|
||||
private CcdiFundGraphEdgeDetailQueryDTO normalizeDetailQuery(CcdiFundGraphEdgeDetailQueryDTO queryDTO) {
|
||||
CcdiFundGraphEdgeDetailQueryDTO query = queryDTO == null ? new CcdiFundGraphEdgeDetailQueryDTO() : queryDTO;
|
||||
query.setKeyword(normalizeText(query.getKeyword()));
|
||||
query.setFromKey(normalizeText(query.getFromKey()));
|
||||
query.setToKey(normalizeText(query.getToKey()));
|
||||
query.setDirection(normalizeText(query.getDirection()));
|
||||
query.setTransactionStartTime(normalizeText(query.getTransactionStartTime()));
|
||||
query.setTransactionEndTime(normalizeText(query.getTransactionEndTime()));
|
||||
return query;
|
||||
}
|
||||
|
||||
private Integer normalizeLimit(Integer limit) {
|
||||
if (limit == null || limit <= 0) {
|
||||
return DEFAULT_LIMIT;
|
||||
}
|
||||
return Math.min(limit, MAX_LIMIT);
|
||||
}
|
||||
|
||||
private List<CcdiFundGraphEdgeVO> sortAndLimitEdges(List<CcdiFundGraphEdgeVO> edges, Integer limit) {
|
||||
if (edges == null || edges.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<CcdiFundGraphEdgeVO> sorted = new ArrayList<>(edges);
|
||||
sorted.sort(EDGE_COMPARATOR);
|
||||
int finalLimit = normalizeLimit(limit);
|
||||
if (sorted.size() > finalLimit) {
|
||||
return List.copyOf(sorted.subList(0, finalLimit));
|
||||
}
|
||||
return List.copyOf(sorted);
|
||||
}
|
||||
|
||||
private String normalizeText(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String trimmed = value.trim();
|
||||
return trimmed.isEmpty() ? null : trimmed;
|
||||
}
|
||||
|
||||
private boolean isBlank(String value) {
|
||||
return value == null || value.trim().isEmpty();
|
||||
}
|
||||
|
||||
private String toSubjectKey(String objectKey) {
|
||||
return "idno_node/" + objectKey;
|
||||
}
|
||||
|
||||
private String md5(String value) {
|
||||
return DigestUtils.md5DigestAsHex(value.trim().getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
private static BigDecimal safeAmount(CcdiFundGraphEdgeVO edge) {
|
||||
return edge == null || edge.getTotalAmount() == null ? BigDecimal.ZERO : edge.getTotalAmount();
|
||||
}
|
||||
|
||||
private static Long safeTransactionCount(CcdiFundGraphEdgeVO edge) {
|
||||
return edge == null || edge.getTransactionCount() == null ? 0L : edge.getTransactionCount();
|
||||
}
|
||||
|
||||
private static String safeDateText(CcdiFundGraphEdgeVO edge) {
|
||||
return normalizeSortText(edge == null ? null : edge.getLastTrxDate());
|
||||
}
|
||||
|
||||
private static String normalizeSortText(String value) {
|
||||
return value == null ? "" : value;
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import com.ruoyi.ccdi.project.service.ICcdiProjectService;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -53,6 +54,7 @@ public class CcdiModelParamServiceImpl implements ICcdiModelParamService {
|
||||
private ICcdiProjectService projectService;
|
||||
|
||||
@Resource
|
||||
@Lazy
|
||||
private ICcdiBankTagService bankTagService;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -57,6 +57,7 @@ import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@@ -90,6 +91,7 @@ public class CcdiProjectOverviewServiceImpl implements ICcdiProjectOverviewServi
|
||||
private CcdiProjectOverviewReportPdfExporter reportPdfExporter;
|
||||
|
||||
@Resource
|
||||
@Lazy
|
||||
private ICcdiModelParamService modelParamService;
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
package com.ruoyi.ccdi.project.service.impl;
|
||||
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiRelationGraphQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.dto.CcdiRelationGraphSuspectedEnterpriseQueryDTO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphEdgeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphNodeVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphSuspectedEnterpriseItemVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphSuspectedEnterpriseVO;
|
||||
import com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphVO;
|
||||
import com.ruoyi.ccdi.project.mapper.CcdiRelationGraphMapper;
|
||||
import com.ruoyi.ccdi.project.service.ICcdiRelationGraphService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.time.LocalDate;
|
||||
import java.time.Period;
|
||||
import java.time.format.DateTimeFormatter;
|
||||
import java.time.format.DateTimeParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 关系图谱Service实现
|
||||
*/
|
||||
@Service
|
||||
public class CcdiRelationGraphServiceImpl implements ICcdiRelationGraphService {
|
||||
|
||||
private static final int DEFAULT_LIMIT = 80;
|
||||
private static final int MAX_LIMIT = 200;
|
||||
private static final int DEFAULT_SUSPECTED_LIMIT = 10;
|
||||
private static final int MAX_SUSPECTED_LIMIT = 20;
|
||||
private static final int SAME_NAME_BLOCK_THRESHOLD = 20;
|
||||
private static final String NODE_PREFIX = "rel_node/";
|
||||
private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
||||
|
||||
@Resource
|
||||
private CcdiRelationGraphMapper relationGraphMapper;
|
||||
|
||||
@Override
|
||||
public List<CcdiRelationGraphNodeVO> searchSubjects(CcdiRelationGraphQueryDTO queryDTO) {
|
||||
CcdiRelationGraphQueryDTO query = normalizeGraphQuery(queryDTO);
|
||||
if (isBlank(query.getKeyword()) && isBlank(query.getObjectKey())) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return relationGraphMapper.selectRelationGraphSubjects(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CcdiRelationGraphVO getRelationGraph(CcdiRelationGraphQueryDTO queryDTO) {
|
||||
CcdiRelationGraphQueryDTO query = normalizeGraphQuery(queryDTO);
|
||||
CcdiRelationGraphNodeVO centerNode = resolveCenterNode(query);
|
||||
if (centerNode == null || isBlank(centerNode.getObjectKey())) {
|
||||
return new CcdiRelationGraphVO();
|
||||
}
|
||||
|
||||
query.setObjectKey(centerNode.getObjectKey());
|
||||
List<CcdiRelationGraphEdgeVO> edges = relationGraphMapper.selectRelationGraphEdges(query);
|
||||
if (edges == null) {
|
||||
edges = Collections.emptyList();
|
||||
}
|
||||
|
||||
List<CcdiRelationGraphNodeVO> nodes = buildNodes(centerNode, edges);
|
||||
CcdiRelationGraphVO graph = new CcdiRelationGraphVO();
|
||||
graph.setCenterNode(centerNode);
|
||||
graph.setNodes(nodes);
|
||||
graph.setEdges(edges);
|
||||
graph.setEdgeCount((long) edges.size());
|
||||
graph.setMaxDepth(1);
|
||||
return graph;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CcdiRelationGraphSuspectedEnterpriseVO getSuspectedEnterprises(CcdiRelationGraphSuspectedEnterpriseQueryDTO queryDTO) {
|
||||
CcdiRelationGraphSuspectedEnterpriseVO result = new CcdiRelationGraphSuspectedEnterpriseVO();
|
||||
CcdiRelationGraphSuspectedEnterpriseQueryDTO query = normalizeSuspectedEnterpriseQuery(queryDTO);
|
||||
if (isBlank(query.getPersonName())) {
|
||||
result.setMessage("缺少人员姓名,无法按工商同名主体召回");
|
||||
return result;
|
||||
}
|
||||
|
||||
int sameNameKeyNoCount = relationGraphMapper.countSuspectedEnterpriseKeyNos(query.getPersonName());
|
||||
result.setSameNameKeyNoCount(sameNameKeyNoCount);
|
||||
if (sameNameKeyNoCount > SAME_NAME_BLOCK_THRESHOLD) {
|
||||
result.setBlocked(true);
|
||||
result.setMessage("同名工商主体过多,请结合交易对手企业名称或其他线索进一步筛选");
|
||||
return result;
|
||||
}
|
||||
|
||||
LocalDate birthDate = resolveBirthDate(query);
|
||||
List<CcdiRelationGraphSuspectedEnterpriseItemVO> rows =
|
||||
relationGraphMapper.selectSuspectedEnterprises(query.getPersonName(), MAX_SUSPECTED_LIMIT);
|
||||
List<CcdiRelationGraphSuspectedEnterpriseItemVO> filteredRows = new ArrayList<>();
|
||||
if (rows != null) {
|
||||
for (CcdiRelationGraphSuspectedEnterpriseItemVO row : rows) {
|
||||
if (row == null) {
|
||||
continue;
|
||||
}
|
||||
row.setPersonName(query.getPersonName());
|
||||
if (applyAgeRule(row, birthDate)) {
|
||||
filteredRows.add(row);
|
||||
if (filteredRows.size() >= query.getLimit()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
result.setRows(filteredRows);
|
||||
if (filteredRows.isEmpty()) {
|
||||
result.setMessage("未发现可展示的疑似同名企业");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private CcdiRelationGraphNodeVO resolveCenterNode(CcdiRelationGraphQueryDTO query) {
|
||||
List<CcdiRelationGraphNodeVO> subjects = relationGraphMapper.selectRelationGraphSubjects(query);
|
||||
if (subjects == null || subjects.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return subjects.get(0);
|
||||
}
|
||||
|
||||
private List<CcdiRelationGraphNodeVO> buildNodes(CcdiRelationGraphNodeVO centerNode, List<CcdiRelationGraphEdgeVO> edges) {
|
||||
Set<String> objectKeys = new LinkedHashSet<>();
|
||||
objectKeys.add(centerNode.getObjectKey());
|
||||
for (CcdiRelationGraphEdgeVO edge : edges) {
|
||||
edge.setFromObjectKey(toObjectKey(edge.getFromKey()));
|
||||
edge.setToObjectKey(toObjectKey(edge.getToKey()));
|
||||
if (!isBlank(edge.getFromObjectKey())) {
|
||||
objectKeys.add(edge.getFromObjectKey());
|
||||
}
|
||||
if (!isBlank(edge.getToObjectKey())) {
|
||||
objectKeys.add(edge.getToObjectKey());
|
||||
}
|
||||
}
|
||||
|
||||
List<CcdiRelationGraphNodeVO> rawNodes = relationGraphMapper.selectRelationGraphNodesByKeys(new ArrayList<>(objectKeys));
|
||||
Map<String, CcdiRelationGraphNodeVO> nodeMap = new LinkedHashMap<>();
|
||||
if (rawNodes != null) {
|
||||
for (CcdiRelationGraphNodeVO node : rawNodes) {
|
||||
enrichNode(node, centerNode);
|
||||
nodeMap.put(node.getObjectKey(), node);
|
||||
}
|
||||
}
|
||||
if (!nodeMap.containsKey(centerNode.getObjectKey())) {
|
||||
enrichNode(centerNode, centerNode);
|
||||
nodeMap.put(centerNode.getObjectKey(), centerNode);
|
||||
}
|
||||
|
||||
for (CcdiRelationGraphEdgeVO edge : edges) {
|
||||
CcdiRelationGraphNodeVO fromNode = nodeMap.get(edge.getFromObjectKey());
|
||||
CcdiRelationGraphNodeVO toNode = nodeMap.get(edge.getToObjectKey());
|
||||
if (fromNode != null) {
|
||||
edge.setFromName(fromNode.getNodeName());
|
||||
}
|
||||
if (toNode != null) {
|
||||
edge.setToName(toNode.getNodeName());
|
||||
}
|
||||
}
|
||||
return List.copyOf(nodeMap.values());
|
||||
}
|
||||
|
||||
private void enrichNode(CcdiRelationGraphNodeVO node, CcdiRelationGraphNodeVO centerNode) {
|
||||
if (node == null) {
|
||||
return;
|
||||
}
|
||||
node.setNodeKey(NODE_PREFIX + node.getObjectKey());
|
||||
node.setCanExpand(true);
|
||||
node.setDepth(node.getObjectKey() != null && node.getObjectKey().equals(centerNode.getObjectKey()) ? 0 : 1);
|
||||
}
|
||||
|
||||
private CcdiRelationGraphQueryDTO normalizeGraphQuery(CcdiRelationGraphQueryDTO queryDTO) {
|
||||
CcdiRelationGraphQueryDTO query = queryDTO == null ? new CcdiRelationGraphQueryDTO() : queryDTO;
|
||||
query.setKeyword(normalizeText(query.getKeyword()));
|
||||
query.setObjectKey(normalizeText(query.getObjectKey()));
|
||||
query.setLimit(normalizeLimit(query.getLimit()));
|
||||
query.setDepth(1);
|
||||
return query;
|
||||
}
|
||||
|
||||
private CcdiRelationGraphSuspectedEnterpriseQueryDTO normalizeSuspectedEnterpriseQuery(CcdiRelationGraphSuspectedEnterpriseQueryDTO queryDTO) {
|
||||
CcdiRelationGraphSuspectedEnterpriseQueryDTO query =
|
||||
queryDTO == null ? new CcdiRelationGraphSuspectedEnterpriseQueryDTO() : queryDTO;
|
||||
query.setPersonName(normalizeText(query.getPersonName()));
|
||||
query.setCertNo(normalizeText(query.getCertNo()));
|
||||
query.setBirthDate(normalizeText(query.getBirthDate()));
|
||||
query.setLimit(normalizeSuspectedLimit(query.getLimit()));
|
||||
return query;
|
||||
}
|
||||
|
||||
private Integer normalizeSuspectedLimit(Integer limit) {
|
||||
if (limit == null || limit <= 0) {
|
||||
return DEFAULT_SUSPECTED_LIMIT;
|
||||
}
|
||||
return Math.min(limit, MAX_SUSPECTED_LIMIT);
|
||||
}
|
||||
|
||||
private LocalDate resolveBirthDate(CcdiRelationGraphSuspectedEnterpriseQueryDTO query) {
|
||||
LocalDate explicitBirthDate = parseDate(query.getBirthDate());
|
||||
if (explicitBirthDate != null) {
|
||||
return explicitBirthDate;
|
||||
}
|
||||
return parseBirthDateFromCertNo(query.getCertNo());
|
||||
}
|
||||
|
||||
private boolean applyAgeRule(CcdiRelationGraphSuspectedEnterpriseItemVO row, LocalDate birthDate) {
|
||||
LocalDate establishDate = parseDate(row.getEstablishDate());
|
||||
if (birthDate == null || establishDate == null) {
|
||||
row.setMatchReason("姓名一致;企业成立日期或出生日期缺失,年龄无法判断");
|
||||
return true;
|
||||
}
|
||||
int age = Period.between(birthDate, establishDate).getYears();
|
||||
row.setAgeAtEstablish(age);
|
||||
if (age < 18) {
|
||||
return false;
|
||||
}
|
||||
row.setMatchReason("姓名一致;成立时年龄" + age + "岁");
|
||||
return true;
|
||||
}
|
||||
|
||||
private LocalDate parseBirthDateFromCertNo(String certNo) {
|
||||
if (isBlank(certNo)) {
|
||||
return null;
|
||||
}
|
||||
String value = certNo.trim();
|
||||
if (value.matches("^\\d{17}[0-9Xx]$")) {
|
||||
return parseCompactDate(value.substring(6, 14));
|
||||
}
|
||||
if (value.matches("^\\d{15}$")) {
|
||||
return parseCompactDate("19" + value.substring(6, 12));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private LocalDate parseCompactDate(String value) {
|
||||
try {
|
||||
return LocalDate.parse(value, DateTimeFormatter.BASIC_ISO_DATE);
|
||||
} catch (DateTimeParseException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private LocalDate parseDate(String value) {
|
||||
if (isBlank(value)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return LocalDate.parse(value.trim(), DATE_FORMATTER);
|
||||
} catch (DateTimeParseException ignored) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Integer normalizeLimit(Integer limit) {
|
||||
if (limit == null || limit <= 0) {
|
||||
return DEFAULT_LIMIT;
|
||||
}
|
||||
return Math.min(limit, MAX_LIMIT);
|
||||
}
|
||||
|
||||
private String toObjectKey(String nodeKey) {
|
||||
if (isBlank(nodeKey)) {
|
||||
return null;
|
||||
}
|
||||
return nodeKey.startsWith(NODE_PREFIX) ? nodeKey.substring(NODE_PREFIX.length()) : nodeKey;
|
||||
}
|
||||
|
||||
private String normalizeText(String value) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
String trimmed = value.trim();
|
||||
return trimmed.isEmpty() ? null : trimmed;
|
||||
}
|
||||
|
||||
private boolean isBlank(String value) {
|
||||
return value == null || value.trim().isEmpty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
<?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.ruoyi.ccdi.project.mapper.CcdiFundGraphMapper">
|
||||
|
||||
<resultMap id="FundGraphNodeResultMap" type="com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphNodeVO">
|
||||
<id property="objectKey" column="objectKey"/>
|
||||
<result property="nodeKey" column="nodeKey"/>
|
||||
<result property="nodeName" column="nodeName"/>
|
||||
<result property="idNo" column="idNo"/>
|
||||
<result property="cinocsno" column="cinocsno"/>
|
||||
<result property="idnoType" column="idnoType"/>
|
||||
<result property="staffId" column="staffId"/>
|
||||
<result property="sourceType" column="sourceType"/>
|
||||
<result property="nodeType" column="nodeType"/>
|
||||
<result property="identityType" column="identityType"/>
|
||||
<result property="relationType" column="relationType"/>
|
||||
<result property="accountCount" column="accountCount"/>
|
||||
<result property="createdTime" column="createdTime"/>
|
||||
<result property="updatedTime" column="updatedTime"/>
|
||||
<result property="canExpand" column="canExpand"/>
|
||||
<result property="depth" column="depth"/>
|
||||
<result property="totalAmount" column="totalAmount"/>
|
||||
<result property="transactionCount" column="transactionCount"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap id="FundGraphEdgeResultMap" type="com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphEdgeVO">
|
||||
<id property="edgeKey" column="edgeKey"/>
|
||||
<result property="fromKey" column="fromKey"/>
|
||||
<result property="toKey" column="toKey"/>
|
||||
<result property="fromObjectKey" column="fromObjectKey"/>
|
||||
<result property="toObjectKey" column="toObjectKey"/>
|
||||
<result property="fromName" column="fromName"/>
|
||||
<result property="toName" column="toName"/>
|
||||
<result property="totalAmount" column="totalAmount"/>
|
||||
<result property="transactionCount" column="transactionCount"/>
|
||||
<result property="firstTrxDate" column="firstTrxDate"/>
|
||||
<result property="lastTrxDate" column="lastTrxDate"/>
|
||||
<result property="direction" column="direction"/>
|
||||
<result property="familyRelationType" column="familyRelationType"/>
|
||||
<result property="sourceType" column="sourceType"/>
|
||||
<result property="relationDesc" column="relationDesc"/>
|
||||
<result property="sourceDesc" column="sourceDesc"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="depth" column="depth"/>
|
||||
<result property="canTrace" column="canTrace"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap id="FundGraphStatementResultMap" type="com.ruoyi.ccdi.project.domain.vo.CcdiFundGraphStatementVO">
|
||||
<id property="bankStatementId" column="bankStatementId"/>
|
||||
<result property="trxDate" column="trxDate"/>
|
||||
<result property="leAccountNo" column="leAccountNo"/>
|
||||
<result property="leAccountName" column="leAccountName"/>
|
||||
<result property="customerAccountName" column="customerAccountName"/>
|
||||
<result property="customerAccountNo" column="customerAccountNo"/>
|
||||
<result property="cashType" column="cashType"/>
|
||||
<result property="userMemo" column="userMemo"/>
|
||||
<result property="amount" column="amount"/>
|
||||
<result property="direction" column="direction"/>
|
||||
<result property="familyRelationType" column="familyRelationType"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="detailFilter">
|
||||
<if test="query.transactionStartTime != null and query.transactionStartTime != ''">
|
||||
AND d.trx_date <![CDATA[ >= ]]> (#{query.transactionStartTime} COLLATE utf8mb4_general_ci)
|
||||
</if>
|
||||
<if test="query.transactionEndTime != null and query.transactionEndTime != ''">
|
||||
AND d.trx_date <![CDATA[ <= ]]>
|
||||
(CASE
|
||||
WHEN LENGTH(TRIM(#{query.transactionEndTime})) = 10
|
||||
THEN CONCAT(TRIM(#{query.transactionEndTime}), ' 23:59:59')
|
||||
ELSE TRIM(#{query.transactionEndTime})
|
||||
END COLLATE utf8mb4_general_ci)
|
||||
</if>
|
||||
<if test="query.amountMin != null">
|
||||
AND d.amount <![CDATA[ >= ]]> #{query.amountMin}
|
||||
</if>
|
||||
<if test="query.amountMax != null">
|
||||
AND d.amount <![CDATA[ <= ]]> #{query.amountMax}
|
||||
</if>
|
||||
<if test="query.direction != null and query.direction != ''">
|
||||
AND d.flag = (#{query.direction} COLLATE utf8mb4_general_ci)
|
||||
</if>
|
||||
</sql>
|
||||
|
||||
<sql id="subjectJoinRows">
|
||||
SELECT
|
||||
d.object_key AS detailObjectKey,
|
||||
d.bank_statement_id AS bankStatementId,
|
||||
d.trx_date AS trxDate,
|
||||
d.le_account_no AS leAccountNo,
|
||||
d.le_account_name AS leAccountName,
|
||||
d.customer_account_name AS customerAccountName,
|
||||
d.customer_account_no AS customerAccountNo,
|
||||
d.cash_type AS cashType,
|
||||
d.user_memo AS userMemo,
|
||||
d.amount,
|
||||
d.flag AS direction,
|
||||
d.family_relation_type AS familyRelationType,
|
||||
from_subject.object_key AS fromObjectKey,
|
||||
to_subject.object_key AS toObjectKey,
|
||||
CONCAT('idno_node/', from_subject.object_key) AS fromKey,
|
||||
CONCAT('idno_node/', to_subject.object_key) AS toKey,
|
||||
from_subject.name AS fromName,
|
||||
to_subject.name AS toName,
|
||||
from_subject.idnocfno AS fromIdNo,
|
||||
to_subject.idnocfno AS toIdNo
|
||||
FROM lx_fund_flow_detail_edge d
|
||||
INNER JOIN lx_fund_flow_own_account_edge from_own
|
||||
ON from_own.to_key = d.from_key
|
||||
INNER JOIN lx_fund_flow_subject_node from_subject
|
||||
ON CONCAT('idno_node/', from_subject.object_key) = from_own.from_key
|
||||
INNER JOIN lx_fund_flow_own_account_edge to_own
|
||||
ON to_own.to_key = d.to_key
|
||||
INNER JOIN lx_fund_flow_subject_node to_subject
|
||||
ON CONCAT('idno_node/', to_subject.object_key) = to_own.from_key
|
||||
WHERE 1 = 1
|
||||
<if test="query.objectKey != null and query.objectKey != ''">
|
||||
AND (
|
||||
from_subject.object_key = (#{query.objectKey} COLLATE utf8mb4_general_ci)
|
||||
OR to_subject.object_key = (#{query.objectKey} COLLATE utf8mb4_general_ci)
|
||||
)
|
||||
</if>
|
||||
<include refid="detailFilter"/>
|
||||
</sql>
|
||||
|
||||
<select id="selectFundGraphSubjects" resultMap="FundGraphNodeResultMap">
|
||||
SELECT
|
||||
n.object_key AS objectKey,
|
||||
CONCAT('idno_node/', n.object_key) AS nodeKey,
|
||||
n.name AS nodeName,
|
||||
n.idnocfno AS idNo,
|
||||
n.cinocsno AS cinocsno,
|
||||
n.idno_type AS idnoType,
|
||||
n.staff_id AS staffId,
|
||||
n.source_type AS sourceType,
|
||||
CASE
|
||||
WHEN n.idno_type = 'NAME_PROXY' OR n.source_type LIKE '%COUNTERPARTY%' THEN 'PROXY'
|
||||
ELSE 'PERSON'
|
||||
END AS nodeType,
|
||||
CASE
|
||||
WHEN n.idnocfno IS NOT NULL AND TRIM(n.idnocfno) != '' THEN 'IDNO'
|
||||
ELSE 'NAME'
|
||||
END AS identityType,
|
||||
CASE
|
||||
WHEN n.source_type LIKE 'GRAPH_TEST_FAMILY_%' THEN REPLACE(n.source_type, 'GRAPH_TEST_FAMILY_', '')
|
||||
ELSE NULL
|
||||
END AS relationType,
|
||||
CASE
|
||||
WHEN EXISTS (
|
||||
SELECT 1
|
||||
FROM lx_fund_flow_own_account_edge own
|
||||
WHERE own.from_key = CONCAT('idno_node/', n.object_key)
|
||||
) THEN 1
|
||||
ELSE 0
|
||||
END AS canExpand,
|
||||
(
|
||||
SELECT COUNT(1)
|
||||
FROM lx_fund_flow_own_account_edge own_count
|
||||
WHERE own_count.from_key = CONCAT('idno_node/', n.object_key)
|
||||
) AS accountCount,
|
||||
DATE_FORMAT(n.created_time, '%Y-%m-%d %H:%i:%s') AS createdTime,
|
||||
DATE_FORMAT(n.updated_time, '%Y-%m-%d %H:%i:%s') AS updatedTime,
|
||||
0 AS depth,
|
||||
0 AS totalAmount,
|
||||
0 AS transactionCount
|
||||
FROM lx_fund_flow_subject_node n
|
||||
WHERE 1 = 1
|
||||
<if test="query.objectKey != null and query.objectKey != ''">
|
||||
AND n.object_key = (#{query.objectKey} COLLATE utf8mb4_general_ci)
|
||||
</if>
|
||||
<if test="query.objectKey == null or query.objectKey == ''">
|
||||
<if test="query.keyword != null and query.keyword != ''">
|
||||
AND (
|
||||
n.idnocfno = (TRIM(#{query.keyword}) COLLATE utf8mb4_general_ci)
|
||||
OR n.name LIKE (CONCAT('%', TRIM(#{query.keyword}), '%') COLLATE utf8mb4_general_ci)
|
||||
OR n.object_key = (TRIM(#{query.keyword}) COLLATE utf8mb4_general_ci)
|
||||
)
|
||||
</if>
|
||||
</if>
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN n.idnocfno = (TRIM(IFNULL(#{query.keyword}, '')) COLLATE utf8mb4_general_ci) THEN 0
|
||||
WHEN n.object_key = (TRIM(IFNULL(#{query.keyword}, '')) COLLATE utf8mb4_general_ci) THEN 1
|
||||
WHEN n.staff_id IS NOT NULL AND TRIM(n.staff_id) != '' THEN 2
|
||||
WHEN UPPER(IFNULL(n.source_type, '')) LIKE '%EMPLOYEE%' THEN 2
|
||||
WHEN n.source_type LIKE '%员工%' THEN 2
|
||||
ELSE 3
|
||||
END,
|
||||
n.name
|
||||
LIMIT
|
||||
<choose>
|
||||
<when test="query.limit != null and query.limit > 0">
|
||||
#{query.limit}
|
||||
</when>
|
||||
<otherwise>
|
||||
20
|
||||
</otherwise>
|
||||
</choose>
|
||||
</select>
|
||||
|
||||
<select id="selectFundGraphEdges" resultMap="FundGraphEdgeResultMap">
|
||||
SELECT
|
||||
MD5(CONCAT(graph_rows.fromKey, '|', graph_rows.toKey, '|', graph_rows.direction, '|', IFNULL(graph_rows.familyRelationType, ''))) AS edgeKey,
|
||||
graph_rows.fromKey,
|
||||
graph_rows.toKey,
|
||||
graph_rows.fromObjectKey,
|
||||
graph_rows.toObjectKey,
|
||||
MAX(graph_rows.fromName) AS fromName,
|
||||
MAX(graph_rows.toName) AS toName,
|
||||
SUM(graph_rows.amount) AS totalAmount,
|
||||
COUNT(1) AS transactionCount,
|
||||
MIN(graph_rows.trxDate) AS firstTrxDate,
|
||||
MAX(graph_rows.trxDate) AS lastTrxDate,
|
||||
graph_rows.direction,
|
||||
graph_rows.familyRelationType,
|
||||
'BANK' AS sourceType,
|
||||
NULL AS relationDesc,
|
||||
NULL AS sourceDesc,
|
||||
NULL AS remark,
|
||||
1 AS depth,
|
||||
CASE
|
||||
WHEN MAX(
|
||||
CASE
|
||||
WHEN graph_rows.fromObjectKey = #{query.objectKey} THEN
|
||||
CASE
|
||||
WHEN graph_rows.toIdNo IS NOT NULL AND TRIM(graph_rows.toIdNo) != '' THEN 1
|
||||
ELSE 0
|
||||
END
|
||||
ELSE
|
||||
CASE
|
||||
WHEN graph_rows.fromIdNo IS NOT NULL AND TRIM(graph_rows.fromIdNo) != '' THEN 1
|
||||
ELSE 0
|
||||
END
|
||||
END
|
||||
) = 1 THEN 1
|
||||
WHEN EXISTS (
|
||||
SELECT 1
|
||||
FROM lx_fund_flow_own_account_edge own
|
||||
WHERE own.from_key = CASE
|
||||
WHEN graph_rows.fromObjectKey = #{query.objectKey}
|
||||
THEN graph_rows.toKey
|
||||
ELSE graph_rows.fromKey
|
||||
END
|
||||
) THEN 1
|
||||
ELSE 0
|
||||
END AS canTrace
|
||||
FROM (
|
||||
<include refid="subjectJoinRows"/>
|
||||
) graph_rows
|
||||
WHERE 1 = 1
|
||||
GROUP BY
|
||||
graph_rows.fromKey,
|
||||
graph_rows.toKey,
|
||||
graph_rows.fromObjectKey,
|
||||
graph_rows.toObjectKey,
|
||||
graph_rows.direction,
|
||||
graph_rows.familyRelationType
|
||||
<if test="query.minTotalAmount != null">
|
||||
HAVING SUM(graph_rows.amount) <![CDATA[ >= ]]> #{query.minTotalAmount}
|
||||
</if>
|
||||
ORDER BY totalAmount DESC, transactionCount DESC
|
||||
LIMIT #{query.limit}
|
||||
</select>
|
||||
|
||||
<select id="selectFundGraphManualEdges" resultMap="FundGraphEdgeResultMap">
|
||||
SELECT
|
||||
m.object_key AS edgeKey,
|
||||
CONCAT('idno_node/', m.from_object_key) AS fromKey,
|
||||
CONCAT('idno_node/', m.to_object_key) AS toKey,
|
||||
m.from_object_key AS fromObjectKey,
|
||||
m.to_object_key AS toObjectKey,
|
||||
COALESCE(from_subject.name, m.from_name) AS fromName,
|
||||
COALESCE(to_subject.name, m.to_name) AS toName,
|
||||
m.amount AS totalAmount,
|
||||
m.transaction_count AS transactionCount,
|
||||
DATE_FORMAT(m.created_time, '%Y-%m-%d %H:%i:%s') AS firstTrxDate,
|
||||
DATE_FORMAT(m.created_time, '%Y-%m-%d %H:%i:%s') AS lastTrxDate,
|
||||
m.direction,
|
||||
NULL AS familyRelationType,
|
||||
m.source_type AS sourceType,
|
||||
m.relation_desc AS relationDesc,
|
||||
m.source_desc AS sourceDesc,
|
||||
m.remark,
|
||||
1 AS depth,
|
||||
0 AS canTrace
|
||||
FROM lx_fund_flow_manual_edge m
|
||||
LEFT JOIN lx_fund_flow_subject_node from_subject
|
||||
ON from_subject.object_key = m.from_object_key
|
||||
LEFT JOIN lx_fund_flow_subject_node to_subject
|
||||
ON to_subject.object_key = m.to_object_key
|
||||
WHERE m.source_type = 'MANUAL'
|
||||
AND (
|
||||
m.from_object_key = (#{query.objectKey} COLLATE utf8mb4_general_ci)
|
||||
OR m.to_object_key = (#{query.objectKey} COLLATE utf8mb4_general_ci)
|
||||
)
|
||||
ORDER BY m.updated_time DESC
|
||||
LIMIT #{query.limit}
|
||||
</select>
|
||||
|
||||
<select id="selectFundGraphEdgeDetails" resultMap="FundGraphStatementResultMap">
|
||||
SELECT
|
||||
graph_rows.bankStatementId,
|
||||
graph_rows.trxDate,
|
||||
graph_rows.leAccountNo,
|
||||
graph_rows.leAccountName,
|
||||
graph_rows.customerAccountName,
|
||||
graph_rows.customerAccountNo,
|
||||
graph_rows.cashType,
|
||||
graph_rows.userMemo,
|
||||
graph_rows.amount,
|
||||
graph_rows.direction,
|
||||
graph_rows.familyRelationType
|
||||
FROM (
|
||||
<include refid="subjectJoinRows"/>
|
||||
) graph_rows
|
||||
WHERE graph_rows.fromKey = (#{query.fromKey} COLLATE utf8mb4_general_ci)
|
||||
AND graph_rows.toKey = (#{query.toKey} COLLATE utf8mb4_general_ci)
|
||||
<if test="query.direction != null and query.direction != ''">
|
||||
AND graph_rows.direction = (#{query.direction} COLLATE utf8mb4_general_ci)
|
||||
</if>
|
||||
ORDER BY graph_rows.trxDate DESC, graph_rows.bankStatementId DESC
|
||||
</select>
|
||||
|
||||
<select id="countSubjectByObjectKey" resultType="int">
|
||||
SELECT COUNT(1)
|
||||
FROM lx_fund_flow_subject_node
|
||||
WHERE object_key = (#{objectKey} COLLATE utf8mb4_general_ci)
|
||||
</select>
|
||||
|
||||
<insert id="insertManualSubject">
|
||||
INSERT IGNORE INTO lx_fund_flow_subject_node (
|
||||
object_key,
|
||||
idnocfno,
|
||||
name,
|
||||
idno_type,
|
||||
source_type
|
||||
) VALUES (
|
||||
#{objectKey},
|
||||
#{idNo},
|
||||
#{name},
|
||||
CASE
|
||||
WHEN #{idNo} IS NULL OR TRIM(#{idNo}) = '' THEN 'NAME_PROXY'
|
||||
ELSE 'PERSON'
|
||||
END,
|
||||
'MANUAL'
|
||||
)
|
||||
</insert>
|
||||
|
||||
<insert id="insertManualEdge">
|
||||
INSERT INTO lx_fund_flow_manual_edge (
|
||||
object_key,
|
||||
from_object_key,
|
||||
to_object_key,
|
||||
from_name,
|
||||
to_name,
|
||||
amount,
|
||||
transaction_count,
|
||||
direction,
|
||||
relation_desc,
|
||||
source_desc,
|
||||
remark,
|
||||
source_type,
|
||||
created_by,
|
||||
updated_by
|
||||
) VALUES (
|
||||
#{objectKey},
|
||||
#{dto.fromObjectKey},
|
||||
#{dto.toObjectKey},
|
||||
#{dto.fromName},
|
||||
#{dto.toName},
|
||||
#{dto.amount},
|
||||
#{dto.transactionCount},
|
||||
#{dto.direction},
|
||||
#{dto.relationDesc},
|
||||
#{dto.sourceDesc},
|
||||
#{dto.remark},
|
||||
'MANUAL',
|
||||
#{operator},
|
||||
#{operator}
|
||||
)
|
||||
</insert>
|
||||
</mapper>
|
||||
@@ -0,0 +1,330 @@
|
||||
<?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.ruoyi.ccdi.project.mapper.CcdiRelationGraphMapper">
|
||||
|
||||
<resultMap id="RelationGraphNodeResultMap" type="com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphNodeVO">
|
||||
<id property="objectKey" column="objectKey"/>
|
||||
<result property="nodeKey" column="nodeKey"/>
|
||||
<result property="nodeName" column="nodeName"/>
|
||||
<result property="idNumber" column="idNumber"/>
|
||||
<result property="subjectType" column="subjectType"/>
|
||||
<result property="sourceType" column="sourceType"/>
|
||||
<result property="createdTime" column="createdTime"/>
|
||||
<result property="updatedTime" column="updatedTime"/>
|
||||
<result property="canExpand" column="canExpand"/>
|
||||
<result property="depth" column="depth"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap id="RelationGraphEdgeResultMap" type="com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphEdgeVO">
|
||||
<id property="objectKey" column="objectKey"/>
|
||||
<result property="fromKey" column="fromKey"/>
|
||||
<result property="toKey" column="toKey"/>
|
||||
<result property="edgeTable" column="edgeTable"/>
|
||||
<result property="relationType" column="relationType"/>
|
||||
<result property="companyName" column="companyName"/>
|
||||
<result property="stockName" column="stockName"/>
|
||||
<result property="stockType" column="stockType"/>
|
||||
<result property="stockPercent" column="stockPercent"/>
|
||||
<result property="shouldCapi" column="shouldCapi"/>
|
||||
<result property="shouldCapiValue" column="shouldCapiValue"/>
|
||||
<result property="shouldCapiUnit" column="shouldCapiUnit"/>
|
||||
<result property="shoudDate" column="shoudDate"/>
|
||||
<result property="pKeyNo" column="pKeyNo"/>
|
||||
<result property="operName" column="operName"/>
|
||||
<result property="operKeyNo" column="operKeyNo"/>
|
||||
<result property="personId" column="personId"/>
|
||||
<result property="relationName" column="relationName"/>
|
||||
<result property="relationCertNo" column="relationCertNo"/>
|
||||
<result property="gender" column="gender"/>
|
||||
<result property="birthDate" column="birthDate"/>
|
||||
<result property="relationCertType" column="relationCertType"/>
|
||||
<result property="mobilePhone1" column="mobilePhone1"/>
|
||||
<result property="mobilePhone2" column="mobilePhone2"/>
|
||||
<result property="wechatNo1" column="wechatNo1"/>
|
||||
<result property="wechatNo2" column="wechatNo2"/>
|
||||
<result property="wechatNo3" column="wechatNo3"/>
|
||||
<result property="contactAddress" column="contactAddress"/>
|
||||
<result property="annualIncome" column="annualIncome"/>
|
||||
<result property="relationDesc" column="relationDesc"/>
|
||||
<result property="status" column="status"/>
|
||||
<result property="effectiveDate" column="effectiveDate"/>
|
||||
<result property="invalidDate" column="invalidDate"/>
|
||||
<result property="remark" column="remark"/>
|
||||
<result property="dataSource" column="dataSource"/>
|
||||
</resultMap>
|
||||
|
||||
<resultMap id="SuspectedEnterpriseResultMap" type="com.ruoyi.ccdi.project.domain.vo.CcdiRelationGraphSuspectedEnterpriseItemVO">
|
||||
<result property="candidateKeyNo" column="candidateKeyNo"/>
|
||||
<result property="personName" column="personName"/>
|
||||
<result property="companyId" column="companyId"/>
|
||||
<result property="companyName" column="companyName"/>
|
||||
<result property="creditCode" column="creditCode"/>
|
||||
<result property="enterpriseStatus" column="enterpriseStatus"/>
|
||||
<result property="industryName" column="industryName"/>
|
||||
<result property="relationType" column="relationType"/>
|
||||
<result property="stockPercent" column="stockPercent"/>
|
||||
<result property="establishDate" column="establishDate"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="nodeColumns">
|
||||
n.object_key AS objectKey,
|
||||
CONCAT('rel_node/', n.object_key) AS nodeKey,
|
||||
n.node_name AS nodeName,
|
||||
n.id_number AS idNumber,
|
||||
n.subject_type AS subjectType,
|
||||
n.source_type AS sourceType,
|
||||
DATE_FORMAT(n.created_time, '%Y-%m-%d %H:%i:%s') AS createdTime,
|
||||
DATE_FORMAT(n.updated_time, '%Y-%m-%d %H:%i:%s') AS updatedTime,
|
||||
1 AS canExpand,
|
||||
0 AS depth
|
||||
</sql>
|
||||
|
||||
<select id="selectRelationGraphSubjects" resultMap="RelationGraphNodeResultMap">
|
||||
SELECT
|
||||
<include refid="nodeColumns"/>
|
||||
FROM lx_rel_node n
|
||||
WHERE 1 = 1
|
||||
<if test="query.objectKey != null and query.objectKey != ''">
|
||||
AND n.object_key = (#{query.objectKey} COLLATE utf8mb4_general_ci)
|
||||
</if>
|
||||
<if test="query.objectKey == null or query.objectKey == ''">
|
||||
<if test="query.keyword != null and query.keyword != ''">
|
||||
AND (
|
||||
n.object_key = (TRIM(#{query.keyword}) COLLATE utf8mb4_general_ci)
|
||||
OR n.id_number = (TRIM(#{query.keyword}) COLLATE utf8mb4_general_ci)
|
||||
OR n.node_name LIKE (CONCAT('%', TRIM(#{query.keyword}), '%') COLLATE utf8mb4_general_ci)
|
||||
)
|
||||
</if>
|
||||
</if>
|
||||
ORDER BY
|
||||
CASE
|
||||
WHEN n.object_key = (TRIM(IFNULL(#{query.keyword}, '')) COLLATE utf8mb4_general_ci) THEN 0
|
||||
WHEN n.id_number = (TRIM(IFNULL(#{query.keyword}, '')) COLLATE utf8mb4_general_ci) THEN 1
|
||||
ELSE 2
|
||||
END,
|
||||
n.node_name
|
||||
LIMIT 20
|
||||
</select>
|
||||
|
||||
<select id="selectRelationGraphNodesByKeys" resultMap="RelationGraphNodeResultMap">
|
||||
SELECT
|
||||
<include refid="nodeColumns"/>
|
||||
FROM lx_rel_node n
|
||||
WHERE n.object_key IN
|
||||
<foreach collection="objectKeys" item="objectKey" open="(" separator="," close=")">
|
||||
#{objectKey}
|
||||
</foreach>
|
||||
</select>
|
||||
|
||||
<select id="selectRelationGraphEdges" resultMap="RelationGraphEdgeResultMap">
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT
|
||||
e.object_key AS objectKey,
|
||||
e.from_key AS fromKey,
|
||||
e.to_key AS toKey,
|
||||
'lx_rel_family_edge' AS edgeTable,
|
||||
e.relation_type AS relationType,
|
||||
NULL AS companyName,
|
||||
NULL AS stockName,
|
||||
NULL AS stockType,
|
||||
NULL AS stockPercent,
|
||||
NULL AS shouldCapi,
|
||||
NULL AS shouldCapiValue,
|
||||
NULL AS shouldCapiUnit,
|
||||
NULL AS shoudDate,
|
||||
NULL AS pKeyNo,
|
||||
NULL AS operName,
|
||||
NULL AS operKeyNo,
|
||||
e.person_id AS personId,
|
||||
e.relation_name AS relationName,
|
||||
e.relation_cert_no AS relationCertNo,
|
||||
NULL AS gender,
|
||||
NULL AS birthDate,
|
||||
NULL AS relationCertType,
|
||||
NULL AS mobilePhone1,
|
||||
NULL AS mobilePhone2,
|
||||
NULL AS wechatNo1,
|
||||
NULL AS wechatNo2,
|
||||
NULL AS wechatNo3,
|
||||
NULL AS contactAddress,
|
||||
NULL AS annualIncome,
|
||||
e.relation_desc AS relationDesc,
|
||||
NULL AS status,
|
||||
NULL AS effectiveDate,
|
||||
NULL AS invalidDate,
|
||||
NULL AS remark,
|
||||
NULL AS dataSource
|
||||
FROM lx_rel_family_edge e
|
||||
WHERE e.from_key = CONCAT('rel_node/', #{query.objectKey})
|
||||
OR e.to_key = CONCAT('rel_node/', #{query.objectKey})
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
e.object_key AS objectKey,
|
||||
e.from_key AS fromKey,
|
||||
e.to_key AS toKey,
|
||||
'lx_rel_stock_edge' AS edgeTable,
|
||||
e.stock_type AS relationType,
|
||||
e.company_name AS companyName,
|
||||
e.stock_name AS stockName,
|
||||
e.stock_type AS stockType,
|
||||
e.stock_percent AS stockPercent,
|
||||
e.should_capi AS shouldCapi,
|
||||
e.should_capi_value AS shouldCapiValue,
|
||||
e.should_capi_unit AS shouldCapiUnit,
|
||||
e.shoud_date AS shoudDate,
|
||||
e.p_key_no AS pKeyNo,
|
||||
NULL AS operName,
|
||||
NULL AS operKeyNo,
|
||||
NULL AS personId,
|
||||
NULL AS relationName,
|
||||
NULL AS relationCertNo,
|
||||
NULL AS gender,
|
||||
NULL AS birthDate,
|
||||
NULL AS relationCertType,
|
||||
NULL AS mobilePhone1,
|
||||
NULL AS mobilePhone2,
|
||||
NULL AS wechatNo1,
|
||||
NULL AS wechatNo2,
|
||||
NULL AS wechatNo3,
|
||||
NULL AS contactAddress,
|
||||
NULL AS annualIncome,
|
||||
NULL AS relationDesc,
|
||||
NULL AS status,
|
||||
NULL AS effectiveDate,
|
||||
NULL AS invalidDate,
|
||||
NULL AS remark,
|
||||
NULL AS dataSource
|
||||
FROM lx_rel_stock_edge e
|
||||
WHERE e.from_key = CONCAT('rel_node/', #{query.objectKey})
|
||||
OR e.to_key = CONCAT('rel_node/', #{query.objectKey})
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
e.object_key AS objectKey,
|
||||
e.from_key AS fromKey,
|
||||
e.to_key AS toKey,
|
||||
'lx_rel_represent_edge' AS edgeTable,
|
||||
'法定代表人' AS relationType,
|
||||
NULL AS companyName,
|
||||
NULL AS stockName,
|
||||
NULL AS stockType,
|
||||
NULL AS stockPercent,
|
||||
NULL AS shouldCapi,
|
||||
NULL AS shouldCapiValue,
|
||||
NULL AS shouldCapiUnit,
|
||||
NULL AS shoudDate,
|
||||
NULL AS pKeyNo,
|
||||
e.oper_name AS operName,
|
||||
e.oper_key_no AS operKeyNo,
|
||||
NULL AS personId,
|
||||
NULL AS relationName,
|
||||
NULL AS relationCertNo,
|
||||
NULL AS gender,
|
||||
NULL AS birthDate,
|
||||
NULL AS relationCertType,
|
||||
NULL AS mobilePhone1,
|
||||
NULL AS mobilePhone2,
|
||||
NULL AS wechatNo1,
|
||||
NULL AS wechatNo2,
|
||||
NULL AS wechatNo3,
|
||||
NULL AS contactAddress,
|
||||
NULL AS annualIncome,
|
||||
NULL AS relationDesc,
|
||||
NULL AS status,
|
||||
NULL AS effectiveDate,
|
||||
NULL AS invalidDate,
|
||||
NULL AS remark,
|
||||
NULL AS dataSource
|
||||
FROM lx_rel_represent_edge e
|
||||
WHERE e.from_key = CONCAT('rel_node/', #{query.objectKey})
|
||||
OR e.to_key = CONCAT('rel_node/', #{query.objectKey})
|
||||
) graph_edges
|
||||
ORDER BY
|
||||
CASE edgeTable
|
||||
WHEN 'lx_rel_family_edge' THEN 0
|
||||
WHEN 'lx_rel_stock_edge' THEN 1
|
||||
ELSE 2
|
||||
END,
|
||||
relationType,
|
||||
objectKey
|
||||
LIMIT #{query.limit}
|
||||
</select>
|
||||
|
||||
<select id="countSuspectedEnterpriseKeyNos" resultType="int">
|
||||
SELECT COUNT(DISTINCT candidate_key_no)
|
||||
FROM (
|
||||
SELECT e.oper_key_no AS candidate_key_no
|
||||
FROM lx_rel_represent_edge e
|
||||
WHERE e.oper_name = (#{personName} COLLATE utf8mb4_general_ci)
|
||||
AND e.oper_key_no IS NOT NULL
|
||||
AND e.oper_key_no != ''
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT e.p_key_no AS candidate_key_no
|
||||
FROM lx_rel_stock_edge e
|
||||
WHERE e.stock_name = (#{personName} COLLATE utf8mb4_general_ci)
|
||||
AND e.stock_type = '自然人股东'
|
||||
AND e.p_key_no IS NOT NULL
|
||||
AND e.p_key_no != ''
|
||||
) same_name_candidates
|
||||
</select>
|
||||
|
||||
<select id="selectSuspectedEnterprises" resultMap="SuspectedEnterpriseResultMap">
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT
|
||||
e.oper_key_no AS candidateKeyNo,
|
||||
e.oper_name AS personName,
|
||||
REPLACE(e.to_key, 'rel_node/', '') AS companyId,
|
||||
COALESCE(ent.enterprise_name, company_node.node_name) AS companyName,
|
||||
COALESCE(ent.social_credit_code, company_node.id_number) AS creditCode,
|
||||
ent.status AS enterpriseStatus,
|
||||
ent.industry_name AS industryName,
|
||||
'法定代表人' AS relationType,
|
||||
NULL AS stockPercent,
|
||||
DATE_FORMAT(ent.establish_date, '%Y-%m-%d') AS establishDate,
|
||||
0 AS relationSort
|
||||
FROM lx_rel_represent_edge e
|
||||
LEFT JOIN lx_rel_node company_node
|
||||
ON company_node.object_key = REPLACE(e.to_key, 'rel_node/', '')
|
||||
LEFT JOIN ccdi_enterprise_base_info ent
|
||||
ON ent.social_credit_code = company_node.id_number
|
||||
WHERE e.oper_name = (#{personName} COLLATE utf8mb4_general_ci)
|
||||
AND e.oper_key_no IS NOT NULL
|
||||
AND e.oper_key_no != ''
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT
|
||||
e.p_key_no AS candidateKeyNo,
|
||||
e.stock_name AS personName,
|
||||
REPLACE(e.to_key, 'rel_node/', '') AS companyId,
|
||||
COALESCE(ent.enterprise_name, e.company_name, company_node.node_name) AS companyName,
|
||||
COALESCE(ent.social_credit_code, company_node.id_number) AS creditCode,
|
||||
ent.status AS enterpriseStatus,
|
||||
ent.industry_name AS industryName,
|
||||
e.stock_type AS relationType,
|
||||
e.stock_percent AS stockPercent,
|
||||
COALESCE(DATE_FORMAT(ent.establish_date, '%Y-%m-%d'), e.shoud_date) AS establishDate,
|
||||
1 AS relationSort
|
||||
FROM lx_rel_stock_edge e
|
||||
LEFT JOIN lx_rel_node company_node
|
||||
ON company_node.object_key = REPLACE(e.to_key, 'rel_node/', '')
|
||||
LEFT JOIN ccdi_enterprise_base_info ent
|
||||
ON ent.social_credit_code = company_node.id_number
|
||||
WHERE e.stock_name = (#{personName} COLLATE utf8mb4_general_ci)
|
||||
AND e.stock_type = '自然人股东'
|
||||
AND e.p_key_no IS NOT NULL
|
||||
AND e.p_key_no != ''
|
||||
) suspected_enterprises
|
||||
ORDER BY relationSort, companyName, companyId
|
||||
LIMIT #{limit}
|
||||
</select>
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user