neo-cmp-cli 1.13.15 → 1.13.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/README.md +2 -1
  2. package/dist/index2.js +1 -1
  3. package/dist/main2.js +1 -1
  4. package/dist/neo/neoLogin.js +1 -1
  5. package/dist/package.json.js +1 -1
  6. package/docs//351/200/232/347/224/250/344/273/243/347/220/206/346/216/245/345/217/243/forward.zip +0 -0
  7. package/docs//351/200/232/347/224/250/344/273/243/347/220/206/346/216/245/345/217/243//350/207/252/345/256/232/344/271/211API:/351/200/232/347/224/250/344/273/243/347/220/206/346/216/245/345/217/243/344/275/277/347/224/250/350/257/264/346/230/216.md +13 -0
  8. package/package.json +1 -1
  9. package/template/antd-custom-cmp-template/package.json +1 -1
  10. package/template/asset-manage-template/package.json +2 -2
  11. package/template/echarts-custom-cmp-template/package.json +1 -1
  12. package/template/empty-custom-cmp-template/package.json +2 -2
  13. package/template/map-custom-cmp-template/package.json +1 -1
  14. package/template/neo-bi-cmps/neo.config.js +7 -1
  15. package/template/neo-bi-cmps/package.json +8 -7
  16. package/template/neo-bi-cmps/public/403.html +77 -0
  17. package/template/neo-bi-cmps/src/assets/icon/barChart.svg +1 -0
  18. package/template/neo-bi-cmps/src/assets/icon/card.svg +1 -0
  19. package/template/neo-bi-cmps/src/assets/icon/filter.svg +1 -0
  20. package/template/neo-bi-cmps/src/assets/icon/funnel.svg +1 -0
  21. package/template/neo-bi-cmps/src/assets/icon/tab.svg +1 -0
  22. package/template/neo-bi-cmps/src/components/filterBar__c/README.md +3 -14
  23. package/template/neo-bi-cmps/src/components/filterBar__c/common.scss +29 -0
  24. package/template/neo-bi-cmps/src/components/filterBar__c/index.tsx +668 -146
  25. package/template/neo-bi-cmps/src/components/filterBar__c/model.ts +26 -48
  26. package/template/neo-bi-cmps/src/components/filterBar__c/style.scss +46 -139
  27. package/template/neo-bi-cmps/src/components/targetNumber__c/customStyleConfig/index.tsx +11 -10
  28. package/template/neo-bi-cmps/src/components/targetNumber__c/index.tsx +9 -16
  29. package/template/neo-bi-cmps/src/utils/common.ts +231 -0
  30. package/template/neo-bi-cmps/src/utils/filter2chartFilter.ts +268 -0
  31. package/template/neo-bi-cmps/src/utils/filterBar.ts +140 -0
  32. package/template/neo-bi-cmps/src/utils/pipelineFunnel.ts +341 -0
  33. package/template/neo-bi-cmps/src/utils/queryByCustomSQL.ts +117 -0
  34. package/template/neo-bi-cmps/src/utils/requestDebounce.ts +22 -0
  35. package/template/neo-bi-cmps/src/utils/simpleTable.tsx +344 -0
  36. package/template/neo-bi-cmps/src/utils/stageSwitch.ts +15 -0
  37. package/template/neo-bi-cmps/src/utils/stageTimeChart.ts +90 -0
  38. package/template/neo-bi-cmps/src/utils/targetNumber.ts +12 -0
  39. package/template/neo-custom-cmp-template/package.json +2 -2
  40. package/template/neo-h5-cmps/package.json +2 -2
  41. package/template/neo-order-cmps/package.json +2 -2
  42. package/template/neo-pipeline-cmps/.prettierrc.js +12 -0
  43. package/template/neo-pipeline-cmps/@types/neo-ui-common.d.ts +36 -0
  44. package/template/neo-pipeline-cmps/README.md +99 -0
  45. package/template/neo-pipeline-cmps/commitlint.config.js +59 -0
  46. package/template/neo-pipeline-cmps/neo.config.js +124 -0
  47. package/template/neo-pipeline-cmps/package.json +66 -0
  48. package/template/neo-pipeline-cmps/public/403.html +77 -0
  49. package/template/neo-pipeline-cmps/public/css/base.css +283 -0
  50. package/template/neo-pipeline-cmps/public/demo.html +2453 -0
  51. package/template/neo-pipeline-cmps/public/scripts/app/bluebird.js +6679 -0
  52. package/template/neo-pipeline-cmps/public/template.html +13 -0
  53. package/template/neo-pipeline-cmps/src/assets/css/common.scss +127 -0
  54. package/template/neo-pipeline-cmps/src/assets/css/mixin.scss +47 -0
  55. package/template/neo-pipeline-cmps/src/assets/icon/barChart.svg +1 -0
  56. package/template/neo-pipeline-cmps/src/assets/icon/card.svg +1 -0
  57. package/template/neo-pipeline-cmps/src/assets/icon/filter.svg +1 -0
  58. package/template/neo-pipeline-cmps/src/assets/icon/funnel.svg +1 -0
  59. package/template/neo-pipeline-cmps/src/assets/icon/tab.svg +1 -0
  60. package/template/neo-pipeline-cmps/src/assets/img/AIBtn.gif +0 -0
  61. package/template/neo-pipeline-cmps/src/assets/img/NeoCRM.jpg +0 -0
  62. package/template/neo-pipeline-cmps/src/assets/img/aiLogo.png +0 -0
  63. package/template/neo-pipeline-cmps/src/assets/img/card-list.svg +1 -0
  64. package/template/neo-pipeline-cmps/src/assets/img/contact-form.svg +1 -0
  65. package/template/neo-pipeline-cmps/src/assets/img/custom-form.svg +1 -0
  66. package/template/neo-pipeline-cmps/src/assets/img/custom-widget.svg +1 -0
  67. package/template/neo-pipeline-cmps/src/assets/img/data-list.svg +1 -0
  68. package/template/neo-pipeline-cmps/src/assets/img/detail.svg +1 -0
  69. package/template/neo-pipeline-cmps/src/assets/img/favicon.png +0 -0
  70. package/template/neo-pipeline-cmps/src/assets/img/map.svg +1 -0
  71. package/template/neo-pipeline-cmps/src/assets/img/search.svg +1 -0
  72. package/template/neo-pipeline-cmps/src/assets/img/table.svg +1 -0
  73. package/template/neo-pipeline-cmps/src/components/filterBar__c/README.md +24 -0
  74. package/template/neo-pipeline-cmps/src/components/filterBar__c/common.scss +29 -0
  75. package/template/neo-pipeline-cmps/src/components/filterBar__c/index.tsx +730 -0
  76. package/template/neo-pipeline-cmps/src/components/filterBar__c/model.ts +50 -0
  77. package/template/neo-pipeline-cmps/src/components/filterBar__c/style.scss +119 -0
  78. package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/index.tsx +415 -0
  79. package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/model.ts +79 -0
  80. package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/style.scss +83 -0
  81. package/template/neo-pipeline-cmps/src/components/showHealthResult__c/index.tsx +463 -0
  82. package/template/neo-pipeline-cmps/src/components/showHealthResult__c/model.ts +45 -0
  83. package/template/neo-pipeline-cmps/src/components/showHealthResult__c/style.scss +137 -0
  84. package/template/neo-pipeline-cmps/src/components/simpleTable__c/README.md +90 -0
  85. package/template/neo-pipeline-cmps/src/components/simpleTable__c/common.scss +195 -0
  86. package/template/neo-pipeline-cmps/src/components/simpleTable__c/index.tsx +665 -0
  87. package/template/neo-pipeline-cmps/src/components/simpleTable__c/model.ts +124 -0
  88. package/template/neo-pipeline-cmps/src/components/simpleTable__c/style.scss +193 -0
  89. package/template/neo-pipeline-cmps/src/components/stageSwitch__c/index.tsx +511 -0
  90. package/template/neo-pipeline-cmps/src/components/stageSwitch__c/model.ts +70 -0
  91. package/template/{neo-bi-cmps → neo-pipeline-cmps}/src/components/stageSwitch__c/style.scss +4 -2
  92. package/template/neo-pipeline-cmps/src/components/stageTimeChart__c/index.tsx +455 -0
  93. package/template/neo-pipeline-cmps/src/components/stageTimeChart__c/model.ts +103 -0
  94. package/template/{neo-bi-cmps → neo-pipeline-cmps}/src/components/stageTimeChart__c/style.scss +3 -2
  95. package/template/neo-pipeline-cmps/src/utils/common.ts +229 -0
  96. package/template/neo-pipeline-cmps/src/utils/filter2chartFilter.ts +268 -0
  97. package/template/neo-pipeline-cmps/src/utils/filterBar.ts +140 -0
  98. package/template/neo-pipeline-cmps/src/utils/pipelineFunnel.ts +343 -0
  99. package/template/neo-pipeline-cmps/src/utils/queryByCustomSQL.ts +117 -0
  100. package/template/neo-pipeline-cmps/src/utils/requestDebounce.ts +22 -0
  101. package/template/neo-pipeline-cmps/src/utils/simpleTable.tsx +344 -0
  102. package/template/neo-pipeline-cmps/src/utils/stageSwitch.ts +15 -0
  103. package/template/neo-pipeline-cmps/src/utils/stageTimeChart.ts +90 -0
  104. package/template/neo-pipeline-cmps/src/utils/targetNumber.ts +12 -0
  105. package/template/neo-pipeline-cmps/tsconfig.json +40 -0
  106. package/template/neo-web-entity-grid/package.json +2 -2
  107. package/template/neo-web-form/package.json +2 -2
  108. package/template/react-custom-cmp-template/package.json +1 -1
  109. package/template/react-ts-custom-cmp-template/package.json +1 -1
  110. package/template/vue2-custom-cmp-template/package.json +1 -1
  111. package/template/neo-bi-cmps/.npmrc copy +0 -1
  112. package/template/neo-bi-cmps/docs/gartner-pipeline-apis.md +0 -251
  113. package/template/neo-bi-cmps/docs/gartner-pipeline-prd.md +0 -389
  114. package/template/neo-bi-cmps/docs/neo-backend-dev/SKILL.md +0 -188
  115. package/template/neo-bi-cmps/docs/neo-backend-dev/references/01-Trigger/345/274/200/345/217/221.md +0 -183
  116. package/template/neo-bi-cmps/docs/neo-backend-dev/references/02-/350/207/252/345/256/232/344/271/211API/345/274/200/345/217/221.md +0 -196
  117. package/template/neo-bi-cmps/docs/neo-backend-dev/references/03-SDK/345/267/245/345/205/267/347/261/273/346/216/245/345/217/243.md +0 -346
  118. package/template/neo-bi-cmps/docs/neo-backend-dev/references/04-/350/256/241/345/210/222/344/275/234/344/270/232/345/274/200/345/217/221.md +0 -188
  119. package/template/neo-bi-cmps/docs/neo-backend-dev/references/05-/351/241/265/351/235/242/345/274/200/345/217/221.md +0 -293
  120. package/template/neo-bi-cmps/docs/neo-backend-dev/references/06-/346/265/201/347/250/213/346/211/251/345/261/225/345/274/200/345/217/221.md +0 -175
  121. package/template/neo-bi-cmps/docs/neo-backend-dev/references/PaaS/345/271/263/345/217/260/345/274/200/345/217/221/346/211/213/345/206/214/350/247/243/350/257/273.md +0 -313
  122. package/template/neo-bi-cmps/docs/neo-backend-dev/references/auth-config.md +0 -77
  123. package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/deploy_server_script.py +0 -118
  124. package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/download_server_script.py +0 -74
  125. package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/gen_entity_desc.py +0 -69
  126. package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/gen_entitylist.py +0 -87
  127. package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/query_crm.py +0 -65
  128. package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/uninstall_server_script.py +0 -48
  129. package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/update_model_jar.py +0 -49
  130. package/template/neo-bi-cmps/docs/neo-frontend-dev/SKILL.md +0 -138
  131. package/template/neo-bi-cmps/docs/neo-frontend-dev/references/auth-config.md +0 -77
  132. package/template/neo-bi-cmps/docs/neo-frontend-dev/references/component-dev.md +0 -205
  133. package/template/neo-bi-cmps/docs/neo-frontend-dev/references/entityTable-example.md +0 -167
  134. package/template/neo-bi-cmps/docs/neo-frontend-dev/references/templates.md +0 -38
  135. package/template/neo-bi-cmps/docs/neo-frontend-dev/scripts/gen_entity_desc.py +0 -69
  136. package/template/neo-bi-cmps/docs/neo-frontend-dev/scripts/gen_entitylist.py +0 -87
  137. package/template/neo-bi-cmps/docs/neo-frontend-dev/scripts/query_crm.py +0 -65
  138. package/template/neo-bi-cmps/docs//350/264/246/345/217/267/347/233/270/345/205/263/344/277/241/346/201/257.md +0 -10
  139. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/README.md +0 -52
  140. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/index.tsx +0 -183
  141. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/model.ts +0 -90
  142. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/style.scss +0 -218
  143. package/template/neo-bi-cmps/src/components/forecastChart__c/README.md +0 -31
  144. package/template/neo-bi-cmps/src/components/forecastChart__c/index.tsx +0 -158
  145. package/template/neo-bi-cmps/src/components/forecastChart__c/model.ts +0 -40
  146. package/template/neo-bi-cmps/src/components/forecastChart__c/style.scss +0 -154
  147. package/template/neo-bi-cmps/src/components/forecastGrid__c/README.md +0 -36
  148. package/template/neo-bi-cmps/src/components/forecastGrid__c/index.tsx +0 -86
  149. package/template/neo-bi-cmps/src/components/forecastGrid__c/model.ts +0 -62
  150. package/template/neo-bi-cmps/src/components/forecastGrid__c/style.scss +0 -48
  151. package/template/neo-bi-cmps/src/components/gapCloser__c/README.md +0 -24
  152. package/template/neo-bi-cmps/src/components/gapCloser__c/index.tsx +0 -100
  153. package/template/neo-bi-cmps/src/components/gapCloser__c/model.ts +0 -46
  154. package/template/neo-bi-cmps/src/components/gapCloser__c/style.scss +0 -60
  155. package/template/neo-bi-cmps/src/components/kpiCards__c/README.md +0 -35
  156. package/template/neo-bi-cmps/src/components/kpiCards__c/index.tsx +0 -70
  157. package/template/neo-bi-cmps/src/components/kpiCards__c/model.ts +0 -50
  158. package/template/neo-bi-cmps/src/components/kpiCards__c/style.scss +0 -33
  159. package/template/neo-bi-cmps/src/components/oppList__c/README.md +0 -52
  160. package/template/neo-bi-cmps/src/components/oppList__c/index.tsx +0 -285
  161. package/template/neo-bi-cmps/src/components/oppList__c/model.ts +0 -86
  162. package/template/neo-bi-cmps/src/components/oppList__c/style.scss +0 -133
  163. package/template/neo-bi-cmps/src/components/pipelineFunnel__c/index.tsx +0 -130
  164. package/template/neo-bi-cmps/src/components/pipelineFunnel__c/model.ts +0 -66
  165. package/template/neo-bi-cmps/src/components/pipelineFunnel__c/style.scss +0 -133
  166. package/template/neo-bi-cmps/src/components/stageSwitch__c/index.tsx +0 -118
  167. package/template/neo-bi-cmps/src/components/stageSwitch__c/model.ts +0 -92
  168. package/template/neo-bi-cmps/src/components/stageTimeChart__c/index.tsx +0 -126
  169. package/template/neo-bi-cmps/src/components/stageTimeChart__c/model.ts +0 -57
  170. package/template/neo-bi-cmps/src/components/tabSwitch__c/README.md +0 -37
  171. package/template/neo-bi-cmps/src/components/tabSwitch__c/index.tsx +0 -80
  172. package/template/neo-bi-cmps/src/components/tabSwitch__c/model.ts +0 -45
  173. package/template/neo-bi-cmps/src/components/tabSwitch__c/style.scss +0 -37
  174. package/template/neo-bi-cmps/src/utils/axiosFetcher.ts +0 -37
  175. package/template/neo-bi-cmps/src/utils/queryObjectData.ts +0 -76
  176. package/template/neo-bi-cmps/src/utils/xobjects.ts +0 -162
  177. /package/template/neo-bi-cmps/{docs/prototype-pipeline-forecasting.html → public/demo.html} +0 -0
  178. /package/template/{neo-bi-cmps → neo-pipeline-cmps}/src/components/pipelineFunnel__c/README.md +0 -0
  179. /package/template/{neo-bi-cmps → neo-pipeline-cmps}/src/components/stageSwitch__c/README.md +0 -0
  180. /package/template/{neo-bi-cmps → neo-pipeline-cmps}/src/components/stageTimeChart__c/README.md +0 -0
