neo-cmp-cli 1.13.11 → 1.13.13

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 (100) hide show
  1. package/dist/neo/neoService.js +1 -1
  2. package/dist/package.json.js +1 -1
  3. package/package.json +1 -1
  4. package/template/antd-custom-cmp-template/package.json +1 -1
  5. package/template/asset-manage-template/package.json +1 -1
  6. package/template/echarts-custom-cmp-template/package.json +1 -1
  7. package/template/empty-custom-cmp-template/package.json +1 -1
  8. package/template/map-custom-cmp-template/package.json +1 -1
  9. package/template/neo-bi-cmps/docs/gartner-pipeline-apis.md +279 -0
  10. package/template/neo-bi-cmps/docs/gartner-pipeline-prd.md +389 -0
  11. package/template/neo-bi-cmps/docs/neo-backend-dev/SKILL.md +188 -0
  12. package/template/neo-bi-cmps/docs/neo-backend-dev/references/01-Trigger/345/274/200/345/217/221.md +183 -0
  13. 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 +196 -0
  14. 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 +346 -0
  15. 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 +188 -0
  16. package/template/neo-bi-cmps/docs/neo-backend-dev/references/05-/351/241/265/351/235/242/345/274/200/345/217/221.md +293 -0
  17. 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 +175 -0
  18. 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 +313 -0
  19. package/template/neo-bi-cmps/docs/neo-backend-dev/references/auth-config.md +77 -0
  20. package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/deploy_server_script.py +118 -0
  21. package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/download_server_script.py +74 -0
  22. package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/gen_entity_desc.py +69 -0
  23. package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/gen_entitylist.py +87 -0
  24. package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/query_crm.py +65 -0
  25. package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/uninstall_server_script.py +48 -0
  26. package/template/neo-bi-cmps/docs/neo-backend-dev/scripts/update_model_jar.py +49 -0
  27. package/template/neo-bi-cmps/docs/neo-frontend-dev/SKILL.md +138 -0
  28. package/template/neo-bi-cmps/docs/neo-frontend-dev/references/auth-config.md +77 -0
  29. package/template/neo-bi-cmps/docs/neo-frontend-dev/references/component-dev.md +205 -0
  30. package/template/neo-bi-cmps/docs/neo-frontend-dev/references/entityTable-example.md +167 -0
  31. package/template/neo-bi-cmps/docs/neo-frontend-dev/references/templates.md +38 -0
  32. package/template/neo-bi-cmps/docs/neo-frontend-dev/scripts/gen_entity_desc.py +69 -0
  33. package/template/neo-bi-cmps/docs/neo-frontend-dev/scripts/gen_entitylist.py +87 -0
  34. package/template/neo-bi-cmps/docs/neo-frontend-dev/scripts/query_crm.py +65 -0
  35. package/template/neo-bi-cmps/docs/prototype-pipeline-forecasting.html +2453 -0
  36. 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 +10 -0
  37. package/template/neo-bi-cmps/package.json +1 -1
  38. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/README.md +52 -0
  39. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/index.tsx +176 -0
  40. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/model.ts +49 -0
  41. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/style.scss +218 -0
  42. package/template/neo-bi-cmps/src/components/filterBar__c/README.md +35 -0
  43. package/template/neo-bi-cmps/src/components/filterBar__c/index.tsx +186 -0
  44. package/template/neo-bi-cmps/src/components/filterBar__c/model.ts +72 -0
  45. package/template/neo-bi-cmps/src/components/filterBar__c/style.scss +212 -0
  46. package/template/neo-bi-cmps/src/components/forecastChart__c/README.md +31 -0
  47. package/template/neo-bi-cmps/src/components/forecastChart__c/index.tsx +161 -0
  48. package/template/neo-bi-cmps/src/components/forecastChart__c/model.ts +39 -0
  49. package/template/neo-bi-cmps/src/components/forecastChart__c/style.scss +154 -0
  50. package/template/neo-bi-cmps/src/components/forecastGrid__c/README.md +36 -0
  51. package/template/neo-bi-cmps/src/components/forecastGrid__c/index.tsx +86 -0
  52. package/template/neo-bi-cmps/src/components/forecastGrid__c/model.ts +34 -0
  53. package/template/neo-bi-cmps/src/components/forecastGrid__c/style.scss +48 -0
  54. package/template/neo-bi-cmps/src/components/gapCloser__c/README.md +24 -0
  55. package/template/neo-bi-cmps/src/components/gapCloser__c/index.tsx +95 -0
  56. package/template/neo-bi-cmps/src/components/gapCloser__c/model.ts +43 -0
  57. package/template/neo-bi-cmps/src/components/gapCloser__c/style.scss +60 -0
  58. package/template/neo-bi-cmps/src/components/kpiCards__c/README.md +35 -0
  59. package/template/neo-bi-cmps/src/components/kpiCards__c/index.tsx +70 -0
  60. package/template/neo-bi-cmps/src/components/kpiCards__c/model.ts +35 -0
  61. package/template/neo-bi-cmps/src/components/kpiCards__c/style.scss +33 -0
  62. package/template/neo-bi-cmps/src/components/oppList__c/README.md +52 -0
  63. package/template/neo-bi-cmps/src/components/oppList__c/index.tsx +228 -0
  64. package/template/neo-bi-cmps/src/components/oppList__c/model.ts +40 -0
  65. package/template/neo-bi-cmps/src/components/oppList__c/style.scss +133 -0
  66. package/template/neo-bi-cmps/src/components/pipelineFunnel__c/README.md +39 -0
  67. package/template/neo-bi-cmps/src/components/pipelineFunnel__c/index.tsx +128 -0
  68. package/template/neo-bi-cmps/src/components/pipelineFunnel__c/model.ts +42 -0
  69. package/template/neo-bi-cmps/src/components/pipelineFunnel__c/style.scss +133 -0
  70. package/template/neo-bi-cmps/src/components/stageSwitch__c/README.md +36 -0
  71. package/template/neo-bi-cmps/src/components/stageSwitch__c/index.tsx +103 -0
  72. package/template/neo-bi-cmps/src/components/stageSwitch__c/model.ts +37 -0
  73. package/template/neo-bi-cmps/src/components/stageSwitch__c/style.scss +89 -0
  74. package/template/neo-bi-cmps/src/components/stageTimeChart__c/README.md +37 -0
  75. package/template/neo-bi-cmps/src/components/stageTimeChart__c/index.tsx +126 -0
  76. package/template/neo-bi-cmps/src/components/stageTimeChart__c/model.ts +35 -0
  77. package/template/neo-bi-cmps/src/components/stageTimeChart__c/style.scss +140 -0
  78. package/template/neo-bi-cmps/src/components/tabSwitch__c/README.md +37 -0
  79. package/template/neo-bi-cmps/src/components/tabSwitch__c/index.tsx +80 -0
  80. package/template/neo-bi-cmps/src/components/tabSwitch__c/model.ts +45 -0
  81. package/template/neo-bi-cmps/src/components/tabSwitch__c/style.scss +37 -0
  82. package/template/neo-custom-cmp-template/package.json +1 -1
  83. package/template/neo-custom-cmp-template/src/components/entityForm__c/index.tsx +48 -54
  84. package/template/neo-custom-cmp-template/src/components/entityForm__c/model.ts +1 -1
  85. package/template/neo-custom-cmp-template/src/components/entityForm__c/style.scss +80 -77
  86. package/template/neo-h5-cmps/package.json +1 -1
  87. package/template/neo-order-cmps/package.json +1 -1
  88. package/template/neo-web-entity-grid/package.json +1 -1
  89. package/template/neo-web-entity-grid/src/components/createForm__c/index.tsx +46 -54
  90. package/template/neo-web-entity-grid/src/components/createForm__c/resetAntd.scss +74 -0
  91. package/template/neo-web-entity-grid/src/components/createForm__c/style.scss +81 -152
  92. package/template/neo-web-entity-grid/src/components/searchForm__c/index.tsx +47 -52
  93. package/template/neo-web-entity-grid/src/components/searchForm__c/style.scss +60 -74
  94. package/template/neo-web-form/package.json +1 -1
  95. package/template/neo-web-form/src/components/batchAddTable__c/index.tsx +16 -7
  96. package/template/neo-web-form/src/components/batchAddTable__c/style.scss +14 -0
  97. package/template/neo-web-form/src/components/batchAddTable__c/tableModal.scss +60 -13
  98. package/template/react-custom-cmp-template/package.json +1 -1
  99. package/template/react-ts-custom-cmp-template/package.json +1 -1
  100. package/template/vue2-custom-cmp-template/package.json +1 -1
