weaver-work-cli 0.1.39 → 0.1.42

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 (197) hide show
  1. package/README.md +4 -2
  2. package/dist/chunks/{archive-ENZYBBME.js → archive-J4I6MCKF.js} +2 -2
  3. package/dist/chunks/{archive-oa-YWLEC5V4.js → archive-oa-BRZKKTO4.js} +2 -2
  4. package/dist/chunks/{asset-OOV6DWPA.js → asset-L7D4FAOZ.js} +2 -2
  5. package/dist/chunks/{asset-idle-RE632MY5.js → asset-idle-DADLLV75.js} +2 -2
  6. package/dist/chunks/{attachment-content-RWN2FCLL.js → attachment-content-K4C7VLWQ.js} +3 -3
  7. package/dist/chunks/{blog-PEPOJAL7.js → blog-BVGQ7NZL.js} +2 -2
  8. package/dist/chunks/{caizhilian-WYIQDVPJ.js → caizhilian-SAADNFD6.js} +2 -2
  9. package/dist/chunks/{calendar-CIARBAOX.js → calendar-Q7NQY5Z2.js} +61 -23
  10. package/dist/chunks/{chunk-F2EQXUEE.js → chunk-3KTFS4IA.js} +397 -159
  11. package/dist/chunks/{chunk-G2JSIUWF.js → chunk-4PD5NWAX.js} +89 -0
  12. package/dist/chunks/{chunk-HJYVHXUQ.js → chunk-4RAE6JXP.js} +1 -1
  13. package/dist/chunks/{chunk-CQHGNCK2.js → chunk-72CKAUAG.js} +41 -8
  14. package/dist/chunks/{chunk-K3RUEEOL.js → chunk-APVFJUQH.js} +2 -2
  15. package/dist/chunks/{chunk-BJGXMFGD.js → chunk-BBKDXQEC.js} +2 -2
  16. package/dist/chunks/chunk-BIPYLLVS.js +501 -0
  17. package/dist/chunks/{chunk-GVPJZXJ2.js → chunk-EKWAQSLU.js} +92 -50
  18. package/dist/chunks/{chunk-XXJOSZTQ.js → chunk-FOAA27U5.js} +381 -57
  19. package/dist/chunks/{chunk-I2HB737U.js → chunk-G4UR6NXN.js} +2 -2
  20. package/dist/chunks/{chunk-YS5DPN4T.js → chunk-GEWYMQME.js} +1 -1
  21. package/dist/chunks/{chunk-P2DAISYW.js → chunk-GHXCDPTM.js} +1 -1
  22. package/dist/chunks/{chunk-L4N7B7ZD.js → chunk-IZ7S7QUS.js} +4 -4
  23. package/dist/chunks/{chunk-NLK2RZKG.js → chunk-JPRO6ER2.js} +122 -2214
  24. package/dist/chunks/{chunk-36DIFZAH.js → chunk-LADPYOWC.js} +2 -2
  25. package/dist/chunks/chunk-LDZQPUIA.js +1238 -0
  26. package/dist/chunks/chunk-NKZRQXST.js +2546 -0
  27. package/dist/chunks/{chunk-EINRJHQ3.js → chunk-QKNKR4RH.js} +3 -3
  28. package/dist/chunks/{chunk-T7JDJJ7H.js → chunk-R4CHUSKC.js} +126 -19
  29. package/dist/chunks/{chunk-EZGFHJFW.js → chunk-SA6VBIHY.js} +88 -15
  30. package/dist/chunks/{chunk-ZXRNHZTE.js → chunk-TTPJJJC4.js} +2 -2
  31. package/dist/chunks/{chunk-KTCB5R5H.js → chunk-W7BEHOSR.js} +2 -2
  32. package/dist/chunks/{chunk-MUQUHKPG.js → chunk-YRSZQUD2.js} +2 -2
  33. package/dist/chunks/{conflict-DRMDOL56.js → conflict-F2OMZRTO.js} +2 -2
  34. package/dist/chunks/{contract-73MERZWN.js → contract-5BETHRSG.js} +2 -2
  35. package/dist/chunks/{cowork-HNGBPD7A.js → cowork-3MN6EQQO.js} +27 -10
  36. package/dist/chunks/create-flow-5FQNNMVO.js +55 -0
  37. package/dist/chunks/{ebuilder-form-OY6DVNRK.js → ebuilder-form-SBHOYBUD.js} +3 -3
  38. package/dist/chunks/{ehr-RAQNEQO7.js → ehr-KMOJULKG.js} +432 -1234
  39. package/dist/chunks/env-LB7NBL2O.js +19 -0
  40. package/dist/chunks/{esb-6XV7C7YV.js → esb-W2PJCFCX.js} +4 -4
  41. package/dist/chunks/factory-6ZFQXQ46.js +30 -0
  42. package/dist/chunks/{fna-XTSRB7G7.js → fna-ZQPCUV4R.js} +2 -2
  43. package/dist/chunks/group-chat-2HHAJN46.js +20 -0
  44. package/dist/chunks/{host-YMBXWFWX.js → host-4CBHGOHT.js} +3 -3
  45. package/dist/chunks/{host-A7J6GDUP.js → host-ATKVNZAT.js} +3 -3
  46. package/dist/chunks/{host-3F5UM5GN.js → host-BQH22NTQ.js} +3 -3
  47. package/dist/chunks/{host-YAQAPYNP.js → host-X2CSLFM6.js} +3 -3
  48. package/dist/chunks/{host-VGPVP7YF.js → host-YTODKMSL.js} +3 -3
  49. package/dist/chunks/{hrm-TLHKC545.js → hrm-FFM4UJFS.js} +4 -4
  50. package/dist/chunks/{im-YOUCFMUK.js → im-VEHKDQPB.js} +8 -8
  51. package/dist/chunks/{invoice-WNBS2B4C.js → invoice-LVIKSIIF.js} +3 -3
  52. package/dist/chunks/{jiuchuanhui-XABWS5RN.js → jiuchuanhui-X6DINO5P.js} +2 -2
  53. package/dist/chunks/{lazy-dispatch-NLZ5UQQI.js → lazy-dispatch-KSWTN5L6.js} +4 -4
  54. package/dist/chunks/{mail-LRYMBFNL.js → mail-VDKRGUD3.js} +9 -4
  55. package/dist/chunks/{meeting-ESXL6MFI.js → meeting-CLC6HP3Z.js} +12 -10
  56. package/dist/chunks/{okr-EOV65SSF.js → okr-CHG4OO3U.js} +2 -2
  57. package/dist/chunks/{plan-YFPVKW6Y.js → plan-XWR75667.js} +2 -2
  58. package/dist/chunks/{project-MDVZUYQW.js → project-5BXOOKMG.js} +40 -23
  59. package/dist/chunks/recruit-stage-DGMFNNDE.js +4507 -0
  60. package/dist/chunks/{registry-VT5Y2HLA.js → registry-7FFOXIAW.js} +4 -4
  61. package/dist/chunks/{registry-QCLZEDAP.js → registry-BKBZPBAJ.js} +10 -8
  62. package/dist/chunks/{registry-YX4CSEMD.js → registry-RHMW6ANW.js} +2 -2
  63. package/dist/chunks/{registry-NYPYMZXG.js → registry-Z43434VG.js} +1 -1
  64. package/dist/chunks/{room-recommend-L3MWH4JW.js → room-recommend-62H7ZQQ6.js} +4 -4
  65. package/dist/chunks/{schedule-UASAVDVD.js → schedule-FNXKH3DQ.js} +4 -4
  66. package/dist/chunks/{workflow-KDGIUCNW.js → workflow-ADHKCAJK.js} +4 -4
  67. package/dist/index.js +33 -28
  68. package/dist/internal/e10/auth/commands.js +110 -56
  69. package/dist/internal/e10/auth/messages.js +6 -0
  70. package/dist/internal/e10/auth/session.js +28 -1
  71. package/dist/internal/e10/auth/xiaoe.js +315 -48
  72. package/dist/internal/e10/auth-recovery.js +36 -5
  73. package/dist/internal/e10/client.js +13 -0
  74. package/dist/internal/e10/context.js +61 -9
  75. package/dist/internal/e10/index.js +1 -1
  76. package/dist/internal/e10/network-error.js +93 -0
  77. package/dist/internal/e10/request-runtime.js +15 -0
  78. package/dist/shortcuts/calendar/operations/read.js +31 -22
  79. package/dist/shortcuts/calendar/operations/write.js +45 -1
  80. package/dist/shortcuts/cowork/operations/discuss-write.js +5 -1
  81. package/dist/shortcuts/cowork/operations/item-write.js +5 -3
  82. package/dist/shortcuts/cowork/operations/member-write.js +3 -1
  83. package/dist/shortcuts/cowork/operations/permission-write.js +5 -1
  84. package/dist/shortcuts/cowork/operations/shared.js +7 -0
  85. package/dist/shortcuts/ehr/operations/attend-write.js +43 -1
  86. package/dist/shortcuts/ehr/operations/hr-contact.js +7 -4
  87. package/dist/shortcuts/ehr/operations/hr-report.js +13 -7
  88. package/dist/shortcuts/ehr/operations/recruit-candidate-import.js +134 -59
  89. package/dist/shortcuts/ehr/operations/recruit-write.js +262 -17
  90. package/dist/shortcuts/ehr/operations/recruit.js +10 -4
  91. package/dist/shortcuts/ehr/operations/shared.js +47 -0
  92. package/dist/shortcuts/hrm/operations/org.js +118 -0
  93. package/dist/shortcuts/index.js +5 -0
  94. package/dist/shortcuts/mail/operations/mail-send.js +8 -2
  95. package/dist/shortcuts/meeting/operations/eb/catalog.js +9 -2
  96. package/dist/shortcuts/meeting/operations/eb/create-flow.js +461 -127
  97. package/dist/shortcuts/meeting/operations/eb/crm-search.js +87 -5
  98. package/dist/shortcuts/meeting/operations/eb/factory.js +33 -0
  99. package/dist/shortcuts/meeting/operations/eb/flow-memory.js +49 -0
  100. package/dist/shortcuts/meeting/operations/eb/group-chat.js +605 -0
  101. package/dist/shortcuts/meeting/operations/eb/index.js +2 -0
  102. package/dist/shortcuts/meeting/operations/eb/person-cache.js +96 -0
  103. package/dist/shortcuts/meeting/operations/eb/room-recommend.js +44 -6
  104. package/dist/shortcuts/meeting/operations/eb/room-summary.js +2 -0
  105. package/dist/shortcuts/meeting/operations/eb/usage-cache.js +99 -0
  106. package/dist/shortcuts/meeting/operations/from-group-chat.js +35 -12
  107. package/dist/shortcuts/project/operations/read.js +6 -25
  108. package/dist/shortcuts/project/operations/shared.js +22 -0
  109. package/dist/shortcuts/project/operations/write.js +28 -2
  110. package/dist/shortcuts/recruit-stage/context.js +119 -0
  111. package/dist/shortcuts/recruit-stage/continuation.js +73 -0
  112. package/dist/shortcuts/recruit-stage/errors.js +65 -0
  113. package/dist/shortcuts/recruit-stage/host.js +109 -0
  114. package/dist/shortcuts/recruit-stage/index.js +115 -0
  115. package/dist/shortcuts/recruit-stage/manifest.js +29 -0
  116. package/dist/shortcuts/recruit-stage/operations/interview-arrange.js +722 -0
  117. package/dist/shortcuts/recruit-stage/operations/interview-feedback.js +269 -0
  118. package/dist/shortcuts/recruit-stage/operations/jd-create.js +630 -0
  119. package/dist/shortcuts/recruit-stage/operations/list.js +431 -0
  120. package/dist/shortcuts/recruit-stage/operations/registry.js +38 -0
  121. package/dist/shortcuts/recruit-stage/operations/resume-import.js +1198 -0
  122. package/dist/shortcuts/recruit-stage/operations/search.js +158 -0
  123. package/dist/shortcuts/recruit-stage/operations/types.js +25 -0
  124. package/dist/shortcuts/recruit-stage/school-tiers.json +318 -0
  125. package/dist/shortcuts/recruit-stage/shared.js +608 -0
  126. package/dist/shortcuts/workflow/operations/form.js +21 -2
  127. package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupRules.js +52 -1
  128. package/dist/shortcuts/workflow/operations/todoSmartConvert/detailFieldRules.js +4 -2
  129. package/dist/shortcuts/workflow/operations/todoSmartConvert/summaryCache.js +19 -11
  130. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailCache.js +17 -24
  131. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailFetcher.js +14 -9
  132. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +78 -10
  133. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.core.js +3 -1
  134. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.detail.js +17 -11
  135. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.group.js +16 -40
  136. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +3 -2
  137. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +52 -15
  138. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.pipeline.js +16 -1
  139. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +151 -63
  140. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.subGroup.js +56 -0
  141. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +53 -16
  142. package/docs/e10-auth.md +22 -1
  143. package/docs/operation-manual.md +8 -0
  144. package/package.json +1 -1
  145. package/scripts/install-skill-to-xiaoe.mjs +105 -0
  146. package/scripts/mcp-meeting.mjs +234 -0
  147. package/scripts/package-skill.mjs +4 -2
  148. package/skill-template/business-info.json +24 -0
  149. package/skill-template/domains/recruit-stage.md +29 -0
  150. package/skills/weaver-e10-calendar/SKILL.md +2 -1
  151. package/skills/weaver-e10-calendar/references/calendar-write.md +54 -0
  152. package/skills/weaver-e10-cowork/SKILL.md +1 -1
  153. package/skills/weaver-e10-cowork/references/cowork-write.md +3 -1
  154. package/skills/weaver-e10-jucailin/SKILL.md +1 -1
  155. package/skills/weaver-e10-jucailin/references/attend-write.md +8 -0
  156. package/skills/weaver-e10-jucailin/references/hr-contact.md +8 -0
  157. package/skills/weaver-e10-jucailin/references/hr-report.md +8 -0
  158. package/skills/weaver-e10-jucailin/references/recruit-create.md +2 -2
  159. package/skills/weaver-e10-jucailin/references/recruit-read.md +1 -1
  160. package/skills/weaver-e10-jucailin/references/recruit-write.md +4 -3
  161. package/skills/weaver-e10-mail/SKILL.md +1 -1
  162. package/skills/weaver-e10-mail/references/mail-send.md +2 -0
  163. package/skills/weaver-e10-meeting/SKILL.md +119 -26
  164. package/skills/weaver-e10-meeting/references/meeting-minute-file.md +25 -11
  165. package/skills/weaver-e10-meeting.zip +0 -0
  166. package/skills/weaver-e10-recruit-stage/SKILL.md +226 -0
  167. package/skills/weaver-e10-recruit-stage/agents/openai.yaml +119 -0
  168. package/skills/weaver-e10-recruit-stage/lib/recruit-xiaoe-file.mjs +188 -0
  169. package/skills/weaver-e10-recruit-stage/references/recruit-arrange-interview.md +322 -0
  170. package/skills/weaver-e10-recruit-stage/references/recruit-capability-check.md +127 -0
  171. package/skills/weaver-e10-recruit-stage/references/recruit-check-install.md +65 -0
  172. package/skills/weaver-e10-recruit-stage/references/recruit-detail-process.md +63 -0
  173. package/skills/weaver-e10-recruit-stage/references/recruit-edit-interview-feedback.md +142 -0
  174. package/skills/weaver-e10-recruit-stage/references/recruit-jd-create.md +73 -0
  175. package/skills/weaver-e10-recruit-stage/references/recruit-jd-template.md +56 -0
  176. package/skills/weaver-e10-recruit-stage/references/recruit-list-candidate.md +101 -0
  177. package/skills/weaver-e10-recruit-stage/references/recruit-list-interview.md +148 -0
  178. package/skills/weaver-e10-recruit-stage/references/recruit-match-candidates.md +77 -0
  179. package/skills/weaver-e10-recruit-stage/references/recruit-output-links.md +59 -0
  180. package/skills/weaver-e10-recruit-stage/references/recruit-resolve-creator.md +69 -0
  181. package/skills/weaver-e10-recruit-stage/references/recruit-resolve-metadata.md +241 -0
  182. package/skills/weaver-e10-recruit-stage/references/recruit-resume-import.md +438 -0
  183. package/skills/weaver-e10-recruit-stage/references/recruit-resume-parse.md +128 -0
  184. package/skills/weaver-e10-recruit-stage/references/recruit-search-candidate.md +146 -0
  185. package/skills/weaver-e10-recruit-stage/references/recruit-urge-feedback.md +69 -0
  186. package/skills/weaver-e10-shared/SKILL.md +2 -2
  187. package/skills/weaver-e10-shared/references/e10-auth-and-session.md +4 -2
  188. package/skills/weaver-e10-shijingran/SKILL.md +3 -2
  189. package/skills/weaver-e10-shijingran/references/operations.md +3 -1
  190. package/skills/weaver-e10-shijingran/references/source-manifest.json +41 -40
  191. package/skills/weaver-e10-shijingran/references/write-operations.md +2 -0
  192. package/skills/weaver-e10-workflow/SKILL.md +7 -1
  193. package/skills/weaver-e10-workflow/aigroup/default.json +23 -9
  194. package/skills/weaver-e10-workflow/references/todo-smart-convert.md +37 -21
  195. package/skills/weaver-e10-workflow/tools/todo-summary.cjs +135 -43
  196. package/skills/weaver-e10-yepiaotong/SKILL.md +9 -10
  197. package/skills/weaver-e10-yepiaotong/references/invoice-agent-entry.md +6 -3
@@ -1,31 +1,34 @@
1
1
  import { createRequire as __esbuildCreateRequire } from 'node:module';
2
2
  const require = __esbuildCreateRequire(import.meta.url);
3
+ import {
4
+ meetingEbGroupChatOperations
5
+ } from "./chunk-BIPYLLVS.js";
6
+ import {
7
+ meetingEbCreateFlowOperations
8
+ } from "./chunk-NKZRQXST.js";
3
9
  import {
4
10
  ebRoomRecommendOperation,
5
- loadRooms,
6
11
  recommendRooms,
7
12
  rememberFrequentRoom
8
- } from "./chunk-T7JDJJ7H.js";
13
+ } from "./chunk-R4CHUSKC.js";
9
14
  import {
10
15
  meetingEbScheduleOperations
11
- } from "./chunk-L4N7B7ZD.js";
16
+ } from "./chunk-IZ7S7QUS.js";
12
17
  import {
13
18
  ebMeetingWritePreflight,
14
- fetchEbAppSettings,
15
- findCommonFreeSlots,
16
19
  meetingEbConflictOperations
17
- } from "./chunk-EINRJHQ3.js";
20
+ } from "./chunk-QKNKR4RH.js";
18
21
  import {
19
22
  PENDING_MARK,
20
23
  listMeetingAttachments,
21
24
  meetingAttachmentContentOperations,
22
25
  renderDocx
23
- } from "./chunk-KTCB5R5H.js";
26
+ } from "./chunk-W7BEHOSR.js";
24
27
  import {
25
28
  meetingEnvOperations,
26
29
  meetingStateDir,
27
30
  resolveMeetingEnvMode
28
- } from "./chunk-YS5DPN4T.js";
31
+ } from "./chunk-GEWYMQME.js";
29
32
  import {
30
33
  EB_BASE,
31
34
  EB_ENDPOINTS,
@@ -57,7 +60,7 @@ import {
57
60
  toIdString,
58
61
  verifyLease,
59
62
  writeBody
60
- } from "./chunk-CQHGNCK2.js";
63
+ } from "./chunk-72CKAUAG.js";
61
64
 
62
65
  // src/shortcuts/meeting/operations/meetings.ts
