@steedos/service-plugin-amis 2.2.35 → 2.2.38

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.
@@ -0,0 +1,391 @@
1
+ const Tpl = require('../tpl');
2
+ const _ = require('underscore');
3
+ const OMIT_FIELDS = ['created', 'created_by', 'modified', 'modified_by'];
4
+ const Lookup = require('./lookup');
5
+ const AmisFormInputs = [
6
+ 'text',
7
+ 'date',
8
+ 'datetime',
9
+ 'time',
10
+ 'number',
11
+ 'currency',
12
+ 'percent',
13
+ 'password',
14
+ 'url',
15
+ 'email'
16
+ ]
17
+
18
+ function getBaseFields(readonly){
19
+ let calssName = 'm-0';
20
+ if(readonly){
21
+ calssName = `${calssName} slds-form-element_readonly`
22
+ }
23
+ return [
24
+ {
25
+ name: "createdInfo",
26
+ label: "创建人",
27
+ type: "static",
28
+ labelClassName: 'text-left',
29
+ className: calssName,
30
+ tpl: Tpl.getCreatedInfoTpl()
31
+ },
32
+ {
33
+ name: "modifiedInfo",
34
+ label: "修改人",
35
+ type: "static",
36
+ labelClassName: 'text-left',
37
+ className: calssName,
38
+ tpl: Tpl.getModifiedInfoTpl()
39
+ }
40
+ ]
41
+ };
42
+
43
+ function getAmisStaticFieldType(type, readonly){
44
+ if(!readonly){
45
+ if(_.include(AmisFormInputs, type)){
46
+ return `input-${type}`;
47
+ }
48
+ return type;
49
+ }
50
+ if(_.include(['text'], type)){
51
+ return `static-${type}`;
52
+ }else{
53
+ return 'static';
54
+ }
55
+ };
56
+
57
+ function getAmisFieldType(sField){
58
+ switch (sField.type) {
59
+ case 'text':
60
+ return 'text';
61
+ case 'textarea':
62
+ return 'textarea';
63
+ case 'html':
64
+ return 'html';
65
+ case 'select':
66
+ return 'select';
67
+ case 'boolean':
68
+ return 'checkbox';
69
+ case 'date':
70
+ return 'date';
71
+ case 'datetime':
72
+ return 'datetime';
73
+ case 'number':
74
+ return 'number';
75
+ case 'currency':
76
+ return 'number';
77
+ case 'percent':
78
+ return 'number'
79
+ case 'password':
80
+ return 'password';
81
+ case 'lookup':
82
+ // TODO 根据字段配置返回 select || picker
83
+ return 'select';
84
+ case 'master_detail':
85
+ // TODO 根据字段配置返回 select || picker
86
+ return 'picker';
87
+ case 'autonumber':
88
+ return 'text';
89
+ case 'url':
90
+ return 'url'
91
+ case 'email':
92
+ return 'email'
93
+ case 'image':
94
+ return 'image'
95
+ case 'formula':
96
+ //TODO
97
+ break;
98
+ case 'summary':
99
+ //TODO
100
+ break;
101
+ case 'grid':
102
+ return 'table';
103
+ default:
104
+ console.log('convertData default', sField.type);
105
+ // convertData.type = field.type
106
+ break;
107
+ }
108
+
109
+ };
110
+
111
+ function getObjectFieldSubFields(mainField, fields){
112
+ const newMainField = Object.assign({subFields: []}, mainField);
113
+ const subFields = _.filter(fields, function(field){
114
+ return field.name.startsWith(`${mainField.name}.`)
115
+ });
116
+ newMainField.subFields = subFields;
117
+ return newMainField;
118
+ }
119
+
120
+ function getGridFieldSubFields(mainField, fields){
121
+ const newMainField = Object.assign({subFields: []}, mainField);
122
+ const subFields = _.filter(fields, function(field){
123
+ return field.name.startsWith(`${mainField.name}.`)
124
+ });
125
+ newMainField.subFields = subFields;
126
+ return newMainField;
127
+ }
128
+
129
+ /**
130
+ * TODO 处理权限
131
+ * @param {*} object steedos object
132
+ * @param {*} userSession
133
+ */
134
+ function getPermissionFields(object, userSession){
135
+ const permissionFields = [];
136
+ const fieldsArr = [];
137
+ _.each(object.fields , (field, field_name)=>{
138
+ if(!_.has(field, "name")){
139
+ field.name = field_name
140
+ }
141
+ fieldsArr.push(field)
142
+ })
143
+ _.each(_.sortBy(fieldsArr, "sort_no"), function(field){
144
+ if(!field.hidden){
145
+ permissionFields.push( Object.assign({}, field, {permission: {allowEdit: true}}))
146
+ }
147
+ })
148
+ return permissionFields;
149
+ }
150
+
151
+
152
+ function getSelectFieldOptions(field){
153
+ const dataType = field.data_type || 'text';
154
+ const options = [];
155
+ _.each(field.options, (item)=>{
156
+ switch (dataType) {
157
+ case 'number':
158
+ options.push({label: item.label, value: Number(item.value)});
159
+ break;
160
+ case 'text':
161
+ options.push({label: item.label, value: String(item.value)});
162
+ break;
163
+ case 'boolean':
164
+ options.push({label: item.label, value: item.value === 'false' ? false : true});
165
+ break;
166
+ default:
167
+ break;
168
+ }
169
+ });
170
+ return options;
171
+ }
172
+
173
+ function convertSFieldToAmisField(field, readonly) {
174
+ // 创建人和修改人、创建时间和修改时间不显示
175
+ if(_.include(OMIT_FIELDS, field.name)){
176
+ return;
177
+ }
178
+ const baseData = {name: field.name, label: field.label, labelRemark: field.inlineHelpText, required: field.required};
179
+ let convertData = {};
180
+ // if(_.include(OMIT_FIELDS, field.name)){
181
+ // readonly = true;
182
+ // }
183
+ switch (field.type) {
184
+ case 'text':
185
+ convertData.type = getAmisStaticFieldType('text', readonly);
186
+ break;
187
+ case 'textarea':
188
+ convertData.type = getAmisStaticFieldType('textarea', readonly);
189
+ convertData.tpl = `<b><%=data.${field.name}%></b>`;
190
+ break;
191
+ case 'html':
192
+ convertData = {
193
+ type: "editor",
194
+ language: "html",
195
+ value: field.defaultValue || ''
196
+ }
197
+ break;
198
+ // convertData = {
199
+ // type: getAmisStaticFieldType('html', readonly)
200
+ // }
201
+ // break;
202
+ case 'select':
203
+ convertData = {
204
+ type: getAmisStaticFieldType('select', readonly),
205
+ joinValues: false,
206
+ options: getSelectFieldOptions(field),
207
+ extractValue: true,
208
+ labelField: 'label',
209
+ valueField: 'value',
210
+ tpl: readonly ? Tpl.getSelectTpl(field) : null
211
+ }
212
+ if(_.has(field, 'defaultValue') && !(_.isString(field.defaultValue) && field.defaultValue.startsWith("{"))){
213
+ const dataType = field.data_type || 'text';
214
+ if(field.defaultValue != null){
215
+ if(dataType === 'text'){
216
+ convertData.value = String(field.defaultValue);
217
+ }else if(dataType === 'number'){
218
+ convertData.value = Number(field.defaultValue);
219
+ }else if(dataType === 'boolean'){
220
+ convertData.value = field.defaultValue === 'false' ? false : true;
221
+ }
222
+ }
223
+ }
224
+ if(field.multiple){
225
+ convertData.multiple = true
226
+ convertData.extractValue = true
227
+ }
228
+ break;
229
+ case 'boolean':
230
+ convertData = {
231
+ type: getAmisStaticFieldType('checkbox', readonly),
232
+ option: field.inlineHelpText,
233
+ tpl: readonly ? Tpl.getSwitchTpl(field) : null
234
+ }
235
+ break;
236
+ case 'date':
237
+ convertData = {
238
+ type: getAmisStaticFieldType('date', readonly),
239
+ inputFormat: "YYYY-MM-DD",
240
+ format:'YYYY-MM-DDT00:00:00.000[Z]',
241
+ tpl: readonly ? Tpl.getDateTpl(field) : null,
242
+ // utc: true
243
+ }
244
+ break;
245
+ case 'datetime':
246
+ convertData = {
247
+ type: getAmisStaticFieldType('datetime', readonly),
248
+ inputFormat: 'YYYY-MM-DD HH:mm',
249
+ format:'YYYY-MM-DDTHH:mm:ss.SSS[Z]',
250
+ tpl: readonly ? Tpl.getDateTimeTpl(field) : null,
251
+ utc: true
252
+ }
253
+ break;
254
+ case 'time':
255
+ convertData = {
256
+ type: getAmisStaticFieldType('time', readonly),
257
+ inputFormat: 'HH:mm',
258
+ timeFormat:'1970-01-01THH:mm:00.000[Z]',
259
+ format:'1970-01-01THH:mm:00.000[Z]',
260
+ tpl: readonly ? Tpl.getDateTimeTpl(field) : null,
261
+ // utc: true
262
+ }
263
+ break;
264
+ case 'number':
265
+ convertData = {
266
+ type: getAmisStaticFieldType('number', readonly),
267
+ min: field.min,
268
+ max: field.max,
269
+ precision: field.scale
270
+ }
271
+ break;
272
+ case 'currency':
273
+ //TODO
274
+ convertData = {
275
+ type: getAmisStaticFieldType('number', readonly),
276
+ min: field.min,
277
+ max: field.max,
278
+ precision: field.scale
279
+ }
280
+ break;
281
+ case 'percent':
282
+ //TODO
283
+ convertData = {
284
+ type: getAmisStaticFieldType('number', readonly),
285
+ min: field.min,
286
+ max: field.max,
287
+ precision: field.scale
288
+ }
289
+ break;
290
+ case 'password':
291
+ convertData = {
292
+ type: getAmisStaticFieldType('password', readonly),
293
+ tpl: readonly ? Tpl.getPasswordTpl(field) : null
294
+ }
295
+ break;
296
+ case 'lookup':
297
+ convertData = Lookup.lookupToAmis(field, readonly)
298
+ break;
299
+ case 'master_detail':
300
+ convertData = Lookup.lookupToAmis(field, readonly)
301
+ break;
302
+ case 'autonumber':
303
+ //TODO
304
+ break;
305
+ case 'url':
306
+ convertData = {
307
+ type: getAmisStaticFieldType('url', readonly)
308
+ }
309
+ break;
310
+ case 'email':
311
+ convertData = {
312
+ type: getAmisStaticFieldType('email', readonly)
313
+ }
314
+ break;
315
+ case 'image':
316
+ //TODO
317
+ break;
318
+ case 'formula':
319
+ //TODO
320
+ break;
321
+ case 'summary':
322
+ //TODO
323
+ break;
324
+ case 'code':
325
+ convertData = {
326
+ type: "editor",
327
+ language: field.language,
328
+ value: field.defaultValue || ''
329
+ }
330
+ break;
331
+ case 'toggle':
332
+ convertData = {
333
+ type: "switch"
334
+ }
335
+ break;
336
+ case 'grid':
337
+ convertData = {
338
+ type: 'input-table',
339
+ strictMode:false,
340
+ affixHeader: false, // 是否固定表头, 不固定表头, 否则form有y轴滚动条时, 表头会跟随滚动条滚动.
341
+ // needConfirm: true, 此属性设置为false后,导致table不能编辑。
342
+ editable: !readonly,
343
+ addable: !readonly,
344
+ removable: !readonly,
345
+ draggable: !readonly,
346
+ columns: []
347
+ }
348
+ _.each(field.subFields, function(subField){
349
+ const subFieldName = subField.name.replace(`${field.name}.$.`, '').replace(`${field.name}.`, '');
350
+ const gridSub = convertSFieldToAmisField(Object.assign({}, subField, {name: subFieldName}), readonly);
351
+ if(gridSub){
352
+ delete gridSub.name
353
+ delete gridSub.label
354
+ convertData.columns.push({
355
+ name: subFieldName,
356
+ label: subField.label,
357
+ quickEdit: readonly ? false : gridSub
358
+ })
359
+ }
360
+ })
361
+ break;
362
+ default:
363
+ // console.log('convertData default', field.type);
364
+ // convertData.type = field.type
365
+ break;
366
+ }
367
+ if(!_.isEmpty(convertData)){
368
+ if(field.is_wide){
369
+ convertData.className = 'col-span-2 m-0';
370
+ }else{
371
+ convertData.className = 'm-0';
372
+ }
373
+ if(readonly){
374
+ convertData.className = `${convertData.className} slds-form-element_readonly`
375
+ }
376
+ convertData.labelClassName = 'text-left';
377
+ if(readonly){
378
+ convertData.quickEdit = false;
379
+ }
380
+ return Object.assign({}, baseData, convertData);
381
+ }
382
+
383
+ }
384
+
385
+ exports.convertSFieldToAmisField = convertSFieldToAmisField;
386
+ exports.getPermissionFields = getPermissionFields;
387
+ exports.getObjectFieldSubFields = getObjectFieldSubFields;
388
+ exports.getGridFieldSubFields = getGridFieldSubFields;
389
+ exports.getAmisStaticFieldType = getAmisStaticFieldType;
390
+ exports.getBaseFields = getBaseFields;
391
+ exports.getAmisFieldType = getAmisFieldType;
@@ -0,0 +1,236 @@
1
+ const _ = require('underscore');
2
+ const objectql = require('@steedos/objectql');
3
+ const steedosI18n = require("@steedos/i18n");
4
+ const graphql = require('../graphql');
5
+ const clone = require('clone');
6
+ const Tpl = require('../tpl');
7
+ const Field = require('./index');
8
+ const Table = require('./table');
9
+
10
+ const getReferenceTo = (field)=>{
11
+ let referenceTo = field.reference_to;
12
+ if(!referenceTo){
13
+ return ;
14
+ }
15
+ if(referenceTo === 'users'){
16
+ referenceTo = 'space_users';
17
+ }
18
+ const refObject = objectql.getObject(referenceTo);
19
+ const refObjectConfig = clone(refObject.toConfig());
20
+ let valueFieldName = field.reference_to_field;
21
+ if(!valueFieldName){
22
+ if(referenceTo === 'space_users'){
23
+ valueFieldName = 'user';
24
+ }else{
25
+ valueFieldName = refObject.key_field || '_id';
26
+ }
27
+ }
28
+ if(valueFieldName === '_id'){
29
+ valueField = {name: '_id', label: 'ID', type: 'text', toggled: false};
30
+ }else{
31
+ valueField = refObjectConfig.fields[valueFieldName];
32
+ }
33
+ return {
34
+ objectName: referenceTo,
35
+ valueField: valueField,
36
+ labelField: refObjectConfig.fields[refObject.NAME_FIELD_KEY || 'name']
37
+ }
38
+ }
39
+
40
+
41
+ function lookupToAmisPicker(field, readonly){
42
+ let referenceTo = getReferenceTo(field);
43
+ if(!referenceTo){
44
+ return ;
45
+ }
46
+ const refObject = objectql.getObject(referenceTo.objectName);
47
+ const refObjectConfig = clone(refObject.toConfig());
48
+ steedosI18n.translationObject('zh-CN', refObjectConfig.name, refObjectConfig)
49
+ const tableFields = [referenceTo.valueField];
50
+ let i = 0;
51
+ const searchableFields = [];
52
+ _.each(refObjectConfig.fields,function(field){
53
+ if(i < 5){
54
+ if(!_.find(tableFields, function(f){
55
+ return f.name === field.name
56
+ })){
57
+ i++;
58
+ tableFields.push(field)
59
+ if(field.searchable){
60
+ searchableFields.push(field.name);
61
+ }
62
+ }
63
+ }
64
+ });
65
+
66
+ const fields = {
67
+ [referenceTo.labelField.name]: referenceTo.labelField,
68
+ [referenceTo.valueField.name]: referenceTo.valueField
69
+ };
70
+
71
+ _.each(tableFields, (tableField)=>{
72
+ fields[tableField.name] = tableField;
73
+ });
74
+
75
+ const source = getApi({
76
+ name: referenceTo.objectName
77
+ }, null, fields, {alias: 'rows', queryOptions: `filters: {__filters}, top: {__top}, skip: {__skip}, sort: "{__sort}"`});
78
+ source.data.$term = "$term";
79
+ source.data.$self = "$$";
80
+
81
+ source.requestAdaptor = `
82
+ const selfData = JSON.parse(JSON.stringify(api.data.$self));
83
+ var filters = [];
84
+ var pageSize = api.data.pageSize || 10;
85
+ var pageNo = api.data.pageNo || 1;
86
+ var skip = (pageNo - 1) * pageSize;
87
+ var orderBy = api.data.orderBy || '';
88
+ var orderDir = api.data.orderDir || '';
89
+ var sort = orderBy + ' ' + orderDir;
90
+ var allowSearchFields = ${JSON.stringify(searchableFields)};
91
+ if(api.data.$term){
92
+ filters = [["name", "contains", "'+ api.data.$term +'"]];
93
+ }else if(selfData.op === 'loadOptions' && selfData.value){
94
+ filters = [["${valueField}", "=", selfData.value]];
95
+ }
96
+ if(allowSearchFields){
97
+ allowSearchFields.forEach(function(key){
98
+ const keyValue = selfData[key];
99
+ if(keyValue){
100
+ filters.push([key, "contains", keyValue]);
101
+ }
102
+ })
103
+ }
104
+ api.data.query = api.data.query.replaceAll('{__filters}', JSON.stringify(filters)).replace('{__top}', pageSize).replace('{__skip}', skip).replace('{__sort}', sort.trim());
105
+ return api;
106
+ `
107
+
108
+ let top = 50;
109
+
110
+ if(refObjectConfig.paging && refObjectConfig.paging.enabled === false){
111
+ top = 1000;
112
+ };
113
+
114
+ const data = {
115
+ type: Field.getAmisStaticFieldType('picker', readonly),
116
+ labelField: referenceTo.labelField.name,
117
+ valueField: referenceTo.valueField.name,
118
+ modalMode: 'dialog', //TODO 设置 dialog 或者 drawer,用来配置弹出方式
119
+ source: source,
120
+ size: "lg",
121
+ pickerSchema: Table.getTableSchema(tableFields, {
122
+ top: top
123
+ }),
124
+ joinValues: false
125
+ }
126
+ if(field.multiple){
127
+ data.multiple = true
128
+ data.extractValue = true
129
+ }
130
+
131
+ if(readonly){
132
+ data.tpl = Tpl.getLookupTpl(field)
133
+ }
134
+
135
+ return data;
136
+ }
137
+
138
+ function lookupToAmisSelect(field, readonly){
139
+ let referenceTo = getReferenceTo(field);
140
+
141
+ let apiInfo;
142
+
143
+ if(referenceTo){
144
+ apiInfo = getApi({
145
+ name: referenceTo.objectName
146
+ }, null, {
147
+ [referenceTo.labelField.name]: referenceTo.labelField,
148
+ [referenceTo.valueField.name]: referenceTo.valueField
149
+ }, {alias: 'options', queryOptions: `filters: {__filters}, top: {__top}`})
150
+ }else{
151
+ apiInfo = {
152
+ method: "post",
153
+ url: graphql.getApi(),
154
+ data: {query: '{objects(filters: ["_id", "=", "-1"]){_id}}', $: "$$"}
155
+ }
156
+ }
157
+
158
+
159
+ apiInfo.data.$term = "$term";
160
+ apiInfo.data.$value = `$${field.name}.${referenceTo ? referenceTo.valueField.name : '_id'}`;
161
+ _.each(field.depend_on, function(fName){
162
+ apiInfo.data[fName] = `$${fName}`;
163
+ })
164
+ apiInfo.data['$'] = `$$`;
165
+ apiInfo.data['rfield'] = `\${object_name}`;
166
+ // [["_id", "=", "$${field.name}._id"],"or",["name", "contains", "$term"]]
167
+ apiInfo.requestAdaptor = `
168
+ var filters = '[]';
169
+ var top = 10;
170
+ if(api.data.$term){
171
+ filters = '["name", "contains", "'+ api.data.$term +'"]';
172
+ }else if(api.data.$value){
173
+ filters = '["_id", "=", "'+ api.data.$value +'"]';
174
+ }
175
+ api.data.query = api.data.query.replaceAll('{__filters}', filters).replace('{__top}', top);
176
+ return api;
177
+ `
178
+ let labelField = referenceTo ? referenceTo.labelField.name : '';
179
+ let valueField = referenceTo ? referenceTo.valueField.name : '';
180
+ if(field._optionsFunction){
181
+ apiInfo.adaptor = `
182
+ payload.data.options = eval(${field._optionsFunction})(api.data);
183
+ return payload;
184
+ `
185
+ labelField = 'label';
186
+ valueField = 'value';
187
+ }
188
+
189
+ const data = {
190
+ type: Field.getAmisStaticFieldType('select', readonly),
191
+ joinValues: false,
192
+ extractValue: true,
193
+ labelField: labelField,
194
+ valueField: valueField,
195
+ autoComplete: apiInfo,
196
+ }
197
+ if(_.has(field, 'defaultValue') && !(_.isString(field.defaultValue) && field.defaultValue.startsWith("{"))){
198
+ data.value = field.defaultValue
199
+ }
200
+ if(field.multiple){
201
+ data.multiple = true
202
+ data.extractValue = true
203
+ }
204
+
205
+ if(readonly){
206
+ data.tpl = Tpl.getLookupTpl(field)
207
+ }
208
+
209
+ return data;
210
+ }
211
+
212
+ function getApi(object, recordId, fields, options){
213
+ return {
214
+ method: "post",
215
+ url: graphql.getApi(),
216
+ data: graphql.getFindQuery(object, recordId, fields, Object.assign(options, {expand: false}))
217
+ }
218
+ }
219
+
220
+ exports.lookupToAmis = (field, readonly)=>{
221
+ let referenceTo = getReferenceTo(field);
222
+ if(!referenceTo){
223
+ return lookupToAmisSelect(field, readonly);
224
+ }
225
+ const refObject = objectql.getObject(referenceTo.objectName);
226
+
227
+ // 此处不参考 steedos 的 enable_enhanced_lookup 规则. 如果默认是开启弹出选择,用户选择过程操作太繁琐, 所以默认是关闭弹出选择.
228
+ if(refObject.enable_enhanced_lookup == true){
229
+ return lookupToAmisPicker(field, readonly);
230
+ }else{
231
+ return lookupToAmisSelect(field, readonly);
232
+ }
233
+ }
234
+
235
+ exports.lookupToAmisPicker = lookupToAmisPicker;
236
+ exports.lookupToAmisSelect = lookupToAmisSelect;