@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.
- package/designer/dist/amis-renderer/amis-renderer.css +1 -1
- package/designer/dist/amis-renderer/amis-renderer.js +1 -1
- package/designer/dist/assets/{index-IqLl5PBH.js → index-DX2PUSq4.js} +148 -148
- package/designer/dist/assets/index-YXPc2HMf.css +1 -0
- package/designer/dist/index.html +2 -2
- package/main/default/client/socket.client.js +43 -13
- package/main/default/manager/uuflow_manager.js +9 -2
- package/main/default/objects/flows/flows.object.yml +4 -9
- package/main/default/objects/instance_tasks/listviews/inbox.listview.yml +4 -1
- package/main/default/pages/flow_selector.page.amis.json +2 -2
- package/main/default/pages/flow_selector_mobile.page.amis.json +2 -2
- package/main/default/pages/page_instance_print.page.amis.json +108 -32
- package/main/default/routes/api_workflow_approve_save.router.js +7 -0
- package/main/default/routes/api_workflow_forward.router.js +4 -4
- package/main/default/routes/api_workflow_forward_refill.router.js +1 -1
- package/main/default/routes/api_workflow_instance_forward.router.js +4 -4
- package/main/default/routes/api_workflow_retrieve.router.js +64 -33
- package/main/default/services/instance.service.js +1 -0
- package/main/default/test/test_socket_reconnect.js +105 -0
- package/main/default/utils/designerManager.js +12 -0
- package/package.json +1 -1
- package/public/amis-renderer/amis-renderer.css +1 -1
- package/public/amis-renderer/amis-renderer.js +1 -1
- package/public/workflow/index.css +14 -10
- package/src/instance_record_queue.js +326 -207
- 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
|
-
.
|
|
84
|
+
.steedos-object-listview .unread-instance .antd-Table-checkCell {
|
|
85
85
|
position: relative
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
/* PC端未读列表蓝色圆点 */
|
|
89
|
-
.
|
|
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
|
-
|
|
102
|
-
|
|
101
|
+
/* 分栏/手机端:含未读行的列表中所有行统一缩进,保持已读与未读左侧对齐 */
|
|
102
|
+
.steedos-object-listview:has(.unread-instance) .steedos-listview-item {
|
|
103
|
+
position: relative;
|
|
104
|
+
padding-left: 12px;
|
|
103
105
|
}
|
|
104
106
|
|
|
105
|
-
/*
|
|
106
|
-
.
|
|
107
|
+
/* 手机端及分栏模式未读列表蓝色圆点 */
|
|
108
|
+
.steedos-object-listview .unread-instance .steedos-listview-item:before {
|
|
107
109
|
content: " ";
|
|
108
110
|
position: absolute;
|
|
109
|
-
left:
|
|
110
|
-
width:
|
|
111
|
-
height:
|
|
111
|
+
left: 0;
|
|
112
|
+
width: 10px;
|
|
113
|
+
height: 10px;
|
|
112
114
|
background-color: #1890ff;
|
|
113
|
-
border-radius:
|
|
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
|
-
|
|
242
|
+
targetCollection = 'cfs.images.filerecord';
|
|
138
243
|
} else if (fType === 'file') {
|
|
139
|
-
|
|
140
|
-
}
|
|
141
|
-
if (_.isString(recordFieldId)) {
|
|
142
|
-
query = {
|
|
143
|
-
_id: {
|
|
144
|
-
$in: [recordFieldId]
|
|
145
|
-
}
|
|
146
|
-
};
|
|
244
|
+
targetCollection = 'cfs.files.filerecord';
|
|
147
245
|
} else {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
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
|
|
377
|
-
|
|
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
|
|
395
|
-
|
|
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
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
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');
|