63
66
  function overlapsDate(beginDatetime, endDatetime, date) {
@@ -2223,7 +2226,7 @@ var meetingAttachmentAttach = {
2223
2226
  if (mode === "append" && existingIds.length === 0) {
2224
2227
  existingIds.push(...beforeIds);
2225
2228
  }
2226
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
2229
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-BKBZPBAJ.js");
2227
2230
  const list = getMeetingOperation2("meeting.eb.meeting.list");
2228
2231
  let fileId = incomingFileId;
2229
2232
  let name = String(args.name ?? "").trim();
@@ -2311,7 +2314,7 @@ function textOf(value) {
2311
2314
  return value === void 0 || value === null ? "" : String(value);
2312
2315
  }
2313
2316
  async function readMinute(env, id) {
2314
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
2317
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-BKBZPBAJ.js");
2315
2318
  const detail = getMeetingOperation2("meeting.eb.minute.detail");
2316
2319
  const result = await detail.handler({ id }, env);
2317
2320
  const row = result?.data?.data;
@@ -2390,7 +2393,7 @@ var meetingMinuteWriteContent = {
2390
2393
  } else {
2391
2394
  statusReason = "\u4EC5\u6E05\u7A7A\u5185\u5BB9\uFF0C\u672A\u6539\u72B6\u6001";
2392
2395
  }
2393
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
2396
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-BKBZPBAJ.js");
2394
2397
  const prepare = getMeetingOperation2("meeting.eb.minute.update.prepare");
2395
2398
  const apply = getMeetingOperation2("meeting.eb.minute.update.apply");
2396
2399
  const prepared = await prepare.handler({ id, mt_id: mtId, ...patch }, env);
@@ -2506,8 +2509,9 @@ var meetingMinuteContentOperations = [
2506
2509
  ];
2507
2510
 
2508
2511
  // src/shortcuts/meeting/operations/from-group-chat.ts
2509
- var FLOW_GENERATE_MINUTES = "1325287772302863633";
2510
- var FLOW_GENERATE_DOCUMENT = "1325287772302863628";
2512
+ var FLOW_GENERATE_MINUTES = "7204936B2ACC4B12A1CECD1DAB60DD97";
2513
+ var FLOW_GENERATE_DOCUMENT = "1F638AE31BC746C28A1D9DCF26D91037";
2514
+ var DEFAULT_AI_MINUTE_PAGE = "1250830691712172036";
2511
2515
  function textOf2(value) {
2512
2516
  return value === void 0 || value === null ? "" : String(value);
2513
2517
  }
@@ -2520,8 +2524,8 @@ function parseLocalTime(value) {
2520
2524
  return Number.isNaN(parsed.getTime()) ? null : parsed;
2521
2525
  }
2522
2526
  function formatStamp(d) {
2523
- const pad3 = (n) => String(n).padStart(2, "0");
2524
- return `${d.getFullYear()}-${pad3(d.getMonth() + 1)}-${pad3(d.getDate())} ${pad3(d.getHours())}:${pad3(d.getMinutes())}:${pad3(d.getSeconds())}`;
2527
+ const pad2 = (n) => String(n).padStart(2, "0");
2528
+ return `${d.getFullYear()}-${pad2(d.getMonth() + 1)}-${pad2(d.getDate())} ${pad2(d.getHours())}:${pad2(d.getMinutes())}:${pad2(d.getSeconds())}`;
2525
2529
  }
2526
2530
  function computeChatWindow(meeting, now = /* @__PURE__ */ new Date()) {
2527
2531
  const begin = parseLocalTime(meeting.begin_datetime);
@@ -2649,16 +2653,16 @@ function buildDigest(messages, nameByUid, keepSystem, maxChars) {
2649
2653
  return { transcript, kept: lines.length, dropped, truncated };
2650
2654
  }
2651
2655
  async function saveTranscript(ctx, mtId, transcript) {
2652
- const { mkdir: mkdir5, writeFile: writeFile5 } = await import("node:fs/promises");
2656
+ const { mkdir: mkdir4, writeFile: writeFile4 } = await import("node:fs/promises");
2653
2657
  const { join: join3 } = await import("node:path");
2654
2658
  const { stateDir } = await import("./state-Y2XBP6YE.js");
2655
2659
  const dir = join3(stateDir(ctx), "transcripts");
2656
- await mkdir5(dir, { recursive: true });
2657
- const pad3 = (n) => String(n).padStart(2, "0");
2660
+ await mkdir4(dir, { recursive: true });
2661
+ const pad2 = (n) => String(n).padStart(2, "0");
2658
2662
  const now = /* @__PURE__ */ new Date();
2659
- const stamp2 = `${now.getFullYear()}${pad3(now.getMonth() + 1)}${pad3(now.getDate())}-${pad3(now.getHours())}${pad3(now.getMinutes())}${pad3(now.getSeconds())}`;
2663
+ const stamp2 = `${now.getFullYear()}${pad2(now.getMonth() + 1)}${pad2(now.getDate())}-${pad2(now.getHours())}${pad2(now.getMinutes())}${pad2(now.getSeconds())}`;
2660
2664
  const filePath = join3(dir, `${mtId}-${stamp2}.txt`);
2661
- await writeFile5(filePath, transcript, "utf8");
2665
+ await writeFile4(filePath, transcript, "utf8");
2662
2666
  return filePath;
2663
2667
  }
2664
2668
  var meetingMinuteFromGroupChat = {
@@ -2727,13 +2731,13 @@ var meetingMinuteFromGroupChat = {
2727
2731
  },
2728
2732
  flowGenerateMinutes: {
2729
2733
  type: "string",
2730
- pattern: "^\\d+$",
2731
- description: "ESB\u300C\u6839\u636E\u89E3\u6790\u6587\u672C\u751F\u6210\u667A\u80FD\u7EAA\u8981\u6587\u672C\u300D\u6D41\u7A0B id\u3002\u7701\u7565\u65F6\u7528\u5185\u7F6E\u9ED8\u8BA4\u503C\uFF1B**\u6362\u79DF\u6237\u5FC5\u987B\u8986\u76D6**\uFF08\u6D41\u7A0B id \u662F\u79DF\u6237\u7EA7\u914D\u7F6E\uFF0C\u5404\u73AF\u5883\u4E0D\u540C\uFF09"
2734
+ pattern: "^(\\d+|[0-9A-Fa-f]{32})$",
2735
+ description: "ESB\u300C\u6839\u636E\u89E3\u6790\u6587\u672C\u751F\u6210\u667A\u80FD\u7EAA\u8981\u6587\u672C\u300D\u7684 id\u3002\u53EF\u4F20 19 \u4F4D\u6570\u5B57 id \u6216 32 \u4F4D\u5341\u516D\u8FDB\u5236 primary_key\uFF08GUID \u4F1A\u81EA\u52A8\u8D70\u552F\u4E00\u503C\u89E6\u53D1 uniqueIndent\uFF09\u3002\u7701\u7565\u65F6\u7528\u5185\u7F6E\u9ED8\u8BA4\u503C\uFF1B\u6362\u79DF\u6237\u5FC5\u987B\u8986\u76D6"
2732
2736
  },
2733
2737
  flowGenerateDocument: {
2734
2738
  type: "string",
2735
- pattern: "^\\d+$",
2736
- description: "ESB\u300C\u4FDD\u5B58\u89E3\u6790\u5E76\u751F\u6210\u6587\u6863\u300D\u6D41\u7A0B id\u3002\u7701\u7565\u65F6\u7528\u5185\u7F6E\u9ED8\u8BA4\u503C\uFF1B\u6362\u79DF\u6237\u5FC5\u987B\u8986\u76D6"
2739
+ pattern: "^(\\d+|[0-9A-Fa-f]{32})$",
2740
+ description: "ESB\u300C\u4FDD\u5B58\u89E3\u6790\u5E76\u751F\u6210\u6587\u6863\u300D\u7684 id\uFF0C\u652F\u6301\u6570\u5B57 id \u6216 32 \u4F4D primary_key\uFF1B\u7701\u7565\u65F6\u7528\u5185\u7F6E\u9ED8\u8BA4\u503C"
2737
2741
  }
2738
2742
  },
2739
2743
  required: ["mt_id"]
@@ -2748,7 +2752,7 @@ var meetingMinuteFromGroupChat = {
2748
2752
  const mtId = textOf2(args.mt_id).trim();
2749
2753
  if (!mtId) throw meetingValidationError("mt_id_required", "\u5FC5\u987B\u63D0\u4F9B\u4F1A\u8BAE id\uFF08mt_id\uFF09");
2750
2754
  const pipeline = ["text", "minutes", "document"].includes(args.pipeline) ? args.pipeline : "text";
2751
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
2755
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-BKBZPBAJ.js");
2752
2756
  const ctx = env.ctx;
2753
2757
  let stepStart = Date.now();
2754
2758
  const listed = await getMeetingOperation2("meeting.eb.meeting.list").handler(
@@ -2772,7 +2776,7 @@ var meetingMinuteFromGroupChat = {
2772
2776
  }
2773
2777
  mark("readMeeting", stepStart);
2774
2778
  const pullStart = Date.now();
2775
- const { createImHost } = await import("./host-3F5UM5GN.js");
2779
+ const { createImHost } = await import("./host-BQH22NTQ.js");
2776
2780
  const { createImContinuationSigner } = await import("./continuation-2CKSBLA6.js");
2777
2781
  const { getImOperation } = await import("./registry-OZSMDVPP.js");
2778
2782
  const imEnv = { ctx, host: createImHost(ctx), continuation: createImContinuationSigner(ctx) };
@@ -2840,9 +2844,9 @@ var meetingMinuteFromGroupChat = {
2840
2844
  const extraSections = [];
2841
2845
  for (const file of extraFiles) {
2842
2846
  try {
2843
- const { readFile: readFile5 } = await import("node:fs/promises");
2844
- const buffer = await readFile5(file);
2845
- const { extractText } = await import("./attachment-content-RWN2FCLL.js");
2847
+ const { readFile: readFile4 } = await import("node:fs/promises");
2848
+ const buffer = await readFile4(file);
2849
+ const { extractText } = await import("./attachment-content-K4C7VLWQ.js");
2846
2850
  const extracted = extractText(buffer, file, "");
2847
2851
  if (extracted.text.trim()) {
2848
2852
  extraSections.push(`\u3010\u6750\u6599\uFF1A${file.split(/[\\/]/).pop() ?? file}\u3011
@@ -2912,7 +2916,8 @@ ${groupTranscript}` : ""
2912
2916
  } catch {
2913
2917
  }
2914
2918
  if (!aiPageId) {
2915
- warnings.push("\u672A\u53D6\u5230 mt_minutes_ai_page\uFF08\u53EF\u4F20 aiPageId\uFF09\uFF1BESB \u89E3\u6790\u8BE5\u5B57\u6BB5\u53EF\u80FD\u5FC5\u586B\uFF0C\u7F3A\u5B83\u4F1A\u5931\u8D25");
2919
+ aiPageId = DEFAULT_AI_MINUTE_PAGE;
2920
+ warnings.push(`\u672A\u4ECE\u5DF2\u6709\u7EAA\u8981\u53D6\u5230 mt_minutes_ai_page\uFF0C\u5DF2\u7528\u672C\u79DF\u6237\u9ED8\u8BA4\u503C ${DEFAULT_AI_MINUTE_PAGE}`);
2916
2921
  }
2917
2922
  }
2918
2923
  stepStart = Date.now();
@@ -2957,6 +2962,7 @@ ${groupTranscript}` : ""
2957
2962
  pipeline,
2958
2963
  aiPageId: aiPageId || null
2959
2964
  };
2965
+ let documentIdFromFlow = "";
2960
2966
  if (pipeline === "text") {
2961
2967
  result.timings = { ...timings, total: Date.now() - startedAt };
2962
2968
  return meetingSuccess("meeting.minute.fromGroupChat", result, warnings.length > 0 ? { warnings } : void 0);
@@ -2969,15 +2975,16 @@ ${groupTranscript}` : ""
2969
2975
  if (!employeeId) {
2970
2976
  warnings.push("\u672A\u53D6\u5230 ESB \u89E6\u53D1\u4EBA id\uFF08employeeId\uFF09\uFF0C\u5DF2\u8DF3\u8FC7\u540E\u7EED ESB \u8C03\u7528");
2971
2977
  } else {
2972
- const { createEsbHost } = await import("./host-VGPVP7YF.js");
2978
+ const { createEsbHost } = await import("./host-YTODKMSL.js");
2973
2979
  const { createEsbContinuationSigner } = await import("./continuation-NLECEJPX.js");
2974
- const { getEsbOperation } = await import("./registry-VT5Y2HLA.js");
2980
+ const { getEsbOperation } = await import("./registry-7FFOXIAW.js");
2975
2981
  const esbEnv = { ctx, host: createEsbHost(ctx), continuation: createEsbContinuationSigner(ctx) };
2976
2982
  const prepareOp = getEsbOperation("esb.trigger.prepare");
2977
2983
  const applyOp = getEsbOperation("esb.trigger.apply");
2978
2984
  const trigger = async (flowId, mainTable) => {
2985
+ const target = /^\d+$/.test(flowId) ? { esbFlowId: flowId } : { uniqueIndent: flowId };
2979
2986
  const pre = await prepareOp.handler(
2980
- { employeeId, esbFlowId: flowId, customParams: { mainTable } },
2987
+ { employeeId, ...target, customParams: { mainTable } },
2981
2988
  esbEnv
2982
2989
  );
2983
2990
  return applyOp.handler({ continuation: pre?.data?.continuation, confirm: true }, esbEnv);
@@ -2996,7 +3003,10 @@ ${groupTranscript}` : ""
2996
3003
  warnings.push("\u7EAA\u8981\u6587\u6848\u4E3A\u7A7A\uFF0C\u5DF2\u8DF3\u8FC7\u751F\u6210\u6587\u6863\uFF08\u6587\u672C\u751F\u6210\u53EF\u80FD\u4ECD\u5728\u540E\u53F0\u8FDB\u884C\uFF0C\u53EF\u7A0D\u540E\u7528 meeting.minute.parseStatus \u590D\u67E5\uFF09");
2997
3004
  } else {
2998
3005
  try {
2999
- await trigger(flowDocument, { parse_content: parseContent, mt_minute_id: minuteId });
3006
+ const docResult = await trigger(flowDocument, { parse_content: parseContent, mt_minute_id: minuteId });
3007
+ documentIdFromFlow = textOf2(
3008
+ docResult?.data?.actionData?.responseData?.customData?.mainTable?.wdID
3009
+ );
3000
3010
  mark("esbDocument", stepDocStart);
3001
3011
  } catch (error) {
3002
3012
  warnings.push(`ESB \u751F\u6210\u6587\u6863\u672A\u6B63\u5E38\u8FD4\u56DE\uFF08${String(error?.message ?? error).slice(0, 100)}\uFF09`);
@@ -3008,7 +3018,7 @@ ${groupTranscript}` : ""
3008
3018
  const row = final?.data?.data ?? {};
3009
3019
  result.finalStatus = textOf2(row.minutes_status);
3010
3020
  result.parseContentLength = textOf2(row.parse_content).length;
3011
- result.documentId = textOf2(row.mt_minutes) || null;
3021
+ result.documentId = textOf2(row.mt_minutes) || documentIdFromFlow || null;
3012
3022
  result.timings = { ...timings, total: Date.now() - startedAt };
3013
3023
  return meetingSuccess("meeting.minute.fromGroupChat", result, warnings.length > 0 ? { warnings } : void 0);
3014
3024
  }
@@ -3155,7 +3165,7 @@ var meetingDecisionNotifyGroup = {
3155
3165
  const warnings = [];
3156
3166
  const mtId = textOf3(args.mt_id).trim();
3157
3167
  if (!mtId) throw meetingValidationError("mt_id_required", "\u5FC5\u987B\u63D0\u4F9B\u4F1A\u8BAE id\uFF08mt_id\uFF09");
3158
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
3168
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-BKBZPBAJ.js");
3159
3169
  const ctx = env.ctx;
3160
3170
  const listed = await getMeetingOperation2("meeting.eb.meeting.list").handler(
3161
3171
  { mt_id: mtId, pageNo: 1, pageSize: 1 },
@@ -3219,7 +3229,7 @@ var meetingDecisionNotifyGroup = {
3219
3229
  charCount: formatted.text.length,
3220
3230
  text: formatted.text
3221
3231
  };
3222
- const { createImHost } = await import("./host-3F5UM5GN.js");
3232
+ const { createImHost } = await import("./host-BQH22NTQ.js");
3223
3233
  const imHost = createImHost(ctx);
3224
3234
  let displayText = formatted.text;
3225
3235
  let wireText = formatted.text;
@@ -3361,14 +3371,14 @@ function defaultDueDate(begin, days) {
3361
3371
  const base = new Date(normalized.replace(/-/g, "/"));
3362
3372
  const start = Number.isNaN(base.getTime()) ? /* @__PURE__ */ new Date() : base;
3363
3373
  const due = new Date(start.getTime() + Math.max(days, 1) * 24 * 36e5);
3364
- const pad3 = (n) => String(n).padStart(2, "0");
3365
- return `${due.getFullYear()}-${pad3(due.getMonth() + 1)}-${pad3(due.getDate())} 18:00`;
3374
+ const pad2 = (n) => String(n).padStart(2, "0");
3375
+ return `${due.getFullYear()}-${pad2(due.getMonth() + 1)}-${pad2(due.getDate())} 18:00`;
3366
3376
  }
3367
3377
  async function waitForTaskIncrease(fetchTotal, baseline, timeoutMs = 15e3, intervalMs = 2e3) {
3368
3378
  const start = Date.now();
3369
3379
  let total = baseline;
3370
3380
  while (Date.now() - start < timeoutMs) {
3371
- await new Promise((resolve6) => setTimeout(resolve6, intervalMs));
3381
+ await new Promise((resolve5) => setTimeout(resolve5, intervalMs));
3372
3382
  total = await fetchTotal();
3373
3383
  if (total > baseline) return { total, waitedMs: Date.now() - start, increased: true };
3374
3384
  }
@@ -3457,7 +3467,7 @@ var meetingPipelineRun = {
3457
3467
  const needsConfirm = level === "tasks" || level === "notify";
3458
3468
  const confirmed = args.confirm === true;
3459
3469
  const executedLevel = needsConfirm && !confirmed ? "document" : level;
3460
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
3470
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-BKBZPBAJ.js");
3461
3471
  const ctx = env.ctx;
3462
3472
  let stepStart = Date.now();
3463
3473
  const reuseMinuteId = textOf4(args.minuteId).trim();
@@ -3526,8 +3536,8 @@ var meetingPipelineRun = {
3526
3536
  ]);
3527
3537
  }
3528
3538
  stepStart = Date.now();
3529
- const { createHrmHost } = await import("./host-A7J6GDUP.js");
3530
- const { getHrmOperation } = await import("./registry-NYPYMZXG.js");
3539
+ const { createHrmHost } = await import("./host-ATKVNZAT.js");
3540
+ const { getHrmOperation } = await import("./registry-Z43434VG.js");
3531
3541
  const hrmEnv = { ctx, host: createHrmHost(ctx) };
3532
3542
  const queryOp = getHrmOperation("hrm.employee.query");
3533
3543
  const resolved = [];
@@ -3564,8 +3574,8 @@ var meetingPipelineRun = {
3564
3574
  })();
3565
3575
  const beginAt = textOf4(meetingInfo.end_datetime).trim() || textOf4(meetingInfo.begin_datetime).trim() || (() => {
3566
3576
  const now = /* @__PURE__ */ new Date();
3567
- const pad3 = (n) => String(n).padStart(2, "0");
3568
- return `${now.getFullYear()}-${pad3(now.getMonth() + 1)}-${pad3(now.getDate())} ${pad3(now.getHours())}:${pad3(now.getMinutes())}`;
3577
+ const pad2 = (n) => String(n).padStart(2, "0");
3578
+ return `${now.getFullYear()}-${pad2(now.getMonth() + 1)}-${pad2(now.getDate())} ${pad2(now.getHours())}:${pad2(now.getMinutes())}`;
3569
3579
  })();
3570
3580
  const dueDays = typeof args.taskDueDays === "number" && args.taskDueDays > 0 ? args.taskDueDays : 7;
3571
3581
  const dueAt = defaultDueDate(beginAt, dueDays);
@@ -3829,7 +3839,7 @@ function formatTimeRange(start, end) {
3829
3839
  }
3830
3840
  async function loadAgendaFromTopics(env, mtId) {
3831
3841
  try {
3832
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
3842
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-BKBZPBAJ.js");
3833
3843
  const operation = getMeetingOperation2("meeting.eb.topic.list");
3834
3844
  const result = await operation.handler({ mt_id: mtId, pageNo: 1, pageSize: 200 }, env);
3835
3845
  const rows = result.data?.rows ?? [];
@@ -3967,7 +3977,7 @@ async function supplementRowFromDetail(row, mtId, env) {
3967
3977
  const missing = DETAIL_FALLBACK_KEYS.filter((key) => isBlank(row[key]));
3968
3978
  if (missing.length === 0) return { row, filled: [] };
3969
3979
  try {
3970
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
3980
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-BKBZPBAJ.js");
3971
3981
  const detailOperation = getMeetingOperation2("meeting.eb.meeting.detail");
3972
3982
  const result = await detailOperation.handler({ id: mtId }, env);
3973
3983
  const flat = result?.data?.data ?? result?.data ?? {};
@@ -4141,7 +4151,7 @@ var meetingInvitationRender = {
4141
4151
  };
4142
4152
  dataSource = "payload";
4143
4153
  } else {
4144
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
4154
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-BKBZPBAJ.js");
4145
4155
  const listOperation = getMeetingOperation2("meeting.eb.meeting.list");
4146
4156
  try {
4147
4157
  const listed = await listOperation.handler({ mt_id: mtId, pageNo: 1, pageSize: 1 }, env);
@@ -4543,7 +4553,7 @@ function buildCodewords(bytes, version, ecc) {
4543
4553
  for (const byte of bytes) appendBits(byte, 8);
4544
4554
  appendBits(0, Math.min(4, capacityBits - bits.length));
4545
4555
  appendBits(0, (8 - bits.length % 8) % 8);
4546
- for (let pad3 = 236; bits.length < capacityBits; pad3 ^= 236 ^ 17) appendBits(pad3, 8);
4556
+ for (let pad2 = 236; bits.length < capacityBits; pad2 ^= 236 ^ 17) appendBits(pad2, 8);
4547
4557
  const dataCodewords = new Array(bits.length / 8).fill(0);
4548
4558
  bits.forEach((bit, i) => {
4549
4559
  dataCodewords[i >>> 3] |= bit << 7 - (i & 7);
@@ -4729,8 +4739,8 @@ function renderQrSvg(matrix, options = {}) {
4729
4739
  var ECC_LEVELS = ["L", "M", "Q", "H"];
4730
4740
  function stamp() {
4731
4741
  const now = /* @__PURE__ */ new Date();
4732
- const pad3 = (n) => String(n).padStart(2, "0");
4733
- return `${now.getFullYear()}${pad3(now.getMonth() + 1)}${pad3(now.getDate())}-${pad3(now.getHours())}${pad3(now.getMinutes())}${pad3(now.getSeconds())}`;
4742
+ const pad2 = (n) => String(n).padStart(2, "0");
4743
+ return `${now.getFullYear()}${pad2(now.getMonth() + 1)}${pad2(now.getDate())}-${pad2(now.getHours())}${pad2(now.getMinutes())}${pad2(now.getSeconds())}`;
4734
4744
  }
4735
4745
  function safeName(input) {
4736
4746
  return input.replace(/[\\/:*?"<>|\s]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 60);
@@ -4895,7 +4905,7 @@ var meetingSummaryGet = {
4895
4905
  const mtId = textOf5(args.mt_id).trim();
4896
4906
  if (!mtId) throw meetingValidationError("mt_id_required", "\u5FC5\u987B\u63D0\u4F9B\u4F1A\u8BAE id\uFF08mt_id\uFF09");
4897
4907
  const ctx = env.ctx;
4898
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
4908
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-BKBZPBAJ.js");
4899
4909
  const warnings = [];
4900
4910
  const timings = {};
4901
4911
  const include = Array.isArray(args.include) && args.include.length > 0 ? args.include.filter((item) => ALL_SECTIONS.includes(item)) : ALL_SECTIONS;
@@ -5031,7 +5041,7 @@ var meetingSummaryGet = {
5031
5041
  warnings.push("\u8BE5\u4F1A\u8BAE\u6CA1\u6709\u5173\u8054\u7FA4\u804A\uFF08imchat_groupid \u4E3A\u7A7A\uFF09\uFF0Cchat \u6BB5\u4E3A null");
5032
5042
  } else {
5033
5043
  try {
5034
- const { createImHost } = await import("./host-3F5UM5GN.js");
5044
+ const { createImHost } = await import("./host-BQH22NTQ.js");
5035
5045
  const { createImContinuationSigner } = await import("./continuation-2CKSBLA6.js");
5036
5046
  const { getImOperation } = await import("./registry-OZSMDVPP.js");
5037
5047
  const imEnv = {
@@ -5157,7 +5167,7 @@ var meetingFormFields = {
5157
5167
  hint: "\u6CA1\u89E3\u6790\u5230\u8BE5\u8868\u7684 objId\uFF08\u53EF\u80FD\u5F53\u524D\u73AF\u5883\u6CA1\u6709\u8FD9\u5F20\u8868\uFF0C\u6216\u8D26\u53F7\u65E0\u6743\u9650\uFF09"
5158
5168
  }, { warnings: resolved.warnings });
5159
5169
  }
5160
- const { createEbuilderFormHost } = await import("./host-YMBXWFWX.js");
5170
+ const { createEbuilderFormHost } = await import("./host-4CBHGOHT.js");
5161
5171
  const { createEbuilderFormContinuationSigner } = await import("./continuation-RN6PZN2M.js");
5162
5172
  const { executeEbuilderFormOperation } = await import("./operations-5QL3AECO.js");
5163
5173
  const formEnv = {
@@ -5209,15 +5219,15 @@ var CONTINUATION_TTL_SECONDS6 = 600;
5209
5219
  var DATE_PATTERN = "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$";
5210
5220
  function formatSecondNow() {
5211
5221
  const now = /* @__PURE__ */ new Date();
5212
- const pad3 = (value) => String(value).padStart(2, "0");
5213
- return `${now.getFullYear()}-${pad3(now.getMonth() + 1)}-${pad3(now.getDate())} ${pad3(now.getHours())}:${pad3(now.getMinutes())}:${pad3(now.getSeconds())}`;
5222
+ const pad2 = (value) => String(value).padStart(2, "0");
5223
+ return `${now.getFullYear()}-${pad2(now.getMonth() + 1)}-${pad2(now.getDate())} ${pad2(now.getHours())}:${pad2(now.getMinutes())}:${pad2(now.getSeconds())}`;
5214
5224
  }
5215
5225
  var DECISION_DONE = "2";
5216
5226
  var MT_STATUS_OVER = "8";
5217
5227
  var CANCELLED_MARK_DELAY_MS = 800;
5218
5228
  async function isCancelledMeeting(env, mtId) {
5219
5229
  try {
5220
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
5230
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-BKBZPBAJ.js");
5221
5231
  const listed = await getMeetingOperation2("meeting.eb.meeting.list").handler(
5222
5232
  // withCount:false —— 这里只要一行状态,不必额外请求 count(少一次往返,也便于测试替身)
5223
5233
  { mt_id: mtId, pageNo: 1, pageSize: 1, withCount: false },
@@ -5436,8 +5446,8 @@ var decisionPublishApply = {
5436
5446
  );
5437
5447
  }
5438
5448
  if (cancelled) {
5439
- await new Promise((resolve6) => {
5440
- setTimeout(resolve6, CANCELLED_MARK_DELAY_MS);
5449
+ await new Promise((resolve5) => {
5450
+ setTimeout(resolve5, CANCELLED_MARK_DELAY_MS);
5441
5451
  });
5442
5452
  warnings.push(
5443
5453
  `\u8BE5\u4F1A\u8BAE\u6B64\u524D\u88AB\u53D6\u6D88\u8FC7\uFF1A\u5DF2\u5728\u300C\u5199\u51B3\u8BAE\u300D\u4E0E\u300C\u6807\u8BB0\u5DF2\u51B3\u8BAE\u300D\u4E4B\u95F4\u7559 ${CANCELLED_MARK_DELAY_MS}ms \u95F4\u9694\uFF0C\u907F\u514D ESB \u628A\u540C\u4E00\u6279\u660E\u7EC6\u751F\u6210\u4E24\u8F6E\u4EFB\u52A1\uFF08\u771F\u673A\u9A8C\u8BC1\u8FC7\u7684\u5751\uFF09`
@@ -5798,11 +5808,33 @@ function unwrapRow(value) {
5798
5808
  const main = asRecord(record.mainTable);
5799
5809
  return main ?? record;
5800
5810
  }
5811
+ function columnarCustomerRows(record) {
5812
+ const idKey = ID_KEYS.find((key) => Array.isArray(record[key]));
5813
+ const nameKey = NAME_KEYS.find((key) => Array.isArray(record[key]));
5814
+ if (!idKey && !nameKey) return [];
5815
+ const idValues = idKey ? record[idKey] : [];
5816
+ const nameValues = nameKey ? record[nameKey] : [];
5817
+ const size = Math.max(idValues.length, nameValues.length);
5818
+ if (size <= 1) return [];
5819
+ const rows = [];
5820
+ for (let index = 0; index < size; index += 1) {
5821
+ const row = {};
5822
+ if (idKey) row[idKey] = idValues[index];
5823
+ if (nameKey) row[nameKey] = nameValues[index];
5824
+ rows.push(row);
5825
+ }
5826
+ return rows;
5827
+ }
5801
5828
  function collectCandidateLists(customData) {
5802
5829
  const found = [];
5803
5830
  const main = asRecord(customData.mainTable);
5804
5831
  if (main) {
5805
- found.push({ source: "customData.mainTable", rows: [main] });
5832
+ const columnar = columnarCustomerRows(main);
5833
+ if (columnar.length > 1) {
5834
+ found.push({ source: "customData.mainTable.columns", rows: columnar });
5835
+ } else {
5836
+ found.push({ source: "customData.mainTable", rows: [main] });
5837
+ }
5806
5838
  for (const key of LIST_KEYS) {
5807
5839
  const value = main[key];
5808
5840
  if (Array.isArray(value)) found.push({ source: `customData.mainTable.${key}`, rows: value });
@@ -5812,6 +5844,16 @@ function collectCandidateLists(customData) {
5812
5844
  const value = customData[key];
5813
5845
  if (Array.isArray(value)) found.push({ source: `customData.${key}`, rows: value });
5814
5846
  }
5847
+ for (const [key, value] of Object.entries(customData)) {
5848
+ if (LIST_KEYS.includes(key)) continue;
5849
+ if (!Array.isArray(value) || value.length === 0) continue;
5850
+ const looksLikeCustomers = value.some((raw) => {
5851
+ const row = unwrapRow(raw);
5852
+ if (!row) return false;
5853
+ return pickFirst(row, ID_KEYS) !== "" || pickFirst(row, NAME_KEYS) !== "";
5854
+ });
5855
+ if (looksLikeCustomers) found.push({ source: `customData.${key}`, rows: value });
5856
+ }
5815
5857
  return found;
5816
5858
  }
5817
5859
  var CONTACT_LIST_KEYS = ["lxr", "contacts", "contactList", "lxrList"];
@@ -5878,6 +5920,19 @@ function parseCrmAddresses(raw) {
5878
5920
  }
5879
5921
  return out;
5880
5922
  }
5923
+ function pickContactArray(row) {
5924
+ const direct = pickRawList(row, CONTACT_LIST_KEYS);
5925
+ if (direct !== void 0) return direct;
5926
+ for (const value of Object.values(row)) {
5927
+ if (!Array.isArray(value) || value.length === 0) continue;
5928
+ const first = asRecord(value[0]);
5929
+ if (!first) continue;
5930
+ const hasName = CONTACT_NAME_KEYS.some((key) => String(first[key] ?? "").trim() !== "");
5931
+ const hasMobile = CONTACT_MOBILE_KEYS.some((key) => String(first[key] ?? "").trim() !== "");
5932
+ if (hasName || hasMobile) return value;
5933
+ }
5934
+ return void 0;
5935
+ }
5881
5936
  function normalizeCustomers(rows, limit) {
5882
5937
  const seen = /* @__PURE__ */ new Map();
5883
5938
  for (const raw of rows) {
@@ -5888,7 +5943,7 @@ function normalizeCustomers(rows, limit) {
5888
5943
  if (customerId === "" && name === "") continue;
5889
5944
  const key = customerId !== "" ? customerId : `name:${name}`;
5890
5945
  if (seen.has(key)) continue;
5891
- const contacts = parseCrmContacts(pickRawList(row, CONTACT_LIST_KEYS));
5946
+ const contacts = parseCrmContacts(pickContactArray(row));
5892
5947
  const addresses = parseCrmAddresses(pickRawList(row, ADDRESS_LIST_KEYS));
5893
5948
  seen.set(key, {
5894
5949
  customerId,
@@ -5985,9 +6040,9 @@ async function runCrmSearchFlow(env, input) {
5985
6040
  if (!employeeId) {
5986
6041
  throw meetingValidationError("crm_employee_required", "\u53D6\u4E0D\u5230\u5F53\u524D\u767B\u5F55\u7528\u6237 id\uFF0C\u65E0\u6CD5\u89E6\u53D1 ESB \u5BA2\u6237\u67E5\u8BE2");
5987
6042
  }
5988
- const { createEsbHost } = await import("./host-VGPVP7YF.js");
6043
+ const { createEsbHost } = await import("./host-YTODKMSL.js");
5989
6044
  const { createEsbContinuationSigner } = await import("./continuation-NLECEJPX.js");
5990
- const { getEsbOperation } = await import("./registry-VT5Y2HLA.js");
6045
+ const { getEsbOperation } = await import("./registry-7FFOXIAW.js");
5991
6046
  const esbEnv = {
5992
6047
  ctx: env.ctx,
5993
6048
  host: createEsbHost(env.ctx),
@@ -6055,7 +6110,7 @@ var ebCrmSearch = {
6055
6110
  minLength: 1,
6056
6111
  description: "\u5BA2\u6237\u540D\u79F0\uFF0C\u8D70\u52A8\u4F5C\u6D41\u5165\u53C2 custom_name\uFF08\u5305\u542B\u5339\u914D\uFF09\uFF1A\u7ED9\u5168\u79F0\u6700\u7A33\uFF0C\u7247\u6BB5\u53EA\u56DE\u9996\u4E2A\u5339\u914D"
6057
6112
  },
6058
- limit: { type: "number", description: "\u8FD4\u56DE\u6761\u6570\u4E0A\u9650\uFF0C\u9ED8\u8BA4 10\uFF08\u5F53\u524D\u52A8\u4F5C\u6D41\u4E00\u6B21\u53EA\u56DE 1 \u6761\uFF0C\u4EC5\u4F5C\u517C\u5BB9\uFF09" },
6113
+ limit: { type: "number", description: "\u8FD4\u56DE\u6761\u6570\u4E0A\u9650\uFF0C\u9ED8\u8BA4 10\u3002\u52A8\u4F5C\u6D41\u662F\u6A21\u7CCA\u67E5\uFF0C\u53EF\u80FD\u547D\u4E2D\u591A\u4E2A\u8FD1\u540D\u5BA2\u6237\uFF1B\u5217\u5F0F\u8F93\u51FA\uFF08mc/sjID \u5E73\u884C\u6570\u7EC4\uFF09\u4F1A\u6309\u7D22\u5F15\u62C6\u6210\u591A\u884C\u8FD4\u56DE" },
6059
6114
  flowId: { type: "string", description: "\u8986\u76D6 ESB \u52A8\u4F5C\u6D41 id\uFF08\u9ED8\u8BA4 904205116264026112\uFF09" },
6060
6115
  employeeId: { type: "string", description: "\u8986\u76D6\u89E6\u53D1\u4EBA\u5458 id\uFF08\u9ED8\u8BA4\u5F53\u524D\u767B\u5F55\u7528\u6237\uFF09" },
6061
6116
  includeRaw: { type: "boolean", description: "true=\u9644\u5E26 ESB \u539F\u59CB\u8FD4\u56DE\uFF0C\u4FBF\u4E8E\u6392\u67E5\u8F93\u51FA\u7ED3\u6784" }
@@ -6110,2154 +6165,6 @@ var ebCrmSearch = {
6110
6165
  };
6111
6166
  var meetingEbCrmOperations = [ebCrmSearch];
6112
6167
 
6113
- // src/shortcuts/meeting/operations/eb/create-flow.ts
6114
- import { existsSync as existsSync3 } from "node:fs";
6115
- import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
6116
- import { homedir } from "node:os";
6117
- import { resolve as resolve5 } from "node:path";
6118
- var FIELD_ALIASES = {
6119
- mt_name: ["\u4F1A\u8BAE\u540D\u79F0", "\u4F1A\u8BAE\u4E3B\u9898", "\u4E3B\u9898"],
6120
- begin_datetime: ["\u5F00\u59CB\u65F6\u95F4", "\u4F1A\u8BAE\u5F00\u59CB\u65F6\u95F4"],
6121
- end_datetime: ["\u7ED3\u675F\u65F6\u95F4", "\u4F1A\u8BAE\u7ED3\u675F\u65F6\u95F4"],
6122
- mt_desc: ["\u4F1A\u8BAE\u5185\u5BB9", "\u4F1A\u8BAE\u8BF4\u660E", "\u4F1A\u8BAE\u63CF\u8FF0"],
6123
- address: ["\u4F1A\u8BAE\u5730\u70B9", "\u4F1A\u8BAE\u5BA4"],
6124
- customize_address: ["\u81EA\u5B9A\u4E49\u4F1A\u8BAE\u5730\u70B9", "\u81EA\u5B9A\u4E49\u5730\u70B9"],
6125
- hrm_members: ["\u53C2\u4F1A\u4EBA\u5458", "\u53C2\u4F1A\u4EBA"],
6126
- total_member: ["\u53C2\u4F1A\u4EBA\u6570", "\u4EBA\u6570"],
6127
- /** 参会客户(CustomerComponent 客户浏览按钮):值是客户 id 列表,不是客户名称文本。 */
6128
- crm_members: ["\u53C2\u4F1A\u5BA2\u6237", "\u5BA2\u6237"],
6129
- crm_member_count: ["\u5E94\u5230\u5BA2\u6237\u6570", "\u5BA2\u6237\u6570"],
6130
- caller: ["\u53EC\u96C6\u4EBA", "\u53D1\u8D77\u4EBA"],
6131
- contacter: ["\u8054\u7CFB\u4EBA"],
6132
- mt_type: ["\u4F1A\u8BAE\u7C7B\u578B"],
6133
- other_remark: ["\u5907\u6CE8", "\u5176\u4ED6\u8BF4\u660E"]
6134
- };
6135
- var PERSON_FIELD_LABELS = { caller: "\u53EC\u96C6\u4EBA", contacter: "\u8054\u7CFB\u4EBA" };
6136
- function workflowEnv(env) {
6137
- return env;
6138
- }
6139
- async function loadCreateForm(env, workflowId) {
6140
- const { createWorkflowHost } = await import("./host-YAQAPYNP.js");
6141
- const { createWorkflowContinuationSigner } = await import("./continuation-HZIZRZBX.js");
6142
- const { getWorkflowOperation } = await import("./registry-YX4CSEMD.js");
6143
- const wfEnv = {
6144
- ...workflowEnv(env),
6145
- host: createWorkflowHost(env.ctx),
6146
- continuation: createWorkflowContinuationSigner(env.ctx)
6147
- };
6148
- const operation = getWorkflowOperation("workflow.createForm");
6149
- const result = await operation.handler({ workflow: [workflowId] }, wfEnv);
6150
- const data = result?.data ?? {};
6151
- if (data.status !== "FORM_READY") {
6152
- throw meetingValidationError(
6153
- "flow_form_unavailable",
6154
- `\u5EFA\u4F1A\u6D41\u7A0B\u8868\u5355\u8F7D\u5165\u5931\u8D25\uFF08status=${String(data.status)}\uFF09\uFF1A${String(data.clarificationQuestion ?? data.note ?? "").slice(0, 200)}`,
6155
- { workflowId }
6156
- );
6157
- }
6158
- const wf = data.workflow ?? {};
6159
- return {
6160
- fields: data.fields ?? [],
6161
- continuation: data.continuation,
6162
- requestName: data.requestName,
6163
- contextId: data.contextId,
6164
- workflowName: String(wf.name ?? wf.workflowName ?? "").trim() || void 0
6165
- };
6166
- }
6167
- async function resolveEmployeeNames(env, ids) {
6168
- const map = /* @__PURE__ */ new Map();
6169
- const unique = [...new Set(ids.map((id) => String(id).trim()).filter((id) => id !== ""))];
6170
- if (unique.length === 0) return map;
6171
- try {
6172
- const { hrmEmployeeOperations } = await import("./employee-SAK2QYXX.js");
6173
- const batch = hrmEmployeeOperations.find((operation) => operation.name === "hrm.employee.batch");
6174
- if (!batch) return map;
6175
- const result = await batch.handler({ ids: unique }, env);
6176
- const rows = result?.data?.rows ?? result?.data?.userList ?? [];
6177
- for (const row of rows) {
6178
- const id = String(row.id ?? "").trim();
6179
- const name = String(row.name ?? "").trim();
6180
- if (id && name) map.set(id, name);
6181
- }
6182
- } catch {
6183
- }
6184
- return map;
6185
- }
6186
- async function resolvePersonTokens(env, tokens) {
6187
- const map = /* @__PURE__ */ new Map();
6188
- const unique = [...new Set(tokens.map((token) => String(token).trim()).filter((token) => token !== ""))];
6189
- if (unique.length === 0) return map;
6190
- const idLike = unique.filter((token) => /^\d{8,}$/.test(token));
6191
- const nameLike = unique.filter((token) => !/^\d{8,}$/.test(token));
6192
- if (idLike.length > 0) {
6193
- const names = await resolveEmployeeNames(env, idLike);
6194
- for (const id of idLike) map.set(id, { id, name: names.get(id) ?? id });
6195
- }
6196
- if (nameLike.length > 0) {
6197
- try {
6198
- const { hrmEmployeeOperations } = await import("./employee-SAK2QYXX.js");
6199
- const query = hrmEmployeeOperations.find((operation) => operation.name === "hrm.employee.query");
6200
- for (const name of nameLike) {
6201
- if (!query) break;
6202
- const found = await query.handler({ keyword: name, pageSize: 10 }, env).catch(() => null);
6203
- const rows = found?.data?.rows ?? [];
6204
- const exact = rows.find((row) => String(row.name ?? "").trim() === name);
6205
- const hit = exact ?? (rows.length === 1 ? rows[0] : void 0);
6206
- const id = String(hit?.id ?? "").trim();
6207
- if (id === "") continue;
6208
- map.set(name, { id, name: String(hit?.name ?? name) });
6209
- }
6210
- } catch {
6211
- }
6212
- }
6213
- return map;
6214
- }
6215
- async function resolveSelfPerson(env) {
6216
- let session = null;
6217
- try {
6218
- session = await env.host?.getSession?.();
6219
- } catch {
6220
- return null;
6221
- }
6222
- const id = String(session?.userId ?? "").trim();
6223
- if (id === "" || id === "unknown") return null;
6224
- const names = await resolveEmployeeNames(env, [id]);
6225
- const name = String(names.get(id) ?? "").trim();
6226
- if (name === "") return null;
6227
- return { id, name };
6228
- }
6229
- function applySelfPersonDefaults(args, self) {
6230
- const filled = [];
6231
- const missing = ["caller", "contacter"].filter((field) => String(args[field] ?? "").trim() === "");
6232
- if (missing.length === 0) return { filled, warning: "" };
6233
- if (!self) {
6234
- return {
6235
- filled,
6236
- warning: missing.length === 2 ? "\u26A0\uFE0F \u6CA1\u80FD\u786E\u8BA4\u5F53\u524D\u767B\u5F55\u7528\u6237\u5BF9\u5E94\u7684\u5458\u5DE5 \u2014\u2014\u300C\u53EC\u96C6\u4EBA\u300D\u300C\u8054\u7CFB\u4EBA\u300D\u4F1A\u7559\u7A7A\uFF0C\u8BF7\u663E\u5F0F\u4F20 caller / contacter\uFF08\u5458\u5DE5 id \u6216\u59D3\u540D\uFF09\u3002" : ""
6237
- };
6238
- }
6239
- for (const field of missing) {
6240
- args[field] = self.id;
6241
- filled.push({ field, id: self.id, name: self.name });
6242
- }
6243
- return { filled, warning: "" };
6244
- }
6245
- function parseRoomRef(input) {
6246
- const text = String(input ?? "").trim();
6247
- if (!text) return {};
6248
- const withId = /^(.*?)[((]\s*(\d{4,})\s*[))]$/.exec(text);
6249
- if (withId) {
6250
- const name = withId[1].trim();
6251
- const id = withId[2];
6252
- return name ? { id, name } : { id };
6253
- }
6254
- if (/^\d+$/.test(text)) return { id: text };
6255
- return { name: text };
6256
- }
6257
- async function resolveAddressRoom(env, input) {
6258
- const text = String(input ?? "").trim();
6259
- if (!text) return null;
6260
- const ref = parseRoomRef(text);
6261
- const { loadRooms: loadRooms2 } = await import("./room-recommend-L3MWH4JW.js");
6262
- let rooms = [];
6263
- try {
6264
- rooms = (await loadRooms2(env, {})).rooms;
6265
- } catch {
6266
- return { id: ref.id ?? "", name: ref.name ?? text, status: "unknown", lookupFailed: true };
6267
- }
6268
- const hit = (ref.id ? rooms.find((room) => room.id === ref.id) : void 0) ?? (ref.name ? rooms.find((room) => room.name === ref.name) : void 0);
6269
- if (hit) return { id: hit.id, name: hit.name, status: hit.status, statusText: hit.statusText };
6270
- if (ref.id) return { id: ref.id, name: ref.name ?? "", status: "unknown" };
6271
- return null;
6272
- }
6273
- async function resolveRoomValue(env, input) {
6274
- const text = String(input ?? "").trim();
6275
- if (!text) return null;
6276
- const resolved = await resolveAddressRoom(env, text).catch(() => null);
6277
- if (resolved?.id && !resolved.lookupFailed) {
6278
- return { id: resolved.id, name: resolved.name || resolved.id };
6279
- }
6280
- const ref = parseRoomRef(text);
6281
- if (ref.id) {
6282
- try {
6283
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
6284
- const detail = await getMeetingOperation2("meeting.eb.room.detail").handler({ id: ref.id }, env);
6285
- const main = detail?.data?.mainTable ?? detail?.data?.data?.mainTable ?? {};
6286
- const name = String(main.room_name ?? "").trim() || ref.name || "";
6287
- if (name) return { id: ref.id, name };
6288
- } catch {
6289
- }
6290
- return { id: ref.id, name: ref.name || ref.id };
6291
- }
6292
- return null;
6293
- }
6294
- async function shapeBrowserValues(env, values) {
6295
- const notes = [];
6296
- const shaped = { ...values };
6297
- const readable = {};
6298
- if (shaped.address !== void 0 && shaped.address !== "") {
6299
- const room = await resolveRoomValue(env, String(shaped.address));
6300
- if (room) {
6301
- shaped.address = room;
6302
- readable.address = room.name;
6303
- notes.push(`\u4F1A\u8BAE\u5730\u70B9\u6309\u6D4F\u89C8\u6309\u94AE\u683C\u5F0F\u63D0\u4EA4\uFF1A${room.name}(${room.id})`);
6304
- } else {
6305
- readable.address = String(shaped.address);
6306
- }
6307
- }
6308
- const personFields = ["hrm_members", "caller", "contacter"];
6309
- const idPool = [];
6310
- for (const key of personFields) {
6311
- const raw = shaped[key];
6312
- if (raw === void 0 || raw === "") continue;
6313
- const ids = String(raw).split(/[,;,;\s]+/).map((item) => item.trim()).filter((item) => item !== "");
6314
- idPool.push(...ids);
6315
- }
6316
- if (idPool.length > 0) {
6317
- const people = await resolvePersonTokens(env, idPool);
6318
- const toObject = (token) => people.get(token) ?? { id: token, name: token };
6319
- const toName = (token) => people.get(token)?.name ?? token;
6320
- if (shaped.hrm_members !== void 0 && shaped.hrm_members !== "") {
6321
- const ids = String(shaped.hrm_members).split(/[,;,;\s]+/).map((item) => item.trim()).filter((item) => item !== "");
6322
- shaped.hrm_members = ids.map(toObject);
6323
- readable.hrm_members = ids.map(toName).join("\u3001");
6324
- notes.push(`\u53C2\u4F1A\u4EBA\u5458\u6309\u6D4F\u89C8\u6309\u94AE\u683C\u5F0F\u63D0\u4EA4\uFF1A${ids.length} \u4EBA`);
6325
- }
6326
- if (shaped.caller !== void 0 && shaped.caller !== "") {
6327
- const id = String(shaped.caller).trim();
6328
- shaped.caller = toObject(id);
6329
- readable.caller = toName(id);
6330
- }
6331
- if (shaped.contacter !== void 0 && shaped.contacter !== "") {
6332
- const id = String(shaped.contacter).trim();
6333
- shaped.contacter = toObject(id);
6334
- readable.contacter = toName(id);
6335
- }
6336
- const unresolved = [...new Set(idPool)].filter((token) => !people.has(token));
6337
- if (unresolved.length > 0) {
6338
- notes.push(
6339
- `\u26A0\uFE0F \u6709 ${unresolved.length} \u4E2A\u4EBA\u5458\u6CA1\u89E3\u6790\u5230\u5458\u5DE5\uFF1A${unresolved.join("\u3001")} \u2014\u2014 \u8868\u5355\u91CC\u7684\u300C\u53C2\u4F1A\u4EBA\u5458/\u53EC\u96C6\u4EBA/\u8054\u7CFB\u4EBA\u300D\u53EF\u80FD\u663E\u793A\u4E0D\u51FA\u6765\u3002\u8BF7\u6539\u4F20\u5458\u5DE5 id\uFF0C\u6216\u786E\u8BA4\u59D3\u540D\u4E0E\u82B1\u540D\u518C\u5B8C\u5168\u4E00\u81F4\u3002`
6340
- );
6341
- }
6342
- }
6343
- if (shaped.crm_members !== void 0 && shaped.crm_members !== "") {
6344
- const rows = [];
6345
- const push = (idRaw, nameRaw) => {
6346
- const id = String(idRaw ?? "").trim();
6347
- const name = String(nameRaw ?? "").trim();
6348
- if (id === "" && name === "") return;
6349
- rows.push({ id, name });
6350
- };
6351
- const pushToken = (tokenRaw) => {
6352
- const token = String(tokenRaw ?? "").trim();
6353
- if (token === "") return;
6354
- const matched = token.match(/^(.*?)[((]\s*([0-9A-Za-z_-]+)\s*[))]$/);
6355
- if (matched) {
6356
- push(matched[2], matched[1]);
6357
- return;
6358
- }
6359
- if (/^\d{8,}$/.test(token)) {
6360
- push(token, "");
6361
- return;
6362
- }
6363
- push("", token);
6364
- };
6365
- const raw = shaped.crm_members;
6366
- if (Array.isArray(raw)) {
6367
- for (const item of raw) {
6368
- if (item && typeof item === "object") {
6369
- const obj = item;
6370
- push(obj.id ?? obj.sjID ?? obj.customerId, obj.name ?? obj.mc);
6371
- } else {
6372
- for (const token of String(item).split(/[,;,;]+/).map((one) => one.trim()).filter((one) => one !== "")) {
6373
- pushToken(token);
6374
- }
6375
- }
6376
- }
6377
- } else if (typeof raw === "object") {
6378
- const obj = raw;
6379
- push(obj.id ?? obj.sjID ?? obj.customerId, obj.name ?? obj.mc);
6380
- } else {
6381
- for (const token of String(raw).split(/[,;,;]+/).map((item) => item.trim()).filter((item) => item !== "")) {
6382
- pushToken(token);
6383
- }
6384
- }
6385
- if (rows.length > 0) {
6386
- const nameOnly = rows.filter((row) => row.id === "" && row.name !== "");
6387
- if (nameOnly.length > 0) {
6388
- try {
6389
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
6390
- const search = getMeetingOperation2("meeting.eb.crm.search");
6391
- for (const row of nameOnly) {
6392
- const found = await search.handler({ keyword: row.name, limit: 5 }, env).catch(() => null);
6393
- const items = found?.data?.items ?? [];
6394
- const hit = items.find((item) => String(item?.name ?? "").trim() === row.name) ?? items[0];
6395
- const id = String(hit?.customerId ?? "").trim();
6396
- if (id === "") continue;
6397
- row.id = id;
6398
- const fullName = String(hit?.name ?? "").trim();
6399
- if (fullName !== "") row.name = fullName;
6400
- }
6401
- } catch {
6402
- }
6403
- }
6404
- const unresolved = rows.filter((row) => row.id === "");
6405
- if (unresolved.length > 0) {
6406
- throw meetingValidationError(
6407
- "crm_not_found",
6408
- `\u53C2\u4F1A\u5BA2\u6237\u6709 ${unresolved.length} \u4E2A\u5728 CRM \u91CC\u67E5\u4E0D\u5230\uFF1A${unresolved.map((row) => row.name).join("\u3001")}\u3002\u8BF7\u786E\u8BA4\u5BA2\u6237\u540D\u79F0\uFF0C\u6216\u5148\u5230\u5BA2\u6237\u8868\u5EFA\u6863\uFF1B\u4E5F\u53EF\u4EE5\u6539\u7528\u300C\u5BA2\u6237\u540D(\u5BA2\u6237id)\u300D\u6216 \`[{id,name}]\` \u4F20 crm_members\u3002`
6409
- );
6410
- }
6411
- shaped.crm_members = rows;
6412
- readable.crm_members = rows.map((row) => row.name || row.id).join("\u3001");
6413
- notes.push(`\u53C2\u4F1A\u5BA2\u6237\u6309\u5BA2\u6237\u6D4F\u89C8\u6309\u94AE\u683C\u5F0F\u63D0\u4EA4\uFF1A${rows.length} \u4E2A\u5BA2\u6237`);
6414
- const missingNames = rows.filter((row) => row.name === "");
6415
- if (missingNames.length > 0) {
6416
- throw meetingValidationError(
6417
- "crm_name_required",
6418
- `\u53C2\u4F1A\u5BA2\u6237\u6709 ${missingNames.length} \u4E2A\u53EA\u7ED9\u4E86 id\u3001\u6CA1\u6709\u5BA2\u6237\u540D\u79F0\uFF1A${missingNames.map((row) => row.id).join("\u3001")}\u3002\u5BA2\u6237\u6D4F\u89C8\u6309\u94AE\u5FC5\u987B\u5E26\u540D\u79F0\u624D\u80FD\u5199\u5165\uFF08\u53EA\u7ED9 id \u4F1A\u88AB\u670D\u52A1\u7AEF\u9759\u9ED8\u5B58\u6210\u7A7A\u503C\uFF09\u3002\u8BF7\u5148\u7528 \`meeting.eb.crm.search\` \u6309\u5BA2\u6237\u540D\u67E5\u5230 \`{ customerId, name }\`\uFF0C\u518D\u4EE5 \`[{id,name}]\` \u6216\u300C\u5BA2\u6237\u540D(\u5BA2\u6237id)\u300D\u7684\u5F62\u5F0F\u4F20 \`crm_members\`\u3002`
6419
- );
6420
- }
6421
- } else {
6422
- delete shaped.crm_members;
6423
- }
6424
- }
6425
- for (const [key, raw] of Object.entries(values)) {
6426
- if (readable[key] !== void 0) continue;
6427
- if (raw === void 0 || raw === null || raw === "") continue;
6428
- if (typeof raw === "object") continue;
6429
- readable[key] = String(raw);
6430
- }
6431
- return { values: shaped, notes, readable };
6432
- }
6433
- function normalizeFieldName(name) {
6434
- return String(name ?? "").replace(/[((][^(())]*[))]/g, "").replace(/[\s\u3000]+/g, "").trim();
6435
- }
6436
- var CRM_DETAIL_COLUMNS = {
6437
- xm: ["\u59D3\u540D", "\u5BA2\u6237\u59D3\u540D", "\u53C2\u4F1A\u4EBA", "\u53C2\u4F1A\u4EBA\u59D3\u540D"],
6438
- xb: ["\u6027\u522B"],
6439
- zw: ["\u804C\u4F4D", "\u804C\u52A1"],
6440
- sjhm: ["\u624B\u673A\u53F7\u7801", "\u624B\u673A\u53F7", "\u624B\u673A", "\u7535\u8BDD", "\u8054\u7CFB\u7535\u8BDD"],
6441
- bz: ["\u5907\u6CE8", "\u8BF4\u660E"]
6442
- };
6443
- function resolveCrmDetailTarget(fields) {
6444
- const groups = /* @__PURE__ */ new Map();
6445
- for (const field of fields) {
6446
- const sid = String(field.subFormId ?? "").trim();
6447
- if (!sid) continue;
6448
- const list = groups.get(sid);
6449
- if (list) list.push(field);
6450
- else groups.set(sid, [field]);
6451
- }
6452
- let best = null;
6453
- for (const [subFormId, list] of groups) {
6454
- const columns = {};
6455
- const labels = {};
6456
- for (const [semantic, aliases] of Object.entries(CRM_DETAIL_COLUMNS)) {
6457
- const hit = list.find((field) => aliases.includes(normalizeFieldName(field.name)));
6458
- if (!hit) continue;
6459
- columns[semantic] = hit.id;
6460
- labels[semantic] = hit.name;
6461
- }
6462
- if (!columns.xm) continue;
6463
- const score = Object.keys(columns).length + (columns.sjhm ? 1 : 0) + (columns.zw ? 1 : 0);
6464
- if (!best || score > best.score) best = { subFormId, columns, labels, score };
6465
- }
6466
- return best ? { subFormId: best.subFormId, columns: best.columns, labels: best.labels } : null;
6467
- }
6468
- function detectCrmMentionInText(...texts) {
6469
- for (const text of texts) {
6470
- if (typeof text !== "string") continue;
6471
- const value = text.trim();
6472
- if (value === "") continue;
6473
- const hit = /(?:参会|拜访|来访)?客户\s*(?:名称)?\s*(?:是|为|[::])\s*([^\s,,。;;、))]{2,40})/.exec(value);
6474
- if (hit?.[1]) return hit[1].trim();
6475
- }
6476
- return null;
6477
- }
6478
- function normalizeCrmDetailRows(raw) {
6479
- if (raw === void 0 || raw === null || raw === "") return [];
6480
- const list = Array.isArray(raw) ? raw : [raw];
6481
- const keyAlias = {
6482
- xm: "xm",
6483
- name: "xm",
6484
- customername: "xm",
6485
- \u59D3\u540D: "xm",
6486
- \u5BA2\u6237\u59D3\u540D: "xm",
6487
- xb: "xb",
6488
- gender: "xb",
6489
- sex: "xb",
6490
- \u6027\u522B: "xb",
6491
- zw: "zw",
6492
- title: "zw",
6493
- position: "zw",
6494
- job: "zw",
6495
- \u804C\u4F4D: "zw",
6496
- \u804C\u52A1: "zw",
6497
- sjhm: "sjhm",
6498
- mobile: "sjhm",
6499
- phone: "sjhm",
6500
- tel: "sjhm",
6501
- \u624B\u673A\u53F7\u7801: "sjhm",
6502
- \u624B\u673A\u53F7: "sjhm",
6503
- \u7535\u8BDD: "sjhm",
6504
- \u8054\u7CFB\u7535\u8BDD: "sjhm",
6505
- bz: "bz",
6506
- remark: "bz",
6507
- note: "bz",
6508
- \u5907\u6CE8: "bz",
6509
- \u8BF4\u660E: "bz"
6510
- };
6511
- const rows = [];
6512
- for (const item of list) {
6513
- if (item === void 0 || item === null || typeof item !== "object") continue;
6514
- const row = {};
6515
- for (const [key, value] of Object.entries(item)) {
6516
- const semantic = keyAlias[String(key).trim().toLowerCase()] ?? keyAlias[String(key).trim()];
6517
- if (!semantic) continue;
6518
- if (value === void 0 || value === null) continue;
6519
- const text = String(value).trim();
6520
- if (text === "") continue;
6521
- row[semantic] = text;
6522
- }
6523
- if (!row.xm && !row.sjhm) continue;
6524
- rows.push(row);
6525
- }
6526
- return rows;
6527
- }
6528
- function crmMemberEntriesFromArgs(raw) {
6529
- const list = Array.isArray(raw) ? raw : raw === void 0 || raw === null || raw === "" ? [] : [raw];
6530
- const out = [];
6531
- const push = (idRaw, nameRaw, contactsRaw) => {
6532
- const id = String(idRaw ?? "").trim();
6533
- const name = String(nameRaw ?? "").trim();
6534
- if (id === "" && name === "") return;
6535
- const contacts = (Array.isArray(contactsRaw) ? contactsRaw : []).map((item) => {
6536
- const row = item ?? {};
6537
- return {
6538
- name: String(row.name ?? row.xm ?? "").trim(),
6539
- mobile: String(row.mobile ?? row.sjhm ?? row.phone ?? "").trim(),
6540
- ...String(row.dept ?? row.bm ?? "").trim() === "" ? {} : { dept: String(row.dept ?? row.bm).trim() }
6541
- };
6542
- }).filter((one) => one.name !== "" || one.mobile !== "");
6543
- out.push({ id: id === "" ? name : id, name, contacts });
6544
- };
6545
- for (const item of list) {
6546
- if (item && typeof item === "object") {
6547
- const obj = item;
6548
- push(obj.customerId ?? obj.sjID ?? obj.id, obj.name ?? obj.mc, obj.contacts ?? obj.lxr);
6549
- } else {
6550
- const token = String(item).trim();
6551
- if (token === "") continue;
6552
- const matched = token.match(/^(.*?)[((]\s*([0-9A-Za-z_-]+)\s*[))]$/);
6553
- if (matched) push(matched[2], matched[1], void 0);
6554
- else push(token, "", void 0);
6555
- }
6556
- }
6557
- return out;
6558
- }
6559
- function crmContactsToDetailRows(entries) {
6560
- const rows = [];
6561
- const seen = /* @__PURE__ */ new Set();
6562
- for (const entry of entries) {
6563
- for (const contact of entry.contacts) {
6564
- const xm = contact.name.trim();
6565
- const sjhm = contact.mobile.trim();
6566
- if (xm === "" && sjhm === "") continue;
6567
- const key = `${xm}|${sjhm}`;
6568
- if (seen.has(key)) continue;
6569
- seen.add(key);
6570
- const row = { xm: xm === "" ? sjhm : xm };
6571
- if (sjhm !== "") row.sjhm = sjhm;
6572
- if (contact.dept && contact.dept.trim() !== "") row.bz = `\u90E8\u95E8\uFF1A${contact.dept.trim()}`;
6573
- rows.push(row);
6574
- }
6575
- }
6576
- return rows;
6577
- }
6578
- async function resolveAutoCrmDetailRows(env, raw) {
6579
- const entries = crmMemberEntriesFromArgs(raw);
6580
- const missing = [];
6581
- if (entries.length > 0) {
6582
- try {
6583
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
6584
- const search = getMeetingOperation2("meeting.eb.crm.search");
6585
- for (const entry of entries) {
6586
- const keyword = (entry.name || entry.id).trim();
6587
- if (keyword === "") {
6588
- missing.push(entry.id);
6589
- continue;
6590
- }
6591
- const searchOnce = async (kw) => {
6592
- const found = await search.handler({ keyword: kw, limit: 5 }, env).catch(() => null);
6593
- const items = found?.data?.items ?? [];
6594
- const hit = items.find((item) => String(item?.customerId ?? "") === entry.id) ?? items[0];
6595
- return hit?.contacts ?? [];
6596
- };
6597
- let live = await searchOnce(keyword);
6598
- if (live.length === 0 && keyword.includes("--")) {
6599
- const short = keyword.split("--")[0].trim();
6600
- if (short !== "") live = await searchOnce(short);
6601
- }
6602
- if (live.length === 0) {
6603
- if (entry.contacts.length === 0) missing.push(entry.name || entry.id);
6604
- continue;
6605
- }
6606
- const keyOf = (one) => `${String(one.name ?? "").trim()}|${String(one.mobile ?? "").trim()}`;
6607
- const merged = /* @__PURE__ */ new Map();
6608
- for (const one of live) merged.set(keyOf(one), one);
6609
- for (const one of entry.contacts) {
6610
- const key = keyOf(one);
6611
- const base = merged.get(key);
6612
- merged.set(key, base ? { ...base, ...one } : one);
6613
- }
6614
- entry.contacts = [...merged.values()];
6615
- }
6616
- } catch {
6617
- }
6618
- }
6619
- return {
6620
- rows: crmContactsToDetailRows(entries),
6621
- customers: entries.map((entry) => entry.name || entry.id).filter((one) => one !== ""),
6622
- missing
6623
- };
6624
- }
6625
- function mapFields(fields, values, preferred = {}) {
6626
- const byName = new Map(fields.map((field) => [field.name.trim(), field]));
6627
- const byId = new Map(fields.map((field) => [field.id, field]));
6628
- const byNormalized = /* @__PURE__ */ new Map();
6629
- for (const field of fields) {
6630
- const key = normalizeFieldName(field.name);
6631
- if (key && !byNormalized.has(key)) byNormalized.set(key, field);
6632
- }
6633
- const main = {};
6634
- const mapped = {};
6635
- const unmapped = [];
6636
- const resolved = {};
6637
- const findField = (aliases) => {
6638
- for (const name of aliases) {
6639
- const field = byName.get(name);
6640
- if (field) return field;
6641
- }
6642
- for (const name of aliases) {
6643
- const field = byNormalized.get(normalizeFieldName(name));
6644
- if (field) return field;
6645
- }
6646
- for (const name of aliases) {
6647
- const needle = normalizeFieldName(name);
6648
- if (needle.length < 2) continue;
6649
- for (const [key, field] of byNormalized) {
6650
- if (key.includes(needle)) return field;
6651
- }
6652
- }
6653
- return void 0;
6654
- };
6655
- for (const [key, raw] of Object.entries(values)) {
6656
- if (raw === void 0 || raw === null || raw === "") continue;
6657
- const aliases = FIELD_ALIASES[key] ?? [key];
6658
- const prefId = preferred[key];
6659
- const hit = (prefId ? byId.get(prefId) : void 0) ?? findField(aliases);
6660
- if (!hit) {
6661
- unmapped.push(key);
6662
- continue;
6663
- }
6664
- main[hit.id] = raw;
6665
- mapped[key] = `${hit.name}(${hit.id})`;
6666
- resolved[key] = hit.id;
6667
- }
6668
- return { main, mapped, unmapped, resolved };
6669
- }
6670
- var PREVIEW_PERSON_FIELD_RE = /^(召集人|联系人|参会人员|会议创建人|主讲人|负责人|费用承担人)$/;
6671
- async function decoratePreviewPersonNames(env, main, fields, known = /* @__PURE__ */ new Map()) {
6672
- const targets = fields.filter((field) => PREVIEW_PERSON_FIELD_RE.test(String(field?.name ?? "").trim()));
6673
- if (targets.length === 0) return main;
6674
- const ID_ONLY_RE = /^\d{8,}$/;
6675
- const missingNameId = (value) => {
6676
- if (typeof value === "string") return ID_ONLY_RE.test(value.trim()) ? value.trim() : null;
6677
- if (value && typeof value === "object" && !Array.isArray(value)) {
6678
- const obj = value;
6679
- const id = String(obj.id ?? "").trim();
6680
- const name = String(obj.name ?? "").trim();
6681
- if (id !== "" && (name === "" || name === id)) return id;
6682
- }
6683
- return null;
6684
- };
6685
- const ids = /* @__PURE__ */ new Set();
6686
- for (const field of targets) {
6687
- const value = main[field.id];
6688
- const one = missingNameId(value);
6689
- if (one) ids.add(one);
6690
- else if (Array.isArray(value)) for (const item of value) {
6691
- const hit = missingNameId(item);
6692
- if (hit) ids.add(hit);
6693
- }
6694
- }
6695
- if (ids.size === 0) return main;
6696
- let names = new Map(known);
6697
- const unknown = [...ids].filter((id) => !names.has(id));
6698
- if (unknown.length > 0) {
6699
- try {
6700
- const resolved = await resolveEmployeeNames(env, unknown);
6701
- for (const [id, name] of resolved) names.set(id, name);
6702
- } catch {
6703
- }
6704
- }
6705
- if (names.size === 0) return main;
6706
- const rename = (value) => {
6707
- const one = missingNameId(value);
6708
- if (one) return names.get(one) ?? value;
6709
- if (value && typeof value === "object" && !Array.isArray(value)) {
6710
- const obj = value;
6711
- const id = String(obj.id ?? "").trim();
6712
- const name = names.get(id);
6713
- if (name) return { ...obj, name };
6714
- }
6715
- return value;
6716
- };
6717
- const decorated = { ...main };
6718
- for (const field of targets) {
6719
- const value = decorated[field.id];
6720
- decorated[field.id] = Array.isArray(value) ? value.map(rename) : rename(value);
6721
- }
6722
- return decorated;
6723
- }
6724
- function renderFormPreview(fields, main) {
6725
- const fmt = (value) => {
6726
- if (value === void 0 || value === null) return "\u2014";
6727
- if (Array.isArray(value)) {
6728
- const parts = value.map((one) => fmt(one)).filter((one) => one !== "\u2014");
6729
- return parts.length > 0 ? parts.join("\u3001") : "\u2014";
6730
- }
6731
- if (typeof value === "object") {
6732
- const obj = value;
6733
- const name = String(obj.name ?? obj.mc ?? "").trim();
6734
- if (name !== "") return name.replace(/\|/gu, "/");
6735
- const id = String(obj.id ?? obj.customerId ?? obj.sjID ?? "").trim();
6736
- return id === "" ? "\u2014" : id;
6737
- }
6738
- const text = String(value).trim();
6739
- return text === "" ? "\u2014" : text.replace(/\|/gu, "/").replace(/\r?\n/gu, " ");
6740
- };
6741
- const lines = ["| \u5B57\u6BB5 | \u503C |", "| --- | --- |"];
6742
- const known = /* @__PURE__ */ new Set();
6743
- for (const field of fields) {
6744
- known.add(field.id);
6745
- if (!(field.id in main)) continue;
6746
- lines.push(`| ${String(field.name).replace(/\|/gu, "/")} | ${fmt(main[field.id])} |`);
6747
- }
6748
- for (const [id, value] of Object.entries(main)) {
6749
- if (known.has(id)) continue;
6750
- lines.push(`| ${id} | ${fmt(value)} |`);
6751
- }
6752
- return lines.join("\n");
6753
- }
6754
- function flowFieldCacheDir(env) {
6755
- const configured = env?.ctx?.config?.path?.();
6756
- const root = configured ? resolve5(String(configured), "..") : process.env.WEAVER_WORK_CLI_HOME || process.env.WORK_CLI_HOME || resolve5(homedir(), ".weaver-work-cli");
6757
- return resolve5(root, "meeting", "cache");
6758
- }
6759
- function flowFieldCacheFile(env, workflowId) {
6760
- return resolve5(flowFieldCacheDir(env), `flow-fields-${workflowId}.json`);
6761
- }
6762
- async function readFlowFieldMap(env, workflowId) {
6763
- try {
6764
- const file = flowFieldCacheFile(env, workflowId);
6765
- if (!existsSync3(file)) return {};
6766
- const parsed = JSON.parse(await readFile4(file, "utf8"));
6767
- return parsed && typeof parsed.mapping === "object" && parsed.mapping ? parsed.mapping : {};
6768
- } catch {
6769
- return {};
6770
- }
6771
- }
6772
- async function writeFlowFieldMap(env, workflowId, workflowName, mapping) {
6773
- if (Object.keys(mapping).length === 0) return;
6774
- try {
6775
- const file = flowFieldCacheFile(env, workflowId);
6776
- await mkdir4(resolve5(file, ".."), { recursive: true });
6777
- const cache = {
6778
- workflowId,
6779
- ...workflowName ? { workflowName } : {},
6780
- savedAt: (/* @__PURE__ */ new Date()).toISOString(),
6781
- mapping
6782
- };
6783
- await writeFile4(file, JSON.stringify(cache, null, 2), "utf8");
6784
- } catch {
6785
- }
6786
- }
6787
- function normalizeWorkflowIds(raw) {
6788
- if (raw === void 0 || raw === null) return [];
6789
- const list = Array.isArray(raw) ? raw : [raw];
6790
- const ids = [];
6791
- for (const item of list) {
6792
- for (const piece of String(item ?? "").split(/[,;,;\s]+/)) {
6793
- const term = piece.trim();
6794
- if (!term) continue;
6795
- const matched = term.match(/[((](\d{6,})[))]$/);
6796
- const id = matched ? matched[1] : term;
6797
- if (!ids.includes(id)) ids.push(id);
6798
- }
6799
- }
6800
- return ids;
6801
- }
6802
- var FIXED_FLOW_IDS = ["1325677244111462606", "1326190634427154474"];
6803
- var FIXED_FLOW_PROFILES = [
6804
- {
6805
- host: "www.e-cology.com.cn",
6806
- tenantKey: "t7akvdnf84",
6807
- label: "\u6CDB\u5FAE\u751F\u4EA7\uFF08\u6CDB\u5FAE\u7F51\u7EDC\uFF09",
6808
- ids: [...FIXED_FLOW_IDS]
6809
- }
6810
- ];
6811
- function fixedFlowFlagOn() {
6812
- const flag = String(process.env.WEAVER_MEETING_FIXED_FLOW ?? "1").trim().toLowerCase();
6813
- return !(flag === "0" || flag === "false" || flag === "off");
6814
- }
6815
- function fixedFlowOverride() {
6816
- const override = String(process.env.WEAVER_MEETING_FIXED_FLOW_IDS ?? "").trim();
6817
- if (!override) return [];
6818
- return override.split(/[,;,;\s]+/).map((item) => item.trim()).filter((item) => item !== "");
6819
- }
6820
- async function fixedFlowIdsForEnv(env) {
6821
- if (!fixedFlowFlagOn()) return { ids: [] };
6822
- const override = fixedFlowOverride();
6823
- if (override.length > 0) return { ids: override, label: "\u73AF\u5883\u53D8\u91CF\u6307\u5B9A" };
6824
- let baseUrl = "";
6825
- let tenantKey = "";
6826
- try {
6827
- const session = await env?.host?.getSession?.();
6828
- baseUrl = String(session?.baseUrl ?? "");
6829
- tenantKey = String(session?.tenantKey ?? session?.tenantId ?? "");
6830
- } catch {
6831
- }
6832
- if (!baseUrl) return { ids: [...FIXED_FLOW_IDS], label: "\u9ED8\u8BA4\u56FA\u5316\u914D\u7F6E\uFF08\u672A\u53D6\u5230\u767B\u5F55\u73AF\u5883\uFF09" };
6833
- const host = baseUrl.replace(/^https?:\/\//i, "").replace(/\/.*$/, "").toLowerCase();
6834
- const hit = FIXED_FLOW_PROFILES.find((profile) => profile.host === host && (!profile.tenantKey || !tenantKey || profile.tenantKey === tenantKey));
6835
- return hit ? { ids: [...hit.ids], label: hit.label } : { ids: [] };
6836
- }
6837
- function shouldAutoPickFlow(args) {
6838
- if (args.flowChoice === "auto") return true;
6839
- return String(process.env.WEAVER_MEETING_FLOW_CHOICE ?? "").trim().toLowerCase() === "auto";
6840
- }
6841
- async function resolveWorkflowId(env, args) {
6842
- const explicitList = normalizeWorkflowIds(args.workflowId);
6843
- if (explicitList.length > 0) {
6844
- return {
6845
- workflowId: explicitList.length === 1 ? explicitList[0] : "",
6846
- candidates: explicitList,
6847
- source: "argument"
6848
- };
6849
- }
6850
- const fixed = await fixedFlowIdsForEnv(env);
6851
- if (fixed.ids.length > 0) {
6852
- return {
6853
- workflowId: fixed.ids.length === 1 ? fixed.ids[0] : "",
6854
- candidates: fixed.ids,
6855
- source: "fixed",
6856
- ...fixed.label ? { label: fixed.label } : {}
6857
- };
6858
- }
6859
- const settings = await fetchEbAppSettings(env, "meeting.eb.meeting.create.flow.prepare");
6860
- const candidates = String(settings.mtNewWf ?? "").split(/[,;,;\s]+/).map((item) => item.trim()).filter((item) => item !== "");
6861
- if (candidates.length === 0) {
6862
- throw meetingValidationError(
6863
- "flow_not_configured",
6864
- "\u5E94\u7528\u8BBE\u7F6E\u91CC\u6CA1\u6709\u914D\u7F6E\u300C\u65B0\u5EFA\u4F1A\u8BAE\u5DE5\u4F5C\u6D41\u300D\uFF08mt_new_wf \u4E3A\u7A7A\uFF09\uFF0C\u4E5F\u6CA1\u6709\u542F\u7528\u56FA\u5316\u6D41\u7A0B\uFF0C\u65E0\u6CD5\u8D70\u6D41\u7A0B\u5EFA\u4F1A\uFF1B\u8BF7\u7BA1\u7406\u5458\u5728\u4F1A\u8BAE\u5E94\u7528\u8BBE\u7F6E\u91CC\u914D\u7F6E\uFF0C\u6216\u7528 WEAVER_MEETING_FIXED_FLOW_IDS \u6307\u5B9A\u9ED8\u8BA4\u6D41\u7A0B"
6865
- );
6866
- }
6867
- return { workflowId: candidates.length === 1 ? candidates[0] : "", candidates, source: "settings" };
6868
- }
6869
- function pad2(value) {
6870
- return String(value).padStart(2, "0");
6871
- }
6872
- function tomorrowIso() {
6873
- const date = new Date(Date.now() + 24 * 60 * 60 * 1e3);
6874
- return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())}`;
6875
- }
6876
- function formatMinute(date) {
6877
- return `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())} ${pad2(date.getHours())}:${pad2(date.getMinutes())}`;
6878
- }
6879
- async function probeWorkflowCandidates(env, ids) {
6880
- const probed = await Promise.all(ids.map(async (id) => {
6881
- try {
6882
- const probeForm = await loadCreateForm(env, id);
6883
- return {
6884
- id,
6885
- probeForm,
6886
- probe: {
6887
- workflowId: id,
6888
- ...probeForm.workflowName ? { name: probeForm.workflowName } : {},
6889
- launchable: true
6890
- }
6891
- };
6892
- } catch (error) {
6893
- return {
6894
- id,
6895
- probeForm: null,
6896
- probe: {
6897
- workflowId: id,
6898
- launchable: false,
6899
- reason: String(error?.message ?? error).slice(0, 160)
6900
- }
6901
- };
6902
- }
6903
- }));
6904
- const probes = [];
6905
- const loadedForms = /* @__PURE__ */ new Map();
6906
- for (const item of probed) {
6907
- if (item.probeForm) loadedForms.set(item.id, item.probeForm);
6908
- probes.push(item.probe);
6909
- }
6910
- return { probes, loadedForms };
6911
- }
6912
- var ebMeetingCreateFlowPrepare = {
6913
- name: "meeting.eb.meeting.create.flow.prepare",
6914
- resource: "eb",
6915
- method: "meeting.eb.meeting.create.flow.prepare",
6916
- action: "meeting.eb.meeting.create.flow.prepare",
6917
- summary: '\u6D41\u7A0B\u5EFA\u4F1A\uFF08\u51C6\u5907\uFF09\uFF1A\u7528\u56FA\u5316\u6D41\u7A0B\u5019\u9009\u9010\u4E2A\u63A2\u6D4B\u53D1\u8D77\u6743\u9650 \u2014\u2014 \u4EC5 1 \u4E2A\u53EF\u53D1\u8D77\u5C31\u81EA\u52A8\u7528\u5B83\u3001\u591A\u4E2A\u90FD\u53EF\u53D1\u8D77\u5219\u8FD4\u56DE\u9009\u9879\u8BA9\u7528\u6237\u9009\u3001\u90FD\u4E0D\u53EF\u53D1\u8D77\u62A5\u300C\u6CA1\u6709\u53D1\u8D77\u6743\u9650\u300D\uFF1B\u4E0D\u4F20 begin_datetime \u65F6\u81EA\u52A8\u63A8\u8350\u300C\u4EBA+\u4F1A\u8BAE\u5BA4\u90FD\u7A7A\u95F2\u300D\u7684\u65F6\u6BB5\u3002\u53EA\u51FA\u9884\u89C8\u4E0E\u786E\u8BA4\u7968\u636E\uFF0C\u4E0D\u63D0\u4EA4\u3002\u26A0\uFE0F \u7528\u6237\u63D0\u5230\u5BA2\u6237\u540D\uFF08\u300C\u5BA2\u6237\u662F X\u300D\uFF09\u65F6**\u5FC5\u987B\u5148** meeting.eb.crm.search {"keyword":"X"} \u62FF customerId\uFF0C\u518D\u4F20 crm_members:[{id,name}]\uFF1B\u53EA\u628A\u5BA2\u6237\u540D\u5199\u8FDB\u4F1A\u8BAE\u540D\u79F0/\u5185\u5BB9\uFF0C\u8868\u5355\u300C\u53C2\u4F1A\u5BA2\u6237\u300D\u5C31\u662F\u7A7A\u7684',
6918
- capability: "eb.meeting",
6919
- risk: "read-before-write",
6920
- requiresConfirmation: true,
6921
- inputSchema: schemaOf(
6922
- {
6923
- mt_name: { type: "string", description: "\u4F1A\u8BAE\u540D\u79F0\uFF08\u5FC5\u586B\uFF09" },
6924
- begin_datetime: {
6925
- ...SCHEMA_DATETIME_MINUTE,
6926
- description: "\u5F00\u59CB\u65F6\u95F4\uFF08yyyy-MM-dd HH:mm\uFF09\u3002**\u53EF\u4EE5\u4E0D\u4F20**\uFF1A\u4E0D\u4F20\u4F1A\u6309\u53C2\u4F1A\u4EBA\u4E0E\u4F1A\u8BAE\u5BA4\u7A7A\u95F2\u60C5\u51B5\u63A8\u8350 3 \u4E2A\u65F6\u6BB5\u8BA9\u4F60\u9009\uFF1B\u53EA\u4F20\u5F00\u59CB\u65F6\u95F4\u3001\u4E0D\u4F20\u7ED3\u675F\u65F6\u95F4\u65F6\uFF0C\u6309 durationMinutes\uFF08\u9ED8\u8BA4 60 \u5206\u949F\uFF09\u81EA\u52A8\u7B97\u7ED3\u675F\u65F6\u95F4"
6927
- },
6928
- end_datetime: {
6929
- ...SCHEMA_DATETIME_MINUTE,
6930
- description: "\u7ED3\u675F\u65F6\u95F4\uFF08yyyy-MM-dd HH:mm\uFF09\uFF1B\u4E0D\u4F20\u5219\u6309 durationMinutes \u4ECE\u5F00\u59CB\u65F6\u95F4\u63A8\u7B97\uFF08\u9ED8\u8BA4 60 \u5206\u949F\uFF09"
6931
- },
6932
- mt_desc: { type: "string", description: "\u4F1A\u8BAE\u5185\u5BB9/\u8BF4\u660E" },
6933
- address: { type: "string", description: "\u4F1A\u8BAE\u5BA4\uFF08\u540D\u79F0\u6216 id\uFF0C\u6309\u6D41\u7A0B\u8868\u5355\u5B57\u6BB5\u8981\u6C42\uFF09" },
6934
- customize_address: { type: "string", description: "\u81EA\u5B9A\u4E49\u4F1A\u8BAE\u5730\u70B9" },
6935
- hrm_members: { type: "string", description: "\u53C2\u4F1A\u4EBA\u5458\uFF08\u9017\u53F7\u5206\u9694\u5458\u5DE5 id \u6216\u59D3\u540D\uFF0C\u6309\u6D41\u7A0B\u8868\u5355\u8981\u6C42\uFF09" },
6936
- total_member: { type: "number", description: "\u53C2\u4F1A\u4EBA\u6570" },
6937
- crm_members: {
6938
- oneOf: [{ type: "string" }, { type: "array", items: { oneOf: [{ type: "string" }, { type: "object" }] } }],
6939
- description: "\u53C2\u4F1A\u5BA2\u6237\uFF1A**\u5FC5\u987B\u5E26\u5BA2\u6237\u540D\u79F0**\uFF0C\u5199\u6CD5 `[{id,name}]` \u6216\u300C\u5BA2\u6237\u540D(\u5BA2\u6237id)\u300D\u6216\u9017\u53F7\u5206\u9694\u7684\u8FD9\u4E24\u79CD\u3002\u5BA2\u6237\u5148\u4ECE `meeting.eb.crm.search` \u6309\u5BA2\u6237\u540D\u67E5\u51FA\uFF08\u5165\u53C2 custom_name\uFF0C\u51FA\u53C2 items[].customerId / name\uFF09\uFF0C\u8BE5\u67E5\u8BE2**\u4E00\u6B21\u53EA\u56DE\u9996\u4E2A\u5339\u914D** \u21D2 exact=false \u65F6\u5FC5\u987B\u5148\u8BA9\u7528\u6237\u786E\u8BA4\u5BA2\u6237\u540D\u518D\u5199\u8FD9\u4E2A\u5B57\u6BB5\u3002\u26D4 \u53EA\u7ED9 id \u4E0D\u7ED9\u540D\u79F0\u4F1A\u88AB\u62D2\u7EDD\uFF08\u5BA2\u6237\u6D4F\u89C8\u6309\u94AE\u6309\u540D\u79F0\u843D\u503C\uFF0C\u53EA\u7ED9 id \u4F1A\u9759\u9ED8\u5B58\u6210\u7A7A\uFF09"
6940
- },
6941
- crm_member_count: { type: "number", description: "\u5E94\u5230\u5BA2\u6237\u6570\uFF1B\u4E0D\u4F20\u5219\u6309 crm_members \u6761\u6570\u81EA\u52A8\u7B97" },
6942
- crm_member_details: {
6943
- type: "array",
6944
- description: '\u53C2\u4F1A\u5BA2\u6237\u660E\u7EC6\uFF08\u5BBF\u4E3B\u8868\u5355\u91CC\u7684\u660E\u7EC6\u8868\uFF0C\u5217 \u59D3\u540D/\u6027\u522B/\u804C\u4F4D/\u624B\u673A\u53F7\u7801/\u5907\u6CE8\uFF09\uFF1A\u6BCF\u884C `{"xm":"\u5F20\u4E09","xb":"\u7537","zw":"\u7ECF\u7406","sjhm":"138...","bz":""}`\uFF0C\u4E5F\u63A5\u53D7\u4E2D\u6587\u952E\uFF08\u59D3\u540D/\u6027\u522B/\u804C\u4F4D/\u624B\u673A\u53F7\u7801/\u5907\u6CE8\uFF09\u3002\u5217\u5B57\u6BB5 id \u7531 CLI \u4ECE\u8868\u5355\u91CC\u6309\u5217\u540D\u53CD\u67E5\uFF0C\u4E0D\u7528\u4F20\u3002\u26A0\uFE0F \u8BE5\u660E\u7EC6\u8868\u5FC5\u987B\u5728\u53D1\u8D77\u8282\u70B9\u5E03\u5C40\u91CC\uFF08\u5426\u5219 CLI \u4F1A\u63D0\u793A"\u8868\u5355\u91CC\u6CA1\u6709\u53C2\u4F1A\u5BA2\u6237\u660E\u7EC6"\u5E76\u5FFD\u7565\u8FD9\u4E9B\u884C\uFF09\u26D4 \u9ED8\u8BA4\u4E0D\u751F\u6548\uFF1A\u5BA2\u6237\u8054\u7CFB\u4EBA\u7531 CLI \u6309 CRM \u5168\u91CF\u81EA\u52A8\u5E26\u5165\uFF0C\u8FD9\u91CC\u53EA\u5728 crm_detail_mode:"only" \u65F6\u624D\u7528\u6765"\u53EA\u5199\u8FD9\u51E0\u4F4D"',
6945
- items: { type: "object" }
6946
- },
6947
- crm_detail_mode: {
6948
- type: "string",
6949
- description: '\u660E\u7EC6\u884C\u53E3\u5F84\uFF1A\u4E0D\u4F20\uFF08\u9ED8\u8BA4\uFF09= \u6309 CRM \u628A\u8BE5\u5BA2\u6237**\u5168\u90E8**\u8054\u7CFB\u4EBA\u81EA\u52A8\u5199\u5165\u300C\u53C2\u4F1A\u5BA2\u6237\u660E\u7EC6\u300D\uFF08\u4E00\u4EBA\u4E00\u884C\uFF0C\u4E0D\u7528\u95EE\u7528\u6237\u9009\u54EA\u4F4D\uFF09\uFF1B\u4F20 "only" = \u53EA\u5199 crm_member_details \u91CC\u70B9\u540D\u7684\u8FD9\u51E0\u4F4D'
6950
- },
6951
- caller: { type: "string", description: "\u53EC\u96C6\u4EBA\uFF08\u5458\u5DE5 id \u6216\u59D3\u540D\uFF09\u3002\u7F3A\u7701 = \u5F53\u524D\u767B\u5F55\u4EBA\uFF0C\u4E0D\u7528\u4F20\uFF1B\u53EA\u6709\u6307\u5B9A\u522B\u4EBA\u5F53\u53EC\u96C6\u4EBA\u624D\u4F20" },
6952
- contacter: { type: "string", description: "\u8054\u7CFB\u4EBA\uFF08\u5458\u5DE5 id \u6216\u59D3\u540D\uFF09\u3002\u7F3A\u7701 = \u5F53\u524D\u767B\u5F55\u4EBA\uFF0C\u4E0D\u7528\u4F20\uFF1B\u53EA\u6709\u6307\u5B9A\u522B\u4EBA\u5F53\u8054\u7CFB\u4EBA\u624D\u4F20" },
6953
- mt_type: {
6954
- type: "string",
6955
- description: "\u4F1A\u8BAE\u7C7B\u578B\uFF1A\u53EF\u4F20\u7C7B\u578B\u540D\u79F0\u6216 id\uFF08\u5148\u7528 `meeting.eb.type.list` \u67E5\u6709\u54EA\u4E9B\uFF09\u3002**\u5F88\u591A\u79DF\u6237\u7684\u6D41\u7A0B\u8868\u5355\u628A\u300C\u4F1A\u8BAE\u7C7B\u578B\u300D\u8BBE\u4E3A\u5FC5\u586B**\uFF0C\u4E0D\u4F20\u4F1A\u88AB `workflow.createRequest` \u6253\u56DE\u7F3A\u5B57\u6BB5"
6956
- },
6957
- other_remark: { type: "string", description: "\u5907\u6CE8" },
6958
- workflowId: {
6959
- oneOf: [{ type: "string" }, { type: "array", items: { type: "string" } }],
6960
- description: "\u6307\u5B9A\u5EFA\u4F1A\u6D41\u7A0B id\uFF1A\u5355\u4E2A id\u3001id \u6570\u7EC4\u6216\u9017\u53F7\u5206\u9694\u90FD\u53EF\u4EE5\uFF0C\u4E5F\u63A5\u53D7\u300C\u6D41\u7A0B\u540D(123456)\u300D\u5199\u6CD5\u3002**\u4F20\u591A\u4E2A\u65F6 CLI \u540C\u6837\u4E0D\u4F1A\u66FF\u4F60\u9009**\u2014\u2014\u4F1A\u9010\u4E2A\u63A2\u6D4B\u53EF\u53D1\u8D77\u6027\uFF0C\u591A\u4E2A\u53EF\u7528\u5219\u8FD4\u56DE NEEDS_SELECTION \u8BA9\u7528\u6237\u6311\uFF1B\u4E0D\u4F20\u5219\u7528\u5E94\u7528\u8BBE\u7F6E mt_new_wf \u914D\u7F6E\u7684\u6D41\u7A0B\uFF08\u914D\u4E86\u591A\u4E2A\u65F6\u540C\u6837\u8BA9\u7528\u6237\u9009\uFF09"
6961
- },
6962
- autoRoom: { type: "boolean", description: "\u9ED8\u8BA4 false\uFF1A\u672A\u6307\u5B9A\u4F1A\u8BAE\u5BA4\u65F6\u8FD4\u56DE\u5019\u9009\u8BA9\u7528\u6237\u9009\uFF1B\u4F20 true \u624D\u81EA\u52A8\u91C7\u7528\u63A8\u8350" },
6963
- allowNoRoom: { type: "boolean", description: "\u786E\u5B9E\u4E0D\u9700\u8981\u4F1A\u8BAE\u5BA4\uFF08\u7EBF\u4E0A\u4F1A\u7B49\uFF09\u65F6\u4F20 true\uFF0C\u907F\u514D\u88AB\u201C\u8BF7\u9009\u62E9\u4F1A\u8BAE\u5BA4\u201D\u62E6\u4F4F" },
6964
- timeConfirmed: {
6965
- type: "boolean",
6966
- description: '\u26D4 **\u65F6\u95F4\u7684"\u7528\u6237\u5DF2\u786E\u8BA4"\u6807\u8BB0**\u3002\u53EA\u6709\u4EE5\u4E0B\u4E24\u79CD\u60C5\u51B5\u624D\u4F20 true\uFF1A\u2460 \u7528\u6237\u539F\u8BDD\u91CC\u660E\u786E\u7ED9\u51FA\u4E86\u65F6\u95F4\uFF08\u5982"\u660E\u5929 9 \u70B9\u5230 10 \u70B9"\uFF09\uFF1B\u2461 \u7528\u6237\u5728\u65F6\u6BB5\u9009\u9879\u91CC\u70B9\u9009\u540E\uFF0C\u628A `options[].value` **\u6574\u4F53**\u539F\u6837\u56DE\u4F20\uFF08value \u81EA\u5E26\u8BE5\u6807\u8BB0\uFF09\u3002\u4E0D\u4F20 = \u672A\u786E\u8BA4\uFF1A\u5373\u4F7F\u4F60\u4F20\u4E86 begin_datetime\uFF0CCLI \u4E5F**\u4E0D\u4F1A**\u5F53\u6210\u5DF2\u5B9A\uFF0C\u800C\u662F\u8FD4\u56DE\u65F6\u6BB5\u9009\u9879\u8BA9\u7528\u6237\u70B9\u9009\u3002\u26D4 \u7528\u6237\u53EA\u8BF4"\u660E\u5929/\u4E0A\u5348/\u4E0B\u5348"\u8FD9\u7C7B\u6A21\u7CCA\u8BF4\u6CD5\u65F6\uFF0C**\u5FC5\u987B\u4E0D\u4F20**\uFF0C\u8BA9 CLI \u7ED9\u5019\u9009'
6967
- },
6968
- roomConfirmed: {
6969
- type: "boolean",
6970
- description: '\u26D4 **\u4F1A\u8BAE\u5BA4\u7684"\u7528\u6237\u5DF2\u786E\u8BA4"\u6807\u8BB0**\u3002\u53EA\u6709\u4EE5\u4E0B\u4E24\u79CD\u60C5\u51B5\u624D\u4F20 true\uFF1A\u2460 \u7528\u6237\u539F\u8BDD\u660E\u786E\u6307\u5B9A\u4E86\u67D0\u95F4\u4F1A\u8BAE\u5BA4\uFF1B\u2461 \u7528\u6237\u5728\u623F\u95F4\u9009\u9879\u91CC\u70B9\u9009\u540E\u628A `options[].value` \u6574\u4F53\u539F\u6837\u56DE\u4F20\u3002\u4E0D\u4F20 = \u672A\u786E\u8BA4\uFF1A\u5373\u4F7F\u4F20\u4E86 address\uFF0CCLI \u4E5F\u4F1A\u628A"\u4F60\u6307\u5B9A\u7684\u8FD9\u95F4"\u548C\u63A8\u8350\u5019\u9009\u4E00\u8D77\u5217\u51FA\u6765\u8BA9\u7528\u6237\u70B9\u9009\u3002\u26D4 \u4E0D\u8981\u81EA\u5DF1\u4ECE room.list / room.recommend \u91CC\u6311\u4E00\u95F4\u585E\u8FDB address \u2014\u2014 \u90A3\u662F\u66FF\u7528\u6237\u62CD\u677F'
6971
- },
6972
- extraFields: {
6973
- type: "object",
6974
- description: '\u6309**\u6D41\u7A0B\u8868\u5355\u91CC\u7684\u5B57\u6BB5\u540D**\u586B\u989D\u5916\u5B57\u6BB5\uFF0C\u5F62\u5982 {"\u53C2\u4F1A\u5BA2\u6237": "xx\u516C\u53F8", "\u8054\u7CFB\u65B9\u5F0F": "138xxxx"}\uFF1A\u7528\u4E8E\u79DF\u6237\u5728\u6D41\u7A0B\u8868\u5355\u4E0A\u81EA\u5EFA\u3001CLI \u5185\u7F6E\u522B\u540D\u91CC\u6CA1\u6709\u7684\u5B57\u6BB5\u3002\u952E\u5FC5\u987B\u4E0E\u8BE5\u6D41\u7A0B\u8868\u5355\u7684\u5B57\u6BB5\u540D\u5B8C\u5168\u4E00\u81F4\uFF08prepare \u7684 warnings \u4F1A\u5217\u51FA\u8868\u5355\u73B0\u6709\u5168\u90E8\u5B57\u6BB5\u540D\uFF09\uFF1B\u5339\u914D\u4E0D\u5230\u7684\u4F1A\u8FDB unmapped \u63D0\u793A\uFF0C\u4E0D\u4F1A\u778E\u586B\u3002\u26D4 **\u4F1A\u8BAE\u5730\u70B9 / \u53C2\u4F1A\u4EBA\u5458 / \u53EC\u96C6\u4EBA / \u8054\u7CFB\u4EBA / \u4F1A\u8BAE\u7C7B\u578B \u4E0D\u8981\u585E\u8FD9\u91CC** \u2014\u2014 \u5B83\u4EEC\u6709\u4E13\u7528\u5165\u53C2\uFF08address / hrm_members / caller / contacter / mt_type\uFF09\uFF0CCLI \u4F1A\u628A\u503C\u8865\u6210\u6D4F\u89C8\u6309\u94AE\u8981\u7684 `{id,name}` \u5BF9\u8C61\uFF1B\u585E\u8FDB extraFields \u4F1A\u6309\u7EAF\u6587\u672C\u63D0\u4EA4\uFF0C\u670D\u52A1\u7AEF\u4F1A\u6253\u56DE\u300C\u8BF7\u6309\u540D\u79F0\u9009\u62E9\u300D'
6975
- },
6976
- dateFrom: {
6977
- type: "string",
6978
- description: "\u6CA1\u7ED9\u5177\u4F53\u65F6\u95F4\u65F6\u6309\u54EA\u4E00\u5929\u63A8\u8350\u65F6\u6BB5\uFF08yyyy-MM-dd\uFF1B\u4E0D\u4F20\u9ED8\u8BA4\u660E\u5929\uFF09"
6979
- },
6980
- durationMinutes: {
6981
- type: "number",
6982
- description: "\u4F1A\u8BAE\u65F6\u957F\uFF08\u5206\u949F\uFF0C\u9ED8\u8BA4 60\uFF09\uFF1A\u53EA\u7ED9\u4E86\u5F00\u59CB\u65F6\u95F4\u65F6\u7528\u6765\u7B97\u7ED3\u675F\u65F6\u95F4\uFF1B\u63A8\u8350\u65F6\u6BB5\u65F6\u4E5F\u6309\u8FD9\u4E2A\u65F6\u957F\u627E"
6983
- },
6984
- workStartHour: { type: "number", description: "\u63A8\u8350\u65F6\u6BB5\u7684\u6700\u65E9\u5C0F\u65F6\uFF08\u9ED8\u8BA4 9\uFF09" },
6985
- workEndHour: { type: "number", description: "\u63A8\u8350\u65F6\u6BB5\u7684\u6700\u665A\u5C0F\u65F6\uFF08\u9ED8\u8BA4 18\uFF09" },
6986
- fieldValues: {
6987
- type: "object",
6988
- additionalProperties: true,
6989
- description: '\u6309**\u8868\u5355\u5B57\u6BB5 datakey\uFF08fieldId\uFF09**\u76F4\u63A5\u7ED9\u503C\uFF0C\u5F62\u5982 {"1325677252711735881": "\u7814\u8BA8\u4F1A"}\u3002\u4F18\u5148\u7EA7\u6700\u9AD8\uFF08\u540C\u540D\u5B57\u6BB5\u4EE5\u5B83\u4E3A\u51C6\uFF09\uFF1A\u9002\u5408\u5B57\u6BB5\u540D\u5E26\u63D0\u793A\u8BED\u3001\u6216\u79DF\u6237\u81EA\u5EFA\u5B57\u6BB5\u8FD9\u7C7B\u6309\u4E2D\u6587\u540D\u731C\u4E0D\u5230\u7684\u60C5\u51B5\u3002datakey \u4ECE prepare \u8FD4\u56DE\u7684 preview.mapped\uFF08\u5F62\u5982 "\u4F1A\u8BAE\u540D\u79F0(1325677252711735881)"\uFF09\u91CC\u53D6\uFF1B\u6BCF\u4E2A\u6D41\u7A0B\u7684 datakey \u56FA\u5B9A\u4E0D\u53D8\uFF0C\u53EF\u957F\u671F\u786C\u7F16\u7801\u3002'
6990
- },
6991
- flowChoice: {
6992
- type: "string",
6993
- enum: ["auto", "ask"],
6994
- description: "\u591A\u4E2A\u5EFA\u4F1A\u6D41\u7A0B**\u90FD\u6709\u53D1\u8D77\u6743\u9650**\u65F6\u600E\u4E48\u529E\uFF1A**\u9ED8\u8BA4\uFF08\u4E0D\u4F20 / ask\uFF09= \u8FD4\u56DE\u9009\u9879\u8BA9\u7528\u6237\u6311**\uFF1Bauto = \u81EA\u52A8\u53D6\u4F18\u5148\u7EA7\u6700\u9AD8\u7684\u90A3\u4E2A\uFF08\u7701\u4E00\u8F6E\uFF0C\u4F46\u9009\u9519\u6D41\u7A0B\u4F1A\u6F0F\u5B57\u6BB5\uFF0C\u614E\u7528\uFF09\u3002\u53EA\u6709 1 \u4E2A\u6709\u6743\u9650\u65F6\u4E0D\u53D7\u6B64\u53C2\u6570\u5F71\u54CD\uFF0CCLI \u76F4\u63A5\u53D1\u8D77"
6995
- }
6996
- },
6997
- { required: ["mt_name"] }
6998
- ),
6999
- handler: async (args, env) => {
7000
- let workflowId = "";
7001
- let flowPickNote = null;
7002
- const decisions = {};
7003
- const enrich = args.enrich !== false;
7004
- const beginText = String(args.begin_datetime ?? "").trim();
7005
- let endText = String(args.end_datetime ?? "").trim();
7006
- const rawMembers = String(args.hrm_members ?? "").split(/[,;,;\s]+/).map((item) => item.trim()).filter((item) => item !== "");
7007
- const nameLike = rawMembers.filter((item) => !/^\d+$/.test(item));
7008
- const nameToId = nameLike.length > 0 ? await import("./schedule-UASAVDVD.js").then((m) => m.resolveMemberIdsByName(env, nameLike)).catch(() => /* @__PURE__ */ new Map()) : /* @__PURE__ */ new Map();
7009
- const memberIds = rawMembers.map((item) => nameToId.get(item) ?? item);
7010
- const timeConfirmed = args.timeConfirmed === true;
7011
- const callerWorkflowId = String(args.workflowId ?? "").trim();
7012
- const earlyWorkflowNote = callerWorkflowId === "" ? "" : `\u26D4 \u4F60\u4F20\u4E86 workflowId=${callerWorkflowId}\uFF0C\u4F46**\u6D41\u7A0B\u8FD8\u6CA1\u5230\u786E\u8BA4\u6B65\u9AA4**\uFF08\u987A\u5E8F\u662F \u540D\u79F0\u2192\u65F6\u95F4\u2192\u53C2\u4F1A\u4EBA\u2192\u5730\u70B9\u2192\u6D41\u7A0B\uFF09\u3002\u672C\u6B21\u53EA\u5904\u7406\u65F6\u95F4/\u5730\u70B9\uFF1B\u26D4 \u4E0D\u8981\u5728\u56DE\u590D\u91CC\u8BF4"\u6309 X \u6D41\u7A0B\u53D1\u8D77"\u2014\u2014\u56DB\u8981\u7D20\u5B9A\u5B8C\u540E CLI \u4F1A\u8FD4\u56DE\u6D41\u7A0B\u9009\u9879\u8BA9\u7528\u6237\u70B9\u3002`;
7013
- const beginHasTime = /^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}/.test(beginText);
7014
- const endHasTime = /^\d{4}-\d{2}-\d{2}[ T]\d{2}:\d{2}/.test(endText);
7015
- if (beginHasTime && !endHasTime) {
7016
- const duration = Number(args.durationMinutes) > 0 ? Math.round(Number(args.durationMinutes)) : 60;
7017
- const startMs = Date.parse(beginText.slice(0, 16).replace(" ", "T"));
7018
- if (Number.isFinite(startMs)) endText = formatMinute(new Date(startMs + duration * 6e4));
7019
- }
7020
- if (!beginHasTime || !timeConfirmed) {
7021
- const day2 = /^\d{4}-\d{2}-\d{2}/.test(beginText) ? beginText.slice(0, 10) : String(args.dateFrom ?? "").trim().slice(0, 10) || tomorrowIso();
7022
- const duration = Number(args.durationMinutes) > 0 ? Math.round(Number(args.durationMinutes)) : 60;
7023
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
7024
- const suggested = await getMeetingOperation2("meeting.eb.meeting.create.suggest").handler(
7025
- {
7026
- dateFrom: day2,
7027
- durationMinutes: duration,
7028
- hrm_members: memberIds.join(","),
7029
- maxSlots: 3,
7030
- topN: 3,
7031
- ...Number(args.total_member) > 0 ? { memberCount: Number(args.total_member) } : {},
7032
- ...args.workStartHour !== void 0 ? { workStartHour: Number(args.workStartHour) } : {},
7033
- ...args.workEndHour !== void 0 ? { workEndHour: Number(args.workEndHour) } : {}
7034
- },
7035
- env
7036
- ).catch((error) => ({ data: { slots: [] }, slotError: String(error?.message ?? error).slice(0, 160) }));
7037
- const slotOptions2 = suggested?.data?.slots ?? [];
7038
- const slotWarnings = [
7039
- ...suggested?.warnings ?? [],
7040
- ...suggested?.slotError ? [`\u65F6\u6BB5\u63A8\u8350\u672A\u8DD1\u6210\u529F\uFF1A${suggested.slotError}`] : [],
7041
- ...memberIds.length === 0 ? ['\u26A0\uFE0F \u6CA1\u6709\u53C2\u4F1A\u4EBA\u5458\uFF0C\u65E0\u6CD5\u6838\u9A8C"\u4EBA\u662F\u5426\u7A7A\u95F2" \u2014\u2014 \u4E0B\u9762\u53EA\u662F**\u4F1A\u8BAE\u5BA4\u6709\u7A7A**\u7684\u65F6\u6BB5\uFF0C\u8BF7\u5982\u5B9E\u8BF4\u660E\u3002'] : []
7042
- ];
7043
- return meetingSuccess("meeting.eb.meeting.create.flow.prepare", {
7044
- status: "NEEDS_SELECTION",
7045
- selectionType: "slot",
7046
- ui: { component: "choice", multiple: false, recommendedKey: "T1" },
7047
- message: slotOptions2.length > 0 ? `${beginHasTime ? `\u4F60\u4F20\u5165\u7684\u65F6\u95F4 ${beginText}~${endText} **\u672A\u7ECF\u7528\u6237\u786E\u8BA4**\uFF08\u6CA1\u5E26 timeConfirmed\uFF09` : "\u6CA1\u6709\u7ED9\u51FA\u5177\u4F53\u65F6\u95F4"}\uFF0C\u5DF2\u6309\u53C2\u4F1A\u4EBA\u4E0E\u4F1A\u8BAE\u5BA4\u7A7A\u95F2\u60C5\u51B5\u63A8\u8350 ${slotOptions2.length} \u4E2A\u65F6\u6BB5\uFF08${day2}\uFF0C\u65F6\u957F ${duration} \u5206\u949F\uFF09\u2014\u2014 \u26D4 \u5FC5\u987B\u8BA9\u7528\u6237\u5728\u9009\u9879\u91CC\u70B9\u9009\uFF0C**\u4E0D\u8981**\u628A\u4EFB\u4F55\u4E00\u4E2A\u5019\u9009\u5199\u6210"\u5DF2\u5B9A"\u6216\u653E\u8FDB\u786E\u8BA4\u6458\u8981` : `${beginHasTime ? `\u4F60\u4F20\u5165\u7684\u65F6\u95F4 ${beginText}~${endText} \u672A\u7ECF\u7528\u6237\u786E\u8BA4\uFF08\u6CA1\u5E26 timeConfirmed\uFF09` : "\u6CA1\u6709\u7ED9\u51FA\u5177\u4F53\u65F6\u95F4"}\uFF0C\u4E14 ${day2} \u6CA1\u80FD\u627E\u5230\u300C\u53C2\u4F1A\u4EBA\u7A7A\u95F2 + \u4F1A\u8BAE\u5BA4\u7A7A\u95F2\u300D\u7684\u65F6\u6BB5\uFF0C\u8BF7\u8BA9\u7528\u6237\u6362\u4E2A\u65E5\u671F\u6216\u6307\u5B9A\u65F6\u95F4`,
7048
- options: slotOptions2.map((slot, index) => ({
7049
- key: `T${index + 1}`,
7050
- label: String(slot.label ?? ""),
7051
- // ⛔ 时间不在 slot 顶层,而在 slot.value 里(suggest 的返回结构)—— 取错会让调用方
7052
- // 拿不到 begin/end,只能再问用户一次时间(2026-10-30 冒烟实测踩到)。
7053
- // `timeConfirmed: true` 在这里是**关键**:用户点选后 value 原样回传,下一轮才被认作"已确认";
7054
- // agent 自己编的时间不带这个标记,就永远停在选项这一步。
7055
- value: {
7056
- begin_datetime: String(slot.value?.begin ?? slot.begin ?? "").trim(),
7057
- end_datetime: String(slot.value?.end ?? slot.end ?? "").trim(),
7058
- address: slot.value?.address ?? null,
7059
- timeConfirmed: true
7060
- },
7061
- reason: String(slot.reason ?? ""),
7062
- rooms: slot.rooms ?? []
7063
- })),
7064
- day: day2,
7065
- durationMinutes: duration,
7066
- memberIds,
7067
- // ⛔ 这里**不能**出现 workflowId:流程确认在四要素之后(2026-10-30 顺序调整)。
7068
- // 返回 workflowId 会让 agent 误以为"流程已定",于是在回复里先讲流程、再问时间。
7069
- workflowPending: true,
7070
- hint: "\u9009\u5B9A\u540E\u628A value **\u6574\u4F53**\u539F\u6837\u5E26\u56DE\u91CD\u65B0\u8C03\u7528\uFF08\u542B timeConfirmed: true\uFF09\uFF1Baddress \u5DF2\u81EA\u52A8\u5E26\u4E0A\u8BE5\u65F6\u6BB5\u53EF\u7528\u7684\u4F1A\u8BAE\u5BA4\uFF0C\u4ECD\u9700\u8BA9\u7528\u6237\u5355\u72EC\u786E\u8BA4\u6216\u7528 roomConfirmed: true"
7071
- }, {
7072
- warnings: [
7073
- `${beginHasTime ? `\u672C\u6B21**\u6CA1\u6709\u63D0\u4EA4**\uFF1A\u4F60\u4F20\u5165\u7684\u65F6\u95F4 ${beginText}~${endText} \u6CA1\u6709\u7528\u6237\u786E\u8BA4\u6807\u8BB0\uFF08timeConfirmed\uFF09\uFF0C\u5DF2\u6539\u4E3A\u7ED9\u5019\u9009\u3002` : "\u672C\u6B21**\u6CA1\u6709\u63D0\u4EA4**\uFF1A\u65F6\u95F4\u672A\u786E\u5B9A\uFF08\u7F3A begin_datetime\uFF09\u3002"}\u5DF2\u6309 ${day2} \u63A8\u8350\u65F6\u6BB5\uFF0C\u8BF7\u7528\u9009\u9879\u8BA9\u7528\u6237\u6311\u4E00\u4E2A\u3002`,
7074
- ...slotWarnings,
7075
- ...earlyWorkflowNote ? [earlyWorkflowNote] : []
7076
- ]
7077
- });
7078
- }
7079
- let addressInput = args.address;
7080
- const hadAddressInput = String(args.address ?? "").trim() !== "";
7081
- const day = beginText.slice(0, 10);
7082
- const durationMinutes = beginText && endText ? Math.max(15, Math.round((Date.parse(endText.replace(" ", "T")) - Date.parse(beginText.replace(" ", "T"))) / 6e4) || 60) : 60;
7083
- const timings = {};
7084
- const startedAt = Date.now();
7085
- const enrichFailures = [];
7086
- const noteFailure = (label) => (error) => {
7087
- enrichFailures.push(`${label}\u672A\u5B8C\u6210\uFF1A${String(error?.message ?? error).slice(0, 120)}`);
7088
- return null;
7089
- };
7090
- const needSelfPerson = String(args.caller ?? "").trim() === "" || String(args.contacter ?? "").trim() === "";
7091
- const autoPerson = applySelfPersonDefaults(
7092
- args,
7093
- needSelfPerson ? await resolveSelfPerson(env) : null
7094
- );
7095
- const autoFilledPerson = autoPerson.filled;
7096
- const selfPersonWarning = autoPerson.warning;
7097
- const declaredTotal = Number(args.total_member) > 0 ? Number(args.total_member) : null;
7098
- const callerToken = String(args.caller ?? "").trim();
7099
- const callerInMembers = callerToken !== "" && (rawMembers.includes(callerToken) || memberIds.includes(callerToken));
7100
- const roomMemberCount = declaredTotal ?? (memberIds.length > 0 ? memberIds.length + (callerInMembers ? 0 : 1) : void 0);
7101
- const roomTask = enrich && beginText && endText ? recommendRooms(env, {
7102
- beginDatetime: beginText,
7103
- endDatetime: endText,
7104
- ...roomMemberCount ? { memberCount: roomMemberCount } : {},
7105
- // 建会是"要下单"的场景:宁可多一次请求也必须拿最新台账(24h 缓存会让刚导入的会议室看不到)。
7106
- refreshRooms: true,
7107
- topN: 3
7108
- }).catch(noteFailure("\u4F1A\u8BAE\u5BA4\u63A8\u8350")) : Promise.resolve(null);
7109
- const addressId = String(addressInput ?? "").trim();
7110
- const roomConfirmed = args.roomConfirmed === true;
7111
- const roomConflictTask = enrich && beginText && endText && addressId !== "" ? (async () => {
7112
- const room = await resolveAddressRoom(env, addressId);
7113
- if (!room) return { unresolved: true, input: addressId };
7114
- if (!room.id || room.lookupFailed || room.status !== "0") return { room };
7115
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
7116
- const result = await getMeetingOperation2("meeting.eb.conflict.room").handler(
7117
- { beginDatetime: beginText, endDatetime: endText, address: room.id },
7118
- env
7119
- );
7120
- return { room, ...result?.data ?? {} };
7121
- })().catch(noteFailure("\u4F1A\u8BAE\u5BA4**\u5360\u7528**\u68C0\u6D4B")) : Promise.resolve(null);
7122
- const conflictTask = enrich && beginText && endText && memberIds.length > 0 ? (async () => {
7123
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
7124
- return getMeetingOperation2("meeting.eb.conflict.member").handler(
7125
- { beginDatetime: beginText, endDatetime: endText, hrmMembers: memberIds.join(",") },
7126
- env
7127
- );
7128
- })().catch(noteFailure("\u53C2\u4F1A\u4EBA**\u4F1A\u8BAE\u5360\u7528**\u68C0\u6D4B")) : Promise.resolve(null);
7129
- const availabilityTask = enrich && beginText && endText && memberIds.length > 0 ? findCommonFreeSlots(env, {
7130
- rangeStart: `${day} 00:00`,
7131
- rangeEnd: `${day} 23:59`,
7132
- durationMinutes,
7133
- members: memberIds,
7134
- maxSlots: 3,
7135
- maxDays: 1,
7136
- includeSchedule: true
7137
- }).catch(noteFailure("\u53C2\u4F1A\u4EBA**\u65E5\u7A0B\u7A7A\u95F2**\u68C0\u6D4B")) : Promise.resolve(null);
7138
- const [roomRec, memberConflict, free, roomConflict] = await Promise.all([
7139
- roomTask,
7140
- conflictTask,
7141
- availabilityTask,
7142
- roomConflictTask
7143
- ]);
7144
- timings.parallelMs = Date.now() - startedAt;
7145
- const memberConflicts = memberConflict?.data?.conflicts ?? [];
7146
- if (memberConflicts.length > 0) decisions.memberConflicts = memberConflicts;
7147
- const freeSlots = free?.slots ?? [];
7148
- if (free) {
7149
- decisions.scheduleItems = free.scheduleItems;
7150
- decisions.availabilityCost = free.cost;
7151
- if (freeSlots.length > 0) {
7152
- decisions.suggestedSlots = freeSlots;
7153
- decisions.slotOptions = freeSlots.map((slot, index) => ({
7154
- key: `T${index + 1}`,
7155
- label: `${slot.begin.slice(11)}~${slot.end.slice(11)}\uFF08${day}\uFF09 \xB7 \u5168\u90E8\u53C2\u4F1A\u4EBA\u7A7A\u95F2`,
7156
- value: { begin: slot.begin, end: slot.end },
7157
- reason: "\u8BE5\u65F6\u6BB5\u6240\u6709\u53C2\u4F1A\u4EBA\u90FD\u6CA1\u6709\u4F1A\u8BAE\u4E0E\u65E5\u7A0B\u5360\u7528\uFF08\u5DF2\u540C\u65F6\u6838\u5BF9\u4F1A\u8BAE\u56DE\u6267\u4E0E\u65E5\u7A0B\uFF09"
7158
- }));
7159
- } else if (free.blockingSummary) {
7160
- decisions.dayBlocked = { day, summary: free.blockingSummary };
7161
- }
7162
- }
7163
- const conflictBrief = {
7164
- memberConflicts,
7165
- suggestedSlots: freeSlots,
7166
- ...enrichFailures.length > 0 ? { enrichFailures } : {}
7167
- };
7168
- const failureWarnings = enrichFailures.map(
7169
- (failure) => `\u26A0\uFE0F ${failure} \u2014\u2014 **\u8FD9\u4E0D\u4EE3\u8868\u6CA1\u6709\u51B2\u7A81**\uFF0C\u8BF7\u5982\u5B9E\u544A\u77E5\u7528\u6237\u8BE5\u9879\u672A\u6838\u9A8C\uFF0C\u4E0D\u8981\u58F0\u79F0"\u65F6\u95F4\u5DF2\u786E\u8BA4\u7A7A\u95F2"`
7170
- );
7171
- const roomOptions = (roomRec?.candidates ?? []).map((candidate, index) => ({
7172
- key: `R${index + 1}`,
7173
- label: `${candidate.name}${candidate.capacity.max > 0 ? `\uFF08\u53EF\u5BB9 ${candidate.capacity.max} \u4EBA\uFF09` : ""}${index === 0 ? " \xB7 \u63A8\u8350" : ""}`,
7174
- // roomConfirmed: true = 用户点选该选项即代表"确认用这间",原样回传后下一轮才被认。
7175
- value: { id: candidate.id, name: candidate.name, roomConfirmed: true },
7176
- reason: candidate.reasons.join("\uFF1B")
7177
- }));
7178
- const roomConflictData = roomConflict;
7179
- const resolvedAddress = roomConflictData?.room ?? null;
7180
- const resolvedAddressId = resolvedAddress?.id || addressId;
7181
- const addressDisplay = resolvedAddress?.name || addressId;
7182
- if (roomConflictData?.unresolved === true) {
7183
- decisions.roomNotFound = { input: addressId, candidates: roomOptions.length };
7184
- if (roomOptions.length > 0) decisions.roomOptions = roomOptions;
7185
- return meetingSuccess("meeting.eb.meeting.create.flow.prepare", {
7186
- status: "NEEDS_SELECTION",
7187
- selectionType: "room",
7188
- ui: { component: "choice", multiple: false, recommendedKey: "R1" },
7189
- message: `\u6CA1\u627E\u5230\u540D\u4E3A\u300C${addressId}\u300D\u7684\u4F1A\u8BAE\u5BA4\uFF08\u4F1A\u8BAE\u5BA4\u53F0\u8D26\u91CC\u6CA1\u6709\u8FD9\u4E2A\u540D\u5B57\uFF09\uFF0C\u672C\u6B21**\u6CA1\u6709\u63D0\u4EA4**\u3002` + (roomOptions.length > 0 ? `\u8BF7\u4ECE\u4E0B\u9762 ${roomOptions.length} \u4E2A\u5728\u8BE5\u65F6\u6BB5\u7A7A\u95F2\u7684\u4F1A\u8BAE\u5BA4\u91CC\u9009\u4E00\u95F4\uFF0C\u6216\u6838\u5BF9\u4E00\u4E0B\u4F1A\u8BAE\u5BA4\u540D\u79F0` : "\u8BE5\u65F6\u6BB5\u4E5F\u6CA1\u6709\u53EF\u7528\u7684\u7A7A\u95F2\u4F1A\u8BAE\u5BA4\uFF0C\u8BF7\u6539\u4F1A\u8BAE\u65F6\u95F4\u6216\u6539\u7EBF\u4E0A\u4F1A\u8BAE\uFF08allowNoRoom: true\uFF09"),
7190
- workflowPending: true,
7191
- options: roomOptions,
7192
- recommended: roomOptions[0]?.value ?? null,
7193
- roomNotFound: decisions.roomNotFound,
7194
- hint: "\u9009\u5B9A\u540E\u628A value **\u6574\u4F53**\u539F\u6837\u5E26\u56DE\uFF08\u542B roomConfirmed: true\uFF09\uFF1B\u6838\u5BF9\u540D\u79F0\u53EF\u7528 `meeting.eb.room.list` \u770B\u5168\u91CF\u6E05\u5355"
7195
- }, {
7196
- warnings: [
7197
- `\u4F1A\u8BAE\u5BA4\u300C${addressId}\u300D\u5728\u53F0\u8D26\u91CC\u4E0D\u5B58\u5728\uFF0C\u5DF2\u62E6\u4E0B\u672A\u63D0\u4EA4\u3002`,
7198
- '\u26D4 \u4E0D\u8981\u628A\u5B83\u5F53\u6210"\u7528\u6237\u6307\u5B9A\u7684\u623F\u95F4"\u5199\u8FDB\u786E\u8BA4\u6458\u8981 \u2014\u2014 \u8FD9\u95F4\u623F\u6839\u672C\u6CA1\u6709\u88AB\u89E3\u6790\u51FA\u6765\u3002'
7199
- ]
7200
- });
7201
- }
7202
- if (resolvedAddress && resolvedAddress.status === "1") {
7203
- decisions.roomSealed = { id: resolvedAddress.id, name: resolvedAddress.name };
7204
- if (roomOptions.length > 0) decisions.roomOptions = roomOptions;
7205
- return meetingSuccess("meeting.eb.meeting.create.flow.prepare", {
7206
- status: "NEEDS_SELECTION",
7207
- selectionType: "room",
7208
- ui: { component: "choice", multiple: false, recommendedKey: "R1" },
7209
- message: `\u4F1A\u8BAE\u5BA4\u300C${resolvedAddress.name}\u300D\u5F53\u524D\u662F**\u5C01\u5B58**\u72B6\u6001\uFF08\u4E0D\u53EF\u9884\u7EA6\uFF09\uFF0C\u672C\u6B21**\u6CA1\u6709\u63D0\u4EA4**\u3002` + (roomOptions.length > 0 ? "\u8BF7\u6539\u7528\u4E0B\u9762\u7A7A\u95F2\u7684\u4F1A\u8BAE\u5BA4" : "\u8BE5\u65F6\u6BB5\u6CA1\u6709\u5176\u5B83\u53EF\u7528\u4F1A\u8BAE\u5BA4\uFF0C\u8BF7\u6539\u4F1A\u8BAE\u65F6\u95F4"),
7210
- workflowPending: true,
7211
- options: roomOptions,
7212
- recommended: roomOptions[0]?.value ?? null,
7213
- roomSealed: decisions.roomSealed
7214
- }, {
7215
- warnings: [`\u4F1A\u8BAE\u5BA4\u300C${resolvedAddress.name}\u300D\uFF08${resolvedAddress.id}\uFF09\u5DF2\u5C01\u5B58\uFF0C\u4E0D\u53EF\u9884\u7EA6\uFF0C\u5DF2\u62E6\u4E0B\u672A\u63D0\u4EA4\u3002`]
7216
- });
7217
- }
7218
- if (addressInput && roomConfirmed && roomConflictData?.hasConflict === true) {
7219
- const busy = Array.isArray(roomConflictData.conflicts) ? roomConflictData.conflicts : [];
7220
- decisions.roomConflict = {
7221
- address: resolvedAddressId,
7222
- addressName: addressDisplay,
7223
- hasConflict: true,
7224
- conflicts: busy,
7225
- verdict: roomConflictData.verdict ?? "conflict"
7226
- };
7227
- if (roomOptions.length > 0) decisions.roomOptions = roomOptions;
7228
- return meetingSuccess("meeting.eb.meeting.create.flow.prepare", {
7229
- status: "NEEDS_SELECTION",
7230
- selectionType: "room_conflict",
7231
- ui: { component: "choice", multiple: false, recommendedKey: "R1" },
7232
- message: `\u4F60\u6307\u5B9A\u7684\u4F1A\u8BAE\u5BA4\u300C${addressDisplay}\u300D\u5728 ${beginText}~${endText} \u5DF2\u88AB\u5360\u7528\uFF08${busy.length} \u6761\u5360\u7528\u8BB0\u5F55\uFF09\uFF0C\u672C\u6B21**\u6CA1\u6709\u63D0\u4EA4**\u3002\u8BF7\u6539\u7528\u4E0B\u9762\u7A7A\u95F2\u7684\u4F1A\u8BAE\u5BA4\uFF0C\u6216\u8C03\u6574\u4F1A\u8BAE\u65F6\u95F4`,
7233
- workflowPending: true,
7234
- options: roomOptions,
7235
- recommended: roomOptions[0]?.value ?? null,
7236
- conflicts: busy,
7237
- roomConflict: decisions.roomConflict,
7238
- hint: "\u9009\u5B9A\u540E\u628A value.id \u4F5C\u4E3A address \u91CD\u65B0\u8C03\u7528\uFF1B\u8981\u6539\u65F6\u95F4\u5C31\u540C\u65F6\u4F20\u65B0\u7684 begin_datetime/end_datetime"
7239
- }, {
7240
- warnings: [
7241
- `\u4F1A\u8BAE\u5BA4\u300C${addressDisplay}\u300D\uFF08${resolvedAddressId}\uFF09\u5728\u8BE5\u65F6\u6BB5\u5DF2\u6709 ${busy.length} \u6761\u5360\u7528\uFF0C\u5DF2\u62E6\u4E0B\u672A\u63D0\u4EA4\u3002`,
7242
- roomOptions.length > 0 ? `\u5DF2\u6309\u4EBA\u6570/\u5E38\u7528/\u7A7A\u95F2\u7ED9\u51FA ${roomOptions.length} \u4E2A\u66FF\u4EE3\u4F1A\u8BAE\u5BA4\uFF08R1 \u4E3A\u9996\u9009\uFF09\u3002` : "\u8BE5\u65F6\u6BB5\u6CA1\u6709\u53EF\u66FF\u4EE3\u7684\u7A7A\u95F2\u4F1A\u8BAE\u5BA4\uFF0C\u5EFA\u8BAE\u8C03\u6574\u4F1A\u8BAE\u65F6\u95F4\u6216\u6539\u7EBF\u4E0A\u4F1A\u8BAE\uFF08allowNoRoom: true\uFF09\u3002"
7243
- ]
7244
- });
7245
- }
7246
- if (roomRec) {
7247
- decisions.roomOptions = roomOptions;
7248
- decisions.autoRoom = {
7249
- picked: roomRec.best ? { id: roomRec.best.id, name: roomRec.best.name, score: roomRec.best.score, reasons: roomRec.best.reasons } : null,
7250
- candidates: roomRec.candidates,
7251
- meta: roomRec.meta
7252
- };
7253
- const autoRoom = args.autoRoom === true;
7254
- const needRoomPick = !addressInput || !roomConfirmed;
7255
- let pickOptions = roomOptions;
7256
- if (addressInput && !roomConfirmed) {
7257
- const hit = roomOptions.find((item) => String(item.value?.id) === resolvedAddressId);
7258
- const specified = hit ? { ...hit, label: `${hit.label}\uFF08\u4F60\u6307\u5B9A\u7684\uFF0C\u5F85\u786E\u8BA4\uFF09`, value: { ...hit.value, roomConfirmed: true } } : {
7259
- key: "R0",
7260
- label: `${addressDisplay}\uFF08\u4F60\u6307\u5B9A\u7684\uFF0C\u5F85\u786E\u8BA4\uFF09`,
7261
- value: { ...resolvedAddressId ? { id: resolvedAddressId } : {}, name: addressDisplay, roomConfirmed: true },
7262
- reason: "\u4F60\u4F20\u5165\u7684\u4F1A\u8BAE\u5BA4\uFF0C\u672A\u63D0\u4EA4\u3001\u672A\u786E\u8BA4"
7263
- };
7264
- pickOptions = [specified, ...roomOptions.filter((item) => String(item.value?.id) !== resolvedAddressId)].map((item, index) => ({ ...item, key: `R${index + 1}` }));
7265
- }
7266
- if (needRoomPick && !autoRoom && pickOptions.length > 0 && args.allowNoRoom !== true) {
7267
- return meetingSuccess("meeting.eb.meeting.create.flow.prepare", {
7268
- status: "NEEDS_SELECTION",
7269
- selectionType: "room",
7270
- ui: { component: "choice", multiple: false, recommendedKey: "R1" },
7271
- message: addressInput ? `\u4F60\u4F20\u5165\u7684\u4F1A\u8BAE\u5BA4\u300C${addressDisplay}\u300D**\u672A\u7ECF\u7528\u6237\u786E\u8BA4**\uFF08\u6CA1\u5E26 roomConfirmed\uFF09\uFF0C\u5DF2\u628A\u5B83\u548C\u5176\u5B83\u5019\u9009\u4E00\u8D77\u5217\u51FA\u6765 \u2014\u2014 \u26D4 \u5FC5\u987B\u8BA9\u7528\u6237\u5728\u9009\u9879\u91CC\u70B9\u9009\uFF0C\u4E0D\u8981\u76F4\u63A5\u63D0\u4EA4` : `\u672A\u6307\u5B9A\u4F1A\u8BAE\u5BA4\uFF0C\u8BF7\u4ECE ${pickOptions.length} \u4E2A\u5019\u9009\u91CC\u9009\u62E9\uFF08\u5DF2\u6309\u4EBA\u6570/\u5E38\u7528/\u65F6\u6BB5\u5360\u7528\u6392\u5E8F\uFF09`,
7272
- // 固化自动选的流程要带出来:调用方下一轮带 address 重调时不用再猜用的是哪条流程。
7273
- workflowPending: true,
7274
- options: pickOptions,
7275
- recommended: pickOptions[0]?.value ?? null,
7276
- hint: "\u9009\u5B9A\u540E\u628A value **\u6574\u4F53**\u539F\u6837\u5E26\u56DE\uFF08\u542B roomConfirmed: true\uFF09\uFF1B\u786E\u5B9E\u4E0D\u9700\u8981\u4F1A\u8BAE\u5BA4\u8BF7\u4F20 allowNoRoom: true",
7277
- ...conflictBrief
7278
- }, {
7279
- warnings: [
7280
- addressInput ? `\u4F1A\u8BAE\u5BA4\u300C${addressDisplay}\u300D\u672A\u7ECF\u7528\u6237\u786E\u8BA4\uFF1A\u672C\u6B21**\u6CA1\u6709**\u63D0\u4EA4\u3002` : "\u672A\u6307\u5B9A\u4F1A\u8BAE\u5BA4\uFF1A\u672C\u6B21**\u6CA1\u6709**\u63D0\u4EA4\uFF0C\u4E5F\u6CA1\u6709\u66FF\u7528\u6237\u6311\u623F\u95F4\u3002",
7281
- "\u5982\u9700\u76F4\u63A5\u5EFA\u4F1A\u5E76\u6CBF\u7528\u63A8\u8350\uFF0C\u53EF\u4F20 autoRoom: true\uFF1B\u4E0D\u9700\u8981\u4F1A\u8BAE\u5BA4\u5219\u4F20 allowNoRoom: true\u3002",
7282
- ...earlyWorkflowNote ? [earlyWorkflowNote] : [],
7283
- ...memberConflicts.length > 0 ? [`\u26A0\uFE0F \u6CE8\u610F\uFF1A\u53C2\u4F1A\u4EBA\u5728\u8BE5\u65F6\u6BB5\u5DF2\u6709 ${memberConflicts.length} \u573A\u4F1A\u8BAE\u51B2\u7A81 \u2014\u2014 \u9009\u623F\u524D\u5148\u628A\u8FD9\u6761\u544A\u8BC9\u7528\u6237\uFF0C\u522B\u8BA9\u4ED6\u9009\u5B8C\u624D\u53D1\u73B0\u3002`] : [],
7284
- ...freeSlots.length > 0 ? [`\u5F53\u5929\u5168\u90E8\u53C2\u4F1A\u4EBA\u90FD\u7A7A\u95F2\u7684\u65F6\u6BB5\uFF1A${freeSlots.map((s) => `${s.begin.slice(11)}~${s.end.slice(11)}`).join("\u3001")}`] : [],
7285
- ...failureWarnings
7286
- ]
7287
- });
7288
- }
7289
- if (addressInput) {
7290
- } else if (autoRoom && roomRec.best) {
7291
- addressInput = roomRec.best.id;
7292
- }
7293
- }
7294
- if (enrich && !addressInput && args.allowNoRoom !== true) {
7295
- decisions.roomUnavailable = {
7296
- reason: roomRec ? `\u8BE5\u65F6\u6BB5\u6CA1\u6709\u6EE1\u8DB3\u6761\u4EF6\u7684\u7A7A\u95F2\u4F1A\u8BAE\u5BA4\uFF08\u5171 ${roomRec.meta?.roomsTotal ?? 0} \u95F4\uFF0C\u53EF\u7528 ${roomRec.meta?.roomsUsable ?? 0} \u95F4\uFF0C\u88AB\u5360\u7528 ${roomRec.meta?.roomsBusy ?? 0} \u95F4\uFF09` : "\u4F1A\u8BAE\u5BA4\u63A8\u8350\u6CA1\u6709\u8FD4\u56DE\u7ED3\u679C\uFF08\u4F1A\u8BAE\u5BA4\u5217\u8868\u63A5\u53E3\u8BFB\u4E0D\u5230\uFF0C\u6216\u63A8\u8350\u8FC7\u7A0B\u51FA\u9519\uFF09",
7297
- meta: roomRec?.meta ?? null
7298
- };
7299
- return meetingSuccess("meeting.eb.meeting.create.flow.prepare", {
7300
- status: "NEEDS_SELECTION",
7301
- selectionType: "room_unavailable",
7302
- ui: { component: "choice", multiple: false, recommendedKey: "C2" },
7303
- message: "\u672A\u6307\u5B9A\u4F1A\u8BAE\u5BA4\uFF0C\u4E14\u6309\u4EBA\u6570/\u65F6\u6BB5\u6CA1\u80FD\u63A8\u8350\u51FA\u53EF\u7528\u7684\u7A7A\u95F2\u4F1A\u8BAE\u5BA4\u3002\u8BF7\u8BA9\u7528\u6237\u4ECE\u4E0B\u9762\u4E09\u6761\u91CC\u9009\u4E00\u6761\uFF0C**\u4E0D\u8981**\u76F4\u63A5\u63D0\u4EA4\u4E00\u4E2A\u6CA1\u6709\u5730\u70B9\u7684\u4F1A\u8BAE",
7304
- workflowPending: true,
7305
- options: [
7306
- { key: "C1", label: "\u6211\u6307\u5B9A\u5177\u4F53\u4F1A\u8BAE\u5BA4\uFF08\u8868\u5355\u91CC\u70B9\u9009\uFF0C\u6216\u544A\u8BC9\u6211\u4F1A\u8BAE\u5BA4\u540D\u79F0/id\uFF09", value: { action: "specify" } },
7307
- { key: "C2", label: "\u6539\u7528\u7EBF\u4E0A\u4F1A\u8BAE\uFF08\u817E\u8BAF\u4F1A\u8BAE/\u89C6\u9891\uFF09", value: { action: "no_room" } },
7308
- { key: "C3", label: '\u5148\u6309"\u5730\u70B9\u5F85\u5B9A"\u63D0\u4EA4', value: { action: "allow_no_room" } }
7309
- ],
7310
- roomUnavailable: decisions.roomUnavailable,
7311
- ...conflictBrief
7312
- }, {
7313
- warnings: [
7314
- `\u4F1A\u8BAE\u5BA4\u63A8\u8350\u65E0\u7ED3\u679C\uFF1A${String(decisions.roomUnavailable.reason)}\u3002\u672C\u6B21**\u6CA1\u6709\u63D0\u4EA4**\u3002`,
7315
- "\u786E\u5B9E\u4E0D\u9700\u8981\u4F1A\u8BAE\u5BA4\uFF08\u7EBF\u4E0A\u4F1A\uFF09\u5C31\u5E26 allowNoRoom: true \u91CD\u65B0\u8C03\u7528\uFF1B\u8981\u6307\u5B9A\u623F\u95F4\u5C31\u5E26 address\u3002",
7316
- ...memberConflicts.length > 0 ? [`\u26A0\uFE0F \u53E6\u5916\uFF1A\u53C2\u4F1A\u4EBA\u5728\u8BE5\u65F6\u6BB5\u5DF2\u6709 ${memberConflicts.length} \u573A\u4F1A\u8BAE\u51B2\u7A81 \u2014\u2014 \u6362\u65F6\u95F4\u53EF\u80FD\u6BD4\u6362\u623F\u95F4\u66F4\u5212\u7B97\u3002`] : [],
7317
- ...freeSlots.length > 0 ? [`\u5F53\u5929\u5168\u90E8\u53C2\u4F1A\u4EBA\u90FD\u7A7A\u95F2\u7684\u65F6\u6BB5\uFF1A${freeSlots.map((s) => `${s.begin.slice(11)}~${s.end.slice(11)}`).join("\u3001")}`] : [],
7318
- ...failureWarnings
7319
- ]
7320
- });
7321
- }
7322
- if (enrich && addressInput && !roomConfirmed && roomOptions.length === 0 && args.allowNoRoom !== true) {
7323
- const specified = {
7324
- key: "R1",
7325
- label: `${addressDisplay}\uFF08\u4F60\u6307\u5B9A\u7684\uFF0C\u5F85\u786E\u8BA4\uFF09`,
7326
- value: { ...resolvedAddressId ? { id: resolvedAddressId } : {}, name: addressDisplay, roomConfirmed: true },
7327
- reason: "\u4F60\u4F20\u5165\u7684\u4F1A\u8BAE\u5BA4\uFF0C\u672A\u63D0\u4EA4\u3001\u672A\u786E\u8BA4"
7328
- };
7329
- return meetingSuccess("meeting.eb.meeting.create.flow.prepare", {
7330
- status: "NEEDS_SELECTION",
7331
- selectionType: "room",
7332
- ui: { component: "choice", multiple: false, recommendedKey: "R1" },
7333
- message: "\u4F60\u4F20\u5165\u7684\u4F1A\u8BAE\u5BA4\u672A\u7ECF\u7528\u6237\u786E\u8BA4\uFF0C\u4E14\u672C\u6B21\u6CA1\u80FD\u63A8\u8350\u51FA\u5176\u5B83\u5019\u9009 \u2014\u2014 \u8BF7\u8BA9\u7528\u6237\u786E\u8BA4\u8FD9\u4E00\u95F4\uFF0C\u6216\u6362\u4E00\u95F4 / \u6539\u65F6\u6BB5",
7334
- workflowPending: true,
7335
- options: [specified],
7336
- recommended: specified.value,
7337
- hint: "\u7528\u6237\u786E\u8BA4\u7528\u8FD9\u95F4\u5C31\u628A value \u539F\u6837\u5E26\u56DE\uFF08\u542B roomConfirmed: true\uFF09"
7338
- }, {
7339
- warnings: ["\u4F1A\u8BAE\u5BA4\u672A\u7ECF\u7528\u6237\u786E\u8BA4\uFF0C\u672C\u6B21**\u6CA1\u6709**\u63D0\u4EA4\u3002", ...failureWarnings]
7340
- });
7341
- }
7342
- const resolved = await resolveWorkflowId(env, args);
7343
- const confirmedAddressId = resolvedAddressId;
7344
- const confirmedAddressLabel = addressId === "" ? "" : resolvedAddress?.name || String(roomOptions.find((item) => String(item.value?.id ?? "") === confirmedAddressId)?.value?.name ?? "") || addressId;
7345
- const confirmedWhen = `${beginText}~${String(endText).slice(11) || endText}`;
7346
- let candidates = resolved.candidates;
7347
- workflowId = resolved.workflowId;
7348
- let sourceLabel = resolved.source === "argument" ? "\u8C03\u7528\u65B9\u4F20\u5165" : resolved.source === "fixed" ? `\u56FA\u5316\u914D\u7F6E\uFF08${resolved.label ?? "\u9ED8\u8BA4"}\uFF09` : "\u5E94\u7528\u8BBE\u7F6E\u914D\u7F6E";
7349
- let probes = [];
7350
- let loadedForms = /* @__PURE__ */ new Map();
7351
- const autoPick = shouldAutoPickFlow(args);
7352
- if (!workflowId && candidates.length > 1) {
7353
- let probed = await probeWorkflowCandidates(env, candidates);
7354
- probes = probed.probes;
7355
- loadedForms = probed.loadedForms;
7356
- let launchable = probes.filter((probe) => probe.launchable);
7357
- if (launchable.length === 0 && resolved.source === "fixed") {
7358
- const settings = await fetchEbAppSettings(env, "meeting.eb.meeting.create.flow.prepare");
7359
- const fallbackIds = String(settings.mtNewWf ?? "").split(/[,;,;\s]+/).map((item) => item.trim()).filter((item) => item !== "");
7360
- if (fallbackIds.length > 0) {
7361
- probed = await probeWorkflowCandidates(env, fallbackIds);
7362
- probes = probed.probes;
7363
- loadedForms = probed.loadedForms;
7364
- candidates = fallbackIds;
7365
- sourceLabel = "\u5E94\u7528\u8BBE\u7F6E\u914D\u7F6E";
7366
- launchable = probes.filter((probe) => probe.launchable);
7367
- }
7368
- }
7369
- if (launchable.length === 0) {
7370
- throw meetingValidationError(
7371
- "flow_not_launchable",
7372
- `\u5F53\u524D\u8D26\u53F7**\u6CA1\u6709\u53D1\u8D77\u5EFA\u4F1A\u6D41\u7A0B\u7684\u6743\u9650**\uFF1A${sourceLabel}\u7684 ${candidates.length} \u4E2A\u5EFA\u4F1A\u6D41\u7A0B\u90FD\u53D1\u8D77\u4E0D\u4E86\uFF08\u65E0\u53D1\u8D77\u6743\u9650\u6216\u6D41\u7A0B\u5DF2\u505C\u7528\uFF09\u2014\u2014${probes.map((probe) => `${probe.workflowId}\uFF08${probe.reason ?? "\u4E0D\u53EF\u53D1\u8D77"}\uFF09`).join("\uFF1B")}\u3002\u8BF7\u5982\u5B9E\u544A\u77E5\u7528\u6237\uFF1A\u9700\u8981\u627E\u7BA1\u7406\u5458\u5F00\u901A\u8BE5\u6D41\u7A0B\u7684\u53D1\u8D77\u6743\u9650\uFF0C\u6216\u8BF7\u6709\u6743\u9650\u7684\u540C\u4E8B\u4EE3\u4E3A\u53D1\u8D77\uFF1B**\u4E0D\u8981**\u6539\u7528\u76F4\u8FDE\u5EFA\u4F1A\u7ED5\u8FC7\u6D41\u7A0B\u7BA1\u63A7\u3002`,
7373
- { probes }
7374
- );
7375
- }
7376
- if (launchable.length > 1 && !autoPick) {
7377
- return meetingSuccess("meeting.eb.meeting.create.flow.prepare", {
7378
- status: "NEEDS_SELECTION",
7379
- // ⚠️ 以前漏了这个字段(agent 拿到 undefined 无法判断是哪类选择,2026-10-30 真机发现)。
7380
- selectionType: "flow",
7381
- // 明确告诉调用方"这是一道选择题,请用选项控件呈现",不要降级成文本列表
7382
- // (2026-10-30 用户反馈:agent 把会议室候选写成文本 + "需要你指定一间",没给选项卡)。
7383
- ui: { component: "choice", multiple: false, recommendedKey: "W1" },
7384
- // 四要素已经确认到这一步了:摘要一起给出去,用户只需点一下流程,就能直接提交。
7385
- confirmed: {
7386
- mt_name: String(args.mt_name ?? ""),
7387
- begin_datetime: beginText,
7388
- end_datetime: endText,
7389
- address: confirmedAddressId || null,
7390
- addressName: confirmedAddressLabel || null,
7391
- hrm_members: memberIds
7392
- },
7393
- message: `\u4F1A\u8BAE\u8981\u7D20\u5DF2\u786E\u8BA4\uFF08${String(args.mt_name ?? "")} \xB7 ${confirmedWhen}${confirmedAddressLabel ? ` \xB7 ${confirmedAddressLabel}` : " \xB7 \u65E0\u4F1A\u8BAE\u5BA4"}\uFF09\uFF1B\u5F53\u524D\u8D26\u53F7\u5BF9 ${sourceLabel}\u7684 ${candidates.length} \u4E2A\u5EFA\u4F1A\u6D41\u7A0B**\u90FD\u6709\u53D1\u8D77\u6743\u9650**\uFF0C\u8BF7\u8BA9\u7528\u6237\u6700\u540E\u9009\u4E00\u4E0B\u300C\u7528\u54EA\u6761\u6D41\u7A0B\u53D1\u8D77\u300D\u2014\u2014 **\u4E0D\u8981\u9ED8\u8BA4\u53D6\u7B2C\u4E00\u4E2A**\uFF08\u5404\u6D41\u7A0B\u8868\u5355\u5B57\u6BB5\u53EF\u80FD\u5B8C\u5168\u4E0D\u540C\uFF0C\u9009\u9519\u4F1A\u6F0F\u5B57\u6BB5\uFF1B2026-10-29 \u771F\u5B9E\u4E8B\u6545\uFF1A\u53D6\u7B2C\u4E00\u4E2A\u5BFC\u81F4\u5B57\u6BB5\u5168\u586B\u4E0D\u8FDB\u53E6\u4E00\u6761\u6D41\u7A0B\uFF0C\u7528\u6237\u4EE5\u4E3A"\u7CFB\u7EDF\u53EA\u652F\u6301\u4E00\u6761\u6D41\u7A0B"\uFF09\u3002\u26A0\uFE0F \u53EA\u6709\u5176\u4E2D 1 \u4E2A\u6709\u6743\u9650\u65F6 CLI \u4F1A\u76F4\u63A5\u53D1\u8D77\uFF0C\u4E0D\u4F1A\u8D70\u5230\u8FD9\u4E00\u6B65`,
7394
- options: launchable.map((probe, index) => ({
7395
- key: `W${index + 1}`,
7396
- label: probe.name ? `${probe.name}\uFF08${probe.workflowId}\uFF09` : probe.workflowId,
7397
- // ⛔ 把已确认的四要素一起带回去:用户点选流程后**原样回传 value** 就能直接出确认摘要,
7398
- // 不用再走一遍时间/房间闸门(否则"先定四要素再选流程"会多出一轮无效往返)。
7399
- value: {
7400
- workflowId: probe.workflowId,
7401
- begin_datetime: beginText,
7402
- end_datetime: endText,
7403
- timeConfirmed: true,
7404
- ...confirmedAddressId ? { address: confirmedAddressId, roomConfirmed: true } : {}
7405
- },
7406
- reason: "\u5F53\u524D\u8D26\u53F7\u6709\u53D1\u8D77\u6743\u9650",
7407
- // 把该流程的字段名如实带出来:不同流程字段差异很大(有的有设备需求/涉密项目,有的没有),
7408
- // 用户要靠这个才能选对(2026-10-29 用户反馈:选错方式后字段全填不进去)。
7409
- fields: (loadedForms.get(probe.workflowId)?.fields ?? []).map((f) => f.name).filter(Boolean)
7410
- })),
7411
- probes
7412
- }, {
7413
- warnings: [
7414
- `${sourceLabel}\uFF1A\u5171 ${candidates.length} \u4E2A\u5EFA\u4F1A\u6D41\u7A0B\uFF0C\u5176\u4E2D ${launchable.length} \u4E2A\u5F53\u524D\u8D26\u53F7\u53EF\u53D1\u8D77\uFF1B**\u5FC5\u987B\u628A\u8FD9\u51E0\u4E2A\u6D41\u7A0B\u505A\u6210\u9009\u9879\u8BA9\u7528\u6237\u6311\u4E00\u4E2A\uFF0C\u7981\u6B62\u81EA\u5DF1\u66FF\u7528\u6237\u9009**\uFF1B\u9009\u5B9A\u540E\u5E26\u5355\u4E2A workflowId \u91CD\u65B0 prepare\u3002`,
7415
- ...probes.filter((probe) => !probe.launchable).map((probe) => `\u6D41\u7A0B ${probe.workflowId} \u5F53\u524D\u8D26\u53F7\u65E0\u6CD5\u53D1\u8D77\uFF08${probe.reason ?? "\u65E0\u6743\u9650"}\uFF09\uFF0C\u5DF2\u6392\u9664`)
7416
- ]
7417
- });
7418
- }
7419
- workflowId = launchable[0].workflowId;
7420
- if (launchable.length === 1 && candidates.length > 1) {
7421
- const only = launchable[0];
7422
- flowPickNote = `${sourceLabel}\uFF1A\u5171 ${candidates.length} \u4E2A\u5EFA\u4F1A\u6D41\u7A0B\uFF0C\u5F53\u524D\u8D26\u53F7\u53EA\u6709\u300C${only.name ?? only.workflowId}\u300D\uFF08${only.workflowId}\uFF09\u6709\u53D1\u8D77\u6743\u9650\uFF0C\u5DF2\u76F4\u63A5\u7528\u5B83\u53D1\u8D77`;
7423
- }
7424
- if (launchable.length > 1) {
7425
- const picked2 = launchable[0];
7426
- const others = launchable.slice(1).map((probe) => probe.name ? `${probe.name}\uFF08${probe.workflowId}\uFF09` : probe.workflowId);
7427
- flowPickNote = `${sourceLabel}\uFF1A\u5171 ${candidates.length} \u4E2A\u5EFA\u4F1A\u6D41\u7A0B\uFF0C\u5F53\u524D\u8D26\u53F7\u53EF\u53D1\u8D77 ${launchable.length} \u4E2A\uFF0C\u5DF2\u6309\u4F18\u5148\u7EA7\u81EA\u52A8\u9009\u7528\u300C${picked2.name ?? picked2.workflowId}\u300D\uFF08${picked2.workflowId}\uFF09\uFF1B\u5176\u4ED6\u53EF\u7528\u6D41\u7A0B\uFF1A${others.join("\u3001")} \u2014\u2014 \u8981\u7528\u5B83\u4EEC\u8BF7\u663E\u5F0F\u4F20 workflowId\u3002`;
7428
- }
7429
- }
7430
- let form = loadedForms.get(workflowId);
7431
- if (!form) {
7432
- try {
7433
- form = await loadCreateForm(env, workflowId);
7434
- } catch (error) {
7435
- throw meetingValidationError(
7436
- "flow_not_launchable",
7437
- `\u5F53\u524D\u8D26\u53F7**\u6CA1\u6709\u53D1\u8D77\u5EFA\u4F1A\u6D41\u7A0B\u7684\u6743\u9650**\uFF08\u6216\u6D41\u7A0B\u5DF2\u505C\u7528\uFF09\uFF1A\u5EFA\u4F1A\u6D41\u7A0B ${workflowId} \u7684\u8868\u5355\u8F7D\u5165\u5931\u8D25 \u2014\u2014 ${String(error?.message ?? error).slice(0, 200)}\u3002\u8BF7\u5982\u5B9E\u544A\u77E5\u7528\u6237\uFF1A\u9700\u8981\u627E\u7BA1\u7406\u5458\u5F00\u901A\u8BE5\u6D41\u7A0B\u7684\u53D1\u8D77\u6743\u9650\uFF0C\u6216\u8BF7\u6709\u6743\u9650\u7684\u540C\u4E8B\u4EE3\u4E3A\u53D1\u8D77\uFF1B**\u4E0D\u8981**\u6539\u7528\u76F4\u8FDE\u5EFA\u4F1A\u7ED5\u8FC7\u6D41\u7A0B\u7BA1\u63A7\u3002`,
7438
- { workflowId }
7439
- );
7440
- }
7441
- }
7442
- if (!form.continuation) {
7443
- throw meetingValidationError("flow_context_missing", "\u5EFA\u4F1A\u6D41\u7A0B\u8868\u5355\u6CA1\u6709\u8FD4\u56DE continuation\uFF0C\u65E0\u6CD5\u7EE7\u7EED\u63D0\u4EA4");
7444
- }
7445
- decisions.timings = timings;
7446
- const crmMemberCount = (() => {
7447
- if (args.crm_member_count !== void 0 && args.crm_member_count !== "") return args.crm_member_count;
7448
- const raw = args.crm_members;
7449
- if (raw === void 0 || raw === null || raw === "") return void 0;
7450
- if (Array.isArray(raw)) return raw.length > 0 ? raw.length : void 0;
7451
- const text = String(raw).trim();
7452
- if (!text) return void 0;
7453
- const count = text.split(/[,;,;]+/).map((item) => item.trim()).filter((item) => item !== "").length;
7454
- return count > 0 ? count : void 0;
7455
- })();
7456
- const shaped = await shapeBrowserValues(env, {
7457
- mt_name: args.mt_name,
7458
- begin_datetime: args.begin_datetime,
7459
- end_datetime: args.end_datetime,
7460
- mt_desc: args.mt_desc,
7461
- address: addressInput,
7462
- customize_address: args.customize_address,
7463
- hrm_members: args.hrm_members,
7464
- total_member: args.total_member,
7465
- crm_members: args.crm_members,
7466
- ...crmMemberCount === void 0 ? {} : { crm_member_count: crmMemberCount },
7467
- caller: args.caller,
7468
- contacter: args.contacter,
7469
- other_remark: args.other_remark,
7470
- mt_type: args.mt_type,
7471
- ...args.extraFields && typeof args.extraFields === "object" && !Array.isArray(args.extraFields) ? args.extraFields : {}
7472
- });
7473
- const preferredFields = await readFlowFieldMap(env, workflowId);
7474
- const { main, mapped, unmapped, resolved: resolvedFields } = mapFields(form.fields, shaped.values, preferredFields);
7475
- await writeFlowFieldMap(env, workflowId, form.workflowName, resolvedFields);
7476
- const warnings = [];
7477
- if (autoFilledPerson.length > 0) {
7478
- const labels = autoFilledPerson.map((one) => `\u300C${PERSON_FIELD_LABELS[one.field]}\u300D`).join("");
7479
- warnings.push(
7480
- `${labels}\u6CA1\u6709\u4F20\u503C\uFF0C\u5DF2\u6309**\u5F53\u524D\u767B\u5F55\u4EBA**\u8865\u9F50\uFF1A${autoFilledPerson[0].name}\uFF08${autoFilledPerson[0].id}\uFF09\u3002\u8981\u6362\u6210\u522B\u4EBA\uFF08\u4F8B\u5982\u66FF\u4ED6\u4EBA\u5EFA\u4F1A\u3001\u6307\u5B9A\u522B\u7684\u8054\u7CFB\u4EBA\uFF09\u8BF7\u663E\u5F0F\u4F20 caller / contacter\u3002`
7481
- );
7482
- } else if (selfPersonWarning) {
7483
- warnings.push(selfPersonWarning);
7484
- }
7485
- if (flowPickNote) warnings.push(flowPickNote);
7486
- for (const note of shaped.notes) warnings.push(note);
7487
- const crmMentioned = detectCrmMentionInText(args.mt_name, args.mt_desc, args.other_remark);
7488
- if (crmMentioned && !args.crm_members) {
7489
- const hasCrmField = form.fields.some((field) => /参会客户/.test(String(field?.label ?? field?.name ?? field?.fieldName ?? "")));
7490
- warnings.push(
7491
- `\u4F1A\u8BAE\u540D\u79F0/\u5185\u5BB9\u91CC\u63D0\u5230\u5BA2\u6237\u300C${crmMentioned}\u300D\uFF0C\u4F46\u672C\u6B21\u6CA1\u4F20 crm_members` + (hasCrmField ? `\uFF0C\u8BE5\u6D41\u7A0B\u8868\u5355**\u6709\u300C\u53C2\u4F1A\u5BA2\u6237\u300D\u5B57\u6BB5\uFF0C\u73B0\u5728\u4F1A\u662F\u7A7A\u7684**\u3002\u8BF7\u5148 meeting.eb.crm.search {"keyword":"${crmMentioned}"} \u62FF items[].customerId\uFF0C\u518D\u7528 crm_members:[{id,name}] \u91CD\u65B0\u63D0\u4EA4\uFF08\u5FC5\u987B\u5E26\u5BA2\u6237\u540D\u79F0\uFF09\u3002` : "\uFF08\u8BE5\u6D41\u7A0B\u8868\u5355\u91CC\u6CA1\u6709\u300C\u53C2\u4F1A\u5BA2\u6237\u300D\u5B57\u6BB5\uFF0C\u672C\u6761\u53EF\u5FFD\u7565\uFF09\u3002")
7492
- );
7493
- }
7494
- const crmMembersGiven = Array.isArray(args.crm_members) ? args.crm_members.length > 0 : String(args.crm_members ?? "").trim() !== "";
7495
- if (crmMembersGiven) {
7496
- const crmFieldId = String(resolvedFields.crm_members ?? "").trim();
7497
- const crmField = form.fields.find((field) => String(field?.id ?? "") === crmFieldId);
7498
- const componentKey = String(crmField?.componentKey ?? "").toLowerCase();
7499
- if (crmField && componentKey !== "" && componentKey !== "customer" && componentKey !== "customercomponent") {
7500
- warnings.push(
7501
- `\u300C\u53C2\u4F1A\u5BA2\u6237\u300D\u5B57\u6BB5\uFF08${crmFieldId}\uFF09\u662F ${crmField.componentKey} \u7EC4\u4EF6\uFF1A\u5BA2\u6237 id \u4E0E\u540D\u79F0\u7167\u5E38\u5199\u8FDB\u6D41\u7A0B\u5355\u636E\uFF0C\u518D\u7531 ESB \u7684\u5B57\u6BB5\u6620\u5C04\u540C\u6B65\u5230\u4F1A\u8BAE\u8868 \u2014\u2014 \u6B63\u5E38\u914D\u7F6E\uFF0C\u4E0D\u9700\u8981\u6539\u8868\u5355\u3002`
7502
- );
7503
- }
7504
- }
7505
- const providedCrmDetailRows = normalizeCrmDetailRows(args.crm_member_details);
7506
- const onlyDetailMode = String(args.crm_detail_mode ?? "").trim().toLowerCase() === "only";
7507
- let crmDetailRows = onlyDetailMode ? providedCrmDetailRows : [];
7508
- if (crmMembersGiven && !onlyDetailMode) {
7509
- const detailTarget = resolveCrmDetailTarget(form.fields);
7510
- if (detailTarget) {
7511
- const auto = await resolveAutoCrmDetailRows(env, args.crm_members);
7512
- if (auto.rows.length > 0) {
7513
- crmDetailRows = auto.rows;
7514
- if (providedCrmDetailRows.length > 0) {
7515
- const byName = new Map(providedCrmDetailRows.map((row) => [String(row.xm ?? "").trim(), row]));
7516
- crmDetailRows = crmDetailRows.map((row) => {
7517
- const given = byName.get(String(row.xm ?? "").trim());
7518
- if (!given) return row;
7519
- const merged = { ...row };
7520
- for (const [key, value] of Object.entries(given)) {
7521
- if (String(value ?? "").trim() !== "") merged[key] = String(value);
7522
- }
7523
- return merged;
7524
- });
7525
- }
7526
- warnings.push(
7527
- `\u5DF2\u81EA\u52A8\u628A\u300C${auto.customers.join("\u3001")}\u300D\u7684 ${auto.rows.length} \u4F4D\u8054\u7CFB\u4EBA\u5199\u8FDB\u300C\u53C2\u4F1A\u5BA2\u6237\u660E\u7EC6\u300D\uFF1A${auto.rows.map((row) => `${row.xm}${row.sjhm ? ` ${row.sjhm}` : ""}`).join("\u3001")}\uFF08\u660E\u7EC6\u8868\u672C\u6765\u5C31\u4E00\u4EBA\u4E00\u884C\uFF0C\u4E0D\u9700\u8981\u8BA9\u7528\u6237\u6311\uFF09\u3002\u786E\u5B9E\u53EA\u60F3\u8981\u5176\u4E2D\u51E0\u4F4D\u65F6\uFF0C\u4F20 crm_detail_mode:"only" \u518D\u914D crm_member_details \u624D\u8986\u76D6\u672C\u6B21\u81EA\u52A8\u5E26\u5165\u3002`
7528
- );
7529
- } else if (auto.missing.length > 0) {
7530
- warnings.push(
7531
- `\u5DF2\u5199\u300C\u53C2\u4F1A\u5BA2\u6237\u300D\uFF0C\u4F46\u6CA1\u80FD\u81EA\u52A8\u5E26\u51FA\u300C${auto.missing.join("\u3001")}\u300D\u7684\u8054\u7CFB\u4EBA\uFF08CRM \u91CC\u67E5\u4E0D\u5230\uFF09\u3002\u8BF7\u628A\u5DF2\u67E5\u5230\u7684\u8054\u7CFB\u4EBA\u76F4\u63A5\u544A\u7ED9\u7528\u6237\u6838\u5BF9\uFF1B\u786E\u5B9E\u6CA1\u6709\u8054\u7CFB\u4EBA\u65F6\u95EE\u4E00\u6B21\u59D3\u540D+\u624B\u673A\u53F7\uFF0C\u518D\u4EE5 crm_member_details:[{"xm":"\u5F20\u4E09","sjhm":"13800000000"}] \u91CD\u65B0 prepare\u3002`
7532
- );
7533
- }
7534
- }
7535
- }
7536
- let detailPayload;
7537
- if (crmDetailRows.length > 0) {
7538
- const target = resolveCrmDetailTarget(form.fields);
7539
- if (!target) {
7540
- warnings.push(
7541
- `\u4F20\u4E86 crm_member_details\uFF08${crmDetailRows.length} \u884C\uFF09\uFF0C\u4F46\u8BE5\u5EFA\u4F1A\u6D41\u7A0B\u7684**\u53D1\u8D77\u8282\u70B9\u8868\u5355\u91CC\u6CA1\u6709\u300C\u53C2\u4F1A\u5BA2\u6237\u660E\u7EC6\u300D\u660E\u7EC6\u8868**\uFF08\u6216\u5B83\u88AB\u6446\u5728\u9690\u85CF\u884C\u4E0A\uFF09\uFF0C\u660E\u7EC6\u65E0\u6CD5\u5199\u5165\uFF0C\u5DF2\u5FFD\u7565\u8FD9\u4E9B\u884C\uFF1B\u4E3B\u8868\u7684\u300C\u53C2\u4F1A\u5BA2\u6237\u300D\u7167\u5E38\u5199\u5165\u3002`
7542
- );
7543
- } else {
7544
- detailPayload = {
7545
- [target.subFormId]: crmDetailRows.map((row) => {
7546
- const line = {};
7547
- for (const [semantic, fieldId] of Object.entries(target.columns)) {
7548
- const value = row[semantic];
7549
- if (value !== void 0 && value !== "") line[fieldId] = value;
7550
- }
7551
- return line;
7552
- })
7553
- };
7554
- warnings.push(
7555
- `\u53C2\u4F1A\u5BA2\u6237\u660E\u7EC6\uFF1A${crmDetailRows.length} \u884C\u5199\u5165\u660E\u7EC6\u8868 ${target.subFormId}\uFF08\u5217\uFF1A${Object.values(target.labels).join("/")}\uFF09`
7556
- );
7557
- }
7558
- }
7559
- if (args.fieldValues && typeof args.fieldValues === "object" && !Array.isArray(args.fieldValues)) {
7560
- const knownIds = new Set(form.fields.map((field) => field.id));
7561
- for (const [fieldId, raw] of Object.entries(args.fieldValues)) {
7562
- if (raw === void 0 || raw === null || raw === "") continue;
7563
- if (!knownIds.has(fieldId)) {
7564
- warnings.push(`fieldValues \u91CC\u7684 datakey\u300C${fieldId}\u300D\u4E0D\u5728\u8BE5\u6D41\u7A0B\u8868\u5355\u91CC\uFF0C\u5DF2\u5FFD\u7565\uFF08\u5148\u7528 prepare \u4E0D\u5E26 fieldValues \u8DD1\u4E00\u6B21\uFF0C\u770B unmapped/\u8868\u5355\u5B57\u6BB5\u6E05\u5355\uFF09`);
7565
- continue;
7566
- }
7567
- main[fieldId] = raw;
7568
- mapped[`datakey:${fieldId}`] = fieldId;
7569
- }
7570
- }
7571
- if (enrichFailures.length > 0) {
7572
- decisions.enrichFailures = enrichFailures;
7573
- for (const failure of enrichFailures) {
7574
- warnings.push(`\u26A0\uFE0F ${failure} \u2014\u2014 **\u8FD9\u4E0D\u4EE3\u8868\u6CA1\u6709\u51B2\u7A81**\uFF0C\u8BF7\u5982\u5B9E\u544A\u77E5\u7528\u6237\u8BE5\u9879\u672A\u6838\u9A8C\uFF0C\u4E0D\u8981\u58F0\u79F0"\u65F6\u95F4\u5DF2\u786E\u8BA4\u7A7A\u95F2"`);
7575
- }
7576
- }
7577
- const picked = decisions.autoRoom?.picked;
7578
- if (picked && !hadAddressInput) {
7579
- warnings.push(
7580
- `\u672A\u6307\u5B9A\u4F1A\u8BAE\u5BA4 \u2192 \u5DF2\u81EA\u52A8\u9009\u62E9\u300C${picked.name}\u300D\uFF08${(picked.reasons ?? []).join("\uFF1B")}\uFF09\uFF1B\u53E6\u6709\u5019\u9009 ${(decisions.roomOptions ?? []).slice(1).map((item) => item.label).join(" / ") || "\u65E0"}`
7581
- );
7582
- }
7583
- const slotOptions = decisions.slotOptions ?? [];
7584
- const memberConflictCount = decisions.memberConflicts?.length ?? 0;
7585
- if (memberConflictCount > 0 && slotOptions.length > 0) {
7586
- warnings.push(
7587
- `\u53C2\u4F1A\u4EBA\u65F6\u95F4\u6709\u51B2\u7A81\uFF08${memberConflictCount} \u6761\u5360\u7528\uFF09\uFF1B\u5F53\u5929\u6240\u6709\u4EBA\u90FD\u7A7A\u7684\u65F6\u6BB5\uFF1A` + slotOptions.map((item) => `[${item.key}] ${item.label}`).join("\uFF1B") + "\u2014\u2014\u8BF7\u7528\u9009\u9879\u65B9\u5F0F\u8BA9\u7528\u6237\u6311\uFF08\u9009\u5B9A\u540E\u91CD\u65B0 prepare \u5E76\u6539\u65F6\u95F4\uFF09\u3002"
7588
- );
7589
- } else if (memberConflictCount === 0 && slotOptions.length > 0) {
7590
- warnings.push(
7591
- `\u8BE5\u65F6\u6BB5\u53C2\u4F1A\u4EBA\u6CA1\u6709\u4F1A\u8BAE/\u65E5\u7A0B\u5360\u7528\uFF08\u5DF2\u6838\u5BF9\u4F1A\u8BAE\u56DE\u6267\u4E0E\u65E5\u7A0B\uFF09\u3002\u5F53\u5929\u5176\u4ED6\u5171\u540C\u7A7A\u95F2\u65F6\u6BB5\uFF1A${slotOptions.map((item) => `[${item.key}] ${item.label}`).join("\uFF1B")}`
7592
- );
7593
- } else if (decisions.dayBlocked?.summary) {
7594
- warnings.push(String(decisions.dayBlocked.summary));
7595
- }
7596
- const unmappedReal = unmapped.filter((name) => name !== "mt_name" && name !== "crm_member_count");
7597
- if (unmappedReal.length > 0) {
7598
- warnings.push(
7599
- `\u4EE5\u4E0B\u5B57\u6BB5\u6CA1\u6709\u5728\u5EFA\u4F1A\u6D41\u7A0B\u8868\u5355\u91CC\u627E\u5230\u540C\u540D\u5B57\u6BB5\uFF0C\u672A\u81EA\u52A8\u586B\u5199\uFF1A${unmappedReal.join("\u3001")}\uFF08\u8868\u5355\u73B0\u6709\u5B57\u6BB5\uFF1A${form.fields.map((field) => field.name).join("\u3001")}\uFF09`
7600
- );
7601
- }
7602
- if (!main[form.fields.find((field) => field.name === "\u4F1A\u8BAE\u540D\u79F0")?.id ?? ""] && !mapped.mt_name) {
7603
- warnings.push(
7604
- "\u8BE5\u5EFA\u4F1A\u6D41\u7A0B\u7684\u8868\u5355\u6CA1\u6709\u300C\u4F1A\u8BAE\u540D\u79F0\u300D\u5B57\u6BB5\uFF08\u90E8\u5206\u6D41\u7A0B\u7528\u6D41\u7A0B\u6807\u9898\u4EE3\u66FF\u4F1A\u8BAE\u540D\u79F0\uFF0C\u5C5E\u6B63\u5E38\u914D\u7F6E\uFF0C\u4E0D\u662F\u6D41\u7A0B\u914D\u9519\uFF09\u3002\u5982\u9700\u4F1A\u8BAE\u540D\u79F0\u72EC\u7ACB\u6210\u5B57\u6BB5\uFF0C\u8BF7\u6539\u9009\u5E26\u8BE5\u5B57\u6BB5\u7684\u6D41\u7A0B\uFF08\u5982\u300C\u4F1A\u8BAE\u7533\u8BF7\u6D41\u7A0B\uFF08NEW\uFF09\u300D\uFF09\u3002"
7605
- );
7606
- }
7607
- const crmPatchIds = (Array.isArray(shaped.values.crm_members) ? shaped.values.crm_members : []).map((row) => String(row?.id ?? "").trim()).filter((id) => id !== "");
7608
- const session = await env.host.getSession();
7609
- const continuation = await env.continuation.issue(
7610
- {
7611
- operation: "meeting.eb.meeting.create.flow.apply",
7612
- baseUrl: session.baseUrl,
7613
- profile: session.profile,
7614
- userId: session.userId,
7615
- payload: {
7616
- workflowId,
7617
- requestName: String(args.mt_name),
7618
- mtName: String(args.mt_name),
7619
- data: { main, ...detailPayload ? { details: detailPayload } : {} },
7620
- surfaceContinuation: form.continuation,
7621
- // 供 apply 在「会议还没生成」时按申请单信息预生成邀请函(预置函)
7622
- invitationFields: shaped.readable,
7623
- // 提交后回显要用「字段名 → 值」,字段清单先存下来(apply 阶段拿不到 createForm 结果)
7624
- fieldLabels: form.fields.map((field) => ({ id: String(field.id), name: String(field.name) })),
7625
- // 已确认的「人员 id → 姓名」,供 apply 回显时把裸 id 换成姓名
7626
- ...autoFilledPerson.length > 0 ? { personLabels: Object.fromEntries(autoFilledPerson.map((one) => [one.id, one.name])) } : {},
7627
- // 会议记录的客户要靠 apply 补写(表单「参会客户」是 Ebuilder,单据↔会议表不同步)
7628
- ...crmPatchIds.length > 0 ? { crmPatch: { ids: crmPatchIds, count: crmMemberCount === void 0 ? crmPatchIds.length : crmMemberCount } } : {}
7629
- },
7630
- fingerprint: JSON.stringify({ workflowId, main, ...detailPayload ? { details: detailPayload } : {} })
7631
- },
7632
- 10 * 60 * 1e3
7633
- );
7634
- return meetingSuccess(
7635
- "meeting.eb.meeting.create.flow.prepare",
7636
- {
7637
- status: "AWAITING_CONFIRMATION",
7638
- preview: {
7639
- workflowId,
7640
- workflowCandidates: candidates,
7641
- ...probes.length > 0 ? { workflowProbes: probes } : {},
7642
- ...flowPickNote ? { workflowAutoPicked: { workflowId, source: resolved.source, note: flowPickNote } } : {},
7643
- requestName: String(args.mt_name),
7644
- fieldMapping: mapped,
7645
- formData: { main },
7646
- // 人话版「即将提交的内容」—— 提交前必须先贴给用户核对(见 SKILL 建会章节)。
7647
- formPreview: renderFormPreview(
7648
- form.fields,
7649
- await decoratePreviewPersonNames(
7650
- env,
7651
- main,
7652
- form.fields,
7653
- new Map(autoFilledPerson.map((one) => [one.id, one.name]))
7654
- )
7655
- ),
7656
- // 召集人/联系人是不是"替用户默认填的"要说清楚,用户才知道能不能改。
7657
- ...autoFilledPerson.length > 0 ? {
7658
- autoFilled: Object.fromEntries(
7659
- autoFilledPerson.map((one) => [PERSON_FIELD_LABELS[one.field], `${one.name}(${one.id})`])
7660
- )
7661
- } : {},
7662
- ...detailPayload ? { detailRows: { subFormId: Object.keys(detailPayload)[0], count: crmDetailRows.length, rows: crmDetailRows } } : {},
7663
- formFieldCount: form.fields.length,
7664
- ...Object.keys(decisions).length > 0 ? { decisions } : {}
7665
- },
7666
- continuation,
7667
- expiresInSeconds: 600
7668
- },
7669
- warnings.length > 0 ? { warnings } : {}
7670
- );
7671
- }
7672
- };
7673
- var CRM_PATCH_SETTLE_MS = [4e3, 6e3];
7674
- async function patchMeetingCrmMembers(env, meetingId, ids, count, settleMsList = CRM_PATCH_SETTLE_MS) {
7675
- const list = ids.map((id) => String(id ?? "").trim()).filter((id) => id !== "");
7676
- if (String(meetingId).trim() === "" || list.length === 0) {
7677
- return { ok: false, error: "\u6CA1\u6709\u4F1A\u8BAE id \u6216\u5BA2\u6237 id" };
7678
- }
7679
- const mainTable = {
7680
- id: String(meetingId).trim(),
7681
- operate_type: "UPDATE",
7682
- crm_members: list.join(",")
7683
- };
7684
- const total = Number(count);
7685
- if (Number.isFinite(total) && total > 0) mainTable.crm_total_member = String(total);
7686
- const write = async () => {
7687
- const session = await env.host.getSession();
7688
- await env.host.request({
7689
- method: "POST",
7690
- path: `${EB_BASE}/updateFormData/change_meeting`,
7691
- query: { id: String(meetingId).trim() },
7692
- operation: "meeting.eb.meeting.create.flow.apply",
7693
- body: writeBody(String(session.userId), { mainTable, details: {}, operateType: {} }),
7694
- acceptBusiness: ebBusinessSuccess
7695
- });
7696
- };
7697
- const readBack = async () => {
7698
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
7699
- const detail = getMeetingOperation2("meeting.eb.meeting.detail");
7700
- const read = await detail.handler({ id: String(meetingId).trim() }, env);
7701
- return String(read?.data?.data?.crm_members ?? "").trim();
7702
- };
7703
- let lastError = "";
7704
- for (const settleMs of settleMsList) {
7705
- try {
7706
- await write();
7707
- } catch (error) {
7708
- return { ok: false, error: String(error?.message ?? error).slice(0, 160) };
7709
- }
7710
- await new Promise((resolve6) => setTimeout(resolve6, settleMs));
7711
- try {
7712
- const value = await readBack();
7713
- if (value !== "") return { ok: true, value };
7714
- lastError = "\u8865\u5199\u540E\u56DE\u8BFB crm_members \u4ECD\u4E3A\u7A7A\uFF08\u591A\u534A\u88AB\u4F1A\u8BAE\u521D\u59CB\u5316\u7684\u540E\u7EED\u5199\u5165\u8986\u76D6\u4E86\uFF09";
7715
- } catch (error) {
7716
- lastError = `\u8865\u5199\u6210\u529F\u4F46\u56DE\u8BFB\u5931\u8D25\uFF1A${String(error?.message ?? error).slice(0, 120)}`;
7717
- }
7718
- }
7719
- return { ok: false, error: lastError };
7720
- }
7721
- async function renderPreInvitation(payload, env) {
7722
- const fields = payload?.invitationFields ?? {};
7723
- const started = Date.now();
7724
- try {
7725
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
7726
- const render = getMeetingOperation2("meeting.invitation.render");
7727
- const rendered = await render.handler(
7728
- {
7729
- mt_name: String(fields.mt_name ?? payload?.mtName ?? "").trim(),
7730
- begin_datetime: String(fields.begin_datetime ?? "").trim(),
7731
- end_datetime: String(fields.end_datetime ?? "").trim(),
7732
- address: String(fields.address ?? fields.customize_address ?? "").trim(),
7733
- hrm_members: String(fields.hrm_members ?? "").trim(),
7734
- mt_desc: String(fields.mt_desc ?? "").trim(),
7735
- org_members: String(fields.org_members ?? "").trim(),
7736
- caller: String(fields.caller ?? "").trim(),
7737
- contacter: String(fields.contacter ?? "").trim(),
7738
- total_member: String(fields.total_member ?? "").trim(),
7739
- // 客户单位(邀请函开头「尊敬的 XXX」):建会时填了参会客户就直接带过去,
7740
- // 否则整句永远是【待补充】—— 用户看到的就是"客户明明填了,邀请函里却没有"。
7741
- extra: { guest_org: String(fields.crm_members ?? "").trim() }
7742
- },
7743
- env
7744
- );
7745
- return {
7746
- invitation: { pending: true, preRendered: true, ...rendered?.data ?? {} },
7747
- ms: Date.now() - started
7748
- };
7749
- } catch (error) {
7750
- return {
7751
- invitation: {
7752
- pending: true,
7753
- preRendered: false,
7754
- ok: false,
7755
- error: String(error?.message ?? error).slice(0, 200)
7756
- },
7757
- ms: Date.now() - started
7758
- };
7759
- }
7760
- }
7761
- var ebMeetingCreateFlowApply = {
7762
- name: "meeting.eb.meeting.create.flow.apply",
7763
- resource: "eb",
7764
- method: "meeting.eb.meeting.create.flow.apply",
7765
- action: "meeting.eb.meeting.create.flow.apply",
7766
- summary: "\u6D41\u7A0B\u5EFA\u4F1A\uFF08\u63D0\u4EA4\uFF09\uFF1A\u7528\u786E\u8BA4\u7968\u636E\u63D0\u4EA4\u5EFA\u4F1A\u6D41\u7A0B\uFF1B\u63D0\u4EA4\u540E\u8F6E\u8BE2\u4F1A\u8BAE\u5217\u8868\u786E\u8BA4\u4F1A\u8BAE\u662F\u5426\u5DF2\u751F\u6210\uFF0C\u751F\u6210\u5219\u81EA\u52A8\u51FA\u9080\u8BF7\u51FD",
7767
- capability: "eb.meeting",
7768
- risk: "high-risk-write",
7769
- requiresConfirmation: true,
7770
- inputSchema: schemaOf(
7771
- {
7772
- continuation: { type: "string", description: "prepare \u8FD4\u56DE\u7684\u786E\u8BA4\u7968\u636E\uFF08\u5FC5\u586B\uFF09" },
7773
- confirm: { type: "boolean", description: "\u5FC5\u987B\u663E\u5F0F\u4F20 true" },
7774
- submit_mode: {
7775
- type: "string",
7776
- enum: ["direct", "browser"],
7777
- description: '\u63D0\u4EA4\u65B9\u5F0F\uFF0C\u9ED8\u8BA4 browser\uFF1A\u5728\u5C0Fe \u91CC**\u5F39\u51FA\u6D41\u7A0B\u8868\u5355**\uFF0C\u5B57\u6BB5\u5DF2\u9884\u586B\uFF0C\u7528\u6237\u6838\u5BF9/\u4FEE\u6539\u540E\u81EA\u5DF1\u70B9\u63D0\u4EA4\u3002direct = \u76F4\u63A5\u5199\u670D\u52A1\u7AEF\uFF08\u4F1A\u8BAE\u5F53\u573A\u751F\u6210\u3001\u9080\u8BF7\u51FD\u7528\u771F\u5B9E\u6570\u636E\uFF0C\u4F46\u6CA1\u6709\u4EBA\u5DE5\u6838\u5BF9\u8868\u5355\u8FD9\u4E00\u6B65\uFF09\uFF1B\u53EA\u6709\u7528\u6237\u660E\u786E\u8BF4"\u4E0D\u7528\u6211\u786E\u8BA4\uFF0C\u76F4\u63A5\u5EFA"\u65F6\u624D\u4F20 direct'
7778
- },
7779
- waitSeconds: { type: "number", description: "\u63D0\u4EA4\u540E\u7B49\u5F85\u4F1A\u8BAE\u751F\u6210\u7684\u6700\u957F\u79D2\u6570\uFF08\u9ED8\u8BA4 60\uFF0C0 = \u4E0D\u7B49\u5F85\uFF09" }
7780
- },
7781
- { required: ["continuation", "confirm"] }
7782
- ),
7783
- handler: async (args, env) => {
7784
- if (args.confirm !== true) {
7785
- throw meetingValidationError("confirmation_required", "\u6D41\u7A0B\u5EFA\u4F1A\u5C5E\u4E8E\u9AD8\u5F71\u54CD\u5199\u64CD\u4F5C\uFF0C\u5FC5\u987B\u663E\u5F0F\u4F20 confirm=true");
7786
- }
7787
- const lease = await env.continuation.verify(
7788
- String(args.continuation ?? ""),
7789
- "meeting.eb.meeting.create.flow.apply"
7790
- );
7791
- const session = await env.host.getSession();
7792
- if (lease.baseUrl !== session.baseUrl || lease.userId !== session.userId) {
7793
- throw meetingValidationError("context_mismatch", "\u786E\u8BA4\u4E0A\u4E0B\u6587\u5DF2\u53D8\u5316\uFF08\u79DF\u6237\u6216\u767B\u5F55\u8D26\u53F7\u4E0D\u540C\uFF09\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C prepare");
7794
- }
7795
- const payload = lease?.payload ?? {};
7796
- const { createWorkflowHost } = await import("./host-YAQAPYNP.js");
7797
- const { createWorkflowContinuationSigner } = await import("./continuation-HZIZRZBX.js");
7798
- const { getWorkflowOperation } = await import("./registry-YX4CSEMD.js");
7799
- const wfEnv = {
7800
- ...workflowEnv(env),
7801
- host: createWorkflowHost(env.ctx),
7802
- continuation: createWorkflowContinuationSigner(env.ctx)
7803
- };
7804
- const submitStartedAt = Date.now();
7805
- const submit = getWorkflowOperation("workflow.createRequest");
7806
- const submitMode = String(args.submit_mode ?? "browser").trim();
7807
- const submitted = await submit.handler(
7808
- {
7809
- // 工作流的入参名是 context(createForm 返回的 continuation 就是它的 context 句柄)
7810
- context: payload.surfaceContinuation,
7811
- data: payload.data,
7812
- action: "submit",
7813
- requestName: payload.requestName,
7814
- confirm: true,
7815
- ...submitMode === "browser" ? {} : { forceServerSubmit: true }
7816
- },
7817
- wfEnv
7818
- );
7819
- const submittedData = submitted?.data ?? {};
7820
- const requestId = String(submittedData.requestId ?? submittedData.id ?? "").trim();
7821
- if (!requestId && String(submittedData.status ?? "") === "NEEDS_CONFIRMATION") {
7822
- return meetingSuccess(
7823
- "meeting.eb.meeting.create.flow.apply",
7824
- {
7825
- status: "NEEDS_CONFIRMATION",
7826
- workflowId: payload.workflowId,
7827
- requestName: payload.requestName,
7828
- message: String(submittedData.message ?? ""),
7829
- resolvedValues: submittedData.resolvedValues ?? [],
7830
- unresolved: submittedData.unresolved ?? submittedData.candidates ?? [],
7831
- submit: submittedData
7832
- },
7833
- {
7834
- warnings: [
7835
- "\u5EFA\u4F1A\u6D41\u7A0B\u672A\u63D0\u4EA4\uFF1A\u670D\u52A1\u7AEF\u6709\u5B57\u6BB5\u65E0\u6CD5\u552F\u4E00\u89E3\u6790\uFF08\u591A\u4E3A\u4F1A\u8BAE\u5730\u70B9/\u53C2\u4F1A\u4EBA\u5458/\u53EC\u96C6\u4EBA\u7B49\u6D4F\u89C8\u6309\u94AE\u5B57\u6BB5\uFF09\uFF0C\u8BF7\u6309 message / unresolved \u4E0E\u7528\u6237\u786E\u8BA4\u53D6\u503C\u540E\u91CD\u65B0 prepare\uFF08\u628A\u8FD9\u4E9B\u5B57\u6BB5\u6539\u6210\u670D\u52A1\u7AEF\u8BA4\u5F97\u7684\u683C\u5F0F\uFF0C\u5982\u300C\u540D\u79F0(ID)\u300D\uFF09\u3002"
7836
- ]
7837
- }
7838
- );
7839
- }
7840
- if (!requestId) {
7841
- const submitStatus = String(submittedData.status ?? submitted?.status ?? "");
7842
- if (submitStatus === "BROWSER_FILL") {
7843
- const pre = await renderPreInvitation(payload, env);
7844
- return meetingSuccess(
7845
- "meeting.eb.meeting.create.flow.apply",
7846
- {
7847
- status: "BROWSER_FILL",
7848
- workflowId: payload.workflowId,
7849
- requestName: payload.requestName,
7850
- requestId: null,
7851
- meetingId: null,
7852
- contextId: submittedData.contextId ?? null,
7853
- // 宿主要靠这段 <browsertool> 才能把表单拉到浏览器里填,必须原样透出
7854
- finalMarkdown: submittedData.finalMarkdown ?? null,
7855
- message: String(submittedData.message ?? ""),
7856
- invitation: pre.invitation,
7857
- timings: { submitMs: Date.now() - submitStartedAt, invitationMs: pre.ms }
7858
- },
7859
- {
7860
- warnings: [
7861
- '\u5F53\u524D\u662F\u5C0Fe \u73AF\u5883\uFF1A\u672C\u6B21**\u6CA1\u6709\u5411\u670D\u52A1\u7AEF\u5199\u5165**\uFF0C\u5EFA\u4F1A\u6D41\u7A0B\u6539\u7531\u6D4F\u89C8\u5668\u9875\u9762\u5B8C\u6210\u586B\u5355\uFF08\u89C1 finalMarkdown\uFF09\u3002\u56E0\u6B64\u8FD8\u6CA1\u6709 requestId / \u4F1A\u8BAE id\uFF0C\u4E5F**\u4E0D\u80FD\u8BF4"\u6D41\u7A0B\u5DF2\u63D0\u4EA4"**\u3002',
7862
- `\u9080\u8BF7\u51FD\u5DF2\u6309\u7533\u8BF7\u5355\u4FE1\u606F**\u9884\u751F\u6210**\uFF08\u9884\u7F6E\u51FD\uFF0C${String(pre.invitation.filePath ?? "\u89C1 filePath")}\uFF09\uFF1A\u8BF7\u4E0B\u8F7D\u540E\u4EBA\u5DE5\u6838\u5BF9\u3001\u81EA\u884C\u53D1\u9001\uFF1B\u6D41\u7A0B\u5BA1\u6279\u901A\u8FC7\u3001\u4F1A\u8BAE\u751F\u6210\u540E\u53EF\u7528 mtId \u518D\u8DD1\u4E00\u6B21 meeting.invitation.render \u62FF\u5B8C\u6574\u5B57\u6BB5\u7248\u672C\u3002`,
7863
- '\u26D4 \u4E0D\u8981\u56E0\u4E3A"\u6CA1\u6709 requestId / \u6CA1\u6709\u4F1A\u8BAE id"\u91CD\u590D apply \u2014\u2014 \u586B\u5355\u8981\u5728\u90A3\u4E2A\u6D4F\u89C8\u5668\u9875\u9762\u91CC\u70B9\u63D0\u4EA4\u3002'
7864
- ]
7865
- }
7866
- );
7867
- }
7868
- const missing = submittedData.missingFields ?? submittedData.requiredMissing ?? submittedData.missing ?? [];
7869
- throw meetingValidationError(
7870
- "flow_submit_incomplete",
7871
- `\u5EFA\u4F1A\u6D41\u7A0B\u672A\u63D0\u4EA4\u6210\u529F\uFF08status=${String(submittedData.status ?? submitted?.status ?? "\u672A\u77E5")}\uFF09\uFF1A` + (Array.isArray(missing) && missing.length > 0 ? `\u7F3A\u5C11\u5FC5\u586B\u9879 ${missing.map((item) => item?.name ?? item).join("\u3001")}` : "\u670D\u52A1\u7AEF\u672A\u8FD4\u56DE requestId\uFF0C\u8BF7\u67E5\u770B result \u6392\u67E5"),
7872
- { submit: submittedData, missing }
7873
- );
7874
- }
7875
- const warnings = [];
7876
- const waitSeconds = args.waitSeconds === void 0 ? 20 : Math.max(0, Math.min(180, Number(args.waitSeconds)));
7877
- let meetingId = "";
7878
- const timings = { submitMs: Date.now() - submitStartedAt };
7879
- if (waitSeconds > 0) {
7880
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
7881
- const list = getMeetingOperation2("meeting.eb.meeting.list");
7882
- const deadline = Date.now() + Math.min(waitSeconds, 30) * 1e3;
7883
- const pollStart = Date.now();
7884
- let waited = 0;
7885
- while (Date.now() <= deadline) {
7886
- try {
7887
- const page = await list.handler({ mt_name: payload.mtName, pageSize: 5 }, env);
7888
- const rows = page?.data?.rows ?? [];
7889
- const hit = rows.map((row) => row?.mainTable ?? row ?? {}).find((main) => String(main.mt_name ?? "").trim() === String(payload.mtName).trim());
7890
- if (hit) {
7891
- meetingId = String(hit.id ?? "").trim();
7892
- if (meetingId) break;
7893
- }
7894
- } catch {
7895
- }
7896
- if (waited >= 5e3) break;
7897
- await new Promise((resolve6) => setTimeout(resolve6, 5e3));
7898
- waited += 5e3;
7899
- }
7900
- timings.pollMs = Date.now() - pollStart;
7901
- }
7902
- let crmLinked;
7903
- const crmPatch = payload?.crmPatch;
7904
- const crmPatchEnabled = process.env.WEAVER_MEETING_CRM_PATCH === "1";
7905
- if (meetingId && crmPatchEnabled && Array.isArray(crmPatch?.ids) && crmPatch.ids.length > 0) {
7906
- const patched = await patchMeetingCrmMembers(env, meetingId, crmPatch.ids, crmPatch.count);
7907
- crmLinked = {
7908
- ok: patched.ok,
7909
- requested: crmPatch.ids.length,
7910
- ...patched.value ? { readBack: patched.value } : {},
7911
- ...patched.error ? { error: patched.error } : {}
7912
- };
7913
- if (patched.ok) {
7914
- warnings.push(`\u300C\u53C2\u4F1A\u5BA2\u6237\u300D\u5DF2\u8865\u5199\u5230\u4F1A\u8BAE\u8BB0\u5F55\uFF08crm_members=${patched.value}\uFF09\u3002`);
7915
- } else {
7916
- warnings.push(
7917
- `\u300C\u53C2\u4F1A\u5BA2\u6237\u300D\u6CA1\u6709\u56DE\u8BFB\u5230\uFF08${patched.error ?? "\u672A\u77E5\u539F\u56E0"}\uFF09\uFF1A\u5F53\u524D\u8D70\u7684\u662F CLI \u624B\u5DE5\u8865\u5199\uFF08WEAVER_MEETING_CRM_PATCH=1\uFF09\uFF0C\u4E0D\u4F9D\u8D56 ESB \u5B57\u6BB5\u6620\u5C04\u65F6\u624D\u9700\u8981\u5B83\u3002`
7918
- );
7919
- }
7920
- }
7921
- let invitation = { pending: true };
7922
- if (meetingId) {
7923
- const invitationStart = Date.now();
7924
- try {
7925
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
7926
- const render = getMeetingOperation2("meeting.invitation.render");
7927
- const rendered = await render.handler(
7928
- {
7929
- mtId: meetingId,
7930
- // 同理:会议主表不存客户名,用建会时填的参会客户补「客户单位」
7931
- extra: { guest_org: String(payload?.invitationFields?.crm_members ?? "").trim() }
7932
- },
7933
- env
7934
- );
7935
- invitation = { pending: false, ...rendered?.data ?? {} };
7936
- timings.invitationMs = Date.now() - invitationStart;
7937
- } catch (error) {
7938
- invitation = {
7939
- pending: false,
7940
- ok: false,
7941
- error: String(error?.message ?? error).slice(0, 200)
7942
- };
7943
- }
7944
- } else {
7945
- const pre = await renderPreInvitation(payload, env);
7946
- invitation = pre.invitation;
7947
- timings.invitationMs = pre.ms;
7948
- warnings.push(
7949
- `\u6D41\u7A0B\u5DF2\u63D0\u4EA4\uFF08requestId=${requestId || "\u672A\u8FD4\u56DE"}\uFF09\uFF0C\u4F46 ${waitSeconds}s \u5185\u6CA1\u5728\u4F1A\u8BAE\u8868\u91CC\u67E5\u5230\u300C${payload.mtName}\u300D\u2014\u2014\u591A\u6570\u60C5\u51B5\u662F\u8FD8\u5728\u5BA1\u6279\u4E2D\u3002\u5DF2\u6309\u7533\u8BF7\u5355\u4FE1\u606F**\u9884\u751F\u6210**\u9080\u8BF7\u51FD\uFF08\u5C5E\u9884\u7F6E\u51FD\uFF0C\u8BF7\u4EBA\u5DE5\u6838\u5BF9\u540E\u81EA\u884C\u53D1\u9001\uFF09\uFF1B\u5BA1\u6279\u901A\u8FC7\u3001\u4F1A\u8BAE\u751F\u6210\u540E\u53EF\u7528 mtId \u518D\u8DD1\u4E00\u6B21 meeting.invitation.render \u62FF\u5230\u5B8C\u6574\u5B57\u6BB5\u7248\u672C\u3002\u26D4 \u672C operation \u4E0D\u91CD\u590D\u63D0\u4EA4\u6D41\u7A0B \u2014\u2014 \u4E0D\u8981\u56E0\u4E3A"\u6CA1\u6709\u4F1A\u8BAE id"\u5C31\u91CD\u590D apply\u3002`
7950
- );
7951
- }
7952
- return meetingSuccess(
7953
- "meeting.eb.meeting.create.flow.apply",
7954
- {
7955
- status: "COMPLETE",
7956
- timings,
7957
- workflowId: payload.workflowId,
7958
- requestId,
7959
- requestName: payload.requestName,
7960
- meetingId: meetingId || null,
7961
- // 参会客户有没有真的写进会议记录(表单侧是 Ebuilder,需 apply 补写;回读确认才算 ok)
7962
- ...crmLinked ? { crmLinked } : {},
7963
- // 提交后回显「实际提交了什么」:字段名 → 值(人员/客户显示姓名,不显示 id)。
7964
- // 用户要的就是"能看见内容",替代走不通的浏览器填单核对。
7965
- submittedPreview: renderFormPreview(
7966
- payload?.fieldLabels ?? [],
7967
- await decoratePreviewPersonNames(
7968
- env,
7969
- payload?.data?.main ?? {},
7970
- payload?.fieldLabels ?? [],
7971
- new Map(Object.entries(payload?.personLabels ?? {}))
7972
- )
7973
- ),
7974
- invitation,
7975
- result: submitted?.data ?? null
7976
- },
7977
- warnings.length > 0 ? { warnings } : {}
7978
- );
7979
- }
7980
- };
7981
- var ebMeetingCreateFlowQuick = {
7982
- name: "meeting.eb.meeting.create.flow.quick",
7983
- resource: "eb",
7984
- method: "meeting.eb.meeting.create.flow.quick",
7985
- action: "meeting.eb.meeting.create.flow.quick",
7986
- summary: '\u4E00\u6B65\u6D41\u7A0B\u5EFA\u4F1A\uFF08prepare+apply \u5408\u5E76\uFF09\uFF1A\u5185\u90E8\u5E76\u884C\u505A\u4F1A\u8BAE\u5BA4\u63A8\u8350/\u51B2\u7A81\u68C0\u6D4B/\u7A7A\u95F2\u65F6\u6BB5\uFF0C\u9ED8\u8BA4**\u5F39\u6D4F\u89C8\u5668\u8868\u5355**\u7ED9\u7528\u6237\u6838\u5BF9\u63D0\u4EA4\uFF08submit_mode=browser\uFF0C\u5C0Fe \u91CC\u9884\u586B\u4EBA\u5458/\u5BA2\u6237\u540E\u7531\u7528\u6237\u70B9\u63D0\u4EA4\uFF1B\u975E\u5C0Fe \u73AF\u5883\u4F1A\u81EA\u52A8\u5199\u670D\u52A1\u7AEF\uFF09\uFF1B\u4F20 submit_mode=direct \u624D\u662F\u670D\u52A1\u7AEF\u76F4\u63D0\uFF08\u62FF requestId + meetingId\uFF0C\u4F1A\u8BAE\u5F53\u573A\u751F\u6210\u3001\u9080\u8BF7\u51FD\u7528\u771F\u5B9E\u6570\u636E\uFF09\u3002\u591A\u6D41\u7A0B\u6216\u9700\u9009\u62E9\u65F6\u4E0D\u63D0\u4EA4\uFF0C\u8FD4\u56DE\u9009\u9879\u3002\u26A0\uFE0F \u7528\u6237\u63D0\u5230\u5BA2\u6237\u540D\u65F6**\u5FC5\u987B\u5148** meeting.eb.crm.search {"keyword":"X"} \u62FF customerId \u518D\u4F20 crm_members:[{id,name}]\uFF1B\u53EA\u628A\u5BA2\u6237\u540D\u5199\u8FDB\u4F1A\u8BAE\u540D\u79F0/\u5185\u5BB9\u800C\u4E0D\u4F20 crm_members \u4F1A\u88AB\u76F4\u63A5\u62D2\u7EDD\uFF08crm_member_required\uFF09\u3002\u26D4 \u4E0D\u8981\u7528 submit_mode=browser \u2014\u2014 \u5C0Fe \u586B\u5355\u9875\u4E0D\u7ED9\u6D4F\u89C8\u6309\u94AE\u8D4B\u503C\uFF0C\u53C2\u4F1A\u4EBA\u5458/\u53C2\u4F1A\u5BA2\u6237\u4F1A\u6574\u6BB5\u4E22\u5931',
7987
- capability: "eb.meeting",
7988
- risk: "high-risk-write",
7989
- requiresConfirmation: true,
7990
- inputSchema: schemaOf(
7991
- {
7992
- mt_name: { type: "string", description: "\u4F1A\u8BAE\u540D\u79F0\uFF08\u5FC5\u586B\uFF09" },
7993
- begin_datetime: {
7994
- ...SCHEMA_DATETIME_MINUTE,
7995
- description: "\u5F00\u59CB\u65F6\u95F4\uFF08yyyy-MM-dd HH:mm\uFF09\u3002**\u53EF\u4EE5\u4E0D\u4F20**\uFF1A\u4E0D\u4F20\u4F1A\u6309\u53C2\u4F1A\u4EBA\u4E0E\u4F1A\u8BAE\u5BA4\u7A7A\u95F2\u60C5\u51B5\u63A8\u8350 3 \u4E2A\u65F6\u6BB5\u8BA9\u4F60\u9009\uFF1B\u53EA\u4F20\u5F00\u59CB\u65F6\u95F4\u3001\u4E0D\u4F20\u7ED3\u675F\u65F6\u95F4\u65F6\uFF0C\u6309 durationMinutes\uFF08\u9ED8\u8BA4 60 \u5206\u949F\uFF09\u81EA\u52A8\u7B97\u7ED3\u675F\u65F6\u95F4"
7996
- },
7997
- end_datetime: {
7998
- ...SCHEMA_DATETIME_MINUTE,
7999
- description: "\u7ED3\u675F\u65F6\u95F4\uFF08yyyy-MM-dd HH:mm\uFF09\uFF1B\u4E0D\u4F20\u5219\u6309 durationMinutes \u4ECE\u5F00\u59CB\u65F6\u95F4\u63A8\u7B97\uFF08\u9ED8\u8BA4 60 \u5206\u949F\uFF09"
8000
- },
8001
- mt_desc: { type: "string", description: "\u4F1A\u8BAE\u5185\u5BB9/\u8BF4\u660E" },
8002
- address: { type: "string", description: "\u4F1A\u8BAE\u5BA4\uFF08id \u6216\u540D\u79F0\uFF1B\u4E0D\u4F20\u5219\u8FD4\u56DE\u5019\u9009\u8BA9\u7528\u6237\u9009\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u51B3\u5B9A\uFF09" },
8003
- customize_address: { type: "string", description: "\u81EA\u5B9A\u4E49\u4F1A\u8BAE\u5730\u70B9" },
8004
- hrm_members: { type: "string", description: "\u53C2\u4F1A\u4EBA\u5458 id\uFF0C\u9017\u53F7\u5206\u9694" },
8005
- total_member: { type: "number", description: "\u53C2\u4F1A\u4EBA\u6570" },
8006
- caller: { type: "string", description: "\u53EC\u96C6\u4EBA\uFF08\u5458\u5DE5 id \u6216\u59D3\u540D\uFF09\u3002\u7F3A\u7701 = \u5F53\u524D\u767B\u5F55\u4EBA\uFF0C\u4E0D\u7528\u4F20\uFF1B\u53EA\u6709\u6307\u5B9A\u522B\u4EBA\u5F53\u53EC\u96C6\u4EBA\u624D\u4F20" },
8007
- contacter: { type: "string", description: "\u8054\u7CFB\u4EBA\uFF08\u5458\u5DE5 id \u6216\u59D3\u540D\uFF09\u3002\u7F3A\u7701 = \u5F53\u524D\u767B\u5F55\u4EBA\uFF0C\u4E0D\u7528\u4F20\uFF1B\u53EA\u6709\u6307\u5B9A\u522B\u4EBA\u5F53\u8054\u7CFB\u4EBA\u624D\u4F20" },
8008
- mt_type: {
8009
- type: "string",
8010
- description: "\u4F1A\u8BAE\u7C7B\u578B\uFF1A\u53EF\u4F20\u7C7B\u578B\u540D\u79F0\u6216 id\uFF08\u5148\u7528 `meeting.eb.type.list` \u67E5\u6709\u54EA\u4E9B\uFF09\u3002**\u5F88\u591A\u79DF\u6237\u7684\u6D41\u7A0B\u8868\u5355\u628A\u300C\u4F1A\u8BAE\u7C7B\u578B\u300D\u8BBE\u4E3A\u5FC5\u586B**\uFF0C\u4E0D\u4F20\u4F1A\u88AB `workflow.createRequest` \u6253\u56DE\u7F3A\u5B57\u6BB5"
8011
- },
8012
- other_remark: { type: "string", description: "\u5907\u6CE8" },
8013
- workflowId: {
8014
- oneOf: [{ type: "string" }, { type: "array", items: { type: "string" } }],
8015
- description: "\u6307\u5B9A\u5EFA\u4F1A\u6D41\u7A0B id\uFF08\u5355\u4E2A / \u6570\u7EC4 / \u9017\u53F7\u5206\u9694\uFF09\u3002\u4F20\u591A\u4E2A\u65F6\u4E0D\u4F1A\u66FF\u4F60\u9009\uFF1A\u4F1A\u8FD4\u56DE NEEDS_SELECTION \u8BA9\u7528\u6237\u6311"
8016
- },
8017
- autoRoom: { type: "boolean", description: "\u9ED8\u8BA4 false\uFF1A\u4E0D\u6307\u5B9A\u4F1A\u8BAE\u5BA4\u65F6\u8FD4\u56DE\u5019\u9009\u8BA9\u7528\u6237\u9009\uFF1B\u4F20 true \u624D\u81EA\u52A8\u91C7\u7528\u63A8\u8350\u4F1A\u8BAE\u5BA4" },
8018
- allowNoRoom: { type: "boolean", description: "\u786E\u5B9E\u4E0D\u9700\u8981\u4F1A\u8BAE\u5BA4\uFF08\u7EBF\u4E0A\u4F1A\u7B49\uFF09\u65F6\u4F20 true" },
8019
- timeConfirmed: {
8020
- type: "boolean",
8021
- description: '\u65F6\u95F4\u7684"\u7528\u6237\u5DF2\u786E\u8BA4"\u6807\u8BB0\uFF1A\u7528\u6237\u539F\u8BDD\u660E\u786E\u7ED9\u4E86\u65F6\u95F4\u3001\u6216\u5728\u65F6\u6BB5\u9009\u9879\u91CC\u70B9\u9009\u540E\u539F\u6837\u56DE\u4F20 value\uFF08\u81EA\u5E26\u6807\u8BB0\uFF09\u65F6\u624D\u4F20 true\uFF1B\u4E0D\u4F20 = \u672A\u786E\u8BA4\uFF0CCLI \u4F1A\u8FD4\u56DE\u65F6\u6BB5\u9009\u9879\u8BA9\u7528\u6237\u70B9\u9009'
8022
- },
8023
- roomConfirmed: {
8024
- type: "boolean",
8025
- description: '\u4F1A\u8BAE\u5BA4\u7684"\u7528\u6237\u5DF2\u786E\u8BA4"\u6807\u8BB0\uFF1A\u7528\u6237\u539F\u8BDD\u660E\u786E\u6307\u5B9A\u3001\u6216\u5728\u623F\u95F4\u9009\u9879\u91CC\u70B9\u9009\u540E\u539F\u6837\u56DE\u4F20 value\uFF08\u81EA\u5E26\u6807\u8BB0\uFF09\u65F6\u624D\u4F20 true\uFF1B\u4E0D\u4F20 = \u672A\u786E\u8BA4\uFF0CCLI \u4F1A\u628A\u6307\u5B9A\u623F\u95F4\u548C\u5019\u9009\u4E00\u8D77\u5217\u51FA\u6765\u8BA9\u7528\u6237\u70B9\u9009'
8026
- },
8027
- confirm: { type: "boolean", description: "\u5FC5\u987B\u663E\u5F0F true \u624D\u4F1A\u771F\u6B63\u63D0\u4EA4" },
8028
- waitSeconds: { type: "number", description: "\u63D0\u4EA4\u540E\u7B49\u5F85\u4F1A\u8BAE\u751F\u6210\u7684\u79D2\u6570\uFF08\u9ED8\u8BA4 20\uFF1B\u7B97\u6CD5\u662F\u7ACB\u5373\u67E5\u4E00\u6B21 + 5s \u518D\u67E5\u4E00\u6B21\uFF0C\u4ECD\u672A\u751F\u6210\u5C31\u8FD4\u56DE pending\uFF09" },
8029
- enrich: { type: "boolean", description: "\u662F\u5426\u987A\u5E26\u505A\u4F1A\u8BAE\u5BA4\u63A8\u8350/\u51B2\u7A81\u68C0\u6D4B/\u7A7A\u95F2\u65F6\u6BB5\uFF08\u9ED8\u8BA4 true\uFF1B\u4EBA\u3001\u65F6\u95F4\u3001\u623F\u95F4\u90FD\u5DF2\u786E\u5B9A\u65F6\u4F20 false \u53EF\u663E\u8457\u52A0\u5FEB\uFF09" },
8030
- extraFields: {
8031
- type: "object",
8032
- description: '\u6309\u6D41\u7A0B\u8868\u5355\u5B57\u6BB5\u540D\u586B\u989D\u5916\u5B57\u6BB5\uFF08\u79DF\u6237\u81EA\u5EFA\u5B57\u6BB5\u7528\u8FD9\u4E2A\u53E3\u5B50\u5E26\u8FDB\u53BB\uFF09\uFF0C\u5F62\u5982 {"\u53C2\u4F1A\u5BA2\u6237": "xx\u516C\u53F8"}'
8033
- },
8034
- dateFrom: {
8035
- type: "string",
8036
- description: "\u6CA1\u7ED9\u5177\u4F53\u65F6\u95F4\u65F6\u6309\u54EA\u4E00\u5929\u63A8\u8350\u65F6\u6BB5\uFF08yyyy-MM-dd\uFF1B\u4E0D\u4F20\u9ED8\u8BA4\u660E\u5929\uFF09"
8037
- },
8038
- durationMinutes: {
8039
- type: "number",
8040
- description: "\u4F1A\u8BAE\u65F6\u957F\uFF08\u5206\u949F\uFF0C\u9ED8\u8BA4 60\uFF09\uFF1A\u53EA\u7ED9\u4E86\u5F00\u59CB\u65F6\u95F4\u65F6\u7528\u6765\u7B97\u7ED3\u675F\u65F6\u95F4\uFF1B\u63A8\u8350\u65F6\u6BB5\u65F6\u4E5F\u6309\u8FD9\u4E2A\u65F6\u957F\u627E"
8041
- },
8042
- workStartHour: { type: "number", description: "\u63A8\u8350\u65F6\u6BB5\u7684\u6700\u65E9\u5C0F\u65F6\uFF08\u9ED8\u8BA4 9\uFF09" },
8043
- workEndHour: { type: "number", description: "\u63A8\u8350\u65F6\u6BB5\u7684\u6700\u665A\u5C0F\u65F6\uFF08\u9ED8\u8BA4 18\uFF09" },
8044
- fieldValues: {
8045
- type: "object",
8046
- additionalProperties: true,
8047
- description: '\u6309**\u8868\u5355\u5B57\u6BB5 datakey\uFF08fieldId\uFF09**\u76F4\u63A5\u7ED9\u503C\uFF0C\u5F62\u5982 {"1325677252711735881": "\u7814\u8BA8\u4F1A"}\uFF1B\u4F18\u5148\u7EA7\u6700\u9AD8\uFF0C\u9002\u5408\u5B57\u6BB5\u540D\u5E26\u63D0\u793A\u8BED\u6216\u79DF\u6237\u81EA\u5EFA\u5B57\u6BB5\u3002datakey \u89C1 prepare \u7684 preview.mapped'
8048
- },
8049
- flowChoice: {
8050
- type: "string",
8051
- enum: ["auto", "ask"],
8052
- description: "\u591A\u4E2A\u5EFA\u4F1A\u6D41\u7A0B**\u90FD\u6709\u53D1\u8D77\u6743\u9650**\u65F6\uFF1A\u9ED8\u8BA4\uFF08\u4E0D\u4F20 / ask\uFF09= \u8FD4\u56DE\u9009\u9879\u8BA9\u7528\u6237\u6311\uFF1Bauto = \u81EA\u52A8\u53D6\u4F18\u5148\u7EA7\u6700\u9AD8\u7684\u3002\u53EA\u6709 1 \u4E2A\u6709\u6743\u9650\u65F6\u76F4\u63A5\u53D1\u8D77"
8053
- },
8054
- crm_skip: {
8055
- type: "boolean",
8056
- description: "\u663E\u5F0F\u58F0\u660E\u300C\u8FD9\u6B21\u4E0D\u586B\u53C2\u4F1A\u5BA2\u6237\u300D\u3002\u4F1A\u8BAE\u540D\u79F0/\u5185\u5BB9\u91CC\u51FA\u73B0 `\u5BA2\u6237\uFF1AX`\u3001`\u5BA2\u6237\u662FX` \u8FD9\u7C7B\u5B57\u6837\u5374**\u6CA1\u4F20 `crm_members`**\u65F6\uFF0C\u4E00\u6B65\u5EFA\u4F1A\u4F1A\u76F4\u63A5\u62D2\u7EDD\uFF08crm_member_required\uFF09\u2014\u2014\u786E\u8BA4\u8FD9\u4E9B\u5B57\u6837\u4E0D\u662F\u8981\u4E0A\u4F1A\u8868\u7684\u5BA2\u6237\uFF0C\u624D\u4F20 true"
8057
- },
8058
- submit_mode: {
8059
- type: "string",
8060
- enum: ["direct", "browser"],
8061
- description: '\u63D0\u4EA4\u65B9\u5F0F\uFF0C\u9ED8\u8BA4 browser\uFF1A\u5728\u5C0Fe \u91CC**\u5F39\u51FA\u6D41\u7A0B\u8868\u5355**\uFF08\u5B57\u6BB5\u5DF2\u9884\u586B\u542B\u4EBA\u5458/\u5BA2\u6237\uFF09\uFF0C\u7528\u6237\u6838\u5BF9\u4FEE\u6539\u540E\u81EA\u5DF1\u70B9\u63D0\u4EA4\u3002direct = \u76F4\u63A5\u5199\u670D\u52A1\u7AEF\uFF08\u4F1A\u8BAE\u5F53\u573A\u751F\u6210\u3001\u9080\u8BF7\u51FD\u7528\u771F\u5B9E\u6570\u636E\uFF0C\u4F46\u6CA1\u6709\u4EBA\u5DE5\u6838\u5BF9\u8868\u5355\u8FD9\u4E00\u6B65\uFF09\uFF1B\u53EA\u6709\u7528\u6237\u660E\u786E\u8BF4"\u4E0D\u7528\u6211\u786E\u8BA4\uFF0C\u76F4\u63A5\u5EFA"\u65F6\u624D\u4F20 direct'
8062
- }
8063
- },
8064
- { required: ["mt_name", "confirm"] }
8065
- ),
8066
- handler: async (args, env) => {
8067
- if (args.confirm !== true) {
8068
- throw meetingValidationError(
8069
- "confirmation_required",
8070
- "\u4E00\u6B65\u5EFA\u4F1A\u4F1A\u76F4\u63A5\u63D0\u4EA4\u6D41\u7A0B\uFF0C\u5FC5\u987B\u663E\u5F0F\u4F20 confirm=true\uFF1B\u5982\u53EA\u60F3\u770B\u65B9\u6848\uFF0C\u8BF7\u7528 meeting.eb.meeting.create.flow.prepare"
8071
- );
8072
- }
8073
- const crmMentioned = detectCrmMentionInText(args.mt_name, args.mt_desc, args.other_remark);
8074
- const crmSkipped = args.crm_skip === true;
8075
- if (crmMentioned && !args.crm_members && !crmSkipped) {
8076
- throw meetingValidationError(
8077
- "crm_member_required",
8078
- `\u4F1A\u8BAE\u540D\u79F0/\u5185\u5BB9\u91CC\u63D0\u5230\u5BA2\u6237\u300C${crmMentioned}\u300D\uFF0C\u4F46\u6CA1\u4F20 crm_members \u2014\u2014 \u63D0\u4EA4\u540E\u300C\u53C2\u4F1A\u5BA2\u6237\u300D\u4F1A\u662F\u7A7A\u7684\u3002\u5148 meeting.eb.crm.search {"keyword":"${crmMentioned}"} \u62FF items[].customerId\uFF0C\u518D\u628A crm_members:[{"id":"<customerId>","name":"<\u5B8C\u6574\u5BA2\u6237\u540D>"}] \u4E00\u8D77\u4F20\uFF08\u5FC5\u987B\u5E26\u540D\u79F0\uFF0C\u53EA\u7ED9 id \u4F1A\u88AB\u9759\u9ED8\u5B58\u7A7A\uFF09\uFF1B\u786E\u5B9E\u4E0D\u9700\u8981\u586B\u53C2\u4F1A\u5BA2\u6237\u5C31\u4F20 crm_skip:true\u3002`
8079
- );
8080
- }
8081
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
8082
- const prepareStartedAt = Date.now();
8083
- const { submit_mode: _submitMode, confirm: _confirm, ...prepareArgs } = args;
8084
- const prepared = await getMeetingOperation2("meeting.eb.meeting.create.flow.prepare").handler(
8085
- // submit_mode 只属于提交阶段,prepare 的 schema 不接受它(additionalProperties:false)
8086
- prepareArgs,
8087
- env
8088
- );
8089
- if (prepared?.data?.status === "NEEDS_SELECTION") {
8090
- return prepared;
8091
- }
8092
- const continuation = String(prepared?.data?.continuation ?? "");
8093
- if (!continuation) {
8094
- throw meetingValidationError("flow_prepare_failed", "\u5EFA\u4F1A\u6D41\u7A0B\u51C6\u5907\u9636\u6BB5\u6CA1\u6709\u8FD4\u56DE\u786E\u8BA4\u7968\u636E\uFF0C\u672A\u63D0\u4EA4");
8095
- }
8096
- const prepareMs = Date.now() - prepareStartedAt;
8097
- const applyStartedAt = Date.now();
8098
- const applied = await getMeetingOperation2("meeting.eb.meeting.create.flow.apply").handler(
8099
- {
8100
- continuation,
8101
- confirm: true,
8102
- ...args.submit_mode ? { submit_mode: args.submit_mode } : {},
8103
- ...args.waitSeconds !== void 0 ? { waitSeconds: args.waitSeconds } : {}
8104
- },
8105
- env
8106
- );
8107
- const warnings = [
8108
- ...prepared?.warnings ?? [],
8109
- ...applied?.warnings ?? []
8110
- ];
8111
- return meetingSuccess(
8112
- "meeting.eb.meeting.create.flow.quick",
8113
- {
8114
- status: applied?.data?.status ?? "COMPLETE",
8115
- workflowId: applied?.data?.workflowId,
8116
- requestId: applied?.data?.requestId,
8117
- meetingId: applied?.data?.meetingId ?? null,
8118
- invitation: applied?.data?.invitation ?? null,
8119
- // 已提交内容回显(字段名 → 值),提交后可直接贴给用户看"到底填进去了什么"
8120
- submittedPreview: applied?.data?.submittedPreview ?? null,
8121
- // 小e 环境(BROWSER_FILL)不写服务端,表单靠这段 <browsertool> 在浏览器里填 —— 必须一起透出,
8122
- // 否则宿主拿不到表单,用户看到的就是"提交了但没反应"。
8123
- ...applied?.data?.contextId ? { contextId: (applied?.data).contextId } : {},
8124
- ...applied?.data?.finalMarkdown ? { finalMarkdown: (applied?.data).finalMarkdown } : {},
8125
- decisions: prepared?.data?.preview?.decisions ?? null,
8126
- timings: {
8127
- ...prepared?.data?.preview?.decisions?.timings ?? {},
8128
- // apply 侧的分段耗时(提交/轮询/邀请函)也要带出来,否则"到底慢在哪"还是看不清
8129
- ...applied?.data?.timings ?? {},
8130
- prepareMs,
8131
- applyMs: Date.now() - applyStartedAt,
8132
- totalMs: Date.now() - prepareStartedAt
8133
- }
8134
- },
8135
- warnings.length > 0 ? { warnings } : {}
8136
- );
8137
- }
8138
- };
8139
- var ebMeetingCreateSuggest = {
8140
- name: "meeting.eb.meeting.create.suggest",
8141
- resource: "eb",
8142
- method: "meeting.eb.meeting.create.suggest",
8143
- action: "meeting.eb.meeting.create.suggest",
8144
- summary: "\u5EFA\u4F1A\u5EFA\u8BAE\uFF1A\u7ED9\u5B9A\u65E5\u671F\u8303\u56F4\u4E0E\u53C2\u4F1A\u4EBA\uFF0C\u63A8\u8350\u300C\u6240\u6709\u4EBA\u90FD\u7A7A\u95F2 + \u8BE5\u65F6\u6BB5\u6709\u53EF\u7528\u4F1A\u8BAE\u5BA4\u300D\u7684\u65F6\u95F4\u5019\u9009\uFF08\u53EA\u8BFB\uFF0C\u4E0D\u5EFA\u4F1A\uFF09",
8145
- capability: "eb.meeting",
8146
- risk: "read",
8147
- inputSchema: schemaOf(
8148
- {
8149
- dateFrom: { type: "string", description: "\u8D77\u59CB\u65E5\u671F\uFF08\u5FC5\u586B\uFF0Cyyyy-MM-dd\uFF09" },
8150
- dateTo: { type: "string", description: "\u7ED3\u675F\u65E5\u671F\uFF08\u53EF\u9009\uFF0C\u9ED8\u8BA4\u540C dateFrom\uFF1B\u6700\u591A\u8DE8 14 \u5929\uFF09" },
8151
- durationMinutes: { type: "number", description: "\u4F1A\u8BAE\u65F6\u957F\uFF08\u5206\u949F\uFF0C\u9ED8\u8BA4 60\uFF09" },
8152
- hrm_members: { type: "string", description: "\u53C2\u4F1A\u4EBA\u5458\uFF08\u5FC5\u586B\uFF0C\u5458\u5DE5 id \u6216\u59D3\u540D\uFF0C\u9017\u53F7\u5206\u9694\uFF1B\u59D3\u540D\u4F1A\u81EA\u52A8\u53CD\u67E5 id\uFF09" },
8153
- memberCount: { type: "number", description: "\u53C2\u4F1A\u4EBA\u6570\uFF08\u53EF\u9009\uFF0C\u7528\u4E8E\u4F1A\u8BAE\u5BA4\u5BB9\u91CF\u7B5B\u9009\uFF1B\u4E0D\u4F20\u5219\u6309 hrm_members \u4E2A\u6570\uFF09" },
8154
- workStartHour: { type: "number", description: "\u53EA\u5728\u51E0\u70B9\u4EE5\u540E\u627E\uFF08\u9ED8\u8BA4 9\uFF09" },
8155
- workEndHour: { type: "number", description: "\u53EA\u5728\u51E0\u70B9\u4EE5\u524D\u627E\uFF08\u9ED8\u8BA4 18\uFF09" },
8156
- maxSlots: { type: "number", description: "\u6700\u591A\u7ED9\u51E0\u4E2A\u65F6\u95F4\u5019\u9009\uFF08\u9ED8\u8BA4 3\uFF0C\u6700\u5927 8\uFF09" },
8157
- topN: { type: "number", description: "\u6BCF\u4E2A\u65F6\u95F4\u5019\u9009\u6700\u591A\u5E26\u51E0\u95F4\u4F1A\u8BAE\u5BA4\uFF08\u9ED8\u8BA4 3\uFF09" },
8158
- includeSchedule: { type: "boolean", description: "\u662F\u5426\u628A\u65E5\u7A0B\uFF08ESB\uFF09\u4E5F\u7B97\u8FDB\u5360\u7528\uFF08\u9ED8\u8BA4 true\uFF09" }
8159
- },
8160
- { required: ["dateFrom", "hrm_members"] }
8161
- ),
8162
- handler: async (args, env) => {
8163
- const dateFrom = String(args.dateFrom ?? "").trim().slice(0, 10);
8164
- if (!/^\d{4}-\d{2}-\d{2}$/.test(dateFrom)) {
8165
- throw meetingValidationError("datetime_invalid", `dateFrom \u5FC5\u987B\u662F yyyy-MM-dd\uFF0C\u6536\u5230\u300C${String(args.dateFrom ?? "")}\u300D`);
8166
- }
8167
- const dateTo = String(args.dateTo ?? "").trim().slice(0, 10) || dateFrom;
8168
- if (!/^\d{4}-\d{2}-\d{2}$/.test(dateTo)) {
8169
- throw meetingValidationError("datetime_invalid", `dateTo \u5FC5\u987B\u662F yyyy-MM-dd\uFF0C\u6536\u5230\u300C${String(args.dateTo ?? "")}\u300D`);
8170
- }
8171
- const durationMinutes = Number(args.durationMinutes) > 0 ? Number(args.durationMinutes) : 60;
8172
- const maxSlots = Math.max(1, Math.min(8, Number(args.maxSlots) || 3));
8173
- const topN = Math.max(1, Math.min(5, Number(args.topN) || 3));
8174
- const rawMembers = String(args.hrm_members ?? "").split(/[,;,;\s]+/).map((item) => item.trim()).filter((item) => item !== "");
8175
- const nameLike = rawMembers.filter((item) => !/^\d+$/.test(item));
8176
- const nameToId = nameLike.length > 0 ? await import("./schedule-UASAVDVD.js").then((m) => m.resolveMemberIdsByName(env, nameLike)).catch(() => /* @__PURE__ */ new Map()) : /* @__PURE__ */ new Map();
8177
- const memberIds = rawMembers.map((item) => nameToId.get(item) ?? item);
8178
- const unresolved = rawMembers.filter((item) => nameToId.get(item) === void 0 && !/^\d+$/.test(item));
8179
- const selfId = await env.host.getSession().then((s) => String(s?.userId ?? "")).catch(() => "");
8180
- const selfIncluded = selfId !== "" && memberIds.includes(selfId);
8181
- const memberCount = Number(args.memberCount) > 0 ? Number(args.memberCount) : memberIds.length > 0 ? memberIds.length + (selfIncluded ? 0 : 1) : void 0;
8182
- const warnings = [];
8183
- if (unresolved.length > 0) {
8184
- warnings.push(`\u26A0\uFE0F \u8FD9\u4E9B\u53C2\u4F1A\u4EBA\u6CA1\u67E5\u5230\u5458\u5DE5 id\uFF1A${unresolved.join("\u3001")} \u2014\u2014 \u5DF2\u8DF3\u8FC7\uFF0C\u5176\u7A7A\u95F2\u60C5\u51B5**\u672A\u6838\u9A8C**`);
8185
- }
8186
- const free = await findCommonFreeSlots(env, {
8187
- rangeStart: `${dateFrom} 00:00`,
8188
- rangeEnd: `${dateTo} 23:59`,
8189
- durationMinutes,
8190
- members: memberIds,
8191
- maxSlots,
8192
- maxDays: 14,
8193
- includeSchedule: args.includeSchedule !== false,
8194
- ...args.workStartHour !== void 0 ? { workStartHour: Number(args.workStartHour) } : {},
8195
- ...args.workEndHour !== void 0 ? { workEndHour: Number(args.workEndHour) } : {}
8196
- });
8197
- await loadRooms(env, { refresh: true }).catch(() => null);
8198
- const withRooms = await Promise.all((free.slots ?? []).map(async (slot) => {
8199
- try {
8200
- const rec = await recommendRooms(env, {
8201
- beginDatetime: slot.begin,
8202
- endDatetime: slot.end,
8203
- ...memberCount ? { memberCount } : {},
8204
- topN
8205
- });
8206
- return {
8207
- begin: slot.begin,
8208
- end: slot.end,
8209
- rooms: rec.candidates.map((candidate) => ({
8210
- id: candidate.id,
8211
- name: candidate.name,
8212
- capacityMax: candidate.capacity.max,
8213
- reasons: candidate.reasons
8214
- }))
8215
- };
8216
- } catch {
8217
- return { begin: slot.begin, end: slot.end, rooms: [] };
8218
- }
8219
- }));
8220
- const usable = withRooms.filter((slot) => slot.rooms.length > 0);
8221
- if (usable.length === 0) {
8222
- const why = (free.slots ?? []).length === 0 ? "\u8BE5\u8303\u56F4\u5185\u6240\u6709\u53C2\u4F1A\u4EBA\u6CA1\u6709\u5171\u540C\u7684\u7A7A\u95F2\u65F6\u6BB5" : `${(free.slots ?? []).length} \u4E2A\u300C\u4EBA\u7A7A\u95F2\u300D\u7684\u65F6\u6BB5\u91CC\uFF0C\u6CA1\u6709\u4E00\u4E2A\u8FD8\u80FD\u8BA2\u5230\u4F1A\u8BAE\u5BA4`;
8223
- warnings.push(
8224
- `\u6CA1\u627E\u5230\u540C\u65F6\u6EE1\u8DB3\u300C\u4EBA\u5458\u7A7A\u95F2 + \u4F1A\u8BAE\u5BA4\u7A7A\u95F2\u300D\u7684\u65F6\u95F4\u5019\u9009\uFF1A${why}\u3002\u8BF7\u5982\u5B9E\u544A\u77E5\u7528\u6237\uFF0C\u5E76\u5EFA\u8BAE\u6362\u4E2A\u65E5\u671F\u8303\u56F4\u3001\u7F29\u77ED\u65F6\u957F\uFF0C\u6216\u6539\u4E3A\u7EBF\u4E0A\u4F1A\u8BAE\uFF08allowNoRoom: true\uFF09\u3002`
8225
- );
8226
- if (free.blockingSummary) warnings.push(`\u5F53\u5929\u5360\u7528\u6982\u51B5\uFF1A${free.blockingSummary}`);
8227
- }
8228
- return meetingSuccess(
8229
- "meeting.eb.meeting.create.suggest",
8230
- {
8231
- dateFrom,
8232
- dateTo,
8233
- durationMinutes,
8234
- // 同样是"让用户点一下":时段候选用选项控件呈现,别写成文本列表
8235
- ui: { component: "choice", multiple: false, recommendedKey: "T1" },
8236
- slots: usable.map((slot, index) => ({
8237
- key: `T${index + 1}`,
8238
- label: `${slot.begin.slice(5, 10)} ${slot.begin.slice(11)}~${slot.end.slice(11)}`,
8239
- value: { begin: slot.begin, end: slot.end, address: slot.rooms[0]?.id ?? null },
8240
- reason: `${memberCount ? `${memberCount} \u4EBA\u5168\u90E8\u7A7A\u95F2\uFF08\u4F1A\u8BAE\u56DE\u6267 + \u65E5\u7A0B\u5DF2\u6838\uFF09\uFF1B` : ""}${slot.rooms.length} \u95F4\u4F1A\u8BAE\u5BA4\u53EF\u7528\uFF1A${slot.rooms.map((room) => room.name).join("\u3001")}`,
8241
- rooms: slot.rooms
8242
- })),
8243
- // 把"人空闲但没房间"的时段也带出来,方便调用方解释为什么被剔除
8244
- skippedSlots: withRooms.filter((slot) => slot.rooms.length === 0),
8245
- memberIds,
8246
- scheduleItems: free.scheduleItems,
8247
- idle: free.idle,
8248
- cost: free.cost
8249
- },
8250
- warnings.length > 0 ? { warnings } : {}
8251
- );
8252
- }
8253
- };
8254
- var meetingEbCreateFlowOperations = [
8255
- ebMeetingCreateSuggest,
8256
- ebMeetingCreateFlowPrepare,
8257
- ebMeetingCreateFlowApply,
8258
- ebMeetingCreateFlowQuick
8259
- ];
8260
-
8261
6168
  // src/shortcuts/meeting/operations/eb/index.ts
8262
6169
  var ebAutoRoomPreflight = async (context) => {
8263
6170
  const { extras } = context;
@@ -8345,7 +6252,7 @@ var ebAutoInvitationAfterWrite = async (context) => {
8345
6252
  const mtId = String(context.dataIds?.[0] ?? "").trim();
8346
6253
  if (!isCreate || !enabled || !mtId) return association;
8347
6254
  try {
8348
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
6255
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-BKBZPBAJ.js");
8349
6256
  const render = getMeetingOperation2("meeting.invitation.render");
8350
6257
  const result = await render.handler({ mtId }, context.env);
8351
6258
  return { ...association ?? {}, invitation: result?.data ?? null };
@@ -8370,6 +6277,7 @@ var meetingEbOperations = [
8370
6277
  ...meetingEbScheduleOperations,
8371
6278
  ...meetingEbCrmOperations,
8372
6279
  ...meetingEbCreateFlowOperations,
6280
+ ...meetingEbGroupChatOperations,
8373
6281
  ebRoomRecommendOperation
8374
6282
  ];
8375
6283