@steedos/standard-object-database 2.5.0-beta.8 → 2.5.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.
Files changed (26) hide show
  1. package/main/default/objectTranslations/object_fields.en/object_fields.en.objectTranslation.yml +2 -2
  2. package/main/default/objectTranslations/object_fields.zh-CN/object_fields.zh-CN.objectTranslation.yml +2 -2
  3. package/main/default/objectTranslations/object_triggers.zh-CN/object_triggers.zh-CN.objectTranslation.yml +3 -5
  4. package/main/default/objects/13.permission_fields.observe.object.js +3 -0
  5. package/main/default/objects/14.object_fields.observe.object.js +3 -3
  6. package/main/default/objects/15.permission_objects.observe.object.js +5 -2
  7. package/main/default/objects/2.object_triggers.observe.object.js +42 -34
  8. package/main/default/objects/3.permission_objects.observe.object.js +39 -6
  9. package/main/default/objects/datasources.object.js +4 -0
  10. package/main/default/objects/datasources.object.yml +10 -0
  11. package/main/default/objects/object_actions.object.yml +16 -10
  12. package/main/default/objects/object_fields.object.js +1 -1
  13. package/main/default/objects/object_fields.object.yml +154 -62
  14. package/main/default/objects/object_triggers.object.yml +56 -52
  15. package/main/default/objects/objects.core.js +0 -28
  16. package/main/default/objects/objects.object.yml +1 -1
  17. package/main/default/pages/object_detail.page.amis.json +52 -3
  18. package/main/default/routes/amis_button_design.ejs +6 -5
  19. package/main/default/routes/amis_listview_design.router.js +1 -1
  20. package/main/default/services/database-objects.service.js +137 -0
  21. package/main/default/services/suggestions.service.js +187 -0
  22. package/main/default/triggers/datasources.trigger.js +16 -29
  23. package/main/default/triggers/object_triggers.trigger.js +78 -33
  24. package/package.json +2 -2
  25. package/main/default/objects/object_triggers.core.js +0 -58
  26. package/main/default/objects/object_triggers.object.js +0 -65
@@ -1,94 +1,98 @@
1
1
  name: object_triggers
2
2
  icon: apex
3
3
  label: Object Triggers
4
+ version: 2.0
4
5
  hidden: true
5
6
  fields:
6
- name:
7
+ _name:
7
8
  type: text
8
- label: Name
9
+ label: Api Name
9
10
  searchable: true
10
11
  index: true
11
12
  required: true
12
- # label:
13
- # label: 显示名称
14
- # type: text
15
- object:
13
+ name:
14
+ data_type: text
15
+ type: text
16
+ visible_on: "{{false}}"
17
+ listenTo:
16
18
  label: Object
17
19
  type: master_detail
18
20
  reference_to: objects
19
21
  reference_to_field: name
20
22
  required: true
21
- # on:
22
- # label: 运行于
23
- # type: lookup
24
- # required: true
25
- # optionsFunction: !<tag:yaml.org,2002:js/function> |-
26
- # function () {
27
- # return [{
28
- # label: "客户端",
29
- # value: "client",
30
- # icon: "address"
31
- # }, {
32
- # label: "服务端",
33
- # value: "server",
34
- # icon: "address"
35
- # }];
36
- # }
37
23
  when:
38
24
  label: Execution Time Option
39
- type: lookup
25
+ type: select
40
26
  required: true
41
- optionsFunction: !<tag:yaml.org,2002:js/function> |-
42
- function () {
43
- return [{
27
+ multiple: true
28
+ is_wide: true
29
+ options: [{
44
30
  label: "新增记录之前",
45
- value: "beforeInsert",
46
- icon: "asset_relationship"
31
+ value: "beforeInsert"
47
32
  }, {
48
33
  label: "新增记录之后",
49
- value: "afterInsert",
50
- icon: "asset_relationship"
34
+ value: "afterInsert"
51
35
  }, {
52
36
  label: "修改记录之前",
53
- value: "beforeUpdate",
54
- icon: "asset_relationship"
37
+ value: "beforeUpdate"
55
38
  }, {
56
39
  label: "修改记录之后",
57
- value: "afterUpdate",
58
- icon: "asset_relationship"
40
+ value: "afterUpdate"
59
41
  }, {
60
42
  label: "删除记录之前",
61
- value: "beforeDelete",
62
- icon: "asset_relationship"
43
+ value: "beforeDelete"
63
44
  }, {
64
45
  label: "删除记录之后",
65
- value: "afterDelete",
66
- icon: "asset_relationship"
46
+ value: "afterDelete"
67
47
  }, {
68
48
  label: "查下记录之前",
69
- value: "beforeFind",
70
- icon: "asset_relationship"
71
- }];
72
- }
73
- is_enable:
74
- label: Enable
49
+ value: "beforeFind"
50
+ }]
51
+ isEnabled:
52
+ label: Enabled
75
53
  type: boolean
