@steedos-labs/plugin-workflow 3.0.64 → 3.0.66

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/designer/dist/amis-renderer/amis-renderer.css +1 -1
  2. package/designer/dist/amis-renderer/amis-renderer.js +1 -1
  3. package/designer/dist/assets/{index-IqLl5PBH.js → index-DX2PUSq4.js} +148 -148
  4. package/designer/dist/assets/index-YXPc2HMf.css +1 -0
  5. package/designer/dist/index.html +2 -2
  6. package/main/default/client/socket.client.js +43 -13
  7. package/main/default/manager/uuflow_manager.js +9 -2
  8. package/main/default/objects/flows/flows.object.yml +4 -9
  9. package/main/default/objects/instance_tasks/listviews/inbox.listview.yml +4 -1
  10. package/main/default/pages/flow_selector.page.amis.json +2 -2
  11. package/main/default/pages/flow_selector_mobile.page.amis.json +2 -2
  12. package/main/default/pages/page_instance_print.page.amis.json +108 -32
  13. package/main/default/routes/api_workflow_approve_save.router.js +7 -0
  14. package/main/default/routes/api_workflow_forward.router.js +4 -4
  15. package/main/default/routes/api_workflow_forward_refill.router.js +1 -1
  16. package/main/default/routes/api_workflow_instance_forward.router.js +4 -4
  17. package/main/default/routes/api_workflow_retrieve.router.js +64 -33
  18. package/main/default/services/instance.service.js +1 -0
  19. package/main/default/test/test_socket_reconnect.js +105 -0
  20. package/main/default/utils/designerManager.js +12 -0
  21. package/package.json +1 -1
  22. package/public/amis-renderer/amis-renderer.css +1 -1
  23. package/public/amis-renderer/amis-renderer.js +1 -1
  24. package/public/workflow/index.css +14 -10
  25. package/src/instance_record_queue.js +326 -207
  26. package/designer/dist/assets/index-DvvBwwsG.css +0 -1
@@ -81,12 +81,12 @@ tbody .color-priority-muted *{
81
81
  color: blue !important;
82
82
  }
83
83
 
