neo-cmp-cli 1.13.18 → 1.13.19
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 +23 -3
- package/dist/package.json.js +1 -1
- package/package.json +1 -1
- package/template/neo-bi-cmps/src/components/filterBar__c/common.scss +1 -1
- package/template/neo-bi-cmps/src/components/filterBar__c/index.tsx +18 -10
- package/template/neo-bi-cmps/src/components/filterBar__c/model.ts +8 -2
- package/template/neo-bi-cmps/src/utils/common.ts +18 -20
- package/template/neo-bi-cmps/src/utils/filter2chartFilter.ts +4 -6
- package/template/neo-bi-cmps/src/utils/pipelineFunnel.ts +4 -2
- package/template/neo-bi-cmps/src/utils/simpleTable.tsx +21 -16
- package/template/neo-pipeline-cmps/src/components/filterBar__c/model.ts +10 -2
- package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/index.tsx +1 -0
- package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/model.ts +14 -2
- package/template/neo-pipeline-cmps/src/components/pipelineFunnel__c/reset.scss +4 -0
- package/template/neo-pipeline-cmps/src/components/stageSwitch__c/model.ts +14 -2
- package/template/neo-pipeline-cmps/src/components/stageTimeChart__c/model.ts +14 -2
- package/template/neo-web-entity-grid/src/components/createForm__c/index.tsx +271 -259
- package/template/neo-web-entity-grid/src/components/createForm__c/model.ts +17 -3
- package/template/neo-web-entity-grid/src/components/createForm__c/resetAntd.scss +0 -1
- package/template/neo-web-entity-grid/src/components/createForm__c/style.scss +1 -1
- package/template/neo-web-entity-grid/src/components/entityGrid2__c/index.tsx +5 -1
- package/template/neo-web-entity-grid/src/components/entityGrid2__c/model.ts +4 -3
- package/template/neo-web-entity-grid/src/components/entityGrid3__c/index.tsx +1 -1
- package/template/neo-web-entity-grid/src/components/searchForm__c/index.tsx +4 -3
- package/template/neo-web-entity-grid/src/components/searchForm__c/model.ts +9 -4
- package/template/neo-web-entity-grid/src/components/searchForm__c/style.scss +2 -1
- package/template/neo-web-form/src/components/batchAddTable__c/index.tsx +19 -19
- package/template/neo-web-form/src/components/batchAddTable__c/model.ts +11 -15
- package/template/neo-web-form/src/components/listSummary__c/index.tsx +6 -5
package/README.md
CHANGED
|
@@ -59,10 +59,11 @@ neo init -t vue2 -n myVue2Cmp
|
|
|
59
59
|
### 1. 安装工具
|
|
60
60
|
|
|
61
61
|
```bash
|
|
62
|
-
yarn global add neo-cmp-cli
|
|
63
|
-
#
|
|
64
|
-
npm i -g neo-cmp-cli
|
|
62
|
+
yarn global add neo-cmp-cli --registry https://registry.npmmirror.com
|
|
63
|
+
# 或(备注:使用国内淘宝的NPM源安装)
|
|
64
|
+
npm i -g neo-cmp-cli --registry=https://registry.npmmirror.com
|
|
65
65
|
```
|
|
66
|
+
说明: 默认使用 国内淘宝的NPM源 安装 neo-cmp-cli,提高安装速度。
|
|
66
67
|
|
|
67
68
|
### 2. 创建项目
|
|
68
69
|
|
|
@@ -145,6 +146,25 @@ A: 如果提示“在此系统上禁止运行脚本”,这个可能是 Windows
|
|
|
145
146
|
|
|
146
147
|
说明:以上命令用于设置 允许当前用户在此 Windows 客户端执行所有脚本。[关于 PowerShell 执行策略](https://learn.microsoft.com/zh-cn/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-7.5)
|
|
147
148
|
|
|
149
|
+
**Q2: 使用 neo-cmp-cli 时,提示 “无法将 xxx 项识别为 cmdlet、函数、脚本文件或可运行程序的名称**
|
|
150
|
+
A: 这个报错是 Windows 最典型的环境变量 PATH 问题,PowerShell 找不到你安装的 CLI 命令所在的文件夹。可按以下 三个步骤把 npm 全局路径加到 PATH:
|
|
151
|
+
|
|
152
|
+
步骤1: 查看 npm 全局安装路径(自动获取)
|
|
153
|
+
```bash
|
|
154
|
+
$npmPath = npm config get prefix
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
步骤2: 把路径加到当前终端 PATH(立刻生效)
|
|
158
|
+
```bash
|
|
159
|
+
$env:PATH += ";$npmPath"
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
步骤3: 永久写入系统环境变量(以后重启也能用)
|
|
163
|
+
```bash
|
|
164
|
+
[Environment]::SetEnvironmentVariable("PATH", $env:PATH + ";$npmPath", "User")
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
说明: 出现以上问题,通常是因为安装 Node 时没有勾选「Automatically install the necessary tools. Note that this will also install Chocolatey. The script will pop-up in a new window after the installation completes.」。
|
|
148
168
|
|
|
149
169
|
---
|
|
150
170
|
|
package/dist/package.json.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});var e="1.13.
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});var e="1.13.19";const o={version:e};exports.default=o,exports.version=e;
|
package/package.json
CHANGED
|
@@ -156,8 +156,7 @@ class FilterBar extends BaseCmp<FilterBarProps, FilterBarState> {
|
|
|
156
156
|
this.handleCloseDateRangeChange.bind(this);
|
|
157
157
|
this.handleChangesSinceTimeChange =
|
|
158
158
|
this.handleChangesSinceTimeChange.bind(this);
|
|
159
|
-
this.closeDateRangePickerValue =
|
|
160
|
-
this.closeDateRangePickerValue.bind(this);
|
|
159
|
+
this.closeDateRangePickerValue = this.closeDateRangePickerValue.bind(this);
|
|
161
160
|
this.changesSinceDatePickerValue =
|
|
162
161
|
this.changesSinceDatePickerValue.bind(this);
|
|
163
162
|
this.getFilters = this.getFilters.bind(this);
|
|
@@ -245,9 +244,10 @@ class FilterBar extends BaseCmp<FilterBarProps, FilterBarState> {
|
|
|
245
244
|
closeDateCustomRange: isCustom
|
|
246
245
|
? prev.closeDateCustomRange
|
|
247
246
|
: relativeRange,
|
|
248
|
-
changesSinceCustomTime:
|
|
249
|
-
|
|
250
|
-
|
|
247
|
+
changesSinceCustomTime:
|
|
248
|
+
prev.values.changesSince === 'Custom'
|
|
249
|
+
? prev.changesSinceCustomTime
|
|
250
|
+
: relativeRange?.start ?? null,
|
|
251
251
|
};
|
|
252
252
|
});
|
|
253
253
|
}
|
|
@@ -285,8 +285,8 @@ class FilterBar extends BaseCmp<FilterBarProps, FilterBarState> {
|
|
|
285
285
|
changesSinceCustomTime: changesCustom
|
|
286
286
|
? changesSinceCustomTime ?? undefined
|
|
287
287
|
: rangeResolved?.start != null
|
|
288
|
-
|
|
289
|
-
|
|
288
|
+
? rangeResolved.start
|
|
289
|
+
: undefined,
|
|
290
290
|
};
|
|
291
291
|
}
|
|
292
292
|
|
|
@@ -299,7 +299,7 @@ class FilterBar extends BaseCmp<FilterBarProps, FilterBarState> {
|
|
|
299
299
|
onValuesChange(payload);
|
|
300
300
|
}
|
|
301
301
|
this.onFiltersChange({
|
|
302
|
-
data: payload
|
|
302
|
+
data: payload,
|
|
303
303
|
});
|
|
304
304
|
|
|
305
305
|
/*
|
|
@@ -317,7 +317,11 @@ class FilterBar extends BaseCmp<FilterBarProps, FilterBarState> {
|
|
|
317
317
|
this.setState({ ownerLoading: true });
|
|
318
318
|
const currentUser = Object.assign({}, this.props.data?.__NeoCurrentUser);
|
|
319
319
|
// 给当前用户增加标记
|
|
320
|
-
if (
|
|
320
|
+
if (
|
|
321
|
+
currentUser &&
|
|
322
|
+
currentUser.name &&
|
|
323
|
+
currentUser.name.indexOf('(CurrentUser)') === -1
|
|
324
|
+
) {
|
|
321
325
|
currentUser.name = currentUser.name + '(CurrentUser)';
|
|
322
326
|
}
|
|
323
327
|
const currentUserRecords =
|
|
@@ -709,7 +713,11 @@ class FilterBar extends BaseCmp<FilterBarProps, FilterBarState> {
|
|
|
709
713
|
console.log('[FilterBar__c] render', this.props);
|
|
710
714
|
|
|
711
715
|
return (
|
|
712
|
-
<div
|
|
716
|
+
<div
|
|
717
|
+
className={`filterBar__c ${className || ''}`}
|
|
718
|
+
style={style}
|
|
719
|
+
data-time="2026.4.15 01"
|
|
720
|
+
>
|
|
713
721
|
{this.renderCloseDateBlock()}
|
|
714
722
|
{this.renderOwnerBlock()}
|
|
715
723
|
{this.renderBusinessTypeBlock()}
|
|
@@ -25,8 +25,14 @@ export class FilterBarModel {
|
|
|
25
25
|
label: '筛选条件变化后',
|
|
26
26
|
helpText:
|
|
27
27
|
'任一筛选项或自定义时间区间变更时触发;事件参数含 closeDate、closeDateCustomRange(非 custom 时为当前相对周期起止 Unix 毫秒时间戳;custom 时为 RangePicker 起止)、opportunityOwner(负责人多选 id 数组)、businessType、businessTypeLabel(业务类型展示名)、changesSince、changesSinceCustomTime(Changes Since 为 Custom 时为所选日期当日 0 点;否则在 Close Date 非 custom 时为周期起点当日 0 点)',
|
|
28
|
-
eventParams:
|
|
29
|
-
|
|
28
|
+
eventParams: [
|
|
29
|
+
{
|
|
30
|
+
apiKey: 'eventParam',
|
|
31
|
+
children: [{ apiKey: 'data', label: '当前筛选数据', type: 'Object' }],
|
|
32
|
+
label: '事件入参',
|
|
33
|
+
type: 'Object',
|
|
34
|
+
},
|
|
35
|
+
],
|
|
30
36
|
},
|
|
31
37
|
];
|
|
32
38
|
|
|
@@ -131,16 +131,18 @@ export function getDefaultOpportunityOwnerIds(
|
|
|
131
131
|
): (number | string)[] {
|
|
132
132
|
// return [1246045]; // 默认用户改成 (Alice)
|
|
133
133
|
const curUser = props.data?.__NeoCurrentUser;
|
|
134
|
-
if (
|
|
134
|
+
if (
|
|
135
|
+
curUser?.id == null ||
|
|
136
|
+
curUser.name == null ||
|
|
137
|
+
String(curUser.name).trim() === ''
|
|
138
|
+
) {
|
|
135
139
|
return [];
|
|
136
140
|
}
|
|
137
141
|
return [curUser.id];
|
|
138
142
|
}
|
|
139
143
|
|
|
140
144
|
/** 负责人多选默认值:当前登录用户 id(与 __NeoCurrentUser 一致) */
|
|
141
|
-
export function getDefaultFilterWhereByProps(
|
|
142
|
-
props: any = {},
|
|
143
|
-
): any {
|
|
145
|
+
export function getDefaultFilterWhereByProps(props: any = {}): any {
|
|
144
146
|
let userId = 1246045; // 默认用户(Alice)
|
|
145
147
|
const curUser = props.data?.__NeoCurrentUser;
|
|
146
148
|
if (curUser?.id) {
|
|
@@ -204,28 +206,24 @@ export function getDefaultFilterWhereByProps(
|
|
|
204
206
|
return defaultFilter;
|
|
205
207
|
}
|
|
206
208
|
|
|
207
|
-
export function getDefaultFilterByProps(
|
|
208
|
-
props: any = {},
|
|
209
|
-
): any {
|
|
209
|
+
export function getDefaultFilterByProps(props: any = {}): any {
|
|
210
210
|
let userId = 1246045; // 默认用户(Alice)
|
|
211
211
|
const curUser = props.data?.__NeoCurrentUser;
|
|
212
212
|
if (curUser?.id) {
|
|
213
213
|
userId = curUser.id;
|
|
214
214
|
}
|
|
215
215
|
const defaultFilter = {
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
216
|
+
closeDate: 401,
|
|
217
|
+
closeDateCustomRange: {
|
|
218
|
+
start: 1775059200000,
|
|
219
|
+
end: 1782835199999,
|
|
220
220
|
},
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
"changesSince": "Start of the Period",
|
|
228
|
-
"changesSinceCustomTime": 1775059200000
|
|
221
|
+
opportunityOwner: [userId],
|
|
222
|
+
businessType: 8150459,
|
|
223
|
+
businessTypeLabel: 'New Business',
|
|
224
|
+
businessTypeApiKey: 'defaultBusiType_1',
|
|
225
|
+
changesSince: 'Start of the Period',
|
|
226
|
+
changesSinceCustomTime: 1775059200000,
|
|
229
227
|
};
|
|
230
228
|
return defaultFilter;
|
|
231
|
-
}
|
|
229
|
+
}
|
|
@@ -248,11 +248,9 @@ function entityTypeChunk(
|
|
|
248
248
|
*/
|
|
249
249
|
export const filter2chartFilter = (filter: any): ChartFilterPayload => {
|
|
250
250
|
const f = filter && typeof filter === 'object' ? filter : {};
|
|
251
|
-
const parts = [
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
entityTypeChunk(f),
|
|
255
|
-
].filter(Boolean) as Omit<ChartFilterItem, 'seq'>[];
|
|
251
|
+
const parts = [closeDateChunk(f), ownerChunk(f), entityTypeChunk(f)].filter(
|
|
252
|
+
Boolean,
|
|
253
|
+
) as Omit<ChartFilterItem, 'seq'>[];
|
|
256
254
|
|
|
257
255
|
const filterOut: ChartFilterItem[] = parts.map((p, i) => ({
|
|
258
256
|
...p,
|
|
@@ -265,4 +263,4 @@ export const filter2chartFilter = (filter: any): ChartFilterPayload => {
|
|
|
265
263
|
: filterOut.map((x) => String(x.seq)).join(' and ');
|
|
266
264
|
|
|
267
265
|
return { relation, filter: filterOut };
|
|
268
|
-
};
|
|
266
|
+
};
|
|
@@ -132,13 +132,15 @@ export function classicFunnelLayerHeightPercents(
|
|
|
132
132
|
if (n === 0) return [];
|
|
133
133
|
const h = Math.max(viewHeightPx, 1);
|
|
134
134
|
const factor = (h - gapPx * Math.max(n - 1, 0)) / h;
|
|
135
|
-
const positives = amountNums.map((v) =>
|
|
135
|
+
const positives = amountNums.map((v) =>
|
|
136
|
+
Number.isFinite(v) && v > 0 ? v : 0,
|
|
137
|
+
);
|
|
136
138
|
const sum = positives.reduce((a, v) => a + v, 0);
|
|
137
139
|
if (sum <= 0) {
|
|
138
140
|
const even = (100 / n) * factor;
|
|
139
141
|
return Array(n).fill(`${even}%`);
|
|
140
142
|
}
|
|
141
|
-
return positives.map((v) => `${
|
|
143
|
+
return positives.map((v) => `${100 * (v / sum) * factor}%`);
|
|
142
144
|
}
|
|
143
145
|
|
|
144
146
|
export interface BuildFunnelChartOptionParams {
|
|
@@ -91,9 +91,7 @@ export function historyRowToSnap(row: unknown): HistoryOppSnap | null {
|
|
|
91
91
|
opportunityName: String(
|
|
92
92
|
o.opportunity_1_opportunityName ?? o.opportunityName ?? '',
|
|
93
93
|
),
|
|
94
|
-
saleStageId: String(
|
|
95
|
-
o.opportunity_1_saleStageId ?? o.saleStageId ?? '',
|
|
96
|
-
),
|
|
94
|
+
saleStageId: String(o.opportunity_1_saleStageId ?? o.saleStageId ?? ''),
|
|
97
95
|
money: o.opportunity_1_money ?? o.money,
|
|
98
96
|
};
|
|
99
97
|
}
|
|
@@ -151,7 +149,9 @@ export function formatMoneyCell(value: unknown): string {
|
|
|
151
149
|
}
|
|
152
150
|
|
|
153
151
|
/** oppHealthAssessmentLevel:数值 → 健康度标签(带颜色背景) */
|
|
154
|
-
export function renderOppHealthAssessmentLevel(
|
|
152
|
+
export function renderOppHealthAssessmentLevel(
|
|
153
|
+
value: unknown,
|
|
154
|
+
): React.ReactNode {
|
|
155
155
|
if (value == null || value === '') return '—';
|
|
156
156
|
const n = toFiniteNumber(value);
|
|
157
157
|
if (n === 5) {
|
|
@@ -160,7 +160,9 @@ export function renderOppHealthAssessmentLevel(value: unknown): React.ReactNode
|
|
|
160
160
|
);
|
|
161
161
|
}
|
|
162
162
|
if (n === 6) {
|
|
163
|
-
return
|
|
163
|
+
return (
|
|
164
|
+
<span className="opp-health-tag opp-health-tag--yellow">Health</span>
|
|
165
|
+
);
|
|
164
166
|
}
|
|
165
167
|
if (n === 7) {
|
|
166
168
|
return <span className="opp-health-tag opp-health-tag--red">Risk</span>;
|
|
@@ -205,7 +207,9 @@ export function moneyChangeTooltipTitle(
|
|
|
205
207
|
<div className="simpleTable-change-tip__detail">
|
|
206
208
|
{formatMoneyCell(h.money)}
|
|
207
209
|
{' → '}
|
|
208
|
-
<span className="simpleTable-change-tip__to">
|
|
210
|
+
<span className="simpleTable-change-tip__to">
|
|
211
|
+
{formatMoneyCell(current)}
|
|
212
|
+
</span>
|
|
209
213
|
</div>
|
|
210
214
|
<div className="simpleTable-change-tip__meta">
|
|
211
215
|
Changed on {formatChangeRecordedAt(preset)}
|
|
@@ -227,7 +231,9 @@ export function closeDateChangeTooltipTitle(
|
|
|
227
231
|
<div className="simpleTable-change-tip__detail">
|
|
228
232
|
{formatCloseDate(h.closeDate)}
|
|
229
233
|
{' → '}
|
|
230
|
-
<span className="simpleTable-change-tip__to">
|
|
234
|
+
<span className="simpleTable-change-tip__to">
|
|
235
|
+
{formatCloseDate(current)}
|
|
236
|
+
</span>
|
|
231
237
|
</div>
|
|
232
238
|
<div className="simpleTable-change-tip__meta">
|
|
233
239
|
Changed on {formatChangeRecordedAt(preset)}
|
|
@@ -275,15 +281,10 @@ export function renderWinRateHoverCard(record: any): React.ReactNode {
|
|
|
275
281
|
const negatives = record?.customItem242__c;
|
|
276
282
|
const winRate = record?.customItem239__c;
|
|
277
283
|
|
|
278
|
-
const fmtLine = (v: unknown) =>
|
|
279
|
-
v == null || v === '' ? '—' : String(v);
|
|
284
|
+
const fmtLine = (v: unknown) => (v == null || v === '' ? '—' : String(v));
|
|
280
285
|
|
|
281
286
|
return (
|
|
282
|
-
<Card
|
|
283
|
-
size="small"
|
|
284
|
-
bordered={false}
|
|
285
|
-
className="simpleTable-winrate-card"
|
|
286
|
-
>
|
|
287
|
+
<Card size="small" bordered={false} className="simpleTable-winrate-card">
|
|
287
288
|
<div className="simpleTable-winrate-card__baseline">
|
|
288
289
|
Baseline Probability{' '}
|
|
289
290
|
<span className="simpleTable-winrate-card__baseline-val">
|
|
@@ -291,12 +292,16 @@ export function renderWinRateHoverCard(record: any): React.ReactNode {
|
|
|
291
292
|
</span>
|
|
292
293
|
</div>
|
|
293
294
|
<hr className="simpleTable-winrate-card__hr" />
|
|
294
|
-
<div className="simpleTable-winrate-card__section-title">
|
|
295
|
+
<div className="simpleTable-winrate-card__section-title">
|
|
296
|
+
Positive Factors
|
|
297
|
+
</div>
|
|
295
298
|
<div className="simpleTable-winrate-card__positives">
|
|
296
299
|
{fmtLine(positives)}
|
|
297
300
|
</div>
|
|
298
301
|
<hr className="simpleTable-winrate-card__hr" />
|
|
299
|
-
<div className="simpleTable-winrate-card__section-title">
|
|
302
|
+
<div className="simpleTable-winrate-card__section-title">
|
|
303
|
+
Negative Factors
|
|
304
|
+
</div>
|
|
300
305
|
<div className="simpleTable-winrate-card__negatives">
|
|
301
306
|
{fmtLine(negatives)}
|
|
302
307
|
</div>
|
|
@@ -26,8 +26,16 @@ export class FilterBarModel {
|
|
|
26
26
|
label: 'After filter conditions change',
|
|
27
27
|
helpText:
|
|
28
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
|
-
|
|
29
|
+
eventParams: [
|
|
30
|
+
{
|
|
31
|
+
apiKey: 'eventParam',
|
|
32
|
+
children: [
|
|
33
|
+
{ apiKey: 'data', label: 'Current filter data', type: 'Object' },
|
|
34
|
+
],
|
|
35
|
+
label: 'Event parameters',
|
|
36
|
+
type: 'Object',
|
|
37
|
+
},
|
|
38
|
+
],
|
|
31
39
|
},
|
|
32
40
|
];
|
|
33
41
|
|
|
@@ -21,8 +21,20 @@ export class PipelineFunnelModel {
|
|
|
21
21
|
label: 'Triggered on stage click',
|
|
22
22
|
helpText:
|
|
23
23
|
'Triggered when clicking a funnel stage; event params include activeStage (current active stage)',
|
|
24
|
-
eventParams:
|
|
25
|
-
|
|
24
|
+
eventParams: [
|
|
25
|
+
{
|
|
26
|
+
apiKey: 'eventParam',
|
|
27
|
+
children: [
|
|
28
|
+
{
|
|
29
|
+
apiKey: 'activeStage',
|
|
30
|
+
label: 'Current active stage',
|
|
31
|
+
type: 'String',
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
label: 'Event parameters',
|
|
35
|
+
type: 'Object',
|
|
36
|
+
},
|
|
37
|
+
],
|
|
26
38
|
},
|
|
27
39
|
];
|
|
28
40
|
|
|
@@ -19,8 +19,20 @@ export class StageSwitchModel {
|
|
|
19
19
|
label: 'After active stage changes',
|
|
20
20
|
helpText:
|
|
21
21
|
'Triggered after the active stage changes; event params include activeStage (current active stage)',
|
|
22
|
-
eventParams:
|
|
23
|
-
|
|
22
|
+
eventParams: [
|
|
23
|
+
{
|
|
24
|
+
apiKey: 'eventParam',
|
|
25
|
+
children: [
|
|
26
|
+
{
|
|
27
|
+
apiKey: 'activeStage',
|
|
28
|
+
label: 'Current active stage',
|
|
29
|
+
type: 'String',
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
label: 'Event parameters',
|
|
33
|
+
type: 'Object',
|
|
34
|
+
},
|
|
35
|
+
],
|
|
24
36
|
},
|
|
25
37
|
];
|
|
26
38
|
|
|
@@ -33,8 +33,20 @@ export class StageTimeChartModel {
|
|
|
33
33
|
label: 'Triggered on stage bar click',
|
|
34
34
|
helpText:
|
|
35
35
|
'Triggered when clicking a stage bar; event params include activeStage (current active stage)',
|
|
36
|
-
eventParams:
|
|
37
|
-
|
|
36
|
+
eventParams: [
|
|
37
|
+
{
|
|
38
|
+
apiKey: 'eventParam',
|
|
39
|
+
children: [
|
|
40
|
+
{
|
|
41
|
+
apiKey: 'activeStage',
|
|
42
|
+
label: 'Current active stage',
|
|
43
|
+
type: 'String',
|
|
44
|
+
},
|
|
45
|
+
],
|
|
46
|
+
label: 'Event parameters',
|
|
47
|
+
type: 'Object',
|
|
48
|
+
},
|
|
49
|
+
],
|
|
38
50
|
},
|
|
39
51
|
];
|
|
40
52
|
|
|
@@ -345,7 +345,7 @@ export default class CreateEntityForm extends React.PureComponent<
|
|
|
345
345
|
// 触发表单提交事件
|
|
346
346
|
this.onSubmit({
|
|
347
347
|
xObjectApiKey,
|
|
348
|
-
data: values
|
|
348
|
+
data: values,
|
|
349
349
|
});
|
|
350
350
|
});
|
|
351
351
|
}
|
|
@@ -438,275 +438,287 @@ export default class CreateEntityForm extends React.PureComponent<
|
|
|
438
438
|
|
|
439
439
|
return (
|
|
440
440
|
<>
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
441
|
+
<Form
|
|
442
|
+
ref={(form) => this.setState({ form })}
|
|
443
|
+
layout="horizontal"
|
|
444
|
+
{...formItemLayout}
|
|
445
|
+
>
|
|
446
|
+
<Row gutter={16}>
|
|
447
|
+
{curFieldList.map((field) => {
|
|
448
|
+
// 跳过 ID 字段,不需要在表单中显示
|
|
449
|
+
if (field.apiKey === 'id') return null;
|
|
450
|
+
|
|
451
|
+
let inputComponent;
|
|
452
|
+
const selectitem = field.selectitem || [];
|
|
453
|
+
const checkitem = field.checkitem || [];
|
|
454
|
+
|
|
455
|
+
// 关联字段:存在 referTo 时,渲染为点击选择弹窗的输入框
|
|
456
|
+
if (
|
|
457
|
+
field.referTo &&
|
|
458
|
+
field.type !== 'entityType' &&
|
|
459
|
+
field.type !== 'entitytype'
|
|
460
|
+
) {
|
|
461
|
+
// 非业务类型字段
|
|
462
|
+
const selectedLabel = referSelectedLabels[field.apiKey] || '';
|
|
463
|
+
const colSpan = columnCount === 2 ? 12 : 24;
|
|
464
|
+
return (
|
|
465
|
+
<Col span={colSpan} key={field.apiKey}>
|
|
466
|
+
<Form.Item
|
|
467
|
+
label={field.label}
|
|
468
|
+
required={field.required ?? false}
|
|
469
|
+
>
|
|
470
|
+
<Input.Group compact style={{ display: 'flex' }}>
|
|
471
|
+
<Form.Item
|
|
472
|
+
name={field.apiKey}
|
|
473
|
+
noStyle
|
|
474
|
+
rules={[
|
|
475
|
+
{
|
|
476
|
+
required: field.required,
|
|
477
|
+
message: `请选择${field.label}`,
|
|
478
|
+
},
|
|
479
|
+
]}
|
|
480
|
+
>
|
|
481
|
+
<Input type="hidden" />
|
|
482
|
+
</Form.Item>
|
|
483
|
+
<Input
|
|
484
|
+
readOnly
|
|
485
|
+
value={selectedLabel}
|
|
486
|
+
placeholder={`请点击选择${field.label}`}
|
|
487
|
+
style={{ flex: 1, cursor: 'pointer' }}
|
|
488
|
+
onClick={() => this.openReferModal(field)}
|
|
489
|
+
/>
|
|
490
|
+
<Button
|
|
491
|
+
type="primary"
|
|
492
|
+
onClick={() => this.openReferModal(field)}
|
|
493
|
+
>
|
|
494
|
+
选择
|
|
495
|
+
</Button>
|
|
496
|
+
</Input.Group>
|
|
497
|
+
</Form.Item>
|
|
498
|
+
</Col>
|
|
499
|
+
);
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
// 根据字段类型生成对应的输入组件
|
|
503
|
+
switch (field.type) {
|
|
504
|
+
case 'entityType':
|
|
505
|
+
case 'entitytype':
|
|
506
|
+
// 业务类型选择器
|
|
507
|
+
inputComponent = (
|
|
508
|
+
<Select placeholder="请选择业务类型" allowClear>
|
|
509
|
+
{entityTypeList.map((item) => (
|
|
510
|
+
<Option
|
|
511
|
+
key={item.apiKey}
|
|
512
|
+
value={item.id}
|
|
513
|
+
disabled={!item.active}
|
|
514
|
+
>
|
|
515
|
+
{item.label}
|
|
516
|
+
</Option>
|
|
517
|
+
))}
|
|
518
|
+
</Select>
|
|
519
|
+
);
|
|
520
|
+
break;
|
|
521
|
+
case 'picklist':
|
|
522
|
+
// 单选下拉框
|
|
523
|
+
inputComponent = (
|
|
524
|
+
<Select placeholder={`请选择${field.label}`} allowClear>
|
|
525
|
+
{selectitem.map((item) => (
|
|
526
|
+
<Option key={item.apiKey} value={item.id}>
|
|
527
|
+
{item.label}
|
|
528
|
+
</Option>
|
|
529
|
+
))}
|
|
530
|
+
</Select>
|
|
531
|
+
);
|
|
532
|
+
break;
|
|
533
|
+
case 'textarea':
|
|
534
|
+
// 多行文本输入框
|
|
535
|
+
inputComponent = (
|
|
536
|
+
<Input.TextArea
|
|
537
|
+
placeholder={`请输入${field.label}`}
|
|
538
|
+
rows={3}
|
|
539
|
+
showCount
|
|
540
|
+
maxLength={500}
|
|
541
|
+
/>
|
|
542
|
+
);
|
|
543
|
+
break;
|
|
544
|
+
case 'multipicklist':
|
|
545
|
+
// 多选下拉框
|
|
546
|
+
inputComponent = (
|
|
547
|
+
<Select
|
|
548
|
+
placeholder={`请选择${field.label}`}
|
|
549
|
+
mode="multiple"
|
|
550
|
+
allowClear
|
|
551
|
+
>
|
|
552
|
+
{checkitem.map((item) => (
|
|
553
|
+
<Option key={item.apiKey} value={item.id}>
|
|
554
|
+
{item.label}
|
|
555
|
+
</Option>
|
|
556
|
+
))}
|
|
557
|
+
</Select>
|
|
558
|
+
);
|
|
559
|
+
break;
|
|
560
|
+
case 'datetime':
|
|
561
|
+
// 日期时间选择器
|
|
562
|
+
inputComponent = (
|
|
563
|
+
<DatePicker
|
|
564
|
+
placeholder={`请选择${field.label}`}
|
|
565
|
+
format={'YYYY/MM/DD HH:mm:ss'}
|
|
566
|
+
showTime={true}
|
|
567
|
+
style={{ width: '100%' }}
|
|
568
|
+
/>
|
|
569
|
+
);
|
|
570
|
+
break;
|
|
571
|
+
case 'date':
|
|
572
|
+
// 日期选择器
|
|
573
|
+
inputComponent = (
|
|
574
|
+
<DatePicker
|
|
575
|
+
placeholder={`请选择${field.label}`}
|
|
576
|
+
format={'YYYY/MM/DD'}
|
|
577
|
+
style={{ width: '100%' }}
|
|
578
|
+
/>
|
|
579
|
+
);
|
|
580
|
+
break;
|
|
581
|
+
case 'time':
|
|
582
|
+
// 时间选择器
|
|
583
|
+
inputComponent = (
|
|
584
|
+
<DatePicker
|
|
585
|
+
placeholder={`请选择${field.label}`}
|
|
586
|
+
format={'HH:mm:ss'}
|
|
587
|
+
showTime={true}
|
|
588
|
+
style={{ width: '100%' }}
|
|
589
|
+
/>
|
|
590
|
+
);
|
|
591
|
+
break;
|
|
592
|
+
case 'int':
|
|
593
|
+
case 'float':
|
|
594
|
+
// 数字输入框
|
|
595
|
+
inputComponent = (
|
|
596
|
+
<InputNumber
|
|
597
|
+
placeholder={`请输入${field.label}`}
|
|
598
|
+
style={{ width: '100%' }}
|
|
599
|
+
/>
|
|
600
|
+
);
|
|
601
|
+
break;
|
|
602
|
+
case 'email':
|
|
603
|
+
// 邮箱输入框
|
|
604
|
+
inputComponent = (
|
|
605
|
+
<Input placeholder={`请输入${field.label}`} type="email" />
|
|
606
|
+
);
|
|
607
|
+
break;
|
|
608
|
+
case 'url':
|
|
609
|
+
// URL 输入框
|
|
610
|
+
inputComponent = (
|
|
611
|
+
<Input placeholder={`请输入${field.label}`} type="url" />
|
|
612
|
+
);
|
|
613
|
+
break;
|
|
614
|
+
case 'phone':
|
|
615
|
+
// 电话号码输入框
|
|
616
|
+
inputComponent = (
|
|
617
|
+
<Input placeholder={`请输入${field.label}`} type="tel" />
|
|
618
|
+
);
|
|
619
|
+
break;
|
|
620
|
+
default:
|
|
621
|
+
// 默认文本输入框
|
|
622
|
+
inputComponent = (
|
|
623
|
+
<Input
|
|
624
|
+
placeholder={`请输入${field.label}`}
|
|
625
|
+
maxLength={200}
|
|
626
|
+
/>
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
|
|
459
630
|
const colSpan = columnCount === 2 ? 12 : 24;
|
|
631
|
+
|
|
460
632
|
return (
|
|
461
633
|
<Col span={colSpan} key={field.apiKey}>
|
|
462
634
|
<Form.Item
|
|
635
|
+
name={field.apiKey}
|
|
463
636
|
label={field.label}
|
|
464
637
|
required={field.required ?? false}
|
|
638
|
+
rules={[
|
|
639
|
+
{
|
|
640
|
+
required: field.required,
|
|
641
|
+
message: `请${
|
|
642
|
+
field.type === 'picklist' ||
|
|
643
|
+
field.type === 'multipicklist' ||
|
|
644
|
+
field.type === 'entityType' ||
|
|
645
|
+
field.type === 'entitytype' ||
|
|
646
|
+
field.type === 'date' ||
|
|
647
|
+
field.type === 'datetime' ||
|
|
648
|
+
field.type === 'time'
|
|
649
|
+
? '选择'
|
|
650
|
+
: '输入'
|
|
651
|
+
}${field.label}`,
|
|
652
|
+
},
|
|
653
|
+
]}
|
|
465
654
|
>
|
|
466
|
-
|
|
467
|
-
<Form.Item
|
|
468
|
-
name={field.apiKey}
|
|
469
|
-
noStyle
|
|
470
|
-
rules={[
|
|
471
|
-
{
|
|
472
|
-
required: field.required,
|
|
473
|
-
message: `请选择${field.label}`,
|
|
474
|
-
},
|
|
475
|
-
]}
|
|
476
|
-
>
|
|
477
|
-
<Input type="hidden" />
|
|
478
|
-
</Form.Item>
|
|
479
|
-
<Input
|
|
480
|
-
readOnly
|
|
481
|
-
value={selectedLabel}
|
|
482
|
-
placeholder={`请点击选择${field.label}`}
|
|
483
|
-
style={{ flex: 1, cursor: 'pointer' }}
|
|
484
|
-
onClick={() => this.openReferModal(field)}
|
|
485
|
-
/>
|
|
486
|
-
<Button
|
|
487
|
-
type="primary"
|
|
488
|
-
onClick={() => this.openReferModal(field)}
|
|
489
|
-
>
|
|
490
|
-
选择
|
|
491
|
-
</Button>
|
|
492
|
-
</Input.Group>
|
|
655
|
+
{inputComponent}
|
|
493
656
|
</Form.Item>
|
|
494
657
|
</Col>
|
|
495
658
|
);
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
<Option key={item.apiKey} value={item.id}>
|
|
550
|
-
{item.label}
|
|
551
|
-
</Option>
|
|
552
|
-
))}
|
|
553
|
-
</Select>
|
|
554
|
-
);
|
|
555
|
-
break;
|
|
556
|
-
case 'datetime':
|
|
557
|
-
// 日期时间选择器
|
|
558
|
-
inputComponent = (
|
|
559
|
-
<DatePicker
|
|
560
|
-
placeholder={`请选择${field.label}`}
|
|
561
|
-
format={'YYYY/MM/DD HH:mm:ss'}
|
|
562
|
-
showTime={true}
|
|
563
|
-
style={{ width: '100%' }}
|
|
564
|
-
/>
|
|
565
|
-
);
|
|
566
|
-
break;
|
|
567
|
-
case 'date':
|
|
568
|
-
// 日期选择器
|
|
569
|
-
inputComponent = (
|
|
570
|
-
<DatePicker
|
|
571
|
-
placeholder={`请选择${field.label}`}
|
|
572
|
-
format={'YYYY/MM/DD'}
|
|
573
|
-
style={{ width: '100%' }}
|
|
574
|
-
/>
|
|
575
|
-
);
|
|
576
|
-
break;
|
|
577
|
-
case 'time':
|
|
578
|
-
// 时间选择器
|
|
579
|
-
inputComponent = (
|
|
580
|
-
<DatePicker
|
|
581
|
-
placeholder={`请选择${field.label}`}
|
|
582
|
-
format={'HH:mm:ss'}
|
|
583
|
-
showTime={true}
|
|
584
|
-
style={{ width: '100%' }}
|
|
585
|
-
/>
|
|
586
|
-
);
|
|
587
|
-
break;
|
|
588
|
-
case 'int':
|
|
589
|
-
case 'float':
|
|
590
|
-
// 数字输入框
|
|
591
|
-
inputComponent = (
|
|
592
|
-
<InputNumber
|
|
593
|
-
placeholder={`请输入${field.label}`}
|
|
594
|
-
style={{ width: '100%' }}
|
|
595
|
-
/>
|
|
596
|
-
);
|
|
597
|
-
break;
|
|
598
|
-
case 'email':
|
|
599
|
-
// 邮箱输入框
|
|
600
|
-
inputComponent = (
|
|
601
|
-
<Input placeholder={`请输入${field.label}`} type="email" />
|
|
602
|
-
);
|
|
603
|
-
break;
|
|
604
|
-
case 'url':
|
|
605
|
-
// URL 输入框
|
|
606
|
-
inputComponent = (
|
|
607
|
-
<Input placeholder={`请输入${field.label}`} type="url" />
|
|
608
|
-
);
|
|
609
|
-
break;
|
|
610
|
-
case 'phone':
|
|
611
|
-
// 电话号码输入框
|
|
612
|
-
inputComponent = (
|
|
613
|
-
<Input placeholder={`请输入${field.label}`} type="tel" />
|
|
614
|
-
);
|
|
615
|
-
break;
|
|
616
|
-
default:
|
|
617
|
-
// 默认文本输入框
|
|
618
|
-
inputComponent = (
|
|
619
|
-
<Input placeholder={`请输入${field.label}`} maxLength={200} />
|
|
620
|
-
);
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
const colSpan = columnCount === 2 ? 12 : 24;
|
|
624
|
-
|
|
625
|
-
return (
|
|
626
|
-
<Col span={colSpan} key={field.apiKey}>
|
|
627
|
-
<Form.Item
|
|
628
|
-
name={field.apiKey}
|
|
629
|
-
label={field.label}
|
|
630
|
-
required={field.required ?? false}
|
|
631
|
-
rules={[
|
|
632
|
-
{
|
|
633
|
-
required: field.required,
|
|
634
|
-
message: `请${
|
|
635
|
-
field.type === 'picklist' ||
|
|
636
|
-
field.type === 'multipicklist' ||
|
|
637
|
-
field.type === 'entityType' ||
|
|
638
|
-
field.type === 'entitytype' ||
|
|
639
|
-
field.type === 'date' ||
|
|
640
|
-
field.type === 'datetime' ||
|
|
641
|
-
field.type === 'time'
|
|
642
|
-
? '选择'
|
|
643
|
-
: '输入'
|
|
644
|
-
}${field.label}`,
|
|
659
|
+
})}
|
|
660
|
+
</Row>
|
|
661
|
+
|
|
662
|
+
{submitSuccess && (
|
|
663
|
+
<div className="submit-success-message">
|
|
664
|
+
<CheckCircleOutlined /> 数据已成功提交
|
|
665
|
+
</div>
|
|
666
|
+
)}
|
|
667
|
+
</Form>
|
|
668
|
+
|
|
669
|
+
<Modal
|
|
670
|
+
open={referModalVisible}
|
|
671
|
+
onCancel={this.closeReferModal}
|
|
672
|
+
footer={null}
|
|
673
|
+
width={900}
|
|
674
|
+
title={`选择${currentReferField?.label || ''}`}
|
|
675
|
+
destroyOnClose
|
|
676
|
+
>
|
|
677
|
+
{currentReferField && currentReferField.referTo && (
|
|
678
|
+
<NeoEntityGrid
|
|
679
|
+
render={this.props.render}
|
|
680
|
+
objectApiKey={currentReferField.referTo.apiKey}
|
|
681
|
+
referData={{
|
|
682
|
+
referObjectApiKey: xObjectDataApi?.xObjectApiKey,
|
|
683
|
+
referItemApiKey: currentReferField.apiKey,
|
|
684
|
+
}}
|
|
685
|
+
selectedCount={1}
|
|
686
|
+
hiddenHeader={true}
|
|
687
|
+
onCancel={this.closeReferModal}
|
|
688
|
+
onSelectedCall={(selectedData: any) => {
|
|
689
|
+
const { currentReferField: curField, currentReferField } =
|
|
690
|
+
this.state;
|
|
691
|
+
if (!curField) return;
|
|
692
|
+
|
|
693
|
+
const items = Array.isArray(selectedData)
|
|
694
|
+
? selectedData
|
|
695
|
+
: [selectedData];
|
|
696
|
+
const firstItem = items[0];
|
|
697
|
+
const selectedId = firstItem?.id ?? firstItem;
|
|
698
|
+
const selectedName =
|
|
699
|
+
firstItem[`${currentReferField?.referTo?.apiKey}Name`] ||
|
|
700
|
+
firstItem?.label ||
|
|
701
|
+
firstItem?.name ||
|
|
702
|
+
firstItem?.id;
|
|
703
|
+
|
|
704
|
+
if (selectedId !== undefined && selectedId !== null) {
|
|
705
|
+
this.state.form?.setFieldsValue({
|
|
706
|
+
[curField.apiKey]: selectedId,
|
|
707
|
+
});
|
|
708
|
+
this.setState((prev) => ({
|
|
709
|
+
referSelectedLabels: {
|
|
710
|
+
...prev.referSelectedLabels,
|
|
711
|
+
[curField.apiKey]: selectedName,
|
|
645
712
|
},
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
{submitSuccess && (
|
|
656
|
-
<div className="submit-success-message">
|
|
657
|
-
<CheckCircleOutlined /> 数据已成功提交
|
|
658
|
-
</div>
|
|
659
|
-
)}
|
|
660
|
-
</Form>
|
|
661
|
-
|
|
662
|
-
<Modal
|
|
663
|
-
open={referModalVisible}
|
|
664
|
-
onCancel={this.closeReferModal}
|
|
665
|
-
footer={null}
|
|
666
|
-
width={900}
|
|
667
|
-
title={`选择${currentReferField?.label || ''}`}
|
|
668
|
-
destroyOnClose
|
|
669
|
-
>
|
|
670
|
-
{currentReferField && currentReferField.referTo && (
|
|
671
|
-
<NeoEntityGrid
|
|
672
|
-
render={this.props.render}
|
|
673
|
-
objectApiKey={currentReferField.referTo.apiKey}
|
|
674
|
-
referData={{
|
|
675
|
-
referObjectApiKey: xObjectDataApi?.xObjectApiKey,
|
|
676
|
-
referItemApiKey: currentReferField.apiKey,
|
|
677
|
-
}}
|
|
678
|
-
selectedCount={1}
|
|
679
|
-
hiddenHeader={true}
|
|
680
|
-
onCancel={this.closeReferModal}
|
|
681
|
-
onSelectedCall={(selectedData: any) => {
|
|
682
|
-
const { currentReferField: curField, currentReferField } = this.state;
|
|
683
|
-
if (!curField) return;
|
|
684
|
-
|
|
685
|
-
const items = Array.isArray(selectedData)
|
|
686
|
-
? selectedData
|
|
687
|
-
: [selectedData];
|
|
688
|
-
const firstItem = items[0];
|
|
689
|
-
const selectedId = firstItem?.id ?? firstItem;
|
|
690
|
-
const selectedName = firstItem[`${currentReferField?.referTo?.apiKey}Name`] || firstItem?.label || firstItem?.name || firstItem?.id;
|
|
691
|
-
|
|
692
|
-
if (selectedId !== undefined && selectedId !== null) {
|
|
693
|
-
this.state.form?.setFieldsValue({
|
|
694
|
-
[curField.apiKey]: selectedId,
|
|
695
|
-
});
|
|
696
|
-
this.setState((prev) => ({
|
|
697
|
-
referSelectedLabels: {
|
|
698
|
-
...prev.referSelectedLabels,
|
|
699
|
-
[curField.apiKey]: selectedName,
|
|
700
|
-
},
|
|
701
|
-
referModalVisible: false,
|
|
702
|
-
currentReferField: null,
|
|
703
|
-
}));
|
|
704
|
-
}
|
|
705
|
-
return false; // 阻止事件冒泡
|
|
706
|
-
}}
|
|
707
|
-
/>
|
|
708
|
-
)}
|
|
709
|
-
</Modal>
|
|
713
|
+
referModalVisible: false,
|
|
714
|
+
currentReferField: null,
|
|
715
|
+
}));
|
|
716
|
+
}
|
|
717
|
+
return false; // 阻止事件冒泡
|
|
718
|
+
}}
|
|
719
|
+
/>
|
|
720
|
+
)}
|
|
721
|
+
</Modal>
|
|
710
722
|
</>
|
|
711
723
|
);
|
|
712
724
|
}
|
|
@@ -52,7 +52,14 @@ export class CreateFormModel {
|
|
|
52
52
|
columnCount: 2,
|
|
53
53
|
xObjectDataApi: {
|
|
54
54
|
xObjectApiKey: 'opportunity',
|
|
55
|
-
fields: [
|
|
55
|
+
fields: [
|
|
56
|
+
'entityType',
|
|
57
|
+
'ownerId',
|
|
58
|
+
'opportunityName',
|
|
59
|
+
'accountId',
|
|
60
|
+
'money',
|
|
61
|
+
'closeDate',
|
|
62
|
+
],
|
|
56
63
|
},
|
|
57
64
|
};
|
|
58
65
|
|
|
@@ -65,8 +72,15 @@ export class CreateFormModel {
|
|
|
65
72
|
apiKey: 'onSubmit', // 事件名称
|
|
66
73
|
label: '提交表单后', // 事件
|
|
67
74
|
helpText: '表单提交后触发该事件', // 信息icon hover 时的提示文本
|
|
68
|
-
|
|
69
|
-
|
|
75
|
+
// 定义事件触发时接收到的事件数据格式
|
|
76
|
+
eventParams: [
|
|
77
|
+
{
|
|
78
|
+
apiKey: 'eventParam',
|
|
79
|
+
children: [{ apiKey: 'data', label: '当前表单数据', type: 'Object' }],
|
|
80
|
+
label: '事件入参',
|
|
81
|
+
type: 'Object',
|
|
82
|
+
},
|
|
83
|
+
],
|
|
70
84
|
},
|
|
71
85
|
];
|
|
72
86
|
|
|
@@ -55,7 +55,11 @@ export default class NeoEntityGridCmp extends BaseCmp<
|
|
|
55
55
|
*/
|
|
56
56
|
@NeoEvent.function
|
|
57
57
|
handleCustomSearchEvent(eventData: any) {
|
|
58
|
-
console.log(
|
|
58
|
+
console.log(
|
|
59
|
+
'设置自定义筛选条件(handleCustomSearchEvent): ',
|
|
60
|
+
eventData,
|
|
61
|
+
this.props,
|
|
62
|
+
);
|
|
59
63
|
|
|
60
64
|
if (!eventData) {
|
|
61
65
|
this.setState({ additionalConditions: [] });
|
|
@@ -67,14 +67,15 @@ export class NeoEntityGridModel {
|
|
|
67
67
|
apiKey: 'handleCustomSearchEvent',
|
|
68
68
|
label: '更新筛选条件',
|
|
69
69
|
helpTextKey: '更新自定义筛选条件',
|
|
70
|
-
funcInParams: [
|
|
70
|
+
funcInParams: [
|
|
71
|
+
// 定义组件函数入参
|
|
71
72
|
{
|
|
72
73
|
apiKey: 'eventData',
|
|
73
74
|
label: '自定义筛选条件',
|
|
74
75
|
type: 'Array',
|
|
75
|
-
required: true
|
|
76
|
+
required: true,
|
|
76
77
|
},
|
|
77
|
-
]
|
|
78
|
+
],
|
|
78
79
|
},
|
|
79
80
|
];
|
|
80
81
|
|
|
@@ -61,7 +61,7 @@ export default class NeoEntityGridCmp extends React.PureComponent<NeoEntityGridP
|
|
|
61
61
|
objectApiKey={objectApiKey || 'account'}
|
|
62
62
|
pattern={'pickView'} // Picker 列表(选择器)
|
|
63
63
|
referData={referData}
|
|
64
|
-
selectionMode={selectionMode ??
|
|
64
|
+
selectionMode={selectionMode ?? 'single'} // 多选模式
|
|
65
65
|
shouldCloseDialog={restProps.shouldCloseDialog ?? true}
|
|
66
66
|
onRowSelected={(data: any, event: any) => {
|
|
67
67
|
const selectedIds = data.map(({ data }: any) => data.id);
|
|
@@ -335,10 +335,11 @@ export default class SearchForm extends React.PureComponent<
|
|
|
335
335
|
const payload: CustomQueryPayload = {
|
|
336
336
|
xObjectApiKey, // 冗余数据
|
|
337
337
|
conditions, // 冗余数据
|
|
338
|
-
data: {
|
|
338
|
+
data: {
|
|
339
|
+
// 事件动作的入参数据
|
|
339
340
|
xObjectApiKey,
|
|
340
|
-
conditions
|
|
341
|
-
}
|
|
341
|
+
conditions,
|
|
342
|
+
},
|
|
342
343
|
};
|
|
343
344
|
|
|
344
345
|
this.onQuery(payload);
|
|
@@ -66,10 +66,15 @@ export class SearchFormModel {
|
|
|
66
66
|
label: '点击查询后',
|
|
67
67
|
helpText:
|
|
68
68
|
'点击「查询」后触发;事件参数为 { xObjectApiKey, conditions },conditions 每项含 apiKey、type(1 等于 / 3 包含)、value',
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
// 定义事件触发时接收到的事件数据格式
|
|
70
|
+
eventParams: [
|
|
71
|
+
{
|
|
72
|
+
apiKey: 'eventParam',
|
|
73
|
+
children: [{ apiKey: 'data', label: '当前表单数据', type: 'Object' }],
|
|
74
|
+
label: '事件入参',
|
|
75
|
+
type: 'Object',
|
|
76
|
+
},
|
|
77
|
+
],
|
|
73
78
|
},
|
|
74
79
|
];
|
|
75
80
|
|
|
@@ -189,7 +189,8 @@
|
|
|
189
189
|
font-weight: 400;
|
|
190
190
|
min-width: auto;
|
|
191
191
|
margin-left: 10px;
|
|
192
|
-
transition: border-color 0.2s ease, background 0.2s ease,
|
|
192
|
+
transition: border-color 0.2s ease, background 0.2s ease,
|
|
193
|
+
box-shadow 0.2s ease;
|
|
193
194
|
|
|
194
195
|
&:first-child {
|
|
195
196
|
margin-left: 0;
|
|
@@ -332,17 +332,11 @@ export default class BatchAddTable extends React.PureComponent<
|
|
|
332
332
|
(it) => it.id === raw || String(it.id) === s,
|
|
333
333
|
);
|
|
334
334
|
if (byId) return byId.id;
|
|
335
|
-
const byLabel = entityTypeList.find(
|
|
336
|
-
(it) => String(it.label).trim() === s,
|
|
337
|
-
);
|
|
335
|
+
const byLabel = entityTypeList.find((it) => String(it.label).trim() === s);
|
|
338
336
|
return byLabel ? byLabel.id : raw;
|
|
339
337
|
}
|
|
340
338
|
|
|
341
|
-
parseImportedCell(
|
|
342
|
-
field: FieldInfo,
|
|
343
|
-
raw: any,
|
|
344
|
-
entityTypeList: any[],
|
|
345
|
-
): any {
|
|
339
|
+
parseImportedCell(field: FieldInfo, raw: any, entityTypeList: any[]): any {
|
|
346
340
|
if (raw === undefined || raw === null || raw === '') return undefined;
|
|
347
341
|
if (raw instanceof Date) {
|
|
348
342
|
if (
|
|
@@ -430,7 +424,9 @@ export default class BatchAddTable extends React.PureComponent<
|
|
|
430
424
|
const ws = XLSX.utils.aoa_to_sheet([headers]); // 将标题行转换为工作表
|
|
431
425
|
const wb = XLSX.utils.book_new(); // 创建新的工作簿
|
|
432
426
|
XLSX.utils.book_append_sheet(wb, ws, '导入模板'); // 将工作表添加到工作簿
|
|
433
|
-
const name = `${
|
|
427
|
+
const name = `${
|
|
428
|
+
this.props.xObjectDataApi?.xObjectApiKey || 'data'
|
|
429
|
+
}_导入模板.xlsx`; // 生成文件名
|
|
434
430
|
XLSX.writeFile(wb, name); // 将工作簿写入文件
|
|
435
431
|
message.success('模板已下载');
|
|
436
432
|
}
|
|
@@ -775,11 +771,7 @@ export default class BatchAddTable extends React.PureComponent<
|
|
|
775
771
|
style={{ minWidth: 140 }}
|
|
776
772
|
>
|
|
777
773
|
{entityTypeList.map((item) => (
|
|
778
|
-
<Option
|
|
779
|
-
key={item.apiKey}
|
|
780
|
-
value={item.id}
|
|
781
|
-
disabled={!item.active}
|
|
782
|
-
>
|
|
774
|
+
<Option key={item.apiKey} value={item.id} disabled={!item.active}>
|
|
783
775
|
{item.label}
|
|
784
776
|
</Option>
|
|
785
777
|
))}
|
|
@@ -912,7 +904,17 @@ export default class BatchAddTable extends React.PureComponent<
|
|
|
912
904
|
}
|
|
913
905
|
|
|
914
906
|
render() {
|
|
915
|
-
const {
|
|
907
|
+
const {
|
|
908
|
+
loading,
|
|
909
|
+
error,
|
|
910
|
+
rows,
|
|
911
|
+
submitting,
|
|
912
|
+
title,
|
|
913
|
+
importLoading,
|
|
914
|
+
importProgress,
|
|
915
|
+
currentPage,
|
|
916
|
+
pageSize,
|
|
917
|
+
} = this.state;
|
|
916
918
|
const { tableTitle, className, data } = this.props;
|
|
917
919
|
const curAmisData = data || {};
|
|
918
920
|
const systemInfo = curAmisData.__NeoSystemInfo || {};
|
|
@@ -974,12 +976,10 @@ export default class BatchAddTable extends React.PureComponent<
|
|
|
974
976
|
const endIndex = startIndex + pageSize;
|
|
975
977
|
const paginatedRows = rows.slice(startIndex, endIndex);
|
|
976
978
|
|
|
977
|
-
const displayTitle =
|
|
978
|
-
tableTitle || title || '批量新增数据';
|
|
979
|
+
const displayTitle = tableTitle || title || '批量新增数据';
|
|
979
980
|
const batchImportButtonTitle =
|
|
980
981
|
this.props.batchImportButtonTitle ?? '批量导入';
|
|
981
|
-
const batchImportButtonAlign =
|
|
982
|
-
this.props.batchImportButtonAlign ?? 'right';
|
|
982
|
+
const batchImportButtonAlign = this.props.batchImportButtonAlign ?? 'right';
|
|
983
983
|
|
|
984
984
|
const showModalFooter = !error && !!xObjectApiKey && fields.length > 0;
|
|
985
985
|
|
|
@@ -31,21 +31,17 @@ export class BatchAddTableModel {
|
|
|
31
31
|
apiKey: 'onSubmit',
|
|
32
32
|
label: '点击提交',
|
|
33
33
|
helpText: '点击提交按钮时触发,事件参数包含当前表格中所有行数据',
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}],
|
|
46
|
-
*/
|
|
47
|
-
eventParams:
|
|
48
|
-
'[{"apiKey":"eventParam","children":[{"apiKey":"xObjectApiKey","label":"实体 API Key","type":"String"},{"apiKey":"rows","label":"表格数据列表","type":"Array"}],"label":"事件入参","type":"Object"}]',
|
|
34
|
+
eventParams: [
|
|
35
|
+
{
|
|
36
|
+
apiKey: 'eventParam',
|
|
37
|
+
children: [
|
|
38
|
+
{ apiKey: 'xObjectApiKey', label: '实体 API Key', type: 'String' },
|
|
39
|
+
{ apiKey: 'rows', label: '表格数据列表', type: 'Array' },
|
|
40
|
+
],
|
|
41
|
+
label: '事件入参',
|
|
42
|
+
type: 'Object',
|
|
43
|
+
},
|
|
44
|
+
],
|
|
49
45
|
},
|
|
50
46
|
];
|
|
51
47
|
|
|
@@ -29,7 +29,9 @@ interface ListSummaryState {
|
|
|
29
29
|
listData: any[];
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
function getFirstFieldApiKey(
|
|
32
|
+
function getFirstFieldApiKey(
|
|
33
|
+
desc?: FieldDescItem[] | null,
|
|
34
|
+
): string | undefined {
|
|
33
35
|
if (!desc || !Array.isArray(desc) || desc.length === 0) return undefined;
|
|
34
36
|
const first = desc[0];
|
|
35
37
|
return first?.value;
|
|
@@ -84,12 +86,11 @@ class ListSummary extends BaseCmp<ListSummaryProps, ListSummaryState> {
|
|
|
84
86
|
|
|
85
87
|
const hasRows = Array.isArray(listData) && listData.length > 0;
|
|
86
88
|
const totalQty = hasRows && qtyKey ? sumField(listData, qtyKey) : 0;
|
|
87
|
-
const totalAmount =
|
|
89
|
+
const totalAmount =
|
|
90
|
+
hasRows && amountKey ? sumField(listData, amountKey) : 0;
|
|
88
91
|
|
|
89
92
|
const qtyDisplay =
|
|
90
|
-
!hasRows || !qtyKey
|
|
91
|
-
? '0'
|
|
92
|
-
: totalQty.toLocaleString('zh-CN');
|
|
93
|
+
!hasRows || !qtyKey ? '0' : totalQty.toLocaleString('zh-CN');
|
|
93
94
|
|
|
94
95
|
const amountDisplay =
|
|
95
96
|
!hasRows || !amountKey
|