neo-cmp-cli 1.13.16 → 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/README.md +2 -1
- package/dist/index2.js +1 -1
- package/dist/main2.js +1 -1
- package/dist/neo/env.js +1 -1
- package/dist/neo/neoLogin.js +1 -1
- package/dist/neo/pushCmp.js +1 -1
- package/dist/package.json.js +1 -1
- package/package.json +3 -2
- package/template/antd-custom-cmp-template/package.json +1 -1
- package/template/asset-manage-template/docs/README.md +1 -232
- package/template/asset-manage-template/package.json +2 -2
- package/template/echarts-custom-cmp-template/package.json +1 -1
- package/template/empty-custom-cmp-template/package.json +2 -2
- package/template/map-custom-cmp-template/package.json +1 -1
- package/template/neo-bi-cmps/neo.config.js +7 -1
- package/template/neo-bi-cmps/package.json +8 -7
- package/template/neo-bi-cmps/public/403.html +77 -0
- package/template/neo-bi-cmps/public/demo.html +2453 -0
- package/template/neo-bi-cmps/src/assets/icon/barChart.svg +1 -0
- package/template/neo-bi-cmps/src/assets/icon/card.svg +1 -0
- package/template/neo-bi-cmps/src/assets/icon/filter.svg +1 -0
- package/template/neo-bi-cmps/src/assets/icon/funnel.svg +1 -0
- package/template/neo-bi-cmps/src/assets/icon/tab.svg +1 -0
- package/template/neo-bi-cmps/src/components/filterBar__c/README.md +3 -14
- package/template/neo-bi-cmps/src/components/filterBar__c/common.scss +29 -0
- package/template/neo-bi-cmps/src/components/filterBar__c/index.tsx +668 -146
- package/template/neo-bi-cmps/src/components/filterBar__c/model.ts +26 -48
- package/template/neo-bi-cmps/src/components/filterBar__c/style.scss +46 -139
- package/template/neo-bi-cmps/src/components/targetNumber__c/customStyleConfig/index.tsx +11 -10
- package/template/neo-bi-cmps/src/components/targetNumber__c/index.tsx +9 -16
- package/template/neo-bi-cmps/src/components/targetNumber__c/model.ts +1 -1
- package/template/neo-bi-cmps/src/utils/common.ts +231 -0
- package/template/neo-bi-cmps/src/utils/filter2chartFilter.ts +268 -0
- package/template/neo-bi-cmps/src/utils/filterBar.ts +140 -0
- package/template/neo-bi-cmps/src/utils/pipelineFunnel.ts +341 -0
- package/template/{neo-h5-cmps/src/utils/queryObjectData.ts → neo-bi-cmps/src/utils/queryByCustomSQL.ts} +18 -13
- package/template/neo-bi-cmps/src/utils/requestDebounce.ts +22 -0
- package/template/neo-bi-cmps/src/utils/simpleTable.tsx +344 -0
- package/template/neo-bi-cmps/src/utils/stageSwitch.ts +15 -0
- package/template/neo-bi-cmps/src/utils/stageTimeChart.ts +90 -0
- package/template/neo-bi-cmps/src/utils/targetNumber.ts +12 -0
- package/template/neo-custom-cmp-template/docs/README.md +0 -231
- package/template/neo-custom-cmp-template/package.json +2 -2
- package/template/neo-h5-cmps/package.json +2 -2
- 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-order-cmps/package.json +2 -2
- package/template/neo-pipeline-cmps/.prettierrc.js +12 -0
- package/template/neo-pipeline-cmps/@types/neo-ui-common.d.ts +36 -0
- package/template/neo-pipeline-cmps/README.md +99 -0
- package/template/neo-pipeline-cmps/commitlint.config.js +59 -0
- package/template/neo-pipeline-cmps/neo.config.js +135 -0
- package/template/neo-pipeline-cmps/package.json +66 -0
- package/template/neo-pipeline-cmps/public/403.html +77 -0
- package/template/neo-pipeline-cmps/public/css/base.css +283 -0
- package/template/neo-pipeline-cmps/public/demo.html +2453 -0
- package/template/neo-pipeline-cmps/public/scripts/app/bluebird.js +6679 -0
- package/template/neo-pipeline-cmps/public/template.html +13 -0
- package/template/neo-pipeline-cmps/src/assets/css/common.scss +127 -0
- package/template/neo-pipeline-cmps/src/assets/css/mixin.scss +47 -0
- package/template/neo-pipeline-cmps/src/assets/icon/barChart.svg +1 -0
- package/template/neo-pipeline-cmps/src/assets/icon/card.svg +1 -0
- package/template/neo-pipeline-cmps/src/assets/icon/filter.svg +1 -0
- package/template/neo-pipeline-cmps/src/assets/icon/funnel.svg +1 -0
- package/template/neo-pipeline-cmps/src/assets/icon/tab.svg +1 -0
- package/template/neo-pipeline-cmps/src/assets/img/AIBtn.gif +0 -0
- package/template/neo-pipeline-cmps/src/assets/img/NeoCRM.jpg +0 -0
- package/template/neo-pipeline-cmps/src/assets/img/aiLogo.png +0 -0
- package/template/neo-pipeline-cmps/src/assets/img/card-list.svg +1 -0
- package/template/neo-pipeline-cmps/src/assets/img/contact-form.svg +1 -0
- package/template/neo-pipeline-cmps/src/assets/img/custom-form.svg +1 -0
- package/template/neo-pipeline-cmps/src/assets/img/custom-widget.svg +1 -0
- package/template/neo-pipeline-cmps/src/assets/img/data-list.svg +1 -0
- package/template/neo-pipeline-cmps/src/assets/img/detail.svg +1 -0
- package/template/neo-pipeline-cmps/src/assets/img/favicon.png +0 -0
- package/template/neo-pipeline-cmps/src/assets/img/map.svg +1 -0
- package/template/neo-pipeline-cmps/src/assets/img/search.svg +1 -0
- package/template/neo-pipeline-cmps/src/assets/img/table.svg +1 -0
- package/template/neo-pipeline-cmps/src/components/filterBar__c/README.md +24 -0
- package/template/neo-pipeline-cmps/src/components/filterBar__c/common.scss +29 -0
- package/template/neo-pipeline-cmps/src/components/filterBar__c/index.tsx +731 -0
- package/template/neo-pipeline-cmps/src/components/filterBar__c/model.ts +52 -0
- package/template/neo-pipeline-cmps/src/components/filterBar__c/style.scss +119 -0
- package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/README.md +39 -0
- package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/index.tsx +416 -0
- package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/model.ts +80 -0
- package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/style.scss +83 -0
- package/template/neo-pipeline-cmps/src/components/showHealthResult__c/index.tsx +470 -0
- package/template/neo-pipeline-cmps/src/components/showHealthResult__c/model.ts +45 -0
- package/template/neo-pipeline-cmps/src/components/showHealthResult__c/style.scss +137 -0
- package/template/neo-pipeline-cmps/src/components/simpleTable__c/README.md +89 -0
- package/template/neo-pipeline-cmps/src/components/simpleTable__c/common.scss +195 -0
- package/template/neo-pipeline-cmps/src/components/simpleTable__c/index.tsx +667 -0
- package/template/neo-pipeline-cmps/src/components/simpleTable__c/model.ts +124 -0
- package/template/neo-pipeline-cmps/src/components/simpleTable__c/style.scss +192 -0
- package/template/neo-pipeline-cmps/src/components/stageSwitch__c/README.md +36 -0
- package/template/neo-pipeline-cmps/src/components/stageSwitch__c/index.tsx +513 -0
- package/template/neo-pipeline-cmps/src/components/stageSwitch__c/model.ts +71 -0
- package/template/{neo-bi-cmps → neo-pipeline-cmps}/src/components/stageSwitch__c/style.scss +4 -2
- package/template/neo-pipeline-cmps/src/components/stageTimeChart__c/README.md +37 -0
- package/template/neo-pipeline-cmps/src/components/stageTimeChart__c/index.tsx +455 -0
- package/template/neo-pipeline-cmps/src/components/stageTimeChart__c/model.ts +106 -0
- package/template/{neo-bi-cmps → neo-pipeline-cmps}/src/components/stageTimeChart__c/style.scss +3 -2
- package/template/neo-pipeline-cmps/src/utils/common.ts +229 -0
- package/template/neo-pipeline-cmps/src/utils/filter2chartFilter.ts +266 -0
- package/template/neo-pipeline-cmps/src/utils/filterBar.ts +140 -0
- package/template/neo-pipeline-cmps/src/utils/pipelineFunnel.ts +343 -0
- package/template/neo-pipeline-cmps/src/utils/queryByCustomSQL.ts +121 -0
- package/template/neo-pipeline-cmps/src/utils/requestDebounce.ts +22 -0
- package/template/neo-pipeline-cmps/src/utils/simpleTable.tsx +349 -0
- package/template/neo-pipeline-cmps/src/utils/stageSwitch.ts +15 -0
- package/template/neo-pipeline-cmps/src/utils/stageTimeChart.ts +90 -0
- package/template/neo-pipeline-cmps/src/utils/targetNumber.ts +12 -0
- package/template/neo-pipeline-cmps/tsconfig.json +40 -0
- package/template/neo-web-entity-grid/package.json +2 -2
- package/template/neo-web-form/package.json +2 -2
- 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/react-ts-custom-cmp-template/package.json +1 -1
- package/template/vue2-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-bi-cmps/.npmrc copy +0 -1
- package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/README.md +0 -52
- package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/index.tsx +0 -183
- package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/model.ts +0 -90
- package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/style.scss +0 -218
- package/template/neo-bi-cmps/src/components/forecastChart__c/README.md +0 -31
- package/template/neo-bi-cmps/src/components/forecastChart__c/index.tsx +0 -158
- package/template/neo-bi-cmps/src/components/forecastChart__c/model.ts +0 -40
- package/template/neo-bi-cmps/src/components/forecastChart__c/style.scss +0 -154
- package/template/neo-bi-cmps/src/components/forecastGrid__c/README.md +0 -36
- package/template/neo-bi-cmps/src/components/forecastGrid__c/index.tsx +0 -86
- package/template/neo-bi-cmps/src/components/forecastGrid__c/model.ts +0 -62
- package/template/neo-bi-cmps/src/components/forecastGrid__c/style.scss +0 -48
- package/template/neo-bi-cmps/src/components/gapCloser__c/README.md +0 -24
- package/template/neo-bi-cmps/src/components/gapCloser__c/index.tsx +0 -100
- package/template/neo-bi-cmps/src/components/gapCloser__c/model.ts +0 -46
- package/template/neo-bi-cmps/src/components/gapCloser__c/style.scss +0 -60
- package/template/neo-bi-cmps/src/components/kpiCards__c/README.md +0 -35
- package/template/neo-bi-cmps/src/components/kpiCards__c/index.tsx +0 -70
- package/template/neo-bi-cmps/src/components/kpiCards__c/model.ts +0 -50
- package/template/neo-bi-cmps/src/components/kpiCards__c/style.scss +0 -33
- package/template/neo-bi-cmps/src/components/oppList__c/README.md +0 -52
- package/template/neo-bi-cmps/src/components/oppList__c/index.tsx +0 -285
- package/template/neo-bi-cmps/src/components/oppList__c/model.ts +0 -86
- package/template/neo-bi-cmps/src/components/oppList__c/style.scss +0 -133
- package/template/neo-bi-cmps/src/components/pipelineFunnel__c/README.md +0 -39
- package/template/neo-bi-cmps/src/components/pipelineFunnel__c/index.tsx +0 -130
- package/template/neo-bi-cmps/src/components/pipelineFunnel__c/model.ts +0 -66
- package/template/neo-bi-cmps/src/components/pipelineFunnel__c/style.scss +0 -133
- package/template/neo-bi-cmps/src/components/stageSwitch__c/README.md +0 -36
- package/template/neo-bi-cmps/src/components/stageSwitch__c/index.tsx +0 -118
- package/template/neo-bi-cmps/src/components/stageSwitch__c/model.ts +0 -92
- package/template/neo-bi-cmps/src/components/stageTimeChart__c/README.md +0 -37
- package/template/neo-bi-cmps/src/components/stageTimeChart__c/index.tsx +0 -126
- package/template/neo-bi-cmps/src/components/stageTimeChart__c/model.ts +0 -57
- package/template/neo-bi-cmps/src/components/tabSwitch__c/README.md +0 -37
- package/template/neo-bi-cmps/src/components/tabSwitch__c/index.tsx +0 -80
- package/template/neo-bi-cmps/src/components/tabSwitch__c/model.ts +0 -45
- package/template/neo-bi-cmps/src/components/tabSwitch__c/style.scss +0 -37
- package/template/neo-bi-cmps/src/utils/axiosFetcher.ts +0 -37
- package/template/neo-bi-cmps/src/utils/queryObjectData.ts +0 -76
- package/template/neo-bi-cmps/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/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
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
export class FilterBarModel {
|
|
2
|
+
label: string = 'Filter Bar';
|
|
3
|
+
description: string =
|
|
4
|
+
'Supports multi-dimensional filtering by date range, owner, business type, etc.';
|
|
5
|
+
iconUrl: string = 'https://custom-widgets.bj.bcebos.com/filter.svg';
|
|
6
|
+
targetPage: string[] = ['all'];
|
|
7
|
+
targetDevice: string = 'all';
|
|
8
|
+
|
|
9
|
+
defaultComProps = {
|
|
10
|
+
closeDateOptions: [
|
|
11
|
+
{ value: 201, label: 'This Week' },
|
|
12
|
+
{ value: 301, label: 'This Month' },
|
|
13
|
+
{ value: 401, label: 'This Quarter' },
|
|
14
|
+
{ value: 'custom', label: 'Custom' },
|
|
15
|
+
],
|
|
16
|
+
/** When matching the apiKey of an item returned by the business type API, use it as the default Business Type selection */
|
|
17
|
+
defaultBusiType: 'defaultBusiType_1', // New Business
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Declare all events that the current component will trigger (matching @NeoEvent.dispatch method names in the component)
|
|
22
|
+
*/
|
|
23
|
+
events = [
|
|
24
|
+
{
|
|
25
|
+
apiKey: 'onFiltersChange',
|
|
26
|
+
label: 'After filter conditions change',
|
|
27
|
+
helpText:
|
|
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)',
|
|
29
|
+
eventParams:
|
|
30
|
+
'[{"apiKey":"eventParam","children":[{"apiKey":"data","label":"Current filter data","type":"Object"}],"label":"Event parameters","type":"Object"}]',
|
|
31
|
+
},
|
|
32
|
+
];
|
|
33
|
+
|
|
34
|
+
functions = [
|
|
35
|
+
{
|
|
36
|
+
apiKey: 'resetFilters',
|
|
37
|
+
label: 'Reset filters',
|
|
38
|
+
helpTextKey:
|
|
39
|
+
'Reset all filter conditions to defaults and trigger the "After filter conditions change" event',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
apiKey: 'getFilters',
|
|
43
|
+
label: 'Get filters',
|
|
44
|
+
helpTextKey:
|
|
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',
|
|
46
|
+
},
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
propsSchema = [];
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export default FilterBarModel;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
.filterBar__c {
|
|
2
|
+
background: #fff;
|
|
3
|
+
border-radius: 8px;
|
|
4
|
+
padding: 16px 20px;
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-wrap: wrap;
|
|
7
|
+
justify-content: flex-start;
|
|
8
|
+
gap: 10px 12px;
|
|
9
|
+
align-items: flex-start;
|
|
10
|
+
align-content: flex-start;
|
|
11
|
+
margin-bottom: 12px;
|
|
12
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
|
|
13
|
+
|
|
14
|
+
.filter-block {
|
|
15
|
+
display: flex;
|
|
16
|
+
flex-wrap: nowrap;
|
|
17
|
+
align-items: center;
|
|
18
|
+
gap: 6px 8px;
|
|
19
|
+
flex: 0 1 auto;
|
|
20
|
+
min-width: 0;
|
|
21
|
+
max-width: 100%;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.filter-field {
|
|
25
|
+
display: flex;
|
|
26
|
+
flex-wrap: nowrap;
|
|
27
|
+
align-items: center;
|
|
28
|
+
gap: 6px;
|
|
29
|
+
min-width: 0;
|
|
30
|
+
|
|
31
|
+
label {
|
|
32
|
+
font-size: 13px;
|
|
33
|
+
color: #666;
|
|
34
|
+
white-space: nowrap;
|
|
35
|
+
display: inline-flex;
|
|
36
|
+
align-items: center;
|
|
37
|
+
gap: 4px;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
&.filter-field-range {
|
|
41
|
+
flex: 0 0 auto;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
.filter-select {
|
|
46
|
+
min-width: 160px;
|
|
47
|
+
max-width: 100%;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.filter-select-wide {
|
|
51
|
+
min-width: 220px;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.filter-select-spin-wrap {
|
|
55
|
+
min-width: 220px;
|
|
56
|
+
min-height: 32px;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
.filter-btn {
|
|
60
|
+
padding: 6px 16px;
|
|
61
|
+
border-radius: 6px;
|
|
62
|
+
font-size: 13px;
|
|
63
|
+
cursor: pointer;
|
|
64
|
+
border: 1px solid #ddd;
|
|
65
|
+
background: #fff;
|
|
66
|
+
|
|
67
|
+
&.active {
|
|
68
|
+
background: #6366f1;
|
|
69
|
+
color: #fff;
|
|
70
|
+
border-color: #6366f1;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* Changes Since question mark tooltip */
|
|
75
|
+
.help-tip {
|
|
76
|
+
position: relative;
|
|
77
|
+
display: inline-flex;
|
|
78
|
+
align-items: center;
|
|
79
|
+
justify-content: center;
|
|
80
|
+
cursor: help;
|
|
81
|
+
color: #999;
|
|
82
|
+
font-size: 12px;
|
|
83
|
+
margin-left: 2px;
|
|
84
|
+
width: 16px;
|
|
85
|
+
height: 16px;
|
|
86
|
+
border-radius: 50%;
|
|
87
|
+
border: 1px solid #ddd;
|
|
88
|
+
|
|
89
|
+
.help-tip-text {
|
|
90
|
+
display: none;
|
|
91
|
+
position: absolute;
|
|
92
|
+
bottom: calc(100% + 6px);
|
|
93
|
+
left: 50%;
|
|
94
|
+
transform: translateX(-50%);
|
|
95
|
+
background: #333;
|
|
96
|
+
color: #fff;
|
|
97
|
+
padding: 6px 10px;
|
|
98
|
+
border-radius: 6px;
|
|
99
|
+
font-size: 11px;
|
|
100
|
+
white-space: nowrap;
|
|
101
|
+
z-index: 100;
|
|
102
|
+
font-weight: 400;
|
|
103
|
+
|
|
104
|
+
&::after {
|
|
105
|
+
content: '';
|
|
106
|
+
position: absolute;
|
|
107
|
+
top: 100%;
|
|
108
|
+
left: 50%;
|
|
109
|
+
transform: translateX(-50%);
|
|
110
|
+
border: 5px solid transparent;
|
|
111
|
+
border-top-color: #333;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
&:hover .help-tip-text {
|
|
116
|
+
display: block;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# PipelineFunnel Component
|
|
2
|
+
|
|
3
|
+
Pipeline funnel chart component that displays the funnel conversion of the sales pipeline.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import PipelineFunnel from './components/pipelineFunnel__c';
|
|
9
|
+
|
|
10
|
+
<PipelineFunnel
|
|
11
|
+
title="Pipeline Funnel"
|
|
12
|
+
totalAmount="$11.1M"
|
|
13
|
+
stages={[
|
|
14
|
+
{ name: 'Prospecting', amount: '$3.2M', count: 15, color: '#3b82f6' },
|
|
15
|
+
{ name: 'Needs Analysis', amount: '$1.8M', count: 7, conversionRate: '56.3%', color: '#22c55e' },
|
|
16
|
+
]}
|
|
17
|
+
onStageClick={(name) => console.log('Clicked:', name)}
|
|
18
|
+
/>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Props
|
|
22
|
+
|
|
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
|
+
|
|
31
|
+
## FunnelStage
|
|
32
|
+
|
|
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 |
|
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Pipeline Funnel Chart Component
|
|
3
|
+
* @description Displays the funnel conversion of the sales pipeline, data from NeoBI queryDataTask
|
|
4
|
+
*/
|
|
5
|
+
import * as React from 'react';
|
|
6
|
+
import * as echarts from 'echarts';
|
|
7
|
+
import { Spin } from 'antd';
|
|
8
|
+
// @ts-ignore
|
|
9
|
+
import { request } from 'neo-open-api';
|
|
10
|
+
// @ts-ignore
|
|
11
|
+
import { BaseCmp, NeoEvent } from 'neo-ui-common';
|
|
12
|
+
// @ts-ignore
|
|
13
|
+
import isEqual from 'lodash/isEqual';
|
|
14
|
+
import { filter2chartFilter } from '../../utils/filter2chartFilter';
|
|
15
|
+
import {
|
|
16
|
+
buildQueryDataTaskFormBody,
|
|
17
|
+
formatAmountDisplay,
|
|
18
|
+
getDefaultFilterWhereByProps,
|
|
19
|
+
} from '../../utils/common';
|
|
20
|
+
import {
|
|
21
|
+
buildFunnelChartOption,
|
|
22
|
+
filterOutClosedLostRows,
|
|
23
|
+
isTruthyProp,
|
|
24
|
+
parseRowsToStages,
|
|
25
|
+
type FunnelStage,
|
|
26
|
+
} from '../../utils/pipelineFunnel';
|
|
27
|
+
|
|
28
|
+
import './style.scss';
|
|
29
|
+
|
|
30
|
+
const QUERY_DATA_TASK_URL = '/rest/neobi/v2.0/bestpractices/queryDataTask';
|
|
31
|
+
|
|
32
|
+
const FORM_URLENCODED_UTF8 = 'application/x-www-form-urlencoded;charset=UTF-8';
|
|
33
|
+
|
|
34
|
+
interface PipelineFunnelProps {
|
|
35
|
+
title?: string;
|
|
36
|
+
/** View ID, used in queryDataTask */
|
|
37
|
+
viewId?: string;
|
|
38
|
+
/** View type, corresponding to request parameter type */
|
|
39
|
+
viewType?: string;
|
|
40
|
+
/**
|
|
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
|
+
useClassicFunnelShape?: boolean;
|
|
44
|
+
/** Neo injected, contains current user */
|
|
45
|
+
data?: {
|
|
46
|
+
__NeoCurrentUser?: { id?: string | number };
|
|
47
|
+
};
|
|
48
|
+
showAiButton?: boolean;
|
|
49
|
+
onStageClick?: (stageName: string) => void;
|
|
50
|
+
className?: string;
|
|
51
|
+
style?: React.CSSProperties;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
interface PipelineFunnelState {
|
|
55
|
+
loading: boolean;
|
|
56
|
+
error: string | null;
|
|
57
|
+
stages: FunnelStage[];
|
|
58
|
+
/** Sum of amount values across all stages, used for percentage calculation */
|
|
59
|
+
totalAmountNum: number;
|
|
60
|
+
/** Total amount label for top display */
|
|
61
|
+
totalAmountLabel: string;
|
|
62
|
+
/** Filter for request body, can be updated by component action setFilter */
|
|
63
|
+
filter: any;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
class PipelineFunnel extends BaseCmp<PipelineFunnelProps, PipelineFunnelState> {
|
|
67
|
+
private chartRef = React.createRef<HTMLDivElement>();
|
|
68
|
+
|
|
69
|
+
private chartInstance: echarts.ECharts | null = null;
|
|
70
|
+
|
|
71
|
+
private resizeObserver: ResizeObserver | null = null;
|
|
72
|
+
|
|
73
|
+
constructor(props: PipelineFunnelProps) {
|
|
74
|
+
super(props);
|
|
75
|
+
this.state = {
|
|
76
|
+
loading: false,
|
|
77
|
+
error: null,
|
|
78
|
+
stages: [],
|
|
79
|
+
totalAmountNum: 0,
|
|
80
|
+
totalAmountLabel: formatAmountDisplay(0),
|
|
81
|
+
filter: getDefaultFilterWhereByProps(props),
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
this.initChart = this.initChart.bind(this);
|
|
85
|
+
this.bindResize = this.bindResize.bind(this);
|
|
86
|
+
this.unbindResize = this.unbindResize.bind(this);
|
|
87
|
+
this.handleWindowResize = this.handleWindowResize.bind(this);
|
|
88
|
+
this.updateChart = this.updateChart.bind(this);
|
|
89
|
+
this.fetchChartData = this.fetchChartData.bind(this);
|
|
90
|
+
this.refreshData = this.refreshData.bind(this);
|
|
91
|
+
this.setFilter = this.setFilter.bind(this);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
componentDidMount() {
|
|
95
|
+
this.fetchChartData();
|
|
96
|
+
this.initChart();
|
|
97
|
+
this.bindResize();
|
|
98
|
+
|
|
99
|
+
/*
|
|
100
|
+
// Listen to a broadcast event
|
|
101
|
+
NeoEvent.listen('updateFilterData', (filterData: any) => {
|
|
102
|
+
console.log('PipelineFunnel received broadcast event updateFilterData: ', filterData);
|
|
103
|
+
this.setFilter(filterData);
|
|
104
|
+
});
|
|
105
|
+
*/
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
componentDidUpdate(
|
|
109
|
+
prevProps: PipelineFunnelProps,
|
|
110
|
+
prevState: PipelineFunnelState,
|
|
111
|
+
) {
|
|
112
|
+
const uid = this.props.data?.__NeoCurrentUser?.id;
|
|
113
|
+
const puid = prevProps.data?.__NeoCurrentUser?.id;
|
|
114
|
+
if (
|
|
115
|
+
this.props.viewId !== prevProps.viewId ||
|
|
116
|
+
this.props.viewType !== prevProps.viewType ||
|
|
117
|
+
uid !== puid
|
|
118
|
+
) {
|
|
119
|
+
this.fetchChartData();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (
|
|
123
|
+
prevState.stages !== this.state.stages ||
|
|
124
|
+
prevState.loading !== this.state.loading ||
|
|
125
|
+
isTruthyProp(prevProps.useClassicFunnelShape) !==
|
|
126
|
+
isTruthyProp(this.props.useClassicFunnelShape)
|
|
127
|
+
) {
|
|
128
|
+
this.updateChart();
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (!this.chartInstance && this.chartRef.current) {
|
|
132
|
+
this.initChart();
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
componentWillUnmount() {
|
|
137
|
+
this.unbindResize();
|
|
138
|
+
if (this.chartInstance) {
|
|
139
|
+
this.chartInstance.dispose();
|
|
140
|
+
this.chartInstance = null;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
initChart() {
|
|
145
|
+
if (!this.chartRef.current || this.chartInstance) return;
|
|
146
|
+
this.chartInstance = echarts.init(this.chartRef.current);
|
|
147
|
+
this.updateChart();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
bindResize() {
|
|
151
|
+
window.addEventListener('resize', this.handleWindowResize);
|
|
152
|
+
if (typeof ResizeObserver === 'undefined') return;
|
|
153
|
+
this.resizeObserver = new ResizeObserver(() => {
|
|
154
|
+
this.chartInstance?.resize();
|
|
155
|
+
if (
|
|
156
|
+
isTruthyProp(this.props.useClassicFunnelShape) &&
|
|
157
|
+
this.state.stages.length > 0
|
|
158
|
+
) {
|
|
159
|
+
this.updateChart();
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
const el = this.chartRef.current;
|
|
163
|
+
if (el) this.resizeObserver.observe(el);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
unbindResize() {
|
|
167
|
+
window.removeEventListener('resize', this.handleWindowResize);
|
|
168
|
+
this.resizeObserver?.disconnect();
|
|
169
|
+
this.resizeObserver = null;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
handleWindowResize() {
|
|
173
|
+
this.chartInstance?.resize();
|
|
174
|
+
if (
|
|
175
|
+
isTruthyProp(this.props.useClassicFunnelShape) &&
|
|
176
|
+
this.state.stages.length > 0
|
|
177
|
+
) {
|
|
178
|
+
this.updateChart();
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
updateChart() {
|
|
183
|
+
if (!this.chartInstance) return;
|
|
184
|
+
const { stages } = this.state;
|
|
185
|
+
const { onStageClick, useClassicFunnelShape } = this.props;
|
|
186
|
+
const classicShape = isTruthyProp(useClassicFunnelShape);
|
|
187
|
+
const el = this.chartRef.current;
|
|
188
|
+
const fallbackH = Math.max(stages.length * 52, 220);
|
|
189
|
+
const chartViewHeightPx = Math.max(el?.clientHeight ?? 0, fallbackH);
|
|
190
|
+
|
|
191
|
+
try {
|
|
192
|
+
if (stages.length === 0) {
|
|
193
|
+
this.chartInstance.clear();
|
|
194
|
+
} else {
|
|
195
|
+
const option = buildFunnelChartOption(stages, classicShape, {
|
|
196
|
+
chartViewHeightPx: classicShape ? chartViewHeightPx : undefined,
|
|
197
|
+
funnelGap: 2,
|
|
198
|
+
});
|
|
199
|
+
console.log('[PipelineFunnel__c] updateChart option:', option);
|
|
200
|
+
this.chartInstance.setOption(option, true);
|
|
201
|
+
this.chartInstance.off('click');
|
|
202
|
+
this.chartInstance.on(
|
|
203
|
+
'click',
|
|
204
|
+
(params: {
|
|
205
|
+
componentType?: string;
|
|
206
|
+
seriesType?: string;
|
|
207
|
+
seriesName?: string;
|
|
208
|
+
dataIndex?: number;
|
|
209
|
+
}) => {
|
|
210
|
+
if (
|
|
211
|
+
params.componentType === 'series' &&
|
|
212
|
+
params.seriesType === 'funnel' &&
|
|
213
|
+
params.seriesName !== 'PipelineName'
|
|
214
|
+
) {
|
|
215
|
+
const idx =
|
|
216
|
+
typeof params.dataIndex === 'number' ? params.dataIndex : -1;
|
|
217
|
+
const name = stages[idx]?.name;
|
|
218
|
+
if (name) {
|
|
219
|
+
this.handleStageClick(name);
|
|
220
|
+
onStageClick?.(name);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
},
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
requestAnimationFrame(() => this.chartInstance?.resize());
|
|
227
|
+
} catch (e) {
|
|
228
|
+
console.error('PipelineFunnel ECharts update failed:', e);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
async fetchChartData() {
|
|
233
|
+
const { viewId, viewType } = this.props;
|
|
234
|
+
const userId = this.props.data?.__NeoCurrentUser?.id;
|
|
235
|
+
|
|
236
|
+
if (viewId == null || viewId === '' || userId == null || userId === '') {
|
|
237
|
+
this.setState({
|
|
238
|
+
loading: false,
|
|
239
|
+
error: 'Missing viewId or current user id (data.__NeoCurrentUser.id)',
|
|
240
|
+
stages: [],
|
|
241
|
+
totalAmountNum: 0,
|
|
242
|
+
totalAmountLabel: formatAmountDisplay(0),
|
|
243
|
+
});
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
this.setState({ loading: true, error: null });
|
|
248
|
+
|
|
249
|
+
try {
|
|
250
|
+
const filterObj =
|
|
251
|
+
this.state.filter &&
|
|
252
|
+
typeof this.state.filter === 'object' &&
|
|
253
|
+
!Array.isArray(this.state.filter)
|
|
254
|
+
? this.state.filter
|
|
255
|
+
: {};
|
|
256
|
+
|
|
257
|
+
const res = await request({
|
|
258
|
+
url: QUERY_DATA_TASK_URL,
|
|
259
|
+
method: 'POST',
|
|
260
|
+
data: buildQueryDataTaskFormBody({
|
|
261
|
+
viewId: String(viewId),
|
|
262
|
+
userId,
|
|
263
|
+
type: viewType ?? 'sync',
|
|
264
|
+
filter: filterObj,
|
|
265
|
+
}),
|
|
266
|
+
headers: {
|
|
267
|
+
'Content-Type': FORM_URLENCODED_UTF8,
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
const status = res?.status;
|
|
272
|
+
const table = res?.data;
|
|
273
|
+
|
|
274
|
+
if (status !== 0 || !Array.isArray(table)) {
|
|
275
|
+
this.setState({
|
|
276
|
+
loading: false,
|
|
277
|
+
error: res?.message || res?.msg || 'Failed to query chart data',
|
|
278
|
+
stages: [],
|
|
279
|
+
totalAmountNum: 0,
|
|
280
|
+
totalAmountLabel: formatAmountDisplay(0),
|
|
281
|
+
});
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const filteredTable = filterOutClosedLostRows(table as unknown[][]);
|
|
286
|
+
const { stages, totalAmountNum } = parseRowsToStages(filteredTable);
|
|
287
|
+
|
|
288
|
+
this.setState({
|
|
289
|
+
loading: false,
|
|
290
|
+
error: null,
|
|
291
|
+
stages,
|
|
292
|
+
totalAmountNum,
|
|
293
|
+
totalAmountLabel: formatAmountDisplay(totalAmountNum),
|
|
294
|
+
});
|
|
295
|
+
} catch (e: any) {
|
|
296
|
+
console.error('PipelineFunnel queryDataTask failed:', e);
|
|
297
|
+
this.setState({
|
|
298
|
+
loading: false,
|
|
299
|
+
error: e?.message || 'Network request failed',
|
|
300
|
+
stages: [],
|
|
301
|
+
totalAmountNum: 0,
|
|
302
|
+
totalAmountLabel: formatAmountDisplay(0),
|
|
303
|
+
});
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Refresh funnel chart data (bindable in designer)
|
|
309
|
+
*/
|
|
310
|
+
@NeoEvent.function
|
|
311
|
+
async refreshData() {
|
|
312
|
+
await this.fetchChartData();
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
/**
|
|
316
|
+
* Set filter conditions and re-fetch data (bindable in designer)
|
|
317
|
+
* @param filter Filter object, used as the filter field of queryDataTask
|
|
318
|
+
*/
|
|
319
|
+
@NeoEvent.function
|
|
320
|
+
setFilter(filter?: any) {
|
|
321
|
+
if (!filter) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const nextFilter = filter2chartFilter(filter);
|
|
325
|
+
console.log('[PipelineFunnel__c] setFilter:', filter, nextFilter);
|
|
326
|
+
if (!isEqual(nextFilter, this.state.filter)) {
|
|
327
|
+
this.setState({ filter: nextFilter }, () => {
|
|
328
|
+
this.fetchChartData();
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
@NeoEvent.dispatch
|
|
334
|
+
onActiveStageChange(eventData?: any) {}
|
|
335
|
+
|
|
336
|
+
// Update the current active sales stage when clicking a stage
|
|
337
|
+
handleStageClick(stageName: string) {
|
|
338
|
+
this.onActiveStageChange({
|
|
339
|
+
activeStage: stageName,
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
render() {
|
|
344
|
+
const {
|
|
345
|
+
title = 'Pipeline Funnel',
|
|
346
|
+
// showAiButton = false,
|
|
347
|
+
className,
|
|
348
|
+
style,
|
|
349
|
+
} = this.props;
|
|
350
|
+
const showAiButton = false;
|
|
351
|
+
|
|
352
|
+
const { loading, error, stages, totalAmountLabel } = this.state;
|
|
353
|
+
const chartHeight = Math.max(stages.length * 52, 200);
|
|
354
|
+
|
|
355
|
+
return (
|
|
356
|
+
<div
|
|
357
|
+
className={`pipelineFunnel__c ${className || ''}`}
|
|
358
|
+
style={style}
|
|
359
|
+
data-time="2026.4.17 01"
|
|
360
|
+
>
|
|
361
|
+
<Spin spinning={loading}>
|
|
362
|
+
<div className="funnel-header">
|
|
363
|
+
<h3 className="funnel-title">{title}</h3>
|
|
364
|
+
{showAiButton && (
|
|
365
|
+
<span
|
|
366
|
+
className="ai-btn"
|
|
367
|
+
onClick={() => console.log('AI Analysis clicked')}
|
|
368
|
+
title="AI Analysis"
|
|
369
|
+
>
|
|
370
|
+
✨
|
|
371
|
+
</span>
|
|
372
|
+
)}
|
|
373
|
+
</div>
|
|
374
|
+
|
|
375
|
+
{error ? (
|
|
376
|
+
<div
|
|
377
|
+
className="funnel-error"
|
|
378
|
+
style={{ color: '#cf1322', fontSize: 12, marginBottom: 8 }}
|
|
379
|
+
>
|
|
380
|
+
{error}
|
|
381
|
+
</div>
|
|
382
|
+
) : null}
|
|
383
|
+
|
|
384
|
+
<div className="funnel-total">
|
|
385
|
+
<div className="funnel-total-label">Sales Amount</div>
|
|
386
|
+
<div className="funnel-total-value">{totalAmountLabel}</div>
|
|
387
|
+
</div>
|
|
388
|
+
|
|
389
|
+
<div className="funnel-body">
|
|
390
|
+
<div className="funnel-chart-wrap" style={{ height: chartHeight }}>
|
|
391
|
+
<div
|
|
392
|
+
ref={this.chartRef}
|
|
393
|
+
className="funnel-chart"
|
|
394
|
+
style={{ width: '100%', height: chartHeight }}
|
|
395
|
+
/>
|
|
396
|
+
</div>
|
|
397
|
+
</div>
|
|
398
|
+
|
|
399
|
+
<div className="funnel-legend">
|
|
400
|
+
{stages.map((stage, index) => (
|
|
401
|
+
<span key={index} className="legend-item">
|
|
402
|
+
<span
|
|
403
|
+
className="legend-dot"
|
|
404
|
+
style={{ backgroundColor: stage.color }}
|
|
405
|
+
/>
|
|
406
|
+
{stage.name}
|
|
407
|
+
</span>
|
|
408
|
+
))}
|
|
409
|
+
</div>
|
|
410
|
+
</Spin>
|
|
411
|
+
</div>
|
|
412
|
+
);
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
export default PipelineFunnel;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
export class PipelineFunnelModel {
|
|
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';
|
|
5
|
+
iconUrl: string = 'https://custom-widgets.bj.bcebos.com/funnel.svg';
|
|
6
|
+
targetPage: string[] = ['all'];
|
|
7
|
+
targetDevice: string = 'all';
|
|
8
|
+
|
|
9
|
+
defaultComProps = {
|
|
10
|
+
title: 'Pipeline Funnel',
|
|
11
|
+
viewId: '4264464770007375',
|
|
12
|
+
viewType: 'sync',
|
|
13
|
+
showAiButton: true,
|
|
14
|
+
/** When true, layer width decreases with stage order (classic shape), layer height proportional to amount; default false, layer width proportional to actual amount */
|
|
15
|
+
useClassicFunnelShape: false,
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
events = [
|
|
19
|
+
{
|
|
20
|
+
apiKey: 'onActiveStageChange',
|
|
21
|
+
label: 'Triggered on stage click',
|
|
22
|
+
helpText:
|
|
23
|
+
'Triggered when clicking a funnel stage; event params include activeStage (current active stage)',
|
|
24
|
+
eventParams:
|
|
25
|
+
'[{"apiKey":"eventParam","children":[{"apiKey":"activeStage","label":"Current active stage","type":"String"}],"label":"Event parameters","type":"Object"}]',
|
|
26
|
+
},
|
|
27
|
+
];
|
|
28
|
+
|
|
29
|
+
functions = [
|
|
30
|
+
{
|
|
31
|
+
apiKey: 'refreshData',
|
|
32
|
+
label: 'Refresh data',
|
|
33
|
+
helpTextKey: 'Re-request queryDataTask to refresh funnel chart data',
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
apiKey: 'setFilter',
|
|
37
|
+
label: 'Set filter conditions',
|
|
38
|
+
helpTextKey: 'Set the report component filter and re-fetch data',
|
|
39
|
+
funcInParams: [
|
|
40
|
+
{
|
|
41
|
+
apiKey: 'filter',
|
|
42
|
+
label: 'Filter conditions',
|
|
43
|
+
type: 'Object',
|
|
44
|
+
required: false,
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
propsSchema = [
|
|
51
|
+
{
|
|
52
|
+
type: 'panelInput',
|
|
53
|
+
name: 'title',
|
|
54
|
+
label: 'Title',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
type: 'panelInput',
|
|
58
|
+
name: 'viewId',
|
|
59
|
+
label: 'View ID',
|
|
60
|
+
},
|
|
61
|
+
{
|
|
62
|
+
type: 'panelInput',
|
|
63
|
+
name: 'viewType',
|
|
64
|
+
label: 'View type (request type)',
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
type: 'panelSelect',
|
|
68
|
+
name: 'useClassicFunnelShape',
|
|
69
|
+
label: 'Funnel shape',
|
|
70
|
+
value: false,
|
|
71
|
+
options: [
|
|
72
|
+
{ label: 'Shape based on actual amount', value: false },
|
|
73
|
+
{ label: 'Classic funnel (layer height by value)', value: true },
|
|
74
|
+
],
|
|
75
|
+
clearable: false,
|
|
76
|
+
},
|
|
77
|
+
];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export default PipelineFunnelModel;
|