@steedos/service-plugin-amis 2.3.0-beta.8 → 2.3.0

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.
@@ -47,6 +47,24 @@ module.exports = {
47
47
  async handler(ctx) {
48
48
  return await this.getObjects(ctx);
49
49
  }
50
+ },
51
+ getRelatedObjects: {
52
+ rest: {
53
+ method: "GET",
54
+ path: "/related_objects/:objectName"
55
+ },
56
+ async handler(ctx) {
57
+ return await this.getRelatedObjects(ctx);
58
+ }
59
+ },
60
+ getObject: {
61
+ rest: {
62
+ method: "GET",
63
+ path: "/object/:objectName"
64
+ },
65
+ async handler(ctx) {
66
+ return await this.getObject(ctx);
67
+ }
50
68
  }
51
69
  },
52
70
 
@@ -82,6 +100,145 @@ module.exports = {
82
100
 
83
101
  const dbListViews = await objectql.getObject('object_listviews').directFind({filters: [['shared', '!=', false]]})
84
102
 
103
+ _.each(objects, (object)=>{
104
+ if(object && object.name){
105
+
106
+ steedosI18n.translationObject(lng, object.name, object)
107
+
108
+ if(object.list_views && !_.isEmpty(object.list_views)){
109
+ _.each(object.list_views, (list_view, name)=>{
110
+ list_view.name = name;
111
+ list_view._id = list_view._id || list_view.name;
112
+ list_view.label = list_view.label || list_view.name;
113
+ })
114
+
115
+ object.list_views = objectql.getSteedosSchema().metadataDriver.find(_.values(object.list_views), {
116
+ projection: {
117
+ _id: 1,
118
+ name: 1,
119
+ label: 1
120
+ }
121
+ }, spaceId);
122
+
123
+ }
124
+
125
+ if(_.isEmpty(object.list_views)){
126
+ object.list_views = [];
127
+ }
128
+
129
+ const objectListViews = objectql.getSteedosSchema().metadataDriver.find(dbListViews, {
130
+ filters: [['object_name', '=', object.name], ['shared', '=', true] ],
131
+ fields: "_id, name, label"
132
+ }, spaceId);
133
+
134
+ _.each(object.list_views, (listView)=>{
135
+ if(!_.find(objectListViews, (dbListView)=>{ return dbListView.name === listView.name})){
136
+ objectListViews.push(listView);
137
+ }
138
+ })
139
+ object.list_views = objectListViews;
140
+ }
141
+ })
142
+ return objects;
143
+ }
144
+ },
145
+ /* 复制getObjects函数根据objectName筛选下单独的对象信息 */
146
+ getObject: {
147
+ async handler(ctx) {
148
+ const objectName = ctx.params.objectName;
149
+ const userSession = ctx.meta.user;
150
+ const lng = userSession.language || 'zh-CN';
151
+ const spaceId = userSession.spaceId;
152
+ const allMetadataObjects = await objectql.getSteedosSchema().getAllObject();
153
+ const allObjects = _.pluck(clone(allMetadataObjects), 'metadata');
154
+
155
+ const query = {
156
+ filters: [ ['hidden', '!=', true] , ['name', '<>', ExcludeObjectNames]],
157
+ projection: {
158
+ name: 1,
159
+ label: 1,
160
+ list_views: 1
161
+ }
162
+ };
163
+
164
+ const objects = objectql.getSteedosSchema().metadataDriver.find(allObjects, query, spaceId);
165
+
166
+ const dbListViews = await objectql.getObject('object_listviews').directFind({filters: [['shared', '!=', false]]})
167
+
168
+ _.each(objects, (object)=>{
169
+ if(object && object.name){
170
+
171
+ steedosI18n.translationObject(lng, object.name, object)
172
+
173
+ if(object.list_views && !_.isEmpty(object.list_views)){
174
+ _.each(object.list_views, (list_view, name)=>{
175
+ list_view.name = name;
176
+ list_view._id = list_view._id || list_view.name;
177
+ list_view.label = list_view.label || list_view.name;
178
+ })
179
+
180
+ object.list_views = objectql.getSteedosSchema().metadataDriver.find(_.values(object.list_views), {
181
+ projection: {
182
+ _id: 1,
183
+ name: 1,
184
+ label: 1
185
+ }
186
+ }, spaceId);
187
+
188
+ }
189
+
190
+ if(_.isEmpty(object.list_views)){
191
+ object.list_views = [];
192
+ }
193
+
194
+ const objectListViews = objectql.getSteedosSchema().metadataDriver.find(dbListViews, {
195
+ filters: [['object_name', '=', object.name], ['shared', '=', true] ],
196
+ fields: "_id, name, label"
197
+ }, spaceId);
198
+
199
+ _.each(object.list_views, (listView)=>{
200
+ if(!_.find(objectListViews, (dbListView)=>{ return dbListView.name === listView.name})){
201
+ objectListViews.push(listView);
202
+ }
203
+ })
204
+ object.list_views = objectListViews;
205
+ }
206
+ })
207
+ const object = objects.find(function (obj) {
208
+ return obj.name === objectName;
209
+ });
210
+ return object;
211
+ }
212
+ },
213
+ getRelatedObjects: {
214
+ async handler(ctx) {
215
+ const objectName = ctx.params.objectName;
216
+ const userSession = ctx.meta.user;
217
+ const lng = userSession.language || 'zh-CN';
218
+ const spaceId = userSession.spaceId;
219
+ const allMetadataObjects = await objectql.getSteedosSchema().getAllObject();
220
+ const allObjects = _.pluck(clone(allMetadataObjects), 'metadata');
221
+
222
+ const query = {
223
+ filters: [ ['hidden', '!=', true] , ['name', '<>', ExcludeObjectNames]],
224
+ projection: {
225
+ name: 1,
226
+ label: 1,
227
+ list_views: 1,
228
+ fields: 1
229
+ }
230
+ };
231
+
232
+ let objects = objectql.getSteedosSchema().metadataDriver.find(allObjects, query, spaceId);
233
+ objects = objects.filter(function(object){
234
+ let relatedFieldKey = _.findKey(object.fields, function(field){
235
+ return (field.type === "lookup" || field.type === "master_detail") && field.reference_to === objectName;
236
+ });
237
+ return !!relatedFieldKey;
238
+ });
239
+
240
+ const dbListViews = await objectql.getObject('object_listviews').directFind({filters: [['shared', '!=', false]]})
241
+
85
242
  _.each(objects, (object)=>{
86
243
  if(object && object.name){
87
244
 
@@ -169,6 +169,88 @@ const getFieldOperators = (type, lng)=>{
169
169
 
170
170
  }
171
171
 
172
+ const getField = (objectName, fieldName, type, lng)=>{
173
+ let field = null;
174
+ switch (type) {
175
+ case 'textarea':
176
+ case 'autonumber':
177
+ case 'url':
178
+ case 'email':
179
+ case 'text':
180
+ field = {
181
+ type: 'text',
182
+ operators: getFieldOperators('text', lng)
183
+ };
184
+ break;
185
+ case 'percent':
186
+ case 'currency':
187
+ case 'number':
188
+ field = {
189
+ type: 'number',
190
+ operators: getFieldOperators('number', lng)
191
+ };
192
+ break;
193
+ // 以下date 、datetime、time 不能作为amis 表单项的格式 . filters 对此格式做个特殊兼容,
194
+ case 'date':
195
+ // 华炎魔方中日期字段存的是utc的0点
196
+ field = {
197
+ type: "date",
198
+ format: "YYYY-MM-DDT00:00:00+00:00",
199
+ operators: getFieldOperators("date", lng)
200
+ };
201
+ break;
202
+ case 'datetime':
203
+ // 即amis中日期时间控件的format默认值为"YYYY-MM-DDTHH:mm+08:00"正好满足需求
204
+ field = {
205
+ type: "datetime",
206
+ operators: getFieldOperators("datetime", lng)
207
+ };
208
+ break;
209
+ case 'time':
210
+ // 华炎魔方中时间字段存的是1970-01-01的utc时间
211
+ field = {
212
+ type: "time",
213
+ format: "1970-01-01THH:mm+00:00",
214
+ operators: getFieldOperators("time", lng)
215
+ };
216
+ break;
217
+ case 'lookup':
218
+ case 'master_detail':
219
+ case 'select':
220
+ field = {
221
+ type: 'select',
222
+ source: {
223
+ "method": "get",
224
+ "url": "${context.rootUrl}" + `/service/api/amis-metadata-listviews/getSelectFieldOptions?objectName=${objectName}&fieldName=${fieldName}`,
225
+ "dataType": "json",
226
+ "headers": {
227
+ "Authorization": "Bearer ${context.tenantId},${context.authToken}"
228
+ }
229
+ }
230
+ ,
231
+ searchable: true,
232
+ operators: getFieldOperators("select", lng)
233
+ };
234
+ break;
235
+ case 'boolean':
236
+ case 'toggle':
237
+ field = {
238
+ type: "select",
239
+ options: [
240
+ {label: steedosI18n.t("True", {}, lng), value: true},
241
+ {label: steedosI18n.t("False", {}, lng), value: false}
242
+ ],
243
+ operators: [
244
+ "equal",
245
+ "not_equal"
246
+ ]
247
+ };
248
+ default:
249
+ break;
250
+ }
251
+ return field;
252
+ }
253
+
172
254
  module.exports = {
173
255
  name: "amis-metadata-listviews",
174
256
  mixins: [],
@@ -239,89 +321,19 @@ module.exports = {
239
321
  if(!field.hidden && !_.includes(["grid", "object", "[Object]", "[object]", "Object", "markdown", "html"], field.type)){
240
322
  field.label = field.label || field.name
241
323
  switch (field.type) {
242
- case 'text':
243
- fields.push({
244
- label: field.label,
245
- type: field.type,
246
- name: field.name,
247
- operators: getFieldOperators(field.type, lng)
248
- });
249
- break;
250
- case 'currency':
251
- case 'number':
324
+ case 'formula':
252
325
  fields.push({
253
326
  label: field.label,
254
- type: 'number',
255
327
  name: field.name,
256
- operators: getFieldOperators('number', lng)
257
- });
328
+ ...getField(objectName, field.name, field.data_type, lng)
329
+ })
258
330
  break;
259
- // 以下date 、datetime、time 不能作为amis 表单项的格式 . filters 对此格式做个特殊兼容,
260
- case 'date':
261
- // 华炎魔方中日期字段存的是utc的0点
262
- fields.push({
263
- label: field.label,
264
- type: field.type,
265
- name: field.name,
266
- format: "YYYY-MM-DDT00:00:00+00:00",
267
- operators: getFieldOperators(field.type, lng)
268
- });
269
- break;
270
- case 'datetime':
271
- // 即amis中日期时间控件的format默认值为"YYYY-MM-DDTHH:mm+08:00"正好满足需求
272
- fields.push({
273
- label: field.label,
274
- type: field.type,
275
- name: field.name,
276
- operators: getFieldOperators(field.type, lng)
277
- });
278
- break;
279
- case 'time':
280
- // 华炎魔方中时间字段存的是1970-01-01的utc时间
281
- fields.push({
282
- label: field.label,
283
- type: field.type,
284
- name: field.name,
285
- format: "1970-01-01THH:mm+00:00",
286
- operators: getFieldOperators(field.type, lng)
287
- });
288
- break;
289
- case 'lookup':
290
- case 'master_detail':
291
- case 'select':
292
- fields.push({
293
- label: field.label,
294
- type: 'select',
295
- name: field.name,
296
- source: {
297
- "method": "get",
298
- "url": "${context.rootUrl}" + `/service/api/amis-metadata-listviews/getSelectFieldOptions?objectName=${objectName}&fieldName=${field.name}`,
299
- "dataType": "json",
300
- "headers": {
301
- "Authorization": "Bearer ${context.tenantId},${context.authToken}"
302
- }
303
- }
304
- ,
305
- searchable: true,
306
- operators: getFieldOperators(field.type, lng)
307
- });
308
- break;
309
- case 'boolean':
310
- case 'toggle':
331
+ default:
311
332
  fields.push({
312
333
  label: field.label,
313
- type: "select",
314
334
  name: field.name,
315
- options: [
316
- {label: steedosI18n.t("True", {}, lng), value: true},
317
- {label: steedosI18n.t("False", {}, lng), value: false}
318
- ],
319
- operators: [
320
- "equal",
321
- "not_equal"
322
- ]
323
- });
324
- default:
335
+ ...getField(objectName, field.name, field.type, lng)
336
+ })
325
337
  break;
326
338
  }
327
339
  }
@@ -343,11 +355,17 @@ module.exports = {
343
355
  if(field.type === 'select'){
344
356
  return field.options;
345
357
  }else if(field.reference_to){
346
- const records = await objectql.getObject(field.reference_to).find({filters: [[]]})
358
+ let referenceTo = field.reference_to;
359
+ let reference_to_field = field.reference_to_field || objectConfig._idFieldName || '_id'
360
+ if(referenceTo === 'users'){
361
+ referenceTo = 'space_users';
362
+ reference_to_field = 'user'
363
+ }
364
+ const records = await objectql.getObject(referenceTo).find({filters: [[]]})
347
365
  return _.map(records, (record)=>{
348
366
  return {
349
367
  label: record[objectConfig._NAME_FIELD_KEY || 'name'],
350
- value: record[objectConfig._idFieldName || '_id']
368
+ value: record[reference_to_field]
351
369
  };
352
370
  })
353
371
  }
@@ -127,6 +127,26 @@ module.exports = {
127
127
 
128
128
  return { status: 0, data: { options } }
129
129
  },
130
+ },
131
+ getObjectsForGenerateTabsOptions: {
132
+ rest: {
133
+ method: "GET",
134
+ path: "/objects/generate_tabs_options"
135
+ },
136
+ async handler(ctx) {
137
+ const options = await this.getObjectsGenerateTabsOptions(ctx);
138
+ return { status: 0, data: { options } }
139
+ }
140
+ },
141
+ generateTabs: {
142
+ rest: {
143
+ method: "POST",
144
+ path: "/objects/generate/tabs"
145
+ },
146
+ async handler(ctx) {
147
+ const result = await this.generateTabs(ctx);
148
+ return { status: 0, data: result }
149
+ }
130
150
  }
131
151
  },
132
152
 
@@ -357,6 +377,123 @@ module.exports = {
357
377
  })
358
378
  return options;
359
379
  }