84
- .instance-tasks-list .unread-instance .antd-Table-checkCell {
84
+ .steedos-object-listview .unread-instance .antd-Table-checkCell {
85
85
  position: relative
86
86
  }
87
87
 
88
88
  /* PC端未读列表蓝色圆点 */
89
- .instance-tasks-list .unread-instance .antd-Table-checkCell:before {
89
+ .steedos-object-listview .unread-instance .antd-Table-checkCell:before {
90
90
  content: " ";
91
91
  position: absolute;
92
92
  right: -6px;
@@ -98,19 +98,21 @@ tbody .color-priority-muted *{
98
98
  margin-top: -6px;
99
99
  }
100
100
 
101
- .instance-tasks-list .unread-instance .steedos-listview-item {
102
- position: relative
101
+ /* 分栏/手机端:含未读行的列表中所有行统一缩进,保持已读与未读左侧对齐 */
102
+ .steedos-object-listview:has(.unread-instance) .steedos-listview-item {
103
+ position: relative;
104
+ padding-left: 12px;
103
105
  }
104
106
 
105
- /* 手机端未读列表蓝色圆点 */
106
- .instance-tasks-list .unread-instance .steedos-listview-item:before {
107
+ /* 手机端及分栏模式未读列表蓝色圆点 */
108
+ .steedos-object-listview .unread-instance .steedos-listview-item:before {
107
109
  content: " ";
108
110
  position: absolute;
109
- left: -5px;
110
- width: 8px;
111
- height: 8px;
111
+ left: 0;
112
+ width: 10px;
113
+ height: 10px;
112
114
  background-color: #1890ff;
113
- border-radius: 4px;
115
+ border-radius: 5px;
114
116
  top: 10px;
115
117
  }
116
118
 
@@ -364,6 +366,8 @@ tbody .color-priority-muted *{
364
366
  .instance-form .td-childfield{
365
367
  padding: 0 !important;
366
368
  border: none !important;
369
+ max-width: 0;
370
+ overflow: hidden;
367
371
  }
368
372
 
369
373
  .steedos-instance-style-table .instance-form .td-childfield {
@@ -1,6 +1,110 @@
1
1
  // 审批单同步到台账
2
2
 
3
3
  const objectql = require('@steedos/objectql');
4
+ const crypto = require('crypto');
5
+ const fs = require('fs');
6
+ const pathModule = require('path');
7
+
8
+ // ========== 文件同步辅助函数 ==========
9
+
10
+ function getStorageConfig() {
11
+ try {
12
+ const config = objectql.getSteedosConfig();
13
+ return {
14
+ store: config?.cfs?.store || 'local',
15
+ storageDir: pathModule.resolve(config?.cfs?.storePath || process.env.STEEDOS_STORAGE_DIR || './steedos-storage')
16
+ };
17
+ } catch (e) {
18
+ return { store: 'local', storageDir: pathModule.resolve('./steedos-storage') };
19
+ }
20
+ }
21
+
22
+ function getCollectionFolderName(collectionName) {
23
+ const match = collectionName.match(/^cfs\.(\w+)\.filerecord$/);
24
+ return match ? match[1] : collectionName;
25
+ }
26
+
27
+ async function readFileBuffer(collectionName, fileRecord) {
28
+ // 优先使用 moleculer broker 读取(支持 local 和 S3)
29
+ try {
30
+ const broker = objectql.getSteedosSchema()?.broker;
31
+ if (broker) {
32
+ const folderName = getCollectionFolderName(collectionName);
33
+ return await broker.call('@builder6/files.getFileById', {
34
+ collectionName: folderName,
35
+ fileId: fileRecord._id
36
+ });
37
+ }
38
+ } catch (e) {
39
+ console.warn(`[syncAttach] broker.call getFileById failed for ${fileRecord._id}: ${e.message}`);
40
+ }
41
+
42
+ // 回退:从本地文件系统读取
43
+ const config = getStorageConfig();
44
+ if (config.store !== 'local') {
45
+ console.error(`[syncAttach] Cannot read file ${fileRecord._id}: S3 storage requires broker`);
46
+ return null;
47
+ }
48
+
49
+ const folderName = getCollectionFolderName(collectionName);
50
+ const storeKey = fileRecord.copies?.[folderName]?.key;
51
+ if (!storeKey) {
52
+ console.error(`[syncAttach] No storage key found for file ${fileRecord._id}`);
53
+ return null;
54
+ }
55
+
56
+ const filePath = pathModule.join(config.storageDir, 'files', folderName, storeKey);
57
+ if (fs.existsSync(filePath)) {
58
+ return fs.readFileSync(filePath);
59
+ }
60
+ console.error(`[syncAttach] File not found on disk: ${filePath}`);
61
+ return null;
62
+ }
63
+
64
+ async function uploadFileToCollection(collectionName, buffer, metadata, originalInfo) {
65
+ const config = getStorageConfig();
66
+ const folderName = getCollectionFolderName(collectionName);
67
+ const fileId = crypto.randomUUID();
68
+ const md5Hash = crypto.createHash('md5').update(buffer).digest('hex');
69
+ const now = new Date();
70
+ const year = now.getFullYear();
71
+ const month = String(now.getMonth() + 1).padStart(2, '0');
72
+ const fileName = originalInfo.name || 'file';
73
+ const objName = metadata.object_name || 'default';
74
+ const key = `${objName}/${year}/${month}/${fileId}-${fileName}`;
75
+
76
+ if (config.store === 'local') {
77
+ const filePath = pathModule.join(config.storageDir, 'files', folderName, key);
78
+ fs.mkdirSync(pathModule.dirname(filePath), { recursive: true });
79
+ fs.writeFileSync(filePath, buffer);
80
+ } else {
81
+ // S3: 通过 broker 上传(如果可用)
82
+ try {
83
+ const broker = objectql.getSteedosSchema()?.broker;
84
+ if (broker) {
85
+ // 目前 @builder6/files moleculer 没有 uploadFile action
86
+ // 回退到直接 MongoDB 记录(文件需要通过其他方式上传到 S3)
87
+ console.warn(`[syncAttach] S3 upload not supported via broker, file ${fileId} record created but binary not stored`);
88
+ }
89
+ } catch (e) {
90
+ console.error(`[syncAttach] S3 upload failed for ${fileId}: ${e.message}`);
91
+ }
92
+ }
93
+
94
+ const record = {
95
+ _id: fileId,
96
+ original: { type: originalInfo.type, size: buffer.length, name: fileName, md5: md5Hash },
97
+ metadata: { ...metadata },
98
+ uploadedAt: now,
99
+ copies: {
100
+ [folderName]: { name: fileName, type: originalInfo.type, size: buffer.length, key, updatedAt: now, createdAt: now }
101
+ }
102
+ };
103
+
104
+ const coll = await getCollection(collectionName);
105
+ await coll.insertOne(record);
106
+ return record;
107
+ }
4
108
 
5
109
  async function getCollection(name) {
6
110
  const adapter = objectql.getDataSource('default').adapter
@@ -129,56 +233,57 @@ const getFormField = function (_formFields, _fieldCode) {
129
233
  }
130
234
 
131
235
  const getFileFieldValue = async function (recordFieldId, fType) {
132
- var collection, files, query, value;
133
236
  if (_.isEmpty(recordFieldId)) {
134
237
  return;
135
238
  }
239
+
240
+ var targetCollection;
136
241
  if (fType === 'image') {
137
- collection = 'images';
242
+ targetCollection = 'cfs.images.filerecord';
138
243
  } else if (fType === 'file') {
139
- collection = 'files';
140
- }
141
- if (_.isString(recordFieldId)) {
142
- query = {
143
- _id: {
144
- $in: [recordFieldId]
145
- }
146
- };
244
+ targetCollection = 'cfs.files.filerecord';
147
245
  } else {
148
- query = {
149
- _id: {
150
- $in: recordFieldId
246
+ return;
247
+ }
248
+
249
+ var ids = _.isString(recordFieldId) ? [recordFieldId] : recordFieldId;
250
+
251
+ // 源文件在 cfs.instances.filerecord 中(workflow 上传的附件)
252
+ var sourceCollection = 'cfs.instances.filerecord';
253
+ var sourceColl = await getCollection(sourceCollection);
254
+ var files = await sourceColl.find({ _id: { $in: ids } }).toArray();
255
+
256
+ // 如果在 instances 中找不到,尝试从目标集合中查找(兼容旧数据)
257
+ if (files.length === 0) {
258
+ var targetColl = await getCollection(targetCollection);
259
+ files = await targetColl.find({ _id: { $in: ids } }).toArray();
260
+ if (files.length > 0) {
261
+ sourceCollection = targetCollection;
262
+ }
263
+ }
264
+
265
+ var value = [];
266
+ for (const f of files) {
267
+ try {
268
+ var buffer = await readFileBuffer(sourceCollection, f);
269
+ if (!buffer) {
270
+ console.error(`[getFileFieldValue] Cannot read file ${f._id}`);
271
+ continue;
151
272
  }
152
- };
273
+
274
+ var newRecord = await uploadFileToCollection(targetCollection, buffer, {
275
+ owner: f.metadata?.owner
276
+ }, {
277
+ name: f.original?.name,
278
+ type: f.original?.type
279
+ });
280
+
281
+ value.push(newRecord._id);
282
+ } catch (err) {
283
+ console.error(`[getFileFieldValue] Error copying file ${f._id}: ${err.message}`);
284
+ }
153
285
  }
154
286
 
155
- //TODO 同步附
156
- console.log('TODO, 同步附件')
157
- value = [];
158
- // files = await Creator.Collections["cfs." + collection + ".filerecord"].find(query).toArray();
159
- // for (const f of files) {
160
- // console.log('TODO, 同步附件')
161
- // var newFile;
162
- // newFile = new FS.File();
163
- // await new Promise((resolve, reject) => {
164
- // newFile.attachData(f.createReadStream('files'), {
165
- // type: f.original.type
166
- // }, function (err) {
167
- // if (err) return reject(err);
168
- // var metadata;
169
- // newFile.name(f.name());
170
- // newFile.size(f.size());
171
- // metadata = {
172
- // owner: f.metadata.owner
173
- // };
174
- // newFile.metadata = metadata;
175
- // newFile._id = Creator.Collections.instances._makeNewID();
176
- // cfs[collection].insert(newFile);
177
- // value.push(newFile._id);
178
- // resolve();
179
- // });
180
- // });
181
- // }
182
287
  if (value.length > 0) {
183
288
  if (_.isString(recordFieldId)) {
184
289
  return value[0];
@@ -318,6 +423,27 @@ const getRecordFieldValue = async function (oField, wField, ofValue, wfValue, sp
318
423
  }
319
424
  }
320
425
  }
426
+ // 通用处理:lookup/master_detail 字段,wfValue 为对象格式 {id, name, ...} 或对象数组
427
+ // 适用于部门等字段类型,当 reference_to 不是 organizations 或 users 时
428
+ if (value === undefined || value === null) {
429
+ let referToField = oField.reference_to_field || '_id'
430
+ if (Array.isArray(wfValue)) {
431
+ if (wfValue.length > 0 && typeof wfValue[0] === 'object' && wfValue[0] !== null && (wfValue[0].id || wfValue[0]._id)) {
432
+ if (oField.multiple) {
433
+ value = _.compact(wfValue.map(v => v.id || v._id))
434
+ } else {
435
+ value = wfValue[0].id || wfValue[0]._id
436
+ }
437
+ }
438
+ } else if (typeof wfValue === 'object' && wfValue !== null && (wfValue.id || wfValue._id)) {
439
+ const idValue = wfValue.id || wfValue._id;
440
+ if (oField.multiple) {
441
+ value = [idValue];
442
+ } else {
443
+ value = referToField === '_id' ? (wfValue._id || wfValue.id) : (wfValue[referToField] || idValue);
444
+ }
445
+ }
446
+ }
321
447
  }
322
448
  else if (!oField.multiple && ['lookup', 'master_detail'].includes(oFieldType) && _.isString(oField.reference_to) && _.isString(wfValue)) {
323
449
  // 当是对象类型的 member/org 字段时,应该已在上面处理了,这里只处理字符串值
@@ -372,15 +498,9 @@ const getRecordFieldValue = async function (oField, wField, ofValue, wfValue, sp
372
498
  if (_.isString(ids)) {
373
499
  ids = [ids];
374
500
  }
375
- if (ids) {
376
- await new Promise((resolve, reject) => {
377
- cfs.images.remove({
378
- '_id': { $in: ids }
379
- }, function(err) {
380
- if (err) return reject(err);
381
- resolve();
382
- });
383
- });
501
+ if (ids && ids.length > 0) {
502
+ var imgColl = await getCollection('cfs.images.filerecord');
503
+ await imgColl.deleteMany({ '_id': { $in: ids } });
384
504
  }
385
505
 
386
506
  value = await getFileFieldValue(wfValue, 'image')
@@ -390,15 +510,9 @@ const getRecordFieldValue = async function (oField, wField, ofValue, wfValue, sp
390
510
  if (_.isString(ids)) {
391
511
  ids = [ids];
392
512
  }
393
- if (ids) {
394
- await new Promise((resolve, reject) => {
395
- cfs.files.remove({
396
- '_id': { $in: ids }
397
- }, function(err) {
398
- if (err) return reject(err);
399
- resolve();
400
- });
401
- });
513
+ if (ids && ids.length > 0) {
514
+ var fileColl = await getCollection('cfs.files.filerecord');
515
+ await fileColl.deleteMany({ '_id': { $in: ids } });
402
516
  }
403
517
  value = await getFileFieldValue(wfValue, 'file')
404
518
  } else if (['lookup', 'master_detail'].includes(oFieldType) && wField.type == 'lookup') {
@@ -623,154 +737,158 @@ InstanceRecordQueue.Configure = function (options) {
623
737
  }
624
738
  };
625
739
 
626
- //TODO 同步附件
627
740
  InstanceRecordQueue.syncAttach = async function (sync_attachment, insId, spaceId, newRecordId, objectName) {
628
- console.log(`TODO 同步附件 syncAttach`)
629
- // if (sync_attachment == "lastest") {
630
- // const files = await cfs.instances.find({
631
- // 'metadata.instance': insId,
632
- // 'metadata.current': true
633
- // }).toArray();
634
-
635
- // for (const f of files) {
636
- // if (!f.hasStored('instances')) {
637
- // console.error('syncAttach-file not stored: ', f._id);
638
- // continue;
639
- // }
640
- // var newFile = new FS.File(),
641
- // cmsFileId = Creator.getCollection('cms_files')._makeNewID();
642
-
643
- // await new Promise((resolve, reject) => {
644
- // newFile.attachData(f.createReadStream('instances'), {
645
- // type: f.original.type
646
- // }, function (err) {
647
- // if (err) return reject(err);
648
- // newFile.name(f.name());
649
- // newFile.size(f.size());
650
- // var metadata = {
651
- // owner: f.metadata.owner,
652
- // owner_name: f.metadata.owner_name,
653
- // space: spaceId,
654
- // record_id: newRecordId,
655
- // object_name: objectName,
656
- // parent: cmsFileId
657
- // };
658
-
659
- // newFile.metadata = metadata;
660
- // cfs.files.insert(newFile);
661
- // resolve();
662
- // });
663
- // });
664
-
665
- // await new Promise((resolve, reject) => {
666
- // newFile.once('stored', function (storeName) {
667
- // Creator.getCollection('cms_files').insert({
668
- // _id: cmsFileId,
669
- // parent: {
670
- // o: objectName,
671
- // ids: [newRecordId]
672
- // },
673
- // size: newFile.size(),
674
- // name: newFile.name(),
675
- // extention: newFile.extension(),
676
- // space: spaceId,
677
- // versions: [newFile._id],
678
- // owner: f.metadata.owner,
679
- // created_by: f.metadata.owner,
680
- // modified_by: f.metadata.owner
681
- // });
682
- // resolve();
683
- // });
684
- // newFile.once('error', function (error) {
685
- // console.error('syncAttach-error: ', error);
686
- // reject(error);
687
- // });
688
- // });
689
- // }
690
- // } else if (sync_attachment == "all") {
691
- // var parents = [];
692
- // const files = await cfs.instances.find({
693
- // 'metadata.instance': insId
694
- // }).toArray();
695
-
696
- // for (const f of files) {
697
- // if (!f.hasStored('instances')) {
698
- // console.error('syncAttach-file not stored: ', f._id);
699
- // continue;
700
- // }
701
- // var newFile = new FS.File(),
702
- // cmsFileId = f.metadata.parent;
703
-
704
- // if (!parents.includes(cmsFileId)) {
705
- // parents.push(cmsFileId);
706
- // await Creator.getCollection('cms_files').insert({
707
- // _id: cmsFileId,
708
- // parent: {
709
- // o: objectName,
710
- // ids: [newRecordId]
711
- // },
712
- // space: spaceId,
713
- // versions: [],
714
- // owner: f.metadata.owner,
715
- // created_by: f.metadata.owner,
716
- // modified_by: f.metadata.owner
717
- // });
718
- // }
719
-
720
- // await new Promise((resolve, reject) => {
721
- // newFile.attachData(f.createReadStream('instances'), {
722
- // type: f.original.type
723
- // }, function (err) {
724
- // if (err) return reject(err);
725
- // newFile.name(f.name());
726
- // newFile.size(f.size());
727
- // var metadata = {
728
- // owner: f.metadata.owner,
729
- // owner_name: f.metadata.owner_name,
730
- // space: spaceId,
731
- // record_id: newRecordId,
732
- // object_name: objectName,
733
- // parent: cmsFileId
734
- // };
735
-
736
- // newFile.metadata = metadata;
737
- // cfs.files.insert(newFile);
738
- // resolve();
739
- // });
740
- // });
741
-
742
- // await new Promise((resolve, reject) => {
743
- // newFile.once('stored', function (storeName) {
744
- // if (f.metadata.current == true) {
745
- // Creator.getCollection('cms_files').update(cmsFileId, {
746
- // $set: {
747
- // size: newFile.size(),
748
- // name: newFile.name(),
749
- // extention: newFile.extension(),
750
- // },
751
- // $addToSet: {
752
- // versions: newFile._id
753
- // }
754
- // });
755
- // } else {
756
- // Creator.getCollection('cms_files').update(cmsFileId, {
757
- // $addToSet: {
758
- // versions: newFile._id
759
- // },
760
- // $set: {
761
- // modified: new Date()
762
- // }
763
- // });
764
- // }
765
- // resolve();
766
- // });
767
- // newFile.once('error', function (error) {
768
- // console.error('syncAttach-error: ', error);
769
- // reject(error);
770
- // });
771
- // });
772
- // }
773
- // }
741
+ if (!sync_attachment || sync_attachment === 'null') {
742
+ return;
743
+ }
744
+
745
+ console.log(`[syncAttach] Starting: sync_attachment=${sync_attachment}, insId=${insId}, recordId=${newRecordId}, objectName=${objectName}`);
746
+
747
+ var instanceFilesColl = await getCollection('cfs.instances.filerecord');
748
+
749
+ if (sync_attachment === 'lastest') {
750
+ var files = await instanceFilesColl.find({
751
+ 'metadata.instance': insId,
752
+ 'metadata.current': true
753
+ }).toArray();
754
+
755
+ console.log(`[syncAttach] Found ${files.length} current files for instance ${insId}`);
756
+
757
+ for (const f of files) {
758
+ try {
759
+ var buffer = await readFileBuffer('cfs.instances.filerecord', f);
760
+ if (!buffer) {
761
+ console.error(`[syncAttach] Cannot read file content: ${f._id}`);
762
+ continue;
763
+ }
764
+
765
+ var cmsFileId = crypto.randomUUID();
766
+
767
+ var newFileRecord = await uploadFileToCollection('cfs.files.filerecord', buffer, {
768
+ owner: f.metadata.owner,
769
+ owner_name: f.metadata.owner_name,
770
+ space: spaceId,
771
+ record_id: newRecordId,
772
+ object_name: objectName,
773
+ parent: cmsFileId
774
+ }, {
775
+ name: f.original?.name,
776
+ type: f.original?.type
777
+ });
778
+
779
+ var extension = f.original?.name ? f.original.name.split('.').pop() : '';
780
+ var cmsColl = await getCollection('cms_files');
781
+ await cmsColl.insertOne({
782
+ _id: cmsFileId,
783
+ parent: {
784
+ o: objectName,
785
+ ids: [newRecordId]
786
+ },
787
+ size: buffer.length,
788
+ name: f.original?.name,
789
+ extention: extension,
790
+ space: spaceId,
791
+ versions: [newFileRecord._id],
792
+ owner: f.metadata.owner,
793
+ created_by: f.metadata.owner,
794
+ modified_by: f.metadata.owner,
795
+ created: new Date(),
796
+ modified: new Date()
797
+ });
798
+
799
+ console.log(`[syncAttach] Synced file ${f._id} -> cfs.files ${newFileRecord._id}, cms_files ${cmsFileId}`);
800
+ } catch (err) {
801
+ console.error(`[syncAttach] Error syncing file ${f._id}: ${err.message}`);
802
+ }
803
+ }
804
+ } else if (sync_attachment === 'all') {
805
+ var files = await instanceFilesColl.find({
806
+ 'metadata.instance': insId
807
+ }).toArray();
808
+
809
+ console.log(`[syncAttach] Found ${files.length} total files for instance ${insId}`);
810
+
811
+ var parentMap = {}; // metadata.parent -> cmsFileId
812
+
813
+ for (const f of files) {
814
+ try {
815
+ var buffer = await readFileBuffer('cfs.instances.filerecord', f);
816
+ if (!buffer) {
817
+ console.error(`[syncAttach] Cannot read file content: ${f._id}`);
818
+ continue;
819
+ }
820
+
821
+ var fileParent = f.metadata.parent || f._id;
822
+ var cmsFileId = parentMap[fileParent];
823
+
824
+ // 如果该 parent 组还没有创建 cms_files 记录,先创建
825
+ if (!cmsFileId) {
826
+ cmsFileId = crypto.randomUUID();
827
+ parentMap[fileParent] = cmsFileId;
828
+
829
+ var cmsColl = await getCollection('cms_files');
830
+ await cmsColl.insertOne({
831
+ _id: cmsFileId,
832
+ parent: {
833
+ o: objectName,
834
+ ids: [newRecordId]
835
+ },
836
+ space: spaceId,
837
+ versions: [],
838
+ owner: f.metadata.owner,
839
+ created_by: f.metadata.owner,
840
+ modified_by: f.metadata.owner,
841
+ created: new Date(),
842
+ modified: new Date()
843
+ });
844
+ }
845
+
846
+ var newFileRecord = await uploadFileToCollection('cfs.files.filerecord', buffer, {
847
+ owner: f.metadata.owner,
848
+ owner_name: f.metadata.owner_name,
849
+ space: spaceId,
850
+ record_id: newRecordId,
851
+ object_name: objectName,
852
+ parent: cmsFileId
853
+ }, {
854
+ name: f.original?.name,
855
+ type: f.original?.type
856
+ });
857
+
858
+ // 更新 cms_files:添加版本,如果是 current 则更新名称等信息
859
+ var cmsColl = await getCollection('cms_files');
860
+ if (f.metadata.current === true) {
861
+ var extension = f.original?.name ? f.original.name.split('.').pop() : '';
862
+ await cmsColl.updateOne({ _id: cmsFileId }, {
863
+ $set: {
864
+ size: buffer.length,
865
+ name: f.original?.name,
866
+ extention: extension,
867
+ modified: new Date()
868
+ },
869
+ $addToSet: {
870
+ versions: newFileRecord._id
871
+ }
872
+ });
873
+ } else {
874
+ await cmsColl.updateOne({ _id: cmsFileId }, {
875
+ $addToSet: {
876
+ versions: newFileRecord._id
877
+ },
878
+ $set: {
879
+ modified: new Date()
880
+ }
881
+ });
882
+ }
883
+
884
+ console.log(`[syncAttach] Synced file ${f._id} -> cfs.files ${newFileRecord._id}, cms_files ${cmsFileId} (current=${f.metadata.current})`);
885
+ } catch (err) {
886
+ console.error(`[syncAttach] Error syncing file ${f._id}: ${err.message}`);
887
+ }
888
+ }
889
+ }
890
+
891
+ console.log(`[syncAttach] Completed for instance ${insId}`);
774
892
  }
775
893
 
776
894
  InstanceRecordQueue.syncInsFields = ['name', 'submitter_name', 'applicant_name', 'applicant_organization_name', 'applicant_organization_fullname', 'state',
@@ -1280,10 +1398,11 @@ InstanceRecordQueue.sendDoc = async function (doc) {
1280
1398
  }];
1281
1399
  newObj.instance_state = instance_state;
1282
1400
 
1401
+ newObj._id = newRecordId;
1283
1402
  newObj.owner = newObj.owner || ins.applicant;
1284
1403
  newObj.created_by = ins.applicant;
1285
1404
  newObj.modified_by = ins.applicant;
1286
-
1405
+
1287
1406
  var r = await objectInsert(ow.object_name, newObj);
1288
1407
  recordInserted = !!r;
1289
1408
  const insColl = await getCollection('instances');