graphDetailApi.ts 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. /**
  2. * AI 聊天关系图谱 —— 独立明细查询封装
  3. *
  4. * 与「对象关系分析」页面的 graph/api/analysis.ts 完全独立:只请求后端既有的
  5. * /graph/nodeDetail、/graph/callDetail、/graph/transDetail 三个只读接口。
  6. */
  7. import { defHttp } from '@/core/utils/http/axios';
  8. import { useGlobSetting } from '@/core/hooks/setting';
  9. import { useUserStoreWithOut } from '@/core/store/modules/case';
  10. import { normalizeText, type GraphModelEdge, type GraphModelNode } from './graphData';
  11. const { adminPath } = useGlobSetting();
  12. function resolveCaseId(): string | number | undefined {
  13. const raw: any = useUserStoreWithOut().getCaseInfo?.id;
  14. if (raw === undefined || raw === null || raw === '') return undefined;
  15. return typeof raw === 'number' ? raw : String(raw).trim() || undefined;
  16. }
  17. function withCaseId(data: Record<string, any>): Record<string, any> {
  18. const caseId = data.caseId ?? resolveCaseId();
  19. return caseId === undefined ? data : { ...data, caseId };
  20. }
  21. function removeEmpty(data: Record<string, any>): Record<string, any> {
  22. const result: Record<string, any> = {};
  23. Object.entries(data).forEach(([key, value]) => {
  24. if (value === undefined || value === null || value === '') return;
  25. result[key] = value;
  26. });
  27. return result;
  28. }
  29. async function postGraph(url: string, data: Record<string, any>): Promise<any> {
  30. return defHttp.postJson(
  31. {
  32. url: adminPath + url,
  33. data: withCaseId(removeEmpty(data)),
  34. },
  35. { skipSuccessMessage: true },
  36. );
  37. }
  38. function defaultClazz(node: GraphModelNode): string {
  39. if (node.kind === 'person') return 'sfz';
  40. if (node.kind === 'phone') return 'tel';
  41. if (node.kind === 'bank') return 'card';
  42. if (node.kind === 'house') return 'dz_fc';
  43. if (node.kind === 'car') return 'car';
  44. if (node.kind === 'group') return 'obj';
  45. return 'x';
  46. }
  47. function nodeToken(node: GraphModelNode): string {
  48. const raw = node.raw || {};
  49. return normalizeText(raw.node ?? raw.bm ?? raw.sfz ?? raw.id) || node.id;
  50. }
  51. function nodeClazz(node: GraphModelNode): string {
  52. const raw = node.raw || {};
  53. return normalizeText(raw.clazz ?? raw.class) || defaultClazz(node);
  54. }
  55. function edgeEndpoint(edge: GraphModelEdge, endpoint: 'source' | 'target'): string {
  56. const raw = edge.raw || {};
  57. const value = endpoint === 'source' ? (raw.node1 ?? raw.dx1) : (raw.node2 ?? raw.dx2);
  58. return normalizeText(value) || (endpoint === 'source' ? edge.source : edge.target);
  59. }
  60. export interface NodeDetailExtra {
  61. page?: number;
  62. limit?: number;
  63. startDate?: string;
  64. endDate?: string;
  65. transAmount?: number | string;
  66. transAmountSymbol?: string;
  67. }
  68. /** 节点详情查询(非人节点:卡/号码/车/房/机构等) */
  69. export function buildNodeDetailQuery(node: GraphModelNode, extra: NodeDetailExtra = {}): Record<string, any> {
  70. const raw = node.raw || {};
  71. const lx = Number(raw.lx);
  72. const fx = Number(raw.fx);
  73. return {
  74. node: nodeToken(node),
  75. clazz: nodeClazz(node),
  76. lx: Number.isFinite(lx) ? lx : 0,
  77. fx: Number.isFinite(fx) ? fx : 0,
  78. page: extra.page,
  79. limit: extra.limit,
  80. startDate: extra.startDate,
  81. endDate: extra.endDate,
  82. transAmount: extra.transAmount,
  83. transAmountSymbol: extra.transAmount ? extra.transAmountSymbol || 'GE' : undefined,
  84. };
  85. }
  86. /** 电话节点 → 通话明细 */
  87. export function buildCallDetailQueryFromNode(node: GraphModelNode): Record<string, any> {
  88. const phone = nodeToken(node);
  89. return {
  90. personPhone: phone,
  91. personPhones: [phone],
  92. };
  93. }
  94. /** 通话关系边 → 通话明细 */
  95. export function buildCallDetailQueryFromEdge(edge: GraphModelEdge): Record<string, any> {
  96. const dx1 = edgeEndpoint(edge, 'source');
  97. const dx2 = edgeEndpoint(edge, 'target');
  98. return {
  99. dx1,
  100. dx2,
  101. personPhone: dx1,
  102. otherPhone: dx2,
  103. personPhones: [dx1],
  104. otherPhones: [dx2],
  105. clazz: edge.clazz,
  106. edgeId: edge.id,
  107. };
  108. }
  109. /** 银行卡节点 → 交易明细 */
  110. export function buildTransDetailQueryFromNode(node: GraphModelNode): Record<string, any> {
  111. const card = nodeToken(node);
  112. return {
  113. personCardNo: card,
  114. bankCardNo: card,
  115. cardNo: card,
  116. bm: card,
  117. };
  118. }
  119. /** 交易关系边 → 交易明细 */
  120. export function buildTransDetailQueryFromEdge(edge: GraphModelEdge): Record<string, any> {
  121. const raw = edge.raw || {};
  122. const dx1 = edgeEndpoint(edge, 'source');
  123. const dx2 = edgeEndpoint(edge, 'target');
  124. const lx = Number(raw.lx);
  125. return {
  126. personCardNo: dx1,
  127. otherCardNo: dx2,
  128. bankCardNo: dx1,
  129. cardNo: dx1,
  130. bm: dx1,
  131. lx: Number.isFinite(lx) ? lx : 1,
  132. edgeId: edge.id,
  133. };
  134. }
  135. export function fetchNodeDetail(data: Record<string, any>): Promise<any> {
  136. return postGraph('/graph/nodeDetail', data);
  137. }
  138. export function fetchCallDetail(data: Record<string, any>): Promise<any> {
  139. return postGraph('/graph/callDetail', data);
  140. }
  141. export function fetchTransDetail(data: Record<string, any>): Promise<any> {
  142. return postGraph('/graph/transDetail', data);
  143. }