380
+ },
381
+ getObjectsGenerateTabsOptions: {
382
+ async handler(ctx) {
383
+ const userSession = ctx.meta.user;
384
+ const lng = userSession.language || 'zh-CN';
385
+ const spaceId = userSession.spaceId;
386
+ const objectTabs = await objectql.getObject('tabs').find({filters: [['type', '=', "object"]]});
387
+ const tabObjects = _.map(objectTabs, "object");
388
+ const allMetadataObjects = await objectql.getSteedosSchema().getAllObject();
389
+ const allObjects = _.map(clone(allMetadataObjects), 'metadata');
390
+ const query = {
391
+ filters: [['hidden', '!=', true], ['name', '<>', tabObjects]],
392
+ projection: {
393
+ name: 1,
394
+ label: 1
395
+ }
396
+ };
397
+ // 只列出未找到tabs记录的对象清单
398
+ const objects = objectql.getSteedosSchema().metadataDriver.find(allObjects, query, spaceId);
399
+
400
+ _.each(objects, (object)=>{
401
+ if(object && object.name){
402
+ steedosI18n.translationObject(lng, object.name, object)
403
+ }
404
+ })
405
+ return _.map(objects, (object)=>{
406
+ return {
407
+ value: object.name,
408
+ label: object.label || object.name
409
+ }
410
+ });
411
+ }
412
+ },
413
+ generateTabs: {
414
+ async handler(ctx) {
415
+ let selectedObjects = ctx.params && ctx.params.objects && ctx.params.objects.split(",");
416
+ if(!selectedObjects || !selectedObjects.length){
417
+ return {
418
+ doneCount:0,
419
+ errors: []
420
+ }
421
+ }
422
+ const userSession = ctx.meta.user;
423
+ const lng = userSession.language || 'zh-CN';
424
+ const spaceId = userSession.spaceId;
425
+ const userId = userSession.userId;
426
+ const companyId = userSession.company_id;
427
+ const companyIds = userSession.company_ids;
428
+ const allMetadataObjects = await objectql.getSteedosSchema().getAllObject();
429
+ const allObjects = _.map(clone(allMetadataObjects), 'metadata');
430
+ const query = {
431
+ filters: [['name', 'in', selectedObjects]], //['hidden', '!=', true] ,
432
+ projection: {
433
+ name: 1,
434
+ label: 1
435
+ }
436
+ };
437
+
438
+ const objects = objectql.getSteedosSchema().metadataDriver.find(allObjects, query, spaceId);
439
+
440
+ _.each(objects, (object) => {
441
+ if (object && object.name) {
442
+ steedosI18n.translationObject(lng, object.name, object)
443
+ }
444
+ })
445
+ const errors = [];
446
+ let doneCount = 0;
447
+ for(let i = 0;i < objects.length; i++) {
448
+ const object = objects[i];
449
+ try{
450
+ const existCount = await objectql.getObject('tabs').count({filters: [['object', '=', object.name]]});
451
+ if(existCount > 0){
452
+ return;
453
+ }
454
+ const tabLabel = object.label || object.name;
455
+ const tabName = "object_" + object.name.replace(/__c$/, "");
456
+ const now = new Date();
457
+ const doc = {
458
+ label: tabLabel,
459
+ name: tabName,
460
+ icon: object.icon,
461
+ type: "object",
462
+ mobile: true,
463
+ desktop: true,
464
+ object: object.name,
465
+ space: spaceId,
466
+ owner: userId,
467
+ created_by: userId,
468
+ created: now,
469
+ modified_by: userId,
470
+ modified: now,
471
+ company_id: companyId,
472
+ company_ids: companyIds
473
+ };
474
+ const tab = await objectql.getObject('tabs').insert(doc);
475
+ if(tab && tab._id){
476
+ doneCount++;
477
+ }
478
+ else{
479
+ errors.push({
480
+ object: (object.label || object.name) + `(${object.name})`,
481
+ message: ""
482
+ });
483
+ }
484
+ }
485
+ catch(ex){
486
+ errors.push({
487
+ object: (object.label || object.name) + `(${object.name})`,
488
+ message: ex.message
489
+ });
490
+ }
491
+ };
492
+ return {
493
+ doneCount:doneCount,
494
+ errors: errors
495
+ }
496
+ }
360
497
  }
361
498
  }
362
499
  };