@steedos/standard-object-database 2.7.9 → 2.7.10-beta.10

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.
@@ -1,4 +1,5 @@
1
1
  name: design_field_layout
2
2
  is_enable: true
3
3
  label: 设计字段布局
4
- 'on': record_only
4
+ 'on': record_more
5
+ sort: 80
@@ -1,5 +1,4 @@
1
1
  name: design_fields_layout
2
2
  is_enable: true
3
- label: 设计对象(Beta)
4
- 'on': record_more
5
- sort: 80
3
+ label: 设计对象
4
+ 'on': record_only
@@ -2,7 +2,7 @@
2
2
  * @Author: baozhoutao@steedos.com
3
3
  * @Date: 2022-06-02 17:45:15
4
4
  * @LastEditors: baozhoutao@steedos.com
5
- * @LastEditTime: 2024-09-11 11:49:37
5
+ * @LastEditTime: 2024-10-10 10:20:19
6
6
  * @Description:
7
7
  -->
8
8
  <html>
@@ -11,6 +11,15 @@
11
11
  <script src="/unpkg.com/axios@0.26.1/dist/axios.min.js"></script>
12
12
  <script src="https://unpkg.steedos.cn/flowbite@2.3.0/dist/flowbite.min.js"></script>
13
13
  <script src="https://cdn.tailwindcss.com"></script>
14
+ <link href="/toast/toastr.min.css" rel="stylesheet" />
15
+ <script src="/jquery.min.js" ></script>
16
+ <script src="/toast/toastr.min.js"></script>
17
+ <style>
18
+ #toast-container.toast-bottom-center>div, #toast-container.toast-top-center>div {
19
+ width: 450px;
20
+ opacity: 1;
21
+ }
22
+ </style>
14
23
  </head>
15
24
 
16
25
  <body>
@@ -185,7 +194,7 @@
185
194
 
186
195
  }
187
196
 
188
- return await axios.post(
197
+ const result = await axios.post(
189
198
  `${rootUrl}/service/api/object_fields/amis/design/schema?oid=${oid}`,
190
199
  {
191
200
  withCredentials: true,
@@ -199,6 +208,43 @@
199
208
  // handle error
200
209
  console.log(error);
201
210
  });
211
+ const actionNames = ['insert', 'update', 'delete'];
212
+
213
+ toastr.options = {
214
+ "closeButton": true,
215
+ "debug": false,
216
+ "newestOnTop": false,
217
+ "progressBar": false,
218
+ "positionClass": "toast-top-center",
219
+ "preventDuplicates": false,
220
+ "onclick": null,
221
+ "showDuration": "300",
222
+ "hideDuration": "1000",
223
+ "timeOut": "5000",
224
+ "extendedTimeOut": "1000",
225
+ "showEasing": "swing",
226
+ "hideEasing": "linear",
227
+ "showMethod": "fadeIn",
228
+ "hideMethod": "fadeOut"
229
+ }
230
+
231
+ actionNames.forEach(function(actionName){
232
+ const actionData = result.data.data[actionName];
233
+ let actionLabel = '';
234
+ if(actionName === 'insert'){
235
+ actionLabel = '新增';
236
+ }else if(actionName === 'update'){
237
+ actionLabel = '更新';
238
+ }else if(actionName === 'delete'){
239
+ actionLabel = '删除';
240
+ }
241
+ if(actionData.error && actionData.error.length > 0){
242
+ actionData.error.forEach((error)=>{
243
+ toastr.warning(error.message, `${actionLabel}字段「${error.fieldLabel}(${error.fieldName})」失败:`);
244
+ })
245
+ }
246
+ })
247
+ return result;
202
248
  };
