amis 1.9.1-beta.11 → 1.9.1-beta.12
Sign up to get free protection for your applications and to get access to all the features.
- package/lib/RootRenderer.js +14 -0
- package/lib/RootRenderer.js.map +2 -2
- package/lib/SchemaRenderer.js +8 -3
- package/lib/SchemaRenderer.js.map +2 -2
- package/lib/components/Alert2.d.ts +10 -10
- package/lib/components/DateRangePicker.js +11 -9
- package/lib/components/DateRangePicker.js.map +2 -2
- package/lib/components/SearchBox.d.ts +40 -40
- package/lib/components/Select.d.ts +193 -193
- package/lib/components/Select.js +2 -4
- package/lib/components/Select.js.map +2 -2
- package/lib/components/virtual-list/index.js +1 -1
- package/lib/components/virtual-list/index.js.map +1 -1
- package/lib/index.js +1 -1
- package/lib/locale/de-DE.js +1 -0
- package/lib/locale/de-DE.js.map +2 -2
- package/lib/locale/en-US.js +1 -0
- package/lib/locale/en-US.js.map +2 -2
- package/lib/locale/zh-CN.js +5 -2
- package/lib/locale/zh-CN.js.map +2 -2
- package/lib/renderers/Action.d.ts +6 -0
- package/lib/renderers/Action.js.map +2 -2
- package/lib/renderers/CRUD.js +2 -1
- package/lib/renderers/CRUD.js.map +2 -2
- package/lib/renderers/Card.js +5 -4
- package/lib/renderers/Card.js.map +2 -2
- package/lib/renderers/Carousel.d.ts +1 -1
- package/lib/renderers/Carousel.js +5 -1
- package/lib/renderers/Carousel.js.map +2 -2
- package/lib/renderers/Form/InputImage.js +1 -1
- package/lib/renderers/Form/InputImage.js.map +2 -2
- package/lib/renderers/Form/InputText.js +1 -1
- package/lib/renderers/Form/InputText.js.map +2 -2
- package/lib/renderers/Form/Options.js +1 -0
- package/lib/renderers/Form/Options.js.map +2 -2
- package/lib/renderers/Form/Select.d.ts +12 -0
- package/lib/renderers/Form/Select.js +1 -3
- package/lib/renderers/Form/Select.js.map +2 -2
- package/lib/renderers/Form/wrapControl.js +72 -19
- package/lib/renderers/Form/wrapControl.js.map +2 -2
- package/lib/renderers/Service.js +1 -0
- package/lib/renderers/Service.js.map +2 -2
- package/lib/renderers/Table/TableContent.d.ts +2 -2
- package/lib/renderers/Table/TableContent.js +4 -16
- package/lib/renderers/Table/TableContent.js.map +2 -2
- package/lib/renderers/Table/index.d.ts +2 -5
- package/lib/renderers/Table/index.js +2 -2
- package/lib/renderers/Table/index.js.map +2 -2
- package/lib/store/table.js +7 -3
- package/lib/store/table.js.map +2 -2
- package/lib/themes/ang-ie11.css +0 -1
- package/lib/themes/ang.css +0 -1
- package/lib/themes/ang.css.map +1 -1
- package/lib/themes/antd-ie11.css +0 -1
- package/lib/themes/antd.css +0 -1
- package/lib/themes/antd.css.map +1 -1
- package/lib/themes/cxd-ie11.css +8 -1
- package/lib/themes/cxd.css +8 -1
- package/lib/themes/cxd.css.map +1 -1
- package/lib/themes/dark-ie11.css +0 -1
- package/lib/themes/dark.css +0 -1
- package/lib/themes/dark.css.map +1 -1
- package/lib/themes/default-ie11.css +8 -1
- package/lib/themes/default.css +8 -1
- package/lib/themes/default.css.map +1 -1
- package/lib/types.d.ts +1 -1
- package/lib/types.js.map +1 -1
- package/lib/utils/formula.d.ts +16 -0
- package/lib/utils/formula.js +207 -0
- package/lib/utils/formula.js.map +13 -0
- package/lib/utils/grammar.d.ts +4 -0
- package/lib/utils/grammar.js +47 -0
- package/lib/utils/grammar.js.map +13 -0
- package/lib/utils/helper.js +1 -0
- package/lib/utils/helper.js.map +2 -2
- package/lib/utils/tpl.js +3 -0
- package/lib/utils/tpl.js.map +2 -2
- package/package.json +1 -1
- package/schema.json +278 -222
- package/scss/components/_collapse.scss +1 -1
- package/scss/themes/cxd.scss +12 -0
- package/sdk/ang-ie11.css +0 -1
- package/sdk/ang.css +0 -1
- package/sdk/antd-ie11.css +0 -1
- package/sdk/antd.css +0 -1
- package/sdk/barcode.js +51 -51
- package/sdk/charts.js +14 -14
- package/sdk/codemirror.js +7 -7
- package/sdk/color-picker.js +65 -65
- package/sdk/cropperjs.js +2 -2
- package/sdk/cxd-ie11.css +9 -1
- package/sdk/cxd.css +9 -1
- package/sdk/dark-ie11.css +0 -1
- package/sdk/dark.css +0 -1
- package/sdk/exceljs.js +1 -1
- package/sdk/locale/de-DE.js +1 -0
- package/sdk/markdown.js +69 -69
- package/sdk/papaparse.js +1 -1
- package/sdk/renderers/Form/CityDB.js +1 -1
- package/sdk/rest.js +16 -16
- package/sdk/rich-text.js +62 -62
- package/sdk/sdk-ie11.css +9 -1
- package/sdk/sdk.css +9 -1
- package/sdk/sdk.js +1695 -1665
- package/sdk/thirds/hls.js/hls.js +1 -1
- package/sdk/thirds/mpegts.js/mpegts.js +1 -1
- package/sdk/tinymce.js +57 -57
- package/src/RootRenderer.tsx +14 -0
- package/src/SchemaRenderer.tsx +4 -2
- package/src/components/DateRangePicker.tsx +73 -60
- package/src/components/Select.tsx +2 -4
- package/src/components/virtual-list/index.tsx +1 -1
- package/src/locale/de-DE.ts +1 -0
- package/src/locale/en-US.ts +1 -0
- package/src/locale/zh-CN.ts +5 -2
- package/src/renderers/Action.tsx +8 -0
- package/src/renderers/CRUD.tsx +2 -1
- package/src/renderers/Card.tsx +10 -5
- package/src/renderers/Carousel.tsx +10 -4
- package/src/renderers/Form/InputImage.tsx +1 -1
- package/src/renderers/Form/InputText.tsx +1 -0
- package/src/renderers/Form/Options.tsx +1 -0
- package/src/renderers/Form/Select.tsx +13 -3
- package/src/renderers/Form/wrapControl.tsx +90 -22
- package/src/renderers/Service.tsx +1 -0
- package/src/renderers/Table/TableContent.tsx +22 -34
- package/src/renderers/Table/index.tsx +4 -8
- package/src/store/table.ts +10 -3
- package/src/types.ts +1 -0
- package/src/utils/formula.ts +240 -0
- package/src/utils/grammar.ts +53 -0
- package/src/utils/helper.ts +2 -1
- package/src/utils/tpl.ts +2 -0
@@ -7,8 +7,7 @@ import {LocaleProps} from '../../locale';
|
|
7
7
|
import {observer} from 'mobx-react';
|
8
8
|
import {ActionSchema} from '../Action';
|
9
9
|
import ItemActionsWrapper from './ItemActionsWrapper';
|
10
|
-
import {SchemaTpl
|
11
|
-
import {generateIcon} from '../../utils/icon';
|
10
|
+
import {SchemaTpl} from '../../Schema';
|
12
11
|
import {Icon} from '../../components/icons';
|
13
12
|
import {OnEventProps} from '../../utils/renderer-event';
|
14
13
|
|
@@ -26,7 +25,6 @@ export interface TableContentProps extends LocaleProps {
|
|
26
25
|
}>;
|
27
26
|
rows: Array<IRow>;
|
28
27
|
placeholder?: string | SchemaTpl;
|
29
|
-
emptyIcon?: SchemaIcon;
|
30
28
|
render: (region: string, node: SchemaNode, props?: any) => JSX.Element;
|
31
29
|
onMouseMove: (event: React.MouseEvent) => void;
|
32
30
|
onScroll: (event: React.UIEvent) => void;
|
@@ -61,7 +59,8 @@ export interface TableContentProps extends LocaleProps {
|
|
61
59
|
itemActions?: Array<Action>;
|
62
60
|
store: ITableStore;
|
63
61
|
dispatchEvent?: Function;
|
64
|
-
onEvent?: OnEventProps
|
62
|
+
onEvent?: OnEventProps;
|
63
|
+
loading?: boolean;
|
65
64
|
}
|
66
65
|
|
67
66
|
@observer
|
@@ -131,22 +130,14 @@ export class TableContent extends React.Component<TableContentProps> {
|
|
131
130
|
itemAction,
|
132
131
|
affixRow,
|
133
132
|
store,
|
134
|
-
emptyIcon,
|
135
133
|
dispatchEvent,
|
136
|
-
onEvent
|
134
|
+
onEvent,
|
135
|
+
loading
|
137
136
|
} = this.props;
|
138
137
|
|
139
138
|
const tableClassName = cx('Table-table', this.props.tableClassName);
|
140
139
|
const hideHeader = columns.every(column => !column.label);
|
141
140
|
|
142
|
-
let iconElement = null;
|
143
|
-
if (emptyIcon) {
|
144
|
-
iconElement =
|
145
|
-
typeof emptyIcon === 'string'
|
146
|
-
? generateIcon(cx, emptyIcon, 'Icon')
|
147
|
-
: render('icon', emptyIcon);
|
148
|
-
}
|
149
|
-
|
150
141
|
return (
|
151
142
|
<div
|
152
143
|
onMouseMove={onMouseMove}
|
@@ -185,26 +176,23 @@ export class TableContent extends React.Component<TableContentProps> {
|
|
185
176
|
{!rows.length ? (
|
186
177
|
<tbody>
|
187
178
|
<tr className={cx('Table-placeholder')}>
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
translate(placeholder || 'placeholder.noData')
|
206
|
-
)}
|
207
|
-
</td>
|
179
|
+
{
|
180
|
+
!loading ? (
|
181
|
+
<td colSpan={columns.length}>
|
182
|
+
{
|
183
|
+
typeof placeholder === 'string' ? (
|
184
|
+
<>
|
185
|
+
<Icon
|
186
|
+
icon="desk-empty"
|
187
|
+
className={cx('Table-placeholder-empty-icon', 'icon')}
|
188
|
+
/>
|
189
|
+
{translate(placeholder || 'placeholder.noData')}
|
190
|
+
</>
|
191
|
+
) : render('placeholder', translate(placeholder || 'placeholder.noData'))
|
192
|
+
}
|
193
|
+
</td>
|
194
|
+
) : null
|
195
|
+
}
|
208
196
|
</tr>
|
209
197
|
</tbody>
|
210
198
|
) : (
|
@@ -223,11 +223,6 @@ export interface TableSchema extends BaseSchema {
|
|
223
223
|
*/
|
224
224
|
placeholder?: string | SchemaTpl;
|
225
225
|
|
226
|
-
/**
|
227
|
-
* 无数据展示 icon
|
228
|
-
*/
|
229
|
-
emptyIcon?: string | SchemaIcon;
|
230
|
-
|
231
226
|
/**
|
232
227
|
* 是否显示底部
|
233
228
|
*/
|
@@ -365,6 +360,7 @@ export interface TableProps extends RendererProps {
|
|
365
360
|
canAccessSuperData?: boolean;
|
366
361
|
reUseRow?: boolean;
|
367
362
|
itemBadge?: BadgeSchema;
|
363
|
+
loading?: boolean;
|
368
364
|
}
|
369
365
|
|
370
366
|
export type ExportExcelToolbar = SchemaNode & {
|
@@ -2638,9 +2634,9 @@ export default class Table extends React.Component<TableProps, object> {
|
|
2638
2634
|
prefixRowClassName,
|
2639
2635
|
autoFillHeight,
|
2640
2636
|
itemActions,
|
2641
|
-
emptyIcon,
|
2642
2637
|
dispatchEvent,
|
2643
|
-
onEvent
|
2638
|
+
onEvent,
|
2639
|
+
loading
|
2644
2640
|
} = this.props;
|
2645
2641
|
|
2646
2642
|
// 理论上来说 store.rows 应该也行啊
|
@@ -2663,7 +2659,6 @@ export default class Table extends React.Component<TableProps, object> {
|
|
2663
2659
|
columnsGroup={store.columnGroup}
|
2664
2660
|
rows={store.rows}
|
2665
2661
|
placeholder={placeholder}
|
2666
|
-
emptyIcon={emptyIcon}
|
2667
2662
|
render={render}
|
2668
2663
|
onMouseMove={this.handleMouseMove}
|
2669
2664
|
onScroll={this.handleOutterScroll}
|
@@ -2688,6 +2683,7 @@ export default class Table extends React.Component<TableProps, object> {
|
|
2688
2683
|
translate={translate}
|
2689
2684
|
dispatchEvent={dispatchEvent}
|
2690
2685
|
onEvent={onEvent}
|
2686
|
+
loading={loading}
|
2691
2687
|
/>
|
2692
2688
|
);
|
2693
2689
|
}
|
package/src/store/table.ts
CHANGED
@@ -506,20 +506,27 @@ export const TableStore = iRendererStore
|
|
506
506
|
groups[0].label = columns[1].groupName;
|
507
507
|
}
|
508
508
|
|
509
|
+
// 用户是否启用了 groupName
|
510
|
+
const hasGroupName = columns.some(column => column.groupName);
|
511
|
+
|
509
512
|
for (let i = 1; i < len; i++) {
|
510
513
|
let prev = groups[groups.length - 1];
|
511
514
|
const current = columns[i];
|
512
515
|
|
513
|
-
|
516
|
+
const groupNameIsSame =
|
514
517
|
current.groupName === prev.label ||
|
515
518
|
resolveVariableAndFilter(current.groupName, self.data) ===
|
516
|
-
resolveVariableAndFilter(prev.label, self.data)
|
519
|
+
resolveVariableAndFilter(prev.label, self.data);
|
520
|
+
|
521
|
+
if (
|
522
|
+
groupNameIsSame &&
|
523
|
+
((hasGroupName && current.groupName) || !hasGroupName)
|
517
524
|
) {
|
518
525
|
prev.colSpan++;
|
519
526
|
prev.has.push(current);
|
520
527
|
} else {
|
521
528
|
groups.push({
|
522
|
-
label: current.groupName || ' ', // 如果中间没有配置groupName
|
529
|
+
label: current.groupName || current.label || ' ', // 如果中间没有配置groupName,那么样式会错乱,这里设置列的label配置,lable也没有则设置一个空字符串
|
523
530
|
colSpan: 1,
|
524
531
|
rowSpan: 1,
|
525
532
|
index: current.index,
|
package/src/types.ts
CHANGED
@@ -0,0 +1,240 @@
|
|
1
|
+
import isObjectByLodash from 'lodash/isObject';
|
2
|
+
import isString from 'lodash/isString';
|
3
|
+
import isBoolean from 'lodash/isBoolean';
|
4
|
+
import {
|
5
|
+
getVariable,
|
6
|
+
isPureVariable,
|
7
|
+
resolveVariable,
|
8
|
+
resolveVariableAndFilter,
|
9
|
+
evaluate
|
10
|
+
} from 'amis-formula';
|
11
|
+
|
12
|
+
import {filter} from './tpl';
|
13
|
+
import {getFilters} from './tpl-builtin';
|
14
|
+
import {collectVariables} from './grammar';
|
15
|
+
|
16
|
+
/**
|
17
|
+
* formulaExec 运算器:根据当前字符串类型执行对应运算,也可按指定执行模式执行运算
|
18
|
+
*
|
19
|
+
* 运算模式(execMode)支持以下取值:
|
20
|
+
* 1. tpl: 按模板字符串执行(JavaScript 模板引擎),比如:Hello ${amisUser.email}、<h1>Hello</h1>, <span>${amisUser.email}</span>;
|
21
|
+
* 备注: 在模板中可以自由访问变量,详细请见:https://www.lodashjs.com/docs/lodash.template;
|
22
|
+
* 2. formula: 按新版公式表达式执行,用于执行 ${ xxx } 格式的表达式;
|
23
|
+
* 支持从window、localStorage、sessionStorage获取数据,比如:${num1 + 2}、${ls:env}、${window:document}、${window:document.URL}、${amisUser.email};
|
24
|
+
* 详细请见:https://aisuda.bce.baidu.com/amis/zh-CN/docs/concepts/data-mapping#namespace
|
25
|
+
* 3. evalFormula: 按新版公式表达式执行,用于执行 ${ xxx } 和 非${ xxx } 格式的表达式(evalMode 为 true,不用 ${} 包裹也可以执行),功能同 formula 运算模式;
|
26
|
+
* 4. js: 按Javascript执行,表达式中可以通过data.xxx来获取指定数据,并且支持简单运算;
|
27
|
+
* 比如:data.num1 + 2、this.num1 + 2、num1 + 2;(备注:三个表达式是等价的,这里的 this 就是 data。)
|
28
|
+
* 5. var: 以此字符串作为key值从当前数据域data中获取数值;性能最高(运行期间不会生成ast和表达式运算);
|
29
|
+
* 6. true 或者 false: 当execMode设置为true时,不用 ${} 包裹也可以执行表达式;
|
30
|
+
* 7. collect: 用于从表达式中获取所有变量;
|
31
|
+
*
|
32
|
+
* 备注1: 用户也可以使用 registerFormulaExec 注册一个自定义运算器;
|
33
|
+
* 备注2: 模板字符串 和 Javascript 模板引擎 不可以交叉使用;
|
34
|
+
* 备注3: amis 现有的 evalFormula 方法,可执行 ${} 格式类表达式,但不支持 filter 过滤器,所以这里用 resolveValueByName 实现;
|
35
|
+
* 备注4: 后续可考虑将 amis现有的运算器都放这里管理,充当统一的运算器入口。
|
36
|
+
*/
|
37
|
+
|
38
|
+
// 缓存,用于提升性能
|
39
|
+
const FORMULA_EVAL_CACHE: {[key: string]: Function} = {};
|
40
|
+
|
41
|
+
/**
|
42
|
+
* 用于存储当前可用运算器,默认支持 tpl、formula、js、var 四种类型运算器
|
43
|
+
* 备注:在这里统一参数。
|
44
|
+
*/
|
45
|
+
export const FormulaExec: {
|
46
|
+
[key: string]: Function;
|
47
|
+
} = {
|
48
|
+
tpl: (expression: string, data?: object) => {
|
49
|
+
const curData = data || {};
|
50
|
+
return filter(expression, curData);
|
51
|
+
},
|
52
|
+
formula: (expression: string, data?: object) => {
|
53
|
+
// 邮箱格式直接返回,后续需要在 amis-formula 中处理
|
54
|
+
if (
|
55
|
+
/^\$\{([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((.[a-zA-Z0-9_-]{2,3}){1,2})\}$/.test(
|
56
|
+
expression
|
57
|
+
)
|
58
|
+
) {
|
59
|
+
return expression.substring(2, expression.length - 1); // 剔除前后特殊字符
|
60
|
+
}
|
61
|
+
const curData = data || {};
|
62
|
+
let result = undefined;
|
63
|
+
try {
|
64
|
+
// 执行 ${} 格式类表达式,且支持 filter 过滤器。(备注: isPureVariable 可用于判断是否有 过滤器。)
|
65
|
+
result = resolveVariableAndFilter(expression, curData, '| raw');
|
66
|
+
} catch (e) {
|
67
|
+
console.warn(
|
68
|
+
'[formula]表达式执行异常,当前表达式: ',
|
69
|
+
expression,
|
70
|
+
',当前上下文数据: ',
|
71
|
+
data
|
72
|
+
);
|
73
|
+
return expression;
|
74
|
+
}
|
75
|
+
// 备注: 此处不用 result ?? expression 是为了避免 没有对应结果时直接显示 expression: ${xxx}
|
76
|
+
return result;
|
77
|
+
},
|
78
|
+
evalFormula: (expression: string, data?: object) => {
|
79
|
+
const curData = data || {};
|
80
|
+
let result = undefined;
|
81
|
+
try {
|
82
|
+
result = evaluate(expression, curData, {
|
83
|
+
evalMode: true, // evalMode 为 true 时,不用 ${} 包裹也可以执行,
|
84
|
+
allowFilter: false
|
85
|
+
});
|
86
|
+
} catch (e) {
|
87
|
+
console.warn(
|
88
|
+
'[evalFormula]表达式执行异常,当前表达式: ',
|
89
|
+
expression,
|
90
|
+
',当前上下文数据: ',
|
91
|
+
data
|
92
|
+
);
|
93
|
+
return expression;
|
94
|
+
}
|
95
|
+
return result ?? expression;
|
96
|
+
},
|
97
|
+
js: (expression: string, data?: object) => {
|
98
|
+
let debug = false;
|
99
|
+
const idx = expression.indexOf('debugger');
|
100
|
+
if (~idx) {
|
101
|
+
debug = true;
|
102
|
+
expression = expression.replace(/debugger;?/, '');
|
103
|
+
}
|
104
|
+
|
105
|
+
let fn;
|
106
|
+
if (expression in FORMULA_EVAL_CACHE) {
|
107
|
+
fn = FORMULA_EVAL_CACHE[expression];
|
108
|
+
} else {
|
109
|
+
fn = new Function(
|
110
|
+
'data',
|
111
|
+
'utils',
|
112
|
+
`with(data) {${debug ? 'debugger;' : ''}return (${expression});}`
|
113
|
+
);
|
114
|
+
FORMULA_EVAL_CACHE[expression] = fn;
|
115
|
+
}
|
116
|
+
|
117
|
+
data = data || {};
|
118
|
+
|
119
|
+
let curResult = undefined;
|
120
|
+
try {
|
121
|
+
curResult = fn.call(data, data, getFilters());
|
122
|
+
} catch (e) {
|
123
|
+
console.warn(
|
124
|
+
'[formula:js]表达式执行异常,当前表达式: ',
|
125
|
+
expression,
|
126
|
+
',当前上下文数据: ',
|
127
|
+
data
|
128
|
+
);
|
129
|
+
return expression;
|
130
|
+
}
|
131
|
+
return curResult;
|
132
|
+
},
|
133
|
+
var: (expression: string, data?: object) => {
|
134
|
+
const curData = data || {};
|
135
|
+
const result = getVariable(curData, expression); // 不支持过滤器
|
136
|
+
return result ?? expression;
|
137
|
+
},
|
138
|
+
collect: (expression: any) => {
|
139
|
+
let variables: Array<string> = [];
|
140
|
+
if (isObjectByLodash(expression) || isString(expression)) {
|
141
|
+
// 仅对 Object类型 和 String类型 进行变量提取
|
142
|
+
variables = collectVariables(expression);
|
143
|
+
} else {
|
144
|
+
variables = [];
|
145
|
+
}
|
146
|
+
return variables;
|
147
|
+
}
|
148
|
+
};
|
149
|
+
|
150
|
+
// 根据表达式类型自动匹配指定运算器,也可以通过设置 execMode 直接指定运算器
|
151
|
+
export function formulaExec(
|
152
|
+
value: any,
|
153
|
+
data: any,
|
154
|
+
execMode?: string | boolean
|
155
|
+
) {
|
156
|
+
if (!value) {
|
157
|
+
return '';
|
158
|
+
}
|
159
|
+
let OpenFormulaExecEvalMode = false;
|
160
|
+
let curExecMode = '';
|
161
|
+
if (isBoolean(execMode)) {
|
162
|
+
// OpenFormulaExecEvalMode 设置为 true 后,非 ${ xxx } 格式也使用表达式运算器
|
163
|
+
OpenFormulaExecEvalMode = execMode;
|
164
|
+
} else if (isString(execMode)) {
|
165
|
+
// 指定 execMode 可以直接选用对应的运算器
|
166
|
+
curExecMode = execMode;
|
167
|
+
}
|
168
|
+
if (!isString(value)) {
|
169
|
+
// 非字符串类型,直接返回,比如:boolean、number类型、Object、Array类型
|
170
|
+
return value;
|
171
|
+
} else if (curExecMode && FormulaExec[curExecMode]) {
|
172
|
+
return FormulaExec[curExecMode];
|
173
|
+
}
|
174
|
+
|
175
|
+
const curValue = value.trim(); // 剔除前后空格
|
176
|
+
|
177
|
+
// OpenFormulaExecEvalMode 为 true 时,非 ${ xxx } 格式也会尝试使用表达式运算器
|
178
|
+
if (OpenFormulaExecEvalMode && /^[0-9a-zA-z_]+$/.test(curValue)) {
|
179
|
+
// 普通字符串类型(非表达式),先试一下从上下文中获取数据
|
180
|
+
const curValueTemp = FormulaExec['var'](curValue, data);
|
181
|
+
// 备注: 其他特殊格式,比如邮箱、日期
|
182
|
+
return curValueTemp ?? curValue;
|
183
|
+
} else if (curValue.startsWith('${') && curValue.endsWith('}')) {
|
184
|
+
// ${ xxx } 格式 使用 formula 运算器
|
185
|
+
return FormulaExec['formula'](curValue, data);
|
186
|
+
} else if (isExpression(test)) {
|
187
|
+
// 表达式格式使用 formula 运算器
|
188
|
+
return FormulaExec['formula'](curValue, data);
|
189
|
+
} else if (/(\${).+(\})/.test(curValue)) {
|
190
|
+
// 包含 ${ xxx } 则使用 tpl 运算器
|
191
|
+
return FormulaExec['tpl'](curValue, data); // 可识别 <% %> 语法
|
192
|
+
} else if (OpenFormulaExecEvalMode) {
|
193
|
+
// 支持 ${} 和 非 ${} 表达式
|
194
|
+
return FormulaExec['evalFormula'](curValue, data);
|
195
|
+
} else {
|
196
|
+
return curValue;
|
197
|
+
}
|
198
|
+
}
|
199
|
+
|
200
|
+
// 用于注册自定义 formulaExec 运算器
|
201
|
+
export function registerFormulaExec(execMode: string, formulaExec: Function) {
|
202
|
+
if (FormulaExec[execMode]) {
|
203
|
+
console.error(
|
204
|
+
`registerFormulaExec: 运算器注册失败,存在同名运算器($(execMode))。`
|
205
|
+
);
|
206
|
+
} else {
|
207
|
+
FormulaExec[execMode] = formulaExec;
|
208
|
+
}
|
209
|
+
}
|
210
|
+
|
211
|
+
// 用于判断是否优先使用value。
|
212
|
+
export function isExpression(expression: any): boolean {
|
213
|
+
if (!isString(expression)) {
|
214
|
+
// 非字符串类型,比如:Object、Array类型、boolean、number类型
|
215
|
+
return false;
|
216
|
+
}
|
217
|
+
// 备注: "\\${xxx}"不作为表达式,至少含一个${xxx}才算是表达式
|
218
|
+
return /(?<!\\)(\${).+(\})/.test(expression);
|
219
|
+
}
|
220
|
+
|
221
|
+
// 用于判断是否需要执行表达式:
|
222
|
+
export function isNeedFormula(
|
223
|
+
expression: any,
|
224
|
+
prevData: {[propName: string]: any},
|
225
|
+
curData: {[propName: string]: any}
|
226
|
+
): boolean {
|
227
|
+
const variables = FormulaExec.collect(expression);
|
228
|
+
return variables.some(
|
229
|
+
(variable: string) =>
|
230
|
+
FormulaExec.var(variable, prevData) !== FormulaExec.var(variable, curData)
|
231
|
+
);
|
232
|
+
}
|
233
|
+
|
234
|
+
// 将 \${xx} 替换成 ${xx}
|
235
|
+
export function replaceExpression(expression: any): any {
|
236
|
+
if (expression && isString(expression) && /(\\)(\${).+(\})/.test(expression)) {
|
237
|
+
return expression.replace(/\\\$\{/g, '${');
|
238
|
+
}
|
239
|
+
return expression;
|
240
|
+
}
|
@@ -0,0 +1,53 @@
|
|
1
|
+
/**
|
2
|
+
* @file 公式语法解析
|
3
|
+
*/
|
4
|
+
|
5
|
+
import {parse} from 'amis-formula';
|
6
|
+
|
7
|
+
function traverseAst(ast: any, iterator: (ast: any) => void) {
|
8
|
+
if (!ast || !ast.type) {
|
9
|
+
return;
|
10
|
+
}
|
11
|
+
|
12
|
+
iterator(ast);
|
13
|
+
|
14
|
+
Object.keys(ast).forEach(key => {
|
15
|
+
const value = ast[key];
|
16
|
+
|
17
|
+
if (Array.isArray(value)) {
|
18
|
+
value.forEach(child => traverseAst(child, iterator));
|
19
|
+
} else {
|
20
|
+
traverseAst(value, iterator);
|
21
|
+
}
|
22
|
+
});
|
23
|
+
}
|
24
|
+
|
25
|
+
// 缓存,用于提升性能
|
26
|
+
const COLLECT_EXPRESSION_CACHE: {[key: string]: Array<string>} = {};
|
27
|
+
|
28
|
+
// 提取表达式中有哪些变量
|
29
|
+
export function collectVariables(strOrAst: string | Object, execMode?: boolean): Array<string> {
|
30
|
+
const variables: Array<string> = [];
|
31
|
+
|
32
|
+
if (typeof strOrAst === 'string' && COLLECT_EXPRESSION_CACHE[strOrAst]) {
|
33
|
+
return COLLECT_EXPRESSION_CACHE[strOrAst];
|
34
|
+
}
|
35
|
+
const ast =
|
36
|
+
typeof strOrAst === 'string'
|
37
|
+
? parse(strOrAst, {
|
38
|
+
evalMode: execMode ?? false
|
39
|
+
})
|
40
|
+
: strOrAst;
|
41
|
+
|
42
|
+
traverseAst(ast, (item: any) => {
|
43
|
+
if (item.type === 'variable') {
|
44
|
+
variables.push(item.name);
|
45
|
+
}
|
46
|
+
});
|
47
|
+
|
48
|
+
if (typeof strOrAst === 'string') {
|
49
|
+
COLLECT_EXPRESSION_CACHE[strOrAst] = variables;
|
50
|
+
}
|
51
|
+
|
52
|
+
return variables;
|
53
|
+
}
|
package/src/utils/helper.ts
CHANGED
@@ -20,7 +20,7 @@ import {
|
|
20
20
|
keyToPath,
|
21
21
|
isPureVariable,
|
22
22
|
resolveVariable,
|
23
|
-
resolveVariableAndFilter
|
23
|
+
resolveVariableAndFilter,
|
24
24
|
} from 'amis-formula';
|
25
25
|
import {isObservable} from 'mobx';
|
26
26
|
|
@@ -1424,6 +1424,7 @@ export function getScrollbarWidth() {
|
|
1424
1424
|
return scrollbarWidth;
|
1425
1425
|
}
|
1426
1426
|
|
1427
|
+
// 后续改用 FormulaExec['formula']
|
1427
1428
|
function resolveValueByName(data: any, name?: string) {
|
1428
1429
|
return isPureVariable(name)
|
1429
1430
|
? resolveVariableAndFilter(name, data)
|
package/src/utils/tpl.ts
CHANGED
@@ -71,6 +71,7 @@ export function evalExpression(expression: string, data?: object): boolean {
|
|
71
71
|
return evalFormula(expression, data);
|
72
72
|
}
|
73
73
|
|
74
|
+
// 后续改用 FormulaExec['js']
|
74
75
|
let debug = false;
|
75
76
|
const idx = expression.indexOf('debugger');
|
76
77
|
if (~idx) {
|
@@ -149,6 +150,7 @@ export function evalJS(js: string, data: object): any {
|
|
149
150
|
}
|
150
151
|
|
151
152
|
[registerBulitin, registerLodash].forEach(fn => {
|
153
|
+
if (!fn) return;
|
152
154
|
const info = fn();
|
153
155
|
|
154
156
|
registerTplEnginer(info.name, {
|