weaver-work-cli 0.1.36 → 0.1.39

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 (169) hide show
  1. package/README.md +4 -2
  2. package/dist/chunks/{archive-XBVH7JU7.js → archive-ENZYBBME.js} +559 -68
  3. package/dist/chunks/{archive-oa-MZM3EKFQ.js → archive-oa-YWLEC5V4.js} +4 -3
  4. package/dist/chunks/{asset-4XO7UOUW.js → asset-OOV6DWPA.js} +8 -7
  5. package/dist/chunks/asset-idle-RE632MY5.js +670 -0
  6. package/dist/chunks/{attachment-content-VXSWANAC.js → attachment-content-RWN2FCLL.js} +3 -3
  7. package/dist/chunks/{blog-PGZKOPSC.js → blog-PEPOJAL7.js} +5 -4
  8. package/dist/chunks/{caizhilian-BH4ZVGUN.js → caizhilian-WYIQDVPJ.js} +5 -4
  9. package/dist/chunks/{calendar-MXEMTIO4.js → calendar-CIARBAOX.js} +4 -3
  10. package/dist/chunks/{chunk-NCOVUAZK.js → chunk-36DIFZAH.js} +4 -3
  11. package/dist/chunks/{chunk-I6QGIBDM.js → chunk-BJGXMFGD.js} +4 -3
  12. package/dist/chunks/{chunk-TC6MZAO3.js → chunk-CQHGNCK2.js} +52 -2
  13. package/dist/chunks/{chunk-WXFPWCXG.js → chunk-EINRJHQ3.js} +3 -3
  14. package/dist/chunks/{chunk-JUXVYKII.js → chunk-EZGFHJFW.js} +201 -19
  15. package/dist/chunks/{chunk-VPUTVEMC.js → chunk-F2EQXUEE.js} +436 -290
  16. package/dist/chunks/{chunk-JYKABYCV.js → chunk-GVPJZXJ2.js} +3 -3
  17. package/dist/chunks/{chunk-6LLJFKJE.js → chunk-HJYVHXUQ.js} +1 -1
  18. package/dist/chunks/{chunk-T72N74ZT.js → chunk-I2HB737U.js} +5 -4
  19. package/dist/chunks/{chunk-VPXOPQJI.js → chunk-K3RUEEOL.js} +4 -2
  20. package/dist/chunks/{chunk-HXJQI5NM.js → chunk-KTCB5R5H.js} +3 -2
  21. package/dist/chunks/{chunk-XMGSYD6S.js → chunk-L4N7B7ZD.js} +4 -4
  22. package/dist/chunks/{chunk-QYGO5EE2.js → chunk-MUQUHKPG.js} +4 -3
  23. package/dist/chunks/{chunk-QHFANTX7.js → chunk-NLK2RZKG.js} +1348 -90
  24. package/dist/chunks/{chunk-F746NKNF.js → chunk-P2DAISYW.js} +1 -1
  25. package/dist/chunks/{chunk-BPE37FPB.js → chunk-T7JDJJ7H.js} +3 -3
  26. package/dist/chunks/{chunk-JNG42JKG.js → chunk-XXJOSZTQ.js} +6 -6
  27. package/dist/chunks/{chunk-5DQEEGCC.js → chunk-YS5DPN4T.js} +1 -1
  28. package/dist/chunks/{chunk-EG6ZU444.js → chunk-ZUX3P6BQ.js} +10 -5
  29. package/dist/chunks/{chunk-JCSN3JGM.js → chunk-ZXRNHZTE.js} +7 -6
  30. package/dist/chunks/{conflict-JAB2LJEZ.js → conflict-DRMDOL56.js} +2 -2
  31. package/dist/chunks/{contract-XI2EEIZU.js → contract-73MERZWN.js} +4 -3
  32. package/dist/chunks/{cowork-SCPGLBA4.js → cowork-HNGBPD7A.js} +4 -3
  33. package/dist/chunks/{ebuilder-form-EYLHNOTA.js → ebuilder-form-OY6DVNRK.js} +3 -3
  34. package/dist/chunks/{ehr-EAP77IMT.js → ehr-RAQNEQO7.js} +4 -3
  35. package/dist/chunks/{esb-2TGGXEE7.js → esb-6XV7C7YV.js} +4 -4
  36. package/dist/chunks/{fna-2X7ZE7BU.js → fna-XTSRB7G7.js} +4 -3
  37. package/dist/chunks/{host-Q4LZGCRU.js → host-3F5UM5GN.js} +3 -3
  38. package/dist/chunks/{host-XCLDDXKQ.js → host-A7J6GDUP.js} +3 -3
  39. package/dist/chunks/{host-I4NRK4MX.js → host-VGPVP7YF.js} +3 -3
  40. package/dist/chunks/{host-C6EL2RKL.js → host-YAQAPYNP.js} +3 -3
  41. package/dist/chunks/{host-UEI5FGDM.js → host-YMBXWFWX.js} +3 -3
  42. package/dist/chunks/{hrm-YXERJM76.js → hrm-TLHKC545.js} +3 -3
  43. package/dist/chunks/{im-A4VZN2TQ.js → im-YOUCFMUK.js} +3 -3
  44. package/dist/chunks/{invoice-2Z6YPMIS.js → invoice-WNBS2B4C.js} +3 -3
  45. package/dist/chunks/{jiuchuanhui-AR5GMKZB.js → jiuchuanhui-XABWS5RN.js} +4 -3
  46. package/dist/chunks/{lazy-dispatch-QXW7P4X3.js → lazy-dispatch-NLZ5UQQI.js} +5 -5
  47. package/dist/chunks/{mail-7GZ6CPBJ.js → mail-LRYMBFNL.js} +4 -3
  48. package/dist/chunks/{meeting-3NMGA3MB.js → meeting-ESXL6MFI.js} +13 -12
  49. package/dist/chunks/{okr-BZ6XUOAG.js → okr-EOV65SSF.js} +4 -3
  50. package/dist/chunks/{plan-DR5CMUYP.js → plan-YFPVKW6Y.js} +4 -3
  51. package/dist/chunks/{project-6J63MK33.js → project-MDVZUYQW.js} +4 -3
  52. package/dist/chunks/{registry-VRTNC6UR.js → registry-QCLZEDAP.js} +8 -8
  53. package/dist/chunks/{registry-KDD7DHNK.js → registry-VT5Y2HLA.js} +4 -4
  54. package/dist/chunks/{registry-TKX2E7C7.js → registry-YX4CSEMD.js} +3 -3
  55. package/dist/chunks/{room-recommend-XCWRMB5P.js → room-recommend-L3MWH4JW.js} +4 -4
  56. package/dist/chunks/{schedule-IVBICP32.js → schedule-UASAVDVD.js} +4 -4
  57. package/dist/chunks/{workflow-D74NFK3C.js → workflow-KDGIUCNW.js} +9 -6
  58. package/dist/core/output.js +16 -6
  59. package/dist/index.js +33 -28
  60. package/dist/internal/e10/auth/messages.js +1 -0
  61. package/dist/internal/e10/auth-recovery.js +127 -7
  62. package/dist/internal/e10/client.js +16 -2
  63. package/dist/internal/e10/context.js +16 -3
  64. package/dist/internal/e10/request-runtime.js +106 -8
  65. package/dist/shortcuts/archive/host.js +5 -2
  66. package/dist/shortcuts/archive/manifest.js +1 -1
  67. package/dist/shortcuts/archive/operations/borrow-list.js +13 -1
  68. package/dist/shortcuts/archive/operations/flow-url.js +1 -1
  69. package/dist/shortcuts/archive/operations/prelib.js +472 -0
  70. package/dist/shortcuts/archive/operations/registry.js +2 -0
  71. package/dist/shortcuts/archive/operations/upload.js +1 -1
  72. package/dist/shortcuts/archive-oa/host.js +2 -1
  73. package/dist/shortcuts/asset/host.js +6 -5
  74. package/dist/shortcuts/asset-idle/errors.js +44 -0
  75. package/dist/shortcuts/asset-idle/host.js +161 -0
  76. package/dist/shortcuts/asset-idle/index.js +114 -0
  77. package/dist/shortcuts/asset-idle/manifest.js +159 -0
  78. package/dist/shortcuts/asset-idle/operations/idle.js +47 -0
  79. package/dist/shortcuts/asset-idle/operations/registry.js +33 -0
  80. package/dist/shortcuts/asset-idle/operations/shared.js +142 -0
  81. package/dist/shortcuts/asset-idle/operations/types.js +9 -0
  82. package/dist/shortcuts/asset-idle/operations.js +15 -0
  83. package/dist/shortcuts/blog/host.js +3 -2
  84. package/dist/shortcuts/caizhilian/host.js +3 -2
  85. package/dist/shortcuts/calendar/host.js +2 -1
  86. package/dist/shortcuts/contract/host.js +2 -1
  87. package/dist/shortcuts/cowork/host.js +2 -1
  88. package/dist/shortcuts/ebuilder-form/host.js +3 -1
  89. package/dist/shortcuts/ehr/host.js +2 -1
  90. package/dist/shortcuts/esb/host.js +2 -1
  91. package/dist/shortcuts/fna/host.js +2 -1
  92. package/dist/shortcuts/hrm/host.js +2 -1
  93. package/dist/shortcuts/im/host.js +3 -2
  94. package/dist/shortcuts/index.js +5 -0
  95. package/dist/shortcuts/invoice/host.js +5 -4
  96. package/dist/shortcuts/jiuchuanhui/host.js +2 -1
  97. package/dist/shortcuts/mail/host.js +2 -1
  98. package/dist/shortcuts/meeting/host.js +3 -2
  99. package/dist/shortcuts/meeting/invitation/text.js +71 -0
  100. package/dist/shortcuts/meeting/operations/eb/create-flow.js +1073 -50
  101. package/dist/shortcuts/meeting/operations/eb/crm-search.js +478 -0
  102. package/dist/shortcuts/meeting/operations/eb/factory.js +60 -1
  103. package/dist/shortcuts/meeting/operations/eb/index.js +2 -0
  104. package/dist/shortcuts/meeting/operations/invitation.js +122 -9
  105. package/dist/shortcuts/okr/host.js +2 -1
  106. package/dist/shortcuts/plan/host.js +2 -1
  107. package/dist/shortcuts/project/host.js +2 -1
  108. package/dist/shortcuts/workflow/host.js +3 -0
  109. package/dist/shortcuts/workflow/index.js +1 -1
  110. package/dist/shortcuts/workflow/operations/form.js +44 -11
  111. package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupRules.js +77 -26
  112. package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupStore.js +6 -0
  113. package/dist/shortcuts/workflow/operations/todoSmartConvert/summaryCache.js +59 -117
  114. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailCache.js +44 -7
  115. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailFetcher.js +37 -29
  116. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +20 -6
  117. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.detail.js +22 -18
  118. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +34 -10
  119. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +4 -2
  120. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +9 -2
  121. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +110 -20
  122. package/docs/_catalog.md +3 -0
  123. package/docs/asset-idle.md +45 -0
  124. package/docs/e10-auth.md +1 -1
  125. package/docs/todo-smart-convert/subgroup-rules.md +1 -1
  126. package/package.json +1 -1
  127. package/scripts/package-skill.mjs +2 -0
  128. package/skill-template/business-info.json +14 -1
  129. package/skill-template/domains/asset-idle.md +13 -0
  130. package/skill-template/domains/wenshuding.md +3 -0
  131. package/skills/weaver-e10-archive-oa/SKILL.md +1 -0
  132. package/skills/weaver-e10-archive-oa/references/my-borrow.md +49 -0
  133. package/skills/weaver-e10-asset-idle/SKILL.md +73 -0
  134. package/skills/weaver-e10-asset-idle/references/idle-list.md +62 -0
  135. package/skills/weaver-e10-asset-idle/references/idle-stats-and-charts.md +65 -0
  136. package/skills/weaver-e10-asset-idle/references/source-manifest.json +193 -0
  137. package/skills/weaver-e10-asset-idle/references/widget-style.md +205 -0
  138. package/skills/weaver-e10-caizhilian/SKILL.md +29 -11
  139. package/skills/weaver-e10-caizhilian/references/auth-and-install.md +12 -0
  140. package/skills/weaver-e10-caizhilian/references/files.md +1 -1
  141. package/skills/weaver-e10-caizhilian/references/setting-encrypt.md +1 -1
  142. package/skills/weaver-e10-caizhilian/references/source-manifest.json +45 -45
  143. package/skills/weaver-e10-cowork/SKILL.md +2 -0
  144. package/skills/weaver-e10-jucailin/SKILL.md +2 -0
  145. package/skills/weaver-e10-jucailin/references/recruit-read.md +2 -0
  146. package/skills/weaver-e10-jucailin/references/recruit-write.md +1 -1
  147. package/skills/weaver-e10-mail/SKILL.md +3 -0
  148. package/skills/weaver-e10-meeting/SKILL.md +250 -301
  149. package/skills/weaver-e10-meeting/references/meeting-eb.md +203 -0
  150. package/skills/weaver-e10-meeting/references/meeting-invitation.md +37 -5
  151. package/skills/weaver-e10-meeting.zip +0 -0
  152. package/skills/weaver-e10-okr/references/source-manifest.json +3 -3
  153. package/skills/weaver-e10-shared/SKILL.md +5 -5
  154. package/skills/weaver-e10-shared/references/e10-auth-and-session.md +3 -3
  155. package/skills/weaver-e10-wenshuding/SKILL.md +29 -6
  156. package/skills/weaver-e10-wenshuding/references/archive-borrow-list.md +14 -0
  157. package/skills/weaver-e10-wenshuding/references/archive-download.md +2 -0
  158. package/skills/weaver-e10-wenshuding/references/archive-flow.md +1 -1
  159. package/skills/weaver-e10-wenshuding/references/archive-prelib-arrange.md +76 -0
  160. package/skills/weaver-e10-wenshuding/references/archive-prelib-list.md +107 -0
  161. package/skills/weaver-e10-wenshuding/references/archive-prelib-open.md +59 -0
  162. package/skills/weaver-e10-wenshuding/references/archive-upload.md +4 -1
  163. package/skills/weaver-e10-wenshuding/references/source-manifest.json +108 -65
  164. package/skills/weaver-e10-workflow/SKILL.md +5 -2
  165. package/skills/weaver-e10-workflow/aigroup/default.json +154 -19
  166. package/skills/weaver-e10-workflow/references/todo-smart-convert.md +59 -27
  167. package/skills/weaver-e10-workflow/tools/todo-serve.cjs +113 -25
  168. package/skills/weaver-e10-workflow/tools/todo-summary.cjs +292 -42
  169. package/skills/weaver-e10-yimiaoban/references/source-manifest.json +3 -3