76
- todo:
77
- label: Execute Script <a target="_blank" href="https://developer.steedos.com/developer/object_trigger">View Help</a>
78
- type: textarea
79
- required: true
54
+ defaultValue: true
55
+ handler:
56
+ label: Handler
57
+ type: code
58
+ language: javascript
80
59
  is_wide: true
60
+ required: true
61
+ defaultValue: |-
62
+ // _ : lodash
63
+ // moment: moment
64
+ // validator: validator
65
+ // ctx
66
+ // objects
67
+ // services
68
+ editorDidMount: |-
69
+ if(window._registerCompletionItemProviderTrigger){
70
+ return ;
71
+ }
72
+ window._registerCompletionItemProviderTrigger = true;
73
+ const result = Steedos.authRequest("/service/api/suggestions/trigger.d.ts", {async: false});
74
+ monaco.languages.typescript.javascriptDefaults.addExtraLib(
75
+ result
76
+ );
77
+ record_permissions:
78
+ type: object
79
+ visible_on: "{{global.mode ==='read' ? true : false}}"
80
+ is_system:
81
+ type: boolean
82
+ label: System
83
+ readonly: true
84
+ visible_on: "{{global.mode ==='read' ? true : false}}"
85
+ disabled: true
81
86
  paging:
82
87
  enabled: false
83
88
  list_views:
84
89
  all:
85
90
  columns:
86
91
  - name
87
- # - label
88
- - object
89
- # - 'on'
92
+ - listenTo
90
93
  - when
91
- - is_enable
94
+ - isEnabled
95
+ - is_system
92
96
  label: All
93
97
  filter_scope: space
94
98
  permission_set:
@@ -2,8 +2,6 @@ var objectql = require('@steedos/objectql');
2
2
  const clone = require('clone');
3
3
  const defaultDatasourceName = 'default';
4
4
  const defaultDatasourcesName = ['default','meteor'];
5
- var triggerCore = require('./object_triggers.core.js');
6
- var permissionCore = require('./permission_objects.core.js');
7
5
 
8
6
  const DB_OBJECT_SERVICE_NAME = '~database-objects';
9
7
 
@@ -44,32 +42,6 @@ function getDataSourceName(doc) {
44
42
  return defaultDatasourceName
45
43
  }
46
44
 
47
- function loadObjectTriggers(object) {
48
- Creator.getCollection("object_triggers").find({ space: object.space, object: object.name, is_enable: true }, {
49
- fields: {
50
- created: 0,
51
- created_by: 0,
52
- modified: 0,
53
- modified_by: 0
54
- }
55
- }).forEach(function (trigger) {
56
- triggerCore.loadObjectTrigger(trigger);
57
- })
58
- }
59
-
60
- function loadObjectPermission(object) {
61
- Creator.getCollection("permission_objects").find({ space: object.space, object_name: object.name }, {
62
- fields: {
63
- created: 0,
64
- created_by: 0,
65
- modified: 0,
66
- modified_by: 0
67
- }
68
- }).forEach(function (permission) {
69
- permissionCore.loadObjectPermission(permission);
70
- })
71
- }
72
-
73
45
 
74
46
  function getObjectFields(object) {
75
47
  var object_fields = Creator.getCollection("object_fields").find({
@@ -51,7 +51,6 @@ fields:
51
51
  icon: svg
52
52
  });
53
53
  });
54
-
55
54
  return options;
56
55
  }
57
56
  is_enable:
@@ -116,6 +115,7 @@ fields:
116
115
  group: Switch
117
116
  hidden: true
118
117
  enable_inline_edit:
118
+ hidden: true
119
119
  type: boolean
