neo-cmp-cli 1.13.12 → 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 (61) 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/package.json +1 -1
  10. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/README.md +52 -0
  11. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/index.tsx +176 -0
  12. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/model.ts +49 -0
  13. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/style.scss +218 -0
  14. package/template/neo-bi-cmps/src/components/filterBar__c/README.md +35 -0
  15. package/template/neo-bi-cmps/src/components/filterBar__c/index.tsx +186 -0
  16. package/template/neo-bi-cmps/src/components/filterBar__c/model.ts +72 -0
  17. package/template/neo-bi-cmps/src/components/filterBar__c/style.scss +212 -0
  18. package/template/neo-bi-cmps/src/components/forecastChart__c/README.md +31 -0
  19. package/template/neo-bi-cmps/src/components/forecastChart__c/index.tsx +161 -0
  20. package/template/neo-bi-cmps/src/components/forecastChart__c/model.ts +39 -0
  21. package/template/neo-bi-cmps/src/components/forecastChart__c/style.scss +154 -0
  22. package/template/neo-bi-cmps/src/components/forecastGrid__c/README.md +36 -0
  23. package/template/neo-bi-cmps/src/components/forecastGrid__c/index.tsx +86 -0
  24. package/template/neo-bi-cmps/src/components/forecastGrid__c/model.ts +34 -0
  25. package/template/neo-bi-cmps/src/components/forecastGrid__c/style.scss +48 -0
  26. package/template/neo-bi-cmps/src/components/gapCloser__c/README.md +24 -0
  27. package/template/neo-bi-cmps/src/components/gapCloser__c/index.tsx +95 -0
  28. package/template/neo-bi-cmps/src/components/gapCloser__c/model.ts +43 -0
  29. package/template/neo-bi-cmps/src/components/gapCloser__c/style.scss +60 -0
  30. package/template/neo-bi-cmps/src/components/kpiCards__c/README.md +35 -0
  31. package/template/neo-bi-cmps/src/components/kpiCards__c/index.tsx +70 -0
  32. package/template/neo-bi-cmps/src/components/kpiCards__c/model.ts +35 -0
  33. package/template/neo-bi-cmps/src/components/kpiCards__c/style.scss +33 -0
  34. package/template/neo-bi-cmps/src/components/oppList__c/README.md +52 -0
  35. package/template/neo-bi-cmps/src/components/oppList__c/index.tsx +228 -0
  36. package/template/neo-bi-cmps/src/components/oppList__c/model.ts +40 -0
  37. package/template/neo-bi-cmps/src/components/oppList__c/style.scss +133 -0
  38. package/template/neo-bi-cmps/src/components/pipelineFunnel__c/README.md +39 -0
  39. package/template/neo-bi-cmps/src/components/pipelineFunnel__c/index.tsx +128 -0
  40. package/template/neo-bi-cmps/src/components/pipelineFunnel__c/model.ts +42 -0
  41. package/template/neo-bi-cmps/src/components/pipelineFunnel__c/style.scss +133 -0
  42. package/template/neo-bi-cmps/src/components/stageSwitch__c/README.md +36 -0
  43. package/template/neo-bi-cmps/src/components/stageSwitch__c/index.tsx +103 -0
  44. package/template/neo-bi-cmps/src/components/stageSwitch__c/model.ts +37 -0
  45. package/template/neo-bi-cmps/src/components/stageSwitch__c/style.scss +89 -0
  46. package/template/neo-bi-cmps/src/components/stageTimeChart__c/README.md +37 -0
  47. package/template/neo-bi-cmps/src/components/stageTimeChart__c/index.tsx +126 -0
  48. package/template/neo-bi-cmps/src/components/stageTimeChart__c/model.ts +35 -0
  49. package/template/neo-bi-cmps/src/components/stageTimeChart__c/style.scss +140 -0
  50. package/template/neo-bi-cmps/src/components/tabSwitch__c/README.md +37 -0
  51. package/template/neo-bi-cmps/src/components/tabSwitch__c/index.tsx +80 -0
  52. package/template/neo-bi-cmps/src/components/tabSwitch__c/model.ts +45 -0
  53. package/template/neo-bi-cmps/src/components/tabSwitch__c/style.scss +37 -0
  54. package/template/neo-custom-cmp-template/package.json +1 -1
  55. package/template/neo-h5-cmps/package.json +1 -1
  56. package/template/neo-order-cmps/package.json +1 -1
  57. package/template/neo-web-entity-grid/package.json +1 -1
  58. package/template/neo-web-form/package.json +1 -1
  59. package/template/react-custom-cmp-template/package.json +1 -1
  60. package/template/react-ts-custom-cmp-template/package.json +1 -1
  61. package/template/vue2-custom-cmp-template/package.json +1 -1