@@ -5,26 +5,27 @@ import {
5
5
  loadRooms,
6
6
  recommendRooms,
7
7
  rememberFrequentRoom
8
- } from "./chunk-BPE37FPB.js";
8
+ } from "./chunk-T7JDJJ7H.js";
9
9
  import {
10
10
  meetingEbScheduleOperations
11
- } from "./chunk-XMGSYD6S.js";
11
+ } from "./chunk-L4N7B7ZD.js";
12
12
  import {
13
13
  ebMeetingWritePreflight,
14
14
  fetchEbAppSettings,
15
15
  findCommonFreeSlots,
16
16
  meetingEbConflictOperations
17
- } from "./chunk-WXFPWCXG.js";
17
+ } from "./chunk-EINRJHQ3.js";
18
18
  import {
19
+ PENDING_MARK,
19
20
  listMeetingAttachments,
20
21
  meetingAttachmentContentOperations,
21
22
  renderDocx
22
- } from "./chunk-HXJQI5NM.js";
23
+ } from "./chunk-KTCB5R5H.js";
23
24
  import {
24
25
  meetingEnvOperations,
25
26
  meetingStateDir,
26
27
  resolveMeetingEnvMode
27
- } from "./chunk-5DQEEGCC.js";
28
+ } from "./chunk-YS5DPN4T.js";
28
29
  import {
29
30
  EB_BASE,
30
31
  EB_ENDPOINTS,
@@ -56,7 +57,7 @@ import {
56
57
  toIdString,
57
58
  verifyLease,
58
59
  writeBody
59
- } from "./chunk-TC6MZAO3.js";
60
+ } from "./chunk-CQHGNCK2.js";
60
61
 
61
62
  // src/shortcuts/meeting/operations/meetings.ts
