neo-cmp-cli 1.13.16 → 1.13.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (151) hide show
  1. package/README.md +2 -1
  2. package/dist/index2.js +1 -1
  3. package/dist/main2.js +1 -1
  4. package/dist/neo/neoLogin.js +1 -1
  5. package/dist/package.json.js +1 -1
  6. package/package.json +1 -1
  7. package/template/antd-custom-cmp-template/package.json +1 -1
  8. package/template/asset-manage-template/package.json +2 -2
  9. package/template/echarts-custom-cmp-template/package.json +1 -1
  10. package/template/empty-custom-cmp-template/package.json +2 -2
  11. package/template/map-custom-cmp-template/package.json +1 -1
  12. package/template/neo-bi-cmps/neo.config.js +7 -1
  13. package/template/neo-bi-cmps/package.json +8 -7
  14. package/template/neo-bi-cmps/public/403.html +77 -0
  15. package/template/neo-bi-cmps/public/demo.html +2453 -0
  16. package/template/neo-bi-cmps/src/assets/icon/barChart.svg +1 -0
  17. package/template/neo-bi-cmps/src/assets/icon/card.svg +1 -0
  18. package/template/neo-bi-cmps/src/assets/icon/filter.svg +1 -0
  19. package/template/neo-bi-cmps/src/assets/icon/funnel.svg +1 -0
  20. package/template/neo-bi-cmps/src/assets/icon/tab.svg +1 -0
  21. package/template/neo-bi-cmps/src/components/filterBar__c/README.md +3 -14
  22. package/template/neo-bi-cmps/src/components/filterBar__c/common.scss +29 -0
  23. package/template/neo-bi-cmps/src/components/filterBar__c/index.tsx +668 -146
  24. package/template/neo-bi-cmps/src/components/filterBar__c/model.ts +26 -48
  25. package/template/neo-bi-cmps/src/components/filterBar__c/style.scss +46 -139
  26. package/template/neo-bi-cmps/src/components/targetNumber__c/customStyleConfig/index.tsx +11 -10
  27. package/template/neo-bi-cmps/src/components/targetNumber__c/index.tsx +9 -16
  28. package/template/neo-bi-cmps/src/utils/common.ts +231 -0
  29. package/template/neo-bi-cmps/src/utils/filter2chartFilter.ts +268 -0
  30. package/template/neo-bi-cmps/src/utils/filterBar.ts +140 -0
  31. package/template/neo-bi-cmps/src/utils/pipelineFunnel.ts +341 -0
  32. package/template/neo-bi-cmps/src/utils/queryByCustomSQL.ts +117 -0
  33. package/template/neo-bi-cmps/src/utils/requestDebounce.ts +22 -0
  34. package/template/neo-bi-cmps/src/utils/simpleTable.tsx +344 -0
  35. package/template/neo-bi-cmps/src/utils/stageSwitch.ts +15 -0
  36. package/template/neo-bi-cmps/src/utils/stageTimeChart.ts +90 -0
  37. package/template/neo-bi-cmps/src/utils/targetNumber.ts +12 -0
  38. package/template/neo-custom-cmp-template/package.json +2 -2
  39. package/template/neo-h5-cmps/package.json +2 -2
  40. package/template/neo-order-cmps/package.json +2 -2
  41. package/template/neo-pipeline-cmps/.prettierrc.js +12 -0
  42. package/template/neo-pipeline-cmps/@types/neo-ui-common.d.ts +36 -0
  43. package/template/neo-pipeline-cmps/README.md +99 -0
  44. package/template/neo-pipeline-cmps/commitlint.config.js +59 -0
  45. package/template/neo-pipeline-cmps/neo.config.js +124 -0
  46. package/template/neo-pipeline-cmps/package.json +66 -0
  47. package/template/neo-pipeline-cmps/public/403.html +77 -0
  48. package/template/neo-pipeline-cmps/public/css/base.css +283 -0
  49. package/template/neo-pipeline-cmps/public/demo.html +2453 -0
  50. package/template/neo-pipeline-cmps/public/scripts/app/bluebird.js +6679 -0
  51. package/template/neo-pipeline-cmps/public/template.html +13 -0
  52. package/template/neo-pipeline-cmps/src/assets/css/common.scss +127 -0
  53. package/template/neo-pipeline-cmps/src/assets/css/mixin.scss +47 -0
  54. package/template/neo-pipeline-cmps/src/assets/icon/barChart.svg +1 -0
  55. package/template/neo-pipeline-cmps/src/assets/icon/card.svg +1 -0
  56. package/template/neo-pipeline-cmps/src/assets/icon/filter.svg +1 -0
  57. package/template/neo-pipeline-cmps/src/assets/icon/funnel.svg +1 -0
  58. package/template/neo-pipeline-cmps/src/assets/icon/tab.svg +1 -0
  59. package/template/neo-pipeline-cmps/src/assets/img/AIBtn.gif +0 -0
  60. package/template/neo-pipeline-cmps/src/assets/img/NeoCRM.jpg +0 -0
  61. package/template/neo-pipeline-cmps/src/assets/img/aiLogo.png +0 -0
  62. package/template/neo-pipeline-cmps/src/assets/img/card-list.svg +1 -0
  63. package/template/neo-pipeline-cmps/src/assets/img/contact-form.svg +1 -0
  64. package/template/neo-pipeline-cmps/src/assets/img/custom-form.svg +1 -0
  65. package/template/neo-pipeline-cmps/src/assets/img/custom-widget.svg +1 -0
  66. package/template/neo-pipeline-cmps/src/assets/img/data-list.svg +1 -0
  67. package/template/neo-pipeline-cmps/src/assets/img/detail.svg +1 -0
  68. package/template/neo-pipeline-cmps/src/assets/img/favicon.png +0 -0
  69. package/template/neo-pipeline-cmps/src/assets/img/map.svg +1 -0
  70. package/template/neo-pipeline-cmps/src/assets/img/search.svg +1 -0
  71. package/template/neo-pipeline-cmps/src/assets/img/table.svg +1 -0
  72. package/template/neo-pipeline-cmps/src/components/filterBar__c/README.md +24 -0
  73. package/template/neo-pipeline-cmps/src/components/filterBar__c/common.scss +29 -0
  74. package/template/neo-pipeline-cmps/src/components/filterBar__c/index.tsx +730 -0
  75. package/template/neo-pipeline-cmps/src/components/filterBar__c/model.ts +50 -0
  76. package/template/neo-pipeline-cmps/src/components/filterBar__c/style.scss +119 -0
  77. package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/index.tsx +415 -0
  78. package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/model.ts +79 -0
  79. package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/style.scss +83 -0
  80. package/template/neo-pipeline-cmps/src/components/showHealthResult__c/index.tsx +463 -0
  81. package/template/neo-pipeline-cmps/src/components/showHealthResult__c/model.ts +45 -0
  82. package/template/neo-pipeline-cmps/src/components/showHealthResult__c/style.scss +137 -0
  83. package/template/neo-pipeline-cmps/src/components/simpleTable__c/README.md +90 -0
  84. package/template/neo-pipeline-cmps/src/components/simpleTable__c/common.scss +195 -0
  85. package/template/neo-pipeline-cmps/src/components/simpleTable__c/index.tsx +665 -0
  86. package/template/neo-pipeline-cmps/src/components/simpleTable__c/model.ts +124 -0
  87. package/template/neo-pipeline-cmps/src/components/simpleTable__c/style.scss +193 -0
  88. package/template/neo-pipeline-cmps/src/components/stageSwitch__c/index.tsx +511 -0
  89. package/template/neo-pipeline-cmps/src/components/stageSwitch__c/model.ts +70 -0
  90. package/template/{neo-bi-cmps → neo-pipeline-cmps}/src/components/stageSwitch__c/style.scss +4 -2
  91. package/template/neo-pipeline-cmps/src/components/stageTimeChart__c/index.tsx +455 -0
  92. package/template/neo-pipeline-cmps/src/components/stageTimeChart__c/model.ts +103 -0
  93. package/template/{neo-bi-cmps → neo-pipeline-cmps}/src/components/stageTimeChart__c/style.scss +3 -2
  94. package/template/neo-pipeline-cmps/src/utils/common.ts +229 -0
  95. package/template/neo-pipeline-cmps/src/utils/filter2chartFilter.ts +268 -0
  96. package/template/neo-pipeline-cmps/src/utils/filterBar.ts +140 -0
  97. package/template/neo-pipeline-cmps/src/utils/pipelineFunnel.ts +343 -0
  98. package/template/neo-pipeline-cmps/src/utils/queryByCustomSQL.ts +117 -0
  99. package/template/neo-pipeline-cmps/src/utils/requestDebounce.ts +22 -0
  100. package/template/neo-pipeline-cmps/src/utils/simpleTable.tsx +344 -0
  101. package/template/neo-pipeline-cmps/src/utils/stageSwitch.ts +15 -0
  102. package/template/neo-pipeline-cmps/src/utils/stageTimeChart.ts +90 -0
  103. package/template/neo-pipeline-cmps/src/utils/targetNumber.ts +12 -0
  104. package/template/neo-pipeline-cmps/tsconfig.json +40 -0
  105. package/template/neo-web-entity-grid/package.json +2 -2
  106. package/template/neo-web-form/package.json +2 -2
  107. package/template/react-custom-cmp-template/package.json +1 -1
  108. package/template/react-ts-custom-cmp-template/package.json +1 -1
  109. package/template/vue2-custom-cmp-template/package.json +1 -1
  110. package/template/neo-bi-cmps/.npmrc copy +0 -1
  111. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/README.md +0 -52
  112. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/index.tsx +0 -183
  113. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/model.ts +0 -90
  114. package/template/neo-bi-cmps/src/components/aiCommitDrawer__c/style.scss +0 -218
  115. package/template/neo-bi-cmps/src/components/forecastChart__c/README.md +0 -31
  116. package/template/neo-bi-cmps/src/components/forecastChart__c/index.tsx +0 -158
  117. package/template/neo-bi-cmps/src/components/forecastChart__c/model.ts +0 -40
  118. package/template/neo-bi-cmps/src/components/forecastChart__c/style.scss +0 -154
  119. package/template/neo-bi-cmps/src/components/forecastGrid__c/README.md +0 -36
  120. package/template/neo-bi-cmps/src/components/forecastGrid__c/index.tsx +0 -86
  121. package/template/neo-bi-cmps/src/components/forecastGrid__c/model.ts +0 -62
  122. package/template/neo-bi-cmps/src/components/forecastGrid__c/style.scss +0 -48
  123. package/template/neo-bi-cmps/src/components/gapCloser__c/README.md +0 -24
  124. package/template/neo-bi-cmps/src/components/gapCloser__c/index.tsx +0 -100
  125. package/template/neo-bi-cmps/src/components/gapCloser__c/model.ts +0 -46
  126. package/template/neo-bi-cmps/src/components/gapCloser__c/style.scss +0 -60
  127. package/template/neo-bi-cmps/src/components/kpiCards__c/README.md +0 -35
  128. package/template/neo-bi-cmps/src/components/kpiCards__c/index.tsx +0 -70
  129. package/template/neo-bi-cmps/src/components/kpiCards__c/model.ts +0 -50
  130. package/template/neo-bi-cmps/src/components/kpiCards__c/style.scss +0 -33
  131. package/template/neo-bi-cmps/src/components/oppList__c/README.md +0 -52
  132. package/template/neo-bi-cmps/src/components/oppList__c/index.tsx +0 -285
  133. package/template/neo-bi-cmps/src/components/oppList__c/model.ts +0 -86
  134. package/template/neo-bi-cmps/src/components/oppList__c/style.scss +0 -133
  135. package/template/neo-bi-cmps/src/components/pipelineFunnel__c/index.tsx +0 -130
  136. package/template/neo-bi-cmps/src/components/pipelineFunnel__c/model.ts +0 -66
  137. package/template/neo-bi-cmps/src/components/pipelineFunnel__c/style.scss +0 -133
  138. package/template/neo-bi-cmps/src/components/stageSwitch__c/index.tsx +0 -118
  139. package/template/neo-bi-cmps/src/components/stageSwitch__c/model.ts +0 -92
  140. package/template/neo-bi-cmps/src/components/stageTimeChart__c/index.tsx +0 -126
  141. package/template/neo-bi-cmps/src/components/stageTimeChart__c/model.ts +0 -57
  142. package/template/neo-bi-cmps/src/components/tabSwitch__c/README.md +0 -37
  143. package/template/neo-bi-cmps/src/components/tabSwitch__c/index.tsx +0 -80
  144. package/template/neo-bi-cmps/src/components/tabSwitch__c/model.ts +0 -45
  145. package/template/neo-bi-cmps/src/components/tabSwitch__c/style.scss +0 -37
  146. package/template/neo-bi-cmps/src/utils/axiosFetcher.ts +0 -37
  147. package/template/neo-bi-cmps/src/utils/queryObjectData.ts +0 -76
  148. package/template/neo-bi-cmps/src/utils/xobjects.ts +0 -162
  149. /package/template/{neo-bi-cmps → neo-pipeline-cmps}/src/components/pipelineFunnel__c/README.md +0 -0
  150. /package/template/{neo-bi-cmps → neo-pipeline-cmps}/src/components/stageSwitch__c/README.md +0 -0
  151. /package/template/{neo-bi-cmps → neo-pipeline-cmps}/src/components/stageTimeChart__c/README.md +0 -0
