@steedos/standard-object-database 2.7.8-beta.2 → 2.7.8-beta.21

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 (25) hide show
  1. package/LICENSE.txt +14 -15
  2. package/main/default/client/object_fields.client.js +0 -14
  3. package/main/default/objectTranslations/objects.en/objects.en.objectTranslation.yml +5 -1
  4. package/main/default/objectTranslations/objects.zh-CN/objects.zh-CN.objectTranslation.yml +5 -1
  5. package/main/default/objects/object_triggers/fields/authentication_header_key.field.yml +10 -0
  6. package/main/default/objects/object_triggers/fields/authentication_header_value.field.yml +6 -0
  7. package/main/default/objects/object_triggers/fields/authentication_type.field.yml +12 -0
  8. package/main/default/objects/object_triggers/fields/handler.field.yml +1 -0
  9. package/main/default/objects/object_triggers/fields/type.field.yml +10 -0
  10. package/main/default/objects/object_triggers/fields/url.field.yml +6 -0
  11. package/main/default/objects/objects/buttons/design_field_layout.button.yml +2 -1
  12. package/main/default/objects/objects/buttons/design_fields_layout.button.yml +2 -3
  13. package/main/default/objects/objects/fields/enable_audit.field.yml +6 -0
  14. package/main/default/objects/objects/fields/enable_chatter.field.yml +4 -3
  15. package/main/default/pages/object_fields_form.page.amis.json +10 -1
  16. package/main/default/routes/object_fields_design.ejs +129 -3
  17. package/main/default/routes/object_fields_design.router.js +1 -1
  18. package/main/default/server/object_fields.object.js +4 -3
  19. package/main/default/server/objects.core.js +1 -0
  20. package/main/default/server/objects.object.js +56 -0
  21. package/main/default/services/object_fields.service.js +101 -25
  22. package/main/default/services/object_webhooks.service.js +3 -2
  23. package/main/default/triggers/object_actions.trigger.js +18 -3
  24. package/package.json +5 -5
  25. package/package.service.js +474 -1
package/LICENSE.txt CHANGED
@@ -1,22 +1,21 @@
1
- Steedos Licensing
1
+ # Open Source License
2
2
 
3
- SOFTWARE LICENSING
3
+ Steedos is licensed under a modified version of the Apache License 2.0, with the following additional conditions:
4
4
 
5
- To determine under which license you may use a file from the Steedos source code,
6
- please resort to the header of that file.
5
+ 1. Steedos may be utilized commercially, including as a backend service for other applications or as an application development platform for enterprises. Should the conditions below be met, a commercial license must be obtained from the producer:
7
6
 
8
- If the file has no header, the following rules apply
9
- 1. enterprise features are licensed under Steedos Enterprise Terms, see License.enterprise.txt
10
- 2. source code that is neither (1) is licensed under MIT, see https://opensource.org/licenses/MIT
7
+ a. Multi-tenant service: Unless explicitly authorized by Steedos in writing, you may not use the Steedos source code to operate a multi-tenant environment.
8
+ - Tenant Definition: Within the context of Steedos, one tenant corresponds to one space. The space provides a separated area for each tenant's data and configurations.
11
9
 
12
- On request, licenses under different terms are available.
10
+ b. LOGO and copyright information: In the process of using Steedos's frontend, you may not remove or modify the LOGO or copyright information in the Steedos console or applications. This restriction is inapplicable to uses of Steedos that do not involve its frontend.
13
11
 
14
- Source code of enterprise features are files that
15
- * are in folders named "ee" or start with "ee_", or in subfolders of such folders.
16
- * contain the strings "ee_" in its filename name.
17
- The files can be found by running the command `find . -iname ee -or -iname "*_ee*" -or -iname "*ee_*"`
12
+ 2. As a contributor, you should agree that:
18
13
 
19
- STEEDOS TRADEMARK GUIDELINES
14
+ a. The producer can adjust the open-source agreement to be more strict or relaxed as deemed necessary.
15
+ b. Your contributed code may be used for commercial purposes, including but not limited to its cloud business operations.
20
16
 