120
120
  defaultValue: true
121
121
  label: Enable Single Field Edit
@@ -35,7 +35,8 @@
35
35
  "relatedObjectApiName": "object_fields",
36
36
  "id": "u:6bef459155bd",
37
37
  "top": 2000,
38
- "recordId": "${recordId}"
38
+ "recordId": "${recordId}",
39
+ "relatedKey": "object"
39
40
  }
40
41
  ],
41
42
  "id": "u:f1a52545b642"
@@ -68,6 +69,21 @@
68
69
  ],
69
70
  "id": "u:d75b105f6d02"
70
71
  },
72
+ {
73
+ "title": "对象页面",
74
+ "body": [
75
+ {
76
+ "type": "steedos-object-related-listview",
77
+ "objectApiName": "objects",
78
+ "relatedObjectApiName": "pages",
79
+ "relatedKey": "object_name",
80
+ "perPage": 20,
81
+ "id": "u:e1a8b77a140c2",
82
+ "recordId": "${recordId}"
83
+ }
84
+ ],
85
+ "id": "u:d75b105f6d042"
86
+ },
71
87
  {
72
88
  "title": "页面布局",
73
89
  "body": [
@@ -95,6 +111,19 @@
95
111
  }
96
112
  ]
97
113
  },
114
+ {
115
+ "title": "触发器",
116
+ "body": [
117
+ {
118
+ "type": "steedos-object-related-listview",
119
+ "objectApiName": "objects",
120
+ "recordId": "${recordId}",
121
+ "relatedObjectApiName": "object_triggers",
122
+ "relatedKey": "listenTo",
123
+ "perPage": 20
124
+ }
125
+ ]
126
+ },
98
127
  {
99
128
  "title": "流程映射",
100
129
  "body": [
@@ -153,10 +182,29 @@
153
182
  "className": "object-detail-tabs mt-3 bg-white border-b sm:shadow sm:rounded sm:border border-slate-300",
154
183
  "toolbarClassName": "",
155
184
  "linksClassName": "",
156
- "contentClassName": "bg-white"
185
+ "contentClassName": "bg-white",
186
+ "onEvent": {
187
+ "change": {
188
+ "weight": 0,
189
+ "actions": [
190
+ {
191
+ "actionType": "custom",
192
+ "script": "var objectName = event.data._master?.record?.name;\nvar activeKey = event.data.value;\nif (objectName && activeKey) { \n var activeKeys = {};\n activeKeys[objectName] = activeKey;\n sessionStorage.setItem(\"object_detail_tabs_activeKeys\", JSON.stringify(activeKeys));\n}"
193
+ }
194
+ ]
195
+ },
196
+ "recordLoaded": {
197
+ "weight": 0,
198
+ "actions": [
199
+ {
200
+ "actionType": "custom",
201
+ "script": "var activeKeys = sessionStorage.getItem(\"object_detail_tabs_activeKeys\");\nvar objectName = event.data.record?.name;\nif (activeKeys && objectName) {\n activeKeys = JSON.parse(activeKeys);\n var activeKey = activeKeys[objectName];\n if (activeKey) {\n doAction({\n actionType: 'changeActiveKey',\n args: {\n activeKey: activeKey\n }\n });\n }\n}"
202
+ }
203
+ ]
204
+ }
205
+ }
157
206
  }
158
207
  ],
159
- "objectApiName": "${objectName}",
160
208
  "data": {
161
209
  "objectName": "objects",
162
210
  "recordId": "space_users",
@@ -168,6 +216,7 @@
168
216
  }
169
217
  },
170
218
  "id": "page_objects_record_detail",
219
+ "objectApiName": "${objectName}",
171
220
  "name": "page_objects_record_detail",
172
221
  "bodyClassName": "",
173
222
  "className": "object-detail-page"
@@ -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: 2022-09-22 15:10:22
5
+ * @LastEditTime: 2023-04-28 10:35:46
6
6
  * @Description:
7
7
  -->
8
8
  <html>
@@ -77,8 +77,7 @@
77
77
  ]});
78
78
  }
79
79
 
80
- let objectName = result.data.object;
81
- let pageType = result.data.type;
80
+ let objectName = button.object;
82
81
  if (typeof schema === "string") {
83
82
  schema = JSON.parse(schema);
84
83
  }