203
249
  window.addEventListener('message', function (event) {
204
250
  const { data } = event;
@@ -208,6 +254,34 @@
208
254
  onDndAccept: function(event){
209
255
  return true;
210
256
  },
257
+ beforeDelete: function(event){
258
+ const toastConfig = {
259
+ "closeButton": true,
260
+ "debug": false,
261
+ "newestOnTop": false,
262
+ "progressBar": false,
263
+ "positionClass": "toast-top-center",
264
+ "preventDuplicates": false,
265
+ "onclick": null,
266
+ "showDuration": "300",
267
+ "hideDuration": "1000",
268
+ "timeOut": "5000",
269
+ "extendedTimeOut": "1000",
270
+ "showEasing": "swing",
271
+ "hideEasing": "linear",
272
+ "showMethod": "fadeIn",
273
+ "hideMethod": "fadeOut"
274
+ }
275
+ if(event.context.schema.type.startsWith('sfield') && event.context.schema.config.is_system){
276
+ parent.toastr.warning('禁止删除系统字段', '', toastConfig)
277
+ return event.preventDefault();
278
+ };
279
+
280
+ if(event.context.schema.type.startsWith('sfield') && event.context.schema.config.name === 'name'){
281
+ parent.toastr.warning('禁止删除名称字段', '', toastConfig)
282
+ return event.preventDefault();
283
+ }
284
+ },
211
285
  onInit: function(){
212
286
  // 创建一个新的 style 元素
213
287
  var style = document.createElement('style');
@@ -42,7 +42,7 @@ router.get('/api/amisObjectFieldsDesign', core.requireAuthentication, async func
42
42
  } else if (req.query.locale == "zh-cn") {
43
43
  locale = "zh-CN";
44
44
  }
45
- const retUrl = __meteor_runtime_config__.ROOT_URL + '/app/admin/objects/view/' + req.query.oid
45
+ const retUrl = req.query.retUrl || __meteor_runtime_config__.ROOT_URL + '/app/admin/objects/view/' + req.query.oid
46
46
  const steedosBuilderUrl = process.env.STEEDOS_BUILDER_URL || 'https://builder.steedos.cn';
47
47
  const builderHost = `${steedosBuilderUrl}/object?${assetUrl}retUrl=${retUrl}&locale=${locale}&isObjectDesign=1&pType=objectDesign`;
48
48
 
@@ -2,6 +2,7 @@ var _ = require("underscore");
2
2
  var objectql = require('@steedos/objectql');
3
3
  var clone = require('clone');
4
4
  var objectCore = require('./objects.core.js');
5
+ var lodash = require('lodash');
5
6
 
6
7
  const objectFieldsFind = function (filter) {
7
8
  return objectql.wrapAsync(async function () {
@@ -31,7 +32,7 @@ function getFieldName(objectName, fieldName, spaceId, oldFieldName){
31
32
  if(object && object.datasource && object.datasource != 'default'){
32
33
  return fieldName;
33
34
  }else{
34
- if(fieldName != 'name' && fieldName != 'owner'){
35
+ if(!lodash.includes(['name', 'owner', 'created', 'created_by', 'modified', 'modified_by'], fieldName) ){
35
36
  return objectql._makeNewFieldName(fieldName, spaceId, oldFieldName);
36
37
  }else{
37
38
  return fieldName
@@ -470,7 +471,7 @@ var triggers = {
470
471
  }
471
472
 
472
473
  checkName(doc._name);
473
- if(['name','owner','parent','children'].indexOf(doc._name)>-1){
474
+ if(['name','owner','parent','children'].indexOf(doc._name)>-1 || doc._name && doc.is_system){
474
475
  doc.name = doc._name;
475
476
  }else{
476
477
  doc.name = getFieldName(doc.object,doc._name,doc.space);
@@ -322,6 +322,7 @@ let objectTriggers = {
322
322
  object: doc.name,
323
323
  owner: userId,
324
324
  _name: "created",
325
+ name: "created",
325
326
  label: "创建时间",
326
327
  space: doc.space,
327
328
  type: "datetime",
@@ -335,6 +336,7 @@ let objectTriggers = {
335
336
  object: doc.name,
336
337
  owner: userId,
337
338
  _name: "created_by",
339
+ name: "created_by",
338
340
  label: "创建人",
339
341
  space: doc.space,
340
342
  type: "lookup",
@@ -348,6 +350,7 @@ let objectTriggers = {
348
350
  object: doc.name,
349
351
  owner: userId,
350
352
  _name: "modified",
353
+ name: "modified",
351
354
  label: "修改时间",
352
355
  space: doc.space,
353
356
  type: "datetime",
@@ -361,9 +364,9 @@ let objectTriggers = {
361
364
  object: doc.name,
362
365
  owner: userId,
363
366
  _name: "modified_by",
367
+ name: "modified_by",
364
368
  label: "修改人",
365
369
  space: doc.space,
366
- space: doc.space,
367
370
  type: "lookup",
368
371
  reference_to: 'users',
369
372
  group: '',
@@ -315,7 +315,15 @@ module.exports = {
315
315
  _.map(objectFields, (objectField)=>{
316
316
  if(!objectField.group){
317
317
  objectField.group = '通用'
318
- }
318
+ };
319
+ delete objectField.owner;
320
+ delete objectField.space;
321
+ delete objectField.created;
322
+ delete objectField.modified;
323
+ delete objectField.created_by;
324
+ delete objectField.modified_by;
325
+ delete objectField.company_id;
326
+ delete objectField.company_ids;
319
327
  })
320
328
 
321
329
  return {
@@ -326,12 +334,13 @@ module.exports = {
326
334
  data: {
327
335
  objectName
328
336
  },
329
- className: "steedos-amis-form steedos-field-layout-page m-4",
337
+ className: "steedos-amis-form steedos-field-layout-page",
330
338
  body: _.map(_.groupBy(_.orderBy(objectFields, function(o) { return o.sort_no || 100 }), 'group'), (items, groupName)=>{
331
339
  const group = getGroup(groupName)
332
340
  return {
333
341
  type: 'steedos-field-group',
334
342
  title: group.group_name,
343
+ collapsable: true,
335
344
  collapsed: group.collapsed,
336
345
  visible_on: group.visible_on,
337
346
  body: _.map(items, (field)=>{
@@ -376,22 +385,32 @@ module.exports = {
376
385
  return {}
377
386
  }
378
387
  let sort_no = 50;
379
- _.each(schema.body, (group)=>{
380
- if(group.type === 'steedos-field-group'){
381
- const groupName = group.title;
382
- _.each(group.body, (field)=>{
388
+ _.each(schema.body, (bodyItem)=>{
389
+ if(bodyItem.type === 'steedos-field-group'){
390
+ const groupName = bodyItem.title;
391
+ _.each(bodyItem.body, (field)=>{
383
392
  if(_.startsWith(field.type, 'sfield-')){
384
- fields.push(Object.assign({}, field.config, {group: groupName, sort_no, _name: field.name}));
393
+
394
+ if(field.config && field.config.amis){
395
+ delete field.config.amis.name
396
+ delete field.config.amis.mode
397
+ }
398
+
399
+ fields.push(Object.assign({}, field.config, {group: groupName, sort_no, _name: field.config.name}));
385
400
  sort_no += 50;
386
401
  }
387
402
  })
388
403
  groups.push({
389
- group_name: group.title,
390
- collapsed: group.collapsed,
391
- visible_on: group.visible_on
404
+ group_name: bodyItem.title,
405
+ collapsed: bodyItem.collapsed,
406
+ visible_on: bodyItem.visible_on
392
407
  })
393
- }else if(_.startsWith(field.type, 'sfield-')){
394
- fields.push(Object.assign({}, field.config, {sort_no, _name: field.name}));
408
+ }else if(_.startsWith(bodyItem.type, 'sfield-')){
409
+ if(bodyItem.config && bodyItem.config.amis){
410
+ delete bodyItem.config.amis.name
411
+ delete bodyItem.config.amis.mode
412
+ }
413
+ fields.push(Object.assign({}, bodyItem.config, {sort_no, _name: bodyItem.config.name}));
395
414
  sort_no += 50;
396
415
  }
397
416
  })
@@ -423,10 +442,11 @@ module.exports = {
423
442
 
424
443
  // 循环需要增加的字段
425
444
  for (const fieldName of insertFields) {
445
+ const newId = await object_fields._makeNewID();
446
+ const now = new Date();
447
+ const field = _.find(fields, { name: fieldName });
426
448
  try {
427
- const newId = await object_fields._makeNewID();
428
- const now = new Date();
429
- const field = _.find(fields, { name: fieldName });
449
+
430
450
  const doc = Object.assign({}, field, {
431
451
  _id: newId,
432
452
  owner: userSession.userId,
@@ -445,7 +465,11 @@ module.exports = {
445
465
  await object_fields.directInsert(doc);
446
466
  log.insert.success.push(fieldName);
447
467
  } catch (e) {
448
- log.insert.error.push(fieldName);
468
+ log.insert.error.push({
469
+ fieldName: fieldName,
470
+ fieldLabel: field.label,
471
+ message: steedosI18n.t(e.message, null, 'zh-CN')
472
+ });
449
473
  console.error(`新增字段 ${fieldName} 时出错:`, e);
450
474
  }
451
475
  }
@@ -453,32 +477,45 @@ module.exports = {
453
477
  // 循环需要修改的字段
454
478
  const now = new Date();
455
479
  for (const fieldName of updateFields) {
480
+ const field = _.find(fields, { name: fieldName });
456
481
  try {
457
- const field = _.find(fields, { name: fieldName });
458
482
  const id = _.find(dbFields, { name: fieldName })._id;
459
483
  const submitField = _.omit(field, ['name', '_name']);
460
484
 
461
485
  if(submitField.type === "summary"){
462
486
  await initSummaryDoc(submitField);
463
487
  }
488
+ if(submitField){
489
+ delete submitField._id;
490
+ }
464
491
  await object_fields.directUpdate(id, Object.assign({}, submitField, {
465
492
  modified: now,
466
493
  modified_by: userSession.userId
467
494
  }));
468
495
  log.update.success.push(fieldName);
469
496
  } catch (e) {
470
- log.update.error.push(fieldName);
497
+ log.update.error.push({
498
+ fieldName: fieldName,
499
+ fieldLabel: field.label,
500
+ message: steedosI18n.t(e.message, null, 'zh-CN')
501
+ });
471
502
  console.log(`dbFields`, fieldName, dbFields)
472
503
  console.error(`更新字段 ${fieldName} 时出错:`, e);
473
504
  }
474
505
  }
475
506
  // 循环需要删除的字段
476
507
  for (const fieldName of deleteFields) {
508
+ const field = _.find(dbFields, { name: fieldName })._id;
477
509
  try {
478
- const id = _.find(dbFields, { name: fieldName })._id;
510
+ const id = field._id;
479
511
  await object_fields.directDelete(id);
480
512
  log.delete.success.push(fieldName);
481
513
  } catch (e) {
514
+ log.delete.error.push({
515
+ fieldName: fieldName,
516
+ fieldLabel: field.label,
517
+ message: steedosI18n.t(e.message, null, 'zh-CN')
518
+ });
482
519
  log.delete.error.push(fieldName);
483
520
  console.error(`删除字段 ${fieldName} 时出错:`, e);
484
521
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steedos/standard-object-database",
3
- "version": "2.7.9",
3
+ "version": "2.7.10-beta.10",
4
4
  "main": "package.service.js",
5
5
  "private": false,
6
6
  "publishConfig": {
@@ -12,14 +12,14 @@
12
12
  "description": "steedos package",
13
13
  "dependencies": {
14
14
  "@steedos-widgets/amis-lib": "^1.0.22",
15
- "@steedos/metadata-core": "2.7.9",
16
- "@steedos/service-object-mixin": "2.7.9",
17
- "@steedos/standard-objects": "2.7.9",
15
+ "@steedos/metadata-core": "2.7.10-beta.10",
16
+ "@steedos/service-object-mixin": "2.7.10-beta.10",
17
+ "@steedos/standard-objects": "2.7.10-beta.10",
18
18
  "amis-formula": "~6.3.0",
19
19
  "clone": "^2.1.2",
20
20
  "moleculer-bullmq": "3.0.0"
21
21
  },
22
22
  "repository": {},
23
23
  "license": "MIT",
24
- "gitHead": "1ffda098098a1364492288ee0fd94265a7b9225d"
24
+ "gitHead": "cffd1ba851c6e18adcdd8b92f2c20d4d9d76247e"
25
25
  }
@@ -2,7 +2,7 @@
2
2
  * @Author: sunhaolin@hotoa.com
3
3
  * @Date: 1985-10-26 16:15:00
4
4
  * @LastEditors: baozhoutao@steedos.com
5
- * @LastEditTime: 2024-03-20 14:30:13
5
+ * @LastEditTime: 2024-10-10 15:58:37
6
6
  * @Description:
7
7
  */
8
8
  "use strict";
@@ -14,6 +14,10 @@ const validator = require('validator');
14
14
  const triggers = require('./src/triggers');
15
15
  const { checkAPIName } = require('@steedos/standard-objects').util
16
16
 
17
+ const { customAlphabet } = require('nanoid');
18
+ const { group } = require('console');
19
+ const nanoid = customAlphabet('1234567890abcdef', 10)
20
+
17
21
  /**
18
22
  * @typedef {import('moleculer').Context} Context Moleculer's Context
19
23
  */
@@ -133,6 +137,475 @@ module.exports = {
133
137
  await checkAPIName(objectName, fieldName, fieldValue, recordId, filters)
134
138
  }
135
139
  },
140
+ create_object: {
141
+ rest: {
142
+ method: "POST",
143
+ fullPath: "/service/api/objects/create_by_design"
144
+ },
145
+ async handler(ctx) {
146
+ const { appId, groupId, name, label, icon } = ctx.params;
147
+ const userSession = ctx.meta.user;
148
+
149
+ if(!appId){
150
+ return;
151
+ }
152
+
153
+ const records = await this.getObject('apps').find({
154
+ filters: ['code', '=', appId]
155
+ });
156
+ const app = records.length > 0 ? records[0] : null;
157
+
158
+ if(!app){
159
+ return ;
160
+ }
161
+
162
+ // 1 创建对象
163
+ const obj = await this.getObject('objects').insert({
164
+ name: name || `o_${nanoid(5)}`,
165
+ label: label || '未命名对象',
166
+ datasource: 'default',
167
+ icon: icon || 'account'
168
+ }, userSession);
169
+
170
+
171
+ const tab_items = app.tab_items || {};
172
+ tab_items[`object_${obj.name.replace(/__c$/, "")}`] = {
173
+ group: groupId
174
+ }
175
+
176
+ await this.getObject('apps').update(app._id, {
177
+ tab_items
178
+ }, userSession);
179
+
180
+ return obj;
181
+ }
182
+ },
183
+ create_app_group: {
184
+ rest: {
185
+ method: "POST",
186
+ fullPath: "/service/api/apps/create_app_group_by_design"
187
+ },
188
+ async handler(ctx) {
189
+ const { appId, name, defaultOpen, oldName } = ctx.params;
190
+ const userSession = ctx.meta.user;
191
+
192
+ if(!appId){
193
+ return {};
194
+ }
195
+
196
+ const records = await this.getObject('apps').find({
197
+ filters: ['code', '=', appId]
198
+ });
199
+ const app = records.length > 0 ? records[0] : null;
200
+
201
+ if(!app){
202
+ return {};
203
+ }
204
+
205
+ await this.getObject('apps').update(app._id, {
206
+ $push: {
207
+ tab_groups: {
208
+ group_name: name,
209
+ default_open: defaultOpen
210
+ }
211
+ }
212
+ }, userSession);
213
+
214
+ return {};
215
+ }
216
+ },
217
+ update_app_group: {
218
+ rest: {
219
+ method: "POST",
220
+ fullPath: "/service/api/apps/update_app_group_by_design"
221
+ },
222
+ async handler(ctx) {
223
+ const { appId, name, defaultOpen, oldName } = ctx.params;
224
+ const userSession = ctx.meta.user;
225
+
226
+ if(!oldName){
227
+ return {}
228
+ }
229
+
230
+ if(!appId){
231
+ return {};
232
+ }
233
+
234
+ const records = await this.getObject('apps').find({
235
+ filters: ['code', '=', appId]
236
+ });
237
+ const app = records.length > 0 ? records[0] : null;
238
+
239
+ if(!app){
240
+ return {};
241
+ };
242
+
243
+ const tab_groups = app.tab_groups;
244
+
245
+ const tab_items = app.tab_items;
246
+
247
+ _.each(tab_groups, (tGroup)=>{
248
+ if(tGroup.group_name == oldName){
249
+ tGroup.group_name = name;
250
+ tGroup.default_open = defaultOpen
251
+ }
252
+ });
253
+
254
+
255
+ _.each(tab_items, (tItem, key)=>{
256
+ if(tItem.group === oldName){
257
+ tab_items[key] = {
258
+ group: name
259
+ }
260
+ }
261
+ })
262
+
263
+ await this.getObject('apps').update(app._id, {
264
+ tab_groups, tab_items
265
+ }, userSession);
266
+
267
+ return {};
268
+ }
269
+ },
270
+ create_by_design: {
271
+ rest: {
272
+ method: "POST",
273
+ fullPath: "/service/api/apps/create_by_design"
274
+ },
275
+ async handler(ctx) {
276
+ const { code, name, icon } = ctx.params;
277
+ const userSession = ctx.meta.user;
278
+
279
+ if(!code || !name){
280
+ return {};
281
+ }
282
+
283
+ return await this.getObject('apps').insert({
284
+ name: name,
285
+ code: code,
286
+ sort : 9100,
287
+ is_creator : true,
288
+ mobile : true,
289
+ visible : true,
290
+ showSidebar : true,
291
+ icon_slds : icon || "account",
292
+ }, userSession);
293
+ }
294
+ },
295
+ update_app_by_design: {
296
+ rest: {
297
+ method: "POST",
298
+ fullPath: "/service/api/apps/update_app_by_design"
299
+ },
300
+ async handler(ctx) {
301
+ const { appId, tab_groups, tab_items } = ctx.params;
302
+ const userSession = ctx.meta.user;
303
+
304
+ if(!appId){
305
+ return {};
306
+ }
307
+
308
+ const records = await this.getObject('apps').find({
309
+ filters: ['code', '=', appId]
310
+ });
311
+ const app = records.length > 0 ? records[0] : null;
312
+
313
+ if(!app){
314
+ return {};
315
+ }
316
+
317
+ await this.getObject('apps').update(app._id, {
318
+ tab_groups: tab_groups,
319
+ tab_items: tab_items
320
+ }, userSession);
321
+
322
+ }
323
+ },
324
+ update_app_tabs_by_design: {
325
+ rest: {
326
+ method: "POST",
327
+ fullPath: "/service/api/apps/update_app_tabs_by_design"
328
+ },
329
+ async handler(ctx) {
330
+ const { appId, addTabNames, groupId } = ctx.params;
331
+ const userSession = ctx.meta.user;
332
+
333
+ if(!appId){
334
+ return {};
335
+ }
336
+
337
+ const records = await this.getObject('apps').find({
338
+ filters: ['code', '=', appId]
339
+ });
340
+ const app = records.length > 0 ? records[0] : null;
341
+
342
+ if(!app){
343
+ return {};
344
+ }
345
+
346
+ const tab_items = app.tab_items || {};
347
+
348
+ _.each(addTabNames, (tabName)=>{
349
+ if(tabName){
350
+ tab_items[tabName] = {
351
+ group: groupId
352
+ }
353
+ }
354
+ })
355
+
356
+ await this.getObject('apps').update(app._id, {
357
+ tab_items
358
+ }, userSession);
359
+
360
+ }
361
+ },
362
+ create_link_tab_by_design: {
363
+ rest: {
364
+ method: "POST",
365
+ fullPath: "/service/api/tabs/create_link_tab_by_design"
366
+ },
367
+ async handler(ctx) {
368
+ const { appId, groupId, name, label, icon, url } = ctx.params;
369
+ const userSession = ctx.meta.user;
370
+
371
+ if(!appId){
372
+ return;
373
+ }
374
+
375
+ const records = await this.getObject('apps').find({
376
+ filters: ['code', '=', appId]
377
+ });
378
+ const app = records.length > 0 ? records[0] : null;
379
+
380
+ if(!app){
381
+ return ;
382
+ }
383
+
384
+ const tab = await this.getObject('tabs').insert({
385
+ name: name || `t_${nanoid(5)}`,
386
+ label: label || '未命名选项卡',
387
+ icon: icon || 'account',
388
+ mobile : true,
389
+ desktop : true,
390
+ is_new_window : false,
391
+ is_use_iframe : true,
392
+ type : "url",
393
+ url : url,
394
+ }, userSession);
395
+
396
+
397
+ const tab_items = app.tab_items || {};
398
+ tab_items[tab.name] = {
399
+ group: groupId
400
+ }
401
+ await this.getObject('apps').update(app._id, {
402
+ tab_items
403
+ }, userSession);
404
+
405
+ return tab;
406
+ }
407
+ },
408
+ update_link_tab_by_design: {
409
+ rest: {
410
+ method: "POST",
411
+ fullPath: "/service/api/tabs/update_link_tab_by_design"
412
+ },
413
+ async handler(ctx) {
414
+ const { appId, groupId, name, label, icon, url } = ctx.params;
415
+ const userSession = ctx.meta.user;
416
+
417
+ if(!appId){
418
+ return;
419
+ }
420
+
421
+ const records = await this.getObject('apps').find({
422
+ filters: ['code', '=', appId]
423
+ });
424
+ const app = records.length > 0 ? records[0] : null;
425
+
426
+ if(!app){
427
+ return ;
428
+ }
429
+
430
+ const dbTab = await this.getObject('tabs').find({
431
+ filters: ['name', '=', name]
432
+ }, userSession);
433
+
434
+ if(dbTab.length > 0){
435
+ const tab = await this.getObject('tabs').update(dbTab[0]._id, {
436
+ name: name,
437
+ label: label,
438
+ icon: icon,
439
+ url : url,
440
+ }, userSession);
441
+ return tab;
442
+ }
443
+ return dbTab;
444
+ }
445
+ },
446
+ create_page_by_design: {
447
+ rest: {
448
+ method: "POST",
449
+ fullPath: "/service/api/pages/create_page_by_design"
450
+ },
451
+ async handler(ctx) {
452
+ const { appId, groupId, name, label, icon } = ctx.params;
453
+ const userSession = ctx.meta.user;
454
+
455
+ if(!appId){
456
+ return;
457
+ }
458
+
459
+ const records = await this.getObject('apps').find({
460
+ filters: ['code', '=', appId]
461
+ });
462
+ const app = records.length > 0 ? records[0] : null;
463
+
464
+ if(!app){
465
+ return ;
466
+ }
467
+
468
+ const page = await this.getObject('pages').insert({
469
+ name: name || `t_${nanoid(5)}`,
470
+ label : label,
471
+ is_active : true,
472
+ render_engine : "amis",
473
+ type : "app"
474
+ }, userSession);
475
+
476
+ const tab = await this.getObject('tabs').insert({
477
+ name: `page_${page.name}`,
478
+ mobile : true,
479
+ desktop : true,
480
+ is_new_window : false,
481
+ is_use_iframe : false,
482
+ icon : icon,
483
+ type : "page",
484
+ label : label,
485
+ page : page.name,
486
+ }, userSession);
487
+
488
+
489
+ const tab_items = app.tab_items || {};
490
+ tab_items[tab.name] = {
491
+ group: groupId
492
+ }
493
+ await this.getObject('apps').update(app._id, {
494
+ tab_items
495
+ }, userSession);
496
+
497
+ return page;
498
+ }
499
+ },
500
+ delete_app_tab: {
501
+ rest: {
502
+ method: "POST",
503
+ fullPath: "/service/api/apps/delete_app_tab"
504
+ },
505
+ async handler(ctx) {
506
+ const { appId, tabName } = ctx.params;
507
+ const userSession = ctx.meta.user;
508
+
509
+ if(!appId){
510
+ return;
511
+ }
512
+
513
+ const records = await this.getObject('apps').find({
514
+ filters: ['code', '=', appId]
515
+ });
516
+ const app = records.length > 0 ? records[0] : null;
517
+
518
+ if(!app){
519
+ return ;
520
+ }
521
+
522
+
523
+ const tab_items = app.tab_items || {};
524
+
525
+ delete tab_items[tabName]
526
+
527
+ await this.getObject('apps').update(app._id, {
528
+ tab_items
529
+ }, userSession);
530
+
531
+ return app;
532
+ }
533
+ },
534
+ delete_app_group: {
535
+ rest: {
536
+ method: "POST",
537
+ fullPath: "/service/api/apps/delete_app_group"
538
+ },
539
+ async handler(ctx) {
540
+ const { appId, groupName } = ctx.params;
541
+ const userSession = ctx.meta.user;
542
+
543
+ if(!appId){
544
+ return;
545
+ }
546
+
547
+ const records = await this.getObject('apps').find({
548
+ filters: ['code', '=', appId]
549
+ });
550
+ const app = records.length > 0 ? records[0] : null;
551
+
552
+ if(!app){
553
+ return ;
554
+ }
555
+
556
+ const tab_groups = app.tab_groups || [];
557
+ const newTabGroups = [];
558
+
559
+ _.each(tab_groups, (tGroup)=>{
560
+ if(tGroup.group_name != groupName){
561
+ newTabGroups.push(tGroup);
562
+ }
563
+ });
564
+ await this.getObject('apps').update(app._id, {
565
+ tab_groups: newTabGroups
566
+ }, userSession);
567
+
568
+ return app;
569
+ }
570
+ },
571
+ move_app_tab: {
572
+ rest: {
573
+ method: "POST",
574
+ fullPath: "/service/api/apps/move_app_tab"
575
+ },
576
+ async handler(ctx) {
577
+ const { appId, tabName, groupName, oldGroupName } = ctx.params;
578
+ const userSession = ctx.meta.user;
579
+
580
+ if(!appId){
581
+ return;
582
+ }
583
+
584
+ const records = await this.getObject('apps').find({
585
+ filters: ['code', '=', appId]
586
+ });
587
+ const app = records.length > 0 ? records[0] : null;
588
+
589
+ if(!app){
590
+ return ;
591
+ }
592
+
593
+
594
+ const tab_items = app.tab_items || {};
595
+
596
+ _.each(tab_items, (item, k)=>{
597
+ if(k === tabName){
598
+ tab_items[k].group = groupName == 0 ? '' : groupName
599
+ }
600
+ })
601
+
602
+ await this.getObject('apps').update(app._id, {
603
+ tab_items
604
+ }, userSession);
605
+
606
+ return app;
607
+ }
608
+ },
136
609
  },
137
610
 
138
611
  /**