21
- Your use of the mark Steedos is subject to Steedos, Inc's prior written approval. For trademark approval or any questions
22
- you have about using these trademarks, please email zhuangjianguo@steedos.com
17
+ Apart from the specific conditions mentioned above, all other rights and restrictions follow the Apache License 2.0. Detailed information about the Apache License 2.0 can be found at http://www.apache.org/licenses/LICENSE-2.0.
18
+
19
+ The interactive design of this product is protected by appearance patent.
20
+
21
+ © 2025 Steedos, Inc.
@@ -239,12 +239,6 @@ Steedos.ObjectFieldManager.getSummaryFiltersOperation = function(field_type) {
239
239
  display: none;
240
240
  }
241
241
 
242
- .defaultValue_field.steedos-defaultValue-html-edit .defaultValue_field_formula_hidden .antd-Form-label {
243
- /*html字段类型默认值,显示为静态值编辑器时,因为移除了flex样式类,不再把amis公式配置按钮显示在右侧,而是换行显示,此时label不可以display: none,否则缩进不对*/
244
- display: block;
245
- visibility: hidden;
246
- }
247
-
248
242
  .defaultValue_field .defaultValue_field_formula_hidden {
249
243
  flex-grow: 0;
250
244
  }
@@ -256,14 +250,6 @@ Steedos.ObjectFieldManager.getSummaryFiltersOperation = function(field_type) {
256
250
  .defaultValue_field.steedos-defaultValue-html-edit .defaultValue_field_formula_hidden {
257
251
  margin-left: 0px;
258
252
  }
259
-
260
- .defaultValue_field .defaultValue_field_formula_hidden .antd-Form-label {
261
- display: none;
262
- }
263
-
264
- .defaultValue_field .defaultValue_field_formula_hidden .antd-FormulaPicker-input {
265
- display: none;
266
- }
267
253
  </style>`);
268
254
  $("head").append(styleCss);
269
255
  } catch (error) {
@@ -78,8 +78,12 @@ fields:
78
78
  label: Enable Instances
79
79
  help:
80
80
  description:
81
+ enable_audit:
82
+ label: Enable Audit
83
+ help:
84
+ description:
81
85
  enable_chatter:
82
- label: Enable Chatter
86
+ label: Enable Comments
83
87
  help:
84
88
  description:
85
89
  enable_inline_edit:
@@ -75,8 +75,12 @@ fields:
75
75
  label: 显示审批单子表
76
76
  help:
77
77
  description:
78
+ enable_audit:
79
+ label: 记录字段历史
80
+ help:
81
+ description:
78
82
  enable_chatter:
79
- label: 允许添加留言
83
+ label: 允许添加评论
80
84
  help:
81
85
  description:
82
86
  enable_inline_edit:
@@ -0,0 +1,10 @@
1
+ name: authentication_header_key
2
+ type: text
3
+ label: Header Name
4
+ group: 认证
5
+ sort_no: 180
6
+ visible_on: ${type === 'url' && authentication_type === 'header'}
7
+ amis:
8
+ - options:
9
+ - label: authorization
10
+ value: authorization
@@ -0,0 +1,6 @@
1
+ name: authentication_header_value
2
+ type: text
3
+ label: Header Value
4
+ group: 认证
5
+ sort_no: 190
6
+ visible_on: ${type === 'url' && authentication_type === 'header'}
@@ -0,0 +1,12 @@
1
+ name: authentication_type
2
+ label: 认证类型
3
+ type: select
4
+ group: 认证
5
+ options:
6
+ - label: 不认证
7
+ value: none
8
+ - label: Header Auth
9
+ value: header
10
+ defaultValue: none
11
+ sort_no: 170
12
+ visible_on: ${type === 'url'}
@@ -23,3 +23,4 @@ editorDidMount: >-
23
23
  result
24
24
  );
25
25
  sort_no: 150
26
+ visible_on: ${type != 'url'}
@@ -0,0 +1,10 @@
1
+ name: type
2
+ label: 类型
3
+ type: select
4
+ options:
5
+ - label: 代码
6
+ value: code
7
+ - label: 接口
8
+ value: url
9
+ defaultValue: code
10
+ sort_no: 132
@@ -0,0 +1,6 @@
1
+ name: url
2
+ type: url
3
+ label: URL
4
+ sort_no: 160
5
+ is_wide: true
6
+ visible_on: ${type === 'url'}
@@ -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: 设计字段布局
4
- 'on': record_more
5
- sort: 80
3
+ label: 设计对象
4
+ 'on': record_only
@@ -0,0 +1,6 @@
1
+ name: enable_audit
2
+ type: boolean
3
+ label: Enable Audit
4
+ group: Switch
5
+ sort_no: 305
6
+ visible_on: '{{ Meteor.settings.public.platform && ["platform-standard", "platform-enterprise", "platform-professional"].includes(Meteor.settings.public.platform.product) }}'
@@ -1,6 +1,7 @@
1
1
  name: enable_chatter
2
- hidden: true
3
- label: Enable Chatter
2
+ group: switch
3
+ hidden: false
4
+ label: Enable Comments
4
5
  sort_no: 300
5
6
  type: boolean
6
- visible_on: '{{false}}'
7
+ visible_on: '{{ Meteor.settings.public.platform && ["platform-standard", "platform-enterprise", "platform-professional"].includes(Meteor.settings.public.platform.product) }}'
@@ -184,13 +184,22 @@
184
184
  "visible_on": {
185
185
  "amis": {
186
186
  "type": "input-formula",
187
- "name": "formula",
188
187
  "evalMode": false,
189
188
  "variableMode": "tabs",
190
189
  "variables": "${visibleOnVariables}",
191
190
  "visibleOn": "${visibleOnVariables}",
192
191
  "id": "u:618105d5bfad"
193
192
  }
193
+ },
194
+ "formula": {
195
+ "amis": {
196
+ "type": "input-formula",
197
+ "evalMode": false,
198
+ "variableMode": "tabs",
199
+ "variables": "${visibleOnVariables}",
200
+ "visibleOn": "${visibleOnVariables && (type == 'formula' || type == 'autonumber') }",
201
+ "id": "u:618105d5bfad"
202
+ }
194
203
  }
195
204
  },
196
205
  "form": {
@@ -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-04 18:09:08
5
+ * @LastEditTime: 2024-10-17 12:02:21
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,16 +208,130 @@
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;
205
251
  if (data) {
206
252
  if(data.type === 'builder.loaded'){
207
253
  comp.messageFrame('builder.EditorPropsChanged', { editorProps : JSON.stringify({
254
+ onChange: function(value){
255
+ const fields = [];
256
+ _.each(value.body, (bodyItem)=>{
257
+ if(bodyItem.type === 'steedos-field-group'){
258
+ let groupName = bodyItem.title;
259
+ _.each(bodyItem.body, (field)=>{
260
+ if(_.startsWith(field.type, 'sfield-')){
261
+
262
+ if(field.config && field.config.amis){
263
+ delete field.config.amis.name
264
+ delete field.config.amis.mode
265
+ }
266
+
267
+ fields.push(Object.assign({}, field.config, {group: groupName}));
268
+ }
269
+ })
270
+ }else if(_.startsWith(bodyItem.type, 'sfield-')){
271
+ if(bodyItem.config && bodyItem.config.amis){
272
+ delete bodyItem.config.amis.name
273
+ delete bodyItem.config.amis.mode
274
+ }
275
+ fields.push(Object.assign({}, bodyItem.config, {group: '通用'}));
276
+ }
277
+ })
278
+
279
+
280
+ const variables = [];
281
+
282
+ _.each(_.groupBy(fields, 'group'), (v, k)=>{
283
+ if(k=== '通用'){
284
+ _.each(v, (field)=>{
285
+ variables.push({
286
+ label: field.label,
287
+ value: field.name
288
+ })
289
+ })
290
+ }else{
291
+ variables.push({
292
+ label: k,
293
+ children: _.map(v, (field)=>{
294
+ return {
295
+ label: field.label,
296
+ value: field.name
297
+ }
298
+ })
299
+ })
300
+ }
301
+ })
302
+ window._objectFieldsVariables = variables;
303
+ },
208
304
  onDndAccept: function(event){
209
- console.log(`onDndAccept===>`, event);
210
305
  return true;
211
306
  },
307
+ beforeDelete: function(event){
308
+ const toastConfig = {
309
+ "closeButton": true,
310
+ "debug": false,
311
+ "newestOnTop": false,
312
+ "progressBar": false,
313
+ "positionClass": "toast-top-center",
314
+ "preventDuplicates": false,
315
+ "onclick": null,
316
+ "showDuration": "300",
317
+ "hideDuration": "1000",
318
+ "timeOut": "5000",
319
+ "extendedTimeOut": "1000",
320
+ "showEasing": "swing",
321
+ "hideEasing": "linear",
322
+ "showMethod": "fadeIn",
323
+ "hideMethod": "fadeOut"
324
+ }
325
+ if(event.context.schema.type.startsWith('sfield') && event.context.schema.config.is_system){
326
+ parent.toastr.warning('禁止删除系统字段', '', toastConfig)
327
+ return event.preventDefault();
328
+ };
329
+
330
+ if(event.context.schema.type.startsWith('sfield') && event.context.schema.config.name === 'name'){
331
+ parent.toastr.warning('禁止删除名称字段', '', toastConfig)
332
+ return event.preventDefault();
333
+ }
334
+ },
212
335
  onInit: function(){
213
336
  // 创建一个新的 style 元素
214
337
  var style = document.createElement('style');
@@ -225,6 +348,9 @@
225
348
  .ae-RendererList-tabs-header .antd-Tabs-link:nth-child(n+2) {
226
349
  display: none !important;
227
350
  }
351
+ .ae-RendererList-groupWrap .ae-RendererList-group.collapse-content .ae-RendererList-item:hover .ae-RendererIcon{
352
+ display: none !important;
353
+ }
228
354
  `;
229
355
 
230
356
  // 将 style 元素插入到 head 中
@@ -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,10 +2,11 @@ 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 () {
8
- return await objectql.getObject('object_fields').find(this.filter);
9
+ return await objectql.getObject('object_fields').directFind(this.filter);
9
10
  }, { filter: filter })
