neo-cmp-cli 1.13.17 → 1.13.18
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.
- package/dist/index2.js +1 -1
- package/dist/neo/env.js +1 -1
- package/dist/neo/pushCmp.js +1 -1
- package/dist/package.json.js +1 -1
- package/package.json +3 -2
- package/template/asset-manage-template/docs/README.md +1 -232
- package/template/echarts-custom-cmp-template/package.json +1 -1
- package/template/neo-bi-cmps/package.json +1 -1
- package/template/neo-bi-cmps/src/components/targetNumber__c/model.ts +1 -1
- package/template/neo-custom-cmp-template/docs/README.md +0 -231
- package/template/neo-custom-cmp-template/package.json +1 -1
- package/template/neo-h5-cmps/src/components/entityList__c/index.tsx +1 -2
- package/template/neo-h5-cmps/src/components/entityTabs__c/index.tsx +1 -1
- package/template/neo-h5-cmps/src/components/globalSearchInput__c/index.tsx +1 -1
- package/template/neo-h5-cmps/src/components/openChatPageBtn__c/index.tsx +1 -2
- package/template/neo-pipeline-cmps/neo.config.js +11 -0
- package/template/neo-pipeline-cmps/src/assets/css/common.scss +16 -16
- package/template/neo-pipeline-cmps/src/assets/css/mixin.scss +5 -5
- package/template/neo-pipeline-cmps/src/components/filterBar__c/README.md +9 -9
- package/template/neo-pipeline-cmps/src/components/filterBar__c/common.scss +5 -5
- package/template/neo-pipeline-cmps/src/components/filterBar__c/index.tsx +47 -46
- package/template/neo-pipeline-cmps/src/components/filterBar__c/model.ts +13 -11
- package/template/neo-pipeline-cmps/src/components/filterBar__c/style.scss +1 -1
- package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/README.md +17 -17
- package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/index.tsx +23 -22
- package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/model.ts +18 -17
- package/template/neo-pipeline-cmps/src/components/showHealthResult__c/index.tsx +33 -26
- package/template/neo-pipeline-cmps/src/components/showHealthResult__c/model.ts +9 -9
- package/template/neo-pipeline-cmps/src/components/simpleTable__c/README.md +53 -54
- package/template/neo-pipeline-cmps/src/components/simpleTable__c/common.scss +5 -5
- package/template/neo-pipeline-cmps/src/components/simpleTable__c/index.tsx +70 -68
- package/template/neo-pipeline-cmps/src/components/simpleTable__c/model.ts +41 -41
- package/template/neo-pipeline-cmps/src/components/simpleTable__c/style.scss +2 -3
- package/template/neo-pipeline-cmps/src/components/stageSwitch__c/README.md +15 -15
- package/template/neo-pipeline-cmps/src/components/stageSwitch__c/index.tsx +35 -33
- package/template/neo-pipeline-cmps/src/components/stageSwitch__c/model.ts +16 -15
- package/template/neo-pipeline-cmps/src/components/stageTimeChart__c/README.md +18 -18
- package/template/neo-pipeline-cmps/src/components/stageTimeChart__c/index.tsx +20 -20
- package/template/neo-pipeline-cmps/src/components/stageTimeChart__c/model.ts +21 -18
- package/template/neo-pipeline-cmps/src/utils/common.ts +14 -14
- package/template/neo-pipeline-cmps/src/utils/filter2chartFilter.ts +21 -23
- package/template/neo-pipeline-cmps/src/utils/filterBar.ts +14 -14
- package/template/neo-pipeline-cmps/src/utils/pipelineFunnel.ts +5 -5
- package/template/neo-pipeline-cmps/src/utils/queryByCustomSQL.ts +26 -22
- package/template/neo-pipeline-cmps/src/utils/requestDebounce.ts +3 -3
- package/template/neo-pipeline-cmps/src/utils/simpleTable.tsx +31 -26
- package/template/neo-pipeline-cmps/src/utils/stageSwitch.ts +1 -1
- package/template/neo-pipeline-cmps/src/utils/stageTimeChart.ts +5 -5
- package/template/neo-pipeline-cmps/src/utils/targetNumber.ts +2 -2
- package/template/neo-web-form/package.json +1 -1
- package/template/neo-web-form/src/components/batchAddTable__c/index.tsx +161 -41
- package/template/neo-web-form/src/components/batchAddTable__c/model.ts +4 -2
- package/template/react-custom-cmp-template/package.json +1 -1
- package/template/asset-manage-template/src/utils/axiosFetcher.ts +0 -37
- package/template/asset-manage-template/src/utils/queryObjectData.ts +0 -112
- package/template/asset-manage-template/src/utils/xobjects.ts +0 -162
- package/template/neo-custom-cmp-template/src/utils/axiosFetcher.ts +0 -37
- package/template/neo-custom-cmp-template/src/utils/queryObjectData.ts +0 -112
- package/template/neo-custom-cmp-template/src/utils/xobjects.ts +0 -162
- package/template/neo-h5-cmps/src/utils/axiosFetcher.ts +0 -37
- package/template/neo-h5-cmps/src/utils/queryObjectData.ts +0 -112
- package/template/neo-h5-cmps/src/utils/xobjects.ts +0 -167
- package/template/neo-order-cmps/src/utils/axiosFetcher.ts +0 -37
- package/template/neo-order-cmps/src/utils/queryObjectData.ts +0 -112
- package/template/neo-order-cmps/src/utils/xobjects.ts +0 -162
- package/template/neo-web-entity-grid/src/utils/axiosFetcher.ts +0 -37
- package/template/neo-web-entity-grid/src/utils/queryObjectData.ts +0 -112
- package/template/neo-web-entity-grid/src/utils/xobjects.ts +0 -167
- package/template/neo-web-form/src/utils/axiosFetcher.ts +0 -37
- package/template/neo-web-form/src/utils/queryObjectData.ts +0 -112
- package/template/neo-web-form/src/utils/xobjects.ts +0 -167
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export class FilterBarModel {
|
|
2
|
-
label: string = '
|
|
3
|
-
description: string =
|
|
2
|
+
label: string = 'Filter Bar';
|
|
3
|
+
description: string =
|
|
4
|
+
'Supports multi-dimensional filtering by date range, owner, business type, etc.';
|
|
4
5
|
iconUrl: string = 'https://custom-widgets.bj.bcebos.com/filter.svg';
|
|
5
6
|
targetPage: string[] = ['all'];
|
|
6
7
|
targetDevice: string = 'all';
|
|
@@ -12,35 +13,36 @@ export class FilterBarModel {
|
|
|
12
13
|
{ value: 401, label: 'This Quarter' },
|
|
13
14
|
{ value: 'custom', label: 'Custom' },
|
|
14
15
|
],
|
|
15
|
-
/**
|
|
16
|
+
/** When matching the apiKey of an item returned by the business type API, use it as the default Business Type selection */
|
|
16
17
|
defaultBusiType: 'defaultBusiType_1', // New Business
|
|
17
18
|
};
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
|
-
*
|
|
21
|
+
* Declare all events that the current component will trigger (matching @NeoEvent.dispatch method names in the component)
|
|
21
22
|
*/
|
|
22
23
|
events = [
|
|
23
24
|
{
|
|
24
25
|
apiKey: 'onFiltersChange',
|
|
25
|
-
label: '
|
|
26
|
+
label: 'After filter conditions change',
|
|
26
27
|
helpText:
|
|
27
|
-
'
|
|
28
|
+
'Triggered when any filter option or custom time range changes; event params include closeDate, closeDateCustomRange (for non-custom: current relative period start/end Unix ms timestamps; for custom: RangePicker start/end), opportunityOwner (owner multi-select id array), businessType, businessTypeLabel (business type display name), changesSince, changesSinceCustomTime (for Custom Changes Since: selected date midnight; otherwise for non-custom Close Date: period start midnight)',
|
|
28
29
|
eventParams:
|
|
29
|
-
'[{"apiKey":"eventParam","children":[{"apiKey":"data","label":"
|
|
30
|
+
'[{"apiKey":"eventParam","children":[{"apiKey":"data","label":"Current filter data","type":"Object"}],"label":"Event parameters","type":"Object"}]',
|
|
30
31
|
},
|
|
31
32
|
];
|
|
32
33
|
|
|
33
34
|
functions = [
|
|
34
35
|
{
|
|
35
36
|
apiKey: 'resetFilters',
|
|
36
|
-
label: '
|
|
37
|
-
helpTextKey:
|
|
37
|
+
label: 'Reset filters',
|
|
38
|
+
helpTextKey:
|
|
39
|
+
'Reset all filter conditions to defaults and trigger the "After filter conditions change" event',
|
|
38
40
|
},
|
|
39
41
|
{
|
|
40
42
|
apiKey: 'getFilters',
|
|
41
|
-
label: '
|
|
43
|
+
label: 'Get filters',
|
|
42
44
|
helpTextKey:
|
|
43
|
-
'
|
|
45
|
+
'Return current filter snapshot object; when closeDate is not custom, closeDateCustomRange is the relative period start/end timestamps; when custom, it is the custom range; businessTypeLabel is the business type display name; changesSinceCustomTime is the selected date midnight when Changes Since is Custom, otherwise the period start midnight when Close Date is not custom',
|
|
44
46
|
},
|
|
45
47
|
];
|
|
46
48
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
# PipelineFunnel
|
|
1
|
+
# PipelineFunnel Component
|
|
2
2
|
|
|
3
|
-
Pipeline
|
|
3
|
+
Pipeline funnel chart component that displays the funnel conversion of the sales pipeline.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Usage
|
|
6
6
|
|
|
7
7
|
```tsx
|
|
8
8
|
import PipelineFunnel from './components/pipelineFunnel__c';
|
|
@@ -20,20 +20,20 @@ import PipelineFunnel from './components/pipelineFunnel__c';
|
|
|
20
20
|
|
|
21
21
|
## Props
|
|
22
22
|
|
|
23
|
-
|
|
|
24
|
-
|
|
25
|
-
| title |
|
|
26
|
-
| totalAmount |
|
|
27
|
-
| stages |
|
|
28
|
-
| showAiButton |
|
|
29
|
-
| onStageClick |
|
|
23
|
+
| Property | Description | Type | Default |
|
|
24
|
+
|----------|-------------|------|---------|
|
|
25
|
+
| title | Title | string | 'Pipeline Funnel' |
|
|
26
|
+
| totalAmount | Total amount | string | '$11.1M' |
|
|
27
|
+
| stages | Funnel stage data | FunnelStage[] | [] |
|
|
28
|
+
| showAiButton | Show AI button | boolean | true |
|
|
29
|
+
| onStageClick | Stage click callback | (stageName: string) => void | - |
|
|
30
30
|
|
|
31
31
|
## FunnelStage
|
|
32
32
|
|
|
33
|
-
|
|
|
34
|
-
|
|
35
|
-
| name |
|
|
36
|
-
| amount |
|
|
37
|
-
| count |
|
|
38
|
-
| conversionRate |
|
|
39
|
-
| color |
|
|
33
|
+
| Property | Description | Type |
|
|
34
|
+
|----------|-------------|------|
|
|
35
|
+
| name | Stage name | string |
|
|
36
|
+
| amount | Amount | string |
|
|
37
|
+
| count | Count | number |
|
|
38
|
+
| conversionRate | Conversion rate | string |
|
|
39
|
+
| color | Color | string |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file Pipeline
|
|
3
|
-
* @description
|
|
2
|
+
* @file Pipeline Funnel Chart Component
|
|
3
|
+
* @description Displays the funnel conversion of the sales pipeline, data from NeoBI queryDataTask
|
|
4
4
|
*/
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import * as echarts from 'echarts';
|
|
@@ -33,15 +33,15 @@ const FORM_URLENCODED_UTF8 = 'application/x-www-form-urlencoded;charset=UTF-8';
|
|
|
33
33
|
|
|
34
34
|
interface PipelineFunnelProps {
|
|
35
35
|
title?: string;
|
|
36
|
-
/**
|
|
36
|
+
/** View ID, used in queryDataTask */
|
|
37
37
|
viewId?: string;
|
|
38
|
-
/**
|
|
38
|
+
/** View type, corresponding to request parameter type */
|
|
39
39
|
viewType?: string;
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
42
|
-
*
|
|
41
|
+
* When true, layer width decreases with stage order (classic funnel), layer height proportional to each stage's amount;
|
|
42
|
+
* When false (default), layer width is proportional to each stage's actual amount */
|
|
43
43
|
useClassicFunnelShape?: boolean;
|
|
44
|
-
/** Neo
|
|
44
|
+
/** Neo injected, contains current user */
|
|
45
45
|
data?: {
|
|
46
46
|
__NeoCurrentUser?: { id?: string | number };
|
|
47
47
|
};
|
|
@@ -55,11 +55,11 @@ interface PipelineFunnelState {
|
|
|
55
55
|
loading: boolean;
|
|
56
56
|
error: string | null;
|
|
57
57
|
stages: FunnelStage[];
|
|
58
|
-
/**
|
|
58
|
+
/** Sum of amount values across all stages, used for percentage calculation */
|
|
59
59
|
totalAmountNum: number;
|
|
60
|
-
/**
|
|
60
|
+
/** Total amount label for top display */
|
|
61
61
|
totalAmountLabel: string;
|
|
62
|
-
/**
|
|
62
|
+
/** Filter for request body, can be updated by component action setFilter */
|
|
63
63
|
filter: any;
|
|
64
64
|
}
|
|
65
65
|
|
|
@@ -97,9 +97,9 @@ class PipelineFunnel extends BaseCmp<PipelineFunnelProps, PipelineFunnelState> {
|
|
|
97
97
|
this.bindResize();
|
|
98
98
|
|
|
99
99
|
/*
|
|
100
|
-
//
|
|
100
|
+
// Listen to a broadcast event
|
|
101
101
|
NeoEvent.listen('updateFilterData', (filterData: any) => {
|
|
102
|
-
console.log('PipelineFunnel
|
|
102
|
+
console.log('PipelineFunnel received broadcast event updateFilterData: ', filterData);
|
|
103
103
|
this.setFilter(filterData);
|
|
104
104
|
});
|
|
105
105
|
*/
|
|
@@ -196,6 +196,7 @@ class PipelineFunnel extends BaseCmp<PipelineFunnelProps, PipelineFunnelState> {
|
|
|
196
196
|
chartViewHeightPx: classicShape ? chartViewHeightPx : undefined,
|
|
197
197
|
funnelGap: 2,
|
|
198
198
|
});
|
|
199
|
+
console.log('[PipelineFunnel__c] updateChart option:', option);
|
|
199
200
|
this.chartInstance.setOption(option, true);
|
|
200
201
|
this.chartInstance.off('click');
|
|
201
202
|
this.chartInstance.on(
|
|
@@ -224,7 +225,7 @@ class PipelineFunnel extends BaseCmp<PipelineFunnelProps, PipelineFunnelState> {
|
|
|
224
225
|
}
|
|
225
226
|
requestAnimationFrame(() => this.chartInstance?.resize());
|
|
226
227
|
} catch (e) {
|
|
227
|
-
console.error('PipelineFunnel ECharts
|
|
228
|
+
console.error('PipelineFunnel ECharts update failed:', e);
|
|
228
229
|
}
|
|
229
230
|
}
|
|
230
231
|
|
|
@@ -235,7 +236,7 @@ class PipelineFunnel extends BaseCmp<PipelineFunnelProps, PipelineFunnelState> {
|
|
|
235
236
|
if (viewId == null || viewId === '' || userId == null || userId === '') {
|
|
236
237
|
this.setState({
|
|
237
238
|
loading: false,
|
|
238
|
-
error: '
|
|
239
|
+
error: 'Missing viewId or current user id (data.__NeoCurrentUser.id)',
|
|
239
240
|
stages: [],
|
|
240
241
|
totalAmountNum: 0,
|
|
241
242
|
totalAmountLabel: formatAmountDisplay(0),
|
|
@@ -273,7 +274,7 @@ class PipelineFunnel extends BaseCmp<PipelineFunnelProps, PipelineFunnelState> {
|
|
|
273
274
|
if (status !== 0 || !Array.isArray(table)) {
|
|
274
275
|
this.setState({
|
|
275
276
|
loading: false,
|
|
276
|
-
error: res?.message || res?.msg || '
|
|
277
|
+
error: res?.message || res?.msg || 'Failed to query chart data',
|
|
277
278
|
stages: [],
|
|
278
279
|
totalAmountNum: 0,
|
|
279
280
|
totalAmountLabel: formatAmountDisplay(0),
|
|
@@ -292,10 +293,10 @@ class PipelineFunnel extends BaseCmp<PipelineFunnelProps, PipelineFunnelState> {
|
|
|
292
293
|
totalAmountLabel: formatAmountDisplay(totalAmountNum),
|
|
293
294
|
});
|
|
294
295
|
} catch (e: any) {
|
|
295
|
-
console.error('PipelineFunnel queryDataTask
|
|
296
|
+
console.error('PipelineFunnel queryDataTask failed:', e);
|
|
296
297
|
this.setState({
|
|
297
298
|
loading: false,
|
|
298
|
-
error: e?.message || '
|
|
299
|
+
error: e?.message || 'Network request failed',
|
|
299
300
|
stages: [],
|
|
300
301
|
totalAmountNum: 0,
|
|
301
302
|
totalAmountLabel: formatAmountDisplay(0),
|
|
@@ -304,7 +305,7 @@ class PipelineFunnel extends BaseCmp<PipelineFunnelProps, PipelineFunnelState> {
|
|
|
304
305
|
}
|
|
305
306
|
|
|
306
307
|
/**
|
|
307
|
-
*
|
|
308
|
+
* Refresh funnel chart data (bindable in designer)
|
|
308
309
|
*/
|
|
309
310
|
@NeoEvent.function
|
|
310
311
|
async refreshData() {
|
|
@@ -312,8 +313,8 @@ class PipelineFunnel extends BaseCmp<PipelineFunnelProps, PipelineFunnelState> {
|
|
|
312
313
|
}
|
|
313
314
|
|
|
314
315
|
/**
|
|
315
|
-
*
|
|
316
|
-
* @param filter
|
|
316
|
+
* Set filter conditions and re-fetch data (bindable in designer)
|
|
317
|
+
* @param filter Filter object, used as the filter field of queryDataTask
|
|
317
318
|
*/
|
|
318
319
|
@NeoEvent.function
|
|
319
320
|
setFilter(filter?: any) {
|
|
@@ -332,7 +333,7 @@ class PipelineFunnel extends BaseCmp<PipelineFunnelProps, PipelineFunnelState> {
|
|
|
332
333
|
@NeoEvent.dispatch
|
|
333
334
|
onActiveStageChange(eventData?: any) {}
|
|
334
335
|
|
|
335
|
-
//
|
|
336
|
+
// Update the current active sales stage when clicking a stage
|
|
336
337
|
handleStageClick(stageName: string) {
|
|
337
338
|
this.onActiveStageChange({
|
|
338
339
|
activeStage: stageName,
|
|
@@ -355,7 +356,7 @@ class PipelineFunnel extends BaseCmp<PipelineFunnelProps, PipelineFunnelState> {
|
|
|
355
356
|
<div
|
|
356
357
|
className={`pipelineFunnel__c ${className || ''}`}
|
|
357
358
|
style={style}
|
|
358
|
-
data-time="2026.4.
|
|
359
|
+
data-time="2026.4.17 01"
|
|
359
360
|
>
|
|
360
361
|
<Spin spinning={loading}>
|
|
361
362
|
<div className="funnel-header">
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export class PipelineFunnelModel {
|
|
2
|
-
label: string = 'Pipeline
|
|
3
|
-
description: string =
|
|
2
|
+
label: string = 'Pipeline Funnel Chart';
|
|
3
|
+
description: string =
|
|
4
|
+
'Displays the funnel conversion of the sales pipeline, visually showing amount and count at each stage';
|
|
4
5
|
iconUrl: string = 'https://custom-widgets.bj.bcebos.com/funnel.svg';
|
|
5
6
|
targetPage: string[] = ['all'];
|
|
6
7
|
targetDevice: string = 'all';
|
|
@@ -10,35 +11,35 @@ export class PipelineFunnelModel {
|
|
|
10
11
|
viewId: '4264464770007375',
|
|
11
12
|
viewType: 'sync',
|
|
12
13
|
showAiButton: true,
|
|
13
|
-
/**
|
|
14
|
+
/** When true, layer width decreases with stage order (classic shape), layer height proportional to amount; default false, layer width proportional to actual amount */
|
|
14
15
|
useClassicFunnelShape: false,
|
|
15
16
|
};
|
|
16
17
|
|
|
17
18
|
events = [
|
|
18
19
|
{
|
|
19
20
|
apiKey: 'onActiveStageChange',
|
|
20
|
-
label: '
|
|
21
|
+
label: 'Triggered on stage click',
|
|
21
22
|
helpText:
|
|
22
|
-
'
|
|
23
|
+
'Triggered when clicking a funnel stage; event params include activeStage (current active stage)',
|
|
23
24
|
eventParams:
|
|
24
|
-
'[{"apiKey":"eventParam","children":[{"apiKey":"activeStage","label":"
|
|
25
|
+
'[{"apiKey":"eventParam","children":[{"apiKey":"activeStage","label":"Current active stage","type":"String"}],"label":"Event parameters","type":"Object"}]',
|
|
25
26
|
},
|
|
26
27
|
];
|
|
27
28
|
|
|
28
29
|
functions = [
|
|
29
30
|
{
|
|
30
31
|
apiKey: 'refreshData',
|
|
31
|
-
label: '
|
|
32
|
-
helpTextKey: '
|
|
32
|
+
label: 'Refresh data',
|
|
33
|
+
helpTextKey: 'Re-request queryDataTask to refresh funnel chart data',
|
|
33
34
|
},
|
|
34
35
|
{
|
|
35
36
|
apiKey: 'setFilter',
|
|
36
|
-
label: '
|
|
37
|
-
helpTextKey: '
|
|
37
|
+
label: 'Set filter conditions',
|
|
38
|
+
helpTextKey: 'Set the report component filter and re-fetch data',
|
|
38
39
|
funcInParams: [
|
|
39
40
|
{
|
|
40
41
|
apiKey: 'filter',
|
|
41
|
-
label: '
|
|
42
|
+
label: 'Filter conditions',
|
|
42
43
|
type: 'Object',
|
|
43
44
|
required: false,
|
|
44
45
|
},
|
|
@@ -50,26 +51,26 @@ export class PipelineFunnelModel {
|
|
|
50
51
|
{
|
|
51
52
|
type: 'panelInput',
|
|
52
53
|
name: 'title',
|
|
53
|
-
label: '
|
|
54
|
+
label: 'Title',
|
|
54
55
|
},
|
|
55
56
|
{
|
|
56
57
|
type: 'panelInput',
|
|
57
58
|
name: 'viewId',
|
|
58
|
-
label: '
|
|
59
|
+
label: 'View ID',
|
|
59
60
|
},
|
|
60
61
|
{
|
|
61
62
|
type: 'panelInput',
|
|
62
63
|
name: 'viewType',
|
|
63
|
-
label: '
|
|
64
|
+
label: 'View type (request type)',
|
|
64
65
|
},
|
|
65
66
|
{
|
|
66
67
|
type: 'panelSelect',
|
|
67
68
|
name: 'useClassicFunnelShape',
|
|
68
|
-
label: '
|
|
69
|
+
label: 'Funnel shape',
|
|
69
70
|
value: false,
|
|
70
71
|
options: [
|
|
71
|
-
{ label: '
|
|
72
|
-
{ label: '
|
|
72
|
+
{ label: 'Shape based on actual amount', value: false },
|
|
73
|
+
{ label: 'Classic funnel (layer height by value)', value: true },
|
|
73
74
|
],
|
|
74
75
|
clearable: false,
|
|
75
76
|
},
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file
|
|
3
|
-
* @description
|
|
2
|
+
* @file Opportunity Health Assessment Result Display
|
|
3
|
+
* @description Calls /rest/ai/v2.0/agent/apps/health_assessment/get_health_assessment_result, displays assessmentConclusion summary and ECharts radar chart based on assessmentDimension
|
|
4
4
|
*/
|
|
5
5
|
import * as React from 'react';
|
|
6
6
|
import * as echarts from 'echarts';
|
|
@@ -17,9 +17,9 @@ const HEALTH_ASSESSMENT_URL =
|
|
|
17
17
|
export type HealthScoreRow = { name: string; score: number };
|
|
18
18
|
|
|
19
19
|
interface ShowHealthResultProps {
|
|
20
|
-
/**
|
|
20
|
+
/** Entity API Key, corresponding to request body object_api_key */
|
|
21
21
|
xObjectApiKey?: string;
|
|
22
|
-
/**
|
|
22
|
+
/** Business data ID, corresponding to request body data_id */
|
|
23
23
|
id?: string;
|
|
24
24
|
className?: string;
|
|
25
25
|
style?: React.CSSProperties;
|
|
@@ -60,12 +60,7 @@ function parseSummaryFromConclusion(conclusion: unknown): string {
|
|
|
60
60
|
.map((x: any) => {
|
|
61
61
|
if (!x || typeof x !== 'object') return '';
|
|
62
62
|
return (
|
|
63
|
-
x.summary ??
|
|
64
|
-
x.conclusion ??
|
|
65
|
-
x.desc ??
|
|
66
|
-
x.description ??
|
|
67
|
-
x.remark ??
|
|
68
|
-
''
|
|
63
|
+
x.summary ?? x.conclusion ?? x.desc ?? x.description ?? x.remark ?? ''
|
|
69
64
|
);
|
|
70
65
|
})
|
|
71
66
|
.filter((s: string) => String(s).trim());
|
|
@@ -81,10 +76,12 @@ function parseSummaryFromConclusion(conclusion: unknown): string {
|
|
|
81
76
|
}
|
|
82
77
|
|
|
83
78
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
79
|
+
* Radar chart only uses the API field assessmentDimension, which must be { name, score }[].
|
|
80
|
+
* Does not read conclusion or parse other key names (such as label / value / items wrappers).
|
|
86
81
|
*/
|
|
87
|
-
function scoreRowsFromAssessmentDimension(
|
|
82
|
+
function scoreRowsFromAssessmentDimension(
|
|
83
|
+
dimension: unknown,
|
|
84
|
+
): HealthScoreRow[] {
|
|
88
85
|
if (!Array.isArray(dimension)) return [];
|
|
89
86
|
const rows: HealthScoreRow[] = [];
|
|
90
87
|
for (const item of dimension) {
|
|
@@ -107,8 +104,8 @@ function scoreRowsFromAssessmentDimension(dimension: unknown): HealthScoreRow[]
|
|
|
107
104
|
}
|
|
108
105
|
|
|
109
106
|
/**
|
|
110
|
-
*
|
|
111
|
-
*
|
|
107
|
+
* Radar axis outer label: no 6-character truncation; English wraps by word, non-spaced text (e.g. Chinese) wraps at fixed width.
|
|
108
|
+
* When too many lines, only the last line gets an ellipsis, other lines are shown as completely as possible.
|
|
112
109
|
*/
|
|
113
110
|
function wrapRadarAxisName(
|
|
114
111
|
text: string,
|
|
@@ -159,7 +156,9 @@ function wrapRadarAxisName(
|
|
|
159
156
|
return [...head, last].join('\n');
|
|
160
157
|
}
|
|
161
158
|
|
|
162
|
-
function buildHealthRadarOption(
|
|
159
|
+
function buildHealthRadarOption(
|
|
160
|
+
items: HealthScoreRow[],
|
|
161
|
+
): echarts.EChartsOption {
|
|
163
162
|
if (!items.length) {
|
|
164
163
|
return {
|
|
165
164
|
graphic: [
|
|
@@ -168,7 +167,7 @@ function buildHealthRadarOption(items: HealthScoreRow[]): echarts.EChartsOption
|
|
|
168
167
|
left: 'center',
|
|
169
168
|
top: 'middle',
|
|
170
169
|
style: {
|
|
171
|
-
text: '
|
|
170
|
+
text: 'No radar chart dimension data available',
|
|
172
171
|
fill: '#999',
|
|
173
172
|
fontSize: 12,
|
|
174
173
|
},
|
|
@@ -177,7 +176,7 @@ function buildHealthRadarOption(items: HealthScoreRow[]): echarts.EChartsOption
|
|
|
177
176
|
};
|
|
178
177
|
}
|
|
179
178
|
|
|
180
|
-
//
|
|
179
|
+
// Each axis has its own max to avoid low-score dimensions being squeezed; health scores are typically 0-100
|
|
181
180
|
const indicator = items.map((i) => ({
|
|
182
181
|
name: i.name,
|
|
183
182
|
max: Math.max(10, i.score, 1),
|
|
@@ -213,7 +212,7 @@ function buildHealthRadarOption(items: HealthScoreRow[]): echarts.EChartsOption
|
|
|
213
212
|
data: [
|
|
214
213
|
{
|
|
215
214
|
value: items.map((i) => i.score),
|
|
216
|
-
name: '
|
|
215
|
+
name: 'Health Score',
|
|
217
216
|
areaStyle: {
|
|
218
217
|
color: 'rgba(99,102,241,0.2)',
|
|
219
218
|
},
|
|
@@ -231,7 +230,10 @@ function buildHealthRadarOption(items: HealthScoreRow[]): echarts.EChartsOption
|
|
|
231
230
|
};
|
|
232
231
|
}
|
|
233
232
|
|
|
234
|
-
class ShowHealthResult extends BaseCmp<
|
|
233
|
+
class ShowHealthResult extends BaseCmp<
|
|
234
|
+
ShowHealthResultProps,
|
|
235
|
+
ShowHealthResultState
|
|
236
|
+
> {
|
|
235
237
|
private radarChartRef = React.createRef<HTMLDivElement>();
|
|
236
238
|
|
|
237
239
|
private radarChartInstance: echarts.ECharts | null = null;
|
|
@@ -378,11 +380,11 @@ class ShowHealthResult extends BaseCmp<ShowHealthResultProps, ShowHealthResultSt
|
|
|
378
380
|
},
|
|
379
381
|
);
|
|
380
382
|
} catch (e: any) {
|
|
381
|
-
console.error('showHealthResult
|
|
383
|
+
console.error('showHealthResult health assessment API failed:', e);
|
|
382
384
|
this.setState(
|
|
383
385
|
{
|
|
384
386
|
loading: false,
|
|
385
|
-
error: e?.message || '
|
|
387
|
+
error: e?.message || 'Request failed',
|
|
386
388
|
summaryText: '',
|
|
387
389
|
scoreRows: [],
|
|
388
390
|
},
|
|
@@ -406,13 +408,16 @@ class ShowHealthResult extends BaseCmp<ShowHealthResultProps, ShowHealthResultSt
|
|
|
406
408
|
<div
|
|
407
409
|
className={`showHealthResult__c ${className || ''}`}
|
|
408
410
|
style={style}
|
|
411
|
+
data-time="2026.4.17 01"
|
|
409
412
|
>
|
|
410
413
|
{loading && (
|
|
411
414
|
<div className="showHealthResult__c__loading" aria-busy="true">
|
|
412
415
|
<span className="showHealthResult__c__loadingDot" />
|
|
413
416
|
<span className="showHealthResult__c__loadingDot" />
|
|
414
417
|
<span className="showHealthResult__c__loadingDot" />
|
|
415
|
-
<span className="showHealthResult__c__loadingText"
|
|
418
|
+
<span className="showHealthResult__c__loadingText">
|
|
419
|
+
Fetching health assessment...
|
|
420
|
+
</span>
|
|
416
421
|
</div>
|
|
417
422
|
)}
|
|
418
423
|
|
|
@@ -423,7 +428,7 @@ class ShowHealthResult extends BaseCmp<ShowHealthResultProps, ShowHealthResultSt
|
|
|
423
428
|
>
|
|
424
429
|
<div className="showHealthResult__c__placeholderBody">
|
|
425
430
|
<div className="showHealthResult__c__placeholderTitle">
|
|
426
|
-
|
|
431
|
+
Unable to retrieve assessment results at this time
|
|
427
432
|
</div>
|
|
428
433
|
<div className="showHealthResult__c__placeholderMsg">{error}</div>
|
|
429
434
|
</div>
|
|
@@ -434,10 +439,12 @@ class ShowHealthResult extends BaseCmp<ShowHealthResultProps, ShowHealthResultSt
|
|
|
434
439
|
<div className="showHealthResult__c__placeholder showHealthResult__c__placeholder--empty">
|
|
435
440
|
<div className="showHealthResult__c__placeholderBody">
|
|
436
441
|
<div className="showHealthResult__c__placeholderTitle">
|
|
437
|
-
|
|
442
|
+
No assessment data available
|
|
438
443
|
</div>
|
|
439
444
|
<div className="showHealthResult__c__placeholderHint">
|
|
440
|
-
|
|
445
|
+
The current record may not have generated a health assessment
|
|
446
|
+
conclusion yet. Please try again later or check if the data is
|
|
447
|
+
complete.
|
|
441
448
|
</div>
|
|
442
449
|
</div>
|
|
443
450
|
</div>
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @file
|
|
2
|
+
* @file Opportunity Health Assessment Result Display - Editor model
|
|
3
3
|
*/
|
|
4
4
|
export class ShowHealthResultModel {
|
|
5
|
-
label: string = '
|
|
5
|
+
label: string = 'Health Score Display';
|
|
6
6
|
|
|
7
7
|
description: string =
|
|
8
|
-
'
|
|
8
|
+
'Calls the health assessment API to display conclusion summary and radar chart';
|
|
9
9
|
|
|
10
10
|
iconUrl: string = 'https://custom-widgets.bj.bcebos.com/detail.svg';
|
|
11
11
|
|
|
@@ -21,8 +21,8 @@ export class ShowHealthResultModel {
|
|
|
21
21
|
functions = [
|
|
22
22
|
{
|
|
23
23
|
apiKey: 'refreshData',
|
|
24
|
-
label: '
|
|
25
|
-
helpTextKey: '
|
|
24
|
+
label: 'Refresh health data',
|
|
25
|
+
helpTextKey: 'Re-request the health assessment API',
|
|
26
26
|
},
|
|
27
27
|
];
|
|
28
28
|
|
|
@@ -30,14 +30,14 @@ export class ShowHealthResultModel {
|
|
|
30
30
|
{
|
|
31
31
|
type: 'panelInput',
|
|
32
32
|
name: 'xObjectApiKey',
|
|
33
|
-
label: '
|
|
34
|
-
placeholder: '
|
|
33
|
+
label: 'Entity key (xObjectApiKey)',
|
|
34
|
+
placeholder: 'e.g. opportunity',
|
|
35
35
|
},
|
|
36
36
|
{
|
|
37
37
|
type: 'panelInput',
|
|
38
38
|
name: 'id',
|
|
39
|
-
label: '
|
|
40
|
-
placeholder: '
|
|
39
|
+
label: 'Business data ID (data_id)',
|
|
40
|
+
placeholder: 'Business record primary key',
|
|
41
41
|
},
|
|
42
42
|
];
|
|
43
43
|
}
|