@@ -0,0 +1,83 @@
1
+ .pipelineFunnel__c {
2
+ background: #fff;
3
+ border-radius: 8px;
4
+ padding: 12px 20px;
5
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
6
+ min-height: 400px;
7
+
8
+ .funnel-header {
9
+ display: flex;
10
+ justify-content: space-between;
11
+ align-items: center;
12
+ margin-bottom: 4px;
13
+ }
14
+
15
+ .funnel-title {
16
+ font-size: 14px;
17
+ font-weight: 600;
18
+ margin: 0;
19
+ }
20
+
21
+ .ai-btn {
22
+ cursor: pointer;
23
+ font-size: 16px;
24
+ transition: transform 0.2s;
25
+
26
+ &:hover {
27
+ transform: scale(1.1);
28
+ }
29
+ }
30
+
31
+ .funnel-total {
32
+ text-align: center;
33
+ margin-bottom: 0;
34
+
35
+ .funnel-total-label {
36
+ font-size: 12px;
37
+ color: #888;
38
+ }
39
+
40
+ .funnel-total-value {
41
+ font-size: 20px;
42
+ font-weight: 700;
43
+ }
44
+ }
45
+
46
+ .funnel-body {
47
+ min-height: 220px;
48
+ }
49
+
50
+ .funnel-chart-wrap {
51
+ width: 100%;
52
+ position: relative;
53
+ }
54
+
55
+ .funnel-chart {
56
+ min-height: 200px;
57
+ }
58
+
59
+ .funnel-legend {
60
+ display: flex;
61
+ gap: 12px;
62
+ justify-content: center;
63
+ flex-wrap: wrap;
64
+ margin-top: 8px;
65
+ font-size: 11px;
66
+ color: #666;
67
+ }
68
+
69
+ .legend-item {
70
+ display: flex;
71
+ align-items: center;
72
+ gap: 4px;
73
+ }
74
+
75
+ .legend-dot {
76
+ display: inline-block;
77
+ width: 10px;
78
+ height: 10px;
79
+ border-radius: 50%;
80
+ margin-right: 4px;
81
+ vertical-align: middle;
82
+ }
83
+ }
@@ -0,0 +1,463 @@
1
+ /**
2
+ * @file 商机健康度评估结果展示
3
+ * @description 调用 /rest/ai/v2.0/agent/apps/health_assessment/get_health_assessment_result,展示 assessmentConclusion 摘要与基于 assessmentDimension 的 ECharts 雷达图
4
+ */
5
+ import * as React from 'react';
6
+ import * as echarts from 'echarts';
7
+ // @ts-ignore
8
+ import { request } from 'neo-open-api';
9
+ // @ts-ignore
10
+ import { BaseCmp, NeoEvent } from 'neo-ui-common';
11
+
12
+ import './style.scss';
13
+
14
+ const HEALTH_ASSESSMENT_URL =
15
+ '/rest/ai/v2.0/agent/apps/health_assessment/get_health_assessment_result';
16
+
17
+ export type HealthScoreRow = { name: string; score: number };
18
+
19
+ interface ShowHealthResultProps {
20
+ /** 实体 API Key,对应请求体 object_api_key */
21
+ xObjectApiKey?: string;
22
+ /** 业务数据 ID,对应请求体 data_id */
23
+ id?: string;
24
+ className?: string;
25
+ style?: React.CSSProperties;
26
+ data?: any;
27
+ }
28
+
29
+ interface ShowHealthResultState {
30
+ loading: boolean;
31
+ error: string | null;
32
+ summaryText: string;
33
+ scoreRows: HealthScoreRow[];
34
+ }
35
+
36
+ function unwrapResultRecord(res: any): Record<string, unknown> {
37
+ if (!res || typeof res !== 'object') return {};
38
+ const r = res as Record<string, unknown>;
39
+ const inner = r.data;
40
+ if (inner && typeof inner === 'object' && !Array.isArray(inner)) {
41
+ const d = inner as Record<string, unknown>;
42
+ if ('assessmentConclusion' in d || 'assessmentDimension' in d) {
43
+ return d;
44
+ }
45
+ }
46
+ if ('assessmentConclusion' in r || 'assessmentDimension' in r) {
47
+ return r;
48
+ }
49
+ if (inner && typeof inner === 'object') {
50
+ return inner as Record<string, unknown>;
51
+ }
52
+ return {};
53
+ }
54
+
55
+ function parseSummaryFromConclusion(conclusion: unknown): string {
56
+ if (conclusion == null) return '';
57
+ if (typeof conclusion === 'string') return conclusion.trim();
58
+ if (Array.isArray(conclusion)) {
59
+ const parts = conclusion
60
+ .map((x: any) => {
61
+ if (!x || typeof x !== 'object') return '';
62
+ return (
63
+ x.summary ??
64
+ x.conclusion ??
65
+ x.desc ??
66
+ x.description ??
67
+ x.remark ??
68
+ ''
69
+ );
70
+ })
71
+ .filter((s: string) => String(s).trim());
72
+ return parts.join('\n').trim();
73
+ }
74
+ if (typeof conclusion === 'object') {
75
+ const o = conclusion as Record<string, unknown>;
76
+ const text =
77
+ o.summary ?? o.conclusion ?? o.text ?? o.assessmentSummary ?? '';
78
+ return String(text ?? '').trim();
79
+ }
80
+ return String(conclusion).trim();
81
+ }
82
+
83
+ /**
84
+ * 雷达图仅使用接口字段 assessmentDimension,且须为 { name, score }[]。
85
+ * 不读取 conclusion、不解析其它键名(如 label / value / items 包装等)。
86
+ */
87
+ function scoreRowsFromAssessmentDimension(dimension: unknown): HealthScoreRow[] {
88
+ if (!Array.isArray(dimension)) return [];
89
+ const rows: HealthScoreRow[] = [];
90
+ for (const item of dimension) {
91
+ if (!item || typeof item !== 'object') continue;
92
+ const o = item as Record<string, unknown>;
93
+ if (!('name' in o) || !('score' in o)) continue;
94
+ const name = String(o.name ?? '').trim();
95
+ if (!name) continue;
96
+ const scoreRaw = o.score;
97
+ let score = 0;
98
+ if (typeof scoreRaw === 'number' && Number.isFinite(scoreRaw)) {
99
+ score = scoreRaw;
100
+ } else if (scoreRaw != null && scoreRaw !== '') {
101
+ const p = parseFloat(String(scoreRaw));
102
+ score = Number.isFinite(p) ? p : 0;
103
+ }
104
+ rows.push({ name, score });
105
+ }
106
+ return rows;
107
+ }
108
+
109
+ /**
110
+ * 雷达轴外圈文案:不再做6 字截断;英文尽量按词折行,无空格(如中文)按固定宽度折行。
111
+ * 行数过多时仅在最后一行末尾加省略号,其余行尽量完整展示。
112
+ */
113
+ function wrapRadarAxisName(
114
+ text: string,
115
+ maxLineLen = 18,
116
+ maxLines = 8,
117
+ ): string {
118
+ const t = text.trim();
119
+ if (!t) return t;
120
+ if (t.length <= maxLineLen) return t;
121
+
122
+ const lines: string[] = [];
123
+ const push = (s: string) => {
124
+ if (s) lines.push(s);
125
+ };
126
+
127
+ if (/\s/.test(t)) {
128
+ const words = t.split(/\s+/).filter(Boolean);
129
+ let cur = '';
130
+ for (const w of words) {
131
+ if (w.length > maxLineLen) {
132
+ push(cur);
133
+ cur = '';
134
+ for (let i = 0; i < w.length; i += maxLineLen) {
135
+ push(w.slice(i, i + maxLineLen));
136
+ }
137
+ continue;
138
+ }
139
+ const next = cur ? `${cur} ${w}` : w;
140
+ if (next.length <= maxLineLen) cur = next;
141
+ else {
142
+ push(cur);
143
+ cur = w;
144
+ }
145
+ }
146
+ push(cur);
147
+ } else {
148
+ for (let i = 0; i < t.length; i += maxLineLen) {
149
+ push(t.slice(i, i + maxLineLen));
150
+ }
151
+ }
152
+
153
+ if (lines.length <= maxLines) return lines.join('\n');
154
+
155
+ const head = lines.slice(0, maxLines - 1);
156
+ const rest = lines.slice(maxLines - 1).join('');
157
+ const last =
158
+ rest.length > maxLineLen ? `${rest.slice(0, maxLineLen - 1)}…` : `${rest}…`;
159
+ return [...head, last].join('\n');
160
+ }
161
+
162
+ function buildHealthRadarOption(items: HealthScoreRow[]): echarts.EChartsOption {
163
+ if (!items.length) {
164
+ return {
165
+ graphic: [
166
+ {
167
+ type: 'text',
168
+ left: 'center',
169
+ top: 'middle',
170
+ style: {
171
+ text: '暂无雷达图维度数据',
172
+ fill: '#999',
173
+ fontSize: 12,
174
+ },
175
+ },
176
+ ],
177
+ };
178
+ }
179
+
180
+ // 每轴单独上限,避免多轴共用 max 导致低分维度挤在中间;健康分常见 0–100
181
+ const indicator = items.map((i) => ({
182
+ name: i.name,
183
+ max: Math.max(10, i.score, 1),
184
+ }));
185
+
186
+ return {
187
+ tooltip: {
188
+ trigger: 'item',
189
+ },
190
+ radar: {
191
+ indicator,
192
+ radius: '52%',
193
+ center: ['50%', '52%'],
194
+ axisName: {
195
+ color: '#666',
196
+ fontSize: 10,
197
+ lineHeight: 13,
198
+ formatter(name: string) {
199
+ return wrapRadarAxisName(name);
200
+ },
201
+ },
202
+ splitLine: {
203
+ lineStyle: { color: '#e5e7eb' },
204
+ },
205
+ splitArea: { show: false },
206
+ axisLine: {
207
+ lineStyle: { color: '#e5e7eb' },
208
+ },
209
+ },
210
+ series: [
211
+ {
212
+ type: 'radar',
213
+ data: [
214
+ {
215
+ value: items.map((i) => i.score),
216
+ name: '健康度',
217
+ areaStyle: {
218
+ color: 'rgba(99,102,241,0.2)',
219
+ },
220
+ lineStyle: {
221
+ color: '#6366f1',
222
+ width: 2,
223
+ },
224
+ itemStyle: {
225
+ color: '#6366f1',
226
+ },
227
+ },
228
+ ],
229
+ },
230
+ ],
231
+ };
232
+ }
233
+
234
+ class ShowHealthResult extends BaseCmp<ShowHealthResultProps, ShowHealthResultState> {
235
+ private radarChartRef = React.createRef<HTMLDivElement>();
236
+
237
+ private radarChartInstance: echarts.ECharts | null = null;
238
+
239
+ private radarResizeObserver: ResizeObserver | null = null;
240
+
241
+ constructor(props: ShowHealthResultProps) {
242
+ super(props);
243
+ this.state = {
244
+ loading: false,
245
+ error: null,
246
+ summaryText: '',
247
+ scoreRows: [],
248
+ };
249
+
250
+ this.initRadarChart = this.initRadarChart.bind(this);
251
+ this.updateRadarChart = this.updateRadarChart.bind(this);
252
+ this.bindRadarResize = this.bindRadarResize.bind(this);
253
+ this.unbindRadarResize = this.unbindRadarResize.bind(this);
254
+ this.handleRadarWindowResize = this.handleRadarWindowResize.bind(this);
255
+ this.disposeRadarChart = this.disposeRadarChart.bind(this);
256
+ }
257
+
258
+ componentDidMount() {
259
+ this.fetchHealthAssessment();
260
+ }
261
+
262
+ componentDidUpdate(
263
+ prevProps: ShowHealthResultProps,
264
+ prevState: ShowHealthResultState,
265
+ ) {
266
+ if (
267
+ prevProps.id !== this.props.id ||
268
+ prevProps.xObjectApiKey !== this.props.xObjectApiKey
269
+ ) {
270
+ this.fetchHealthAssessment();
271
+ }
272
+
273
+ const hasBlock =
274
+ !this.state.error &&
275
+ (this.state.summaryText || this.state.scoreRows.length > 0);
276
+
277
+ if (!hasBlock) {
278
+ if (this.radarChartInstance) {
279
+ this.disposeRadarChart();
280
+ }
281
+ return;
282
+ }
283
+
284
+ if (!this.radarChartInstance && this.radarChartRef.current) {
285
+ this.initRadarChart();
286
+ } else if (prevState.scoreRows !== this.state.scoreRows) {
287
+ this.updateRadarChart();
288
+ }
289
+ }
290
+
291
+ componentWillUnmount() {
292
+ this.disposeRadarChart();
293
+ }
294
+
295
+ disposeRadarChart() {
296
+ this.unbindRadarResize();
297
+ if (this.radarChartInstance) {
298
+ this.radarChartInstance.dispose();
299
+ this.radarChartInstance = null;
300
+ }
301
+ }
302
+
303
+ initRadarChart() {
304
+ if (!this.radarChartRef.current || this.radarChartInstance) return;
305
+ this.radarChartInstance = echarts.init(this.radarChartRef.current);
306
+ this.bindRadarResize();
307
+ this.updateRadarChart();
308
+ }
309
+
310
+ bindRadarResize() {
311
+ if (typeof window === 'undefined') return;
312
+ window.addEventListener('resize', this.handleRadarWindowResize);
313
+ if (typeof ResizeObserver === 'undefined') return;
314
+ this.radarResizeObserver = new ResizeObserver(() => {
315
+ this.radarChartInstance?.resize();
316
+ });
317
+ const el = this.radarChartRef.current;
318
+ if (el) this.radarResizeObserver.observe(el);
319
+ }
320
+
321
+ unbindRadarResize() {
322
+ if (typeof window !== 'undefined') {
323
+ window.removeEventListener('resize', this.handleRadarWindowResize);
324
+ }
325
+ this.radarResizeObserver?.disconnect();
326
+ this.radarResizeObserver = null;
327
+ }
328
+
329
+ handleRadarWindowResize() {
330
+ this.radarChartInstance?.resize();
331
+ }
332
+
333
+ updateRadarChart() {
334
+ if (!this.radarChartInstance) return;
335
+ const opt = buildHealthRadarOption(this.state.scoreRows);
336
+ this.radarChartInstance.setOption(opt, { notMerge: true });
337
+ requestAnimationFrame(() => {
338
+ this.radarChartInstance?.resize();
339
+ });
340
+ }
341
+
342
+ async fetchHealthAssessment() {
343
+ const xObjectApiKey = this.props.xObjectApiKey;
344
+ const id = this.props.id;
345
+
346
+ this.setState({ loading: true, error: null });
347
+
348
+ try {
349
+ const res = await request({
350
+ url: HEALTH_ASSESSMENT_URL,
351
+ method: 'POST',
352
+ data: {
353
+ data_id: id,
354
+ object_api_key: String(xObjectApiKey),
355
+ },
356
+ });
357
+
358
+ const record = unwrapResultRecord(res);
359
+ const conclusion = record.assessmentConclusion;
360
+ const dimension = record.assessmentDimension;
361
+
362
+ const summaryText = parseSummaryFromConclusion(conclusion);
363
+ const scoreRows = scoreRowsFromAssessmentDimension(dimension);
364
+
365
+ this.setState(
366
+ {
367
+ loading: false,
368
+ error: null,
369
+ summaryText,
370
+ scoreRows,
371
+ },
372
+ () => {
373
+ if (!this.radarChartInstance && this.radarChartRef.current) {
374
+ this.initRadarChart();
375
+ } else {
376
+ this.updateRadarChart();
377
+ }
378
+ },
379
+ );
380
+ } catch (e: any) {
381
+ console.error('showHealthResult 健康度接口失败:', e);
382
+ this.setState(
383
+ {
384
+ loading: false,
385
+ error: e?.message || '请求失败',
386
+ summaryText: '',
387
+ scoreRows: [],
388
+ },
389
+ () => this.disposeRadarChart(),
390
+ );
391
+ }
392
+ }
393
+
394
+ @NeoEvent.function
395
+ async refreshData() {
396
+ await this.fetchHealthAssessment();
397
+ }
398
+
399
+ render() {
400
+ const { className, style } = this.props;
401
+ const { loading, error, summaryText, scoreRows } = this.state;
402
+
403
+ console.log('showHealthResult__c:', scoreRows, this.props);
404
+
405
+ return (
406
+ <div
407
+ className={`showHealthResult__c ${className || ''}`}
408
+ style={style}
409
+ >
410
+ {loading && (
411
+ <div className="showHealthResult__c__loading" aria-busy="true">
412
+ <span className="showHealthResult__c__loadingDot" />
413
+ <span className="showHealthResult__c__loadingDot" />
414
+ <span className="showHealthResult__c__loadingDot" />
415
+ <span className="showHealthResult__c__loadingText">正在获取健康度评估…</span>
416
+ </div>
417
+ )}
418
+
419
+ {error && !loading && (
420
+ <div
421
+ className="showHealthResult__c__placeholder showHealthResult__c__placeholder--error"
422
+ role="alert"
423
+ >
424
+ <div className="showHealthResult__c__placeholderBody">
425
+ <div className="showHealthResult__c__placeholderTitle">
426
+ 暂时无法获取评估结果
427
+ </div>
428
+ <div className="showHealthResult__c__placeholderMsg">{error}</div>
429
+ </div>
430
+ </div>
431
+ )}
432
+
433
+ {!loading && !error && !summaryText && !scoreRows.length && (
434
+ <div className="showHealthResult__c__placeholder showHealthResult__c__placeholder--empty">
435
+ <div className="showHealthResult__c__placeholderBody">
436
+ <div className="showHealthResult__c__placeholderTitle">
437
+ 暂无评估数据
438
+ </div>
439
+ <div className="showHealthResult__c__placeholderHint">
440
+ 当前记录可能尚未生成健康度结论,请稍后重试或检查数据是否完整。
441
+ </div>
442
+ </div>
443
+ </div>
444
+ )}
445
+
446
+ {(summaryText || scoreRows.length > 0) && (
447
+ <>
448
+ <div className="showHealthResult__c__summary" id="stSummary">
449
+ {summaryText || ' '}
450
+ </div>
451
+ <div
452
+ ref={this.radarChartRef}
453
+ className="showHealthResult__c__radar"
454
+ style={{ width: '100%', height: 300 }}
455
+ />
456
+ </>
457
+ )}
458
+ </div>
459
+ );
460
+ }
461
+ }
462
+
463
+ export default ShowHealthResult;
@@ -0,0 +1,45 @@
1
+ /**
2
+ * @file 商机健康度评估结果展示 — 编辑器 model
3
+ */
4
+ export class ShowHealthResultModel {
5
+ label: string = '健康度信息展示';
6
+
7
+ description: string =
8
+ '调用健康度评估接口,展示结论摘要与雷达图';
9
+
10
+ iconUrl: string = 'https://custom-widgets.bj.bcebos.com/detail.svg';
11
+
12
+ targetPage: string[] = ['all'];
13
+
14
+ targetDevice: string = 'all';
15
+
16
+ defaultComProps = {
17
+ xObjectApiKey: 'opportunity',
18
+ id: '1627009883848800',
19
+ };
20
+
21
+ functions = [
22
+ {
23
+ apiKey: 'refreshData',
24
+ label: '刷新健康度数据',
25
+ helpTextKey: '重新请求健康度评估接口',
26
+ },
27
+ ];
28
+
29
+ propsSchema = [
30
+ {
31
+ type: 'panelInput',
32
+ name: 'xObjectApiKey',
33
+ label: '实体 key(xObjectApiKey)',
34
+ placeholder: '例如 opportunity',
35
+ },
36
+ {
37
+ type: 'panelInput',
38
+ name: 'id',
39
+ label: '业务数据 ID(data_id)',
40
+ placeholder: '业务记录主键',
41
+ },
42
+ ];
43
+ }
44
+
45
+ export default ShowHealthResultModel;