10
11
  }
11
12
 
@@ -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);
@@ -169,6 +169,7 @@ function _sendObjectMeta(objectConfig){
169
169
  if(res){
170
170
  // console.log('send object meta success', length);
171
171
  broker.broadcast("$packages.statisticsActivatedPackages", {});
172
+ broker.emit(`translations.object.change`, {});
172
173
  }
173
174
  })
174
175
  _objectConfigs = [];
@@ -318,6 +318,62 @@ let objectTriggers = {
318
318
  filterable: true,
319
319
  sort_no: 10
320
320
  });
321
+ Creator.getCollection("object_fields").insert({
322
+ object: doc.name,
323
+ owner: userId,
324
+ _name: "created",
325
+ name: "created",
326
+ label: "创建时间",
327
+ space: doc.space,
328
+ type: "datetime",
329
+ group: '',
330
+ sort_no: 9999,
331
+ readonly: true,
332
+ disabled: true,
333
+ sortable: true
334
+ });
335
+ Creator.getCollection("object_fields").insert({
336
+ object: doc.name,
337
+ owner: userId,
338
+ _name: "created_by",
339
+ name: "created_by",
340
+ label: "创建人",
341
+ space: doc.space,
342
+ type: "lookup",
343
+ reference_to: 'users',
344
+ group: '',
345
+ sort_no: 9999,
346
+ readonly: true,
347
+ disabled: true,
348
+ });
349
+ Creator.getCollection("object_fields").insert({
350
+ object: doc.name,
351
+ owner: userId,
352
+ _name: "modified",
353
+ name: "modified",
354
+ label: "修改时间",
355
+ space: doc.space,
356
+ type: "datetime",
357
+ group: '',
358
+ sort_no: 9999,
359
+ readonly: true,
360
+ disabled: true,
361
+ sortable: true
362
+ });
363
+ Creator.getCollection("object_fields").insert({
364
+ object: doc.name,
365
+ owner: userId,
366
+ _name: "modified_by",
367
+ name: "modified_by",
368
+ label: "修改人",
369
+ space: doc.space,
370
+ type: "lookup",
371
+ reference_to: 'users',
372
+ group: '',
373
+ sort_no: 9999,
374
+ readonly: true,
375
+ disabled: true,
376
+ });
321
377
  // Creator.getCollection("object_fields").insert({
