@kne/fastify-account 1.0.0-alpha.2 → 1.0.0-alpha.20

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 (54) hide show
  1. package/README.md +2506 -803
  2. package/index.js +61 -8
  3. package/libs/controllers/account.js +221 -37
  4. package/libs/controllers/admin.js +92 -17
  5. package/libs/controllers/adminPermission.js +188 -38
  6. package/libs/controllers/adminTenant.js +44 -257
  7. package/libs/controllers/adminTenantCompany.js +53 -0
  8. package/libs/controllers/adminTenantOrg.js +71 -0
  9. package/libs/controllers/{adminRole.js → adminTenantRole.js} +15 -12
  10. package/libs/controllers/adminTenantUser.js +169 -0
  11. package/libs/controllers/requestLog.js +77 -0
  12. package/libs/controllers/tenant.js +4 -14
  13. package/libs/controllers/tenantCompany.js +54 -0
  14. package/libs/controllers/tenantOrg.js +65 -0
  15. package/libs/controllers/tenantRole.js +219 -0
  16. package/libs/controllers/tenantUser.js +169 -0
  17. package/libs/controllers/user.js +4 -3
  18. package/libs/models/admin-role.js +4 -8
  19. package/libs/models/application.js +16 -10
  20. package/libs/models/company-info.js +25 -0
  21. package/libs/models/login-log.js +11 -9
  22. package/libs/models/permission.js +7 -9
  23. package/libs/models/request-log.js +43 -0
  24. package/libs/models/tenant-application.js +8 -10
  25. package/libs/models/tenant-org.js +5 -9
  26. package/libs/models/tenant-permission.js +7 -9
  27. package/libs/models/tenant-role-application.js +13 -13
  28. package/libs/models/tenant-role-permission.js +9 -14
  29. package/libs/models/tenant-role.js +5 -9
  30. package/libs/models/tenant-share-group-permission.js +5 -9
  31. package/libs/models/tenant-share-group.js +5 -9
  32. package/libs/models/tenant-source-user-share-group.js +5 -9
  33. package/libs/models/tenant-token.js +7 -9
  34. package/libs/models/tenant-user-org.js +11 -10
  35. package/libs/models/tenant-user-role.js +11 -10
  36. package/libs/models/tenant-user-share-group.js +6 -10
  37. package/libs/models/tenant-user.js +35 -16
  38. package/libs/models/tenant.js +17 -9
  39. package/libs/models/user-account.js +17 -9
  40. package/libs/models/user.js +27 -17
  41. package/libs/models/verification-code.js +8 -10
  42. package/libs/services/account.js +95 -71
  43. package/libs/services/admin.js +38 -122
  44. package/libs/services/application.js +170 -0
  45. package/libs/services/permission.js +161 -163
  46. package/libs/services/request-log.js +37 -0
  47. package/libs/services/tenant-company.js +54 -0
  48. package/libs/services/tenant-invite.js +62 -0
  49. package/libs/services/tenant-org.js +118 -0
  50. package/libs/services/tenant-role.js +109 -0
  51. package/libs/services/tenant-user.js +578 -0
  52. package/libs/services/tenant.js +69 -670
  53. package/libs/services/user.js +109 -33
  54. package/package.json +3 -3
@@ -1,14 +1,19 @@
1
1
  const fp = require('fastify-plugin');
2
2
 