@@ -0,0 +1,42 @@
1
+ export class PipelineFunnelModel {
2
+ label: string = 'Pipeline漏斗图';
3
+ description: string = '展示销售管道的漏斗转化情况,直观显示各阶段金额和数量';
4
+ iconUrl: string = 'https://custom-widgets.bj.bcebos.com/pipelineFunnel.svg';
5
+ targetPage: string[] = ['all'];
6
+ targetDevice: string = 'all';
7
+
8
+ defaultComProps = {
9
+ title: 'Pipeline Funnel',
10
+ totalAmount: '$11.1M',
11
+ stages: [
12
+ { name: 'Prospecting', amount: '$3.2M', count: 15, conversionRate: '—', color: '#3b82f6' },
13
+ { name: 'Needs Analysis', amount: '$1.8M', count: 7, conversionRate: '56.3%', color: '#22c55e' },
14
+ { name: 'Proposal/Price Quote', amount: '$4.5M', count: 8, conversionRate: '28.1%', color: '#f59e0b' },
15
+ { name: 'Closed Won', amount: '$1.6M', count: 3, conversionRate: '10.0%', color: '#8b5cf6' },
16
+ ],
17
+ showAiButton: true,
18
+ };
19
+
20
+ functions = [
21
+ {
22
+ apiKey: 'refreshData',
23
+ label: '刷新数据',
24
+ helpTextKey: '刷新漏斗图数据',
25
+ },
26
+ ];
27
+
28
+ propsSchema = [
29
+ {
30
+ type: 'string',
31
+ name: 'title',
32
+ label: '标题',
33
+ },
34
+ {
35
+ type: 'string',
36
+ name: 'totalAmount',
37
+ label: '总金额',
38
+ },
39
+ ];
40
+ }
41
+
42
+ export default PipelineFunnelModel;
@@ -0,0 +1,133 @@
1
+ .pipeline-funnel__c {
2
+ background: #fff;
3
+ border-radius: 8px;
4
+ padding: 20px;
5
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
6
+
7
+ .funnel-header {
8
+ display: flex;
9
+ justify-content: space-between;
10
+ align-items: center;
11
+ margin-bottom: 16px;
12
+ }
13
+
14
+ .funnel-title {
15
+ font-size: 14px;
16
+ font-weight: 600;
17
+ margin: 0;
18
+ }
19
+
20
+ .ai-btn {
21
+ cursor: pointer;
22
+ font-size: 16px;
23
+ transition: transform 0.2s;
24
+
25
+ &:hover {
26
+ transform: scale(1.1);
27
+ }
28
+ }
29
+
30
+ .funnel-total {
31
+ text-align: center;
32
+ margin-bottom: 16px;
33
+
34
+ .funnel-total-label {
35
+ font-size: 12px;
36
+ color: #888;
37
+ }
38
+
39
+ .funnel-total-value {
40
+ font-size: 22px;
41
+ font-weight: 700;
42
+ }
43
+ }
44
+
45
+ .funnel-body {
46
+ display: flex;
47
+ align-items: stretch;
48
+ gap: 0;
49
+ }
50
+
51
+ .funnel-left-rates {
52
+ width: 100px;
53
+ display: flex;
54
+ flex-direction: column;
55
+ justify-content: center;
56
+ gap: 0;
57
+ font-size: 11px;
58
+ color: #888;
59
+ }
60
+
61
+ .funnel-rate {
62
+ height: 48px;
63
+ display: flex;
64
+ align-items: center;
65
+ }
66
+
67
+ .funnel-main {
68
+ flex: 1;
69
+ display: flex;
70
+ flex-direction: column;
71
+ align-items: center;
72
+ }
73
+
74
+ .funnel-segment {
75
+ width: 100%;
76
+ height: 48px;
77
+ display: flex;
78
+ align-items: center;
79
+ justify-content: center;
80
+ color: #fff;
81
+ font-size: 12px;
82
+ font-weight: 600;
83
+ cursor: pointer;
84
+ transition: opacity 0.2s;
85
+
86
+ &:hover {
87
+ opacity: 0.85;
88
+ }
89
+ }
90
+
91
+ .funnel-right-data {
92
+ width: 110px;
93
+ display: flex;
94
+ flex-direction: column;
95
+ justify-content: center;
96
+ gap: 0;
97
+ font-size: 11px;
98
+ color: #555;
99
+ text-align: right;
100
+ }
101
+
102
+ .funnel-data {
103
+ height: 48px;
104
+ display: flex;
105
+ align-items: center;
106
+ justify-content: flex-end;
107
+ }
108
+
109
+ .funnel-legend {
110
+ display: flex;
111
+ gap: 12px;
112
+ justify-content: center;
113
+ flex-wrap: wrap;
114
+ margin-top: 16px;
115
+ font-size: 11px;
116
+ color: #666;
117
+ }
118
+
119
+ .legend-item {
120
+ display: flex;
121
+ align-items: center;
122
+ gap: 4px;
123
+ }
124
+
125
+ .legend-dot {
126
+ display: inline-block;
127
+ width: 10px;
128
+ height: 10px;
129
+ border-radius: 50%;
130
+ margin-right: 4px;
131
+ vertical-align: middle;
132
+ }
133
+ }
@@ -0,0 +1,36 @@
1
+ # StageSwitch 组件
2
+
3
+ 阶段切换卡片组件,切换显示不同销售阶段的数据。
4
+
5
+ ## 使用方式
6
+
7
+ ```tsx
8
+ import StageSwitch from './components/stageSwitch__c';
9
+
10
+ <StageSwitch
11
+ stages={[
12
+ { key: 'Prospecting', name: 'Prospecting', amount: '$3.2M', count: 15 },
13
+ { key: 'Proposal', name: 'Proposal', amount: '$4.5M', count: 8 },
14
+ ]}
15
+ activeStage="Prospecting"
16
+ onStageChange={(stage) => console.log('Changed:', stage.key)}
17
+ />
18
+ ```
19
+
20
+ ## Props
21
+
22
+ | 属性 | 说明 | 类型 | 默认值 |
23
+ |------|------|------|--------|
24
+ | stages | 阶段数据 | StageTab[] | [] |
25
+ | activeStage | 当前阶段 | string | 第一个阶段 |
26
+ | onStageChange | 阶段切换回调 | (stage: StageTab) => void | - |
27
+
28
+ ## StageTab
29
+
30
+ | 属性 | 说明 | 类型 |
31
+ |------|------|------|
32
+ | key | 唯一标识 | string |
33
+ | name | 阶段名称 | string |
34
+ | amount | 金额 | string |
35
+ | count | 数量 | number |
36
+ | changes | 变化数据 | { amount, amountDirection, count, countDirection } |
@@ -0,0 +1,103 @@
1
+ /**
2
+ * @file 阶段切换卡片组件
3
+ * @description 切换显示不同销售阶段的数据
4
+ */
5
+ import * as React from 'react';
6
+ // @ts-ignore
7
+ import { BaseCmp, StatusHoc, NeoEvent } from 'neo-ui-common';
8
+
9
+ import './style.scss';
10
+
11
+ interface StageTab {
12
+ key: string;
13
+ name: string;
14
+ amount: string;
15
+ count: number;
16
+ changes?: {
17
+ amount: string;
18
+ amountDirection: 'up' | 'down';
19
+ count: string;
20
+ countDirection: 'up' | 'down';
21
+ };
22
+ }
23
+
24
+ interface StageSwitchProps {
25
+ stages?: StageTab[];
26
+ activeStage?: string;
27
+ onStageChange?: (stage: StageTab) => void;
28
+ className?: string;
29
+ style?: React.CSSProperties;
30
+ }
31
+
32
+ interface StageSwitchState {
33
+ activeStage: string;
34
+ }
35
+
36
+ class StageSwitch extends BaseCmp<StageSwitchProps, StageSwitchState> {
37
+ constructor(props: StageSwitchProps) {
38
+ super(props);
39
+ this.state = {
40
+ activeStage: props.activeStage || (props.stages?.[0]?.key ?? ''),
41
+ };
42
+ }
43
+
44
+ componentDidMount() {
45
+ console.log('StageSwitch 组件挂载');
46
+ }
47
+
48
+ componentWillReceiveProps(nextProps: StageSwitchProps) {
49
+ if (nextProps.activeStage && nextProps.activeStage !== this.props.activeStage) {
50
+ this.setState({ activeStage: nextProps.activeStage });
51
+ }
52
+ }
53
+
54
+ handleStageClick(stage: StageTab) {
55
+ this.setState({ activeStage: stage.key });
56
+ const { onStageChange } = this.props;
57
+ if (onStageChange) {
58
+ onStageChange(stage);
59
+ }
60
+ }
61
+
62
+ render() {
63
+ const { stages = [], className, style } = this.props;
64
+ const { activeStage } = this.state;
65
+
66
+ return (
67
+ <div className={`stage-switch__c ${className || ''}`} style={style}>
68
+ <div className="stage-tabs">
69
+ {stages.map((stage) => (
70
+ <div
71
+ key={stage.key}
72
+ className={`stage-tab ${activeStage === stage.key ? 'active' : ''}`}
73
+ onClick={() => this.handleStageClick(stage)}
74
+ >
75
+ <div className="stage-name">{stage.name}</div>
76
+ <div className="stage-amount-row">
77
+ <span className="stage-amount">{stage.amount}</span>
78
+ <span className="stage-count">({stage.count})</span>
79
+ </div>
80
+ {stage.changes && (
81
+ <div className="stage-sub">
82
+ <span
83
+ className={`change-amount ${stage.changes.amountDirection === 'up' ? 'positive' : 'negative'}`}
84
+ >
85
+ {stage.changes.amountDirection === 'up' ? '↑' : '↓'} {stage.changes.amount}
86
+ </span>
87
+ <span> &nbsp; </span>
88
+ <span
89
+ className={`change-count ${stage.changes.countDirection === 'up' ? 'positive' : 'negative'}`}
90
+ >
91
+ {stage.changes.countDirection === 'up' ? '↑' : '↓'} {stage.changes.count}
92
+ </span>
93
+ </div>
94
+ )}
95
+ </div>
96
+ ))}
97
+ </div>
98
+ </div>
99
+ );
100
+ }
101
+ }
102
+
103
+ export default StatusHoc(StageSwitch);
@@ -0,0 +1,37 @@
1
+ export class StageSwitchModel {
2
+ label: string = '阶段切换卡片';
3
+ description: string = '切换显示不同销售阶段的数据,包含金额、数量和变化趋势';
4
+ iconUrl: string = 'https://custom-widgets.bj.bcebos.com/stageSwitch.svg';
5
+ targetPage: string[] = ['all'];
6
+ targetDevice: string = 'all';
7
+
8
+ defaultComProps = {
9
+ stages: [
10
+ { key: 'Prospecting', name: 'Prospecting', amount: '$3.2M', count: 15, changes: { amount: '$280K', amountDirection: 'up', count: '3', countDirection: 'up' } },
11
+ { key: 'Needs Analysis', name: 'Needs Analysis', amount: '$1.8M', count: 7, changes: { amount: '$320K', amountDirection: 'down', count: '2', countDirection: 'down' } },
12
+ { key: 'Proposal', name: 'Proposal/Price Quote', amount: '$4.5M', count: 8, changes: { amount: '$500K', amountDirection: 'up', count: '3', countDirection: 'up' } },
13
+ { key: 'Closed Won', name: 'Closed Won', amount: '$1.6M', count: 3, changes: { amount: '$400K', amountDirection: 'up', count: '1', countDirection: 'up' } },
14
+ { key: 'Closed Lost', name: 'Closed Lost', amount: '$0.9M', count: 4, changes: { amount: '$200K', amountDirection: 'down', count: '2', countDirection: 'up' } },
15
+ ],
16
+ activeStage: 'Prospecting',
17
+ };
18
+
19
+ functions = [
20
+ {
21
+ apiKey: 'setActiveStage',
22
+ label: '设置当前阶段',
23
+ helpTextKey: '设置当前激活的销售阶段',
24
+ },
25
+ ];
26
+
27
+ propsSchema = [
28
+ {
29
+ type: 'object',
30
+ name: 'stages',
31
+ label: '阶段配置',
32
+ schema: [],
33
+ },
34
+ ];
35
+ }
36
+
37
+ export default StageSwitchModel;
@@ -0,0 +1,89 @@
1
+ .stage-switch__c {
2
+ .stage-tabs {
3
+ display: flex;
4
+ gap: 0;
5
+ margin-bottom: 20px;
6
+ background: #fff;
7
+ border-radius: 8px;
8
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
9
+ overflow: hidden;
10
+ }
11
+
12
+ .stage-tab {
13
+ flex: 1;
14
+ padding: 10px 16px;
15
+ cursor: pointer;
16
+ border-right: 1px solid #f0f0f0;
17
+ transition: all 0.2s;
18
+ position: relative;
19
+
20
+ &:last-child {
21
+ border-right: none;
22
+ }
23
+
24
+ &:hover {
25
+ background: #fafafa;
26
+ }
27
+
28
+ &.active {
29
+ background: #fff;
30
+
31
+ &::before {
32
+ content: '';
33
+ position: absolute;
34
+ top: 0;
35
+ left: 0;
36
+ right: 0;
37
+ height: 3px;
38
+ background: #6366f1;
39
+ }
40
+
41
+ .stage-name {
42
+ color: #6366f1;
43
+ font-weight: 600;
44
+ }
45
+ }
46
+ }
47
+
48
+ .stage-name {
49
+ font-size: 11px;
50
+ color: #888;
51
+ margin-bottom: 2px;
52
+ }
53
+
54
+ .stage-amount-row {
55
+ display: flex;
56
+ align-items: baseline;
57
+ gap: 4px;
58
+ }
59
+
60
+ .stage-amount {
61
+ font-size: 15px;
62
+ font-weight: 700;
63
+ color: #333;
64
+ }
65
+
66
+ .stage-count {
67
+ font-size: 11px;
68
+ color: #999;
69
+ }
70
+
71
+ .stage-sub {
72
+ font-size: 10px;
73
+ color: #999;
74
+ margin-top: 2px;
75
+ }
76
+
77
+ .change-amount,
78
+ .change-count {
79
+ font-weight: 700;
80
+ }
81
+
82
+ .positive {
83
+ color: #16a34a;
84
+ }
85
+
86
+ .negative {
87
+ color: #dc2626;
88
+ }
89
+ }
@@ -0,0 +1,37 @@
1
+ # StageTimeChart 组件
2
+
3
+ 阶段停留时间组件,展示各销售阶段的平均停留时间。
4
+
5
+ ## 使用方式
6
+
7
+ ```tsx
8
+ import StageTimeChart from './components/stageTimeChart__c';
9
+
10
+ <StageTimeChart
11
+ title="Avg. Time in Stage"
12
+ items={[
13
+ { stageName: 'Prospecting', actualTime: '8天6时', actualPercent: 28, actualColor: '#22c55e', targetPercent: 33, limitPercent: 50 },
14
+ ]}
15
+ onStageClick={(name) => console.log('Clicked:', name)}
16
+ />
17
+ ```
18
+
19
+ ## Props
20
+
21
+ | 属性 | 说明 | 类型 | 默认值 |
22
+ |------|------|------|--------|
23
+ | title | 标题 | string | 'Avg. Time in Stage' |
24
+ | items | 阶段数据 | StageTimeItem[] | [] |
25
+ | showAiButton | 显示AI按钮 | boolean | true |
26
+ | onStageClick | 阶段点击回调 | (stageName: string) => void | - |
27
+
28
+ ## StageTimeItem
29
+
30
+ | 属性 | 说明 | 类型 |
31
+ |------|------|------|
32
+ | stageName | 阶段名称 | string |
33
+ | actualTime | 实际时间 | string |
34
+ | actualPercent | 实际百分比 | number |
35
+ | actualColor | 实际颜色 | string |
36
+ | targetPercent | 目标百分比 | number |
37
+ | limitPercent | 限制百分比 | number |
@@ -0,0 +1,126 @@
1
+ /**
2
+ * @file 阶段停留时间组件
3
+ * @description 展示各销售阶段的平均停留时间,包含实际值、目标值和限制值
4
+ */
5
+ import * as React from 'react';
6
+ // @ts-ignore
7
+ import { BaseCmp, StatusHoc, NeoEvent } from 'neo-ui-common';
8
+
9
+ import './style.scss';
10
+
11
+ interface StageTimeItem {
12
+ stageName: string;
13
+ actualTime: string;
14
+ actualPercent: number;
15
+ actualColor: string;
16
+ targetPercent: number;
17
+ limitPercent: number;
18
+ }
19
+
20
+ interface StageTimeChartProps {
21
+ title?: string;
22
+ items?: StageTimeItem[];
23
+ showAiButton?: boolean;
24
+ onStageClick?: (stageName: string) => void;
25
+ className?: string;
26
+ style?: React.CSSProperties;
27
+ }
28
+
29
+ interface StageTimeChartState {
30
+ loading: boolean;
31
+ }
32
+
33
+ class StageTimeChart extends BaseCmp<StageTimeChartProps, StageTimeChartState> {
34
+ constructor(props: StageTimeChartProps) {
35
+ super(props);
36
+ this.state = {
37
+ loading: false,
38
+ };
39
+ }
40
+
41
+ componentDidMount() {
42
+ console.log('StageTimeChart 组件挂载');
43
+ }
44
+
45
+ render() {
46
+ const {
47
+ title = 'Avg. Time in Stage',
48
+ items = [],
49
+ showAiButton = true,
50
+ onStageClick,
51
+ className,
52
+ style,
53
+ } = this.props;
54
+
55
+ return (
56
+ <div className={`stage-time-chart__c ${className || ''}`} style={style}>
57
+ <div className="chart-header">
58
+ <h3 className="chart-title">{title}</h3>
59
+ {showAiButton && (
60
+ <span
61
+ className="ai-btn"
62
+ onClick={() => console.log('AI Analysis clicked')}
63
+ title="AI Analysis"
64
+ >
65
+
66
+ </span>
67
+ )}
68
+ </div>
69
+
70
+ <div className="chart-legend">
71
+ <span className="legend-item">
72
+ <span className="legend-actual" />
73
+ Actual
74
+ </span>
75
+ <span className="legend-item">
76
+ <span className="legend-target" />
77
+ Target
78
+ </span>
79
+ <span className="legend-item">
80
+ <span className="legend-limit" />
81
+ Limit
82
+ </span>
83
+ </div>
84
+
85
+ <div className="chart-body">
86
+ {items.map((item, index) => (
87
+ <div
88
+ key={index}
89
+ className="stage-time-item"
90
+ onClick={() => onStageClick?.(item.stageName)}
91
+ >
92
+ <div className="stage-time-header">
93
+ <span className="stage-name">{item.stageName}</span>
94
+ <span
95
+ className="stage-time-value"
96
+ style={{ color: item.actualColor }}
97
+ >
98
+ {item.actualTime}
99
+ </span>
100
+ </div>
101
+ <div className="stage-time-bar">
102
+ <div
103
+ className="stage-time-actual"
104
+ style={{
105
+ width: `${item.actualPercent}%`,
106
+ backgroundColor: item.actualColor,
107
+ }}
108
+ />
109
+ <div
110
+ className="stage-time-target"
111
+ style={{ left: `${item.targetPercent}%` }}
112
+ />
113
+ <div
114
+ className="stage-time-limit"
115
+ style={{ left: `${item.limitPercent}%` }}
116
+ />
117
+ </div>
118
+ </div>
119
+ ))}
120
+ </div>
121
+ </div>
122
+ );
123
+ }
124
+ }
125
+
126
+ export default StatusHoc(StageTimeChart);
@@ -0,0 +1,35 @@
1
+ export class StageTimeChartModel {
2
+ label: string = '阶段停留时间';
3
+ description: string = '展示各销售阶段的平均停留时间,包含实际值、目标值和限制值';
4
+ iconUrl: string = 'https://custom-widgets.bj.bcebos.com/stageTimeChart.svg';
5
+ targetPage: string[] = ['all'];
6
+ targetDevice: string = 'all';
7
+
8
+ defaultComProps = {
9
+ title: 'Avg. Time in Stage',
10
+ items: [
11
+ { stageName: 'Prospecting', actualTime: '8天6时', actualPercent: 28, actualColor: '#22c55e', targetPercent: 33, limitPercent: 50 },
12
+ { stageName: 'Needs Analysis', actualTime: '15天12时', actualPercent: 52, actualColor: '#eab308', targetPercent: 40, limitPercent: 60 },
13
+ { stageName: 'Proposal/Price Quote', actualTime: '22天8时', actualPercent: 74, actualColor: '#ef4444', targetPercent: 50, limitPercent: 67 },
14
+ ],
15
+ showAiButton: true,
16
+ };
17
+
18
+ functions = [
19
+ {
20
+ apiKey: 'refreshData',
21
+ label: '刷新数据',
22
+ helpTextKey: '刷新停留时间数据',
23
+ },
24
+ ];
25
+
26
+ propsSchema = [
27
+ {
28
+ type: 'string',
29
+ name: 'title',
30
+ label: '标题',
31
+ },
32
+ ];
33
+ }
34
+
35
+ export default StageTimeChartModel;