@kne/fastify-file-manager 3.0.8 → 3.0.9

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,7 +1,23 @@
1
1
  const fp = require('fastify-plugin');
2
+ const { num, list, success, empty, fileRecordProperties, fileRecord, folderNode, folderTreeNode } = require('../schema/response');
2
3
 
3
4
  const DEFAULT_FOLDER_TYPE = 'admin-file-system';
4
5
 
6
+ const TAG_FILE = '文件管理-文件';
7
+ const TAG_LIBRARY = '文件管理-文件库';
8
+ const TAG_FOLDER = '文件管理-文件夹';
9
+
10
+ const uploadedRecord = description =>
11
+ success(description, {
12
+ type: 'object',
13
+ additionalProperties: true,
14
+ properties: Object.assign({}, fileRecordProperties, {
15
+ folder: Object.assign({}, folderNode, { description: '自动挂载到文件系统生成的文件节点;同目录已挂载同一文件时不重复挂载,此时无该字段' })
16
+ })
17
+ });
18
+
19
+ const TENANT_ID = '租户 ID;接口不校验,按原样传给文件夹服务用于隔离不同租户的树(通常由宿主鉴权钩子注入)';
20
+
5
21
  const readMultipartField = (file, name) => {
6
22
  const field = file?.fields?.[name];
7
23
  if (!field) {
@@ -51,9 +67,10 @@ module.exports = fp(async (fastify, options) => {
51
67
  {
52
68
  onRequest: options.createAuthenticate('file:write'),
53
69
  schema: {
70
+ tags: [TAG_FILE],
54
71
  summary: '上传文件',
55
72
  description:
56
- '上传单个文件到服务器或配置的存储服务。保存成功后自动挂到文件系统(默认 type=admin-file-system,未传 path 时挂到根目录;传 path 则按路径创建并挂载)',
73
+ '上传单个文件到服务器或配置的存储服务。保存成功后自动挂到文件系统(默认 type=admin-file-system,未传 path 时挂到根目录;传 path 则按路径创建并挂载)。请求为 multipart/form-data,文件字段名为 file;path、type、language 也可作为表单字段传入(query 优先)',
57
74
  query: {
58
75
  type: 'object',
59
76
  properties: {
@@ -68,7 +85,8 @@ module.exports = fp(async (fastify, options) => {
68
85
  },
69
86
  language: { type: 'string', description: '语言' }
70
87
  }
71
- }
88
+ },
89
+ response: uploadedRecord('上传后的文件记录,挂载到文件系统时带 folder')
72
90
  }
73
91
  },
74
92
  async request => {
@@ -91,13 +109,14 @@ module.exports = fp(async (fastify, options) => {
91
109
  {
92
110
  onRequest: options.createAuthenticate('file:write'),
93
111
  schema: {
112
+ tags: [TAG_FILE],
94
113
  summary: '上传URL文件',
95
114
  description:
96
- '上传单个文件到服务器或配置的存储服务。保存成功后自动挂到文件系统(默认 type=admin-file-system,未传 path 时挂到根目录;传 path 则按路径创建并挂载)',
115
+ '服务端下载 url 指向的文件并保存到服务器或配置的存储服务,文件名优先取 url 的 filename 参数,其次响应头 Content-Disposition,再次 url 路径末段。保存成功后自动挂到文件系统(默认 type=admin-file-system,未传 path 时挂到根目录;传 path 则按路径创建并挂载)',
97
116
  body: {
98
117
  type: 'object',
99
118
  properties: {
100
- url: { type: 'string', description: '文件url' },
119
+ url: { type: 'string', description: '文件url,服务端会发起下载,下载失败返回错误' },
101
120
  namespace: { type: 'string', description: '文件分类命名空间' },
102
121
  path: {
103
122
  type: 'string',
@@ -109,7 +128,8 @@ module.exports = fp(async (fastify, options) => {
109
128
  },
110
129
  language: { type: 'string', description: '语言' }
111
130
  }
112
- }
131
+ },
132
+ response: uploadedRecord('保存后的文件记录,挂载到文件系统时带 folder')
113
133
  }
114
134
  },
115
135
  async request => {
@@ -128,14 +148,18 @@ module.exports = fp(async (fastify, options) => {
128
148
  {
129
149
  onRequest: options.createAuthenticate('file:read'),
130
150
  schema: {
151
+ tags: [TAG_FILE],
131
152
  summary: '获取文件url',
132
- description: '获取文件url',
153
+ description: '获取文件访问地址:本地存储返回 {prefix}/file/{hash}{扩展名}?filename={文件名}(本地文件不存在返回 404),OSS 存储返回 ossAdapter.getFileLink 的结果',
133
154
  params: {
134
155
  type: 'object',
135
156
  required: ['id'],
136
157
  properties: {
137
- id: { type: 'string', description: '文件id' }
158
+ id: { type: 'string', description: '文件id(uuid,兼容主键)' }
138
159
  }
160
+ },
161
+ response: {
162
+ 200: { description: '文件访问地址;本地存储时为 text/plain 字符串' }
139
163
  }
140
164
  }
141
165
  },
@@ -150,21 +174,25 @@ module.exports = fp(async (fastify, options) => {
150
174
  {
151
175
  onRequest: options.createAuthenticate('file:read'),
152
176
  schema: {
177
+ tags: [TAG_FILE],
153
178
  summary: '获取文件信息',
154
- description: '获取文件信息',
179
+ description: '直接输出文件内容(非 JSON):OSS 存储下载后按原 MIME 类型返回;本地存储通过静态文件服务返回。attachment 为 true 时以附件形式下载',
155
180
  query: {
156
181
  type: 'object',
157
182
  properties: {
158
- attachment: { type: 'boolean', description: '是否下载' },
159
- filename: { type: 'string', description: '下载文件名' }
183
+ attachment: { type: 'boolean', description: '是否下载(Content-Disposition: attachment)' },
184
+ filename: { type: 'string', description: '下载文件名,默认原文件名' }
160
185
  }
161
186
  },
162
187
  params: {
163
188
  type: 'object',
164
189
  required: ['id'],
165
190
  properties: {
166
- id: { type: 'string', description: '文件id' }
191
+ id: { type: 'string', description: '文件id(uuid,兼容主键)' }
167
192
  }
193
+ },
194
+ response: {
195
+ 200: { description: '文件二进制内容,Content-Type 为文件 MIME 类型' }
168
196
  }
169
197
  }
170
198
  },
@@ -189,23 +217,36 @@ module.exports = fp(async (fastify, options) => {
189
217
  {
190
218
  onRequest: options.createAuthenticate('file:mange'),
191
219
  schema: {
220
+ tags: [TAG_LIBRARY],
192
221
  summary: '获取文件列表',
193
- description: '查询指定命名空间下的文件列表',
222
+ description: '分页查询文件库,按创建时间倒序',
194
223
  body: {
195
224
  type: 'object',
196
225
  properties: {
197
- perPage: { type: 'number', description: '每页数量' },
198
- currentPage: { type: 'number', description: '当前页数' },
226
+ perPage: { type: 'number', description: '每页数量,默认 20' },
227
+ currentPage: { type: 'number', description: '当前页数,默认 1' },
199
228
  filter: {
200
229
  type: 'object',
230
+ description: '筛选条件',
201
231
  properties: {
202
- namespace: { type: 'string', description: '文件分类命名空间' },
203
- size: { type: 'array', items: { type: 'number' }, description: '文件大小' },
204
- filename: { type: 'string', description: '文件名' }
232
+ id: { description: '按文件 uuid 精确匹配' },
233
+ namespace: { type: 'string', description: '文件分类命名空间,模糊匹配' },
234
+ size: { type: 'array', items: { type: 'number' }, description: '文件大小范围 [最小, 最大],单位 KB,0 或空表示不限' },
235
+ filename: { type: 'string', description: '文件名,模糊匹配' },
236
+ createdAt: { description: '创建时间范围,形如 { startTime, endTime },可只传其一' },
237
+ updatedAt: { description: '更新时间范围,形如 { startTime, endTime },可只传其一' }
205
238
  }
206
239
  }
207
240
  }
208
- }
241
+ },
242
+ response: success('文件分页列表', {
243
+ type: 'object',
244
+ additionalProperties: true,
245
+ properties: {
246
+ pageData: list('当前页文件列表', fileRecord),
247
+ totalCount: num('符合条件的文件总数')
248
+ }
249
+ })
209
250
  }
210
251
  },
211
252
  async request => {
@@ -232,14 +273,16 @@ module.exports = fp(async (fastify, options) => {
232
273
  {
233
274
  onRequest: options.createAuthenticate('file:mange'),
234
275
  schema: {
276
+ tags: [TAG_LIBRARY],
235
277
  summary: '替换文件',
236
- description: '替换文件',
278
+ description: '用上传的新文件(multipart/form-data,字段名 file)覆盖指定文件记录的内容与文件名,文件 id 不变;未传 id 时新建文件记录。不会挂载到文件系统',
237
279
  query: {
238
280
  type: 'object',
239
281
  properties: {
240
- id: { type: 'string', description: '文件id' }
282
+ id: { type: 'string', description: '要替换的文件id(uuid,兼容主键)' }
241
283
  }
242
- }
284
+ },
285
+ response: success('替换后的文件记录', fileRecord)
243
286
  }
244
287
  },
245
288
  async request => {
@@ -256,15 +299,17 @@ module.exports = fp(async (fastify, options) => {
256
299
  {
257
300
  onRequest: options.createAuthenticate('file:mange'),
258
301
  schema: {
302
+ tags: [TAG_LIBRARY],
259
303
  summary: '重命名文件',
260
- description: '重命名文件',
304
+ description: '修改文件记录的文件名;新文件名无扩展名时沿用原扩展名,非法字符替换为下划线',
261
305
  body: {
262
306
  type: 'object',
263
307
  properties: {
264
- id: { type: 'string', description: '文件id' },
308
+ id: { type: 'string', description: '文件id(uuid,兼容主键)' },
265
309
  filename: { type: 'string', description: '新文件名' }
266
310
  }
267
- }
311
+ },
312
+ response: empty('重命名成功')
268
313
  }
269
314
  },
270
315
  async request => {
@@ -278,15 +323,17 @@ module.exports = fp(async (fastify, options) => {
278
323
  {
279
324
  onRequest: options.createAuthenticate('file:mange'),
280
325
  schema: {
326
+ tags: [TAG_LIBRARY],
281
327
  summary: '删除文件',
282
- description: '删除文件',
328
+ description: '按 uuid 删除文件记录(不删除存储中的文件实体,也不删除文件夹树中引用它的节点)',
283
329
  body: {
284
330
  type: 'object',
285
331
  required: ['ids'],
286
332
  properties: {
287
- ids: { type: 'array', items: { type: 'string' }, description: '文件id列表' }
333
+ ids: { type: 'array', items: { type: 'string' }, description: '文件id(uuid)列表' }
288
334
  }
289
- }
335
+ },
336
+ response: empty('删除成功')
290
337
  }
291
338
  },
292
339
  async request => {
@@ -301,15 +348,19 @@ module.exports = fp(async (fastify, options) => {
301
348
  {
302
349
  onRequest: options.createAuthenticate('file:mange'),
303
350
  schema: {
351
+ tags: [TAG_LIBRARY],
304
352
  summary: '批量下载压缩包',
305
- description: '将选中文件打包为 zip 并下载',
353
+ description: '将选中文件打包为 zip 并下载;无效文件会被跳过,全部无效时返回错误',
306
354
  body: {
307
355
  type: 'object',
308
356
  required: ['ids'],
309
357
  properties: {
310
- ids: { type: 'array', items: { type: 'string' }, description: '文件id列表' },
358
+ ids: { type: 'array', items: { type: 'string' }, description: '文件id(uuid)列表' },
311
359
  filename: { type: 'string', description: '下载压缩包文件名,默认 files.zip' }
312
360
  }
361
+ },
362
+ response: {
363
+ 200: { description: 'zip 压缩包文件流,Content-Type 为 application/zip,以附件形式下载' }
313
364
  }
314
365
  }
315
366
  },
@@ -355,16 +406,19 @@ module.exports = fp(async (fastify, options) => {
355
406
  {
356
407
  onRequest: folderOnRequest('read', 'query'),
357
408
  schema: {
409
+ tags: [TAG_FOLDER],
358
410
  summary: '获取文件夹树',
359
- description: '获取指定 type 的文件树;kind=folder 时仅返回文件夹节点;未传 type 时使用 defaultFolderType',
411
+ description: '获取指定 type 的文件树;kind=folder 时仅返回文件夹节点;未传 type 时使用 defaultFolderType。文件节点会补充文件记录的 size、mimetype、filename 与时间',
360
412
  query: {
361
413
  type: 'object',
362
414
  properties: {
363
415
  type: { type: 'string', description: '业务域类型,默认 admin-file-system' },
364
416
  language: { type: 'string', description: '语言' },
365
- kind: { type: 'string', description: '传 folder 时仅返回文件夹树' }
417
+ kind: { type: 'string', description: '传 folder(或 foldersOnly)时仅返回文件夹树' },
418
+ tenantId: { description: TENANT_ID }
366
419
  }
367
- }
420
+ },
421
+ response: success('根节点列表,子节点在 children 中', { type: 'array', items: folderTreeNode })
368
422
  }
369
423
  },
370
424
  async request => {
@@ -377,8 +431,9 @@ module.exports = fp(async (fastify, options) => {
377
431
  {
378
432
  onRequest: folderOnRequest('read', 'body'),
379
433
  schema: {
434
+ tags: [TAG_FOLDER],
380
435
  summary: '分页获取目录子节点',
381
- description: '按 parentId 分页列出直接子节点;文件夹优先,再按名称排序;未传 type 时使用 defaultFolderType',
436
+ description: '按 parentId 分页列出直接子节点;文件夹优先,再按名称排序;未传 type 时使用 defaultFolderType。perPage 最大 200',
382
437
  body: {
383
438
  type: 'object',
384
439
  properties: {
@@ -389,7 +444,15 @@ module.exports = fp(async (fastify, options) => {
389
444
  keyword: { type: 'string', description: '按名称模糊搜索' },
390
445
  language: { type: 'string', description: '语言' }
391
446
  }
392
- }
447
+ },
448
+ response: success('子节点分页列表', {
449
+ type: 'object',
450
+ additionalProperties: true,
451
+ properties: {
452
+ pageData: list('当前页子节点列表', folderNode),
453
+ totalCount: num('直接子节点总数')
454
+ }
455
+ })
393
456
  }
394
457
  },
395
458
  async request => {
@@ -417,18 +480,21 @@ module.exports = fp(async (fastify, options) => {
417
480
  {
418
481
  onRequest: getFolderAuthenticate('write'),
419
482
  schema: {
483
+ tags: [TAG_FOLDER],
420
484
  summary: '新建文件夹',
421
- description: '在指定 type 下创建文件夹节点',
485
+ description: '在指定 type 下创建文件夹节点;同一文件夹下重名返回错误',
422
486
  body: {
423
487
  type: 'object',
424
488
  required: ['type', 'name'],
425
489
  properties: {
426
490
  type: { type: 'string', description: '业务域类型' },
427
491
  name: { type: 'string', description: '文件夹名称' },
428
- parentId: { type: 'string', description: '父文件夹 id' },
429
- language: { type: 'string', description: '语言' }
492
+ parentId: { type: 'string', description: '父文件夹 id,不传为根目录' },
493
+ language: { type: 'string', description: '语言' },
494
+ tenantId: { description: TENANT_ID }
430
495
  }
431
- }
496
+ },
497
+ response: success('创建的文件夹节点', folderNode)
432
498
  }
433
499
  },
434
500
  async request => {
@@ -441,8 +507,9 @@ module.exports = fp(async (fastify, options) => {
441
507
  {
442
508
  onRequest: getFolderAuthenticate('write'),
443
509
  schema: {
510
+ tags: [TAG_FOLDER],
444
511
  summary: '上传文件到文件夹',
445
- description: '上传文件实体并在 group 中创建文件节点。通过 path 定位目标目录(经 ensurePath 解析/创建;空字符串为根目录)',
512
+ description: '上传文件实体(multipart/form-data,字段名 file)并在 group 中创建文件节点。通过 path 定位目标目录(经 ensurePath 解析/创建;空字符串为根目录);同目录重名时文件名自动追加 [_时间戳]',
446
513
  query: {
447
514
  type: 'object',
448
515
  required: ['type'],
@@ -452,7 +519,8 @@ module.exports = fp(async (fastify, options) => {
452
519
  namespace: { type: 'string', description: '文件命名空间' },
453
520
  language: { type: 'string', description: '语言' }
454
521
  }
455
- }
522
+ },
523
+ response: success('创建的文件节点,file 为上传的文件记录', Object.assign({}, folderNode, { properties: Object.assign({}, folderNode.properties, { file: fileRecord }) }))
456
524
  }
457
525
  },
458
526
  async request => {
@@ -475,17 +543,20 @@ module.exports = fp(async (fastify, options) => {
475
543
  {
476
544
  onRequest: getFolderAuthenticate('delete'),
477
545
  schema: {
546
+ tags: [TAG_FOLDER],
478
547
  summary: '删除文件夹节点',
479
- description: '递归删除节点及其子孙;文件节点同步删除 file-record',
548
+ description: '递归删除节点及其子孙;文件节点同步删除 file-record(linked 引用节点只删树节点,不删文件记录)',
480
549
  body: {
481
550
  type: 'object',
482
551
  required: ['type', 'id'],
483
552
  properties: {
484
553
  type: { type: 'string', description: '业务域类型' },
485
554
  id: { type: 'string', description: '节点 id' },
486
- language: { type: 'string', description: '语言' }
555
+ language: { type: 'string', description: '语言' },
556
+ tenantId: { description: TENANT_ID }
487
557
  }
488
- }
558
+ },
559
+ response: empty('删除成功')
489
560
  }
490
561
  },
491
562
  async request => {
@@ -498,8 +569,9 @@ module.exports = fp(async (fastify, options) => {
498
569
  {
499
570
  onRequest: getFolderAuthenticate('write'),
500
571
  schema: {
572
+ tags: [TAG_FOLDER],
501
573
  summary: '移动文件夹节点',
502
- description: '将一个或多个文件/文件夹节点移动到目标文件夹(parentId 为空表示根目录)',
574
+ description: '将一个或多个文件/文件夹节点移动到目标文件夹(parentId 为空表示根目录);目标须为文件夹,目标下重名返回错误',
503
575
  body: {
504
576
  type: 'object',
505
577
  required: ['type', 'ids'],
@@ -512,9 +584,11 @@ module.exports = fp(async (fastify, options) => {
512
584
  description: '要移动的节点 id 列表'
513
585
  },
514
586
  parentId: { type: ['string', 'null'], description: '目标父文件夹 id,空为根目录' },
515
- language: { type: 'string', description: '语言' }
587
+ language: { type: 'string', description: '语言' },
588
+ tenantId: { description: TENANT_ID }
516
589
  }
517
- }
590
+ },
591
+ response: success('移动后的节点列表', { type: 'array', items: folderNode })
518
592
  }
519
593
  },
520
594
  async request => {
@@ -527,6 +601,7 @@ module.exports = fp(async (fastify, options) => {
527
601
  {
528
602
  onRequest: getFolderAuthenticate('write'),
529
603
  schema: {
604
+ tags: [TAG_FOLDER],
530
605
  summary: '复制文件夹节点',
531
606
  description:
532
607
  '将一个或多个文件/文件夹节点复制到目标文件夹(parentId 为空表示根目录);文件以 linked 节点挂载,文件夹递归复制',
@@ -542,9 +617,11 @@ module.exports = fp(async (fastify, options) => {
542
617
  description: '要复制的节点 id 列表'
543
618
  },
544
619
  parentId: { type: ['string', 'null'], description: '目标父文件夹 id,空为根目录' },
545
- language: { type: 'string', description: '语言' }
620
+ language: { type: 'string', description: '语言' },
621
+ tenantId: { description: TENANT_ID }
546
622
  }
547
- }
623
+ },
624
+ response: success('复制生成的顶层节点列表(与 ids 一一对应)', { type: 'array', items: folderNode })
548
625
  }
549
626
  },
550
627
  async request => {
@@ -557,8 +634,9 @@ module.exports = fp(async (fastify, options) => {
557
634
  {
558
635
  onRequest: getFolderAuthenticate('write'),
559
636
  schema: {
637
+ tags: [TAG_FOLDER],
560
638
  summary: '重命名文件夹节点',
561
- description: '重命名文件或文件夹节点;文件节点同步更新 file-record 文件名',
639
+ description: '重命名文件或文件夹节点;文件节点同步更新 file-record 文件名(linked 引用节点只改树节点名称);同一文件夹下重名返回错误',
562
640
  body: {
563
641
  type: 'object',
564
642
  required: ['type', 'id', 'name'],
@@ -566,9 +644,11 @@ module.exports = fp(async (fastify, options) => {
566
644
  type: { type: 'string', description: '业务域类型' },
567
645
  id: { type: 'string', description: '节点 id' },
568
646
  name: { type: 'string', description: '新名称' },
569
- language: { type: 'string', description: '语言' }
647
+ language: { type: 'string', description: '语言' },
648
+ tenantId: { description: TENANT_ID }
570
649
  }
571
- }
650
+ },
651
+ response: success('重命名后的节点', folderNode)
572
652
  }
573
653
  },
574
654
  async request => {
@@ -582,6 +662,7 @@ module.exports = fp(async (fastify, options) => {
582
662
  onRequest: getFolderAuthenticate('write'),
583
663
  preHandler: withDefaultFolderType('body'),
584
664
  schema: {
665
+ tags: [TAG_FOLDER],
585
666
  summary: '将已有文件挂到文件夹树',
586
667
  description:
587
668
  '把文件库中已有文件以 linked 节点形式加入指定文件夹(parentId 为空表示根目录);删除该类节点不会删除文件库实体;未传 type 时使用 defaultFolderType',
@@ -597,9 +678,11 @@ module.exports = fp(async (fastify, options) => {
597
678
  description: '文件库 file-record id 列表'
598
679
  },
599
680
  parentId: { type: ['string', 'null'], description: '目标父文件夹 id,空为根目录' },
600
- language: { type: 'string', description: '语言' }
681
+ language: { type: 'string', description: '语言' },
682
+ tenantId: { description: TENANT_ID }
601
683
  }
602
- }
684
+ },
685
+ response: success('新挂载的文件节点列表;目标目录已挂载的文件会跳过,不出现在结果中', { type: 'array', items: folderNode })
603
686
  }
604
687
  },
605
688
  async request => {
@@ -0,0 +1,53 @@
1
+ // 响应 schema 会参与 fast-json-stringify 序列化:对象一律 additionalProperties: true 以免裁掉未声明字段;
2
+ // 用 nullable 而非类型数组(类型数组遇到不匹配的值会直接 500),类型不确定的字段(如 id、日期、JSON 列)只写说明不声明类型
3
+ const str = description => ({ type: 'string', nullable: true, description });
4
+ const num = description => ({ type: 'number', nullable: true, description });
5
+ const any = description => ({ description });
6
+ const list = (description, items) => ({ type: 'array', nullable: true, description, items });
7
+ const obj = (description, properties = {}) => ({ type: 'object', nullable: true, description, additionalProperties: true, properties });
8
+
9
+ const success = (description, schema) => ({
10
+ 200: Object.assign({}, schema || { type: 'object' }, { description })
11
+ });
12
+
13
+ const empty = (description = '操作成功,返回空对象') => success(description);
14
+
15
+ const fileRecordProperties = {
16
+ id: any('文件 ID(即 uuid),用于 file-url / file-id 等接口'),
17
+ uuid: any('文件 uuid'),
18
+ filename: str('文件名(已替换非法字符)'),
19
+ hash: str('文件内容 md5,存储文件名为 {hash}{扩展名}'),
20
+ namespace: str('文件分类命名空间'),
21
+ size: num('文件大小(字节)'),
22
+ encoding: str('上传编码'),
23
+ mimetype: str('文件 MIME 类型'),
24
+ storageType: str('存储类型:local 本地文件系统,oss 远程 OSS 存储'),
25
+ options: any('扩展字段(JSON)'),
26
+ createdAt: any('创建时间'),
27
+ updatedAt: any('更新时间'),
28
+ deletedAt: any('删除时间,未删除为 null')
29
+ };
30
+
31
+ const fileRecord = obj('文件记录', fileRecordProperties);
32
+
33
+ const folderNodeProperties = {
34
+ id: any('节点 ID'),
35
+ tenantId: any('租户 ID'),
36
+ type: str('业务域类型'),
37
+ code: str('节点编码'),
38
+ name: str('节点名称(文件节点为显示文件名)'),
39
+ language: str('语言'),
40
+ description: str('描述'),
41
+ index: num('排序'),
42
+ parentId: any('父文件夹节点 ID,根目录为 null'),
43
+ options: any('节点扩展信息(JSON):kind 节点类型 file/folder;文件节点含 fileId(文件 uuid)、size、mimetype、filename,linked 为 true 表示引用文件库已有文件(删除节点不删文件实体)'),
44
+ createdAt: any('创建时间(文件节点在树/列表中取文件记录的时间)'),
45
+ updatedAt: any('更新时间(文件节点在树/列表中取文件记录的时间)'),
46
+ deletedAt: any('删除时间,未删除为 null')
47
+ };
48
+
49
+ const folderNode = obj('文件夹树节点', folderNodeProperties);
50
+
51
+ const folderTreeNode = obj('文件夹树节点', Object.assign({}, folderNodeProperties, { children: list('子节点列表,结构同本节点', obj('子节点')) }));
52
+
53
+ module.exports = { str, num, any, list, obj, success, empty, fileRecordProperties, fileRecord, folderNodeProperties, folderNode, folderTreeNode };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kne/fastify-file-manager",
3
- "version": "3.0.8",
3
+ "version": "3.0.9",
4
4
  "description": "用于管理静态文件上传查看等",
5
5
  "main": "index.js",
6
6
  "scripts": {