amis 1.8.0-beta.13 → 1.8.0-beta.15

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 (84) hide show
  1. package/lib/WithStore.js +1 -1
  2. package/lib/WithStore.js.map +2 -2
  3. package/lib/components/DatePicker.js +3 -1
  4. package/lib/components/DatePicker.js.map +2 -2
  5. package/lib/components/Tree.js +3 -1
  6. package/lib/components/Tree.js.map +2 -2
  7. package/lib/helper.css +1 -1
  8. package/lib/helper.css.map +1 -1
  9. package/lib/index.js +1 -1
  10. package/lib/renderers/Date.js +6 -1
  11. package/lib/renderers/Date.js.map +2 -2
  12. package/lib/renderers/Form/TreeSelect.js.map +2 -2
  13. package/lib/renderers/Nav.d.ts +21 -20
  14. package/lib/renderers/Nav.js +8 -1
  15. package/lib/renderers/Nav.js.map +2 -2
  16. package/lib/renderers/Page.js +1 -1
  17. package/lib/renderers/Page.js.map +2 -2
  18. package/lib/renderers/Service.js +1 -1
  19. package/lib/renderers/Service.js.map +2 -2
  20. package/lib/renderers/Table/exportExcel.d.ts +6 -0
  21. package/lib/renderers/Table/exportExcel.js +288 -0
  22. package/lib/renderers/Table/exportExcel.js.map +13 -0
  23. package/lib/renderers/Table/index.d.ts +1 -1
  24. package/lib/renderers/Table/index.js +4 -251
  25. package/lib/renderers/Table/index.js.map +2 -2
  26. package/lib/themes/ang-ie11.css +18 -15
  27. package/lib/themes/ang.css +4 -0
  28. package/lib/themes/ang.css.map +1 -1
  29. package/lib/themes/antd-ie11.css +18 -15
  30. package/lib/themes/antd.css +4 -0
  31. package/lib/themes/antd.css.map +1 -1
  32. package/lib/themes/cxd-ie11.css +3 -0
  33. package/lib/themes/cxd.css +4 -0
  34. package/lib/themes/cxd.css.map +1 -1
  35. package/lib/themes/dark-ie11.css +18 -15
  36. package/lib/themes/dark.css +4 -0
  37. package/lib/themes/dark.css.map +1 -1
  38. package/lib/themes/default-ie11.css +3 -0
  39. package/lib/themes/default.css +4 -0
  40. package/lib/themes/default.css.map +1 -1
  41. package/lib/utils/api.js +28 -6
  42. package/lib/utils/api.js.map +2 -2
  43. package/package.json +1 -1
  44. package/scss/_properties.scss +1 -0
  45. package/scss/components/form/_date.scss +1 -0
  46. package/scss/helper/layout/_display.scss +1 -1
  47. package/sdk/ang-ie11.css +19 -15
  48. package/sdk/ang.css +5 -0
  49. package/sdk/antd-ie11.css +19 -15
  50. package/sdk/antd.css +5 -0
  51. package/sdk/barcode.js +51 -51
  52. package/sdk/charts.js +14 -14
  53. package/sdk/codemirror.js +7 -7
  54. package/sdk/color-picker.js +65 -65
  55. package/sdk/cropperjs.js +2 -2
  56. package/sdk/cxd-ie11.css +4 -0
  57. package/sdk/cxd.css +5 -0
  58. package/sdk/dark-ie11.css +19 -15
  59. package/sdk/dark.css +5 -0
  60. package/sdk/exceljs.js +1 -1
  61. package/sdk/helper.css +1 -1
  62. package/sdk/helper.css.map +1 -1
  63. package/sdk/markdown.js +69 -69
  64. package/sdk/papaparse.js +1 -1
  65. package/sdk/renderers/Form/CityDB.js +1 -1
  66. package/sdk/rest.js +17 -17
  67. package/sdk/rich-text.js +62 -62
  68. package/sdk/sdk-ie11.css +4 -0
  69. package/sdk/sdk.css +5 -0
  70. package/sdk/sdk.js +1269 -1267
  71. package/sdk/thirds/hls.js/hls.js +1 -1
  72. package/sdk/thirds/mpegts.js/mpegts.js +1 -1
  73. package/sdk/tinymce.js +57 -57
  74. package/src/WithStore.tsx +1 -1
  75. package/src/components/DatePicker.tsx +2 -1
  76. package/src/components/Tree.tsx +3 -1
  77. package/src/renderers/Date.tsx +14 -1
  78. package/src/renderers/Form/TreeSelect.tsx +15 -12
  79. package/src/renderers/Nav.tsx +7 -1
  80. package/src/renderers/Page.tsx +9 -2
  81. package/src/renderers/Service.tsx +8 -2
  82. package/src/renderers/Table/exportExcel.ts +289 -0
  83. package/src/renderers/Table/index.tsx +5 -252
  84. package/src/utils/api.ts +36 -10