@@ -0,0 +1,154 @@
1
+ .forecast-chart__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
+ .chart-header {
8
+ display: flex;
9
+ justify-content: space-between;
10
+ align-items: center;
11
+ margin-bottom: 16px;
12
+ }
13
+
14
+ .chart-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
+ .chart-content {
31
+ display: flex;
32
+ gap: 16px;
33
+ flex: 1;
34
+ align-items: flex-end;
35
+ height: 220px;
36
+ }
37
+
38
+ .chart-y-axis {
39
+ width: 50px;
40
+ display: flex;
41
+ flex-direction: column;
42
+ justify-content: space-between;
43
+ align-items: flex-end;
44
+ padding-right: 8px;
45
+ font-size: 11px;
46
+ color: #999;
47
+ }
48
+
49
+ .chart-main {
50
+ flex: 1;
51
+ position: relative;
52
+ padding: 16px 16px 40px 0;
53
+ }
54
+
55
+ .chart-grid {
56
+ position: absolute;
57
+ left: 0;
58
+ right: 0;
59
+ top: 20px;
60
+ bottom: 50px;
61
+
62
+ div {
63
+ position: absolute;
64
+ width: 100%;
65
+ border-top: 1px solid #eee;
66
+ }
67
+ }
68
+
69
+ .chart-quota-line {
70
+ position: absolute;
71
+ left: 0;
72
+ right: 0;
73
+ border-top: 2.5px solid #22c55e;
74
+ z-index: 5;
75
+
76
+ .quota-label {
77
+ position: absolute;
78
+ top: -18px;
79
+ left: 0;
80
+ font-size: 11px;
81
+ background: #22c55e;
82
+ color: #fff;
83
+ padding: 1px 8px;
84
+ border-radius: 3px;
85
+ }
86
+ }
87
+
88
+ .chart-forecast-line {
89
+ position: absolute;
90
+ left: 0;
91
+ right: 0;
92
+ border-top: 2px solid #8b5cf6;
93
+ z-index: 5;
94
+
95
+ .forecast-label {
96
+ position: absolute;
97
+ top: -16px;
98
+ right: 0;
99
+ font-size: 10px;
100
+ color: #8b5cf6;
101
+ }
102
+ }
103
+
104
+ .chart-ai-line {
105
+ position: absolute;
106
+ left: 0;
107
+ right: 0;
108
+ border-top: 2px dashed #a78bfa;
109
+ z-index: 5;
110
+
111
+ .ai-label {
112
+ position: absolute;
113
+ top: -16px;
114
+ right: 80px;
115
+ font-size: 10px;
116
+ color: #a78bfa;
117
+ }
118
+ }
119
+
120
+ .chart-bars {
121
+ position: absolute;
122
+ left: 0;
123
+ right: 0;
124
+ top: 20px;
125
+ bottom: 50px;
126
+ display: flex;
127
+ align-items: flex-end;
128
+ gap: 0;
129
+ }
130
+
131
+ .chart-bar {
132
+ flex: 0 0 60px;
133
+ display: flex;
134
+ flex-direction: column;
135
+ align-items: center;
136
+ }
137
+
138
+ .bar-value {
139
+ font-size: 11px;
140
+ font-weight: 600;
141
+ margin-bottom: 4px;
142
+ }
143
+
144
+ .bar-column {
145
+ width: 50px;
146
+ border-radius: 4px 4px 0 0;
147
+ }
148
+
149
+ .bar-label {
150
+ font-size: 10px;
151
+ color: #666;
152
+ margin-top: 6px;
153
+ }
154
+ }
@@ -0,0 +1,36 @@
1
+ # ForecastGrid 组件
2
+
3
+ 预测矩阵表格组件,展示预测矩阵数据。
4
+
5
+ ## 使用方式
6
+
7
+ ```tsx
8
+ import ForecastGrid from './components/forecastGrid__c';
9
+
10
+ <ForecastGrid
11
+ title="Forecast Grid"
12
+ rows={[
13
+ { name: 'Alice', quota: '$3,000,000', aiForecast: '$2,400,000', closed: '$1,200,000', commit: '$1,800,000', bestCase: '$2,500,000', pipeline: '$8,400,000', coverage: '2.8x' },
14
+ ]}
15
+ />
16
+ ```
17
+
18
+ ## Props
19
+
20
+ | 属性 | 说明 | 类型 | 默认值 |
21
+ |------|------|------|--------|
22
+ | title | 标题 | string | 'Forecast Grid' |
23
+ | rows | 表格数据 | ForecastRow[] | [] |
24
+
25
+ ## ForecastRow
26
+
27
+ | 属性 | 说明 | 类型 |
28
+ |------|------|------|
29
+ | name | 名称 | string |
30
+ | quota | Quota | string |
31
+ | aiForecast | AI预测 | string |
32
+ | closed | 已关闭 | string |
33
+ | commit | 提交 | string |
34
+ | bestCase | 最佳情况 | string |
35
+ | pipeline | 管道 | string |
36
+ | coverage | 覆盖率 | string |
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @file 预测矩阵表格组件
3
+ * @description 展示预测矩阵数据,包含Quota、AI Forecast、Closed、Commit、Best Case、Pipeline等
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 ForecastRow {
12
+ name: string;
13
+ quota: string;
14
+ aiForecast: string;
15
+ closed: string;
16
+ commit: string;
17
+ bestCase: string;
18
+ pipeline: string;
19
+ coverage: string;
20
+ }
21
+
22
+ interface ForecastGridProps {
23
+ title?: string;
24
+ rows?: ForecastRow[];
25
+ className?: string;
26
+ style?: React.CSSProperties;
27
+ }
28
+
29
+ interface ForecastGridState {
30
+ loading: boolean;
31
+ }
32
+
33
+ class ForecastGrid extends BaseCmp<ForecastGridProps, ForecastGridState> {
34
+ constructor(props: ForecastGridProps) {
35
+ super(props);
36
+ this.state = {
37
+ loading: false,
38
+ };
39
+ }
40
+
41
+ componentDidMount() {
42
+ console.log('ForecastGrid 组件挂载');
43
+ }
44
+
45
+ render() {
46
+ const { title = 'Forecast Grid', rows = [], className, style } = this.props;
47
+
48
+ return (
49
+ <div className={`forecast-grid__c ${className || ''}`} style={style}>
50
+ <h3 className="grid-title">{title}</h3>
51
+ <div className="table-wrapper">
52
+ <table className="grid-table">
53
+ <thead>
54
+ <tr>
55
+ <th>Name</th>
56
+ <th style={{ textAlign: 'right' }}>Quota</th>
57
+ <th style={{ textAlign: 'right' }}>✨ AI Forecast</th>
58
+ <th style={{ textAlign: 'right' }}>Closed</th>
59
+ <th style={{ textAlign: 'right' }}>Commit</th>
60
+ <th style={{ textAlign: 'right' }}>Best Case</th>
61
+ <th style={{ textAlign: 'right' }}>Pipeline</th>
62
+ <th style={{ textAlign: 'right' }}>Coverage</th>
63
+ </tr>
64
+ </thead>
65
+ <tbody>
66
+ {rows.map((row, index) => (
67
+ <tr key={index}>
68
+ <td style={{ textAlign: 'left' }}>{row.name}</td>
69
+ <td style={{ textAlign: 'right' }}>{row.quota}</td>
70
+ <td style={{ textAlign: 'right' }}>{row.aiForecast}</td>
71
+ <td style={{ textAlign: 'right' }}>{row.closed}</td>
72
+ <td style={{ textAlign: 'right' }}>{row.commit}</td>
73
+ <td style={{ textAlign: 'right' }}>{row.bestCase}</td>
74
+ <td style={{ textAlign: 'right' }}>{row.pipeline}</td>
75
+ <td style={{ textAlign: 'right' }}>{row.coverage}</td>
76
+ </tr>
77
+ ))}
78
+ </tbody>
79
+ </table>
80
+ </div>
81
+ </div>
82
+ );
83
+ }
84
+ }
85
+
86
+ export default StatusHoc(ForecastGrid);
@@ -0,0 +1,34 @@
1
+ export class ForecastGridModel {
2
+ label: string = '预测矩阵表格';
3
+ description: string = '展示预测矩阵数据,包含Quota、AI Forecast、Closed、Commit、Best Case、Pipeline等';
4
+ iconUrl: string = 'https://custom-widgets.bj.bcebos.com/forecastGrid.svg';
5
+ targetPage: string[] = ['all'];
6
+ targetDevice: string = 'all';
7
+
8
+ defaultComProps = {
9
+ title: 'Forecast Grid',
10
+ rows: [
11
+ { name: 'Alice', quota: '$3,000,000', aiForecast: '$2,400,000', closed: '$1,200,000', commit: '$1,800,000', bestCase: '$2,500,000', pipeline: '$8,400,000', coverage: '2.8x' },
12
+ { name: 'Steve', quota: '$3,500,000', aiForecast: '$2,800,000', closed: '$800,000', commit: '$2,200,000', bestCase: '$3,000,000', pipeline: '$10,850,000', coverage: '3.1x' },
13
+ { name: 'Chloe', quota: '$3,500,000', aiForecast: '$1,600,000', closed: '$1,200,000', commit: '$1,500,000', bestCase: '$2,300,000', pipeline: '$8,750,000', coverage: '2.5x' },
14
+ ],
15
+ };
16
+
17
+ functions = [
18
+ {
19
+ apiKey: 'refreshData',
20
+ label: '刷新数据',
21
+ helpTextKey: '刷新预测矩阵数据',
22
+ },
23
+ ];
24
+
25
+ propsSchema = [
26
+ {
27
+ type: 'string',
28
+ name: 'title',
29
+ label: '标题',
30
+ },
31
+ ];
32
+ }
33
+
34
+ export default ForecastGridModel;
@@ -0,0 +1,48 @@
1
+ .forecast-grid__c {
2
+ background: #fff;
3
+ border-radius: 8px;
4
+ padding: 20px;
5
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
6
+ overflow-x: auto;
7
+
8
+ .grid-title {
9
+ font-size: 14px;
10
+ font-weight: 600;
11
+ margin-bottom: 12px;
12
+ }
13
+
14
+ .table-wrapper {
15
+ overflow-x: auto;
16
+ }
17
+
18
+ .grid-table {
19
+ width: 100%;
20
+ border-collapse: collapse;
21
+ font-size: 13px;
22
+
23
+ th,
24
+ td {
25
+ padding: 10px 12px;
26
+ border-bottom: 1px solid #f0f0f0;
27
+ }
28
+
29
+ th {
30
+ background: #f8f9fa;
31
+ font-weight: 600;
32
+ color: #333;
33
+ border-bottom: 2px solid #e5e7eb;
34
+ }
35
+
36
+ td {
37
+ color: #333;
38
+ }
39
+
40
+ tbody tr {
41
+ transition: background 0.15s;
42
+
43
+ &:hover {
44
+ background: #fafafa;
45
+ }
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,24 @@
1
+ # GapCloser 组件
2
+
3
+ Gap Closer组件,展示Rescue Commit和Upgrade Candidates两类卡片。
4
+
5
+ ## 使用方式
6
+
7
+ ```tsx
8
+ import GapCloser from './components/gapCloser__c';
9
+
10
+ <GapCloser
11
+ cards={[
12
+ { type: 'rescue', title: 'Rescue Commit', amount: '$1,200,000', dealCount: 3, description: '...' },
13
+ { type: 'upgrade', title: 'Upgrade Candidates', amount: '$2,500,000', dealCount: 4, description: '...' },
14
+ ]}
15
+ onViewDeals={(type) => console.log('View deals:', type)}
16
+ />
17
+ ```
18
+
19
+ ## Props
20
+
21
+ | 属性 | 说明 | 类型 | 默认值 |
22
+ |------|------|------|--------|
23
+ | cards | Gap卡片数据 | GapCloserCard[] | [] |
24
+ | onViewDeals | 查看商机回调 | (type: 'rescue' \| 'upgrade') => void | - |
@@ -0,0 +1,95 @@
1
+ /**
2
+ * @file Gap Closer组件
3
+ * @description 展示Rescue Commit和Upgrade Candidates两类Gap Closer卡片
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 GapCloserCard {
12
+ type: 'rescue' | 'upgrade';
13
+ title: string;
14
+ amount: string;
15
+ dealCount: number;
16
+ description: string;
17
+ }
18
+
19
+ interface GapCloserProps {
20
+ cards?: GapCloserCard[];
21
+ onViewDeals?: (type: 'rescue' | 'upgrade') => void;
22
+ className?: string;
23
+ style?: React.CSSProperties;
24
+ }
25
+
26
+ interface GapCloserState {
27
+ loading: boolean;
28
+ }
29
+
30
+ class GapCloser extends BaseCmp<GapCloserProps, GapCloserState> {
31
+ constructor(props: GapCloserProps) {
32
+ super(props);
33
+ this.state = {
34
+ loading: false,
35
+ };
36
+ }
37
+
38
+ componentDidMount() {
39
+ console.log('GapCloser 组件挂载');
40
+ }
41
+
42
+ getCardStyle = (type: 'rescue' | 'upgrade') => {
43
+ if (type === 'rescue') {
44
+ return {
45
+ background: 'linear-gradient(135deg, #fff7ed, #ffedd5)',
46
+ borderLeftColor: '#f59e0b',
47
+ };
48
+ }
49
+ return {
50
+ background: 'linear-gradient(135deg, #f0f0ff, #e8e8ff)',
51
+ borderLeftColor: '#6366f1',
52
+ };
53
+ };
54
+
55
+ getCardTitleStyle = (type: 'rescue' | 'upgrade') => {
56
+ return type === 'rescue' ? '#92400e' : '#4338ca';
57
+ };
58
+
59
+ render() {
60
+ const { cards = [], onViewDeals, className, style } = this.props;
61
+
62
+ return (
63
+ <div className={`gap-closer__c ${className || ''}`} style={style}>
64
+ {cards.map((card, index) => (
65
+ <div
66
+ key={index}
67
+ className="gap-card"
68
+ style={this.getCardStyle(card.type)}
69
+ >
70
+ <div
71
+ className="gap-card-title"
72
+ style={{ color: this.getCardTitleStyle(card.type) }}
73
+ >
74
+ {card.type === 'rescue' ? '⚠' : '✨'} {card.title}
75
+ </div>
76
+ <div className="gap-card-amount">
77
+ <span className="amount-value">{card.amount}</span>
78
+ <span className="amount-count">· {card.dealCount} deals {card.type === 'rescue' ? 'at risk' : 'to pull in'}</span>
79
+ </div>
80
+ <div className="gap-card-desc">{card.description}</div>
81
+ <button
82
+ className="gap-card-btn"
83
+ style={{ backgroundColor: card.type === 'rescue' ? '#f59e0b' : '#6366f1' }}
84
+ onClick={() => onViewDeals?.(card.type)}
85
+ >
86
+ View Deals
87
+ </button>
88
+ </div>
89
+ ))}
90
+ </div>
91
+ );
92
+ }
93
+ }
94
+
95
+ export default StatusHoc(GapCloser);
@@ -0,0 +1,43 @@
1
+ export class GapCloserModel {
2
+ label: string = 'Gap Closer';
3
+ description: string = '展示Rescue Commit和Upgrade Candidates两类Gap Closer卡片';
4
+ iconUrl: string = 'https://custom-widgets.bj.bcebos.com/gapCloser.svg';
5
+ targetPage: string[] = ['all'];
6
+ targetDevice: string = 'all';
7
+
8
+ defaultComProps = {
9
+ cards: [
10
+ {
11
+ type: 'rescue' as const,
12
+ title: 'Rescue Commit',
13
+ amount: '$1,200,000',
14
+ dealCount: 3,
15
+ description: 'Committed deals not fully AI-backed, still worth rescuing',
16
+ },
17
+ {
18
+ type: 'upgrade' as const,
19
+ title: 'Upgrade Candidates',
20
+ amount: '$2,500,000',
21
+ dealCount: 4,
22
+ description: 'High win-rate deals from Open Pipeline worth upgrading to Commit',
23
+ },
24
+ ],
25
+ };
26
+
27
+ functions = [
28
+ {
29
+ apiKey: 'openRescueDrawer',
30
+ label: '打开Rescue抽屉',
31
+ helpTextKey: '打开Rescue Commit抽屉',
32
+ },
33
+ {
34
+ apiKey: 'openUpgradeDrawer',
35
+ label: '打开Upgrade抽屉',
36
+ helpTextKey: '打开Upgrade Candidates抽屉',
37
+ },
38
+ ];
39
+
40
+ propsSchema = [];
41
+ }
42
+
43
+ export default GapCloserModel;
@@ -0,0 +1,60 @@
1
+ .gap-closer__c {
2
+ display: flex;
3
+ flex-direction: column;
4
+ gap: 10px;
5
+
6
+ .gap-card {
7
+ background: #fff;
8
+ border-radius: 8px;
9
+ padding: 12px 14px;
10
+ box-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
11
+ border-left: 3px solid;
12
+ flex: 1;
13
+ display: flex;
14
+ flex-direction: column;
15
+ justify-content: center;
16
+ }
17
+
18
+ .gap-card-title {
19
+ font-size: 13px;
20
+ font-weight: 600;
21
+ margin-bottom: 6px;
22
+ }
23
+
24
+ .gap-card-amount {
25
+ margin-bottom: 6px;
26
+ }
27
+
28
+ .amount-value {
29
+ font-size: 20px;
30
+ font-weight: 700;
31
+ color: #333;
32
+ }
33
+
34
+ .amount-count {
35
+ font-size: 11px;
36
+ color: #888;
37
+ }
38
+
39
+ .gap-card-desc {
40
+ font-size: 11px;
41
+ color: #78716c;
42
+ margin-bottom: 8px;
43
+ }
44
+
45
+ .gap-card-btn {
46
+ padding: 7px 14px;
47
+ border: none;
48
+ border-radius: 6px;
49
+ color: #fff;
50
+ cursor: pointer;
51
+ font-size: 12px;
52
+ font-weight: 600;
53
+ width: 100%;
54
+ transition: opacity 0.2s;
55
+
56
+ &:hover {
57
+ opacity: 0.9;
58
+ }
59
+ }
60
+ }
@@ -0,0 +1,35 @@
1
+ # KpiCards 组件
2
+
3
+ KPI指标卡片组件,展示Quota、Closed、Forecast、AI Forecast等核心KPI指标。
4
+
5
+ ## 使用方式
6
+
7
+ ```tsx
8
+ import KpiCards from './components/kpiCards__c';
9
+
10
+ <KpiCards
11
+ columns={2}
12
+ items={[
13
+ { label: 'Quota', value: '$10,000,000' },
14
+ { label: 'Closed', value: '$3,200,000', subLabel: 'Gap: $6,800,000', subDirection: 'negative' },
15
+ ]}
16
+ />
17
+ ```
18
+
19
+ ## Props
20
+
21
+ | 属性 | 说明 | 类型 | 默认值 |
22
+ |------|------|------|--------|
23
+ | items | KPI数据 | KpiItem[] | [] |
24
+ | columns | 列数 | number | 2 |
25
+ | className | 自定义类名 | string | - |
26
+ | style | 自定义样式 | React.CSSProperties | - |
27
+
28
+ ## KpiItem
29
+
30
+ | 属性 | 说明 | 类型 |
31
+ |------|------|------|
32
+ | label | 指标名称 | string |
33
+ | value | 指标值 | string |
34
+ | subLabel | 副文本 | string |
35
+ | subDirection | 副文本方向 | 'negative' \| 'positive' |
@@ -0,0 +1,70 @@
1
+ /**
2
+ * @file KPI指标卡片组件
3
+ * @description 展示Quota、Closed、Forecast、AI Forecast等核心KPI指标
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 KpiItem {
12
+ label: string;
13
+ value: string;
14
+ subLabel?: string;
15
+ subDirection?: 'negative' | 'positive';
16
+ }
17
+
18
+ interface KpiCardsProps {
19
+ items?: KpiItem[];
20
+ columns?: number;
21
+ className?: string;
22
+ style?: React.CSSProperties;
23
+ }
24
+
25
+ interface KpiCardsState {
26
+ loading: boolean;
27
+ }
28
+
29
+ class KpiCards extends BaseCmp<KpiCardsProps, KpiCardsState> {
30
+ constructor(props: KpiCardsProps) {
31
+ super(props);
32
+ this.state = {
33
+ loading: false,
34
+ };
35
+ }
36
+
37
+ componentDidMount() {
38
+ console.log('KpiCards 组件挂载');
39
+ }
40
+
41
+ render() {
42
+ const { items = [], columns = 2, className, style } = this.props;
43
+
44
+ return (
45
+ <div
46
+ className={`kpi-cards__c ${className || ''}`}
47
+ style={{
48
+ ...style,
49
+ display: 'grid',
50
+ gridTemplateColumns: `repeat(${columns}, 1fr)`,
51
+ gap: '8px',
52
+ }}
53
+ >
54
+ {items.map((item, index) => (
55
+ <div key={index} className="kpi-card">
56
+ <div className="kpi-label">{item.label}</div>
57
+ <div className="kpi-value">{item.value}</div>
58
+ {item.subLabel && (
59
+ <div className={`kpi-sub ${item.subDirection || ''}`}>
60
+ {item.subLabel}
61
+ </div>
62
+ )}
63
+ </div>
64
+ ))}
65
+ </div>
66
+ );
67
+ }
68
+ }
69
+
70
+ export default StatusHoc(KpiCards);