@steedos-labs/plugin-workflow 3.0.62 → 3.0.64

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.
@@ -484,9 +484,16 @@ InstanceRecordQueue.Configure = function (options) {
484
484
  }
485
485
 
486
486
  // Universal send function
487
- var _querySend = function (doc) {
487
+ var _querySend = async function (doc) {
488
488
  if (InstanceRecordQueue.sendDoc) {
489
- InstanceRecordQueue.sendDoc(doc);
489
+ try {
490
+ await InstanceRecordQueue.sendDoc(doc);
491
+ } catch (error) {
492
+ console.error(`${new Date().toISOString()} [InstanceRecordQueue._querySend] sendDoc 异常: docId=${doc._id}, error=${error.message}`);
493
+ throw error;
494
+ }
495
+ } else {
496
+ console.warn(`[InstanceRecordQueue._querySend] InstanceRecordQueue.sendDoc 未定义! docId=${doc._id}`);
490
497
  }
491
498
 
492
499
  return {
@@ -494,9 +501,9 @@ InstanceRecordQueue.Configure = function (options) {
494
501
  };
495
502
  };
496
503
 
497
- self.serverSend = function (doc) {
504
+ self.serverSend = async function (doc) {
498
505
  doc = doc || {};
499
- return _querySend(doc);
506
+ return await _querySend(doc);
500
507
  };
501
508
 
502
509
  var isSendingDoc = false;
@@ -543,6 +550,8 @@ InstanceRecordQueue.Configure = function (options) {
543
550
  }
544
551
  });
545
552
  }
553
+ } else {
554
+ console.warn(`[InstanceRecordQueue.sendDoc-queue] 文档 reserve 失败(可能被其他实例处理): docId=${doc._id}`);
546
555
  } // Else could not reserve
547
556
  }; // EO sendDoc
548
557
 
@@ -584,10 +593,13 @@ InstanceRecordQueue.Configure = function (options) {
584
593
  },
585
594
  limit: batchSize
586
595
  }).toArray();