@@ -90,10 +89,9 @@
90
89
  if (!schema.data.context) {
91
90
  schema.data.context = {};
92
91
  }
93
-
94
92
  schema.data.app_id = '';
95
93
  schema.data.tab_id = '';
96
- schema.data.object_name = '';
94
+ schema.data.objectName = objectName;
97
95
  schema.data.dataComponentId = '';
98
96
  schema.data.record_id = '';
99
97
  schema.data.record = {};
@@ -128,6 +126,9 @@
128
126
  delete schema.data.context.authToken;
129
127
  delete schema.data.context.user;
130
128
  delete schema.data.context.rootUrl;
129
+ delete schema.data.objectName;
130
+ delete schema.data.app_id;
131
+ delete schema.data.tab_id;
131
132
  }
132
133
  return await axios.post(
133
134
  `${rootUrl}/graphql`,
@@ -41,7 +41,7 @@ router.get('/api/amisListviewDesign', core.requireAuthentication, async function
41
41
  userId: userSession.userId,
42
42
  authToken: userSession.authToken,
43
43
  id: req.query.id,
44
- object_name: record?.object_name
44
+ object_name: record && record.object_name ? record.object_name : ""
45
45
  }
46
46
  const options = {}
47
47
  ejs.renderFile(filename, data, options, function(err, str){
@@ -0,0 +1,137 @@
1
+ /*
2
+ * @Author: baozhoutao@steedos.com
3
+ * @Date: 2023-04-21 16:25:07
4
+ * @LastEditors: baozhoutao@steedos.com
5
+ * @LastEditTime: 2023-05-18 09:26:18
6
+ * @Description:
7
+ */
8
+ var packageServiceName = '~database-objects'
9
+ function isPatternTrigger(data){
10
+ const {listenTo} = data;
11
+ if(listenTo === '*'){
12
+ return true;
13
+ }else if(_.isArray(listenTo)){
14
+ return true;
15
+ }else if(_.isRegExp(listenTo)){
16
+ return true;
17
+ }else if(_.isString(listenTo) && listenTo.startsWith("/")){
18
+ try {
19
+ if(_.isRegExp(eval(listenTo))){
20
+ return true;
21
+ }
22
+ } catch (error) {
23
+ return false
24
+ }
25
+ return false;
26
+ }
27
+ return false;
28
+ }
29
+ module.exports = {
30
+ name: packageServiceName,
31
+ namespace: "steedos",
32
+
33
+ dependencies: ['~packages-standard-objects'],
34
+
35
+ /**
36
+ * Actions
37
+ */
38
+ actions: {
39
+
40
+ },
41
+
42
+ /**
43
+ * Events
44
+ */
45
+ events: {
46
+
47
+ },
48
+
49
+ /**
50
+ * Methods
51
+ */
52
+ methods: {
53
+ changeTriggerMetadata: {
54
+ async handler(trigger){
55
+ if(isPatternTrigger(trigger)){
56
+ trigger.isPattern = true
57
+ }
58
+ await this.broker.call(`object_triggers.add`, { apiName: `${trigger.listenTo}.${trigger.name}`, data: trigger }, {
59
+ meta: {
60
+ metadataServiceName: packageServiceName,
61
+ caller: {
62
+ nodeID: this.broker.nodeID,
63
+ service: {
64
+ name: packageServiceName,
65
+ }
66
+ }
67
+ }});
68
+ this.broker.broadcast('metadata.object_triggers.change', {apiName: `${trigger.listenTo}.${trigger.name}`, listenTo: trigger.listenTo})
69
+ }
70
+ },
71
+ removeTriggerMetadata: {
72
+ async handler(trigger){
73
+ await this.broker.call(`object_triggers.delete`, { apiName: `${trigger.listenTo}.${trigger.name}`}, {
74
+ meta: {
75
+ metadataServiceName: packageServiceName,
76
+ caller: {
77
+ nodeID: this.broker.nodeID,
78
+ service: {
79
+ name: packageServiceName,
80
+ }
81
+ }
82
+ }});
83
+ this.broker.broadcast('metadata.object_triggers.change', {apiName: `${trigger.listenTo}.${trigger.name}`, listenTo: trigger.listenTo})
84
+ }
85
+ },
86
+ subTriggers: {
87
+ async handler(){
88
+ return Creator.getCollection("object_triggers").find({}, {
89
+ fields: {
90
+ created: 0,
91
+ created_by: 0,
92
+ modified: 0,
93
+ modified_by: 0
94
+ }
95
+ }).observe({
96
+ added: (newDocument)=>{
97
+ return this.changeTriggerMetadata(newDocument);
98
+ },
99
+ changed: (newDocument, oldDocument) => {
100
+ if(newDocument.name != oldDocument.name){
101
+ this.removeTriggerMetadata(oldDocument);
102
+ }
103
+ return this.changeTriggerMetadata(newDocument);
104
+ },
105
+ removed: (oldDocument) => {
106
+ return this.removeTriggerMetadata(oldDocument);
107
+ }
108
+ });
109
+ }
110
+ }
111
+ },
112
+
113
+ /**
114
+ * Service created lifecycle event handler
115
+ */
116
+ async created() {
117
+
118
+ },
119
+
120
+ /**
121
+ * Service started lifecycle event handler
122
+ */
123
+ async started() {
124
+ Meteor.startup(async ()=>{
125
+ this.subTriggers = await this.subTriggers();
126
+ })
127
+ },
128
+
129
+ /**
130
+ * Service stopped lifecycle event handler
131
+ */
132
+ async stopped() {
133
+ // TODO 停止服务时, 需要执行以下操作
134
+ // 1 stop订阅
135
+ // 2 清理元数据
136
+ }
137
+ }
@@ -0,0 +1,187 @@
1
+ const { getObject } = require('@steedos/objectql');
2
+ const _ = require('lodash');
3
+
4
+ module.exports = {
5
+ name: "suggestions",
6
+ namespace: "steedos",
7
+
8
+ /**
9
+ * Actions
10
+ */
11
+ actions: {
12
+ triggerTSExtraLib: {
13
+ rest: {
14
+ method: "GET",
15
+ path: "/trigger.d.ts",
16
+ },
17
+ async handler(ctx) {
18
+ let servicesTypes = 'declare const services: {';
19
+ _.each(global.services, (v, k)=>{
20
+ if(this.checkVariableName(k)){
21
+ servicesTypes = `${servicesTypes} ${k}: {`
22
+ _.each(v, (v2, k2)=>{
23
+ servicesTypes = `${servicesTypes} ${k2}: (${this.getParameterNames(v2)}) => any`
24
+ })
25
+ servicesTypes = servicesTypes + '}'
26
+ }
27
+ });
28
+
29
+ servicesTypes = servicesTypes + '}'
30
+
31
+ let objectsTypes = 'declare const objects: {';
32
+ _.each(global.objects, (v, k)=>{
33
+ objectsTypes = `${objectsTypes} ${k}: SteedosObjectType;`
34
+ });
35
+
36
+ objectsTypes = objectsTypes + '}'
37
+
38
+ return `
39
+ declare var _: any;
40
+ declare var moment: any;
41
+ declare var validator: any;
42
+ declare var Filters: any;
43
+
44
+ declare type TriggerParams = {
45
+ isInsert?: boolean;
46
+ isUpdate?: boolean;
47
+ isDelete?: boolean;
48
+ isFind?: boolean;
49
+ isBefore?: boolean;
50
+ isAfter?: boolean;
51
+ isFindOne?: boolean;
52
+ isCount?: boolean;
53
+ id?: SteedosIDType;
54
+ doc?: JsonMap;
55
+ previousDoc?: JsonMap;
56
+ size?: number;
57
+ userId: SteedosIDType;
58
+ spaceId?: SteedosIDType;
59
+ objectName?: string;
60
+ query?: SteedosQueryOptions;
61
+ data?: JsonMap;
62
+ }
63
+
64
+ declare type CTXType = {
65
+ params: TriggerParams;
66
+ broker: {
67
+ meta: any;
68
+ call: any;
69
+ mcall: any;
70
+ emit: any;
71
+ broadcast: any;
72
+ broadcastLocal: any;
73
+ namespace: string;
74
+ nodeID: string;
75
+ instanceID: string;
76
+ logger: any;
77
+ metadata: any;
78
+ },
79
+ getObject(objectName: string): any;
80
+ getUser(userId: string, spaceId: string): Promise<SteedosUserSession>;
81
+ makeNewID(): string;
82
+ };
83
+
84
+ declare var ctx: CTXType;
85
+
86
+ declare type SteedosQueryFilters = any;
87
+ declare type SteedosIDType = number | string;
88
+ declare type SteedosQueryOptions = {
89
+ fields?: Array<string> | string;
90
+ readonly filters?: SteedosQueryFilters;
91
+ readonly top?: number;
92
+ readonly skip?: number;
93
+ readonly sort?: string;
94
+ };
95
+ declare type SteedosUserSession = {
96
+ userId: SteedosIDType;
97
+ spaceId?: string;
98
+ name: string;
99
+ username?: string;
100
+ mobile?: string;
101
+ email?: string;
102
+ utcOffset?: number;
103
+ locale?: string;
104
+ roles?: string[];
105
+ space?: any;
106
+ spaces?: any;
107
+ company?: any;
108
+ companies?: any;
109
+ organization?: any;
110
+ organizations?: any;
111
+ permission_shares?: any;
112
+ company_id?: string;
113
+ company_ids?: string[];
114
+ is_space_admin?: boolean;
115
+ steedos_id?: string;
116
+ };
117
+ declare class SteedosObjectType {
118
+ find(query: SteedosQueryOptions, userSession?: SteedosUserSession): Promise<any>;
119
+ findOne(id: SteedosIDType, query: SteedosQueryOptions, userSession?: SteedosUserSession): Promise<any>;
120
+ insert(doc: Dictionary<any>, userSession?: SteedosUserSession): Promise<any>;
121
+ update(id: SteedosIDType, doc: Dictionary<any>, userSession?: SteedosUserSession): Promise<any>;
122
+ delete(id: SteedosIDType, userSession?: SteedosUserSession): Promise<any>;
123
+ directFind(query: SteedosQueryOptions, userSession?: SteedosUserSession): Promise<any>;
124
+ directInsert(doc: Dictionary<any>, userSession?: SteedosUserSession): Promise<any>;
125
+ directUpdate(id: SteedosIDType, doc: Dictionary<any>, userSession?: SteedosUserSession): Promise<any>;
126
+ directDelete(id: SteedosIDType, userSession?: SteedosUserSession): Promise<any>;
127
+ count(query: SteedosQueryOptions, userSession?: SteedosUserSession): Promise<any>;
128
+ }
129
+ ${objectsTypes}
130
+ ${servicesTypes}
131
+ `
132
+ }
133
+ }
134
+ },
135
+
136
+ /**
137
+ * Events
138
+ */
139
+ events: {
140
+
141
+ },
142
+
143
+ /**
144
+ * Methods
145
+ */
146
+ methods: {
147
+ checkVariableName:(variableName)=>{
148
+ var reg = /^[a-zA-Z_$][a-zA-Z0-9_$]*$/;
149
+ if(reg.test(variableName)){
150
+ var keywords = ['break', 'case', 'catch', 'continue', 'debugger', 'default', 'delete', 'do', 'else', 'finally', 'for', 'function', 'if', 'in', 'instanceof', 'new', 'return', 'switch', 'this', 'throw', 'try', 'typeof', 'var', 'void', 'while', 'with', 'true', 'false', 'null', 'undefined', 'NaN', 'Infinity'];
151
+ if(keywords.indexOf(variableName) === -1){
152
+ return true;
153
+ } else {
154
+ return false;
155
+ }
156
+ } else {
157
+ return false;
158
+ }
159
+ },
160
+ getParameterNames:(func)=>{
161
+ const fnStr = func.toString().replace(/((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg, '');
162
+ const result = fnStr.slice(fnStr.indexOf('(')+1, fnStr.indexOf(')')).match(/([^\s,]+)/g);
163
+ if (result === null)
164
+ return [];
165
+ else
166
+ return result;
167
+ }
168
+ },
169
+
170
+ /**
171
+ * Service created lifecycle event handler
172
+ */
173
+ async created() {
174
+ },
175
+
176
+ /**
177
+ * Service started lifecycle event handler
178
+ */
179
+ async started() {
180
+ },
181
+
182
+ /**
183
+ * Service stopped lifecycle event handler
184
+ */
185
+ async stopped() {
186
+ }
187
+ }