weaver-work-cli 0.1.32 → 0.1.33
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/README.md +2 -2
- package/dist/chunks/{archive-UMGX72K6.js → archive-FVFY6GZN.js} +2 -2
- package/dist/chunks/{archive-oa-N2IYBLF3.js → archive-oa-NW3OD4UV.js} +2 -2
- package/dist/chunks/{asset-GLEGKFG5.js → asset-7QJKMIDV.js} +2 -2
- package/dist/chunks/{attachment-content-AQNX5N3S.js → attachment-content-OSAVA6K3.js} +3 -2
- package/dist/chunks/{blog-E44OTVDA.js → blog-I7SDPNW4.js} +2 -2
- package/dist/chunks/{caizhilian-DQUFZXZL.js → caizhilian-O37ZIQNY.js} +2 -2
- package/dist/chunks/{calendar-JKPIRKFD.js → calendar-7KXE4ED3.js} +2 -2
- package/dist/chunks/{chunk-4YC43QQ4.js → chunk-2FLWXFVS.js} +4 -4
- package/dist/chunks/{chunk-QWY6PGL6.js → chunk-2LV74IWP.js} +361 -56
- package/dist/chunks/chunk-3SO6QL6U.js +73 -0
- package/dist/chunks/{chunk-DW6AUUKS.js → chunk-6ATGWRZM.js} +6 -4
- package/dist/chunks/chunk-BYATLLEF.js +68 -0
- package/dist/chunks/chunk-BYBSCN4X.js +932 -0
- package/dist/chunks/{chunk-2GA5ZIQL.js → chunk-D223PTXU.js} +1 -0
- package/dist/chunks/{chunk-H7J4DC5R.js → chunk-EEWPQE3O.js} +2 -2
- package/dist/chunks/{chunk-6RKD4DRZ.js → chunk-GFPXQIY2.js} +2 -2
- package/dist/chunks/{chunk-C6R3B2ML.js → chunk-HEL5XTYI.js} +12 -6
- package/dist/chunks/{chunk-CVZ2JOSW.js → chunk-IHUYP6LO.js} +1 -1
- package/dist/chunks/{chunk-YRVDW4WN.js → chunk-ILMBNVSG.js} +2 -2
- package/dist/chunks/{chunk-G3QJULO2.js → chunk-KAS45KNR.js} +1 -1
- package/dist/chunks/{chunk-H6XSTSLM.js → chunk-MEEFGWTM.js} +54 -196
- package/dist/chunks/{chunk-GCG2NMWR.js → chunk-MQ2I5AA3.js} +4 -2
- package/dist/chunks/chunk-NHA62QD7.js +774 -0
- package/dist/chunks/{chunk-WKI2FBIQ.js → chunk-OCU4RLHC.js} +641 -309
- package/dist/chunks/{chunk-WSKBSQ2U.js → chunk-PRHJGPMA.js} +2 -2
- package/dist/chunks/{chunk-6EFWDL7Y.js → chunk-Q6LWB5HX.js} +2 -2
- package/dist/chunks/{chunk-IURUFGZK.js → chunk-RBGOMK4Y.js} +50 -33
- package/dist/chunks/chunk-VBCFFFGT.js +226 -0
- package/dist/chunks/{ebuilder-form-V5FG2EHC.js → chunk-WRRJ4GG2.js} +22 -1148
- package/dist/chunks/{chunk-E4Z23GHM.js → chunk-WY74UBJ6.js} +264 -750
- package/dist/chunks/conflict-SFNEVJY5.js +21 -0
- package/dist/chunks/continuation-RN6PZN2M.js +11 -0
- package/dist/chunks/cowork-CKWYHXYB.js +2508 -0
- package/dist/chunks/ebuilder-form-KOLJRVZD.js +121 -0
- package/dist/chunks/{ehr-HMFY6VIL.js → ehr-WFOC3B4D.js} +1174 -20
- package/dist/chunks/{esb-ZYSVB7SG.js → esb-LJZTN663.js} +4 -4
- package/dist/chunks/{fna-B7RKPAZD.js → fna-F7QRIIZC.js} +2 -2
- package/dist/chunks/{host-45WED2KK.js → host-BCGUVEWX.js} +3 -3
- package/dist/chunks/host-BQBRHVR3.js +23 -0
- package/dist/chunks/{host-I4Z6BFYX.js → host-DGE2TZD4.js} +3 -3
- package/dist/chunks/{host-KNZ52LJZ.js → host-KXPTEWFS.js} +3 -3
- package/dist/chunks/{host-OCH2BCCV.js → host-VQ6JJXGQ.js} +3 -3
- package/dist/chunks/{hrm-2KAZGUHI.js → hrm-NI6XAKW5.js} +3 -3
- package/dist/chunks/{im-ACJJWH4U.js → im-7TRTF3KT.js} +88 -12
- package/dist/chunks/{invoice-ZK3WCX2U.js → invoice-AOXWJKYT.js} +3 -3
- package/dist/chunks/{jiuchuanhui-5PQD3IL2.js → jiuchuanhui-7NQWEZAW.js} +2 -2
- package/dist/chunks/{lazy-dispatch-JQXBW3GM.js → lazy-dispatch-RNS4EE4S.js} +4 -4
- package/dist/chunks/{mail-S2HDDXO2.js → mail-VDHJAB4O.js} +3 -3
- package/dist/chunks/{meeting-QVN3I37L.js → meeting-GA7XCNNP.js} +214 -43
- package/dist/chunks/{okr-QNG4VC2Q.js → okr-TQIRERPQ.js} +2 -2
- package/dist/chunks/operations-5QL3AECO.js +11 -0
- package/dist/chunks/{plan-A25EMW6U.js → plan-4RY4LN2P.js} +2 -2
- package/dist/chunks/{project-G6XV66DZ.js → project-D6XT2OC5.js} +2 -2
- package/dist/chunks/{registry-DC6KR3NH.js → registry-JHRIDQ3A.js} +4 -4
- package/dist/chunks/{registry-2VLUAESA.js → registry-OZSMDVPP.js} +2 -2
- package/dist/chunks/{registry-TI3CIUXF.js → registry-QKMI43Q6.js} +8 -6
- package/dist/chunks/{registry-7C5UMIPL.js → registry-VOGKFFTR.js} +2 -2
- package/dist/chunks/{room-recommend-WRTHO6Y2.js → room-recommend-D4EUOOWY.js} +4 -3
- package/dist/chunks/{schedule-KFIITGSK.js → schedule-XPFBHPCV.js} +4 -3
- package/dist/chunks/{workflow-DJ7SYWAF.js → workflow-HLBZRWIY.js} +172 -6
- package/dist/index.js +30 -25
- package/dist/internal/e10/auth-recovery.js +14 -4
- package/dist/shortcuts/contract/host.js +34 -59
- package/dist/shortcuts/cowork/continuation.js +70 -0
- package/dist/shortcuts/cowork/errors.js +59 -0
- package/dist/shortcuts/cowork/host.js +172 -0
- package/dist/shortcuts/cowork/index.js +166 -0
- package/dist/shortcuts/cowork/manifest.js +65 -0
- package/dist/shortcuts/cowork/operations/discuss-write.js +277 -0
- package/dist/shortcuts/cowork/operations/item-write.js +380 -0
- package/dist/shortcuts/cowork/operations/member-write.js +283 -0
- package/dist/shortcuts/cowork/operations/permission-write.js +286 -0
- package/dist/shortcuts/cowork/operations/read.js +423 -0
- package/dist/shortcuts/cowork/operations/registry.js +39 -0
- package/dist/shortcuts/cowork/operations/review-write.js +157 -0
- package/dist/shortcuts/cowork/operations/shared.js +215 -0
- package/dist/shortcuts/cowork/operations/types.js +24 -0
- package/dist/shortcuts/cowork/operations.js +19 -0
- package/dist/shortcuts/ehr/host.js +4 -1
- package/dist/shortcuts/ehr/operations/recruit-candidate-import.js +757 -0
- package/dist/shortcuts/ehr/operations/recruit-position.js +367 -0
- package/dist/shortcuts/ehr/operations/recruit-stats.js +133 -0
- package/dist/shortcuts/ehr/operations/recruit-write.js +8 -16
- package/dist/shortcuts/ehr/operations/recruit.js +35 -10
- package/dist/shortcuts/ehr/operations/registry.js +6 -0
- package/dist/shortcuts/im/diagnostics.js +97 -0
- package/dist/shortcuts/im/host.js +58 -31
- package/dist/shortcuts/im/index.js +7 -2
- package/dist/shortcuts/im/operations/at-mention.js +127 -0
- package/dist/shortcuts/im/operations/file-user.js +10 -2
- package/dist/shortcuts/im/operations/group-read.js +26 -5
- package/dist/shortcuts/im/operations/group-write.js +35 -28
- package/dist/shortcuts/im/operations/msg-sync.js +7 -2
- package/dist/shortcuts/im/operations/msg-write.js +76 -10
- package/dist/shortcuts/im/operations/quote-mention.js +119 -0
- package/dist/shortcuts/im/operations/session.js +1 -1
- package/dist/shortcuts/im/operations/shared.js +10 -0
- package/dist/shortcuts/im/operations/types.js +13 -0
- package/dist/shortcuts/index.js +5 -0
- package/dist/shortcuts/mail/host.js +4 -1
- package/dist/shortcuts/meeting/host.js +27 -34
- package/dist/shortcuts/meeting/operations/create.js +4 -1
- package/dist/shortcuts/meeting/operations/eb/catalog.js +5 -0
- package/dist/shortcuts/meeting/operations/eb/conflict.js +78 -7
- package/dist/shortcuts/meeting/operations/eb/create-flow.js +168 -26
- package/dist/shortcuts/meeting/operations/eb/factory.js +69 -1
- package/dist/shortcuts/meeting/operations/eb/index.js +16 -3
- package/dist/shortcuts/meeting/operations/eb/room-recommend.js +14 -3
- package/dist/shortcuts/meeting/operations/eb-fallback.js +159 -0
- package/dist/shortcuts/meeting/operations/env.js +93 -46
- package/dist/shortcuts/meeting/operations/form-fields.js +110 -0
- package/dist/shortcuts/meeting/operations/registry.js +2 -0
- package/dist/shortcuts/meeting/operations/standard-guard.js +71 -0
- package/dist/shortcuts/meeting/operations.js +16 -0
- package/dist/shortcuts/workflow/index.js +110 -1
- package/dist/shortcuts/workflow/operations/form.js +24 -3
- package/dist/shortcuts/workflow/operations/read.js +104 -23
- package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupRules.js +448 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupStore.js +106 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/businessRules.js +47 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +30 -23
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.core.js +1 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.group.js +1 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +2 -1
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +2 -4
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +138 -181
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +12 -7
- package/docs/e10-auth.md +1 -1
- package/docs/im.md +8 -1
- package/docs/todo-smart-convert/README.md +1 -1
- package/docs/todo-smart-convert/data-contract.md +2 -2
- package/docs/todo-smart-convert/subgroup-rules.md +6 -0
- package/package.json +1 -1
- package/skill-template/domains/yimiaoban.md +3 -3
- package/skill-template/skill-template.md +1 -1
- package/skills/weaver-e10-blog/SKILL.md +5 -5
- package/skills/weaver-e10-caizhilian/SKILL.md +5 -5
- package/skills/weaver-e10-calendar/SKILL.md +5 -5
- package/skills/weaver-e10-esb/SKILL.md +5 -5
- package/skills/weaver-e10-hrm/SKILL.md +5 -5
- package/skills/weaver-e10-jinchengda/SKILL.md +2 -2
- package/skills/weaver-e10-jiuchuanhui/SKILL.md +5 -5
- package/skills/weaver-e10-jucailin/SKILL.md +18 -12
- package/skills/weaver-e10-jucailin/references/recruit-create.md +104 -0
- package/skills/weaver-e10-mail/SKILL.md +5 -5
- package/skills/weaver-e10-meeting/SKILL.md +171 -25
- package/skills/weaver-e10-meeting/references/meeting-eb.md +4 -3
- package/skills/weaver-e10-meeting/references/meeting-queries.md +9 -6
- package/skills/weaver-e10-meeting/references/meeting-verification.md +8 -6
- package/skills/weaver-e10-meeting.zip +0 -0
- package/skills/weaver-e10-okr/SKILL.md +5 -5
- package/skills/weaver-e10-okr/references/source-manifest.json +3 -3
- package/skills/weaver-e10-plan/SKILL.md +5 -5
- package/skills/weaver-e10-shared/SKILL.md +12 -12
- package/skills/weaver-e10-shared/references/e10-auth-and-session.md +4 -4
- package/skills/weaver-e10-wenshuding/SKILL.md +5 -5
- package/skills/weaver-e10-workflow/SKILL.md +29 -5
- package/skills/weaver-e10-workflow/aigroup/default.json +88 -0
- package/skills/weaver-e10-workflow/references/todo-smart-convert.md +66 -14
- package/skills/weaver-e10-workflow/references/workflow-agent-entry.md +1 -1
- package/skills/weaver-e10-workflow/references/workflow-memory.md +1 -1
- package/skills/weaver-e10-workflow/references/workflow-query.md +12 -10
- package/skills/weaver-e10-workflow/references/workflow-view.md +2 -2
- package/skills/weaver-e10-workflow/tools/todo-serve.cjs +239 -0
- package/skills/weaver-e10-workflow/{scripts → tools}/todo-summary.cjs +218 -28
- package/skills/weaver-e10-yepiaotong/SKILL.md +10 -8
- package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +7 -7
- package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +10 -10
- package/skills/weaver-e10-yepiaotong/references/reim-examples.md +40 -37
- package/skills/weaver-e10-yepiaotong/references/reim-expense-subject-rules.md +4 -4
- package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +27 -38
- package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +4 -4
- package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +37 -29
- package/skills/weaver-e10-yimiaoban/SKILL.md +156 -33
- package/skills/weaver-e10-yimiaoban/references/ding-write.md +1 -1
- package/skills/weaver-e10-yimiaoban/references/error-codes.md +5 -1
- package/skills/weaver-e10-yimiaoban/references/group-read.md +5 -1
- package/skills/weaver-e10-yimiaoban/references/group-write.md +6 -4
- package/skills/weaver-e10-yimiaoban/references/msg-read.md +1 -0
- package/skills/weaver-e10-yimiaoban/references/msg-write.md +34 -2
- package/skills/weaver-e10-yimiaoban/references/safety-boundaries.md +5 -2
- package/skills/weaver-e10-yimiaoban/references/source-manifest.json +79 -58
- package/skills/weaver-e10-yimiaoban/references/user-remind.md +2 -2
- package/skills/weaver-e10-ziguanjia/SKILL.md +5 -5
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { MeetingCliError } from '../errors.js';
|
|
2
|
+
import { readCache } from './env.js';
|
|
3
|
+
/**
|
|
4
|
+
* 标准版会议 operation → 对应的 EB operation。
|
|
5
|
+
*
|
|
6
|
+
* ⛔ 存在的理由(2026-10-29 真机事故):e-cology 这类租户**同时装了标准会议应用和 EB 会议应用**,
|
|
7
|
+
* 两套数据完全不通(标准版 `meeting.room.list` 返回 74 间「317/342/442会议室」,
|
|
8
|
+
* EB 的 `uf_mt_room_base` 只有 1 间「测试会议室1」)。agent 在 EB 环境误调标准版接口时,
|
|
9
|
+
* 接口**不会报错、照常返回数据**,于是把根本不存在的会议室/会议摆到用户面前,用户还以为数据错了。
|
|
10
|
+
*
|
|
11
|
+
* 所以这里做一道闸:**环境已确认是 EB 时,标准版会议接口直接拒绝**,并给出对应的 EB operation。
|
|
12
|
+
* 只拦"会议域且语义对得上"的 operation —— 其余的(登录、附件、二维码等)不涉及双套数据,放行。
|
|
13
|
+
*/
|
|
14
|
+
const STANDARD_TO_EB = {
|
|
15
|
+
'meeting.list': 'meeting.eb.meeting.list',
|
|
16
|
+
'meeting.detail.field': 'meeting.eb.meeting.detail',
|
|
17
|
+
'meeting.room.list': 'meeting.eb.room.list',
|
|
18
|
+
'meeting.room.usage': 'meeting.eb.roomUsage.list',
|
|
19
|
+
'meeting.type.list': 'meeting.eb.type.list',
|
|
20
|
+
'meeting.receipt.list': 'meeting.eb.receipt.list',
|
|
21
|
+
'meeting.sign.list': 'meeting.eb.sign.list',
|
|
22
|
+
'meeting.conflict.room': 'meeting.eb.conflict.room',
|
|
23
|
+
'meeting.conflict.member': 'meeting.eb.conflict.member',
|
|
24
|
+
'meeting.roomAttribute.list': 'meeting.eb.room.list',
|
|
25
|
+
};
|
|
26
|
+
/** 逃生开关:确认要看标准版数据时设 `WEAVER_MEETING_ALLOW_STANDARD_IN_EB=1`。 */
|
|
27
|
+
function escapeEnabled() {
|
|
28
|
+
const flag = String(process.env.WEAVER_MEETING_ALLOW_STANDARD_IN_EB ?? '').trim().toLowerCase();
|
|
29
|
+
return flag === '1' || flag === 'true';
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* 标准版会议 operation 的环境守卫。
|
|
33
|
+
*
|
|
34
|
+
* 判据只用**已确认的**环境结论(env-mode 缓存):
|
|
35
|
+
* - 缓存说 `eb` → 拒绝(本次事故场景);
|
|
36
|
+
* - 缓存说 `standard` → 放行(这正是降级后的正常状态);
|
|
37
|
+
* - **没有缓存 → 放行**。未探测不等于 EB:标准版租户首次使用不该被拦,
|
|
38
|
+
* 拦住反而会让"第一次就能用"的体验断掉。要纠偏就跑 `meeting.env.detect --refresh`。
|
|
39
|
+
*/
|
|
40
|
+
export async function assertStandardOperationAllowed(operation, context) {
|
|
41
|
+
const peer = STANDARD_TO_EB[operation];
|
|
42
|
+
if (!peer)
|
|
43
|
+
return;
|
|
44
|
+
if (escapeEnabled())
|
|
45
|
+
return;
|
|
46
|
+
let mode;
|
|
47
|
+
try {
|
|
48
|
+
const session = await context.host.getSession();
|
|
49
|
+
const cache = await readCache(context.ctx);
|
|
50
|
+
mode = cache.environments[session.baseUrl]?.mode;
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// 缓存读不到(权限/损坏)不应阻断业务:按"未确认"处理,放行。
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
if (mode !== 'eb')
|
|
57
|
+
return;
|
|
58
|
+
throw new MeetingCliError('api', 'env_mismatch', `当前环境已确认为 **EB 版**,\`${operation}\` 是**标准版**接口,返回的是另一套数据(两套会议数据互不相通,`
|
|
59
|
+
+ '标准版会议室/会议在这里是不存在的东西)。请改用 EB operation **`' + peer + '`**。'
|
|
60
|
+
+ '如果确实要读标准版数据(极少见),设环境变量 `WEAVER_MEETING_ALLOW_STANDARD_IN_EB=1` 后再跑。', {
|
|
61
|
+
code: 'env_mismatch',
|
|
62
|
+
details: {
|
|
63
|
+
requestedOperation: operation,
|
|
64
|
+
standardOperation: operation,
|
|
65
|
+
ebOperation: peer,
|
|
66
|
+
envMode: 'eb',
|
|
67
|
+
},
|
|
68
|
+
retryable: false,
|
|
69
|
+
exitCode: 1,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
@@ -3,6 +3,8 @@ import { dirname, join } from 'node:path';
|
|
|
3
3
|
import { getMeetingOperation } from './operations/registry.js';
|
|
4
4
|
import { assertNoForbiddenKeys, asObject } from './operations/shared.js';
|
|
5
5
|
import { meetingStateDir } from './operations/env.js';
|
|
6
|
+
import { tryDegradeEbFailure } from './operations/eb-fallback.js';
|
|
7
|
+
import { assertStandardOperationAllowed } from './operations/standard-guard.js';
|
|
6
8
|
/**
|
|
7
9
|
* 调用流水(best-effort):每次 operation 追加一行 JSON 到 `<state>/meeting/logs/calls.jsonl`。
|
|
8
10
|
*
|
|
@@ -49,12 +51,26 @@ export async function executeMeetingOperation(operation, rawInput, context) {
|
|
|
49
51
|
};
|
|
50
52
|
const startedAt = Date.now();
|
|
51
53
|
try {
|
|
54
|
+
// 环境守卫(2026-10-29):环境已确认是 EB 时,标准版会议接口直接拒绝 ——
|
|
55
|
+
// 两套数据不通,标准版照常返回 74 间"不存在的会议室",agent 会原样转述给用户。
|
|
56
|
+
await assertStandardOperationAllowed(operation, { ...context, host });
|
|
52
57
|
const envelope = await definition.handler(input, { ...context, host });
|
|
53
58
|
recordCall(context, operation, startedAt, true);
|
|
54
59
|
return envelope;
|
|
55
60
|
}
|
|
56
61
|
catch (error) {
|
|
57
62
|
recordCall(context, operation, startedAt, false, String(error?.type ?? 'unknown'));
|
|
63
|
+
// EB 优先 + 惰性降级:EB operation 在这个环境走不通时,实探标准版并把 standard 固化进
|
|
64
|
+
// env 缓存,然后抛 `env_fallback` 指引调用方改用标准版 operation。标准版也不通则保持原错误。
|
|
65
|
+
try {
|
|
66
|
+
const degraded = await tryDegradeEbFailure(operation, error, context.host, context.ctx);
|
|
67
|
+
if (degraded)
|
|
68
|
+
throw degraded;
|
|
69
|
+
}
|
|
70
|
+
catch (rethrow) {
|
|
71
|
+
if (rethrow !== error)
|
|
72
|
+
throw rethrow;
|
|
73
|
+
}
|
|
58
74
|
throw error;
|
|
59
75
|
}
|
|
60
76
|
}
|
|
@@ -6,6 +6,9 @@ import { workflowManifest } from './manifest.js';
|
|
|
6
6
|
import { executeWorkflowOperation } from './operations.js';
|
|
7
7
|
import { workflowValidationError } from './errors.js';
|
|
8
8
|
import { compactStdoutPaths } from './stdout-compact.js';
|
|
9
|
+
import { join } from 'node:path';
|
|
10
|
+
import { loadRules, resetActiveRules } from './operations/todoSmartConvert/aigroupRules.js';
|
|
11
|
+
import { clearUserIntents, readRawUserIntents, readUserIntents, saveUserIntents, } from './operations/todoSmartConvert/aigroupStore.js';
|
|
9
12
|
function asOptions(value) {
|
|
10
13
|
return value && typeof value === 'object' && !Array.isArray(value) ? value : {};
|
|
11
14
|
}
|
|
@@ -114,6 +117,53 @@ async function executeAndPrint(ctx, operation, input) {
|
|
|
114
117
|
process.exitCode = isCliError(error) ? error.exitCode : ExitCode.GeneralError;
|
|
115
118
|
}
|
|
116
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* 目录里的 `fields` 只取 `inputSchema.properties` 的键名,供 agent 判断「这个字段存不存在」。
|
|
122
|
+
*
|
|
123
|
+
* ★ 2026-10-28:整份 manifest 实测 65,748 B,超过 stdout 预算(`DEFAULT_RESULT_THRESHOLD_BYTES`
|
|
124
|
+
* = 24 KB)后,公共输出层按 `COMPACT_TIERS` 第一档把 `operations` 截到 10 条 —— 26 个 operation 里
|
|
125
|
+
* 排在后面的(`createRequest` 之后,含 `workflow.todoSmartConvert`)在 stdout 上完全不可见,
|
|
126
|
+
* 且没有任何「还有 16 条」的提示。此处改为默认编目形态(约 15 KB,26 条全可见),
|
|
127
|
+
* 完整 inputSchema 用 `--operation` 单取,整份完整 manifest 用 `--full`。
|
|
128
|
+
*/
|
|
129
|
+
function fieldNamesOf(inputSchema) {
|
|
130
|
+
const properties = inputSchema.properties;
|
|
131
|
+
if (!properties || typeof properties !== 'object' || Array.isArray(properties))
|
|
132
|
+
return [];
|
|
133
|
+
return Object.keys(properties);
|
|
134
|
+
}
|
|
135
|
+
function manifestIndex() {
|
|
136
|
+
return {
|
|
137
|
+
schemaVersion: workflowManifest.schemaVersion,
|
|
138
|
+
name: workflowManifest.name,
|
|
139
|
+
title: workflowManifest.title,
|
|
140
|
+
version: workflowManifest.version,
|
|
141
|
+
host: workflowManifest.host,
|
|
142
|
+
status: workflowManifest.status,
|
|
143
|
+
sourceSkill: workflowManifest.sourceSkill,
|
|
144
|
+
capabilities: workflowManifest.capabilities,
|
|
145
|
+
operationCount: workflowManifest.operations.length,
|
|
146
|
+
operations: workflowManifest.operations.map((definition) => ({
|
|
147
|
+
name: definition.name,
|
|
148
|
+
resource: definition.resource,
|
|
149
|
+
summary: definition.summary,
|
|
150
|
+
...(definition.capability ? { capability: definition.capability } : {}),
|
|
151
|
+
risk: definition.risk,
|
|
152
|
+
...(definition.requiresConfirmation ? { requiresConfirmation: true } : {}),
|
|
153
|
+
fields: fieldNamesOf(definition.inputSchema),
|
|
154
|
+
})),
|
|
155
|
+
withheldOperations: workflowManifest.withheldOperations,
|
|
156
|
+
operationsHint: '默认只列 operation 与字段名;字段类型、枚举和填写口径用 `workflow schema --operation <name>` 单取,整份完整 manifest 用 `workflow schema --full`。',
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function findOperationContract(name) {
|
|
160
|
+
const full = name.startsWith('workflow.') ? name : `workflow.${name}`;
|
|
161
|
+
const matched = workflowManifest.operations.find((definition) => definition.name === full);
|
|
162
|
+
if (!matched) {
|
|
163
|
+
throw workflowValidationError('operation_unknown', `流程模块不支持操作:${name}`);
|
|
164
|
+
}
|
|
165
|
+
return matched;
|
|
166
|
+
}
|
|
117
167
|
function withJsonInputOptions(command) {
|
|
118
168
|
command
|
|
119
169
|
.option('--input <path>', 'JSON input file, or - for stdin')
|
|
@@ -130,8 +180,67 @@ export const workflowShortcut = {
|
|
|
130
180
|
.description('泛微E10流程智能助手(待办/已办/我发起/全部、详情、操作、批量、发起、修改)');
|
|
131
181
|
workflow.command('schema')
|
|
132
182
|
.description('Print workflow operation manifest for agents')
|
|
183
|
+
.option('--operation <name>', 'print one operation with its full inputSchema')
|
|
184
|
+
.option('--full', 'print the whole manifest (about 65 KB; stdout may be trimmed)')
|
|
185
|
+
.action(action((ctx, options) => {
|
|
186
|
+
const opts = asOptions(options);
|
|
187
|
+
const requested = String(opts.operation ?? '').trim();
|
|
188
|
+
if (requested && opts.full === true) {
|
|
189
|
+
throw workflowValidationError('option_conflict', '不能同时传 --operation 和 --full');
|
|
190
|
+
}
|
|
191
|
+
if (opts.full === true) {
|
|
192
|
+
ctx.output.write(workflowManifest, { json: true });
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
if (requested) {
|
|
196
|
+
ctx.output.write(findOperationContract(requested), { json: true });
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
ctx.output.write(manifestIndex(), { json: true });
|
|
200
|
+
}));
|
|
201
|
+
/**
|
|
202
|
+
* ai二次分组规则库:`<skill>/aigroup/default.json`(系统只读)+ CLI 状态目录下的
|
|
203
|
+
* `aigroup/user-intents.json`(用户意图,不随 skill 分发)。
|
|
204
|
+
* 意图由模型理解、但**落盘必须结构化**:这里统一做校验 + 按 workflowName 整条覆盖。
|
|
205
|
+
*/
|
|
206
|
+
const aigroup = workflow
|
|
207
|
+
.command('aigroup')
|
|
208
|
+
.description('ai二次分组规则库(默认规则 + 用户意图)');
|
|
209
|
+
aigroup.command('show')
|
|
210
|
+
.description('Print effective ai-group rules (default merged with user intents)')
|
|
211
|
+
.option('--raw', 'also print user-intents.json as stored on disk')
|
|
212
|
+
.action(action((ctx, options) => {
|
|
213
|
+
const opts = asOptions(options);
|
|
214
|
+
const loaded = loadRules({ ctx: ctx });
|
|
215
|
+
const user = readUserIntents({ ctx: ctx });
|
|
216
|
+
ctx.output.write({
|
|
217
|
+
dir: loaded.dir,
|
|
218
|
+
defaultFile: join(loaded.dir, 'default.json'),
|
|
219
|
+
userIntentFile: user.file,
|
|
220
|
+
userIntentExists: user.exists,
|
|
221
|
+
userIntentError: user.error,
|
|
222
|
+
defaults: loaded.file.defaults,
|
|
223
|
+
rules: loaded.file.rules,
|
|
224
|
+
userRules: user.rules,
|
|
225
|
+
warnings: loaded.warnings,
|
|
226
|
+
...(opts.raw === true && user.exists ? { rawUserIntents: readRawUserIntents(user.file) } : {}),
|
|
227
|
+
}, { json: true });
|
|
228
|
+
}));
|
|
229
|
+
withJsonInputOptions(aigroup.command('set')
|
|
230
|
+
.description('Save user-intent rules: validated, whole-entry replace by workflowName')
|
|
231
|
+
.action(action(async (ctx, options) => {
|
|
232
|
+
const payload = await inputFrom(options);
|
|
233
|
+
const result = saveUserIntents(payload, { ctx: ctx });
|
|
234
|
+
// 同一进程内后续命令要看到新规则,避免读到旧的进程内缓存
|
|
235
|
+
resetActiveRules();
|
|
236
|
+
ctx.output.write(result, { json: true });
|
|
237
|
+
})));
|
|
238
|
+
aigroup.command('clear')
|
|
239
|
+
.description('Empty user-intent rules (default.json is never touched)')
|
|
133
240
|
.action(action((ctx) => {
|
|
134
|
-
|
|
241
|
+
const file = clearUserIntents({ ctx: ctx });
|
|
242
|
+
resetActiveRules();
|
|
243
|
+
ctx.output.write({ cleared: true, file }, { json: true });
|
|
135
244
|
}));
|
|
136
245
|
withJsonInputOptions(workflow.command('run')
|
|
137
246
|
.description('Run a workflow operation with JSON input')
|
|
@@ -24,7 +24,7 @@ import { resolveSignRemark } from './sign-input.js';
|
|
|
24
24
|
import { compactStdoutPaths } from '../stdout-compact.js';
|
|
25
25
|
import { continuationReplayError } from '../continuation.js';
|
|
26
26
|
import { writeStateFileBestEffort } from '../state.js';
|
|
27
|
-
import { buildHistoryRequestData, fetchHistoryListSnapshot, filterHistoryRequestData, pickUniqueMineWorkflow } from './read.js';
|
|
27
|
+
import { buildHistoryRequestData, fetchHistoryListSnapshot, filterHistoryRequestData, pickUniqueMineWorkflow, prefetchHistoryDetails } from './read.js';
|
|
28
28
|
import { hasXiaoEEnv } from '../../../internal/e10/auth/xiaoe.js';
|
|
29
29
|
import { buildChatSceneInput, formatLocalNow, requestFormFill } from './chatscene.js';
|
|
30
30
|
// ---------------------------------------------------------------------------
|
|
@@ -448,6 +448,12 @@ function parseTenantSetting(data) {
|
|
|
448
448
|
* 只读字段 35→0);不带时拿到的才是表单设计级的真实属性。
|
|
449
449
|
*/
|
|
450
450
|
function buildLayoutRequest(workflowId, runtime, frame) {
|
|
451
|
+
// 建模表单(relateType=WEA_EBUILDER)的 `module` 与桥接服务名都不是 workflow:服务端按请求体里的
|
|
452
|
+
// `module` 解析 `@Service("<module>_FormCoreService")`,传 `workflow` 会直接 500「未找到名为
|
|
453
|
+
// FormCoreService 的实例对象」(2026-10-29 e-cology 建模流程 1179913136549412865 实测:只把该值
|
|
454
|
+
// 改成 ebuildercard 即 200,其余 params 逐字不变)。页面同场景传 `module:"ebuildercard"` +
|
|
455
|
+
// `customParam.bridgeService:"ebuilder"`(`loadBaseParam` 顶层也返回 `bridgeService:"ebuilder"`)。
|
|
456
|
+
const isEbForm = String(frame.relate_type ?? '').trim() === 'WEA_EBUILDER';
|
|
451
457
|
const custom = {
|
|
452
458
|
permissionType: frame.permission_type,
|
|
453
459
|
requestId: runtime.request_id,
|
|
@@ -463,6 +469,7 @@ function buildLayoutRequest(workflowId, runtime, frame) {
|
|
|
463
469
|
mobile: false,
|
|
464
470
|
formId: frame.form_id,
|
|
465
471
|
source: 'view',
|
|
472
|
+
...(isEbForm ? { bridgeService: 'ebuilder' } : {}),
|
|
466
473
|
isAgent: false,
|
|
467
474
|
beAgentId: '0',
|
|
468
475
|
hideSysFieldArea: true,
|
|
@@ -478,7 +485,7 @@ function buildLayoutRequest(workflowId, runtime, frame) {
|
|
|
478
485
|
terminalType: 'PC',
|
|
479
486
|
formId: frame.form_id,
|
|
480
487
|
...(nodePermissionEnabled && permissionId ? { permissionId } : {}),
|
|
481
|
-
module: 'workflow',
|
|
488
|
+
module: isEbForm ? 'ebuildercard' : 'workflow',
|
|
482
489
|
customParam: custom,
|
|
483
490
|
cacheUid: randomUUID(),
|
|
484
491
|
newLayout: frame.new_layout,
|
|
@@ -1959,6 +1966,18 @@ async function buildCreateFormData(workflowId, env) {
|
|
|
1959
1966
|
* 兜住之后就不会留下未处理的拒绝;真要暴露的认证/网络错误由同批的载入请求抛出,不会被吞掉。
|
|
1960
1967
|
*/
|
|
1961
1968
|
const historyListSnapshot = fetchHistoryListSnapshot(env, { workflowId }).catch(() => null);
|
|
1969
|
+
/**
|
|
1970
|
+
* 明细请求紧跟着**列表**走(2026-10-29 用户口径):它的入参只有 `requestId`(列表给的)与会话
|
|
1971
|
+
* `userId`,与 `getFormLayout` **没有任何参数依赖**;原先排在 layout 之后纯属写法问题,白等约
|
|
1972
|
+
* 100 ms。现在列表一返回就发出去,与 layout 并行;**取值后怎么组装一个字没改**(仍在 layout 之后
|
|
1973
|
+
* 用本表单字段清单做,见下方 `buildHistoryRequestData`)。
|
|
1974
|
+
*
|
|
1975
|
+
* `.catch(() => {})`:表单后续可能先抛错(layout 失败等),这条链就没人 `await` 了 —— 先挂一个
|
|
1976
|
+
* 空处理免得留下未处理的拒绝。真正的认证/网络错误仍由 `buildHistoryRequestData` 里那次 `await`
|
|
1977
|
+
* 决定去留(口径不变)。
|
|
1978
|
+
*/
|
|
1979
|
+
const historyDetails = historyListSnapshot.then(async (snapshot) => (snapshot && snapshot.requestIds.length ? prefetchHistoryDetails(env, snapshot) : null));
|
|
1980
|
+
historyDetails.catch(() => { });
|
|
1962
1981
|
// 2026-09-22:这四个接口**彼此没有数据依赖**(入参只需要 workflowId,见各自的 query/body),
|
|
1963
1982
|
// 真机实测各 171–429 ms、串行合计约 1.1 s;并行后只受最慢的一个约束。
|
|
1964
1983
|
// `loadMinorInfo` / `tenant/setting` 仍是 best-effort(失败只降级、不阻断),所以各自 catch 成
|
|
@@ -2319,7 +2338,9 @@ async function buildCreateFormData(workflowId, env) {
|
|
|
2319
2338
|
const historyCache = fields.length
|
|
2320
2339
|
? await buildHistoryRequestData(env, fields, historyRequiredFieldIds.map((id) => ({ id, name: String((fieldsById.get(id) || {}).name ?? id) })), { allFormFields: true, workflowId },
|
|
2321
2340
|
// 本命令开头就已并发发起的列表请求:这里只补「详情」那几步(P2)。
|
|
2322
|
-
historyListSnapshot
|
|
2341
|
+
historyListSnapshot,
|
|
2342
|
+
// 明细也已在列表返回时就发出去(与 layout 并行),这里只等它回来、按本表单字段组装。
|
|
2343
|
+
historyDetails)
|
|
2323
2344
|
: null;
|
|
2324
2345
|
const session = await getSessionContext(env);
|
|
2325
2346
|
const context = {
|
|
@@ -1717,9 +1717,9 @@ const workflowSearch = {
|
|
|
1717
1717
|
// workflow.search 执行模式路由与最终 Markdown(来源:Python resolve_workflow_search_mode /
|
|
1718
1718
|
// build_workflow_search_final_markdown / todo_probe_notice)
|
|
1719
1719
|
// ---------------------------------------------------------------------------
|
|
1720
|
-
/** 智能分组基线版本(来源:Python _SMART_GROUPING_MIN_OA_VERSION) */
|
|
1721
|
-
const SMART_GROUPING_MIN_OA_VERSION = [10, 0,
|
|
1722
|
-
/** 把版本元组格式化为 OA 习惯的四段式(尾两段补零:10.0.
|
|
1720
|
+
/** 智能分组基线版本(来源:Python _SMART_GROUPING_MIN_OA_VERSION;2026-10-29 用户口径下调到 10.0.9807.01) */
|
|
1721
|
+
const SMART_GROUPING_MIN_OA_VERSION = [10, 0, 9807, 1];
|
|
1722
|
+
/** 把版本元组格式化为 OA 习惯的四段式(尾两段补零:10.0.9807.01)。错误提示一律由常量派生,避免文案与判定漂移。 */
|
|
1723
1723
|
function formatOaVersion(tuple) {
|
|
1724
1724
|
const [a, b, c, d] = tuple;
|
|
1725
1725
|
return `${a}.${b}.${c}.${String(d).padStart(2, '0')}`;
|
|
@@ -1833,7 +1833,7 @@ function requireProbeSuccess(probe, label, title) {
|
|
|
1833
1833
|
//
|
|
1834
1834
|
// 来源:Python `execute_grouped_todo_search` / `normalize_todo_group_list` /
|
|
1835
1835
|
// `combine_todo_group_results` / `build_grouped_todo_summary_markdown`
|
|
1836
|
-
// (V11.2 查询逻辑,V11.3 由 legacy 分支沿用)。恢复版本门槛后(阈值 10.0.
|
|
1836
|
+
// (V11.2 查询逻辑,V11.3 由 legacy 分支沿用)。恢复版本门槛后(阈值 10.0.9807.01),
|
|
1837
1837
|
// 低版本 OA 环境将长期走这条分支,故必须与 V11.3 对齐。
|
|
1838
1838
|
//
|
|
1839
1839
|
// 未移植项(有意为之):V11.3 的 `frequentPreference` / `batchSuggestions` 两路依赖
|
|
@@ -5153,6 +5153,33 @@ function formatHistoryFieldValue(raw, field) {
|
|
|
5153
5153
|
}
|
|
5154
5154
|
return stringifyDetailValue(raw);
|
|
5155
5155
|
}
|
|
5156
|
+
/**
|
|
5157
|
+
* SaaS 公有云正式环境域名(2026-10-29 用户口径)。
|
|
5158
|
+
*
|
|
5159
|
+
* 只有这个环境下,历史取数要在 `getMineListData` 的 `params` 里**写死**带上
|
|
5160
|
+
* `disableCheckUserPermission: '1'`(放开用户权限校验);其余环境不带该键,行为与之前完全一致。
|
|
5161
|
+
*/
|
|
5162
|
+
const SAAS_COLOGY_BASE_URL = 'https://www.e-cology.com.cn';
|
|
5163
|
+
/** 比 baseUrl 时容忍末尾斜杠与大小写差异(`E10AuthSession.getBaseUrl()` 已去掉末尾斜杠)。 */
|
|
5164
|
+
function isSaasCologyBaseUrl(baseUrl) {
|
|
5165
|
+
const normalize = (value) => String(value ?? '').trim().replace(/\/+$/u, '').toLowerCase();
|
|
5166
|
+
return normalize(baseUrl) === SAAS_COLOGY_BASE_URL;
|
|
5167
|
+
}
|
|
5168
|
+
/**
|
|
5169
|
+
* 当前环境是否 SaaS 公有云(`https://www.e-cology.com.cn`)。
|
|
5170
|
+
*
|
|
5171
|
+
* 取不到会话时按"非 SaaS"处理并返回 `false`:这里只是决定要不要多加一个参数,真正的认证错误
|
|
5172
|
+
* 由紧随其后的列表请求自己抛出,不在这一步抢先报错。
|
|
5173
|
+
*/
|
|
5174
|
+
async function isSaasCologyEnv(env) {
|
|
5175
|
+
try {
|
|
5176
|
+
const session = await env.host.getSession();
|
|
5177
|
+
return isSaasCologyBaseUrl(session?.baseUrl);
|
|
5178
|
+
}
|
|
5179
|
+
catch {
|
|
5180
|
+
return false;
|
|
5181
|
+
}
|
|
5182
|
+
}
|
|
5156
5183
|
/**
|
|
5157
5184
|
* 历史取数的**前半段**:只发那一次列表请求。
|
|
5158
5185
|
*
|
|
@@ -5169,6 +5196,7 @@ export async function fetchHistoryListSnapshot(env, options = {}) {
|
|
|
5169
5196
|
const now = new Date();
|
|
5170
5197
|
const start = new Date(now.getTime() - HISTORY_LOOKBACK_DAYS * 24 * 60 * 60 * 1000);
|
|
5171
5198
|
const historyWorkflowId = String(options.workflowId ?? '').trim();
|
|
5199
|
+
const addDisableCheckUserPermission = await isSaasCologyEnv(env);
|
|
5172
5200
|
const listResponse = await env.host.workflowRequest({
|
|
5173
5201
|
method: 'POST',
|
|
5174
5202
|
path: WORKFLOW_ENDPOINTS.MINE_LIST,
|
|
@@ -5181,6 +5209,8 @@ export async function fetchHistoryListSnapshot(env, options = {}) {
|
|
|
5181
5209
|
flowSpareType: 1,
|
|
5182
5210
|
outType: 0,
|
|
5183
5211
|
needIutData: false,
|
|
5212
|
+
// SaaS 公有云环境写死带上(见 `SAAS_COLOGY_BASE_URL`);其余环境不带此键。
|
|
5213
|
+
...(addDisableCheckUserPermission ? { disableCheckUserPermission: '1' } : {}),
|
|
5184
5214
|
},
|
|
5185
5215
|
// `needParseData: true`:让服务端把日期等字段直接解析成可读文本(`displayData`),
|
|
5186
5216
|
// 客户端不再自己转。
|
|
@@ -5301,12 +5331,55 @@ export async function pickUniqueMineWorkflow(candidates, env) {
|
|
|
5301
5331
|
return null;
|
|
5302
5332
|
}
|
|
5303
5333
|
}
|
|
5334
|
+
/**
|
|
5335
|
+
* 历史取数的**中间段**:只把「明细」那几次请求发出去(2026-10-29 用户口径)。
|
|
5336
|
+
*
|
|
5337
|
+
* 明细请求(`getWorkflowRequest`)的入参只有 `requestId`(来自列表)+ 会话 `userId` + 四个写死的
|
|
5338
|
+
* 布尔值,路径里也没有 `formId`/`layoutId` —— 与 `getFormLayout` **没有任何参数依赖**。原先它要等
|
|
5339
|
+
* layout 才发,纯粹是因为「发请求」和「按 layout 字段清单组装」写在同一段里。拆出本函数后,调用方
|
|
5340
|
+
* 可以在**列表一返回**就把它挂上去、与 `getFormLayout` 并行,组装逻辑仍按原样在 layout 之后做。
|
|
5341
|
+
*
|
|
5342
|
+
* 不在这里吞异常:认证/网络错误照旧由 `buildHistoryRequestData` 的 catch
|
|
5343
|
+
* (`rethrowAuthOrNetworkError`)决定去留。调用方只做"预取"时,须另行 `.catch(() => {})` 兜住,
|
|
5344
|
+
* 以免表单后续先抛错时留下无人 `await` 的未处理拒绝。
|
|
5345
|
+
*/
|
|
5346
|
+
export function prefetchHistoryDetails(env, listed) {
|
|
5347
|
+
const requestIds = listed?.requestIds ?? [];
|
|
5348
|
+
if (!requestIds.length)
|
|
5349
|
+
return Promise.resolve([]);
|
|
5350
|
+
return (async () => {
|
|
5351
|
+
const session = await env.host.getSession();
|
|
5352
|
+
return Promise.all(requestIds.map(async (requestId) => {
|
|
5353
|
+
const payload = {
|
|
5354
|
+
requestId,
|
|
5355
|
+
isGetRequestBaseInfo: false,
|
|
5356
|
+
isGetRequestLog: false,
|
|
5357
|
+
isGetFormData: true,
|
|
5358
|
+
isReadRequest: false,
|
|
5359
|
+
};
|
|
5360
|
+
if (session.userId)
|
|
5361
|
+
payload.userId = session.userId;
|
|
5362
|
+
const response = await env.host.workflowRequest({
|
|
5363
|
+
method: 'POST',
|
|
5364
|
+
path: WORKFLOW_ENDPOINTS.REQUEST_DETAIL,
|
|
5365
|
+
operation: 'workflow.createRequest.history.detail',
|
|
5366
|
+
body: payload,
|
|
5367
|
+
});
|
|
5368
|
+
return detailDataOf(response);
|
|
5369
|
+
}));
|
|
5370
|
+
})();
|
|
5371
|
+
}
|
|
5304
5372
|
export async function buildHistoryRequestData(env, fields, targets, options = {},
|
|
5305
5373
|
/**
|
|
5306
5374
|
* 已提前发起的列表请求(见 `fetchHistoryListSnapshot`)。传入即直接复用,不再重复发请求;
|
|
5307
5375
|
* 传 `null` / 不传时退回"本函数内自己发列表"的老口径。
|
|
5308
5376
|
*/
|
|
5309
|
-
prefetchedList
|
|
5377
|
+
prefetchedList,
|
|
5378
|
+
/**
|
|
5379
|
+
* 已提前发起的**明细**请求(见 `prefetchHistoryDetails`)。传入即直接复用,不再在这里重发;
|
|
5380
|
+
* 传 `null` / 不传时退回"本函数内自己发"的老口径。组装逻辑与返回值口径与老口径完全一致。
|
|
5381
|
+
*/
|
|
5382
|
+
prefetchedDetails) {
|
|
5310
5383
|
const targetList = toArray(targets)
|
|
5311
5384
|
.filter((item) => !item?.systemField && String(item?.id ?? '').trim())
|
|
5312
5385
|
.map((item) => ({ id: String(item.id).trim(), name: String(item.name ?? item.id) }));
|
|
@@ -5331,24 +5404,32 @@ prefetchedList) {
|
|
|
5331
5404
|
const items = listed.items;
|
|
5332
5405
|
const requestIds = listed.requestIds;
|
|
5333
5406
|
const session = await env.host.getSession();
|
|
5334
|
-
|
|
5335
|
-
|
|
5336
|
-
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
|
|
5341
|
-
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5407
|
+
// 明细请求可以由调用方提前发(`prefetchHistoryDetails`)—— 那时它的结果已经在飞了,
|
|
5408
|
+
// 这里只等它回来;后续「按本表单字段组装」的口径与老路径逐行相同。
|
|
5409
|
+
const details = prefetchedDetails
|
|
5410
|
+
? await prefetchedDetails
|
|
5411
|
+
: await Promise.all(requestIds.map(async (requestId) => {
|
|
5412
|
+
const payload = {
|
|
5413
|
+
requestId,
|
|
5414
|
+
isGetRequestBaseInfo: false,
|
|
5415
|
+
isGetRequestLog: false,
|
|
5416
|
+
isGetFormData: true,
|
|
5417
|
+
isReadRequest: false,
|
|
5418
|
+
};
|
|
5419
|
+
if (session.userId)
|
|
5420
|
+
payload.userId = session.userId;
|
|
5421
|
+
const response = await env.host.workflowRequest({
|
|
5422
|
+
method: 'POST',
|
|
5423
|
+
path: WORKFLOW_ENDPOINTS.REQUEST_DETAIL,
|
|
5424
|
+
operation: 'workflow.createRequest.history.detail',
|
|
5425
|
+
body: payload,
|
|
5426
|
+
});
|
|
5427
|
+
return detailDataOf(response);
|
|
5428
|
+
}));
|
|
5429
|
+
// 预取链在「没有列表结果」时会回 `null`(正常路径走不到这里,因为上面已经 `!listed` 早退);
|
|
5430
|
+
// 按老口径降级成"没有可参考的历史数据"。
|
|
5431
|
+
if (!details)
|
|
5432
|
+
return null;
|
|
5352
5433
|
const result = [];
|
|
5353
5434
|
for (let index = 0; index < details.length; index += 1) {
|
|
5354
5435
|
const data = details[index] || {};
|