62
63
  function overlapsDate(beginDatetime, endDatetime, date) {
@@ -2222,7 +2223,7 @@ var meetingAttachmentAttach = {
2222
2223
  if (mode === "append" && existingIds.length === 0) {
2223
2224
  existingIds.push(...beforeIds);
2224
2225
  }
2225
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
2226
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
2226
2227
  const list = getMeetingOperation2("meeting.eb.meeting.list");
2227
2228
  let fileId = incomingFileId;
2228
2229
  let name = String(args.name ?? "").trim();
@@ -2310,7 +2311,7 @@ function textOf(value) {
2310
2311
  return value === void 0 || value === null ? "" : String(value);
2311
2312
  }
2312
2313
  async function readMinute(env, id) {
2313
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
2314
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
2314
2315
  const detail = getMeetingOperation2("meeting.eb.minute.detail");
2315
2316
  const result = await detail.handler({ id }, env);
2316
2317
  const row = result?.data?.data;
@@ -2389,7 +2390,7 @@ var meetingMinuteWriteContent = {
2389
2390
  } else {
2390
2391
  statusReason = "\u4EC5\u6E05\u7A7A\u5185\u5BB9\uFF0C\u672A\u6539\u72B6\u6001";
2391
2392
  }
2392
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
2393
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
2393
2394
  const prepare = getMeetingOperation2("meeting.eb.minute.update.prepare");
2394
2395
  const apply = getMeetingOperation2("meeting.eb.minute.update.apply");
2395
2396
  const prepared = await prepare.handler({ id, mt_id: mtId, ...patch }, env);
@@ -2747,7 +2748,7 @@ var meetingMinuteFromGroupChat = {
2747
2748
  const mtId = textOf2(args.mt_id).trim();
2748
2749
  if (!mtId) throw meetingValidationError("mt_id_required", "\u5FC5\u987B\u63D0\u4F9B\u4F1A\u8BAE id\uFF08mt_id\uFF09");
2749
2750
  const pipeline = ["text", "minutes", "document"].includes(args.pipeline) ? args.pipeline : "text";
2750
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
2751
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
2751
2752
  const ctx = env.ctx;
2752
2753
  let stepStart = Date.now();
2753
2754
  const listed = await getMeetingOperation2("meeting.eb.meeting.list").handler(
@@ -2771,7 +2772,7 @@ var meetingMinuteFromGroupChat = {
2771
2772
  }
2772
2773
  mark("readMeeting", stepStart);
2773
2774
  const pullStart = Date.now();
2774
- const { createImHost } = await import("./host-Q4LZGCRU.js");
2775
+ const { createImHost } = await import("./host-3F5UM5GN.js");
2775
2776
  const { createImContinuationSigner } = await import("./continuation-2CKSBLA6.js");
2776
2777
  const { getImOperation } = await import("./registry-OZSMDVPP.js");
2777
2778
  const imEnv = { ctx, host: createImHost(ctx), continuation: createImContinuationSigner(ctx) };
@@ -2841,7 +2842,7 @@ var meetingMinuteFromGroupChat = {
2841
2842
  try {
2842
2843
  const { readFile: readFile5 } = await import("node:fs/promises");
2843
2844
  const buffer = await readFile5(file);
2844
- const { extractText } = await import("./attachment-content-VXSWANAC.js");
2845
+ const { extractText } = await import("./attachment-content-RWN2FCLL.js");
2845
2846
  const extracted = extractText(buffer, file, "");
2846
2847
  if (extracted.text.trim()) {
2847
2848
  extraSections.push(`\u3010\u6750\u6599\uFF1A${file.split(/[\\/]/).pop() ?? file}\u3011
@@ -2968,9 +2969,9 @@ ${groupTranscript}` : ""
2968
2969
  if (!employeeId) {
2969
2970
  warnings.push("\u672A\u53D6\u5230 ESB \u89E6\u53D1\u4EBA id\uFF08employeeId\uFF09\uFF0C\u5DF2\u8DF3\u8FC7\u540E\u7EED ESB \u8C03\u7528");
2970
2971
  } else {
2971
- const { createEsbHost } = await import("./host-I4NRK4MX.js");
2972
+ const { createEsbHost } = await import("./host-VGPVP7YF.js");
2972
2973
  const { createEsbContinuationSigner } = await import("./continuation-NLECEJPX.js");
2973
- const { getEsbOperation } = await import("./registry-KDD7DHNK.js");
2974
+ const { getEsbOperation } = await import("./registry-VT5Y2HLA.js");
2974
2975
  const esbEnv = { ctx, host: createEsbHost(ctx), continuation: createEsbContinuationSigner(ctx) };
2975
2976
  const prepareOp = getEsbOperation("esb.trigger.prepare");
2976
2977
  const applyOp = getEsbOperation("esb.trigger.apply");
@@ -3154,7 +3155,7 @@ var meetingDecisionNotifyGroup = {
3154
3155
  const warnings = [];
3155
3156
  const mtId = textOf3(args.mt_id).trim();
3156
3157
  if (!mtId) throw meetingValidationError("mt_id_required", "\u5FC5\u987B\u63D0\u4F9B\u4F1A\u8BAE id\uFF08mt_id\uFF09");
3157
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
3158
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
3158
3159
  const ctx = env.ctx;
3159
3160
  const listed = await getMeetingOperation2("meeting.eb.meeting.list").handler(
3160
3161
  { mt_id: mtId, pageNo: 1, pageSize: 1 },
@@ -3218,7 +3219,7 @@ var meetingDecisionNotifyGroup = {
3218
3219
  charCount: formatted.text.length,
3219
3220
  text: formatted.text
3220
3221
  };
3221
- const { createImHost } = await import("./host-Q4LZGCRU.js");
3222
+ const { createImHost } = await import("./host-3F5UM5GN.js");
3222
3223
  const imHost = createImHost(ctx);
3223
3224
  let displayText = formatted.text;
3224
3225
  let wireText = formatted.text;
@@ -3456,7 +3457,7 @@ var meetingPipelineRun = {
3456
3457
  const needsConfirm = level === "tasks" || level === "notify";
3457
3458
  const confirmed = args.confirm === true;
3458
3459
  const executedLevel = needsConfirm && !confirmed ? "document" : level;
3459
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
3460
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
3460
3461
  const ctx = env.ctx;
3461
3462
  let stepStart = Date.now();
3462
3463
  const reuseMinuteId = textOf4(args.minuteId).trim();
@@ -3525,7 +3526,7 @@ var meetingPipelineRun = {
3525
3526
  ]);
3526
3527
  }
3527
3528
  stepStart = Date.now();
3528
- const { createHrmHost } = await import("./host-XCLDDXKQ.js");
3529
+ const { createHrmHost } = await import("./host-A7J6GDUP.js");
3529
3530
  const { getHrmOperation } = await import("./registry-NYPYMZXG.js");
3530
3531
  const hrmEnv = { ctx, host: createHrmHost(ctx) };
3531
3532
  const queryOp = getHrmOperation("hrm.employee.query");
@@ -3726,6 +3727,59 @@ import { existsSync as existsSync2 } from "node:fs";
3726
3727
  import { mkdir as mkdir2, readFile as readFile3, writeFile as writeFile2 } from "node:fs/promises";
3727
3728
  import { dirname, join, resolve as resolve3 } from "node:path";
3728
3729
  import { fileURLToPath } from "node:url";
3730
+
3731
+ // src/shortcuts/meeting/invitation/text.ts
3732
+ function cell(value) {
3733
+ return String(value ?? "").replace(/\|/g, "/").replace(/\s*\r?\n\s*/g, " ").trim();
3734
+ }
3735
+ function renderInvitationMarkdown(resolver, agendaRows, options = {}) {
3736
+ const pending = /* @__PURE__ */ new Set();
3737
+ const val = (key) => {
3738
+ const rendered = resolver(key);
3739
+ if (rendered.pending) {
3740
+ pending.add(key);
3741
+ return PENDING_MARK;
3742
+ }
3743
+ return String(rendered.text ?? "").trim();
3744
+ };
3745
+ const lines = [];
3746
+ lines.push("# \u9080\u8BF7\u51FD");
3747
+ lines.push("");
3748
+ lines.push(`**\u5C0A\u656C\u7684 ${val("guest_org")}\uFF1A**`);
3749
+ lines.push("");
3750
+ lines.push(`${val("caller")} \u8BDA\u9080\u60A8\u53C2\u52A0\u300C${val("mt_name")}\u300D\uFF0C\u73B0\u5C06\u4F1A\u8BAE\u5B89\u6392\u901A\u77E5\u5982\u4E0B\uFF1A`);
3751
+ lines.push("");
3752
+ lines.push(`- **\u4F1A\u8BAE\u540D\u79F0**\uFF1A${val("mt_name")}`);
3753
+ lines.push(`- **\u4F1A\u8BAE\u65F6\u95F4**\uFF1A${val("begin_datetime")}~${val("end_datetime")}`);
3754
+ lines.push(`- **\u4F1A\u8BAE\u5730\u70B9**\uFF1A${val("address")}`);
3755
+ lines.push(`- **\u53C2\u4F1A\u4EBA\u5458**\uFF1A${val("hrm_members")}`);
3756
+ lines.push(`- **\u4F1A\u8BAE\u5185\u5BB9**\uFF1A${val("mt_desc")}`);
3757
+ lines.push("");
3758
+ lines.push(`**${val("begin_date")}\u4F1A\u8BAE\u8BAE\u7A0B\u5B89\u6392\uFF1A**`);
3759
+ lines.push("");
3760
+ lines.push("| \u8BAE\u7A0B\u5B89\u6392 | \u8BAE\u7A0B\u5185\u5BB9 | \u8BAE\u7A0B\u65F6\u95F4 |");
3761
+ lines.push("| --- | --- | --- |");
3762
+ if (agendaRows.length === 0) {
3763
+ lines.push("| \u2014 | \u6682\u65E0\u8BAE\u7A0B | \u2014 |");
3764
+ } else {
3765
+ for (const [name, content, timeRange] of agendaRows) {
3766
+ lines.push(`| ${cell(name) || "\u2014"} | ${cell(content) || "\u2014"} | ${cell(timeRange) || "\u2014"} |`);
3767
+ }
3768
+ }
3769
+ lines.push("");
3770
+ lines.push(val("company_name"));
3771
+ lines.push("");
3772
+ lines.push(val("issue_date"));
3773
+ lines.push("");
3774
+ lines.push("> \u6CE8\uFF1A\u4EE5\u4E0A\u4E3A\u62DF\u5B9A\u4F1A\u8BAE\u5B89\u6392\uFF0C\u5177\u4F53\u4F1A\u8BAE\u65F6\u95F4\u4E0E\u8BAE\u7A0B\u9700\u6839\u636E\u5B9E\u9645\u60C5\u51B5\u786E\u8BA4\u3002");
3775
+ if (options.pendingHint !== false && pending.size > 0) {
3776
+ lines.push("");
3777
+ lines.push(`> \u26A0\uFE0F \u6807 ${PENDING_MARK} \u7684\u5B57\u6BB5\u4F1A\u8BAE\u91CC\u6CA1\u6709\u503C\uFF0C\u9700\u8981\u4EBA\u5DE5\u8865\uFF1B\u8865\u5B8C\u53EF\u7528 mtId \u91CD\u65B0\u751F\u6210\u3002`);
3778
+ }
3779
+ return { markdown: lines.join("\n"), pendingFields: [...pending] };
3780
+ }
3781
+
3782
+ // src/shortcuts/meeting/operations/invitation.ts
3729
3783
  function templatePath() {
3730
3784
  const override = process.env.WEAVER_MEETING_INVITATION_TEMPLATE;
3731
3785
  if (override) return resolve3(override);
@@ -3775,7 +3829,7 @@ function formatTimeRange(start, end) {
3775
3829
  }
3776
3830
  async function loadAgendaFromTopics(env, mtId) {
3777
3831
  try {
3778
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
3832
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
3779
3833
  const operation = getMeetingOperation2("meeting.eb.topic.list");
3780
3834
  const result = await operation.handler({ mt_id: mtId, pageNo: 1, pageSize: 200 }, env);
3781
3835
  const rows = result.data?.rows ?? [];
@@ -3872,6 +3926,65 @@ async function resolveIssuerOrganization(env, creatorId) {
3872
3926
  return null;
3873
3927
  }
3874
3928
  }
3929
+ async function resolveSessionUserName(env) {
3930
+ try {
3931
+ const session = await env.host.getSession();
3932
+ const userId = String(session?.userId ?? "").trim();
3933
+ if (!userId) return "";
3934
+ const { hrmEmployeeOperations } = await import("./employee-SAK2QYXX.js");
3935
+ const batch = hrmEmployeeOperations.find((operation) => operation.name === "hrm.employee.batch");
3936
+ if (!batch) return "";
3937
+ const result = await batch.handler({ ids: [userId] }, env);
3938
+ const row = (result?.data?.rows ?? [])[0];
3939
+ return String(row?.name ?? "").trim();
3940
+ } catch {
3941
+ return "";
3942
+ }
3943
+ }
3944
+ var DETAIL_FALLBACK_KEYS = [
3945
+ "hrm_members",
3946
+ "mt_desc",
3947
+ "total_member",
3948
+ "caller",
3949
+ "contacter",
3950
+ "begin_datetime",
3951
+ "end_datetime",
3952
+ "other_members",
3953
+ "mt_creator",
3954
+ "topic_presenter",
3955
+ "mt_format",
3956
+ "mt_type",
3957
+ "video_url",
3958
+ "org_members",
3959
+ "with_secauth"
3960
+ ];
3961
+ async function supplementRowFromDetail(row, mtId, env) {
3962
+ const isBlank = (value) => {
3963
+ if (value === void 0 || value === null) return true;
3964
+ if (Array.isArray(value)) return value.length === 0;
3965
+ return String(value).trim() === "";
3966
+ };
3967
+ const missing = DETAIL_FALLBACK_KEYS.filter((key) => isBlank(row[key]));
3968
+ if (missing.length === 0) return { row, filled: [] };
3969
+ try {
3970
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
3971
+ const detailOperation = getMeetingOperation2("meeting.eb.meeting.detail");
3972
+ const result = await detailOperation.handler({ id: mtId }, env);
3973
+ const flat = result?.data?.data ?? result?.data ?? {};
3974
+ const merged = { ...row };
3975
+ const filled = [];
3976
+ for (const key of missing) {
3977
+ const value = flat[key];
3978
+ if (!isBlank(value)) {
3979
+ merged[key] = value;
3980
+ filled.push(key);
3981
+ }
3982
+ }
3983
+ return { row: merged, filled };
3984
+ } catch {
3985
+ return { row, filled: [] };
3986
+ }
3987
+ }
3875
3988
  function buildResolver(row, extra, issuerOrg) {
3876
3989
  const begin = parseDateTime(row.begin_datetime);
3877
3990
  const end = parseDateTime(row.end_datetime);
@@ -3909,6 +4022,9 @@ function buildResolver(row, extra, issuerOrg) {
3909
4022
  org_members: orgMembers,
3910
4023
  // 落款公司全称:`extra.company_name` 可覆盖(对外开放时客户传自己的公司名)
3911
4024
  company_name: String(extra.company_name ?? "").trim() || DEFAULT_COMPANY_NAME,
4025
+ // 客户单位(「尊敬的 XXX」):先看 extra(建会时由 create.flow 把参会客户名带进来),
4026
+ // 再看会议主表的 crm_members(部分租户会存),都没有才留【待补充】
4027
+ guest_org: String(extra.guest_org ?? "").trim() || flattenFieldValue(row.crm_members) || "",
3912
4028
  // 单独暴露上级公司,模板需要「公司级落款」时可直接用
3913
4029
  issuer_company: issuerCompany,
3914
4030
  other_members: humanizeMembers(row.other_members),
@@ -3931,7 +4047,10 @@ function buildResolver(row, extra, issuerOrg) {
3931
4047
  };
3932
4048
  const lookup = (key) => {
3933
4049
  if (key in derived) return derived[key];
3934
- if (key in standard) return standard[key];
4050
+ if (key in standard) {
4051
+ const standardValue = standard[key];
4052
+ if (String(standardValue ?? "").trim() !== "") return standardValue;
4053
+ }
3935
4054
  if (key.startsWith("extra.") && key.slice(6) in extra) return extra[key.slice(6)];
3936
4055
  if (key in extra) return extra[key];
3937
4056
  const raw = row[key];
@@ -3955,7 +4074,7 @@ var meetingInvitationRender = {
3955
4074
  resource: "invitation",
3956
4075
  method: "render",
3957
4076
  action: "meeting.invitation.render",
3958
- summary: "\u6309\u4F1A\u8BAE\u771F\u5B9E\u6570\u636E\u751F\u6210\u9080\u8BF7\u51FD docx\uFF08\u53EA\u8BFB\uFF0C\u4E0D\u53D1\u9001\uFF09\uFF1A\u6570\u636E\u53D6 meeting.eb.meeting.list \u5355\u67E5\uFF1B\u8BAE\u7A0B\u6709\u8BAE\u9898\u5C31\u6309\u8BAE\u9898\u81EA\u52A8\u586B\u3001\u6CA1\u6709\u5219\u4FDD\u7559\u6A21\u677F\u793A\u4F8B\u884C\uFF1B\u53D6\u4E0D\u5230\u7684\u5B57\u6BB5\u6E32\u67D3\u6210\u9EC4\u8272\u9AD8\u4EAE\u3010\u5F85\u8865\u5145\u3011\uFF1B\u79DF\u6237\u81EA\u5B9A\u4E49\u5B57\u6BB5\u7528 extra \u4F20\u5165",
4077
+ summary: "\u6309\u4F1A\u8BAE\u771F\u5B9E\u6570\u636E\u751F\u6210\u9080\u8BF7\u51FD\uFF08\u53EA\u8BFB\uFF0C\u4E0D\u53D1\u9001\uFF09\uFF1A**\u540C\u65F6\u8FD4\u56DE docx \u4E0E\u5BF9\u8BDD\u5185\u53EF\u5C55\u793A\u7684 Markdown \u5168\u6587**\uFF08`text` \u5B57\u6BB5\uFF09\uFF0C\u4F1A\u8BDD\u91CC\u5E94\u76F4\u63A5\u628A `text` \u8D34\u51FA\u6765\uFF0C\u4E0D\u8981\u53EA\u7ED9\u6587\u4EF6\u540D\u8BA9\u4EBA\u81EA\u5DF1\u4E0B\u8F7D\uFF1B\u6570\u636E\u53D6 meeting.eb.meeting.list \u5355\u67E5\uFF1B\u8BAE\u7A0B\u6709\u8BAE\u9898\u5C31\u6309\u8BAE\u9898\u81EA\u52A8\u586B\u3001\u6CA1\u6709\u5219\u4FDD\u7559\u6A21\u677F\u793A\u4F8B\u884C\uFF1B\u53D6\u4E0D\u5230\u7684\u5B57\u6BB5\u6E32\u67D3\u6210\u3010\u5F85\u8865\u5145\u3011\uFF08docx \u91CC\u662F\u9EC4\u8272\u9AD8\u4EAE\uFF09\uFF1B\u79DF\u6237\u81EA\u5B9A\u4E49\u5B57\u6BB5\u7528 extra \u4F20\u5165",
3959
4078
  capability: "invitation",
3960
4079
  risk: "read",
3961
4080
  inputSchema: {
@@ -3995,6 +4114,7 @@ var meetingInvitationRender = {
3995
4114
  }
3996
4115
  let row;
3997
4116
  let dataSource = "meeting";
4117
+ let detailSupplementary = [];
3998
4118
  if (!mtId) {
3999
4119
  const mtName = String(args.mt_name ?? "").trim();
4000
4120
  const beginText = String(args.begin_datetime ?? "").trim();
@@ -4021,7 +4141,7 @@ var meetingInvitationRender = {
4021
4141
  };
4022
4142
  dataSource = "payload";
4023
4143
  } else {
4024
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
4144
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
4025
4145
  const listOperation = getMeetingOperation2("meeting.eb.meeting.list");
4026
4146
  try {
4027
4147
  const listed = await listOperation.handler({ mt_id: mtId, pageNo: 1, pageSize: 1 }, env);
@@ -4037,6 +4157,17 @@ var meetingInvitationRender = {
4037
4157
  if (!row) {
4038
4158
  throw meetingValidationError("not_found", `\u672A\u627E\u5230\u4F1A\u8BAE id=${mtId}\uFF0C\u6216\u5F53\u524D\u8D26\u53F7\u65E0\u6743\u9650\u67E5\u770B`, { mtId });
4039
4159
  }
4160
+ const supplement = await supplementRowFromDetail(row, mtId, env);
4161
+ row = supplement.row;
4162
+ detailSupplementary = supplement.filled;
4163
+ }
4164
+ let callerFromSession = false;
4165
+ if (!String(row.caller ?? "").trim() && !String(row.mt_creator ?? "").trim()) {
4166
+ const sessionName = await resolveSessionUserName(env);
4167
+ if (sessionName) {
4168
+ row = { ...row, caller: sessionName };
4169
+ callerFromSession = true;
4170
+ }
4040
4171
  }
4041
4172
  const creatorId = String(row.creator ?? "").trim();
4042
4173
  const needsIssuerOrg = !String(row.org_members ?? "").trim() && creatorId !== "";
@@ -4064,6 +4195,7 @@ var meetingInvitationRender = {
4064
4195
  const rendered = renderDocx(template, resolver, {
4065
4196
  agenda: { headerKeyword: AGENDA_HEADER_KEYWORD, rows: agendaRows }
4066
4197
  });
4198
+ const textVersion = renderInvitationMarkdown(resolver, agendaRows);
4067
4199
  const begin = parseDateTime(row.begin_datetime);
4068
4200
  const dateTag = begin ? `${begin.getFullYear()}${pad(begin.getMonth() + 1)}${pad(begin.getDate())}` : "\u672A\u77E5\u65E5\u671F";
4069
4201
  const fileName = `\u9080\u8BF7\u51FD-${safeFileName(String(row.mt_name ?? ""))}-${dateTag}.docx`;
@@ -4104,12 +4236,17 @@ var meetingInvitationRender = {
4104
4236
  meetingName: String(row.mt_name ?? ""),
4105
4237
  // meeting=按真实会议数据;payload=按申请单字段预生成(会议可能还没生成,属预置函)
4106
4238
  dataSource,
4239
+ // 列表单查丢字段时,用 detail 补回来的字段名(有值 = 邀请函用的是合并后的数据)
4240
+ detailSupplemented: detailSupplementary,
4241
+ // 对话内展示用的 Markdown 全文(与 docx 同源)。上层应直接把这段贴进回复正文,
4242
+ // ⛔ 不要只丢一个 filePath 让用户自己去本地打开看内容。
4243
+ text: textVersion.markdown,
4107
4244
  filledFields: rendered.filled,
4108
4245
  pendingFields: rendered.pending,
4109
4246
  // 落款单位的实际来源,便于调用方判断是否需要人工改写
4110
4247
  orgSource,
4111
- // 召集人来源:meeting.caller=会议自己填的 / meeting.mt_creator=回落到创建人 / none=都没有
4112
- callerSource: String(row.caller ?? "").trim() ? "meeting.caller" : String(row.mt_creator ?? "").trim() ? "meeting.mt_creator" : "none",
4248
+ // 召集人来源:meeting.caller=会议自己填的 / meeting.mt_creator=回落到创建人 / session.user=回落到发起人本人 / none=都没有
4249
+ callerSource: callerFromSession ? "session.user" : String(row.caller ?? "").trim() ? "meeting.caller" : String(row.mt_creator ?? "").trim() ? "meeting.mt_creator" : "none",
4113
4250
  // 议程来源:meeting.topic=按议题自动填 / extra=调用方传入 / template=保留模板示例行
4114
4251
  agendaSource,
4115
4252
  agendaRows: agendaRows.length,
@@ -4758,7 +4895,7 @@ var meetingSummaryGet = {
4758
4895
  const mtId = textOf5(args.mt_id).trim();
4759
4896
  if (!mtId) throw meetingValidationError("mt_id_required", "\u5FC5\u987B\u63D0\u4F9B\u4F1A\u8BAE id\uFF08mt_id\uFF09");
4760
4897
  const ctx = env.ctx;
4761
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
4898
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
4762
4899
  const warnings = [];
4763
4900
  const timings = {};
4764
4901
  const include = Array.isArray(args.include) && args.include.length > 0 ? args.include.filter((item) => ALL_SECTIONS.includes(item)) : ALL_SECTIONS;
@@ -4894,7 +5031,7 @@ var meetingSummaryGet = {
4894
5031
  warnings.push("\u8BE5\u4F1A\u8BAE\u6CA1\u6709\u5173\u8054\u7FA4\u804A\uFF08imchat_groupid \u4E3A\u7A7A\uFF09\uFF0Cchat \u6BB5\u4E3A null");
4895
5032
  } else {
4896
5033
  try {
4897
- const { createImHost } = await import("./host-Q4LZGCRU.js");
5034
+ const { createImHost } = await import("./host-3F5UM5GN.js");
4898
5035
  const { createImContinuationSigner } = await import("./continuation-2CKSBLA6.js");
4899
5036
  const { getImOperation } = await import("./registry-OZSMDVPP.js");
4900
5037
  const imEnv = {
@@ -5020,7 +5157,7 @@ var meetingFormFields = {
5020
5157
  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"
5021
5158
  }, { warnings: resolved.warnings });
5022
5159
  }
5023
- const { createEbuilderFormHost } = await import("./host-UEI5FGDM.js");
5160
+ const { createEbuilderFormHost } = await import("./host-YMBXWFWX.js");
5024
5161
  const { createEbuilderFormContinuationSigner } = await import("./continuation-RN6PZN2M.js");
5025
5162
  const { executeEbuilderFormOperation } = await import("./operations-5QL3AECO.js");
5026
5163
  const formEnv = {
@@ -5080,7 +5217,7 @@ var MT_STATUS_OVER = "8";
5080
5217
  var CANCELLED_MARK_DELAY_MS = 800;
5081
5218
  async function isCancelledMeeting(env, mtId) {
5082
5219
  try {
5083
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
5220
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
5084
5221
  const listed = await getMeetingOperation2("meeting.eb.meeting.list").handler(
5085
5222
  // withCount:false —— 这里只要一行状态,不必额外请求 count(少一次往返,也便于测试替身)
5086
5223
  { mt_id: mtId, pageNo: 1, pageSize: 1, withCount: false },
@@ -5601,6 +5738,378 @@ var ebMeetingAssociation = async (ctx) => {
5601
5738
  };
5602
5739
  };
5603
5740
 
5741
+ // src/shortcuts/meeting/operations/eb/crm-search.ts
5742
+ var DEFAULT_CRM_FLOW_ID = "904205116264026112";
5743
+ var DEFAULT_KEYWORD_FIELD = "custom_name";
5744
+ var KEYWORD_FIELD_HINTS = [
5745
+ "custom_name",
5746
+ "mc",
5747
+ "sjmc",
5748
+ "khmc",
5749
+ "customerName",
5750
+ "customer_name",
5751
+ "clientName",
5752
+ "name",
5753
+ "keyword",
5754
+ "keywordName",
5755
+ "searchKey"
5756
+ ];
5757
+ var ID_KEYS = ["sjID", "sjid", "sj_id", "sjjId", "customerId", "custId", "clientId", "id"];
5758
+ var NAME_KEYS = ["mc", "sjmc", "sj_name", "customerName", "custName", "clientName", "name"];
5759
+ var LIST_KEYS = [
5760
+ "detail1",
5761
+ "detail2",
5762
+ "detail3",
5763
+ "detail",
5764
+ "details",
5765
+ "detailList",
5766
+ "list",
5767
+ "rows",
5768
+ "items",
5769
+ "data",
5770
+ "records",
5771
+ "result",
5772
+ "customers",
5773
+ "sjList"
5774
+ ];
5775
+ function asRecord(value) {
5776
+ return value && typeof value === "object" && !Array.isArray(value) ? value : null;
5777
+ }
5778
+ function pickFirst(row, keys) {
5779
+ for (const key of keys) {
5780
+ const value = row[key];
5781
+ if (value === void 0 || value === null) continue;
5782
+ if (typeof value === "object") {
5783
+ const nested = asRecord(value);
5784
+ if (nested) {
5785
+ const inner = pickFirst(nested, keys) || pickFirst(nested, ["id", "name"]);
5786
+ if (inner) return inner;
5787
+ }
5788
+ continue;
5789
+ }
5790
+ const text = String(value).trim();
5791
+ if (text !== "") return text;
5792
+ }
5793
+ return "";
5794
+ }
5795
+ function unwrapRow(value) {
5796
+ const record = asRecord(value);
5797
+ if (!record) return null;
5798
+ const main = asRecord(record.mainTable);
5799
+ return main ?? record;
5800
+ }
5801
+ function collectCandidateLists(customData) {
5802
+ const found = [];
5803
+ const main = asRecord(customData.mainTable);
5804
+ if (main) {
5805
+ found.push({ source: "customData.mainTable", rows: [main] });
5806
+ for (const key of LIST_KEYS) {
5807
+ const value = main[key];
5808
+ if (Array.isArray(value)) found.push({ source: `customData.mainTable.${key}`, rows: value });
5809
+ }
5810
+ }
5811
+ for (const key of LIST_KEYS) {
5812
+ const value = customData[key];
5813
+ if (Array.isArray(value)) found.push({ source: `customData.${key}`, rows: value });
5814
+ }
5815
+ return found;
5816
+ }
5817
+ var CONTACT_LIST_KEYS = ["lxr", "contacts", "contactList", "lxrList"];
5818
+ var ADDRESS_LIST_KEYS = ["khdz", "addresses", "addressList", "dz"];
5819
+ var CONTACT_NAME_KEYS = ["field_1173221220888062706", "xm", "lxrxm", "contactName", "name"];
5820
+ var CONTACT_MOBILE_KEYS = ["field_1173221220888062708", "sjhm", "mobile", "phone", "tel", "lxrdh"];
5821
+ var CONTACT_DEPT_KEYS = ["field_1173221220888062707", "bm", "dept", "department", "bmmc"];
5822
+ var MOBILE_RE = /^[+\d][\d\s-]{6,}$/;
5823
+ var DEPT_RE = /(部|科|处|室|中心|事业部|分公司|集团|公司)$/;
5824
+ function pickRawList(row, keys) {
5825
+ for (const key of keys) {
5826
+ if (Array.isArray(row[key])) return row[key];
5827
+ }
5828
+ return void 0;
5829
+ }
5830
+ function parseCrmContacts(raw) {
5831
+ if (!Array.isArray(raw)) return [];
5832
+ const out = [];
5833
+ const seen = /* @__PURE__ */ new Set();
5834
+ for (const item of raw) {
5835
+ const row = asRecord(item);
5836
+ if (!row) continue;
5837
+ const entries = Object.entries(row).filter(([key, value]) => !key.startsWith("subForm") && value !== null && value !== void 0 && String(value).trim() !== "");
5838
+ if (entries.length === 0) continue;
5839
+ const pick = (keys) => {
5840
+ for (const key of keys) {
5841
+ const hit = entries.find(([k]) => k === key);
5842
+ if (hit) return String(hit[1]).trim();
5843
+ }
5844
+ return "";
5845
+ };
5846
+ let name = pick(CONTACT_NAME_KEYS);
5847
+ let mobile = pick(CONTACT_MOBILE_KEYS);
5848
+ let dept = pick(CONTACT_DEPT_KEYS);
5849
+ for (const [, value] of entries) {
5850
+ const text = String(value).trim();
5851
+ if (text === "") continue;
5852
+ if (!mobile && MOBILE_RE.test(text)) {
5853
+ mobile = text;
5854
+ continue;
5855
+ }
5856
+ if (!name && !DEPT_RE.test(text) && !/^\d+$/.test(text)) {
5857
+ name = text;
5858
+ continue;
5859
+ }
5860
+ if (!dept && DEPT_RE.test(text)) dept = text;
5861
+ }
5862
+ if (name === "" && mobile === "") continue;
5863
+ const dedupeKey = `${name}|${mobile}`;
5864
+ if (seen.has(dedupeKey)) continue;
5865
+ seen.add(dedupeKey);
5866
+ out.push({ name, mobile, ...dept === "" ? {} : { dept } });
5867
+ }
5868
+ return out;
5869
+ }
5870
+ function parseCrmAddresses(raw) {
5871
+ if (!Array.isArray(raw)) return [];
5872
+ const out = [];
5873
+ for (const item of raw) {
5874
+ const row = asRecord(item);
5875
+ if (!row) continue;
5876
+ const parts = Object.entries(row).filter(([key, value]) => !key.startsWith("subForm") && value !== null && value !== void 0 && String(value).trim() !== "").map(([, value]) => String(value).trim());
5877
+ if (parts.length > 0) out.push(parts.join(" "));
5878
+ }
5879
+ return out;
5880
+ }
5881
+ function normalizeCustomers(rows, limit) {
5882
+ const seen = /* @__PURE__ */ new Map();
5883
+ for (const raw of rows) {
5884
+ const row = unwrapRow(raw);
5885
+ if (!row) continue;
5886
+ const customerId = pickFirst(row, ID_KEYS);
5887
+ const name = pickFirst(row, NAME_KEYS);
5888
+ if (customerId === "" && name === "") continue;
5889
+ const key = customerId !== "" ? customerId : `name:${name}`;
5890
+ if (seen.has(key)) continue;
5891
+ const contacts = parseCrmContacts(pickRawList(row, CONTACT_LIST_KEYS));
5892
+ const addresses = parseCrmAddresses(pickRawList(row, ADDRESS_LIST_KEYS));
5893
+ seen.set(key, {
5894
+ customerId,
5895
+ name,
5896
+ ...contacts.length > 0 ? { contacts } : {},
5897
+ ...addresses.length > 0 ? { addresses } : {}
5898
+ });
5899
+ }
5900
+ const all = [...seen.values()];
5901
+ const total = all.length;
5902
+ return { items: limit > 0 ? all.slice(0, limit) : all, total };
5903
+ }
5904
+ function parseCrmSearchPayload(actionData, options) {
5905
+ const action = asRecord(actionData) ?? {};
5906
+ const responseData = asRecord(action.responseData) ?? {};
5907
+ const customData = asRecord(responseData.customData) ?? {};
5908
+ const rawHasData = action.hasData;
5909
+ const hasData = rawHasData === void 0 || rawHasData === null ? null : Number(rawHasData) > 0;
5910
+ const templateFields = options.templateFields ?? [];
5911
+ const base = {
5912
+ keyword: options.keyword,
5913
+ limit: options.limit,
5914
+ total: 0,
5915
+ items: [],
5916
+ truncated: false,
5917
+ source: "customData",
5918
+ hasData,
5919
+ exact: false,
5920
+ singleBestMatch: false,
5921
+ message: "",
5922
+ templateFields,
5923
+ keywordField: options.keywordField ?? null
5924
+ };
5925
+ if (options.templateBlocked === true) {
5926
+ return {
5927
+ ...base,
5928
+ blocked: "esb_template_empty",
5929
+ message: "\u52A8\u4F5C\u6D41\u914D\u4E86\u300C\u81EA\u5B9A\u4E49\u5165\u53C2\u6A21\u677F\u300D\u4F46\u4E3B\u8868\u5B57\u6BB5\u4E3A\u7A7A\uFF08customParams.mainTable = {}\uFF09\uFF0C\u89E6\u53D1\u65F6\u4F20\u5165\u7684\u67E5\u8BE2\u6761\u4EF6\u4F1A\u88AB\u4E22\u5F03\uFF0C\u56E0\u6B64\u67E5\u4E0D\u5230\u5BA2\u6237\u3002\u9700\u8981\u5148\u5728 ESB \u8BBE\u8BA1\u5668\u91CC\u7ED9\u8BE5\u52A8\u4F5C\u6D41\u8865\u5165\u53C2\uFF08`custom_name` \u5BA2\u6237\u540D\u79F0\uFF09\u540E\u518D\u67E5\u3002"
5930
+ };
5931
+ }
5932
+ const lists = collectCandidateLists(customData);
5933
+ const best = lists.map((item) => ({ ...item, normalized: normalizeCustomers(item.rows, options.limit) })).sort((a, b) => b.normalized.total - a.normalized.total)[0];
5934
+ if (!best) {
5935
+ return {
5936
+ ...base,
5937
+ message: "\u52A8\u4F5C\u6D41\u8FD4\u56DE\u91CC\u6CA1\u6709\u53EF\u8BC6\u522B\u7684\u5BA2\u6237\u7ED3\u6784\uFF08\u65E2\u6CA1\u6709 mainTable \u884C\uFF0C\u4E5F\u6CA1\u6709 detail/list \u4E4B\u7C7B\u7684\u5217\u8868\uFF09\uFF0C\u8BF7\u68C0\u67E5\u52A8\u4F5C\u6D41\u7684\u8F93\u51FA\u6A21\u677F\u662F\u5426\u4ECD\u8F93\u51FA sjID/mc"
5938
+ };
5939
+ }
5940
+ if (best.normalized.total === 0) {
5941
+ return {
5942
+ ...base,
5943
+ source: best.source,
5944
+ message: `\u6309\u300C${options.keyword}\u300D\u6CA1\u6709\u5339\u914D\u5230\u5BA2\u6237\uFF08\u52A8\u4F5C\u6D41\u8FD4\u56DE\u7A7A\u884C\uFF09`
5945
+ };
5946
+ }
5947
+ const items = best.normalized.items;
5948
+ const singleBestMatch = best.normalized.total === 1;
5949
+ const exact = singleBestMatch && items[0].name === options.keyword;
5950
+ const rawAddress = pickRawList(best.rows[0], ADDRESS_LIST_KEYS);
5951
+ const addressHint = Array.isArray(rawAddress) && rawAddress.length > 0 && (items[0].addresses?.length ?? 0) === 0 ? `\u52A8\u4F5C\u6D41\u7684\u300C\u5BA2\u6237\u5730\u5740\u300D\uFF08khdz\uFF09\u53EA\u56DE\u4E86 ${rawAddress.length} \u6761\u660E\u7EC6\u884C id\uFF0C\u6CA1\u6709\u5730\u5740\u6587\u672C \u2014\u2014 \u9700\u8981\u5728 ESB \u8F93\u51FA\u6A21\u677F\u91CC\u8865\u4E0A\u5730\u5740\u5B57\u6BB5\uFF08\u5982 \u8BE6\u7EC6\u5730\u5740/\u7701\u5E02\u533A\uFF09\uFF0C\u5426\u5219\u9080\u8BF7\u51FD\u548C\u660E\u7EC6\u8868\u91CC\u62FF\u4E0D\u5230\u5730\u5740\u3002` : void 0;
5952
+ return {
5953
+ ...base,
5954
+ items,
5955
+ total: best.normalized.total,
5956
+ truncated: best.normalized.total > options.limit,
5957
+ source: best.source,
5958
+ exact,
5959
+ singleBestMatch,
5960
+ ...addressHint ? { addressHint } : {},
5961
+ message: exact ? `\u7CBE\u786E\u547D\u4E2D\u5BA2\u6237\u300C${items[0].name}\u300D\uFF08${items[0].customerId}\uFF09` : `\u6309\u300C${options.keyword}\u300D\u6A21\u7CCA\u547D\u4E2D ${best.normalized.total} \u4E2A\u5BA2\u6237` + (singleBestMatch ? "\uFF08\u52A8\u4F5C\u6D41\u53EA\u56DE\u9996\u4E2A\u5339\u914D\uFF09" : "") + (best.normalized.total > options.limit ? `\uFF0C\u5DF2\u6309 limit=${options.limit} \u622A\u65AD` : "")
5962
+ };
5963
+ }
5964
+ function pickKeywordField(templateMainTable) {
5965
+ const keys = Object.keys(templateMainTable ?? {});
5966
+ if (keys.length === 0) return null;
5967
+ for (const hint of KEYWORD_FIELD_HINTS) {
5968
+ const hit = keys.find((key) => key.toLowerCase() === hint.toLowerCase());
5969
+ if (hit) return hit;
5970
+ }
5971
+ return keys.length === 1 ? keys[0] : null;
5972
+ }
5973
+ function pickLimitField(templateMainTable) {
5974
+ const keys = Object.keys(templateMainTable ?? {});
5975
+ const hints = ["pageSize", "pagesize", "limit", "rows", "size", "num"];
5976
+ for (const hint of hints) {
5977
+ const hit = keys.find((key) => key.toLowerCase() === hint.toLowerCase());
5978
+ if (hit) return hit;
5979
+ }
5980
+ return null;
5981
+ }
5982
+ async function runCrmSearchFlow(env, input) {
5983
+ const session = await env.host.getSession();
5984
+ const employeeId = String(input.employeeId ?? session?.userId ?? "").trim();
5985
+ if (!employeeId) {
5986
+ 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
+ }
5988
+ const { createEsbHost } = await import("./host-VGPVP7YF.js");
5989
+ const { createEsbContinuationSigner } = await import("./continuation-NLECEJPX.js");
5990
+ const { getEsbOperation } = await import("./registry-VT5Y2HLA.js");
5991
+ const esbEnv = {
5992
+ ctx: env.ctx,
5993
+ host: createEsbHost(env.ctx),
5994
+ continuation: createEsbContinuationSigner(env.ctx)
5995
+ };
5996
+ const templateOp = getEsbOperation("esb.input-format");
5997
+ const prepareOp = getEsbOperation("esb.trigger.prepare");
5998
+ const applyOp = getEsbOperation("esb.trigger.apply");
5999
+ let templateMainTable = null;
6000
+ let customParamsTemplate = null;
6001
+ let templateReadOk = false;
6002
+ try {
6003
+ const template = await templateOp.handler({ applicationId: input.flowId }, esbEnv);
6004
+ customParamsTemplate = asRecord(template?.data?.customParams);
6005
+ templateMainTable = asRecord(customParamsTemplate?.mainTable);
6006
+ templateReadOk = true;
6007
+ } catch {
6008
+ }
6009
+ const templateFields = Object.keys(templateMainTable ?? {});
6010
+ const templateBlocked = templateReadOk && customParamsTemplate !== null && templateFields.length === 0;
6011
+ const keywordField = pickKeywordField(templateMainTable) ?? DEFAULT_KEYWORD_FIELD;
6012
+ const limitField = pickLimitField(templateMainTable);
6013
+ const mainTable = {};
6014
+ mainTable[keywordField] = input.keyword;
6015
+ if (limitField) mainTable[limitField] = input.limit;
6016
+ const pre = await prepareOp.handler(
6017
+ {
6018
+ esbFlowId: input.flowId,
6019
+ employeeId,
6020
+ customParams: { mainTable }
6021
+ },
6022
+ esbEnv
6023
+ );
6024
+ const applied = await applyOp.handler(
6025
+ { continuation: pre?.data?.continuation, confirm: true },
6026
+ esbEnv
6027
+ );
6028
+ const actionData = applied?.data?.actionData;
6029
+ const parsed = parseCrmSearchPayload(actionData, {
6030
+ keyword: input.keyword,
6031
+ limit: input.limit,
6032
+ templateFields,
6033
+ keywordField,
6034
+ templateBlocked
6035
+ });
6036
+ if (actionData && typeof actionData === "object") {
6037
+ const reminder = actionData.reminder;
6038
+ const reminderText = reminder === void 0 || reminder === null ? "" : String(reminder);
6039
+ if (reminderText !== "" && reminderText !== "0") parsed.actionMessage = reminderText;
6040
+ }
6041
+ return { result: parsed, raw: applied?.data };
6042
+ }
6043
+ var ebCrmSearch = {
6044
+ name: "meeting.eb.crm.search",
6045
+ resource: "eb",
6046
+ method: "meeting.eb.crm.search",
6047
+ action: "meeting.eb.crm.search",
6048
+ summary: "\u6309\u5BA2\u6237\u540D\u79F0\u67E5\u8BE2 CRM \u5BA2\u6237\uFF08ESB \u52A8\u4F5C\u6D41 904205116264026112\uFF0C\u5165\u53C2 custom_name\uFF0C\u51FA\u53C2 sjID/mc\uFF09\uFF1B\u52A8\u4F5C\u6D41\u4E00\u6B21\u53EA\u56DE\u9996\u4E2A\u5339\u914D\uFF0C\u540D\u79F0\u4E0D\u5B8C\u5168\u4E00\u81F4\u65F6\u987B\u56DE\u95EE\u7528\u6237\u786E\u8BA4",
6049
+ capability: "eb.crm",
6050
+ risk: "read",
6051
+ inputSchema: schemaOf(
6052
+ {
6053
+ keyword: {
6054
+ type: "string",
6055
+ minLength: 1,
6056
+ 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
+ },
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" },
6059
+ flowId: { type: "string", description: "\u8986\u76D6 ESB \u52A8\u4F5C\u6D41 id\uFF08\u9ED8\u8BA4 904205116264026112\uFF09" },
6060
+ employeeId: { type: "string", description: "\u8986\u76D6\u89E6\u53D1\u4EBA\u5458 id\uFF08\u9ED8\u8BA4\u5F53\u524D\u767B\u5F55\u7528\u6237\uFF09" },
6061
+ includeRaw: { type: "boolean", description: "true=\u9644\u5E26 ESB \u539F\u59CB\u8FD4\u56DE\uFF0C\u4FBF\u4E8E\u6392\u67E5\u8F93\u51FA\u7ED3\u6784" }
6062
+ },
6063
+ { required: ["keyword"] }
6064
+ ),
6065
+ handler: async (args, env) => {
6066
+ const keyword = String(args.keyword ?? "").trim();
6067
+ if (!keyword) {
6068
+ throw meetingValidationError("crm_keyword_required", "keyword \u4E0D\u80FD\u4E3A\u7A7A\uFF08\u5BA2\u6237\u540D\u79F0\u5173\u952E\u5B57\uFF09");
6069
+ }
6070
+ const limitRaw = Number(args.limit ?? 10);
6071
+ const limit = Number.isFinite(limitRaw) && limitRaw > 0 ? Math.min(Math.floor(limitRaw), 100) : 10;
6072
+ const { result, raw } = await runCrmSearchFlow(env, {
6073
+ keyword,
6074
+ limit,
6075
+ flowId: String(args.flowId ?? "").trim() || DEFAULT_CRM_FLOW_ID,
6076
+ ...args.employeeId ? { employeeId: String(args.employeeId) } : {}
6077
+ });
6078
+ const warnings = [];
6079
+ if (result.blocked === "esb_template_empty") {
6080
+ warnings.push(result.message);
6081
+ warnings.push("\u26D4 \u4E0D\u8981\u56DE\u590D\u300C\u6CA1\u6709\u8FD9\u4E2A\u5BA2\u6237\u300D\uFF1A\u8FD9\u662F\u52A8\u4F5C\u6D41\u5165\u53C2\u6A21\u677F\u672A\u914D\u7F6E\uFF0C\u5C5E\u4E8E\u914D\u7F6E\u95EE\u9898\u3002");
6082
+ } else if (result.items.length === 0) {
6083
+ warnings.push(`\u6309\u300C${keyword}\u300D\u6CA1\u6709\u5339\u914D\u5230\u5BA2\u6237\uFF1B\u53EF\u6362\u66F4\u77ED\u7684\u5173\u952E\u5B57\uFF08\u53BB\u6389\u5730\u57DF/\u540E\u7F00\uFF09\uFF0C\u6216\u786E\u8BA4\u8BE5\u5BA2\u6237\u662F\u5426\u5DF2\u5728 CRM \u5EFA\u6863\uFF08\u8FD9\u662F\u300C\u67E5\u65E0\u300D\uFF0C\u53EF\u4EE5\u5982\u5B9E\u56DE\u590D\u7528\u6237\uFF09\u3002`);
6084
+ } else if (!result.exact) {
6085
+ warnings.push(`\u52A8\u4F5C\u6D41\u4E00\u6B21\u53EA\u56DE\u9996\u4E2A\u5339\u914D\uFF1A\u300C${result.items[0].name}\u300D\uFF08${result.items[0].customerId}\uFF09\uFF0C\u4E0E\u300C${keyword}\u300D\u4E0D\u5B8C\u5168\u4E00\u81F4\u3002\u8BF7\u628A**\u547D\u4E2D\u5168\u540D\u539F\u6837\u5FF5\u51FA\u6765\u95EE"\u662F\u8FD9\u5BB6\u5417"**\uFF0C\u7528\u6237\u8BA4\u4E86\u518D\u628A\u8BE5 id \u5199\u8FDB create.flow.prepare \u7684 crm_members\uFF0C\u4E0D\u8981\u731C\u3002\u26D4 \u4E0D\u8981\u95EE\u6210"\u586B\u8FDB\u53C2\u4F1A\u5BA2\u6237\u5B57\u6BB5\u8FD8\u662F\u53EA\u5199\u8FDB\u4F1A\u8BAE\u5185\u5BB9\u5907\u6CE8"\u8FD9\u79CD\u9009\u62E9\u9898 \u2014\u2014 \u5BA2\u6237\u4E00\u5F8B\u8981\u5173\u8054\u5BA2\u6237\u6863\u6848\uFF0C"\u53EA\u5199\u5907\u6CE8"\u662F\u660E\u4EE4\u7981\u6B62\u7684\u505A\u6CD5\u3002`);
6086
+ }
6087
+ if (result.items.some((item) => item.name === "")) {
6088
+ warnings.push("\u6709\u5BA2\u6237\u53EA\u8FD4\u56DE\u4E86 sjID \u6CA1\u8FD4\u56DE mc\uFF08\u540D\u79F0\uFF09\uFF0C\u8BF7\u8BA9\u52A8\u4F5C\u6D41\u8F93\u51FA mc \u5B57\u6BB5\u3002");
6089
+ }
6090
+ const firstCustomer = result.items[0];
6091
+ if (firstCustomer) {
6092
+ const contacts = firstCustomer.contacts ?? [];
6093
+ if (contacts.length > 0) {
6094
+ warnings.push(
6095
+ `\u8BE5\u5BA2\u6237\u6709 ${contacts.length} \u4F4D\u8054\u7CFB\u4EBA\uFF1A` + contacts.map((c) => `${c.name}${c.dept ? `\uFF08${c.dept}\uFF09` : ""} ${c.mobile || "\u65E0\u624B\u673A\u53F7"}`).join("\u3001") + '\u3002\u5EFA\u4F1A\u65F6\u4F20 `crm_members` \u5C31\u4F1A\u628A\u8FD9**\u5168\u90E8\u8054\u7CFB\u4EBA\u81EA\u52A8\u5199\u6210\u300C\u53C2\u4F1A\u5BA2\u6237\u660E\u7EC6\u300D\u884C**\uFF08\u4E00\u4EBA\u4E00\u884C\uFF09\uFF0C\u26D4 \u4E0D\u8981\u95EE\u7528\u6237"\u9009\u54EA\u4F4D"\u3001\u4E5F\u4E0D\u8981\u53EA\u5E26\u5176\u4E2D\u4E00\u4F4D\uFF1B\u53EA\u6709\u7528\u6237\u660E\u786E\u8BF4"\u53EA\u5199\u67D0\u67D0"\u65F6\u624D\u7528 crm_member_details:[{"xm":"<\u59D3\u540D>","sjhm":"<\u624B\u673A\u53F7>","zw":"<\u90E8\u95E8\u6216\u804C\u4F4D>"}] \u8986\u76D6\u3002'
6096
+ );
6097
+ } else {
6098
+ warnings.push(
6099
+ '\u8BE5\u5BA2\u6237**\u6CA1\u6709\u8054\u7CFB\u4EBA**\uFF08\u52A8\u4F5C\u6D41\u672A\u8F93\u51FA lxr\uFF0C\u6216\u8BE5\u5BA2\u6237\u6CA1\u5EFA\u6863\u8054\u7CFB\u4EBA\uFF09\u2014\u2014 \u8FD9\u662F\u552F\u4E00\u9700\u8981\u95EE\u8054\u7CFB\u4EBA\u7684\u573A\u666F\u3002\u53EF\u4EE5\u95EE\u7528\u6237\u300C\u8981\u4E0D\u8981\u8865\u4E00\u4E0B\u8054\u7CFB\u4EBA\u59D3\u540D\u548C\u624B\u673A\u53F7\uFF08\u65B9\u4FBF\u7684\u8BDD\u518D\u7ED9\u804C\u4F4D\uFF09\u300D\uFF0C\u518D\u4EE5 crm_member_details:[{"xm":"\u5F20\u4E09","sjhm":"13800000000"}] \u4F20\u7ED9 create.flow.prepare/quick\uFF1B\u7528\u6237\u8BF4"\u6CA1\u6709"\u5C31\u7559\u7A7A\uFF0C\u4E0D\u8981\u786C\u7F16\u3002'
6100
+ );
6101
+ }
6102
+ if (result.addressHint) warnings.push(result.addressHint);
6103
+ }
6104
+ return meetingSuccess(
6105
+ "meeting.eb.crm.search",
6106
+ { ...result, ...args.includeRaw === true ? { raw } : {} },
6107
+ warnings.length > 0 ? { warnings } : {}
6108
+ );
6109
+ }
6110
+ };
6111
+ var meetingEbCrmOperations = [ebCrmSearch];
6112
+
5604
6113
  // src/shortcuts/meeting/operations/eb/create-flow.ts
5605
6114
  import { existsSync as existsSync3 } from "node:fs";
5606
6115
  import { mkdir as mkdir4, readFile as readFile4, writeFile as writeFile4 } from "node:fs/promises";
@@ -5615,18 +6124,22 @@ var FIELD_ALIASES = {
5615
6124
  customize_address: ["\u81EA\u5B9A\u4E49\u4F1A\u8BAE\u5730\u70B9", "\u81EA\u5B9A\u4E49\u5730\u70B9"],
5616
6125
  hrm_members: ["\u53C2\u4F1A\u4EBA\u5458", "\u53C2\u4F1A\u4EBA"],
5617
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"],
5618
6130
  caller: ["\u53EC\u96C6\u4EBA", "\u53D1\u8D77\u4EBA"],
5619
6131
  contacter: ["\u8054\u7CFB\u4EBA"],
5620
6132
  mt_type: ["\u4F1A\u8BAE\u7C7B\u578B"],
5621
6133
  other_remark: ["\u5907\u6CE8", "\u5176\u4ED6\u8BF4\u660E"]
5622
6134
  };
6135
+ var PERSON_FIELD_LABELS = { caller: "\u53EC\u96C6\u4EBA", contacter: "\u8054\u7CFB\u4EBA" };
5623
6136
  function workflowEnv(env) {
5624
6137
  return env;
5625
6138
  }
5626
6139
  async function loadCreateForm(env, workflowId) {
5627
- const { createWorkflowHost } = await import("./host-C6EL2RKL.js");
6140
+ const { createWorkflowHost } = await import("./host-YAQAPYNP.js");
5628
6141
  const { createWorkflowContinuationSigner } = await import("./continuation-HZIZRZBX.js");
5629
- const { getWorkflowOperation } = await import("./registry-TKX2E7C7.js");
6142
+ const { getWorkflowOperation } = await import("./registry-YX4CSEMD.js");
5630
6143
  const wfEnv = {
5631
6144
  ...workflowEnv(env),
5632
6145
  host: createWorkflowHost(env.ctx),
@@ -5670,28 +6183,111 @@ async function resolveEmployeeNames(env, ids) {
5670
6183
  }
5671
6184
  return map;
5672
6185
  }
5673
- async function resolveRoomValue(env, input) {
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) {
5674
6258
  const text = String(input ?? "").trim();
5675
6259
  if (!text) return null;
5676
- const { loadRooms: loadRooms2 } = await import("./room-recommend-XCWRMB5P.js");
6260
+ const ref = parseRoomRef(text);
6261
+ const { loadRooms: loadRooms2 } = await import("./room-recommend-L3MWH4JW.js");
6262
+ let rooms = [];
5677
6263
  try {
5678
- const { rooms } = await loadRooms2(env, {});
5679
- const byId = rooms.find((room) => room.id === text);
5680
- if (byId) return { id: byId.id, name: byId.name };
5681
- const byName = rooms.find((room) => room.name === text);
5682
- if (byName) return { id: byName.id, name: byName.name };
6264
+ rooms = (await loadRooms2(env, {})).rooms;
5683
6265
  } catch {
6266
+ return { id: ref.id ?? "", name: ref.name ?? text, status: "unknown", lookupFailed: true };
5684
6267
  }
5685
- if (/^\d+$/.test(text)) {
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) {
5686
6282
  try {
5687
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
5688
- const detail = await getMeetingOperation2("meeting.eb.room.detail").handler({ id: text }, env);
6283
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
6284
+ const detail = await getMeetingOperation2("meeting.eb.room.detail").handler({ id: ref.id }, env);
5689
6285
  const main = detail?.data?.mainTable ?? detail?.data?.data?.mainTable ?? {};
5690
- const name = String(main.room_name ?? "").trim();
5691
- if (name) return { id: text, name };
6286
+ const name = String(main.room_name ?? "").trim() || ref.name || "";
6287
+ if (name) return { id: ref.id, name };
5692
6288
  } catch {
5693
6289
  }
5694
- return { id: text, name: text };
6290
+ return { id: ref.id, name: ref.name || ref.id };
5695
6291
  }
5696
6292
  return null;
5697
6293
  }
@@ -5718,9 +6314,9 @@ async function shapeBrowserValues(env, values) {
5718
6314
  idPool.push(...ids);
5719
6315
  }
5720
6316
  if (idPool.length > 0) {
5721
- const names = await resolveEmployeeNames(env, idPool);
5722
- const toObject = (id) => ({ id, name: names.get(id) ?? id });
5723
- const toName = (id) => names.get(id) ?? id;
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;
5724
6320
  if (shaped.hrm_members !== void 0 && shaped.hrm_members !== "") {
5725
6321
  const ids = String(shaped.hrm_members).split(/[,;,;\s]+/).map((item) => item.trim()).filter((item) => item !== "");
5726
6322
  shaped.hrm_members = ids.map(toObject);
@@ -5737,6 +6333,94 @@ async function shapeBrowserValues(env, values) {
5737
6333
  shaped.contacter = toObject(id);
5738
6334
  readable.contacter = toName(id);
5739
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
+ }
5740
6424
  }
5741
6425
  for (const [key, raw] of Object.entries(values)) {
5742
6426
  if (readable[key] !== void 0) continue;
@@ -5749,6 +6433,195 @@ async function shapeBrowserValues(env, values) {
5749
6433
  function normalizeFieldName(name) {
5750
6434
  return String(name ?? "").replace(/[((][^(())]*[))]/g, "").replace(/[\s\u3000]+/g, "").trim();
5751
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
+ }
5752
6625
  function mapFields(fields, values, preferred = {}) {
5753
6626
  const byName = new Map(fields.map((field) => [field.name.trim(), field]));
5754
6627
  const byId = new Map(fields.map((field) => [field.id, field]));
@@ -5794,6 +6667,90 @@ function mapFields(fields, values, preferred = {}) {
5794
6667
  }
5795
6668
  return { main, mapped, unmapped, resolved };
5796
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
+ }
5797
6754
  function flowFieldCacheDir(env) {
5798
6755
  const configured = env?.ctx?.config?.path?.();
5799
6756
  const root = configured ? resolve5(String(configured), "..") : process.env.WEAVER_WORK_CLI_HOME || process.env.WORK_CLI_HOME || resolve5(homedir(), ".weaver-work-cli");
@@ -5957,7 +6914,7 @@ var ebMeetingCreateFlowPrepare = {
5957
6914
  resource: "eb",
5958
6915
  method: "meeting.eb.meeting.create.flow.prepare",
5959
6916
  action: "meeting.eb.meeting.create.flow.prepare",
5960
- 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",
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',
5961
6918
  capability: "eb.meeting",
5962
6919
  risk: "read-before-write",
5963
6920
  requiresConfirmation: true,
@@ -5977,8 +6934,22 @@ var ebMeetingCreateFlowPrepare = {
5977
6934
  customize_address: { type: "string", description: "\u81EA\u5B9A\u4E49\u4F1A\u8BAE\u5730\u70B9" },
5978
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" },
5979
6936
  total_member: { type: "number", description: "\u53C2\u4F1A\u4EBA\u6570" },
5980
- caller: { type: "string", description: "\u53EC\u96C6\u4EBA" },
5981
- contacter: { type: "string", description: "\u8054\u7CFB\u4EBA" },
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" },
5982
6953
  mt_type: {
5983
6954
  type: "string",
5984
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"
@@ -6034,7 +7005,7 @@ var ebMeetingCreateFlowPrepare = {
6034
7005
  let endText = String(args.end_datetime ?? "").trim();
6035
7006
  const rawMembers = String(args.hrm_members ?? "").split(/[,;,;\s]+/).map((item) => item.trim()).filter((item) => item !== "");
6036
7007
  const nameLike = rawMembers.filter((item) => !/^\d+$/.test(item));
6037
- const nameToId = nameLike.length > 0 ? await import("./schedule-IVBICP32.js").then((m) => m.resolveMemberIdsByName(env, nameLike)).catch(() => /* @__PURE__ */ new Map()) : /* @__PURE__ */ new Map();
7008
+ const nameToId = nameLike.length > 0 ? await import("./schedule-UASAVDVD.js").then((m) => m.resolveMemberIdsByName(env, nameLike)).catch(() => /* @__PURE__ */ new Map()) : /* @__PURE__ */ new Map();
6038
7009
  const memberIds = rawMembers.map((item) => nameToId.get(item) ?? item);
6039
7010
  const timeConfirmed = args.timeConfirmed === true;
6040
7011
  const callerWorkflowId = String(args.workflowId ?? "").trim();
@@ -6049,7 +7020,7 @@ var ebMeetingCreateFlowPrepare = {
6049
7020
  if (!beginHasTime || !timeConfirmed) {
6050
7021
  const day2 = /^\d{4}-\d{2}-\d{2}/.test(beginText) ? beginText.slice(0, 10) : String(args.dateFrom ?? "").trim().slice(0, 10) || tomorrowIso();
6051
7022
  const duration = Number(args.durationMinutes) > 0 ? Math.round(Number(args.durationMinutes)) : 60;
6052
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
7023
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
6053
7024
  const suggested = await getMeetingOperation2("meeting.eb.meeting.create.suggest").handler(
6054
7025
  {
6055
7026
  dateFrom: day2,
@@ -6116,6 +7087,13 @@ var ebMeetingCreateFlowPrepare = {
6116
7087
  enrichFailures.push(`${label}\u672A\u5B8C\u6210\uFF1A${String(error?.message ?? error).slice(0, 120)}`);
6117
7088
  return null;
6118
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;
6119
7097
  const declaredTotal = Number(args.total_member) > 0 ? Number(args.total_member) : null;
6120
7098
  const callerToken = String(args.caller ?? "").trim();
6121
7099
  const callerInMembers = callerToken !== "" && (rawMembers.includes(callerToken) || memberIds.includes(callerToken));
@@ -6129,17 +7107,20 @@ var ebMeetingCreateFlowPrepare = {
6129
7107
  topN: 3
6130
7108
  }).catch(noteFailure("\u4F1A\u8BAE\u5BA4\u63A8\u8350")) : Promise.resolve(null);
6131
7109
  const addressId = String(addressInput ?? "").trim();
6132
- const addressIsRoomId = /^\d+$/.test(addressId);
6133
7110
  const roomConfirmed = args.roomConfirmed === true;
6134
- const roomConflictTask = enrich && beginText && endText && addressIsRoomId ? (async () => {
6135
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
6136
- return getMeetingOperation2("meeting.eb.conflict.room").handler(
6137
- { beginDatetime: beginText, endDatetime: endText, address: addressId },
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 },
6138
7118
  env
6139
7119
  );
7120
+ return { room, ...result?.data ?? {} };
6140
7121
  })().catch(noteFailure("\u4F1A\u8BAE\u5BA4**\u5360\u7528**\u68C0\u6D4B")) : Promise.resolve(null);
6141
7122
  const conflictTask = enrich && beginText && endText && memberIds.length > 0 ? (async () => {
6142
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
7123
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
6143
7124
  return getMeetingOperation2("meeting.eb.conflict.member").handler(
6144
7125
  { beginDatetime: beginText, endDatetime: endText, hrmMembers: memberIds.join(",") },
6145
7126
  env
@@ -6194,11 +7175,51 @@ var ebMeetingCreateFlowPrepare = {
6194
7175
  value: { id: candidate.id, name: candidate.name, roomConfirmed: true },
6195
7176
  reason: candidate.reasons.join("\uFF1B")
6196
7177
  }));
6197
- const roomConflictData = roomConflict?.data;
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
+ }
6198
7218
  if (addressInput && roomConfirmed && roomConflictData?.hasConflict === true) {
6199
7219
  const busy = Array.isArray(roomConflictData.conflicts) ? roomConflictData.conflicts : [];
6200
7220
  decisions.roomConflict = {
6201
- address: addressId,
7221
+ address: resolvedAddressId,
7222
+ addressName: addressDisplay,
6202
7223
  hasConflict: true,
6203
7224
  conflicts: busy,
6204
7225
  verdict: roomConflictData.verdict ?? "conflict"
@@ -6208,15 +7229,16 @@ var ebMeetingCreateFlowPrepare = {
6208
7229
  status: "NEEDS_SELECTION",
6209
7230
  selectionType: "room_conflict",
6210
7231
  ui: { component: "choice", multiple: false, recommendedKey: "R1" },
6211
- message: `\u4F60\u6307\u5B9A\u7684\u4F1A\u8BAE\u5BA4\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`,
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`,
6212
7233
  workflowPending: true,
6213
7234
  options: roomOptions,
6214
7235
  recommended: roomOptions[0]?.value ?? null,
6215
7236
  conflicts: busy,
7237
+ roomConflict: decisions.roomConflict,
6216
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"
6217
7239
  }, {
6218
7240
  warnings: [
6219
- `\u4F1A\u8BAE\u5BA4 ${addressId} \u5728\u8BE5\u65F6\u6BB5\u5DF2\u6709 ${busy.length} \u6761\u5360\u7528\uFF0C\u5DF2\u62E6\u4E0B\u672A\u63D0\u4EA4\u3002`,
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`,
6220
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"
6221
7243
  ]
6222
7244
  });
@@ -6232,21 +7254,21 @@ var ebMeetingCreateFlowPrepare = {
6232
7254
  const needRoomPick = !addressInput || !roomConfirmed;
6233
7255
  let pickOptions = roomOptions;
6234
7256
  if (addressInput && !roomConfirmed) {
6235
- const hit = roomOptions.find((item) => String(item.value?.id) === addressId);
7257
+ const hit = roomOptions.find((item) => String(item.value?.id) === resolvedAddressId);
6236
7258
  const specified = hit ? { ...hit, label: `${hit.label}\uFF08\u4F60\u6307\u5B9A\u7684\uFF0C\u5F85\u786E\u8BA4\uFF09`, value: { ...hit.value, roomConfirmed: true } } : {
6237
7259
  key: "R0",
6238
- label: `${addressInput}\uFF08\u4F60\u6307\u5B9A\u7684\uFF0C\u5F85\u786E\u8BA4\uFF09`,
6239
- value: { ...addressIsRoomId ? { id: addressId } : {}, name: addressInput, roomConfirmed: true },
7260
+ label: `${addressDisplay}\uFF08\u4F60\u6307\u5B9A\u7684\uFF0C\u5F85\u786E\u8BA4\uFF09`,
7261
+ value: { ...resolvedAddressId ? { id: resolvedAddressId } : {}, name: addressDisplay, roomConfirmed: true },
6240
7262
  reason: "\u4F60\u4F20\u5165\u7684\u4F1A\u8BAE\u5BA4\uFF0C\u672A\u63D0\u4EA4\u3001\u672A\u786E\u8BA4"
6241
7263
  };
6242
- pickOptions = [specified, ...roomOptions.filter((item) => String(item.value?.id) !== addressId)].map((item, index) => ({ ...item, key: `R${index + 1}` }));
7264
+ pickOptions = [specified, ...roomOptions.filter((item) => String(item.value?.id) !== resolvedAddressId)].map((item, index) => ({ ...item, key: `R${index + 1}` }));
6243
7265
  }
6244
7266
  if (needRoomPick && !autoRoom && pickOptions.length > 0 && args.allowNoRoom !== true) {
6245
7267
  return meetingSuccess("meeting.eb.meeting.create.flow.prepare", {
6246
7268
  status: "NEEDS_SELECTION",
6247
7269
  selectionType: "room",
6248
7270
  ui: { component: "choice", multiple: false, recommendedKey: "R1" },
6249
- message: addressInput ? `\u4F60\u4F20\u5165\u7684\u4F1A\u8BAE\u5BA4\u300C${addressInput}\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`,
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`,
6250
7272
  // 固化自动选的流程要带出来:调用方下一轮带 address 重调时不用再猜用的是哪条流程。
6251
7273
  workflowPending: true,
6252
7274
  options: pickOptions,
@@ -6255,7 +7277,7 @@ var ebMeetingCreateFlowPrepare = {
6255
7277
  ...conflictBrief
6256
7278
  }, {
6257
7279
  warnings: [
6258
- addressInput ? `\u4F1A\u8BAE\u5BA4\u300C${addressInput}\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",
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",
6259
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",
6260
7282
  ...earlyWorkflowNote ? [earlyWorkflowNote] : [],
6261
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`] : [],
@@ -6300,8 +7322,8 @@ var ebMeetingCreateFlowPrepare = {
6300
7322
  if (enrich && addressInput && !roomConfirmed && roomOptions.length === 0 && args.allowNoRoom !== true) {
6301
7323
  const specified = {
6302
7324
  key: "R1",
6303
- label: `${addressInput}\uFF08\u4F60\u6307\u5B9A\u7684\uFF0C\u5F85\u786E\u8BA4\uFF09`,
6304
- value: { ...addressIsRoomId ? { id: addressId } : {}, name: addressInput, roomConfirmed: true },
7325
+ label: `${addressDisplay}\uFF08\u4F60\u6307\u5B9A\u7684\uFF0C\u5F85\u786E\u8BA4\uFF09`,
7326
+ value: { ...resolvedAddressId ? { id: resolvedAddressId } : {}, name: addressDisplay, roomConfirmed: true },
6305
7327
  reason: "\u4F60\u4F20\u5165\u7684\u4F1A\u8BAE\u5BA4\uFF0C\u672A\u63D0\u4EA4\u3001\u672A\u786E\u8BA4"
6306
7328
  };
6307
7329
  return meetingSuccess("meeting.eb.meeting.create.flow.prepare", {
@@ -6318,8 +7340,8 @@ var ebMeetingCreateFlowPrepare = {
6318
7340
  });
6319
7341
  }
6320
7342
  const resolved = await resolveWorkflowId(env, args);
6321
- const confirmedAddressId = String(addressInput ?? "").trim();
6322
- const confirmedAddressLabel = confirmedAddressId === "" ? "" : String(roomOptions.find((item) => String(item.value?.id ?? "") === confirmedAddressId)?.value?.name ?? "") || confirmedAddressId;
7343
+ const confirmedAddressId = resolvedAddressId;
7344
+ const confirmedAddressLabel = addressId === "" ? "" : resolvedAddress?.name || String(roomOptions.find((item) => String(item.value?.id ?? "") === confirmedAddressId)?.value?.name ?? "") || addressId;
6323
7345
  const confirmedWhen = `${beginText}~${String(endText).slice(11) || endText}`;
6324
7346
  let candidates = resolved.candidates;
6325
7347
  workflowId = resolved.workflowId;
@@ -6421,6 +7443,16 @@ var ebMeetingCreateFlowPrepare = {
6421
7443
  throw meetingValidationError("flow_context_missing", "\u5EFA\u4F1A\u6D41\u7A0B\u8868\u5355\u6CA1\u6709\u8FD4\u56DE continuation\uFF0C\u65E0\u6CD5\u7EE7\u7EED\u63D0\u4EA4");
6422
7444
  }
6423
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
+ })();
6424
7456
  const shaped = await shapeBrowserValues(env, {
6425
7457
  mt_name: args.mt_name,
6426
7458
  begin_datetime: args.begin_datetime,
@@ -6430,6 +7462,8 @@ var ebMeetingCreateFlowPrepare = {
6430
7462
  customize_address: args.customize_address,
6431
7463
  hrm_members: args.hrm_members,
6432
7464
  total_member: args.total_member,
7465
+ crm_members: args.crm_members,
7466
+ ...crmMemberCount === void 0 ? {} : { crm_member_count: crmMemberCount },
6433
7467
  caller: args.caller,
6434
7468
  contacter: args.contacter,
6435
7469
  other_remark: args.other_remark,
@@ -6440,8 +7474,88 @@ var ebMeetingCreateFlowPrepare = {
6440
7474
  const { main, mapped, unmapped, resolved: resolvedFields } = mapFields(form.fields, shaped.values, preferredFields);
6441
7475
  await writeFlowFieldMap(env, workflowId, form.workflowName, resolvedFields);
6442
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
+ }
6443
7485
  if (flowPickNote) warnings.push(flowPickNote);
6444
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
+ }
6445
7559
  if (args.fieldValues && typeof args.fieldValues === "object" && !Array.isArray(args.fieldValues)) {
6446
7560
  const knownIds = new Set(form.fields.map((field) => field.id));
6447
7561
  for (const [fieldId, raw] of Object.entries(args.fieldValues)) {
@@ -6479,7 +7593,7 @@ var ebMeetingCreateFlowPrepare = {
6479
7593
  } else if (decisions.dayBlocked?.summary) {
6480
7594
  warnings.push(String(decisions.dayBlocked.summary));
6481
7595
  }
6482
- const unmappedReal = unmapped.filter((name) => name !== "mt_name");
7596
+ const unmappedReal = unmapped.filter((name) => name !== "mt_name" && name !== "crm_member_count");
6483
7597
  if (unmappedReal.length > 0) {
6484
7598
  warnings.push(
6485
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`
@@ -6490,6 +7604,7 @@ var ebMeetingCreateFlowPrepare = {
6490
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"
6491
7605
  );
6492
7606
  }
7607
+ const crmPatchIds = (Array.isArray(shaped.values.crm_members) ? shaped.values.crm_members : []).map((row) => String(row?.id ?? "").trim()).filter((id) => id !== "");
6493
7608
  const session = await env.host.getSession();
6494
7609
  const continuation = await env.continuation.issue(
6495
7610
  {
@@ -6501,12 +7616,18 @@ var ebMeetingCreateFlowPrepare = {
6501
7616
  workflowId,
6502
7617
  requestName: String(args.mt_name),
6503
7618
  mtName: String(args.mt_name),
6504
- data: { main },
7619
+ data: { main, ...detailPayload ? { details: detailPayload } : {} },
6505
7620
  surfaceContinuation: form.continuation,
6506
7621
  // 供 apply 在「会议还没生成」时按申请单信息预生成邀请函(预置函)
6507
- invitationFields: shaped.readable
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 } } : {}
6508
7629
  },
6509
- fingerprint: JSON.stringify({ workflowId, main })
7630
+ fingerprint: JSON.stringify({ workflowId, main, ...detailPayload ? { details: detailPayload } : {} })
6510
7631
  },
6511
7632
  10 * 60 * 1e3
6512
7633
  );
@@ -6522,6 +7643,23 @@ var ebMeetingCreateFlowPrepare = {
6522
7643
  requestName: String(args.mt_name),
6523
7644
  fieldMapping: mapped,
6524
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 } } : {},
6525
7663
  formFieldCount: form.fields.length,
6526
7664
  ...Object.keys(decisions).length > 0 ? { decisions } : {}
6527
7665
  },
@@ -6532,11 +7670,59 @@ var ebMeetingCreateFlowPrepare = {
6532
7670
  );
6533
7671
  }
6534
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
+ }
6535
7721
  async function renderPreInvitation(payload, env) {
6536
7722
  const fields = payload?.invitationFields ?? {};
6537
7723
  const started = Date.now();
6538
7724
  try {
6539
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
7725
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
6540
7726
  const render = getMeetingOperation2("meeting.invitation.render");
6541
7727
  const rendered = await render.handler(
6542
7728
  {
@@ -6549,7 +7735,10 @@ async function renderPreInvitation(payload, env) {
6549
7735
  org_members: String(fields.org_members ?? "").trim(),
6550
7736
  caller: String(fields.caller ?? "").trim(),
6551
7737
  contacter: String(fields.contacter ?? "").trim(),
6552
- total_member: String(fields.total_member ?? "").trim()
7738
+ total_member: String(fields.total_member ?? "").trim(),
7739
+ // 客户单位(邀请函开头「尊敬的 XXX」):建会时填了参会客户就直接带过去,
7740
+ // 否则整句永远是【待补充】—— 用户看到的就是"客户明明填了,邀请函里却没有"。
7741
+ extra: { guest_org: String(fields.crm_members ?? "").trim() }
6553
7742
  },
6554
7743
  env
6555
7744
  );
@@ -6582,6 +7771,11 @@ var ebMeetingCreateFlowApply = {
6582
7771
  {
6583
7772
  continuation: { type: "string", description: "prepare \u8FD4\u56DE\u7684\u786E\u8BA4\u7968\u636E\uFF08\u5FC5\u586B\uFF09" },
6584
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
+ },
6585
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" }
6586
7780
  },
6587
7781
  { required: ["continuation", "confirm"] }
@@ -6599,9 +7793,9 @@ var ebMeetingCreateFlowApply = {
6599
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");
6600
7794
  }
6601
7795
  const payload = lease?.payload ?? {};
6602
- const { createWorkflowHost } = await import("./host-C6EL2RKL.js");
7796
+ const { createWorkflowHost } = await import("./host-YAQAPYNP.js");
6603
7797
  const { createWorkflowContinuationSigner } = await import("./continuation-HZIZRZBX.js");
6604
- const { getWorkflowOperation } = await import("./registry-TKX2E7C7.js");
7798
+ const { getWorkflowOperation } = await import("./registry-YX4CSEMD.js");
6605
7799
  const wfEnv = {
6606
7800
  ...workflowEnv(env),
6607
7801
  host: createWorkflowHost(env.ctx),
@@ -6609,6 +7803,7 @@ var ebMeetingCreateFlowApply = {
6609
7803
  };
6610
7804
  const submitStartedAt = Date.now();
6611
7805
  const submit = getWorkflowOperation("workflow.createRequest");
7806
+ const submitMode = String(args.submit_mode ?? "browser").trim();
6612
7807
  const submitted = await submit.handler(
6613
7808
  {
6614
7809
  // 工作流的入参名是 context(createForm 返回的 continuation 就是它的 context 句柄)
@@ -6616,7 +7811,8 @@ var ebMeetingCreateFlowApply = {
6616
7811
  data: payload.data,
6617
7812
  action: "submit",
6618
7813
  requestName: payload.requestName,
6619
- confirm: true
7814
+ confirm: true,
7815
+ ...submitMode === "browser" ? {} : { forceServerSubmit: true }
6620
7816
  },
6621
7817
  wfEnv
6622
7818
  );
@@ -6681,7 +7877,7 @@ var ebMeetingCreateFlowApply = {
6681
7877
  let meetingId = "";
6682
7878
  const timings = { submitMs: Date.now() - submitStartedAt };
6683
7879
  if (waitSeconds > 0) {
6684
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
7880
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
6685
7881
  const list = getMeetingOperation2("meeting.eb.meeting.list");
6686
7882
  const deadline = Date.now() + Math.min(waitSeconds, 30) * 1e3;
6687
7883
  const pollStart = Date.now();
@@ -6703,13 +7899,39 @@ var ebMeetingCreateFlowApply = {
6703
7899
  }
6704
7900
  timings.pollMs = Date.now() - pollStart;
6705
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
+ }
6706
7921
  let invitation = { pending: true };
6707
7922
  if (meetingId) {
6708
7923
  const invitationStart = Date.now();
6709
7924
  try {
6710
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
7925
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
6711
7926
  const render = getMeetingOperation2("meeting.invitation.render");
6712
- const rendered = await render.handler({ mtId: meetingId }, env);
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
+ );
6713
7935
  invitation = { pending: false, ...rendered?.data ?? {} };
6714
7936
  timings.invitationMs = Date.now() - invitationStart;
6715
7937
  } catch (error) {
@@ -6736,6 +7958,19 @@ var ebMeetingCreateFlowApply = {
6736
7958
  requestId,
6737
7959
  requestName: payload.requestName,
6738
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
+ ),
6739
7974
  invitation,
6740
7975
  result: submitted?.data ?? null
6741
7976
  },
@@ -6748,7 +7983,7 @@ var ebMeetingCreateFlowQuick = {
6748
7983
  resource: "eb",
6749
7984
  method: "meeting.eb.meeting.create.flow.quick",
6750
7985
  action: "meeting.eb.meeting.create.flow.quick",
6751
- 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\u63D0\u4EA4\u540E\u81EA\u52A8\u51FA\u9080\u8BF7\u51FD\uFF1B\u591A\u6D41\u7A0B\u6216\u9700\u9009\u62E9\u65F6\u4E0D\u63D0\u4EA4\uFF0C\u8FD4\u56DE\u9009\u9879",
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',
6752
7987
  capability: "eb.meeting",
6753
7988
  risk: "high-risk-write",
6754
7989
  requiresConfirmation: true,
@@ -6768,8 +8003,8 @@ var ebMeetingCreateFlowQuick = {
6768
8003
  customize_address: { type: "string", description: "\u81EA\u5B9A\u4E49\u4F1A\u8BAE\u5730\u70B9" },
6769
8004
  hrm_members: { type: "string", description: "\u53C2\u4F1A\u4EBA\u5458 id\uFF0C\u9017\u53F7\u5206\u9694" },
6770
8005
  total_member: { type: "number", description: "\u53C2\u4F1A\u4EBA\u6570" },
6771
- caller: { type: "string", description: "\u53EC\u96C6\u4EBA" },
6772
- contacter: { type: "string", description: "\u8054\u7CFB\u4EBA" },
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" },
6773
8008
  mt_type: {
6774
8009
  type: "string",
6775
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"
@@ -6815,6 +8050,15 @@ var ebMeetingCreateFlowQuick = {
6815
8050
  type: "string",
6816
8051
  enum: ["auto", "ask"],
6817
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'
6818
8062
  }
6819
8063
  },
6820
8064
  { required: ["mt_name", "confirm"] }
@@ -6826,10 +8070,20 @@ var ebMeetingCreateFlowQuick = {
6826
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"
6827
8071
  );
6828
8072
  }
6829
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
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");
6830
8082
  const prepareStartedAt = Date.now();
8083
+ const { submit_mode: _submitMode, confirm: _confirm, ...prepareArgs } = args;
6831
8084
  const prepared = await getMeetingOperation2("meeting.eb.meeting.create.flow.prepare").handler(
6832
- { ...args, confirm: void 0 },
8085
+ // submit_mode 只属于提交阶段,prepare 的 schema 不接受它(additionalProperties:false)
8086
+ prepareArgs,
6833
8087
  env
6834
8088
  );
6835
8089
  if (prepared?.data?.status === "NEEDS_SELECTION") {
@@ -6845,6 +8099,7 @@ var ebMeetingCreateFlowQuick = {
6845
8099
  {
6846
8100
  continuation,
6847
8101
  confirm: true,
8102
+ ...args.submit_mode ? { submit_mode: args.submit_mode } : {},
6848
8103
  ...args.waitSeconds !== void 0 ? { waitSeconds: args.waitSeconds } : {}
6849
8104
  },
6850
8105
  env
@@ -6861,6 +8116,8 @@ var ebMeetingCreateFlowQuick = {
6861
8116
  requestId: applied?.data?.requestId,
6862
8117
  meetingId: applied?.data?.meetingId ?? null,
6863
8118
  invitation: applied?.data?.invitation ?? null,
8119
+ // 已提交内容回显(字段名 → 值),提交后可直接贴给用户看"到底填进去了什么"
8120
+ submittedPreview: applied?.data?.submittedPreview ?? null,
6864
8121
  // 小e 环境(BROWSER_FILL)不写服务端,表单靠这段 <browsertool> 在浏览器里填 —— 必须一起透出,
6865
8122
  // 否则宿主拿不到表单,用户看到的就是"提交了但没反应"。
6866
8123
  ...applied?.data?.contextId ? { contextId: (applied?.data).contextId } : {},
@@ -6916,7 +8173,7 @@ var ebMeetingCreateSuggest = {
6916
8173
  const topN = Math.max(1, Math.min(5, Number(args.topN) || 3));
6917
8174
  const rawMembers = String(args.hrm_members ?? "").split(/[,;,;\s]+/).map((item) => item.trim()).filter((item) => item !== "");
6918
8175
  const nameLike = rawMembers.filter((item) => !/^\d+$/.test(item));
6919
- const nameToId = nameLike.length > 0 ? await import("./schedule-IVBICP32.js").then((m) => m.resolveMemberIdsByName(env, nameLike)).catch(() => /* @__PURE__ */ new Map()) : /* @__PURE__ */ new Map();
8176
+ const nameToId = nameLike.length > 0 ? await import("./schedule-UASAVDVD.js").then((m) => m.resolveMemberIdsByName(env, nameLike)).catch(() => /* @__PURE__ */ new Map()) : /* @__PURE__ */ new Map();
6920
8177
  const memberIds = rawMembers.map((item) => nameToId.get(item) ?? item);
6921
8178
  const unresolved = rawMembers.filter((item) => nameToId.get(item) === void 0 && !/^\d+$/.test(item));
6922
8179
  const selfId = await env.host.getSession().then((s) => String(s?.userId ?? "")).catch(() => "");
@@ -7088,7 +8345,7 @@ var ebAutoInvitationAfterWrite = async (context) => {
7088
8345
  const mtId = String(context.dataIds?.[0] ?? "").trim();
7089
8346
  if (!isCreate || !enabled || !mtId) return association;
7090
8347
  try {
7091
- const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-VRTNC6UR.js");
8348
+ const { getMeetingOperation: getMeetingOperation2 } = await import("./registry-QCLZEDAP.js");
7092
8349
  const render = getMeetingOperation2("meeting.invitation.render");
7093
8350
  const result = await render.handler({ mtId }, context.env);
7094
8351
  return { ...association ?? {}, invitation: result?.data ?? null };
@@ -7111,6 +8368,7 @@ var meetingEbOperations = [
7111
8368
  ...meetingEbConflictOperations,
7112
8369
  ...meetingEbDecisionOperations,
7113
8370
  ...meetingEbScheduleOperations,
8371
+ ...meetingEbCrmOperations,
7114
8372
  ...meetingEbCreateFlowOperations,
7115
8373
  ebRoomRecommendOperation
7116
8374
  ];