322
378
  // object: doc.name,
323
379
  // owner: userId,
@@ -7,7 +7,30 @@ const steedosI18n = require("@steedos/i18n");
7
7
  const _ = require("lodash");
8
8
  const clone = require("clone");
9
9
  const serviceObjectMixin = require('@steedos/service-object-mixin');
10
+ const objectql = require('@steedos/objectql');
10
11
  // 默认值字段代码:services/standard-object-database/main/default/services/object_fields.service.js
12
+
13
+ const initSummaryDoc = async (doc) => {
14
+ if (!doc.summary_object) {
15
+ throw new Error("object_fields_error_summary_object_required");
16
+ }
17
+ let summaryObject = register.getObjectConfig(doc.summary_object);
18
+ let summaryConfig = {
19
+ summary_object: doc.summary_object,
20
+ summary_type: doc.summary_type,
21
+ summary_field: doc.summary_field,
22
+ field_name: doc.name,
23
+ object_name: doc.object
24
+ };
25
+ const dataType = await objectql.getSummaryDataType(summaryConfig, summaryObject);
26
+ if (!dataType) {
27
+ throw new Error("object_fields_error_summary_data_type_not_found");
28
+ }
29
+ doc.data_type = dataType;
30
+ // objectql.validateFilters(doc.summary_filters, summaryObject.fields);
31
+ }
32
+
33
+
11
34
  module.exports = {
12
35
  name: "object_fields",
13
36
  mixins: [serviceObjectMixin],
@@ -291,8 +314,16 @@ module.exports = {
291
314
 
292
315
  _.map(objectFields, (objectField)=>{
293
316
  if(!objectField.group){
294
- objectField.group = '基本信息'
295
- }
317
+ objectField.group = '通用'
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;
296
327
  })
297
328
 
298
329
  return {
@@ -303,18 +334,20 @@ module.exports = {
303
334
  data: {
304
335
  objectName
305
336
  },
306
- className: "steedos-amis-form steedos-field-layout-page m-4",
337
+ className: "steedos-amis-form steedos-field-layout-page",
307
338
  body: _.map(_.groupBy(_.orderBy(objectFields, function(o) { return o.sort_no || 100 }), 'group'), (items, groupName)=>{
308
339
  const group = getGroup(groupName)
309
340
  return {
310
341
  type: 'steedos-field-group',
311
342
  title: group.group_name,
343
+ collapsable: true,
312
344
  collapsed: group.collapsed,
313
345
  visible_on: group.visible_on,
314
346
  body: _.map(items, (field)=>{
315
347
  return {
316
- type: `sfield-${field.type}`,
317
- config: Object.assign({amis: {name: field.name}}, field)
348
+ type: `sfield-${_.camelCase(field.type).toLowerCase()}`,
349
+ config: Object.assign({amis: {name: field.name}}, field),
350
+ visibleOn: field.visible_on
318
351
  }
319
352
  })
320
353
  }
@@ -353,22 +386,39 @@ module.exports = {
353
386
  return {}
354
387
  }
355
388
  let sort_no = 50;
356
- _.each(schema.body, (group)=>{
357
- if(group.type === 'steedos-field-group'){
358
- const groupName = group.title;
359
- _.each(group.body, (field)=>{
389
+ _.each(schema.body, (bodyItem)=>{
390
+ if(bodyItem.type === 'steedos-field-group'){
391
+ const groupName = bodyItem.title;
392
+ _.each(bodyItem.body, (field)=>{
360
393
  if(_.startsWith(field.type, 'sfield-')){
361
- fields.push(Object.assign({}, field.config, {group: groupName, sort_no}));
394
+
395
+ if(field.config){
396
+ field.config.object = object.name
397
+ }
398
+
399
+ if(field.config && field.config.amis){
400
+ delete field.config.amis.name
401
+ delete field.config.amis.mode
402
+ }
403
+
404
+ fields.push(Object.assign({}, field.config, {group: groupName, sort_no, _name: field.config.name}));
362
405
  sort_no += 50;
363
406
  }
364
407
  })
365
408
  groups.push({
366
- group_name: group.title,
367
- collapsed: group.collapsed,
368
- visible_on: group.visible_on
409
+ group_name: bodyItem.title,
410
+ collapsed: bodyItem.collapsed,
411
+ visible_on: bodyItem.visible_on
369
412
  })
370
- }else if(_.startsWith(field.type, 'sfield-')){
371
- fields.push(Object.assign({}, field.config, {sort_no}));
413
+ }else if(_.startsWith(bodyItem.type, 'sfield-')){
414
+ if(bodyItem.config){
415
+ bodyItem.config.object = object.name
416
+ }
417
+ if(bodyItem.config && bodyItem.config.amis){
418
+ delete bodyItem.config.amis.name
419
+ delete bodyItem.config.amis.mode
420
+ }
421
+ fields.push(Object.assign({}, bodyItem.config, {sort_no, _name: bodyItem.config.name}));
372
422
  sort_no += 50;
373
423
  }
374
424
  })
@@ -400,11 +450,12 @@ module.exports = {
400
450
 
401
451
  // 循环需要增加的字段
402
452
  for (const fieldName of insertFields) {
453
+ const newId = await object_fields._makeNewID();
454
+ const now = new Date();
455
+ const field = _.find(fields, { name: fieldName });
403
456
  try {
404
- const newId = await object_fields._makeNewID();
405
- const now = new Date();
406
- const field = _.find(fields, { name: fieldName });
407
- await object_fields.directInsert(Object.assign({}, field, {
457
+
458
+ const doc = Object.assign({}, field, {
408
459
  _id: newId,
409
460
  owner: userSession.userId,
410
461
  space: userSession.spaceId,
@@ -415,10 +466,18 @@ module.exports = {
415
466
  modified_by: userSession.userId,
416
467
  company_id: userSession.company_id,
417
468
  company_ids: userSession.company_ids
418
- }));
469
+ });
470
+ if(doc.type === "summary"){
471
+ await initSummaryDoc(doc);
472
+ }
473
+ await object_fields.directInsert(doc);
419
474
  log.insert.success.push(fieldName);
420
475
  } catch (e) {
421
- log.insert.error.push(fieldName);
476
+ log.insert.error.push({
477
+ fieldName: fieldName,
478
+ fieldLabel: field.label,
479
+ message: steedosI18n.t(e.message, null, 'zh-CN')
480
+ });
422
481
  console.error(`新增字段 ${fieldName} 时出错:`, e);
423
482
  }
424
483
  }
@@ -426,28 +485,45 @@ module.exports = {
426
485
  // 循环需要修改的字段
427
486
  const now = new Date();
428
487
  for (const fieldName of updateFields) {
488
+ const field = _.find(fields, { name: fieldName });
429
489
  try {
430
- const field = _.find(fields, { name: fieldName });
431
490
  const id = _.find(dbFields, { name: fieldName })._id;
432
491
  const submitField = _.omit(field, ['name', '_name']);
492
+
493
+ if(submitField.type === "summary"){
494
+ await initSummaryDoc(submitField);
495
+ }
496
+ if(submitField){
497
+ delete submitField._id;
498
+ }
433
499
  await object_fields.directUpdate(id, Object.assign({}, submitField, {
434
500
  modified: now,
435
501
  modified_by: userSession.userId
436
502
  }));
437
503
  log.update.success.push(fieldName);
438
504
  } catch (e) {
439
- log.update.error.push(fieldName);
505
+ log.update.error.push({
506
+ fieldName: fieldName,
507
+ fieldLabel: field.label,
508
+ message: steedosI18n.t(e.message, null, 'zh-CN')
509
+ });
440
510
  console.log(`dbFields`, fieldName, dbFields)
441
511
  console.error(`更新字段 ${fieldName} 时出错:`, e);
442
512
  }
443
513
  }
444
514
  // 循环需要删除的字段
445
515
  for (const fieldName of deleteFields) {
446
- try {
447
- const id = _.find(dbFields, { name: fieldName })._id;
516
+ const field = _.find(dbFields, { name: fieldName });
517
+ try {
518
+ const id = field._id;
448
519
  await object_fields.directDelete(id);
449
520
  log.delete.success.push(fieldName);
450
521
  } catch (e) {
522
+ log.delete.error.push({
523
+ fieldName: fieldName,
524
+ fieldLabel: field.label,
525
+ message: steedosI18n.t(e.message, null, 'zh-CN')
526
+ });
451
527
  log.delete.error.push(fieldName);
452
528
  console.error(`删除字段 ${fieldName} 时出错:`, e);
453
529
  }
@@ -1,8 +1,8 @@
1
1
  /*
2
2
  * @Author: baozhoutao@steedos.com
3
3
  * @Date: 2024-04-23 14:35:03
4
- * @LastEditors: baozhoutao@steedos.com
5
- * @LastEditTime: 2024-05-06 11:45:46
4
+ * @LastEditors: 孙浩林 sunhaolin@steedos.com
5
+ * @LastEditTime: 2024-09-14 11:24:08
6
6
  * @Description:
7
7
  */
8
8
 
@@ -10,6 +10,7 @@ const BullMqMixin = require('moleculer-bullmq');
10
10
  const axios = require('axios');
11
11
  const { evaluate } = require("amis-formula")
12
12
  const serviceObjectMixin = require('@steedos/service-object-mixin');
13
+ const _ = require("lodash");
13
14
 
14
15
  module.exports = {
15
16
  name: "object_webhooks",
@@ -1,8 +1,8 @@
1
1
  /*
2
2
  * @Author: sunhaolin@hotoa.com
3
3
  * @Date: 2022-05-28 11:07:57
4
- * @LastEditors: 孙浩林 sunhaolin@steedos.com
5
- * @LastEditTime: 2024-05-11 13:57:23
4
+ * @LastEditors: baozhoutao@steedos.com
5
+ * @LastEditTime: 2024-10-31 17:36:24
6
6
  * @Description:
7
7
  */
8
8
  const InternalData = require('@steedos/standard-objects').internalData;
@@ -17,7 +17,22 @@ module.exports = {
17
17
  doc.visible;
18
18
  },
19
19
  beforeUpdate: async function(){
20
- const { doc } = this;
20
+ const { doc, id } = this;
21
+ if(doc.label){
22
+ const dbRecord = await this.getObject('object_actions').findOne(id);
23
+
24
+ const amis_schema = doc.amis_schema || dbRecord.amis_schema;
25
+
26
+ if(dbRecord && dbRecord.label != doc.label && amis_schema && _.isString(amis_schema) ){
27
+ try {
28
+ const json = JSON.parse(amis_schema);
29
+ json.body[0].label = doc.label
30
+ doc.amis_schema = JSON.stringify(json)
31
+ } catch (error) {
32
+ console.log(error)
33
+ }
34
+ }
35
+ }
21
36
  delete doc.visible_type
22
37
  doc.visible;
23
38
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@steedos/standard-object-database",
3
- "version": "2.7.8-beta.2",
3
+ "version": "2.7.8-beta.21",
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.8-beta.2",
16
- "@steedos/service-object-mixin": "2.7.8-beta.2",
17
- "@steedos/standard-objects": "2.7.8-beta.2",
15
+ "@steedos/metadata-core": "2.7.8-beta.21",
16
+ "@steedos/service-object-mixin": "2.7.8-beta.21",
17
+ "@steedos/standard-objects": "2.7.8-beta.21",
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": "d915768c87aaa7bc026623a4953d6f39c5ddace1"
24
+ "gitHead": "bde64f8e1f880f54583600a8bb0a6018f36061b7"
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
  /**