@@ -0,0 +1,341 @@
1
+ /**
2
+ * Pipeline 漏斗 pipelineFunnel 专用(解析表格行、ECharts 配置)
3
+ */
4
+ import * as echarts from 'echarts';
5
+
6
+ import { formatAmountDisplay } from './common';
7
+
8
+ export const FUNNEL_COLORS = [
9
+ '#3b82f6',
10
+ '#22c55e',
11
+ '#f59e0b',
12
+ '#8b5cf6',
13
+ '#ec4899',
14
+ '#06b6d4',
15
+ ];
16
+
17
+ export interface FunnelStage {
18
+ name: string;
19
+ amountNum: number;
20
+ amount: string;
21
+ count: number;
22
+ conversionRate?: string;
23
+ color: string;
24
+ }
25
+
26
+ export function parseAmountToNumber(raw: unknown): number {
27
+ if (raw === null || raw === undefined) return 0;
28
+ const s = String(raw)
29
+ .replace(/,/g, '')
30
+ .replace(/[^\d.-]/g, '');
31
+ const n = parseFloat(s);
32
+ return Number.isFinite(n) ? n : 0;
33
+ }
34
+
35
+ export function formatSharePercent(amount: number, total: number): string {
36
+ if (!total || !Number.isFinite(amount)) return '—';
37
+ return `${((amount / total) * 100).toFixed(1)}%`;
38
+ }
39
+
40
+ export function isTruthyProp(v: unknown): boolean {
41
+ return v === true || v === 'true' || v === 1 || v === '1';
42
+ }
43
+
44
+ /** 与后端阶段名比对时忽略大小写与连续空白 */
45
+ export function isClosedLostStageName(raw: unknown): boolean {
46
+ const n = String(raw ?? '')
47
+ .trim()
48
+ .toLowerCase()
49
+ .replace(/\s+/g, ' ');
50
+ return n === 'closed lost';
51
+ }
52
+
53
+ /** 去掉 Closed Lost 阶段行,保留表头;须在 parseRowsToStages 之前调用,以免计入总额与占比 */
54
+ export function filterOutClosedLostRows(table: unknown[][]): unknown[][] {
55
+ if (!Array.isArray(table) || table.length < 2) return table;
56
+ const header = table[0];
57
+ const rest = table
58
+ .slice(1)
59
+ .filter((row) => !(Array.isArray(row) && isClosedLostStageName(row[0])));
60
+ return [header, ...rest];
61
+ }
62
+
63
+ export function parseRowsToStages(rows: unknown[][]): {
64
+ stages: FunnelStage[];
65
+ totalAmountNum: number;
66
+ } {
67
+ if (!Array.isArray(rows) || rows.length < 2) {
68
+ return { stages: [], totalAmountNum: 0 };
69
+ }
70
+ const dataRows = rows.slice(1);
71
+ const stages: FunnelStage[] = [];
72
+ const amountNums: number[] = [];
73
+ let totalAmountNum = 0;
74
+
75
+ for (let i = 0; i < dataRows.length; i++) {
76
+ const row = dataRows[i];
77
+ if (!Array.isArray(row) || row.length < 4) continue;
78
+
79
+ const name = String(row[0] ?? '');
80
+ const countRaw = row[2];
81
+ const amountNum = parseAmountToNumber(row[3]);
82
+ totalAmountNum += amountNum;
83
+ amountNums.push(amountNum);
84
+
85
+ const countNum = parseInt(String(countRaw).replace(/\D/g, ''), 10);
86
+ const count = Number.isFinite(countNum) ? countNum : 0;
87
+
88
+ stages.push({
89
+ name,
90
+ amountNum,
91
+ amount: formatAmountDisplay(amountNum),
92
+ count,
93
+ color: FUNNEL_COLORS[i % FUNNEL_COLORS.length],
94
+ });
95
+ }
96
+
97
+ for (let j = 0; j < stages.length; j++) {
98
+ stages[j].conversionRate = formatSharePercent(
99
+ amountNums[j],
100
+ totalAmountNum,
101
+ );
102
+ }
103
+
104
+ return { stages, totalAmountNum };
105
+ }
106
+
107
+ export function funnelLayerValue(index: number, total: number): number {
108
+ return Math.max(total - index, 1);
109
+ }
110
+
111
+ export function funnelValueForStage(
112
+ stage: FunnelStage,
113
+ index: number,
114
+ stageCount: number,
115
+ useClassicFunnelShape: boolean,
116
+ ): number {
117
+ if (useClassicFunnelShape) {
118
+ return funnelLayerValue(index, stageCount);
119
+ }
120
+ const v = stage.amountNum;
121
+ if (Number.isFinite(v) && v > 0) return v;
122
+ return 0;
123
+ }
124
+
125
+ /** 经典漏斗:宽度仍由 value(顺序)控制;层高按金额占比分配(与 series.gap 一致,单位为 px) */
126
+ export function classicFunnelLayerHeightPercents(
127
+ amountNums: number[],
128
+ viewHeightPx: number,
129
+ gapPx: number,
130
+ ): string[] {
131
+ const n = amountNums.length;
132
+ if (n === 0) return [];
133
+ const h = Math.max(viewHeightPx, 1);
134
+ const factor = (h - gapPx * Math.max(n - 1, 0)) / h;
135
+ const positives = amountNums.map((v) => (Number.isFinite(v) && v > 0 ? v : 0));
136
+ const sum = positives.reduce((a, v) => a + v, 0);
137
+ if (sum <= 0) {
138
+ const even = (100 / n) * factor;
139
+ return Array(n).fill(`${even}%`);
140
+ }
141
+ return positives.map((v) => `${(100 * (v / sum)) * factor}%`);
142
+ }
143
+
144
+ export interface BuildFunnelChartOptionParams {
145
+ /** 容器高度(px),经典模式下用于计算各层 height 百分比;变化时应重新 setOption */
146
+ chartViewHeightPx?: number;
147
+ funnelGap?: number;
148
+ }
149
+
150
+ export function buildFunnelChartOption(
151
+ stages: FunnelStage[],
152
+ useClassicFunnelShape: boolean,
153
+ params?: BuildFunnelChartOptionParams,
154
+ ): echarts.EChartsOption {
155
+ const n = stages.length;
156
+ const values = stages.map((s, i) =>
157
+ funnelValueForStage(s, i, n, useClassicFunnelShape),
158
+ );
159
+ const funnelMax = useClassicFunnelShape
160
+ ? Math.max(n, 1)
161
+ : Math.max(...values, 1);
162
+
163
+ const gap = params?.funnelGap ?? 2;
164
+ const viewH = params?.chartViewHeightPx;
165
+ const classicHeights =
166
+ useClassicFunnelShape && viewH != null && viewH > 0
167
+ ? classicFunnelLayerHeightPercents(
168
+ stages.map((s) => s.amountNum),
169
+ viewH,
170
+ gap,
171
+ )
172
+ : null;
173
+
174
+ const coloredData = stages.map((s, i) => ({
175
+ name: s.name,
176
+ value: values[i],
177
+ itemStyle: {
178
+ color: s.color,
179
+ ...(classicHeights?.[i] ? { height: classicHeights[i] } : {}),
180
+ },
181
+ }));
182
+
183
+ const alignData = stages.map((s, i) => ({
184
+ name: s.name,
185
+ value: values[i],
186
+ ...(classicHeights?.[i]
187
+ ? { itemStyle: { height: classicHeights[i] } }
188
+ : {}),
189
+ }));
190
+
191
+ const labelLineStyle = {
192
+ length: 28,
193
+ lineStyle: {
194
+ width: 1,
195
+ color: '#d0d0d0',
196
+ type: 'solid' as const,
197
+ },
198
+ };
199
+
200
+ const labelLayoutLeft = () => ({
201
+ x: 0,
202
+ align: 'left' as const,
203
+ dx: 4,
204
+ });
205
+
206
+ const labelLayoutRight = () => ({
207
+ x: '100%',
208
+ align: 'right' as const,
209
+ dx: -6,
210
+ });
211
+
212
+ const funnelLayout = {
213
+ left: '12%',
214
+ top: 4,
215
+ bottom: 4,
216
+ width: '76%',
217
+ min: 0,
218
+ max: funnelMax,
219
+ minSize: '0%',
220
+ maxSize: '100%',
221
+ sort: 'none' as const,
222
+ gap: 1,
223
+ };
224
+
225
+ return {
226
+ backgroundColor: 'transparent',
227
+ legend: { show: false },
228
+ tooltip: {
229
+ trigger: 'item',
230
+ backgroundColor: 'rgba(0, 0, 0, 0.8)',
231
+ borderColor: '#333',
232
+ textStyle: { color: '#fff' },
233
+ formatter: (params: unknown) => {
234
+ const p = params as { dataIndex?: number; seriesName?: string };
235
+ const idx = p.dataIndex ?? 0;
236
+ const st = stages[idx];
237
+ if (!st) return '';
238
+ return [
239
+ `${st.name}`,
240
+ `Percentage: ${st.conversionRate ?? '—'}`,
241
+ `Amount: ${st.amount}`,
242
+ `Quantity: ${st.count}`,
243
+ ].join('<br/>');
244
+ },
245
+ },
246
+ series: [
247
+ {
248
+ name: 'Pipeline',
249
+ type: 'funnel',
250
+ z: 1,
251
+ ...funnelLayout,
252
+ itemStyle: {
253
+ borderColor: '#fff',
254
+ borderWidth: 1,
255
+ },
256
+ emphasis: {
257
+ itemStyle: {
258
+ shadowBlur: 10,
259
+ shadowColor: 'rgba(0, 0, 0, 0.15)',
260
+ },
261
+ },
262
+ label: {
263
+ show: true,
264
+ position: 'left',
265
+ color: '#888',
266
+ fontSize: 11,
267
+ formatter: (p: { dataIndex?: number }) => {
268
+ const idx = typeof p.dataIndex === 'number' ? p.dataIndex : 0;
269
+ return stages[idx]?.conversionRate ?? '—';
270
+ },
271
+ },
272
+ labelLine: {
273
+ show: true,
274
+ ...labelLineStyle,
275
+ },
276
+ labelLayout: labelLayoutLeft,
277
+ data: coloredData,
278
+ },
279
+ {
280
+ name: 'PipelineLabels',
281
+ type: 'funnel',
282
+ z: 2,
283
+ animation: false,
284
+ animationDurationUpdate: 0,
285
+ ...funnelLayout,
286
+ itemStyle: {
287
+ color: 'rgba(0,0,0,0)',
288
+ borderWidth: 0,
289
+ },
290
+ emphasis: { disabled: true },
291
+ label: {
292
+ show: true,
293
+ position: 'right',
294
+ color: '#555',
295
+ fontSize: 11,
296
+ formatter: (p: { dataIndex?: number }) => {
297
+ const idx = typeof p.dataIndex === 'number' ? p.dataIndex : 0;
298
+ const st = stages[idx];
299
+ return st ? `${st.amount} / ${st.count}` : '';
300
+ },
301
+ },
302
+ labelLine: {
303
+ show: true,
304
+ ...labelLineStyle,
305
+ },
306
+ labelLayout: labelLayoutRight,
307
+ data: alignData,
308
+ },
309
+ {
310
+ name: 'PipelineName',
311
+ type: 'funnel',
312
+ z: 3,
313
+ silent: true,
314
+ animation: false,
315
+ animationDurationUpdate: 0,
316
+ tooltip: { show: false },
317
+ ...funnelLayout,
318
+ itemStyle: {
319
+ color: 'rgba(0,0,0,0)',
320
+ borderWidth: 0,
321
+ },
322
+ emphasis: { disabled: true },
323
+ label: {
324
+ show: true,
325
+ position: 'inside',
326
+ color: '#fff',
327
+ fontSize: 12,
328
+ fontWeight: 600,
329
+ textBorderColor: 'rgba(0,0,0,0.4)',
330
+ textBorderWidth: 1,
331
+ formatter: (p: { name?: string; dataIndex?: number }) => {
332
+ const idx = typeof p.dataIndex === 'number' ? p.dataIndex : 0;
333
+ return stages[idx]?.name ?? p.name ?? '';
334
+ },
335
+ },
336
+ labelLine: { show: false },
337
+ data: alignData,
338
+ },
339
+ ],
340
+ };
341
+ }
@@ -0,0 +1,117 @@
1
+ // @ts-nocheck
2
+ import { request as axiosFetcher } from 'neo-open-api';
3
+
4
+ /**
5
+ * 这里存放通用查询类 Open API
6
+ */
7
+
8
+ /** 将 where 规范为 SQL 片段:字符串直接使用;数组用 and 拼接各条件 */
9
+ function normalizeWhere(where: unknown): string {
10
+ if (where == null || where === '') {
11
+ return '';
12
+ }
13
+ if (typeof where === 'string') {
14
+ return where.trim();
15
+ }
16
+ if (Array.isArray(where)) {
17
+ return where
18
+ .map((part) => (part == null ? '' : String(part).trim()))
19
+ .filter(Boolean)
20
+ .join(' and ');
21
+ }
22
+ return '';
23
+ }
24
+
25
+ // 根据 sql 查询 BI 数据
26
+ export const queryByCustomSQL = async (options?: any) => {
27
+ const apiUrl = '/rest/neobi/v2.0/query/queryByCustomSQL';
28
+ const curOptions = options || {};
29
+ const xObjectApiKey = curOptions.xObjectApiKey || '';
30
+ const fields = Object.assign([], curOptions.fields || []);
31
+ const page = curOptions.page || 1;
32
+ const pageSize = curOptions.pageSize || 10;
33
+
34
+ // 自动添加 objectId 字段
35
+ if (!fields.includes('id')) {
36
+ fields.push('id');
37
+ }
38
+
39
+ // 计算分页偏移量
40
+ const offset = (page - 1) * pageSize;
41
+
42
+ // 构建 SQL 查询
43
+ let querySql = `select ${fields.join(',')} from ${xObjectApiKey}`;
44
+
45
+ // 添加排序条件(如果有的话)
46
+ if (curOptions.orderBy) {
47
+ querySql += ` order by ${curOptions.orderBy}`;
48
+ }
49
+
50
+ /**
51
+ * 添加过滤条件(如果有的话)
52
+ * 支持的操作符包括:=、!=、like、not like、not in、is not null、is null、>、<、<>、>=、<=、in、between ... and ...。
53
+ * 对于 =、like 和 in 有以下说明:
54
+ * “=” 作为字符串的条件时,表示精确匹配。例如,查询条件 city = '北京',将返回 city 字段值严格等于 "北京" 的所有记录。
55
+ * "like" 作为字符串的条件时,需要使用"%" 通配符进行模糊匹配。例如,city like‘北京%',将返回 city 字段值以 "北京" 开头的所有记录。
56
+ * 目前仅支持将通配符“%” 放到已知内容之后的查询方式,例如,不支持 city like ‘% 北京'的查询方式。
57
+ * 当 SQL 查询中包含“%”等特殊字符时,需要对 SQL 进行 URL 编码处理。
58
+ * 支持"in",但不包括子查询。
59
+ * 支持的逻辑运算符包括:and、or。
60
+ *
61
+ * `where` 可为字符串,或字符串数组(多项默认以 and 连接,等价于手写 `a and b`)。
62
+ */
63
+ const whereClause = normalizeWhere(curOptions.where);
64
+
65
+ if (whereClause) {
66
+ querySql += ` where ${whereClause}`;
67
+ }
68
+
69
+ if (curOptions.page || curOptions.pageSize) {
70
+ // 添加分页限制
71
+ querySql += ` limit ${offset},${pageSize}`;
72
+ }
73
+
74
+ const querySqlForm = new URLSearchParams();
75
+ querySqlForm.set('sqlObject', querySql);
76
+
77
+ try {
78
+ const config = {
79
+ url: apiUrl,
80
+ method: 'POST',
81
+ data: querySqlForm.toString(),
82
+ headers: {
83
+ 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
84
+ },
85
+ };
86
+
87
+ const resultData = await axiosFetcher(config);
88
+
89
+ if (resultData.code === 200) {
90
+ const records = resultData.data || [];
91
+ return {
92
+ status: true,
93
+ code: resultData.code,
94
+ msg: resultData.msg || '获取业务对象数据列表成功',
95
+ totalSize: records.length,
96
+ data: records || [],
97
+ };
98
+ }
99
+
100
+ return {
101
+ status: false,
102
+ code: resultData.code,
103
+ msg: resultData.msg || '获取业务对象数据列表失败',
104
+ data: [],
105
+ };
106
+ } catch (error) {
107
+ console.error('获取业务对象数据列表失败:', error);
108
+
109
+ return {
110
+ status: false,
111
+ msg: error.msg || error.message || '获取业务对象数据列表失败',
112
+ data: [],
113
+ };
114
+ }
115
+ };
116
+
117
+ export default queryByCustomSQL;
@@ -0,0 +1,22 @@
1
+ // @ts-nocheck
2
+ import debounce from 'lodash/debounce';
3
+
4
+ /** 组件内数据请求防抖间隔(毫秒),用于合并短时间内的重复触发 */
5
+ export const REQUEST_DEBOUNCE_MS = 280;
6
+
7
+ /** lodash debounce 实例(避免依赖 @types/lodash) */
8
+ export type DebouncedRequestFn = {
9
+ (): void;
10
+ cancel(): void;
11
+ flush(): void;
12
+ };
13
+
14
+ /**
15
+ * 尾部防抖:连续触发时仅在停顿后执行一次,适合 filter / props 连更新场景。
16
+ */
17
+ export function createRequestDebounce(
18
+ fn: () => void,
19
+ wait: number = REQUEST_DEBOUNCE_MS,
20
+ ): DebouncedRequestFn {
21
+ return debounce(fn, wait) as DebouncedRequestFn;
22
+ }