package/src/WithStore.tsx CHANGED
@@ -201,7 +201,7 @@ export function HocStoreFactory(renderer: {
201
201
  store.initData(
202
202
  extendObject(
203
203
  props.data,
204
- store.hasRemoteData
204
+ store.hasRemoteData || store.path === 'page'
205
205
  ? {
206
206
  ...store.data,
207
207
  ...props.data
@@ -371,7 +371,8 @@ export class DatePicker extends React.Component<DateProps, DatePickerState> {
371
371
  value: normalizeValue(props.value, props.format)
372
372
  };
373
373
 
374
- newState.inputValue = newState.value.format(this.props.inputFormat) || '';
374
+ newState.inputValue =
375
+ newState.value?.format(this.props.inputFormat) || '';
375
376
 
376
377
  this.setState(newState);
377
378
  }
@@ -210,7 +210,9 @@ export class TreeSelector extends React.Component<
210
210
 
211
211
  componentDidMount() {
212
212
  const {enableNodePath} = this.props;
213
- this.props.onRef(this)
213
+
214
+ // onRef只有渲染器的情况才会使用
215
+ this.props.onRef?.(this);
214
216
  enableNodePath && this.expandLazyLoadNodes();
215
217
  }
216
218
 
@@ -105,6 +105,8 @@ export class DateField extends React.Component<DateProps, DateState> {
105
105
 
106
106
  const value = getPropValue(this.props);
107
107
 
108
+ // 主要是给 fromNow 用的
109
+ let date;
108
110
  if (value) {
109
111
  let ISODate = moment(value, moment.ISO_8601);
110
112
  let NormalDate = moment(value, valueFormat);
@@ -114,6 +116,10 @@ export class DateField extends React.Component<DateProps, DateState> {
114
116
  : NormalDate.isValid()
115
117
  ? NormalDate.format(format)
116
118
  : false;
119
+
120
+ if (viewValue) {
121
+ date = viewValue as string;
122
+ }
117
123
  }
118
124
 
119
125
  if (fromNow) {
@@ -126,7 +132,14 @@ export class DateField extends React.Component<DateProps, DateState> {
126
132
  viewValue
127
133
  );
128
134
 
129
- return <span className={cx('DateField', className)}>{viewValue}</span>;
135
+ return (
136
+ <span
137
+ className={cx('DateField', className)}
138
+ title={fromNow ? date : undefined}
139
+ >
140
+ {viewValue}
141
+ </span>
142
+ );
130
143
  }
131
144
  }
132
145
 
@@ -18,7 +18,12 @@ import {Api} from '../../types';
18
18
  import {isEffectiveApi} from '../../utils/api';
19
19
  import Spinner from '../../components/Spinner';
20
20
  import ResultBox from '../../components/ResultBox';
21
- import {autobind, getTreeAncestors, isMobile, createObject} from '../../utils/helper';
21
+ import {
22
+ autobind,
23
+ getTreeAncestors,
24
+ isMobile,
25
+ createObject
26
+ } from '../../utils/helper';
22
27
  import {findDOMNode} from 'react-dom';
23
28
  import {normalizeOptions} from '../../components/Select';
24
29
  import {Action} from '../../types';
@@ -127,7 +132,7 @@ export default class TreeSelectControl extends React.Component<
127
132
  pathSeparator: '/'
128
133
  };
129
134
 
130
- treeRef: any
135
+ treeRef: any;
131
136
 
132
137
  container: React.RefObject<HTMLDivElement> = React.createRef();
133
138
 
@@ -417,13 +422,8 @@ export default class TreeSelectControl extends React.Component<
417
422
 
418
423
  @autobind
419
424
  handleResultChange(value: Array<Option>) {
420
- const {
421
- joinValues,
422
- extractValue,
423
- delimiter,
424
- valueField,
425
- multiple
426
- } = this.props;
425
+ const {joinValues, extractValue, delimiter, valueField, multiple} =
426
+ this.props;
427
427
 
428
428
  let newValue: any = Array.isArray(value) ? value.concat() : [];
429
429
 
@@ -452,9 +452,12 @@ export default class TreeSelectControl extends React.Component<
452
452
  async resultChangeEvent(value: any) {
453
453
  const {onChange, dispatchEvent, data} = this.props;
454
454
 
455
- const rendererEvent = await dispatchEvent('change', createObject(data, {
456
- value
457
- }));
455
+ const rendererEvent = await dispatchEvent(
456
+ 'change',
457
+ createObject(data, {
458
+ value
459
+ })
460
+ );
458
461
 
459
462
  if (rendererEvent?.prevented) {
460
463
  return;
@@ -230,6 +230,7 @@ export interface NavigationProps
230
230
  onSelect?: (item: Link) => void | false;
231
231
  onToggle?: (item: Link, forceFold?: boolean) => void;
232
232
  onDragUpdate?: (dropInfo: IDropInfo) => void;
233
+ onOrderChange?: (res: Link[]) => void;
233
234
  togglerClassName?: string;
234
235
  links?: Array<Link>;
235
236
  loading?: boolean;
@@ -858,6 +859,7 @@ const ConditionBuilderWithRemoteOptions = withRemoteConfig({
858
859
  }
859
860
  }
860
861
  this.props.updateConfig(links, 'update');
862
+ this.props.onOrderChange!(links);
861
863
  await this.saveOrder(
862
864
  mapTree(links, (link: Link) => {
863
865
  // 清除内部加的字段
@@ -871,6 +873,10 @@ const ConditionBuilderWithRemoteOptions = withRemoteConfig({
871
873
  );
872
874
  }
873
875
 
876
+ /**
877
+ * @description 在接口存在的时候,调用接口保存排序结果
878
+ * @param links 排序后的结果
879
+ */
874
880
  async saveOrder(links: Links) {
875
881
  const {saveOrderApi, env, data, reload} = this.props;
876
882
  if (saveOrderApi && isEffectiveApi(saveOrderApi)) {
@@ -880,7 +886,7 @@ const ConditionBuilderWithRemoteOptions = withRemoteConfig({
880
886
  {method: 'post'}
881
887
  );
882
888
  reload();
883
- } else {
889
+ } else if (!this.props.onOrderChange) {
884
890
  env.alert('NAV saveOrderApi is required!');
885
891
  }
886
892
  }
@@ -12,7 +12,12 @@ import {
12
12
  FunctionPropertyNames
13
13
  } from '../types';
14
14
  import {filter, evalExpression} from '../utils/tpl';
15
- import {isVisible, autobind, bulkBindFunctions} from '../utils/helper';
15
+ import {
16
+ isVisible,
17
+ autobind,
18
+ bulkBindFunctions,
19
+ isObjectShallowModified
20
+ } from '../utils/helper';
16
21
  import {ScopedContext, IScopedContext} from '../Scoped';
17
22
  import Alert from '../components/Alert2';
18
23
  import {isApiOutdated, isEffectiveApi} from '../utils/api';
@@ -422,7 +427,9 @@ export default class Page extends React.Component<PageProps> {
422
427
  JSON.stringify(props.cssVars) !== JSON.stringify(prevProps.cssVars)
423
428
  ) {
424
429
  this.updateVarStyle();
425
- } else if (props.defaultData !== prevProps.defaultData) {
430
+ } else if (
431
+ isObjectShallowModified(prevProps.defaultData, props.defaultData)
432
+ ) {
426
433
  store.reInitData(props.defaultData);
427
434
  }
428
435
  }
@@ -14,7 +14,13 @@ import {
14
14
  str2AsyncFunction
15
15
  } from '../utils/api';
16
16
  import {Spinner} from '../components';
17
- import {autobind, isEmpty, isVisible, qsstringify} from '../utils/helper';
17
+ import {
18
+ autobind,
19
+ isEmpty,
20
+ isObjectShallowModified,
21
+ isVisible,
22
+ qsstringify
23
+ } from '../utils/helper';
18
24
  import {
19
25
  BaseSchema,
20
26
  SchemaApi,
@@ -185,7 +191,7 @@ export default class Service extends React.Component<ServiceProps> {
185
191
  this.socket = this.fetchWSData(props.ws, store.data);
186
192
  }
187
193
 
188
- if (props.defaultData !== prevProps.defaultData) {
194
+ if (isObjectShallowModified(prevProps.defaultData, props.defaultData)) {
189
195
  store.reInitData(props.defaultData);
190
196
  }
191
197
 
@@ -0,0 +1,289 @@
1
+ /**
2
+ * 导出 Excel 功能
3
+ */
4
+
5
+ import {filter} from '../../utils/tpl';
6
+ import './ColumnToggler';
7
+ import {TableStore} from '../../store/table';
8
+ import {saveAs} from 'file-saver';
9
+ import {getVariable, removeHTMLTag, createObject} from '../../utils/helper';
10
+ import {
11
+ isPureVariable,
12
+ resolveVariableAndFilter
13
+ } from '../../utils/tpl-builtin';
14
+ import {BaseSchema} from '../../Schema';
15
+ import {toDataURL, getImageDimensions} from '../../utils/image';
16
+ import {TplSchema} from '../Tpl';
17
+ import {MappingSchema} from '../Mapping';
18
+ import {getSnapshot} from 'mobx-state-tree';
19
+ import {DateSchema} from '../Date';
20
+ import moment from 'moment';
21
+ import type {TableProps, ExportExcelToolbar} from './index';
22
+
23
+ /**
24
+ * 将 url 转成绝对地址
25
+ */
26
+ const getAbsoluteUrl = (function () {
27
+ let link: HTMLAnchorElement;
28
+ return function (url: string) {
29
+ if (!link) link = document.createElement('a');
30
+ link.href = url;
31
+ return link.href;
32
+ };
33
+ })();
34
+
35
+ export async function exportExcel(
36
+ ExcelJS: any,
37
+ props: TableProps,
38
+ toolbar: ExportExcelToolbar
39
+ ) {
40
+ const {store, env, classnames: cx, translate: __, data} = props;
41
+ let columns = store.filteredColumns || [];
42
+
43
+ let rows = [];
44
+ let tmpStore;
45
+ let filename = 'data';
46
+ // 支持配置 api 远程获取
47
+ if (typeof toolbar === 'object' && toolbar.api) {
48
+ const res = await env.fetcher(toolbar.api, data);
49
+ if (!res.data) {
50
+ env.notify('warning', __('placeholder.noData'));
51
+ return;
52
+ }
53
+ if (Array.isArray(res.data)) {
54
+ rows = res.data;
55
+ } else {
56
+ rows = res.data.rows || res.data.items;
57
+ }
58
+ // 因为很多方法是 store 里的,所以需要构建 store 来处理
59
+ tmpStore = TableStore.create(getSnapshot(store));
60
+ tmpStore.initRows(rows);
61
+ rows = tmpStore.rows;
62
+ } else {
63
+ rows = store.rows;
64
+ }
65
+
66
+ if (typeof toolbar === 'object' && toolbar.filename) {
67
+ filename = filter(toolbar.filename, data, '| raw');
68
+ }
69
+
70
+ if (rows.length === 0) {
71
+ env.notify('warning', __('placeholder.noData'));
72
+ return;
73
+ }
74
+
75
+ const workbook = new ExcelJS.Workbook();
76
+ const worksheet = workbook.addWorksheet('sheet', {
77
+ properties: {defaultColWidth: 15}
78
+ });
79
+ worksheet.views = [{state: 'frozen', xSplit: 0, ySplit: 1}];
80
+
81
+ let exportColumnNames = toolbar.columns;
82
+
83
+ if (isPureVariable(exportColumnNames)) {
84
+ exportColumnNames = resolveVariableAndFilter(
85
+ exportColumnNames,
86
+ data,
87
+ '| raw'
88
+ );
89
+ }
90
+
91
+ // 自定义导出列配置
92
+ if (toolbar.exportColumns && Array.isArray(toolbar.exportColumns)) {
93
+ columns = toolbar.exportColumns;
94
+ }
95
+
96
+ const filteredColumns = exportColumnNames
97
+ ? columns.filter(column => {
98
+ const filterColumnsNames = exportColumnNames!;
99
+ if (column.name && filterColumnsNames.indexOf(column.name) !== -1) {
100
+ return true;
101
+ }
102
+ return false;
103
+ })
104
+ : columns;
105
+
106
+ const firstRowLabels = filteredColumns.map(column => {
107
+ return column.label;
108
+ });
109
+ const firstRow = worksheet.getRow(1);
110
+ firstRow.values = firstRowLabels;
111
+ worksheet.autoFilter = {
112
+ from: {
113
+ row: 1,
114
+ column: 1
115
+ },
116
+ to: {
117
+ row: 1,
118
+ column: firstRowLabels.length
119
+ }
120
+ };
121
+ // 用于 mapping source 的情况
122
+ const remoteMappingCache: any = {};
123
+ // 数据从第二行开始
124
+ let rowIndex = 1;
125
+ for (const row of rows) {
126
+ rowIndex += 1;
127
+ const sheetRow = worksheet.getRow(rowIndex);
128
+ let columIndex = 0;
129
+ for (const column of filteredColumns) {
130
+ columIndex += 1;
131
+ const name = column.name!;
132
+ const value = getVariable(row.data, name);
133
+ if (typeof value === 'undefined' && !(column as TplSchema).tpl) {
134
+ continue;
135
+ }
136
+ // 处理合并单元格
137
+ if (name in row.rowSpans) {
138
+ if (row.rowSpans[name] === 0) {
139
+ continue;
140
+ } else {
141
+ // start row, start column, end row, end column
142
+ worksheet.mergeCells(
143
+ rowIndex,
144
+ columIndex,
145
+ rowIndex + row.rowSpans[name] - 1,
146
+ columIndex
147
+ );
148
+ }
149
+ }
150
+
151
+ const type = (column as BaseSchema).type || 'plain';
152
+ // TODO: 这里很多组件都是拷贝对应渲染的逻辑实现的,导致
153
+ if (type === 'image' && value) {
154
+ try {
155
+ const imageData = await toDataURL(value);
156
+ const imageDimensions = await getImageDimensions(imageData);
157
+ let imageWidth = imageDimensions.width;
158
+ let imageHeight = imageDimensions.height;
159
+ // 限制一下图片高宽
160
+ const imageMaxSize = 100;
161
+ if (imageWidth > imageHeight) {
162
+ if (imageWidth > imageMaxSize) {
163
+ imageHeight = (imageMaxSize * imageHeight) / imageWidth;
164
+ imageWidth = imageMaxSize;
165
+ }
166
+ } else {
167
+ if (imageHeight > imageMaxSize) {
168
+ imageWidth = (imageMaxSize * imageWidth) / imageHeight;
169
+ imageHeight = imageMaxSize;
170
+ }
171
+ }
172
+ const imageMatch = imageData.match(/data:image\/(.*);/);
173
+ let imageExt = 'png';
174
+ if (imageMatch) {
175
+ imageExt = imageMatch[1];
176
+ }
177
+ // 目前 excel 只支持这些格式,所以其它格式直接输出 url
178
+ if (imageExt != 'png' && imageExt != 'jpeg' && imageExt != 'gif') {
179
+ sheetRow.getCell(columIndex).value = value;
180
+ continue;
181
+ }
182
+ const imageId = workbook.addImage({
183
+ base64: imageData,
184
+ extension: imageExt
185
+ });
186
+ const linkURL = getAbsoluteUrl(value);
187
+ worksheet.addImage(imageId, {
188
+ // 这里坐标位置是从 0 开始的,所以要减一
189
+ tl: {col: columIndex - 1, row: rowIndex - 1},
190
+ ext: {
191
+ width: imageWidth,
192
+ height: imageHeight
193
+ },
194
+ hyperlinks: {
195
+ tooltip: linkURL
196
+ }
197
+ });
198
+ } catch (e) {
199
+ console.warn(e.stack);
200
+ }
201
+ } else if (type == 'link') {
202
+ const linkURL = getAbsoluteUrl(value);
203
+ sheetRow.getCell(columIndex).value = {
204
+ text: value,
205
+ hyperlink: linkURL
206
+ };
207
+ } else if (type === 'mapping') {
208
+ // 拷贝自 Mapping.tsx
209
+ let map = (column as MappingSchema).map;
210
+ const source = (column as MappingSchema).source;
211
+ if (source) {
212
+ let sourceValue = source;
213
+ if (isPureVariable(source)) {
214
+ sourceValue = resolveVariableAndFilter(
215
+ source as string,
216
+ data,
217
+ '| raw'
218
+ );
219
+ }
220
+
221
+ const mapKey = JSON.stringify(source);
222
+ if (mapKey in remoteMappingCache) {
223
+ map = remoteMappingCache[mapKey];
224
+ } else {
225
+ const res = await env.fetcher(sourceValue, data);
226
+ if (res.data) {
227
+ remoteMappingCache[mapKey] = res.data;
228
+ map = res.data;
229
+ }
230
+ }
231
+ }
232
+
233
+ if (typeof value !== 'undefined' && map && (map[value] ?? map['*'])) {
234
+ const viewValue =
235
+ map[value] ??
236
+ (value === true && map['1']
237
+ ? map['1']
238
+ : value === false && map['0']
239
+ ? map['0']
240
+ : map['*']); // 兼容平台旧用法:即 value 为 true 时映射 1 ,为 false 时映射 0
241
+ sheetRow.getCell(columIndex).value = removeHTMLTag(viewValue);
242
+ } else {
243
+ sheetRow.getCell(columIndex).value = removeHTMLTag(value);
244
+ }
245
+ } else if (type === 'date') {
246
+ let viewValue;
247
+ const {
248
+ fromNow,
249
+ format = 'YYYY-MM-DD',
250
+ valueFormat = 'X'
251
+ } = column as DateSchema;
252
+ if (value) {
253
+ let ISODate = moment(value, moment.ISO_8601);
254
+ let NormalDate = moment(value, valueFormat);
255
+
256
+ viewValue = ISODate.isValid()
257
+ ? ISODate.format(format)
258
+ : NormalDate.isValid()
259
+ ? NormalDate.format(format)
260
+ : false;
261
+ }
262
+
263
+ if (fromNow) {
264
+ viewValue = moment(value).fromNow();
265
+ }
266
+ if (viewValue) {
267
+ sheetRow.getCell(columIndex).value = viewValue;
268
+ }
269
+ } else {
270
+ if ((column as TplSchema).tpl) {
271
+ sheetRow.getCell(columIndex).value = removeHTMLTag(
272
+ filter((column as TplSchema).tpl, createObject(data, row.data))
273
+ );
274
+ } else {
275
+ sheetRow.getCell(columIndex).value = value;
276
+ }
277
+ }
278
+ }
279
+ }
280
+
281
+ const buffer = await workbook.xlsx.writeBuffer();
282
+
283
+ if (buffer) {
284
+ var blob = new Blob([buffer], {
285
+ type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
286
+ });
287
+ saveAs(blob, filename + '.xlsx');
288
+ }
289
+ }