596
+
587
597
  for (const doc of pendingDocs) {
588
598
  try {
599
+ console.log(`${new Date().toISOString()} [InstanceRecordQueue.sendWorker] 处理文档: docId=${doc._id}, insId=${doc.info.instance_id}`);
589
600
  await sendDoc(doc);
590
601
  } catch (error) {
602
+ console.error(`${new Date().toISOString()} [InstanceRecordQueue.sendWorker] 文档处理异常: docId=${doc._id}`);
591
603
  console.error(error.stack);
592
604
  console.log('InstanceRecordQueue: Could not send doc id: "' + doc._id + '", Error: ' + error.message);
593
605
  await InstanceRecordQueue.collection.update({
@@ -954,6 +966,10 @@ InstanceRecordQueue.syncValues = async function (field_map_back, values, ins, ob
954
966
  var relatedObjectName = key;
955
967
  var relatedObjectValues = [];
956
968
  var relatedObjectFields = await getObjectFields(relatedObjectName)
969
+ if (!values[tableCode] || !Array.isArray(values[tableCode])) {
970
+ console.warn(`[InstanceRecordQueue.syncValues] tableToRelated: values['${tableCode}'] is empty or not an array, skipping related object '${relatedObjectName}'`);
971
+ continue;
972
+ }
957
973
  for (const tableValueItem of values[tableCode]) {
958
974
  let relateRecord;
959
975
  if (tableValueItem._id) {
@@ -1073,7 +1089,7 @@ InstanceRecordQueue.sendDoc = async function (doc) {
1073
1089
  const docId = doc._id;
1074
1090
  const insId = doc.info.instance_id;
1075
1091
 
1076
- console.log(`[InstanceRecordQueue.sendDoc] 开始处理文档: docId=${docId}, insId=${insId}, 时间=${startTime.toISOString()}`);
1092
+ console.log(`${new Date().toISOString()} [InstanceRecordQueue.sendDoc] 开始处理: insId=${insId}`);
1077
1093
 
1078
1094
  if (InstanceRecordQueue.debug) {
1079
1095
  console.log("sendDoc:");
@@ -1081,7 +1097,6 @@ InstanceRecordQueue.sendDoc = async function (doc) {
1081
1097
  }
1082
1098
 
1083
1099
  var records = doc.info.records;
1084
- console.log(`[InstanceRecordQueue.sendDoc] 文档中的记录数: ${records ? records.length : 0}`);
1085
1100
 
1086
1101
  var fields = {
1087
1102
  flow: 1,
@@ -1099,18 +1114,15 @@ InstanceRecordQueue.sendDoc = async function (doc) {
1099
1114
  fields[f] = 1;
1100
1115
  })
1101
1116
 
1102
- console.log(`[InstanceRecordQueue.sendDoc] 查询实例: insId=${insId}`);
1103
1117
  var ins = await objectql.getObject('instances').findOne(insId, {
1104
1118
  fields: fields
1105
1119
  })
1106
1120
 
1107
1121
  if (!ins) {
1108
- console.error(`[InstanceRecordQueue.sendDoc] 无法找到实例: insId=${insId}`);
1122
+ console.error(`${new Date().toISOString()} [InstanceRecordQueue.sendDoc] 实例不存在: insId=${insId}`);
1109
1123
  throw new Error(`Instance not found: ${insId}`);
1110
1124
  }
1111
1125
 
1112
- console.log(`[InstanceRecordQueue.sendDoc] 获取实例成功: insId=${insId}, 实例状态=${ins.state}, 实例名称=${ins.name}`);
1113
-
1114
1126
  var values = ins.values,
1115
1127
  spaceId = ins.space;
1116
1128
 
@@ -1120,21 +1132,18 @@ InstanceRecordQueue.sendDoc = async function (doc) {
1120
1132
  }
1121
1133
 
1122
1134
  const flowId = ins.flow
1123
- console.log(`[InstanceRecordQueue.sendDoc] 查询流程: flowId=${flowId}`);
1124
1135
  const flow = await objectql.getObject('flows').findOne(flowId, { fields: { enable_amisform: 1 } })
1125
1136
 
1126
1137
  if (!flow) {
1127
- console.error(`[InstanceRecordQueue.sendDoc] 无法找到流程: flowId=${flowId}`);
1138
+ console.error(`${new Date().toISOString()} [InstanceRecordQueue.sendDoc] 流程不存在: flowId=${flowId}`);
1128
1139
  throw new Error(`Flow not found: ${flowId}`);
1129
1140
  }
1130
1141
 
1131
1142
  const enableAmisform = flow.enable_amisform
1132
- console.log(`[InstanceRecordQueue.sendDoc] 流程启用Amisform: ${enableAmisform}`);
1133
1143
 
1134
1144
  if (records && !_.isEmpty(records)) {
1135
1145
  // 此情况属于从creator中发起审批,或者已经从Apps同步到了creator
1136
1146
  var objectName = records[0].o;
1137
- console.log(`[InstanceRecordQueue.sendDoc] 检测到记录: objectName=${objectName}, recordIds=${JSON.stringify(records[0].ids)}`);
1138
1147
 
1139
1148
  var ow = await objectql.getObject('object_workflows').findOne({
1140
1149
  object_name: objectName,
@@ -1142,39 +1151,32 @@ InstanceRecordQueue.sendDoc = async function (doc) {
1142
1151
  });
1143
1152
 
1144
1153
  if (!ow) {
1145
- console.error(`[InstanceRecordQueue.sendDoc] 无法找到对象工作流配置: objectName=${objectName}, flowId=${ins.flow}`);
1154
+ console.error(`${new Date().toISOString()} [InstanceRecordQueue.sendDoc] 对象工作流配置不存在: objectName=${objectName}, flowId=${ins.flow}`);
1146
1155
  throw new Error(`ObjectWorkflow not found for object=${objectName}, flow=${ins.flow}`);
1147
1156
  }
1148
1157
 
1149
- console.log(`[InstanceRecordQueue.sendDoc] 获取对象工作流配置: objectName=${objectName}`);
1158
+ console.log(`${new Date().toISOString()} [InstanceRecordQueue.sendDoc] 同步到对象: objectName=${objectName}`);
1150
1159
 
1151
1160
  var objectCollection = objectql.getObject(objectName),
1152
1161
  sync_attachment = ow.sync_attachment;
1153
1162
  syncDirection = ow.sync_direction || 'both';
1154
- console.log(`[InstanceRecordQueue.sendDoc] 同步方向: ${syncDirection}, 同步附件: ${sync_attachment}`);
1155
1163
 
1156
1164
  var objectInfo = await getObjectConfig(objectName);
1157
- console.log(`[InstanceRecordQueue.sendDoc] 对象配置获取成功: objectName=${objectName}, 字段数=${Object.keys(objectInfo.fields || {}).length}`);
1158
1165
 
1159
1166
  const recordsToProcess = await objectFind(objectName, { filters: [['_id', 'in', records[0].ids]] });
1160
- console.log(`[InstanceRecordQueue.sendDoc] 查询得到的记录数: ${recordsToProcess.length}`);
1161
1167
 
1162
1168
  for (const record of recordsToProcess) {
1163
1169
  const recordId = record._id;
1164
- console.log(`[InstanceRecordQueue.sendDoc] 处理记录: recordId=${recordId}`);
1165
1170
  try {
1166
1171
  if (!['both', 'ins_to_obj'].includes(syncDirection)) {
1167
- console.log(`[InstanceRecordQueue.sendDoc] 跳过记录,同步方向不匹配: ${syncDirection}`);
1168
1172
  continue;
1169
1173
  }
1170
1174
  var lock_record_after_approval = ow.lock_record_after_approval || false;
1171
- console.log(`[InstanceRecordQueue.sendDoc] 同步值: recordId=${recordId}, flowId=${ins.flow}`);
1172
1175
  var syncValues = await InstanceRecordQueue.syncValues(ow.field_map_back, values, ins, objectInfo, ow.field_map_back_script, record, enableAmisform)
1173
1176
  var setObj = syncValues.mainObjectValue;
1174
1177
 
1175
- console.log(`[InstanceRecordQueue.sendDoc] 字段映射结果: recordId=${recordId}, 映射字段数=${Object.keys(setObj).length}`);
1176
1178
  if (InstanceRecordQueue.debug) {
1177
- console.log(`[InstanceRecordQueue.sendDoc] 映射值详情:`, JSON.stringify(setObj, null, 2));
1179
+ console.log(`${new Date().toISOString()} [InstanceRecordQueue.sendDoc] 映射值详情:`, JSON.stringify(setObj, null, 2));
1178
1180
  }
1179
1181
 
1180
1182
  var instance_state = ins.state;
@@ -1186,13 +1188,10 @@ InstanceRecordQueue.sendDoc = async function (doc) {
1186
1188
  }
1187
1189
  setObj['instances.0.state'] = setObj.instance_state = instance_state;
1188
1190
 
1189
- console.log(`[InstanceRecordQueue.sendDoc] 更新记录: recordId=${recordId}, instanceState=${instance_state}`);
1190
1191
  await objectUpdate(objectName, record._id, setObj);
1191
- console.log(`[InstanceRecordQueue.sendDoc] 记录更新成功: recordId=${recordId}`);
1192
1192
 
1193
1193
  var relatedObjects = await getRelateds(ow.object_name);
1194
1194
  var relatedObjectsValue = syncValues.relatedObjectsValue;
1195
- console.log(`[InstanceRecordQueue.sendDoc] 处理关联对象: 数量=${relatedObjects.length}`);
1196
1195
  await InstanceRecordQueue.syncRelatedObjectsValue(record._id, relatedObjects, relatedObjectsValue, spaceId, ins);
1197
1196
 
1198
1197
  // 以最终申请单附件为准,旧的record中附件删除
@@ -1204,7 +1203,6 @@ InstanceRecordQueue.sendDoc = async function (doc) {
1204
1203
  ids: [record._id]
1205
1204
  }
1206
1205
  });
1207
- console.log(`[InstanceRecordQueue.sendDoc] 删除旧附件: recordId=${recordId}`);
1208
1206
 
1209
1207
  const cfsColl = await getCollection('cfs.files.filerecord');
1210
1208
  await cfsColl.deleteMany({
@@ -1212,16 +1210,11 @@ InstanceRecordQueue.sendDoc = async function (doc) {
1212
1210
  })
1213
1211
 
1214
1212
  // 同步新附件
1215
- console.log(`[InstanceRecordQueue.sendDoc] 同步新附件: recordId=${recordId}, insId=${insId}`);
1216
1213
  await InstanceRecordQueue.syncAttach(sync_attachment, insId, record.space, record._id, objectName);
1217
1214
  // 执行公式
1218
- console.log(`[InstanceRecordQueue.sendDoc] 执行公式: recordId=${recordId}`);
1219
1215
  await runQuoted(objectName, record._id);
1220
- console.log(`[InstanceRecordQueue.sendDoc] 记录处理完成: recordId=${recordId}`);
1221
1216
  } catch (error) {
1222
- console.error(`[InstanceRecordQueue.sendDoc] 记录处理失败: recordId=${recordId}`);
1223
- console.error(`[InstanceRecordQueue.sendDoc] 错误信息:`, error.message);
1224
- console.error(`[InstanceRecordQueue.sendDoc] 错误堆栈:`, error.stack);
1217
+ console.error(`${new Date().toISOString()} [InstanceRecordQueue.sendDoc] 记录处理失败: recordId=${recordId}, error=${error.message}`);
1225
1218
 
1226
1219
  await objectUpdateMany(objectName, [['_id', '=', record._id], ['instances._id', '=', insId]], {
1227
1220
  'instances.$.state': 'pending',
@@ -1246,38 +1239,31 @@ InstanceRecordQueue.sendDoc = async function (doc) {
1246
1239
  }
1247
1240
  } else {
1248
1241
  // 此情况属于从apps中发起审批
1249
- console.log(`[InstanceRecordQueue.sendDoc] 从Apps发起的审批,创建新记录`);
1250
1242
  const owsColl = await getCollection('object_workflows');
1251
1243
  const ows = await owsColl.find({
1252
1244
  flow_id: ins.flow
1253
1245
  }).toArray();
1254
1246
 
1255
- console.log(`[InstanceRecordQueue.sendDoc] 找到的对象工作流配置数: ${ows.length}`);
1256
1247
  for (const ow of ows) {
1257
1248
  const objectName = ow.object_name;
1258
- console.log(`[InstanceRecordQueue.sendDoc] 处理对象工作流: objectName=${objectName}`);
1259
1249
  try {
1260
1250
  var sync_attachment = ow.sync_attachment,
1261
1251
  newRecordId = await makeNewID(ow.object_name),
1262
1252
  syncDirection = ow.sync_direction || 'both';
1263
1253
  lock_record_after_approval = ow.lock_record_after_approval || false;
1254
+ var recordInserted = false;
1264
1255
 
1265
- console.log(`[InstanceRecordQueue.sendDoc] 新建记录: recordId=${newRecordId}, objectName=${objectName}, syncDirection=${syncDirection}`);
1256
+ console.log(`${new Date().toISOString()} [InstanceRecordQueue.sendDoc] 新建记录: objectName=${objectName}, recordId=${newRecordId}`);
1266
1257
 
1267
1258
  if (!['both', 'ins_to_obj'].includes(syncDirection)) {
1268
- console.log(`[InstanceRecordQueue.sendDoc] 跳过对象工作流,同步方向不匹配: ${syncDirection}`);
1269
1259
  continue;
1270
1260
  }
1271
1261
 
1272
1262
  var objectInfo = await getObjectConfig(ow.object_name);
1273
- console.log(`[InstanceRecordQueue.sendDoc] 获取对象配置: objectName=${objectName}, 字段数=${Object.keys(objectInfo.fields || {}).length}`);
1274
1263
 
1275
- console.log(`[InstanceRecordQueue.sendDoc] 同步字段值: objectName=${objectName}`);
1276
1264
  var syncValues = await InstanceRecordQueue.syncValues(ow.field_map_back, values, ins, objectInfo, ow.field_map_back_script, null, enableAmisform);
1277
1265
  var newObj = syncValues.mainObjectValue;
1278
1266
 
1279
- console.log(`[InstanceRecordQueue.sendDoc] 字段映射完成: objectName=${objectName}, 映射字段数=${Object.keys(newObj).length}`);
1280
-
1281
1267
  newObj.space = spaceId;
1282
1268
  newObj.name = newObj.name || ins.name;
1283
1269
 
@@ -1299,6 +1285,7 @@ InstanceRecordQueue.sendDoc = async function (doc) {
1299
1285
  newObj.modified_by = ins.applicant;
1300
1286
 
1301
1287
  var r = await objectInsert(ow.object_name, newObj);
1288
+ recordInserted = !!r;
1302
1289
  const insColl = await getCollection('instances');
1303
1290
  if (r) {
1304
1291
  await insColl.update({_id: ins._id}, {
@@ -1329,32 +1316,38 @@ InstanceRecordQueue.sendDoc = async function (doc) {
1329
1316
  } catch (error) {
1330
1317
  console.error(error);
1331
1318
 
1332
- await objectRemove(ow.object_name, newRecordId);
1333
- const insColl = await getObject('instances');
1334
- await insColl.update(ins._id, {
1335
- $pull: {
1336
- record_ids: {
1337
- o: objectName,
1338
- ids: [newRecordId]
1339
- }
1340
- },
1341
- $set: {
1342
- modified: new Date()
1343
- }
1344
- });
1319
+ if (recordInserted) {
1320
+ try {
1321
+ await objectRemove(ow.object_name, newRecordId);
1322
+ const insColl = await getObject('instances');
1323
+ await insColl.update(ins._id, {
1324
+ $pull: {
1325
+ record_ids: {
1326
+ o: objectName,
1327
+ ids: [newRecordId]
1328
+ }
1329
+ },
1330
+ $set: {
1331
+ modified: new Date()
1332
+ }
1333
+ });
1345
1334
 
1346
- const cfColl = await getCollection('cms_files');
1347
- await cfColl.deleteMany({
1348
- 'parent': {
1349
- o: objectName,
1350
- ids: [newRecordId]
1351
- }
1352
- });
1335
+ const cfColl = await getCollection('cms_files');
1336
+ await cfColl.deleteMany({
1337
+ 'parent': {
1338
+ o: objectName,
1339
+ ids: [newRecordId]
1340
+ }
1341
+ });
1353
1342
 
1354
- const cfsColl = await getCollection('cfs.files.filerecord');
1355
- await cfsColl.deleteMany({
1356
- 'metadata.record_id': newRecordId
1357
- })
1343
+ const cfsColl = await getCollection('cfs.files.filerecord');
1344
+ await cfsColl.deleteMany({
1345
+ 'metadata.record_id': newRecordId
1346
+ })
1347
+ } catch (cleanupError) {
1348
+ console.error(`${new Date().toISOString()} [InstanceRecordQueue.sendDoc] 清理记录失败: objectName=${objectName}, recordId=${newRecordId}`, cleanupError);
1349
+ }
1350
+ }
1358
1351
  throw error;
1359
1352
  }
1360
1353
  }
@@ -16,7 +16,7 @@ module.exports = {
16
16
  return {};
17
17
  }
18
18
 
19
- // 直接 broker.call page.getMeSchema,完全绕过 vm2 沙箱
19
+ // 直接 broker.call page.getMeSchema 获取页面 schema
20
20
  // 参考 steedos-platform/services/service-pages/main/default/routes/page_schema.router.js
21
21
  // flow_selector 这个 page 的 type 固定为 'page'
22
22
  const result = await objectql.getSteedosSchema().broker.call('page.getMeSchema', {
@@ -35,7 +35,7 @@ TimeoutAutoSubmit.Configure = function (options = {}) {
35
35
  _job = null;
36
36
  }
37
37
 
38
- console.log(`[timeout_auto_submit] Configured with interval: ${sendInterval}ms`);
38
+ console.log(`${new Date().toISOString()} [timeout_auto_submit] Configured with interval: ${sendInterval}ms`);
39
39
 
40
40
  // Convert milliseconds interval to a cron-compatible schedule using node-schedule's RecurrenceRule
41
41
  const intervalSeconds = Math.max(Math.round(sendInterval / 1000), 1);
@@ -54,12 +54,17 @@ TimeoutAutoSubmit.Configure = function (options = {}) {
54
54
  return;
55
55
  }
56
56
  _isProcessing = true;
57
+ const startTime = Date.now();
57
58
  try {
58
- console.time('[timeout_auto_submit] execution');
59
59
  await UUFlowManager.timeoutAutoSubmit();
60
- console.timeEnd('[timeout_auto_submit] execution');
60
+ const duration = Date.now() - startTime;
61
+ if (duration > 5000) {
62
+ console.log(`${new Date().toISOString()} [timeout_auto_submit] Completed in ${duration}ms`);
63
+ }
61
64
  } catch (error) {
62
- console.error('[timeout_auto_submit] Error during scheduled execution:', error.stack || error);
65
+ const duration = Date.now() - startTime;
66
+ console.error(`${new Date().toISOString()} [timeout_auto_submit] Fatal error after ${duration}ms: ${error.message}`);
67
+ console.error(`${new Date().toISOString()} [timeout_auto_submit] Stack trace:`, error.stack);
63
68
  } finally {
64
69
  _isProcessing = false;
65
70
  }
@@ -75,7 +80,7 @@ TimeoutAutoSubmit.Stop = function () {
75
80
  _job = null;
76
81
  }
77
82
  _isProcessing = false;
78
- console.log('[timeout_auto_submit] Stopped');
83
+ console.log(`${new Date().toISOString()} [timeout_auto_submit] Stopped`);
79
84
  };
80
85
 
81
86
  module.exports = TimeoutAutoSubmit;