3
3
  module.exports = fp(async (fastify, options) => {
4
- // 用于系统初始化时,设置第一个用户,只能使用一次,其他用户由该用户创建
4
+ const { authenticate, services } = fastify.account;
5
5
  fastify.post(
6
6
  `${options.prefix}/initSuperAdmin`,
7
7
  {
8
- onRequest: [fastify.account.authenticate.user]
8
+ onRequest: [authenticate.user],
9
+ schema: {
10
+ tags: ['管理后台'],
11
+ summary: '初始化用户为管理员',
12
+ description: '用于系统初始化时,设置第一个用户,只能使用一次,其他用户由该用户创建'
13
+ }
9
14
  },
10
15
  async request => {
11
- await fastify.account.services.admin.initSuperAdmin(await fastify.account.services.user.getUserInfo(request.authenticatePayload));
16
+ await services.admin.initSuperAdmin(request.userInfo);
12
17
  return {};
13
18
  }
14
19
  );
@@ -16,24 +21,81 @@ module.exports = fp(async (fastify, options) => {
16
21
  fastify.get(
17
22
  `${options.prefix}/admin/getSuperAdminInfo`,
18
23
  {
19
- onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.admin]
24
+ onRequest: [authenticate.user, authenticate.admin],
25
+ schema: {
26
+ tags: ['管理后台'],
27
+ summary: '获取管理员信息',
28
+ response: {
29
+ 200: {
30
+ content: {
31
+ 'application/json': {
32
+ schema: {
33
+ type: 'object',
34
+ properties: {
35
+ userInfo: {
36
+ type: 'object',
37
+ properties: {
38
+ id: { type: 'string', description: '用户id' },
39
+ nickname: { type: 'string', description: '用户昵称' },
40
+ email: { type: 'string', description: '邮箱' },
41
+ phone: { type: 'string', description: '电话' },
42
+ gender: { type: 'string', description: '性别' },
43
+ birthday: { type: 'string', format: 'date', description: '出生日期' },
44
+ description: { type: 'string', description: '个人简介' },
45
+ currentTenantId: { type: 'string', description: '当前租户ID' },
46
+ status: { type: 'number', description: '状态' }
47
+ }
48
+ }
49
+ }
50
+ }
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
20
56
  },
21
57
  async request => {
22
58
  return { userInfo: request.userInfo };
23
59
  }
24
60
  );
25
61
 
62
+ fastify.post(
63
+ `${options.prefix}/admin/setSuperAdmin`,
64
+ {
65
+ onRequest: [authenticate.user, authenticate.admin],
66
+ schema: {
67
+ tags: ['管理后台'],
68
+ summary: '设置用户为超级管理员',
69
+ body: {
70
+ type: 'object',
71
+ required: ['status', 'userId'],
72
+ properties: {
73
+ status: { type: 'boolean', description: 'true:将用户设置为超级管理员,false:取消用户超级管理员' },
74
+ userId: { type: 'string', description: '用户ID' }
75
+ }
76
+ }
77
+ }
78
+ },
79
+ async request => {
80
+ const { status, userId } = request.body;
81
+ await services.admin[status ? 'setSuperAdmin' : 'cancelSuperAdmin'](await services.user.getUser({ id: userId }));
82
+ return {};
83
+ }
84
+ );
85
+
26
86
  fastify.post(
27
87
  `${options.prefix}/admin/addUser`,
28
88
  {
29
- onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.admin],
89
+ onRequest: [authenticate.user, authenticate.admin],
30
90
  schema: {
91
+ tags: ['管理后台'],
92
+ summary: '添加用户',
31
93
  body: {}
32
94
  }
33
95
  },
34
96
  async request => {
35
97
  const userInfo = request.body;
36
- await fastify.account.services.admin.addUser(Object.assign({}, userInfo, { password: options.defaultPassword }));
98
+ await services.admin.addUser(Object.assign({}, userInfo, { password: services.account.md5(options.defaultPassword) }));
37
99
  return {};
38
100
  }
39
101
  );
@@ -41,9 +103,14 @@ module.exports = fp(async (fastify, options) => {
41
103
  fastify.get(
42
104
  `${options.prefix}/admin/getAllUserList`,
43
105
  {
44
- onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.admin],
106
+ onRequest: [authenticate.user, authenticate.admin],
45
107
  schema: {
46
- query: {}
108
+ tags: ['管理后台'],
109
+ summary: '获取用户列表',
110
+ query: {
111
+ perPage: { type: 'number' },
112
+ currentPage: { type: 'number' }
113
+ }
47
114
  }
48
115
  },
49
116
  async request => {
@@ -54,7 +121,7 @@ module.exports = fp(async (fastify, options) => {
54
121
  },
55
122
  request.query
56
123
  );
57
- return await fastify.account.services.admin.getAllUserList({
124
+ return await services.user.getAllUserList({
58
125
  filter,
59
126
  perPage,
60
127
  currentPage
@@ -65,8 +132,10 @@ module.exports = fp(async (fastify, options) => {
65
132
  fastify.post(
66
133
  `${options.prefix}/admin/resetUserPassword`,
67
134
  {
68
- onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.admin],
135
+ onRequest: [authenticate.user, authenticate.admin],
69
136
  schema: {
137
+ tags: ['管理后台'],
138
+ summary: '重置用户账号密码',
70
139
  body: {
71
140
  type: 'object',
72
141
  required: ['userId', 'password'],
@@ -78,7 +147,7 @@ module.exports = fp(async (fastify, options) => {
78
147
  }
79
148
  },
80
149
  async request => {
81
- await fastify.account.services.admin.resetUserPassword(request.body);
150
+ await services.admin.resetUserPassword(request.body);
82
151
  return {};
83
152
  }
84
153
  );
@@ -86,8 +155,10 @@ module.exports = fp(async (fastify, options) => {
86
155
  fastify.post(
87
156
  `${options.prefix}/admin/saveUser`,
88
157
  {
89
- onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.admin],
158
+ onRequest: [authenticate.user, authenticate.admin],
90
159
  schema: {
160
+ tags: ['管理后台'],
161
+ summary: '修改用户信息',
91
162
  body: {
92
163
  type: 'object',
93
164
  required: ['id'],
@@ -104,7 +175,7 @@ module.exports = fp(async (fastify, options) => {
104
175
  },
105
176
  async request => {
106
177
  const user = request.body;
107
- await fastify.account.services.user.saveUser(user);
178
+ await services.user.saveUser(user);
108
179
  return {};
109
180
  }
110
181
  );
@@ -112,8 +183,10 @@ module.exports = fp(async (fastify, options) => {
112
183
  fastify.post(
113
184
  `${options.prefix}/admin/closeUser`,
114
185
  {
115
- onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.admin],
186
+ onRequest: [authenticate.user, authenticate.admin],
116
187
  schema: {
188
+ tags: ['管理后台'],
189
+ summary: '关闭用户',
117
190
  body: {
118
191
  type: 'object',
119
192
  required: ['id'],
@@ -125,7 +198,7 @@ module.exports = fp(async (fastify, options) => {
125
198
  },
126
199
  async request => {
127
200
  const { id } = request.body;
128
- await fastify.account.services.user.closeUser({ id });
201
+ await services.user.closeUser({ id });
129
202
  return {};
130
203
  }
131
204
  );
@@ -133,8 +206,10 @@ module.exports = fp(async (fastify, options) => {
133
206
  fastify.post(
134
207
  `${options.prefix}/admin/openUser`,
135
208
  {
136
- onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.admin],
209
+ onRequest: [authenticate.user, authenticate.admin],
137
210
  schema: {
211
+ tags: ['管理后台'],
212
+ summary: '将用户设置为正常',
138
213
  body: {
139
214
  type: 'object',
140
215
  required: ['id'],
@@ -146,7 +221,7 @@ module.exports = fp(async (fastify, options) => {
146
221
  },
147
222
  async request => {
148
223
  const { id } = request.body;
149
- await fastify.account.services.user.openUser({ id });
224
+ await services.user.openUser({ id });
150
225
  return {};
151
226
  }
152
227
  );
@@ -1,11 +1,15 @@
1
1
  const fp = require('fastify-plugin');
2
+ const { Readable } = require('stream');
2
3
 
3
4
  module.exports = fp(async (fastify, options) => {
5
+ const { authenticate, services } = fastify.account;
4
6
  fastify.post(
5
7
  `${options.prefix}/admin/addApplication`,
6
8
  {
7
- onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.admin],
9
+ onRequest: [authenticate.user, authenticate.admin],
8
10
  schema: {
11
+ tags: ['管理后台-权限'],
12
+ summary: '添加应用',
9
13
  body: {
10
14
  type: 'object',
11
15
  required: ['name', 'code'],
@@ -20,7 +24,7 @@ module.exports = fp(async (fastify, options) => {
20
24
  }
21
25
  },
22
26
  async request => {
23
- await fastify.account.services.permission.addApplication(request.body);
27
+ await services.application.addApplication(request.body);
24
28
  return {};
25
29
  }
26
30
  );
@@ -28,8 +32,10 @@ module.exports = fp(async (fastify, options) => {
28
32
  fastify.post(
29
33
  `${options.prefix}/admin/saveApplication`,
30
34
  {
31
- onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.admin],
35
+ onRequest: [authenticate.user, authenticate.admin],
32
36
  schema: {
37
+ tags: ['管理后台-权限'],
38
+ summary: '修改应用',
33
39
  body: {
34
40
  type: 'object',
35
41
  required: ['id', 'name', 'code'],
@@ -45,7 +51,7 @@ module.exports = fp(async (fastify, options) => {
45
51
  }
46
52
  },
47
53
  async request => {
48
- await fastify.account.services.permission.saveApplication(request.body);
54
+ await services.application.saveApplication(request.body);
49
55
  return {};
50
56
  }
51
57
  );
@@ -53,8 +59,10 @@ module.exports = fp(async (fastify, options) => {
53
59
  fastify.post(
54
60
  `${options.prefix}/admin/deleteApplication`,
55
61
  {
56
- onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.admin],
62
+ onRequest: [authenticate.user, authenticate.admin],
57
63
  schema: {
64
+ tags: ['管理后台-权限'],
65
+ summary: '删除应用',
58
66
  body: {
59
67
  type: 'object',
60
68
  required: ['id'],
@@ -66,7 +74,7 @@ module.exports = fp(async (fastify, options) => {
66
74
  },
67
75
  async request => {
68
76
  const { id } = request.body;
69
- await fastify.account.services.permission.deleteApplication({ id });
77
+ await services.application.deleteApplication({ id });
70
78
  return {};
71
79
  }
72
80
  );
@@ -74,8 +82,10 @@ module.exports = fp(async (fastify, options) => {
74
82
  fastify.get(
75
83
  `${options.prefix}/admin/getApplicationList`,
76
84
  {
77
- onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.admin],
85
+ onRequest: [authenticate.user, authenticate.admin],
78
86
  schema: {
87
+ tags: ['管理后台-权限'],
88
+ summary: '获取应用列表',
79
89
  query: {
80
90
  type: 'object',
81
91
  properties: {
@@ -86,15 +96,17 @@ module.exports = fp(async (fastify, options) => {
86
96
  },
87
97
  async request => {
88
98
  const { tenantId } = request.query;
89
- return await fastify.account.services.permission.getApplicationList({ tenantId });
99
+ return await services.application.getApplicationList({ tenantId });
90
100
  }
91
101
  );
92
102
 
93
103
  fastify.post(
94
104
  `${options.prefix}/admin/addPermission`,
95
105
  {
96
- onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.admin],
106
+ onRequest: [authenticate.user, authenticate.admin],
97
107
  schema: {
108
+ tags: ['管理后台-权限'],
109
+ summary: '添加应用权限',
98
110
  body: {
99
111
  type: 'object',
100
112
  required: ['applicationId', 'name', 'code'],
@@ -112,7 +124,7 @@ module.exports = fp(async (fastify, options) => {
112
124
  }
113
125
  },
114
126
  async request => {
115
- await fastify.account.services.permission.addPermission(request.body);
127
+ await services.permission.addPermission(request.body);
116
128
  return {};
117
129
  }
118
130
  );
@@ -120,8 +132,10 @@ module.exports = fp(async (fastify, options) => {
120
132
  fastify.get(
121
133
  `${options.prefix}/admin/getPermissionList`,
122
134
  {
123
- onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.admin],
135
+ onRequest: [authenticate.user, authenticate.admin],
124
136
  schema: {
137
+ tags: ['管理后台-权限'],
138
+ summary: '获取应用权限列表',
125
139
  query: {
126
140
  type: 'object',
127
141
  required: ['applicationId'],
@@ -129,20 +143,121 @@ module.exports = fp(async (fastify, options) => {
129
143
  applicationId: { type: 'string' },
130
144
  tenantId: { type: 'string' }
131
145
  }
146
+ },
147
+ response: {
148
+ 200: {
149
+ content: {
150
+ 'application/json': {
151
+ schema: {
152
+ type: 'array',
153
+ items: {
154
+ type: 'object',
155
+ properties: {
156
+ id: { type: 'number' },
157
+ code: { type: 'string' },
158
+ name: { type: 'string' },
159
+ isModule: { type: 'number' },
160
+ isMust: { type: 'number' },
161
+ type: { type: 'number' },
162
+ pid: { type: 'number' },
163
+ paths: { type: 'array', items: { type: 'number' } },
164
+ description: { type: 'string' },
165
+ status: { type: 'number' },
166
+ createdAt: { type: 'string' },
167
+ updatedAt: { type: 'string' },
168
+ deletedAt: { type: 'string' }
169
+ }
170
+ }
171
+ }
172
+ }
173
+ }
174
+ }
132
175
  }
133
176
  }
134
177
  },
135
178
  async request => {
136
179
  const { applicationId, tenantId } = request.query;
137
- return await fastify.account.services.permission.getPermissionList({ applicationId, tenantId });
180
+ return await services.permission.getPermissionList({ applicationId, tenantId });
181
+ }
182
+ );
183
+
184
+ fastify.post(`${options.prefix}/admin/parsePermissionList`, {}, async request => {
185
+ const file = await request.file();
186
+ if (!file) {
187
+ throw new Error('不能获取到上传文件');
188
+ }
189
+
190
+ return await services.permission.parsePermissionListJSON({ file });
191
+ });
192
+
193
+ fastify.post(
194
+ `${options.prefix}/admin/exportPermissionList`,
195
+ {
196
+ onRequest: [authenticate.user, authenticate.admin],
197
+ schema: {
198
+ tags: ['管理后台-权限'],
199
+ summary: '导出应用权限列表',
200
+ body: {
201
+ type: 'object',
202
+ required: ['applicationIds'],
203
+ properties: {
204
+ applicationIds: { type: 'array', items: { type: 'string' } },
205
+ tenantId: { type: 'string' }
206
+ }
207
+ },
208
+ response: {
209
+ 200: {
210
+ content: {
211
+ 'application/json': {
212
+ schema: {
213
+ type: 'array',
214
+ items: {
215
+ type: 'object',
216
+ properties: {
217
+ code: { type: 'string' },
218
+ name: { type: 'string' },
219
+ url: { type: 'string' },
220
+ description: { type: 'string' },
221
+ status: { type: 'number' },
222
+ permissions: {
223
+ type: 'array',
224
+ items: {
225
+ type: 'object',
226
+ properties: {
227
+ id: { type: 'number' },
228
+ code: { type: 'string' },
229
+ name: { type: 'string' },
230
+ isModule: { type: 'number' },
231
+ isMust: { type: 'number' },
232
+ type: { type: 'number' },
233
+ pid: { type: 'number' },
234
+ description: { type: 'string' },
235
+ status: { type: 'number' }
236
+ }
237
+ }
238
+ }
239
+ }
240
+ }
241
+ }
242
+ }
243
+ }
244
+ }
245
+ }
246
+ }
247
+ },
248
+ async request => {
249
+ const { applicationIds, tenantId } = request.body;
250
+ return await services.permission.exportPermissionList({ applicationIds, tenantId });
138
251
  }
139
252
  );
140
253
 
141
254
  fastify.post(
142
255
  `${options.prefix}/admin/deletePermission`,
143
256
  {
144
- onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.admin],
257
+ onRequest: [authenticate.user, authenticate.admin],
145
258
  schema: {
259
+ tags: ['管理后台-权限'],
260
+ summary: '删除应用权限',
146
261
  body: {
147
262
  type: 'object',
148
263
  required: ['id'],
@@ -155,7 +270,7 @@ module.exports = fp(async (fastify, options) => {
155
270
  async request => {
156
271
  const { id } = request.body;
157
272
 
158
- await fastify.account.services.permission.deletePermission({ id });
273
+ await services.permission.deletePermission({ id });
159
274
 
160
275
  return {};
161
276
  }
@@ -164,8 +279,10 @@ module.exports = fp(async (fastify, options) => {
164
279
  fastify.post(
165
280
  `${options.prefix}/admin/savePermission`,
166
281
  {
167
- onRequest: [fastify.account.authenticate.user, fastify.account.authenticate.admin],
282
+ onRequest: [authenticate.user, authenticate.admin],
168
283
  schema: {
284
+ tags: ['管理后台-权限'],
285
+ summary: '修改应用权限',
169
286
  body: {
170
287
  type: 'object',
171
288
  required: ['id'],
@@ -180,51 +297,84 @@ module.exports = fp(async (fastify, options) => {
180
297
  }
181
298
  },
182
299
  async request => {
183
- await fastify.account.services.permission.savePermission(request.body);
300
+ await services.permission.savePermission(request.body);
184
301
  return {};
185
302
  }
186
303
  );
187
304
 
305
+ fastify.get(
306
+ `${options.prefix}/admin/getTenantPermissionList`,
307
+ {
308
+ onRequest: [authenticate.user, authenticate.admin],
309
+ schema: {
310
+ tags: ['管理后台-权限'],
311
+ summary: '获取租户应用权限配置',
312
+ query: {
313
+ type: 'object',
314
+ required: ['tenantId'],
315
+ properties: {
316
+ tenantId: { type: 'string' }
317
+ }
318
+ }
319
+ }
320
+ },
321
+ async request => {
322
+ const { tenantId } = request.query;
323
+ return await services.permission.getTenantPermissionList({ tenantId });
324
+ }
325
+ );
326
+
188
327
  fastify.post(
189
328
  `${options.prefix}/admin/saveTenantPermissionList`,
190
329
  {
191
- body: {
192
- type: 'object',
193
- required: ['tenantId', 'applications', 'permissions'],
194
- properties: {
195
- tenantId: { type: 'string' },
196
- applications: {
197
- type: 'array',
198
- items: { type: 'string' }
199
- },
200
- permissions: {
201
- type: 'array',
202
- items: { type: 'number' }
330
+ onRequest: [authenticate.user, authenticate.admin],
331
+ schema: {
332
+ tags: ['管理后台-权限'],
333
+ summary: '修改租户应用权限配置',
334
+ body: {
335
+ type: 'object',
336
+ required: ['tenantId', 'applications', 'permissions'],
337
+ properties: {
338
+ tenantId: { type: 'string' },
339
+ applications: {
340
+ type: 'array',
341
+ items: { type: 'string' }
342
+ },
343
+ permissions: {
344
+ type: 'array',
345
+ items: { type: 'number' }
346
+ }
203
347
  }
204
348
  }
205
349
  }
206
350
  },
207
351
  async request => {
208
- await fastify.account.services.permission.saveTenantPermissionList(request.body);
352
+ await services.permission.saveTenantPermissionList(request.body);
209
353
 
210
354
  return {};
211
355
  }
212
356
  );
213
357
 
214
- fastify.get(
215
- `${options.prefix}/admin/getTenantPermissionList`,
358
+ fastify.post(
359
+ `${options.prefix}/admin/copyPermissions`,
216
360
  {
217
- query: {
218
- type: 'object',
219
- required: ['tenantId'],
220
- properties: {
221
- tenantId: { type: 'string' }
361
+ onRequest: [authenticate.user, authenticate.admin],
362
+ schema: {
363
+ tags: ['管理后台-权限'],
364
+ summary: '复制应用权限到目标应用',
365
+ body: {
366
+ type: 'object',
367
+ required: ['applicationId', 'originApplicationId'],
368
+ properties: {
369
+ applicationId: { type: 'string' },
370
+ originApplicationId: { type: 'string' }
371
+ }
222
372
  }
223
373
  }
224
374
  },
225
375
  async request => {
226
- const { tenantId } = request.query;
227
- return await fastify.account.services.permission.getTenantPermissionList({ tenantId });
376
+ await services.permission.copyPermissions(request.body);
377
+ return {};
228
378
  }
229
379
  );
230
380
  });