weaver-work-cli 0.1.40 → 0.1.44

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 (401) hide show
  1. package/README.md +17 -0
  2. package/dist/chunks/{archive-JHTONRST.js → archive-P6TBQGKL.js} +13 -5
  3. package/dist/chunks/{archive-oa-FCHLCPHC.js → archive-oa-7TQ2NXOH.js} +12 -5
  4. package/dist/chunks/{asset-RLIHC7DB.js → asset-3ELRG37G.js} +11 -4
  5. package/dist/chunks/{asset-idle-KVOFTLCP.js → asset-idle-WIGMUFMD.js} +7 -3
  6. package/dist/chunks/{attachment-content-RZYDB3MB.js → attachment-content-E3276UOV.js} +5 -4
  7. package/dist/chunks/{blog-42OZTJNP.js → blog-C5NMZAAC.js} +11 -4
  8. package/dist/chunks/{caizhilian-KRK547K5.js → caizhilian-5XSM2DFP.js} +13 -6
  9. package/dist/chunks/{calendar-RTWAMKHD.js → calendar-FI2WNSBO.js} +71 -26
  10. package/dist/chunks/{chunk-CXRQWOZ5.js → chunk-3YBDYOC4.js} +3 -3
  11. package/dist/chunks/{chunk-OOUTBLZ4.js → chunk-56EZERK4.js} +1 -1
  12. package/dist/chunks/chunk-6N4JPNFL.js +76 -0
  13. package/dist/chunks/{chunk-ZUX3P6BQ.js → chunk-727FH2NI.js} +1 -1
  14. package/dist/chunks/chunk-7BDPM5ST.js +11 -0
  15. package/dist/chunks/{chunk-LN447PY2.js → chunk-BCVYBYYT.js} +432 -2247
  16. package/dist/chunks/{chunk-7E6MUOEK.js → chunk-CWYGFU5B.js} +2 -2
  17. package/dist/chunks/{chunk-NOODWMCL.js → chunk-D4ADSZ7H.js} +1 -1
  18. package/dist/chunks/{chunk-WFFNM65B.js → chunk-ETNJSKMM.js} +281 -29
  19. package/dist/chunks/{chunk-CAQNBBQA.js → chunk-F4E4EM35.js} +3 -3
  20. package/dist/chunks/{chunk-4CTESSKI.js → chunk-FAZTGX7S.js} +6 -6
  21. package/dist/chunks/chunk-FRZKBMSW.js +2562 -0
  22. package/dist/chunks/{chunk-BYBSCN4X.js → chunk-G7PQWD4L.js} +6 -3
  23. package/dist/chunks/{chunk-NJKREDA3.js → chunk-GAMZLAG2.js} +1 -1
  24. package/dist/chunks/{chunk-FLS4DPGP.js → chunk-GM6J7Q4B.js} +28 -15
  25. package/dist/chunks/{chunk-NETCCARD.js → chunk-GRDRG6HP.js} +3 -3
  26. package/dist/chunks/chunk-HIT4Y6OI.js +1238 -0
  27. package/dist/chunks/{chunk-EZALDOQH.js → chunk-HP7JIYMT.js} +5 -2
  28. package/dist/chunks/{chunk-IZSSVYAG.js → chunk-IAZ3UPY6.js} +3 -3
  29. package/dist/chunks/{chunk-ZEDWSH32.js → chunk-IC62NFM5.js} +1 -1
  30. package/dist/chunks/{chunk-P26ZWSKU.js → chunk-KIHNAS25.js} +5 -2
  31. package/dist/chunks/{chunk-57IECMWX.js → chunk-N4M2DDFE.js} +29 -15
  32. package/dist/chunks/{chunk-JWRZM2H2.js → chunk-OF4S23UB.js} +4 -4
  33. package/dist/chunks/{chunk-VNBU55SL.js → chunk-PC7VKEB5.js} +80 -2458
  34. package/dist/chunks/{chunk-G2JSIUWF.js → chunk-PUQS5MWL.js} +91 -2
  35. package/dist/chunks/{chunk-E7OK5WD5.js → chunk-Q4OYAQYH.js} +5 -5
  36. package/dist/chunks/{chunk-7BRU4EFH.js → chunk-QVSWRLLU.js} +35 -6
  37. package/dist/chunks/{chunk-T6EGVBKU.js → chunk-TA7FXXJD.js} +6 -3
  38. package/dist/chunks/{chunk-GPMFD4RD.js → chunk-TXUG266F.js} +1 -1
  39. package/dist/chunks/{chunk-4TEDNCON.js → chunk-UFIT2UU3.js} +354 -56
  40. package/dist/chunks/{chunk-LUSPKZKY.js → chunk-UG5G54VL.js} +1 -0
  41. package/dist/chunks/{chunk-NIAJ5ZCG.js → chunk-UL5XUQ25.js} +5 -2
  42. package/dist/chunks/{chunk-FMPJJYYI.js → chunk-WRXSAVKO.js} +1 -1
  43. package/dist/chunks/{chunk-7U577Q7U.js → chunk-WSF4NNMR.js} +3 -3
  44. package/dist/chunks/chunk-XHK4MDR5.js +2497 -0
  45. package/dist/chunks/{chunk-LFMSDBZN.js → chunk-XNIK66I4.js} +326 -161
  46. package/dist/chunks/{chunk-3SO6QL6U.js → chunk-YWX377BY.js} +5 -2
  47. package/dist/chunks/{chunk-BYATLLEF.js → chunk-Z3GDFVJR.js} +1 -1
  48. package/dist/chunks/{chunk-I566ZYNF.js → chunk-Z7VYWPZV.js} +1 -1
  49. package/dist/chunks/{conflict-VR55AOOO.js → conflict-ARLSZJ6V.js} +4 -3
  50. package/dist/chunks/{continuation-2CKSBLA6.js → continuation-3S37AUSH.js} +4 -3
  51. package/dist/chunks/{continuation-RN6PZN2M.js → continuation-3XLYYTKV.js} +4 -3
  52. package/dist/chunks/{continuation-HZIZRZBX.js → continuation-HFW2YT5S.js} +4 -3
  53. package/dist/chunks/{continuation-NLECEJPX.js → continuation-KI7DRRZN.js} +4 -3
  54. package/dist/chunks/{contract-HI4FNPYE.js → contract-DNIIW5VJ.js} +13 -5
  55. package/dist/chunks/{cowork-HJLI353D.js → cowork-GMLRGVIW.js} +31 -14
  56. package/dist/chunks/create-flow-J22BO65E.js +56 -0
  57. package/dist/chunks/{ebuilder-form-HTGI63UU.js → ebuilder-form-ANV2FHYV.js} +12 -7
  58. package/dist/chunks/{ehr-GYXIYH3A.js → ehr-GSTGAIY3.js} +695 -1255
  59. package/dist/chunks/{employee-SAK2QYXX.js → employee-22BGJ3QS.js} +3 -3
  60. package/dist/chunks/{env-DW3G4HUO.js → env-BX3VRFS7.js} +4 -3
  61. package/dist/chunks/{esb-I5INCEFE.js → esb-ATAIASX2.js} +12 -7
  62. package/dist/chunks/{factory-TKXGXS6L.js → factory-PETTFME6.js} +3 -2
  63. package/dist/chunks/{fna-K2MHTQ24.js → fna-YEKBSFSX.js} +14 -8
  64. package/dist/chunks/{group-chat-VYBNMJLG.js → group-chat-BFVXAYFX.js} +7 -4
  65. package/dist/chunks/{host-D5SERMAJ.js → host-HRBXEPDQ.js} +5 -5
  66. package/dist/chunks/{host-JM4YVHFM.js → host-LR55CTHP.js} +5 -5
  67. package/dist/chunks/{host-L3VLITMT.js → host-SUOY6VYQ.js} +5 -5
  68. package/dist/chunks/{host-ZUQTJYYK.js → host-SZGV4UNT.js} +5 -5
  69. package/dist/chunks/{host-256GVCAH.js → host-WIKN2EJ5.js} +5 -5
  70. package/dist/chunks/{hrm-VLRBKTZB.js → hrm-NRDO4W5G.js} +11 -7
  71. package/dist/chunks/{im-QK3VTLXK.js → im-IQ2HN23S.js} +11 -10
  72. package/dist/chunks/{invoice-T5JTA32H.js → invoice-MNRW76PP.js} +636 -1768
  73. package/dist/chunks/{jiuchuanhui-P2FNEQVZ.js → jiuchuanhui-DTRBAX4N.js} +14 -6
  74. package/dist/chunks/{lazy-dispatch-XRRI46M6.js → lazy-dispatch-ZVWAI25B.js} +7 -6
  75. package/dist/chunks/{mail-3Y7MJ6PS.js → mail-ZVAUXOJA.js} +16 -14
  76. package/dist/chunks/{meeting-M7LTXGJE.js → meeting-FEVPZ67S.js} +21 -13
  77. package/dist/chunks/{okr-OBC6S67L.js → okr-SDH3E5RA.js} +12 -5
  78. package/dist/chunks/{operations-5QL3AECO.js → operations-62N6EP3C.js} +4 -3
  79. package/dist/chunks/{plan-5H6I53SK.js → plan-E35JFDI7.js} +12 -5
  80. package/dist/chunks/{project-L75QZV4S.js → project-73QXBAB2.js} +49 -25
  81. package/dist/chunks/reception-UWZVACBN.js +1899 -0
  82. package/dist/chunks/recruit-stage-4MAOCKFY.js +4770 -0
  83. package/dist/chunks/registry-IM5G23LS.js +24 -0
  84. package/dist/chunks/{registry-UGRBCBHO.js → registry-JDUS4E7D.js} +7 -6
  85. package/dist/chunks/{registry-RXPN6BBT.js → registry-KNKSCJNT.js} +7 -6
  86. package/dist/chunks/{registry-NYPYMZXG.js → registry-PO7SI256.js} +4 -4
  87. package/dist/chunks/{registry-QGHFNUWS.js → registry-PVUZQDDQ.js} +3 -3
  88. package/dist/chunks/{room-recommend-A3UDC3CA.js → room-recommend-H7KLXA5R.js} +6 -5
  89. package/dist/chunks/{schedule-5GCACCK7.js → schedule-ESZIBAUO.js} +6 -5
  90. package/dist/chunks/{workflow-M5ZJ7DWF.js → workflow-CWJFJLQU.js} +15 -10
  91. package/dist/cmd/action.js +6 -0
  92. package/dist/cmd/identity/index.js +45 -0
  93. package/dist/cmd/index.js +2 -0
  94. package/dist/core/continuation-ttl.js +18 -0
  95. package/dist/core/error-codes.js +85 -0
  96. package/dist/core/logger.js +11 -0
  97. package/dist/index.js +41 -30
  98. package/dist/internal/e10/auth/commands.js +164 -8
  99. package/dist/internal/e10/auth/error-log.js +182 -0
  100. package/dist/internal/e10/auth/messages.js +6 -0
  101. package/dist/internal/e10/auth/session.js +34 -3
  102. package/dist/internal/e10/auth/xiaoe.js +286 -44
  103. package/dist/internal/e10/auth-recovery.js +72 -14
  104. package/dist/internal/e10/context.js +72 -13
  105. package/dist/internal/e10/index.js +1 -1
  106. package/dist/internal/e10/network-error.js +93 -0
  107. package/dist/internal/e10/request-runtime.js +6 -0
  108. package/dist/internal/skills/install.js +9 -1
  109. package/dist/shortcuts/archive/continuation.js +2 -1
  110. package/dist/shortcuts/archive/index.js +3 -0
  111. package/dist/shortcuts/archive/operations/confirm.js +2 -1
  112. package/dist/shortcuts/archive-oa/continuation.js +2 -1
  113. package/dist/shortcuts/archive-oa/index.js +2 -0
  114. package/dist/shortcuts/archive-oa/operations/confirm.js +2 -1
  115. package/dist/shortcuts/asset/continuation.js +2 -1
  116. package/dist/shortcuts/asset/index.js +2 -0
  117. package/dist/shortcuts/asset-idle/index.js +2 -0
  118. package/dist/shortcuts/blog/continuation.js +2 -1
  119. package/dist/shortcuts/blog/index.js +2 -0
  120. package/dist/shortcuts/caizhilian/continuation.js +2 -1
  121. package/dist/shortcuts/caizhilian/index.js +2 -0
  122. package/dist/shortcuts/caizhilian/operations/confirm.js +3 -2
  123. package/dist/shortcuts/calendar/continuation.js +2 -1
  124. package/dist/shortcuts/calendar/index.js +2 -0
  125. package/dist/shortcuts/calendar/operations/read.js +31 -22
  126. package/dist/shortcuts/calendar/operations/write.js +46 -2
  127. package/dist/shortcuts/contract/continuation.js +2 -1
  128. package/dist/shortcuts/contract/index.js +2 -0
  129. package/dist/shortcuts/contract/operations/write.js +2 -1
  130. package/dist/shortcuts/cowork/continuation.js +2 -1
  131. package/dist/shortcuts/cowork/index.js +2 -0
  132. package/dist/shortcuts/cowork/operations/discuss-write.js +5 -1
  133. package/dist/shortcuts/cowork/operations/item-write.js +1 -7
  134. package/dist/shortcuts/cowork/operations/member-write.js +3 -1
  135. package/dist/shortcuts/cowork/operations/permission-write.js +5 -1
  136. package/dist/shortcuts/cowork/operations/shared.js +7 -0
  137. package/dist/shortcuts/ebuilder-form/continuation.js +2 -1
  138. package/dist/shortcuts/ebuilder-form/index.js +2 -0
  139. package/dist/shortcuts/ebuilder-form/operations/write.js +3 -2
  140. package/dist/shortcuts/ehr/continuation.js +2 -1
  141. package/dist/shortcuts/ehr/index.js +2 -0
  142. package/dist/shortcuts/ehr/operations/attend-write.js +44 -2
  143. package/dist/shortcuts/ehr/operations/hr-contact.js +7 -4
  144. package/dist/shortcuts/ehr/operations/hr-report.js +13 -7
  145. package/dist/shortcuts/ehr/operations/recruit-candidate-import.js +317 -63
  146. package/dist/shortcuts/ehr/operations/recruit-position.js +134 -2
  147. package/dist/shortcuts/ehr/operations/recruit-write.js +263 -18
  148. package/dist/shortcuts/ehr/operations/recruit.js +10 -4
  149. package/dist/shortcuts/ehr/operations/shared.js +47 -0
  150. package/dist/shortcuts/esb/continuation.js +2 -1
  151. package/dist/shortcuts/esb/index.js +2 -0
  152. package/dist/shortcuts/esb/operations/trigger.js +2 -1
  153. package/dist/shortcuts/fna/continuation.js +2 -1
  154. package/dist/shortcuts/fna/index.js +2 -0
  155. package/dist/shortcuts/fna/operations/invoice-writeoff.js +1 -1
  156. package/dist/shortcuts/fna/operations/loan.js +1 -1
  157. package/dist/shortcuts/hrm/index.js +2 -0
  158. package/dist/shortcuts/hrm/operations/org.js +118 -0
  159. package/dist/shortcuts/im/continuation.js +2 -1
  160. package/dist/shortcuts/index.js +10 -0
  161. package/dist/shortcuts/invoice/continuation.js +2 -1
  162. package/dist/shortcuts/invoice/index.js +14 -15
  163. package/dist/shortcuts/invoice/invoice-record.js +93 -0
  164. package/dist/shortcuts/invoice/manifest.js +190 -393
  165. package/dist/shortcuts/invoice/operations/add.js +2 -1
  166. package/dist/shortcuts/invoice/operations/delete.js +2 -1
  167. package/dist/shortcuts/invoice/operations/import.js +2 -1
  168. package/dist/shortcuts/invoice/operations/issuing-contract-detail.js +86 -0
  169. package/dist/shortcuts/invoice/operations/issuing-contracts.js +210 -0
  170. package/dist/shortcuts/invoice/operations/registry.js +17 -17
  171. package/dist/shortcuts/invoice/operations/reim-auto.js +4 -569
  172. package/dist/shortcuts/invoice/operations/reim.js +52 -341
  173. package/dist/shortcuts/invoice/operations/shared.js +21 -4
  174. package/dist/shortcuts/invoice/operations/update.js +2 -1
  175. package/dist/shortcuts/invoice/projection.js +10 -62
  176. package/dist/shortcuts/jiuchuanhui/continuation.js +2 -1
  177. package/dist/shortcuts/jiuchuanhui/index.js +2 -0
  178. package/dist/shortcuts/jiuchuanhui/operations/datajson.js +2 -1
  179. package/dist/shortcuts/jiuchuanhui/operations/esb.js +2 -1
  180. package/dist/shortcuts/mail/continuation.js +2 -1
  181. package/dist/shortcuts/mail/index.js +2 -0
  182. package/dist/shortcuts/mail/operations/mail-blacklist.js +1 -1
  183. package/dist/shortcuts/mail/operations/mail-contacts.js +1 -1
  184. package/dist/shortcuts/mail/operations/mail-send.js +1 -1
  185. package/dist/shortcuts/mail/operations/mail-sign.js +1 -1
  186. package/dist/shortcuts/mail/operations/mail-template.js +1 -1
  187. package/dist/shortcuts/meeting/continuation.js +2 -1
  188. package/dist/shortcuts/meeting/index.js +2 -0
  189. package/dist/shortcuts/meeting/operations/change.js +1 -1
  190. package/dist/shortcuts/meeting/operations/create.js +1 -1
  191. package/dist/shortcuts/meeting/operations/eb/catalog.js +4 -1
  192. package/dist/shortcuts/meeting/operations/eb/create-flow.js +101 -35
  193. package/dist/shortcuts/meeting/operations/eb/decision.js +1 -1
  194. package/dist/shortcuts/meeting/operations/eb/factory.js +34 -1
  195. package/dist/shortcuts/meeting/operations/eb/group-chat.js +25 -3
  196. package/dist/shortcuts/meeting/operations/eb/person-cache.js +96 -0
  197. package/dist/shortcuts/meeting/operations/eb/room-recommend.js +33 -11
  198. package/dist/shortcuts/meeting/operations/lifecycle.js +1 -1
  199. package/dist/shortcuts/meeting/operations/receipts.js +1 -1
  200. package/dist/shortcuts/meeting/operations/signs.js +1 -1
  201. package/dist/shortcuts/okr/continuation.js +2 -1
  202. package/dist/shortcuts/okr/index.js +2 -0
  203. package/dist/shortcuts/okr/operations/write.js +1 -1
  204. package/dist/shortcuts/plan/continuation.js +2 -1
  205. package/dist/shortcuts/plan/index.js +2 -0
  206. package/dist/shortcuts/plan/operations/write.js +1 -1
  207. package/dist/shortcuts/project/continuation.js +2 -1
  208. package/dist/shortcuts/project/index.js +2 -0
  209. package/dist/shortcuts/project/operations/read.js +6 -25
  210. package/dist/shortcuts/project/operations/shared.js +22 -0
  211. package/dist/shortcuts/project/operations/write.js +28 -2
  212. package/dist/shortcuts/reception/constants.js +53 -0
  213. package/dist/shortcuts/reception/errors.js +54 -0
  214. package/dist/shortcuts/reception/host.js +125 -0
  215. package/dist/shortcuts/reception/index.js +198 -0
  216. package/dist/shortcuts/reception/manifest.js +177 -0
  217. package/dist/shortcuts/reception/operations/ask.js +71 -0
  218. package/dist/shortcuts/reception/operations/browsertool.js +58 -0
  219. package/dist/shortcuts/reception/operations/compose.js +129 -0
  220. package/dist/shortcuts/reception/operations/customparams.js +74 -0
  221. package/dist/shortcuts/reception/operations/doc.js +238 -0
  222. package/dist/shortcuts/reception/operations/docrender.js +36 -0
  223. package/dist/shortcuts/reception/operations/panels.js +179 -0
  224. package/dist/shortcuts/reception/operations/registry.js +26 -0
  225. package/dist/shortcuts/reception/operations/render-assets.js +184 -0
  226. package/dist/shortcuts/reception/operations/render.js +123 -0
  227. package/dist/shortcuts/reception/operations/runs.js +38 -0
  228. package/dist/shortcuts/reception/operations/schedule.js +127 -0
  229. package/dist/shortcuts/reception/operations/shared.js +196 -0
  230. package/dist/shortcuts/reception/operations/snapshot.js +68 -0
  231. package/dist/shortcuts/reception/operations/types.js +1 -0
  232. package/dist/shortcuts/reception/operations.js +33 -0
  233. package/dist/shortcuts/reception/upload.js +218 -0
  234. package/dist/shortcuts/recruit-stage/context.js +231 -0
  235. package/dist/shortcuts/recruit-stage/continuation.js +74 -0
  236. package/dist/shortcuts/recruit-stage/errors.js +65 -0
  237. package/dist/shortcuts/recruit-stage/host.js +109 -0
  238. package/dist/shortcuts/recruit-stage/index.js +115 -0
  239. package/dist/shortcuts/recruit-stage/manifest.js +29 -0
  240. package/dist/shortcuts/recruit-stage/operations/interview-arrange.js +722 -0
  241. package/dist/shortcuts/recruit-stage/operations/interview-feedback.js +269 -0
  242. package/dist/shortcuts/recruit-stage/operations/jd-create.js +719 -0
  243. package/dist/shortcuts/recruit-stage/operations/list.js +431 -0
  244. package/dist/shortcuts/recruit-stage/operations/registry.js +38 -0
  245. package/dist/shortcuts/recruit-stage/operations/resume-import.js +1354 -0
  246. package/dist/shortcuts/recruit-stage/operations/search.js +158 -0
  247. package/dist/shortcuts/recruit-stage/operations/types.js +25 -0
  248. package/dist/shortcuts/recruit-stage/school-tiers.json +318 -0
  249. package/dist/shortcuts/recruit-stage/shared.js +608 -0
  250. package/dist/shortcuts/workflow/continuation.js +2 -1
  251. package/dist/shortcuts/workflow/index.js +2 -0
  252. package/dist/shortcuts/workflow/operations/form.js +32 -8
  253. package/dist/shortcuts/workflow/operations/todoSmartConvert/detailFieldRules.js +4 -2
  254. package/dist/shortcuts/workflow/operations/todoSmartConvert/summaryCache.js +13 -6
  255. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailCache.js +17 -24
  256. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailFetcher.js +14 -9
  257. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +50 -8
  258. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.core.js +2 -1
  259. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.detail.js +17 -11
  260. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.group.js +7 -39
  261. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +3 -2
  262. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +51 -15
  263. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.pipeline.js +16 -1
  264. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +151 -63
  265. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.subGroup.js +56 -0
  266. package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +39 -14
  267. package/dist/shortcuts/workflow/operations/write.js +1 -1
  268. package/docs/_catalog.md +3 -0
  269. package/docs/agent-invoice.md +1 -1
  270. package/docs/archive-oa.md +1 -1
  271. package/docs/caizhilian.md +1 -1
  272. package/docs/calendar.md +1 -1
  273. package/docs/contract.md +1 -1
  274. package/docs/e10-auth.md +23 -1
  275. package/docs/ehr.md +2 -2
  276. package/docs/esb.md +1 -1
  277. package/docs/im.md +1 -1
  278. package/docs/invoice.md +8 -12
  279. package/docs/okr.md +1 -1
  280. package/docs/operation-manual.md +8 -0
  281. package/docs/reception.md +119 -0
  282. package/package.json +1 -1
  283. package/scripts/clean.mjs +43 -2
  284. package/scripts/install-skill-to-xiaoe.mjs +105 -0
  285. package/scripts/package-skill.mjs +4 -2
  286. package/skill-template/business-info.json +42 -2
  287. package/skill-template/domains/caizhilian.md +1 -1
  288. package/skill-template/domains/reception-flow.md +18 -0
  289. package/skill-template/domains/recruit-stage.md +29 -0
  290. package/skill-template/domains/yepiaotong.md +4 -7
  291. package/skills/weaver-e10-archive-oa/references/source-manifest.json +14 -14
  292. package/skills/weaver-e10-blog/references/blog-publish.md +1 -1
  293. package/skills/weaver-e10-blog/references/source-manifest.json +7 -7
  294. package/skills/weaver-e10-caizhilian/references/source-manifest.json +21 -21
  295. package/skills/weaver-e10-caizhilian/references/write-protocol.md +2 -2
  296. package/skills/weaver-e10-calendar/SKILL.md +2 -1
  297. package/skills/weaver-e10-calendar/references/calendar-write.md +55 -1
  298. package/skills/weaver-e10-cowork/SKILL.md +1 -1
  299. package/skills/weaver-e10-cowork/references/cowork-write.md +3 -1
  300. package/skills/weaver-e10-ebuilder-form/SKILL.md +1 -1
  301. package/skills/weaver-e10-ebuilder-form/references/custom-api.md +1 -1
  302. package/skills/weaver-e10-ebuilder-form/references/openapi-write.md +1 -1
  303. package/skills/weaver-e10-esb/SKILL.md +2 -2
  304. package/skills/weaver-e10-esb/references/source-manifest.json +22 -22
  305. package/skills/weaver-e10-esb/references/trigger.md +2 -2
  306. package/skills/weaver-e10-jinchengda/references/contract-clause-library-crud.md +1 -1
  307. package/skills/weaver-e10-jinchengda/references/contract-clause-reference-save.md +1 -1
  308. package/skills/weaver-e10-jinchengda/references/contract-request-write.md +1 -1
  309. package/skills/weaver-e10-jinchengda/references/source-manifest.json +29 -29
  310. package/skills/weaver-e10-jucailin/SKILL.md +1 -1
  311. package/skills/weaver-e10-jucailin/references/attend-write.md +10 -2
  312. package/skills/weaver-e10-jucailin/references/hr-contact.md +8 -0
  313. package/skills/weaver-e10-jucailin/references/hr-report.md +8 -0
  314. package/skills/weaver-e10-jucailin/references/recruit-create.md +14 -5
  315. package/skills/weaver-e10-jucailin/references/recruit-read.md +1 -1
  316. package/skills/weaver-e10-jucailin/references/recruit-write.md +5 -4
  317. package/skills/weaver-e10-mail/SKILL.md +1 -1
  318. package/skills/weaver-e10-meeting/SKILL.md +39 -7
  319. package/skills/weaver-e10-meeting/references/meeting-change.md +1 -1
  320. package/skills/weaver-e10-meeting/references/meeting-create.md +1 -1
  321. package/skills/weaver-e10-meeting/references/meeting-lifecycle.md +1 -1
  322. package/skills/weaver-e10-meeting/references/meeting-verification.md +1 -1
  323. package/skills/weaver-e10-okr/references/okr-align.md +1 -1
  324. package/skills/weaver-e10-okr/references/okr-keyresult.md +1 -1
  325. package/skills/weaver-e10-okr/references/okr-write.md +1 -1
  326. package/skills/weaver-e10-okr/references/source-manifest.json +8 -8
  327. package/skills/weaver-e10-plan/references/plan-report-write.md +1 -1
  328. package/skills/weaver-e10-plan/references/source-manifest.json +20 -20
  329. package/skills/weaver-e10-qiyecheng/references/loan-management.md +1 -1
  330. package/skills/weaver-e10-qiyecheng/references/source-manifest.json +18 -18
  331. package/skills/weaver-e10-reception-flow/SKILL.md +173 -0
  332. package/skills/weaver-e10-reception-flow/assets//350/241/214/347/250/213/345/215/225/346/250/241/346/235/277-/346/263/233/345/276/256.docx +0 -0
  333. package/skills/weaver-e10-reception-flow/data/fields-snapshot.json +213 -0
  334. package/skills/weaver-e10-reception-flow/references/browsertool.md +68 -0
  335. package/skills/weaver-e10-reception-flow/references/env-pitfalls.md +51 -0
  336. package/skills/weaver-e10-reception-flow/references/fields-snapshot.md +227 -0
  337. package/skills/weaver-e10-reception-flow/references/guide.md +179 -0
  338. package/skills/weaver-e10-reception-flow/scripts/locate.sh +14 -0
  339. package/skills/weaver-e10-reception-flow/scripts/render.py +724 -0
  340. package/skills/weaver-e10-recruit-stage/SKILL.md +230 -0
  341. package/skills/weaver-e10-recruit-stage/agents/openai.yaml +119 -0
  342. package/skills/weaver-e10-recruit-stage/lib/recruit-xiaoe-file.mjs +188 -0
  343. package/skills/weaver-e10-recruit-stage/lib/xiaoe-session.mjs +66 -0
  344. package/skills/weaver-e10-recruit-stage/references/position-templates.md +202 -0
  345. package/skills/weaver-e10-recruit-stage/references/recruit-arrange-interview.md +322 -0
  346. package/skills/weaver-e10-recruit-stage/references/recruit-capability-check.md +127 -0
  347. package/skills/weaver-e10-recruit-stage/references/recruit-check-install.md +65 -0
  348. package/skills/weaver-e10-recruit-stage/references/recruit-detail-process.md +63 -0
  349. package/skills/weaver-e10-recruit-stage/references/recruit-edit-interview-feedback.md +142 -0
  350. package/skills/weaver-e10-recruit-stage/references/recruit-jd-create.md +95 -0
  351. package/skills/weaver-e10-recruit-stage/references/recruit-jd-template.md +56 -0
  352. package/skills/weaver-e10-recruit-stage/references/recruit-list-candidate.md +101 -0
  353. package/skills/weaver-e10-recruit-stage/references/recruit-list-interview.md +148 -0
  354. package/skills/weaver-e10-recruit-stage/references/recruit-match-candidates.md +77 -0
  355. package/skills/weaver-e10-recruit-stage/references/recruit-output-links.md +59 -0
  356. package/skills/weaver-e10-recruit-stage/references/recruit-resolve-creator.md +69 -0
  357. package/skills/weaver-e10-recruit-stage/references/recruit-resolve-metadata.md +241 -0
  358. package/skills/weaver-e10-recruit-stage/references/recruit-resume-import.md +451 -0
  359. package/skills/weaver-e10-recruit-stage/references/recruit-resume-parse.md +128 -0
  360. package/skills/weaver-e10-recruit-stage/references/recruit-search-candidate.md +146 -0
  361. package/skills/weaver-e10-recruit-stage/references/recruit-urge-feedback.md +69 -0
  362. package/skills/weaver-e10-shared/SKILL.md +1 -1
  363. package/skills/weaver-e10-shared/references/e10-auth-and-session.md +10 -2
  364. package/skills/weaver-e10-shijingran/SKILL.md +7 -6
  365. package/skills/weaver-e10-shijingran/references/operations.md +3 -1
  366. package/skills/weaver-e10-shijingran/references/source-manifest.json +30 -28
  367. package/skills/weaver-e10-shijingran/references/write-operations.md +2 -0
  368. package/skills/weaver-e10-skill-maker/references/module-cli-generation.md +2 -0
  369. package/skills/weaver-e10-wenshuding/references/source-manifest.json +3 -3
  370. package/skills/weaver-e10-workflow/SKILL.md +4 -2
  371. package/skills/weaver-e10-workflow/aigroup/default.json +11 -9
  372. package/skills/weaver-e10-workflow/references/source-manifest.json +32 -32
  373. package/skills/weaver-e10-workflow/references/todo-smart-convert.md +23 -13
  374. package/skills/weaver-e10-workflow/tools/todo-summary.cjs +62 -20
  375. package/skills/weaver-e10-yepiaotong/SKILL.md +28 -36
  376. package/skills/weaver-e10-yepiaotong/references/invoice-agent-entry.md +6 -3
  377. package/skills/weaver-e10-yepiaotong/references/invoice-detail.md +13 -10
  378. package/skills/weaver-e10-yepiaotong/references/invoice-enterprise-list.md +2 -0
  379. package/skills/weaver-e10-yepiaotong/references/invoice-issuing-workflow.md +194 -155
  380. package/skills/weaver-e10-yepiaotong/references/invoice-output-view.md +28 -32
  381. package/skills/weaver-e10-yepiaotong/references/invoice-personal-list.md +5 -1
  382. package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +8 -10
  383. package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +211 -616
  384. package/skills/weaver-e10-yepiaotong/references/reim-examples.md +149 -117
  385. package/skills/weaver-e10-yepiaotong/references/reim-expense-subject-rules.md +17 -20
  386. package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +20 -39
  387. package/skills/weaver-e10-yepiaotong/references/reim-matching-rules.md +55 -22
  388. package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +7 -17
  389. package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +88 -92
  390. package/skills/weaver-e10-yepiaotong/references/source-manifest.json +144 -354
  391. package/skills/weaver-e10-yimiaoban/SKILL.md +1 -1
  392. package/skills/weaver-e10-yimiaoban/references/msg-write.md +1 -1
  393. package/skills/weaver-e10-yimiaoban/references/safety-boundaries.md +1 -1
  394. package/skills/weaver-e10-yimiaoban/references/source-manifest.json +7 -7
  395. package/dist/chunks/chunk-SPRHHSVC.js +0 -465
  396. package/dist/chunks/registry-KMHCPAAD.js +0 -22
  397. package/dist/shortcuts/invoice/markdown.js +0 -172
  398. package/dist/shortcuts/invoice/operations/issuing-qys.js +0 -424
  399. package/skills/weaver-e10-meeting.zip +0 -0
  400. package/skills/weaver-e10-yepiaotong/references/invoice-issuing-examples.md +0 -131
  401. package/skills/weaver-e10-yepiaotong/references/invoice-issuing-form-fill-rules.md +0 -179
@@ -1,20 +1,64 @@
1
1
  import { createRequire as __esbuildCreateRequire } from 'node:module';
2
2
  const require = __esbuildCreateRequire(import.meta.url);
3
+ import {
4
+ EHR_PAGES,
5
+ EhrCliError,
6
+ READ,
7
+ SCHEMA_DATE,
8
+ SCHEMA_ID,
9
+ SCHEMA_ID_LIST,
10
+ SCHEMA_MONTH,
11
+ SCHEMA_STRING_LIST,
12
+ WRITE,
13
+ addDays,
14
+ asObject,
15
+ assertDateRange,
16
+ assertEnum,
17
+ assertMonth,
18
+ assertNoForbiddenKeys,
19
+ buildListBody,
20
+ compact,
21
+ createRecruitContextLoader,
22
+ ehrAuthError,
23
+ ehrConfirmationError,
24
+ ehrNetworkError,
25
+ ehrPageUrl,
26
+ ehrPartialError,
27
+ ehrSuccess,
28
+ ehrValidationError,
29
+ fetchListRows,
30
+ normalizePaged,
31
+ pickDefined,
32
+ recruitOperations,
33
+ requireDateRange,
34
+ resolveSecondAuthToken,
35
+ schemaOf,
36
+ toIdList,
37
+ toNumber,
38
+ toPageQuery,
39
+ toPositiveInt
40
+ } from "./chunk-HIT4Y6OI.js";
41
+ import {
42
+ reportPlatformError
43
+ } from "./chunk-6N4JPNFL.js";
44
+ import {
45
+ CONTINUATION_TTL_MS,
46
+ CONTINUATION_TTL_SECONDS
47
+ } from "./chunk-7BDPM5ST.js";
3
48
  import {
4
49
  E10ApiError,
5
50
  createE10RequestRuntime,
6
51
  isE10SessionExpiredResponse,
7
52
  requireE10Session
8
- } from "./chunk-WFFNM65B.js";
53
+ } from "./chunk-ETNJSKMM.js";
9
54
  import {
10
55
  E10_SESSION_EXPIRED_MESSAGE,
11
56
  getActiveProfile
12
- } from "./chunk-4TEDNCON.js";
57
+ } from "./chunk-UFIT2UU3.js";
13
58
  import {
14
- CliError,
15
59
  isCliError,
16
60
  toErrorEnvelope
17
- } from "./chunk-LUSPKZKY.js";
61
+ } from "./chunk-UG5G54VL.js";
18
62
  import "./chunk-BUSC6UAE.js";
19
63
 
20
64
  // src/shortcuts/ehr/index.ts
@@ -26,62 +70,6 @@ import { existsSync } from "node:fs";
26
70
  import { chmod, mkdir, readFile, writeFile } from "node:fs/promises";
27
71
  import { homedir } from "node:os";
28
72
  import { resolve } from "node:path";
29
-
30
- // src/shortcuts/ehr/errors.ts
31
- var EhrCliError = class extends CliError {
32
- type;
33
- subtype;
34
- code;
35
- retryable;
36
- stage;
37
- details;
38
- partialData;
39
- constructor(type, subtype, message, options = {}) {
40
- super(message, options.exitCode ?? 5 /* InternalError */);
41
- this.name = "EhrCliError";
42
- this.type = type;
43
- this.subtype = subtype;
44
- this.code = options.code;
45
- this.retryable = options.retryable ?? false;
46
- this.stage = options.stage;
47
- this.details = options.details;
48
- this.partialData = options.partialData;
49
- }
50
- };
51
- function ehrValidationError(subtype, message, details) {
52
- return new EhrCliError("validation", subtype, message, {
53
- details,
54
- exitCode: 2 /* UsageError */
55
- });
56
- }
57
- function ehrAuthError(subtype, message, details) {
58
- return new EhrCliError("authentication", subtype, message, {
59
- details,
60
- exitCode: 3 /* AuthError */
61
- });
62
- }
63
- function ehrNetworkError(subtype, message, options = {}) {
64
- return new EhrCliError("network", subtype, message, {
65
- ...options,
66
- retryable: options.retryable ?? true,
67
- exitCode: 4 /* NetworkError */
68
- });
69
- }
70
- function ehrConfirmationError(action, details) {
71
- return new EhrCliError("confirmation", "required", "\u8BE5\u64CD\u4F5C\u9700\u8981\u660E\u786E\u786E\u8BA4", {
72
- details: { action, ...details },
73
- exitCode: 10 /* ConfirmationRequired */
74
- });
75
- }
76
- function ehrPartialError(message, partialData, details) {
77
- return new EhrCliError("partial", "write_uncertain", message, {
78
- details,
79
- partialData,
80
- exitCode: 11 /* Partial */
81
- });
82
- }
83
-
84
- // src/shortcuts/ehr/continuation.ts
85
73
  function stateRoot(ctx) {
86
74
  const configured = ctx?.config?.path();
87
75
  if (configured) return resolve(configured, "..");
@@ -109,7 +97,7 @@ function signature(payload, key) {
109
97
  }
110
98
  function createEhrContinuationSigner(ctx) {
111
99
  return {
112
- async issue(payload, ttlMs = 10 * 6e4) {
100
+ async issue(payload, ttlMs = CONTINUATION_TTL_MS) {
113
101
  const issuedAt = Date.now();
114
102
  const body = encode({ ...payload, issuedAt, expiresAt: issuedAt + ttlMs });
115
103
  const sig = signature(body, await loadKey(ctx));
@@ -325,184 +313,6 @@ function createEhrHost(ctx, dependencies = {}) {
325
313
  return { request, getSession, buildCardSign };
326
314
  }
327
315
 
328
- // src/shortcuts/ehr/operations/types.ts
329
- var READ = "read";
330
- var WRITE = "write";
331
- function ehrSuccess(action, data, meta) {
332
- const payload = { ok: true, action, data };
333
- if (meta && Object.keys(meta).length > 0) payload.meta = meta;
334
- return payload;
335
- }
336
- function schemaOf(properties, options = {}) {
337
- return {
338
- type: "object",
339
- additionalProperties: false,
340
- properties,
341
- ...options.required?.length ? { required: options.required } : {},
342
- ...options.description ? { description: options.description } : {}
343
- };
344
- }
345
- var SCHEMA_DATE = { type: "string", pattern: "^\\d{4}-\\d{2}-\\d{2}$" };
346
- var SCHEMA_MONTH = { type: "string", pattern: "^\\d{4}-\\d{2}$" };
347
- var SCHEMA_ID = { oneOf: [{ type: "integer" }, { type: "string", pattern: "^\\d+$" }] };
348
- var SCHEMA_ID_LIST = { type: "array", items: SCHEMA_ID };
349
- var SCHEMA_STRING_LIST = { type: "array", items: { type: "string" } };
350
-
351
- // src/shortcuts/ehr/operations/shared.ts
352
- var FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
353
- function asObject(value) {
354
- if (!value || typeof value !== "object" || Array.isArray(value)) {
355
- throw ehrValidationError("input_not_object", "\u8F93\u5165\u5FC5\u987B\u662F JSON \u5BF9\u8C61");
356
- }
357
- return value;
358
- }
359
- function assertNoForbiddenKeys(input) {
360
- for (const key of Object.keys(input)) {
361
- if (FORBIDDEN_KEYS.has(key)) {
362
- throw ehrValidationError("forbidden_key", `\u8F93\u5165\u5305\u542B\u975E\u6CD5\u5B57\u6BB5\uFF1A${key}`);
363
- }
364
- }
365
- }
366
- var DATE_PATTERN = /^\d{4}-\d{2}-\d{2}$/;
367
- var MONTH_PATTERN = /^\d{4}-\d{2}$/;
368
- function isDate(value) {
369
- return typeof value === "string" && DATE_PATTERN.test(value);
370
- }
371
- function isMonth(value) {
372
- return typeof value === "string" && MONTH_PATTERN.test(value);
373
- }
374
- function isRealDate(value) {
375
- const [year, month, day] = value.split("-").map(Number);
376
- if (month < 1 || month > 12) return false;
377
- const daysInMonth = new Date(Date.UTC(year, month, 0)).getUTCDate();
378
- return day >= 1 && day <= daysInMonth;
379
- }
380
- function assertDate(value, field) {
381
- if (!isDate(value)) throw ehrValidationError("date_invalid", `${field} \u5FC5\u987B\u662F YYYY-MM-DD \u683C\u5F0F`);
382
- const text = value;
383
- if (!isRealDate(text)) {
384
- throw ehrValidationError("date_invalid", `${field} \u4E0D\u662F\u5408\u6CD5\u65E5\u671F\uFF08\u6708\u4EFD\u9700 01-12\uFF0C\u65E5\u671F\u9700\u5728\u8BE5\u6708\u6709\u6548\u8303\u56F4\u5185\uFF09\uFF1A${text}`);
385
- }
386
- return text;
387
- }
388
- function assertMonth(value, field) {
389
- if (!isMonth(value)) throw ehrValidationError("month_invalid", `${field} \u5FC5\u987B\u662F YYYY-MM \u683C\u5F0F`);
390
- const text = value;
391
- const month = Number(text.slice(5));
392
- if (month < 1 || month > 12) {
393
- throw ehrValidationError("month_invalid", `${field} \u7684\u6708\u4EFD\u5FC5\u987B\u5728 01-12\uFF1A${text}`);
394
- }
395
- return text;
396
- }
397
- function toNumber(value, field) {
398
- if (value === void 0 || value === null || value === "") return void 0;
399
- const numeric = Number(value);
400
- if (!Number.isFinite(numeric)) {
401
- throw ehrValidationError("number_invalid", `${field} \u5FC5\u987B\u662F\u6570\u5B57`);
402
- }
403
- return numeric;
404
- }
405
- function toPositiveInt(value, field) {
406
- if (value === void 0 || value === null || value === "") return void 0;
407
- const numeric = Number(value);
408
- if (!Number.isFinite(numeric)) {
409
- throw ehrValidationError("number_invalid", `${field} \u5FC5\u987B\u662F\u6570\u5B57`);
410
- }
411
- const truncated = Math.trunc(numeric);
412
- if (truncated !== numeric || truncated <= 0) {
413
- throw ehrValidationError("number_invalid", `${field} \u5FC5\u987B\u662F\u6B63\u6574\u6570`);
414
- }
415
- return truncated;
416
- }
417
- function toIdList(value, field) {
418
- if (value === void 0 || value === null) return void 0;
419
- if (!Array.isArray(value)) throw ehrValidationError("id_list_invalid", `${field} \u5FC5\u987B\u662F ID \u6570\u7EC4`);
420
- return value.map((item, index) => {
421
- if (item === void 0 || item === null || item === "") {
422
- throw ehrValidationError("id_list_invalid", `${field}[${index}] \u4E0D\u80FD\u4E3A\u7A7A`);
423
- }
424
- const numeric = Number(item);
425
- if (!Number.isFinite(numeric)) {
426
- throw ehrValidationError("id_list_invalid", `${field}[${index}] \u5FC5\u987B\u662F\u6570\u5B57 ID`);
427
- }
428
- return numeric;
429
- });
430
- }
431
- function pickDefined(value, keys) {
432
- const result = {};
433
- for (const key of keys) {
434
- if (value[key] !== void 0) result[key] = value[key];
435
- }
436
- return result;
437
- }
438
- function compact(body) {
439
- for (const key of Object.keys(body)) {
440
- if (body[key] === void 0) delete body[key];
441
- }
442
- return body;
443
- }
444
- function assertDateRange(args, startField, endField) {
445
- const start = args[startField];
446
- const end = args[endField];
447
- if ((start === void 0 || start === null) !== (end === void 0 || end === null)) {
448
- throw ehrValidationError("date_range_incomplete", `${startField} \u4E0E ${endField} \u5FC5\u987B\u6210\u5BF9\u63D0\u4F9B`);
449
- }
450
- if (start === void 0 || start === null) return {};
451
- const startDate = assertDate(start, startField);
452
- const endDate = assertDate(end, endField);
453
- if (startDate > endDate) {
454
- throw ehrValidationError("date_range_invalid", `${startField} \u4E0D\u5F97\u665A\u4E8E ${endField}`);
455
- }
456
- return { start: startDate, end: endDate };
457
- }
458
- function requireDateRange(args, startField = "beginDate", endField = "endDate") {
459
- const start = args[startField];
460
- const end = args[endField];
461
- if (start === void 0 || start === null || start === "" || end === void 0 || end === null || end === "") {
462
- throw ehrValidationError("date_range_required", `${startField} \u4E0E ${endField} \u5FC5\u586B\uFF0C\u683C\u5F0F YYYY-MM-DD`);
463
- }
464
- const range = assertDateRange(args, startField, endField);
465
- return { beginDate: range.start, endDate: range.end };
466
- }
467
- function unwrapData(response) {
468
- if (!response || typeof response !== "object") return response;
469
- return response.data;
470
- }
471
- function normalizePaged(response) {
472
- const data = unwrapData(response);
473
- const page = {};
474
- const candidates = [data?.page, response?.page, data, response];
475
- for (const source of candidates) {
476
- if (!source || typeof source !== "object") continue;
477
- for (const key of ["pageNo", "current", "pageSize", "total", "totalCount", "totalPage", "tableId"]) {
478
- if (source[key] !== void 0 && page[key] === void 0) page[key] = source[key];
479
- }
480
- }
481
- return { data, page };
482
- }
483
- function toPageQuery(args) {
484
- const page = {};
485
- const current = toPositiveInt(args?.current, "current");
486
- const pageSize = toNumber(args?.pageSize, "pageSize");
487
- const pageNo = toNumber(args?.pageNo, "pageNo");
488
- if (current !== void 0) page.current = current;
489
- if (pageSize !== void 0) page.pageSize = pageSize;
490
- if (pageNo !== void 0) page.pageNo = pageNo;
491
- return page;
492
- }
493
- var SECOND_AUTH_TOKEN_DEFAULT = "DONT_NEED";
494
- function resolveSecondAuthToken(value) {
495
- if (typeof value === "string" && value.trim()) return value.trim();
496
- return SECOND_AUTH_TOKEN_DEFAULT;
497
- }
498
- function assertEnum(value, allowed, field) {
499
- const text = typeof value === "string" ? value : String(value);
500
- if (!allowed.includes(text)) {
501
- throw ehrValidationError("enum_invalid", `${field} \u53D6\u503C\u5FC5\u987B\u662F ${allowed.join(" / ")} \u4E4B\u4E00`);
502
- }
503
- return text;
504
- }
505
-
506
316
  // src/shortcuts/ehr/operations/attend-read.ts
507
317
  var ATTEND_STATUS = [
508
318
  "SIGN_IN_LATE",
@@ -905,7 +715,6 @@ var attendReadOperations = [
905
715
 
906
716
  // src/shortcuts/ehr/operations/attend-write.ts
907
717
  import { createHash as createHash2 } from "node:crypto";
908
- var CONTINUATION_TTL_SECONDS = 600;
909
718
  var CARD_TYPES = ["CHECKIN", "CHECKOUT", "LEAVE", "RETURN", "CHECKIN_AND_RETURN", "CHECKOUT_AND_LEAVE"];
910
719
  var APPEAL_TYPES = [
911
720
  "leave",
@@ -1229,9 +1038,39 @@ var ehrAttendAppealSaveApply = {
1229
1038
  }
1230
1039
  throw error;
1231
1040
  }
1041
+ const session = await env.host.getSession();
1042
+ const appealListUrl = ehrPageUrl(session.baseUrl, EHR_PAGES.attendAbnormal);
1043
+ let appeal = null;
1044
+ let locateWarning;
1045
+ try {
1046
+ const listResp = await env.host.request({
1047
+ method: "POST",
1048
+ path: "/api/attend/web/appeal/getAppealList",
1049
+ body: {
1050
+ beginDate: addDays(String(args.attendDay), -1),
1051
+ endDate: addDays(String(args.attendDay), 1),
1052
+ current: 1,
1053
+ pageSize: 50
1054
+ }
1055
+ });
1056
+ const payload2 = listResp?.data;
1057
+ const rows = Array.isArray(payload2?.data) ? payload2.data : Array.isArray(payload2?.rows) ? payload2.rows : Array.isArray(payload2) ? payload2 : [];
1058
+ const day = String(args.attendDay);
1059
+ const desc = String(args.appealDesc ?? "");
1060
+ const pick = rows.find((r) => String(r?.attendDay ?? r?.attend_date ?? r?.attendDate ?? "").startsWith(day)) || (desc ? rows.find((r) => String(r?.appealDesc ?? r?.appeal_desc ?? "").includes(desc)) : null) || null;
1061
+ if (pick) appeal = pick;
1062
+ else locateWarning = "\u672A\u5728\u7533\u8BC9\u5217\u8868\u4E2D\u5B9A\u4F4D\u5230\u672C\u6B21\u8BB0\u5F55\uFF08\u53EF\u80FD\u521A\u63D0\u4EA4\u5C1A\u5728\u540C\u6B65\uFF09\uFF0C\u8BF7\u7A0D\u540E\u7528 ehr.attend.appeal.list \u590D\u6838";
1063
+ } catch (e) {
1064
+ locateWarning = "\u7533\u8BC9\u5217\u8868\u56DE\u67E5\u5931\u8D25\uFF1A" + (e?.message || "\u672A\u77E5\u539F\u56E0") + "\uFF1B\u8BF7\u7A0D\u540E\u7528 ehr.attend.appeal.list \u590D\u6838";
1065
+ }
1232
1066
  return ehrSuccess("ehr.attend.appeal.save.apply", {
1233
1067
  status: "COMPLETE",
1234
1068
  result: response?.data,
1069
+ /** 定位到的新建申诉记录(含申诉 ID 等,处理申诉时用其 id) */
1070
+ appeal,
1071
+ /** 考勤异常/申诉页面地址(已取证路由,禁止改拼) */
1072
+ appealListUrl,
1073
+ ...locateWarning ? { locateWarning } : {},
1235
1074
  verifyHint: "\u53EF\u901A\u8FC7 ehr.attend.appeal.list \u56DE\u67E5\u7533\u8BC9\u662F\u5426\u5DF2\u751F\u6210"
1236
1075
  });
1237
1076
  }
@@ -1560,7 +1399,8 @@ var contactSearch = {
1560
1399
  body: compact(body)
1561
1400
  });
1562
1401
  const { data, page } = normalizePaged(response);
1563
- return ehrSuccess("ehr.hr.contact.search", data, { page });
1402
+ const hrSession = await host.getSession();
1403
+ return ehrSuccess("ehr.hr.contact.search", data, { page, viewUrl: ehrPageUrl(hrSession.baseUrl, EHR_PAGES.hrEmployeeManager), profileUrlTemplate: ehrPageUrl(hrSession.baseUrl, "/sp/hrm/profileInfo/{\u4EBA\u5458id}") });
1564
1404
  }
1565
1405
  };
1566
1406
  var contactCount = {
@@ -1684,7 +1524,8 @@ var birthdayList = {
1684
1524
  body
1685
1525
  });
1686
1526
  const { data, page } = normalizePaged(response);
1687
- return ehrSuccess("ehr.hr.birthday.list", data, { page });
1527
+ const hrSession = await host.getSession();
1528
+ return ehrSuccess("ehr.hr.birthday.list", data, { page, viewUrl: ehrPageUrl(hrSession.baseUrl, EHR_PAGES.hrBirthdayList), profileUrlTemplate: ehrPageUrl(hrSession.baseUrl, "/sp/hrm/profileInfo/{\u4EBA\u5458id}") });
1688
1529
  }
1689
1530
  };
1690
1531
  var empchangeConditions = {
@@ -1758,7 +1599,8 @@ var empchangeList = {
1758
1599
  body: compact(body)
1759
1600
  });
1760
1601
  const { data, page } = normalizePaged(response);
1761
- return ehrSuccess("ehr.hr.empchange.list", data, { page });
1602
+ const hrSession = await host.getSession();
1603
+ return ehrSuccess("ehr.hr.empchange.list", data, { page, viewUrl: ehrPageUrl(hrSession.baseUrl, EHR_PAGES.hrPersonalStateChange), profileUrlTemplate: ehrPageUrl(hrSession.baseUrl, "/sp/hrm/profileInfo/{\u4EBA\u5458id}") });
1762
1604
  }
1763
1605
  };
1764
1606
  var hrContactOperations = [
@@ -2104,7 +1946,8 @@ var reportDeptTable = {
2104
1946
  body: buildPersonReport(args, "departmentName")
2105
1947
  });
2106
1948
  const { data, page } = normalizePaged(response);
2107
- return ehrSuccess("ehr.hr.report.dept.table", data, { page });
1949
+ const hrSession = await host.getSession();
1950
+ return ehrSuccess("ehr.hr.report.dept.table", data, { page, viewUrl: ehrPageUrl(hrSession.baseUrl, EHR_PAGES.hrReportDeptPerson), profileUrlTemplate: ehrPageUrl(hrSession.baseUrl, "/sp/hrm/profileInfo/{\u4EBA\u5458id}") });
2108
1951
  }
2109
1952
  };
2110
1953
  var reportPosiTable = {
@@ -2123,7 +1966,8 @@ var reportPosiTable = {
2123
1966
  body: buildPersonReport(args, "positionName")
2124
1967
  });
2125
1968
  const { data, page } = normalizePaged(response);
2126
- return ehrSuccess("ehr.hr.report.posi.table", data, { page });
1969
+ const hrSession = await host.getSession();
1970
+ return ehrSuccess("ehr.hr.report.posi.table", data, { page, viewUrl: ehrPageUrl(hrSession.baseUrl, EHR_PAGES.hrReportPosiPerson), profileUrlTemplate: ehrPageUrl(hrSession.baseUrl, "/sp/hrm/profileInfo/{\u4EBA\u5458id}") });
2127
1971
  }
2128
1972
  };
2129
1973
  var reportJobTable = {
@@ -2142,7 +1986,8 @@ var reportJobTable = {
2142
1986
  body: buildPersonReport(args, "jobName")
2143
1987
  });
2144
1988
  const { data, page } = normalizePaged(response);
2145
- return ehrSuccess("ehr.hr.report.job.table", data, { page });
1989
+ const hrSession = await host.getSession();
1990
+ return ehrSuccess("ehr.hr.report.job.table", data, { page, viewUrl: ehrPageUrl(hrSession.baseUrl, EHR_PAGES.hrReportJobPerson), profileUrlTemplate: ehrPageUrl(hrSession.baseUrl, "/sp/hrm/profileInfo/{\u4EBA\u5458id}") });
2146
1991
  }
2147
1992
  };
2148
1993
  var reportJobTypeTable = {
@@ -2249,7 +2094,8 @@ var estEmpTable = {
2249
2094
  }
2250
2095
  });
2251
2096
  const { data, page } = normalizePaged(response);
2252
- return ehrSuccess("ehr.hr.est.emp.table", data, { page });
2097
+ const hrSession = await host.getSession();
2098
+ return ehrSuccess("ehr.hr.est.emp.table", data, { page, viewUrl: ehrPageUrl(hrSession.baseUrl, EHR_PAGES.hrTpReportTp), profileUrlTemplate: ehrPageUrl(hrSession.baseUrl, "/sp/hrm/profileInfo/{\u4EBA\u5458id}") });
2253
2099
  }
2254
2100
  };
2255
2101
  var estDcEmpTable = {
@@ -2295,7 +2141,8 @@ var estDcEmpTable = {
2295
2141
  }
2296
2142
  });
2297
2143
  const { data, page } = normalizePaged(response);
2298
- return ehrSuccess("ehr.hr.est.dc.emp.table", data, { page });
2144
+ const hrSession = await host.getSession();
2145
+ return ehrSuccess("ehr.hr.est.dc.emp.table", data, { page, viewUrl: ehrPageUrl(hrSession.baseUrl, EHR_PAGES.hrTpReportHw), profileUrlTemplate: ehrPageUrl(hrSession.baseUrl, "/sp/hrm/profileInfo/{\u4EBA\u5458id}") });
2299
2146
  }
2300
2147
  };
2301
2148
  var turnEmpTable = {
@@ -2342,7 +2189,8 @@ var turnEmpTable = {
2342
2189
  body
2343
2190
  });
2344
2191
  const { data, page } = normalizePaged(response);
2345
- return ehrSuccess("ehr.hr.turn.emp.table", data, { page });
2192
+ const hrSession = await host.getSession();
2193
+ return ehrSuccess("ehr.hr.turn.emp.table", data, { page, viewUrl: ehrPageUrl(hrSession.baseUrl, EHR_PAGES.hrTpReportTurn), profileUrlTemplate: ehrPageUrl(hrSession.baseUrl, "/sp/hrm/profileInfo/{\u4EBA\u5458id}") });
2346
2194
  }
2347
2195
  };
2348
2196
  var propsSa = {
@@ -2419,928 +2267,8 @@ var hrReportOperations = [
2419
2267
  propsTable
2420
2268
  ];
2421
2269
 
2422
- // src/shortcuts/ehr/operations/recruit.ts
2423
- import { randomBytes as randomBytes2, randomUUID } from "node:crypto";
2424
- import { existsSync as existsSync2, mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs";
2425
- import { homedir as homedir2 } from "node:os";
2426
- import { join, resolve as resolve2 } from "node:path";
2427
- var RECRUIT_APP_TAG = "weaver-recruit-service";
2428
- var RECRUIT_TAGS = {
2429
- talent_pool: "uf_rcrt_talent_pool",
2430
- interview_plan: "uf_rcrt_interview_plan",
2431
- interview_detail: "uf_rcrt_interview_detail",
2432
- demand_manage: "uf_rcrt_demand_manage",
2433
- position_manage: "uf_rcrt_position_manage",
2434
- entry_manage: "uf_rcrt_entry_manage",
2435
- offer: "uf_rcrt_offer",
2436
- offer_sending: "uf_rcrt_offer_sending",
2437
- candidate_manage: "uf_rcrt_candidate_manage",
2438
- entry_transact: "uf_rcrt_entry_transact",
2439
- entry_cancel: "uf_rcrt_entry_cancel",
2440
- entry_change: "uf_rcrt_entry_change",
2441
- dictionary: "uf_rcrt_dictionary",
2442
- biz_config: "uf_rcrt_biz_config_mapper"
2443
- };
2444
- var LIST_KEYWORDS = {
2445
- talent: ["\u4EBA\u624D\u5E93", "\u4EBA\u624D\u7BA1\u7406"],
2446
- demand: ["\u62DB\u8058\u9700\u6C42", "\u9700\u6C42"],
2447
- position: ["\u62DB\u8058\u804C\u4F4D", "\u804C\u4F4D\u5217\u8868", "\u804C\u4F4D\u7BA1\u7406"],
2448
- entry: ["\u5165\u804C\u7BA1\u7406"],
2449
- offer: ["\u5F55\u7528\u7BA1\u7406", "offer\u7BA1\u7406", "offer"],
2450
- interview: ["\u9762\u8BD5\u7BA1\u7406"],
2451
- biz_config: ["\u4E1A\u52A1\u914D\u7F6E\u6620\u5C04\u8868"]
2452
- };
2453
- var LIST_TYPES = {
2454
- demand: { listKey: "demand", formType: "demand_manage", title: "\u62DB\u8058\u9700\u6C42" },
2455
- position: { listKey: "position", formType: "position_manage", title: "\u62DB\u8058\u804C\u4F4D" },
2456
- entry: { listKey: "entry", formType: "entry_manage", title: "\u5165\u804C\u7BA1\u7406" },
2457
- offer: { listKey: "offer", formType: "offer", title: "\u5F55\u7528\u7BA1\u7406" }
2458
- };
2459
- var INTERNAL_KEYS = /* @__PURE__ */ new Set([
2460
- "id",
2461
- "form_data_id",
2462
- "form_table_id",
2463
- "rowKey",
2464
- "ebrecord_rowkey",
2465
- "isFollow",
2466
- "is_flow",
2467
- "data_status",
2468
- "data_status_value",
2469
- "update_time",
2470
- "formDataId",
2471
- "isFollowSearch",
2472
- "isShareToMe"
2473
- ]);
2474
- var DISPLAY_UI_KEYS = /* @__PURE__ */ new Set([
2475
- ...INTERNAL_KEYS,
2476
- "operate",
2477
- "isToDo",
2478
- "todoPropSpan",
2479
- "flow_status"
2480
- ]);
2481
- function randHex32() {
2482
- return randomUUID().replace(/-/g, "");
2483
- }
2484
- function randHex6() {
2485
- return randomBytes2(3).toString("hex");
2486
- }
2487
- function cacheDirFor(baseUrl) {
2488
- const url = new URL(baseUrl);
2489
- const host = url.hostname + (url.port ? `_${url.port}` : "");
2490
- const envRoot = process.env.E10_SKILL_CACHE_DIR;
2491
- if (envRoot) return join(envRoot, host);
2492
- const home = process.env.WEAVER_WORK_CLI_HOME || process.env.WORK_CLI_HOME || resolve2(homedir2(), ".weaver-work-cli");
2493
- return join(home, "env-cache", "recruit-ops", host);
2494
- }
2495
- function namesOf(field) {
2496
- if (!field) return null;
2497
- let arr;
2498
- if (Array.isArray(field)) arr = field;
2499
- else if (typeof field === "object") arr = [field];
2500
- else if (typeof field === "string") {
2501
- const text = field.trim();
2502
- if (!text.startsWith("[") && !text.startsWith("{")) return text || null;
2503
- try {
2504
- arr = JSON.parse(text);
2505
- } catch {
2506
- return text || null;
2507
- }
2508
- if (!Array.isArray(arr)) arr = [arr];
2509
- } else return null;
2510
- const names = arr.map((item) => item && typeof item === "object" ? item.name || item.username || item.text || item.title : null).filter(Boolean);
2511
- return names.length ? names.join("\u3001") : null;
2512
- }
2513
- function isPlainId(value) {
2514
- return value != null && /^\d+$/.test(String(value).trim());
2515
- }
2516
- var RecruitContextError = class extends Error {
2517
- subtype;
2518
- constructor(subtype, message) {
2519
- super(message);
2520
- this.subtype = subtype;
2521
- }
2522
- };
2523
- async function fetchFormFields(host, appId, objId) {
2524
- const form = new FormData();
2525
- form.set("groupId", appId);
2526
- form.set("sourceId", objId);
2527
- form.set("sourceType", "FORM");
2528
- form.set("detailFieldsGroup", "true");
2529
- form.set("enableMerge", "true");
2530
- form.set("customParam", '{"terminal":""}');
2531
- form.set("params", "[]");
2532
- const response = await host.request({
2533
- method: "POST",
2534
- path: "/api/ebuilder/common/ds/fields",
2535
- multipart: form
2536
- });
2537
- const fmap = {};
2538
- const omap = {};
2539
- for (const group of response?.data || []) {
2540
- for (const field of group?.fields || []) {
2541
- const config = field?.config || {};
2542
- const dataKey = config.dataKey || "";
2543
- const fieldId = String(field?.id || "");
2544
- if (dataKey && fieldId) fmap[dataKey] = fieldId;
2545
- if (fieldId && Array.isArray(config.options) && config.options.length) {
2546
- const map = {};
2547
- for (const option of config.options) {
2548
- if (!option || typeof option !== "object") continue;
2549
- const name = option.name;
2550
- let selectionId = option.selectionId;
2551
- if (!selectionId && typeof option.extra === "string") {
2552
- try {
2553
- const extra = JSON.parse(option.extra);
2554
- selectionId = extra.selectionId || extra.id;
2555
- } catch {
2556
- }
2557
- }
2558
- if (!selectionId) selectionId = option.value || option.valueKey || option.id;
2559
- if (selectionId && name) map[String(selectionId)] = name;
2560
- }
2561
- if (Object.keys(map).length) omap[fieldId] = map;
2562
- }
2563
- }
2564
- }
2565
- return { fmap, omap };
2566
- }
2567
- async function resolveRecruitEnv(host, appId) {
2568
- const forms = {};
2569
- let tenantKey = "";
2570
- for (const [logic, tag] of Object.entries(RECRUIT_TAGS)) {
2571
- const response = await host.request({
2572
- path: "/api/ebuilder/form/obj/getObjsByTag",
2573
- query: { appId, tag }
2574
- });
2575
- const entry = Array.isArray(response?.data) && response.data.length ? response.data[0] : null;
2576
- forms[logic] = {
2577
- objId: String(entry?.id || ""),
2578
- formId: String(entry?.formId || ""),
2579
- objName: entry?.objName || ""
2580
- };
2581
- if (!tenantKey && entry?.tenantKey) tenantKey = String(entry.tenantKey);
2582
- }
2583
- const menuResponse = await host.request({
2584
- path: "/api/cusapp/app/allMenus",
2585
- query: { isFront: 1, appId, terminalType: "PC" }
2586
- });
2587
- const flat = [];
2588
- const walk = (nodes) => {
2589
- for (const node of nodes || []) {
2590
- if (node && typeof node === "object") {
2591
- flat.push(node);
2592
- walk(node.children || node.childs);
2593
- }
2594
- }
2595
- };
2596
- const menuData = menuResponse?.data;
2597
- walk(typeof menuData === "object" && menuData ? menuData.cusAppMenus || menuData : menuData);
2598
- const searchMenus = [];
2599
- const pages = [];
2600
- for (const node of flat) {
2601
- if (node.pageType === "SEARCH") {
2602
- searchMenus.push({ menuName: node.menuName, listId: String(node.pageId || ""), cusMenuId: String(node.id || "") });
2603
- } else if (node.pageType === "PAGE") {
2604
- pages.push({ menuName: node.menuName, pageId: String(node.pageId || "") });
2605
- }
2606
- }
2607
- const fields = {};
2608
- const fieldOptions = {};
2609
- const resolvedForms = Object.entries(forms).filter(([, v]) => v.objId);
2610
- await Promise.all(resolvedForms.map(async ([logic, entry]) => {
2611
- const { fmap, omap } = await fetchFormFields(host, appId, entry.objId);
2612
- if (Object.keys(fmap).length) fields[entry.objId] = fmap;
2613
- if (Object.keys(omap).length) fieldOptions[entry.objId] = omap;
2614
- void logic;
2615
- }));
2616
- const dictByName = {};
2617
- const dictRaw = [];
2618
- const dictMenu = searchMenus.find((m) => (m.menuName || "").trim() === "\u6570\u636E\u5B57\u5178") || null;
2619
- const dictObjId = forms.dictionary?.objId || "";
2620
- if (dictObjId && dictMenu) {
2621
- const size = 500;
2622
- let current = 1;
2623
- for (; ; ) {
2624
- const response = await host.request({
2625
- path: `/api/ebuilder/form/list/getListDatas?passid=${dictObjId}&cid=${dictObjId}`,
2626
- body: {
2627
- current,
2628
- pageSize: size,
2629
- tableuid: randHex32(),
2630
- listId: dictMenu.listId,
2631
- searchParamData: { searchType: "3", type: "and" },
2632
- terminal: "PC",
2633
- browser: "Chrome",
2634
- requiredMatch: 1,
2635
- mapResult: 1,
2636
- recheckQuery: 1,
2637
- isFollow: 0,
2638
- isShareToMe: 0,
2639
- filterCondition: {},
2640
- cusMenuId: dictMenu.cusMenuId,
2641
- urlPageTitle: "\u6570\u636E\u5B57\u5178",
2642
- menuName: "\u6570\u636E\u5B57\u5178"
2643
- },
2644
- headers: { ebBusinessId: dictMenu.listId }
2645
- });
2646
- const rows = response?.data?.data || [];
2647
- for (const row of rows) {
2648
- const name = row.selection_name;
2649
- const optionId = row.form_data_id;
2650
- if (name && optionId) {
2651
- (dictByName[String(name)] ||= []).push(String(optionId));
2652
- dictRaw.push({ selection_name: String(name), option_id: String(optionId), dict_type: row.dict_type, browser_key: row.browser_key });
2653
- }
2654
- }
2655
- if (rows.length < size) break;
2656
- current += 1;
2657
- }
2658
- }
2659
- let ebdDetailPageId = "";
2660
- let selfUse = "0";
2661
- const bizConfig = forms.biz_config || { objId: "", formId: "", objName: "" };
2662
- const bizConfigMenu = searchMenus.find((m) => (m.menuName || "").trim() === "\u4E1A\u52A1\u914D\u7F6E\u6620\u5C04\u8868") || null;
2663
- if (bizConfig.objId && bizConfigMenu) {
2664
- try {
2665
- const { fmap } = await fetchFormFields(host, appId, bizConfig.objId);
2666
- const keyField = fmap.config_key || "";
2667
- const valueField = fmap.config || "";
2668
- if (keyField && valueField) {
2669
- let current = 1;
2670
- for (; ; ) {
2671
- const response = await host.request({
2672
- path: `/api/ebuilder/form/list/getListDatas?passid=${bizConfig.objId}&cid=${bizConfig.objId}`,
2673
- body: {
2674
- current,
2675
- pageSize: 100,
2676
- tableuid: randHex32(),
2677
- listId: bizConfigMenu.listId,
2678
- searchParamData: { searchType: "3", type: "and" },
2679
- terminal: "PC",
2680
- browser: "Chrome",
2681
- requiredMatch: 1,
2682
- mapResult: 1,
2683
- recheckQuery: 1,
2684
- isFollow: 0,
2685
- isShareToMe: 0,
2686
- filterCondition: {},
2687
- cusMenuId: bizConfigMenu.cusMenuId,
2688
- urlPageTitle: "\u4E1A\u52A1\u914D\u7F6E\u6620\u5C04\u8868",
2689
- menuName: "\u4E1A\u52A1\u914D\u7F6E\u6620\u5C04\u8868"
2690
- },
2691
- headers: { ebBusinessId: bizConfigMenu.listId }
2692
- });
2693
- const rows = response?.data?.data || [];
2694
- if (!rows.length) break;
2695
- for (const row of rows) {
2696
- if (String(row.config_key || "") === "28" && row.config) {
2697
- const match = String(row.config).match(/\/sp\/ebdpage\/view\/(\d+)/);
2698
- if (match) ebdDetailPageId = match[1];
2699
- }
2700
- if (String(row.config_key || "") === "-9999" && String(row.config) === "1") selfUse = "1";
2701
- }
2702
- if (rows.length < 100) break;
2703
- current += 1;
2704
- }
2705
- }
2706
- } catch {
2707
- }
2708
- }
2709
- if (!ebdDetailPageId) {
2710
- try {
2711
- const response = await host.request({
2712
- path: "/api/bs/ebuilder/page/list",
2713
- query: { appid: appId }
2714
- });
2715
- for (const page of Array.isArray(response?.data) ? response.data : []) {
2716
- if ((page?.name || "") === "\u4EBA\u624D\u5361\u7247" && page?.type === "PAGE" && page?.id) {
2717
- ebdDetailPageId = String(page.id);
2718
- break;
2719
- }
2720
- }
2721
- } catch {
2722
- }
2723
- }
2724
- const options = {};
2725
- for (const [dataKey, logic] of [["recruit_status", "talent_pool"], ["channel", "talent_pool"]]) {
2726
- const entry = forms[logic] || { objId: "", formId: "", objName: "" };
2727
- const fieldId = (fields[entry.objId] || {})[dataKey] || "";
2728
- if (fieldId && entry.objId) {
2729
- const response = await host.request({
2730
- path: "/api/ebuilder/common/ds/options",
2731
- query: { fieldName: fieldId, objId: entry.objId, sourceType: "FORM", groupId: appId }
2732
- });
2733
- if (Array.isArray(response?.data)) {
2734
- options[dataKey] = {};
2735
- for (const option of response.data) {
2736
- if (option?.id) options[dataKey][String(option.id)] = option.name;
2737
- }
2738
- }
2739
- }
2740
- }
2741
- const lists = {
2742
- talent: null,
2743
- demand: null,
2744
- position: null,
2745
- entry: null,
2746
- offer: null,
2747
- interview: null,
2748
- dict: dictMenu,
2749
- biz_config: bizConfigMenu,
2750
- all_search: searchMenus,
2751
- pages
2752
- };
2753
- for (const [biz, keywords] of Object.entries(LIST_KEYWORDS)) {
2754
- for (const menu of searchMenus) {
2755
- if (keywords.some((keyword) => (menu.menuName || "").includes(keyword))) {
2756
- lists[biz] = menu;
2757
- break;
2758
- }
2759
- }
2760
- }
2761
- return {
2762
- appId,
2763
- tenantKey,
2764
- forms,
2765
- lists,
2766
- fields,
2767
- field_options: fieldOptions,
2768
- options,
2769
- dict: { by_name: dictByName, raw: dictRaw },
2770
- ebdDetailPageId,
2771
- selfUse
2772
- };
2773
- }
2774
- function createRecruitContextLoader() {
2775
- const memo = /* @__PURE__ */ new Map();
2776
- async function load(host) {
2777
- const session = await host.getSession();
2778
- const baseUrl = session.baseUrl.replace(/\/+$/, "");
2779
- const memoKey = baseUrl;
2780
- let cached = memo.get(memoKey);
2781
- if (cached) return cached;
2782
- let appId = "";
2783
- let diskCache = null;
2784
- try {
2785
- const dir = cacheDirFor(baseUrl);
2786
- if (existsSync2(dir)) {
2787
- const files = readdirSync(dir).filter((file) => file.endsWith(".json"));
2788
- if (files.length === 1) {
2789
- appId = files[0].replace(/\.json$/, "");
2790
- diskCache = JSON.parse(readFileSync(join(dir, files[0]), "utf8"));
2791
- }
2792
- }
2793
- } catch {
2794
- }
2795
- if (diskCache) {
2796
- memo.set(memoKey, diskCache);
2797
- return diskCache;
2798
- }
2799
- const gate = await host.request({
2800
- path: "/api/bs/ebuilder/app/tags/getAppIds",
2801
- query: { tag: RECRUIT_APP_TAG }
2802
- });
2803
- const appIds = gate?.data;
2804
- if (!Array.isArray(appIds) || !appIds.length) {
2805
- throw new RecruitContextError(
2806
- "recruit_service_not_installed",
2807
- "\u5F53\u524D\u79DF\u6237\u672A\u5B89\u88C5\u62DB\u8058\u670D\u52A1\uFF08weaver-recruit-service\uFF09\uFF0C\u65E0\u6CD5\u4F7F\u7528\u62DB\u8058\u80FD\u529B\u3002\u8BF7\u5148\u5728 E10 \u5E94\u7528\u5E02\u573A\u5B89\u88C5\u300C\u62DB\u8058\u300D\u5E94\u7528\u3002"
2808
- );
2809
- }
2810
- appId = String(appIds[0]);
2811
- const resolved = await resolveRecruitEnv(host, appId);
2812
- try {
2813
- const dir = cacheDirFor(baseUrl);
2814
- mkdirSync(dir, { recursive: true });
2815
- writeFileSync(
2816
- join(dir, `${appId}.json`),
2817
- JSON.stringify({
2818
- __meta__: {
2819
- capturedAt: (/* @__PURE__ */ new Date()).toISOString().replace("T", " ").substring(0, 19),
2820
- note: "recruit-ops \u73AF\u5883\u53C2\u6570\u7F13\u5B58\uFF08weaver-work-cli \u8FD0\u884C\u65F6\u89E3\u6790\u4EA7\u7269\uFF0C\u4E0D\u542B\u8BA4\u8BC1\u5B57\u6BB5\uFF09"
2821
- },
2822
- envKey: `${dir.split(/[\\/]/).pop()}|${appId}`,
2823
- ...resolved
2824
- }, null, 2),
2825
- "utf8"
2826
- );
2827
- } catch {
2828
- }
2829
- memo.set(memoKey, resolved);
2830
- return resolved;
2831
- }
2832
- return { load };
2833
- }
2834
- function buildListBody(params) {
2835
- return {
2836
- current: params.current ?? 1,
2837
- pageSize: params.pageSize ?? 10,
2838
- tableuid: randHex32(),
2839
- listId: params.listId,
2840
- searchParamData: {
2841
- searchType: "3",
2842
- type: "and",
2843
- ...params.conditions && Object.keys(params.conditions).length ? { commonSearchFields: params.conditions } : {}
2844
- },
2845
- terminal: "PC",
2846
- browser: "Chrome",
2847
- requiredMatch: 1,
2848
- mapResult: 1,
2849
- recheckQuery: 1,
2850
- isFollow: 0,
2851
- isShareToMe: 0,
2852
- filterCondition: {},
2853
- cusMenuId: params.cusMenuId,
2854
- urlPageTitle: params.title,
2855
- menuName: params.menuName
2856
- };
2857
- }
2858
- async function fetchListRows(host, objId, listId, body) {
2859
- const countBody = { ...body };
2860
- delete countBody.current;
2861
- delete countBody.pageSize;
2862
- const [listResponse, countResponse] = await Promise.all([
2863
- host.request({
2864
- path: `/api/ebuilder/form/list/getListDatas?passid=${objId}&cid=${objId}`,
2865
- body,
2866
- headers: { ebBusinessId: listId }
2867
- }),
2868
- host.request({
2869
- path: `/api/ebuilder/form/list/getListDataCount?passid=${objId}&cid=${objId}`,
2870
- body: countBody,
2871
- headers: { ebBusinessId: listId }
2872
- }).catch(() => null)
2873
- ]);
2874
- const data = normalizePaged(listResponse).data;
2875
- const rawRows = data?.data || [];
2876
- const displayRows = data?.displayData;
2877
- const hasDisplay = Array.isArray(displayRows) && displayRows.length > 0;
2878
- const rows = hasDisplay ? displayRows : rawRows;
2879
- const countData = countResponse ? normalizePaged(countResponse).data : null;
2880
- const pageSize = typeof body.pageSize === "number" ? body.pageSize : typeof body.pageSize === "string" ? Number(body.pageSize) || rows.length : rows.length;
2881
- const countUsable = countData !== null && typeof countData.total === "number";
2882
- let total;
2883
- let totalExact;
2884
- let totalNote;
2885
- if (countUsable) {
2886
- total = countData.total;
2887
- totalExact = true;
2888
- } else if (rows.length < pageSize) {
2889
- total = rows.length;
2890
- totalExact = true;
2891
- totalNote = "\u8BA1\u6570\u63A5\u53E3\u4E0D\u53EF\u7528\uFF0C\u672C\u9875\u672A\u6EE1\uFF08\u5DF2\u5230\u672B\u9875\uFF09\uFF0C\u603B\u6570\u6309\u5DF2\u53D6\u56DE\u884C\u6570\u5F97\u51FA";
2892
- } else {
2893
- total = null;
2894
- totalExact = false;
2895
- totalNote = "\u8BA1\u6570\u63A5\u53E3\u4E0D\u53EF\u7528\u4E14\u672C\u9875\u5DF2\u6EE1\uFF0C\u603B\u6570\u4E0D\u53EF\u77E5\uFF08\u53EF\u8C03\u5927 pageSize \u53D6\u56DE\u5168\u90E8\u884C\u6570\uFF09";
2896
- }
2897
- return { rows, displayRows: hasDisplay ? displayRows : null, total, totalExact, totalNote };
2898
- }
2899
- var contextResolve = {
2900
- name: "ehr.recruit.context.resolve",
2901
- resource: "recruit",
2902
- method: "context.resolve",
2903
- action: "ehr.recruit.context.resolve",
2904
- summary: "\u89E3\u6790\u62DB\u8058\u6A21\u5757\u8FD0\u884C\u65F6\u53C2\u6570\uFF08appId/\u8868\u5355 objId/\u5217\u8868 listId+cusMenuId/\u5B57\u6BB5\u6620\u5C04\uFF09\uFF0C\u4E3B\u8981\u4F9B\u8C03\u8BD5\u4E0E\u515C\u5E95\uFF1B\u4E1A\u52A1 operation \u4F1A\u9690\u5F0F\u81EA\u52A8\u89E3\u6790",
2905
- capability: "recruit",
2906
- risk: READ,
2907
- inputSchema: schemaOf({}),
2908
- handler: async (_args, env) => {
2909
- if (!env.recruitContext) {
2910
- throw ehrValidationError("recruit_context_unavailable", "\u62DB\u8058\u4E0A\u4E0B\u6587\u52A0\u8F7D\u5668\u672A\u521D\u59CB\u5316");
2911
- }
2912
- const cache = await env.recruitContext.load(env.host);
2913
- return ehrSuccess("ehr.recruit.context.resolve", {
2914
- appId: cache.appId,
2915
- tenantKey: cache.tenantKey || null,
2916
- forms: cache.forms,
2917
- lists: cache.lists,
2918
- ebdDetailPageId: cache.ebdDetailPageId || null,
2919
- selfUse: cache.selfUse
2920
- });
2921
- }
2922
- };
2923
- var candidateSearch = {
2924
- name: "ehr.recruit.candidate.search",
2925
- resource: "recruit",
2926
- method: "candidate.search",
2927
- action: "ehr.recruit.candidate.search",
2928
- summary: "\u6309\u59D3\u540D/\u624B\u673A\u53F7\u6A21\u7CCA\u641C\u7D22\u4EBA\u624D\u5E93\u4EBA\u624D\uFF1B\u65E0\u7B5B\u9009\u6761\u4EF6\u65F6\u5217\u51FA\u5168\u90E8\u4EBA\u624D\u7528\u4E8E\u6D4F\u89C8\u3002\u8FD4\u56DE\u767D\u540D\u5355\u5C55\u793A\u5B57\u6BB5",
2929
- capability: "recruit",
2930
- risk: READ,
2931
- inputSchema: schemaOf({
2932
- name: { type: "string", description: "\u59D3\u540D\u6A21\u7CCA\u5339\u914D" },
2933
- mobile: { type: "string", description: "\u624B\u673A\u53F7\u6A21\u7CCA\u5339\u914D" },
2934
- current: SCHEMA_ID,
2935
- pageSize: SCHEMA_ID
2936
- }),
2937
- handler: async (args, env) => {
2938
- if (!env.recruitContext) {
2939
- throw ehrValidationError("recruit_context_unavailable", "\u62DB\u8058\u4E0A\u4E0B\u6587\u52A0\u8F7D\u5668\u672A\u521D\u59CB\u5316");
2940
- }
2941
- const cache = await env.recruitContext.load(env.host);
2942
- const talentList = cache.lists.talent;
2943
- const talentObjId = cache.forms.talent_pool?.objId;
2944
- if (!talentList?.listId || !talentObjId) {
2945
- throw new RecruitContextError("recruit_context_missing", "\u5F53\u524D\u73AF\u5883\u672A\u89E3\u6790\u5230\u300C\u4EBA\u624D\u5E93\u300D\u83DC\u5355\u6216\u4EBA\u624D\u5E93\u8868\u5355\uFF0C\u65E0\u6CD5\u641C\u7D22\u4EBA\u624D\u3002\u8BF7\u5148\u8FD0\u884C ehr.recruit.context.resolve \u68C0\u67E5\u73AF\u5883\u3002");
2946
- }
2947
- const fields = cache.fields[talentObjId] || {};
2948
- const nameField = "field_" + (fields.candidate_name || fields.name);
2949
- const mobileField = "field_" + fields.telephone;
2950
- const conditions = {};
2951
- if (args.name) conditions[nameField] = [{ [nameField]: args.name, [`${nameField}_condition_type`]: "like" }];
2952
- if (args.mobile) conditions[mobileField] = [{ [mobileField]: args.mobile, [`${mobileField}_condition_type`]: "like" }];
2953
- const body = buildListBody({
2954
- listId: talentList.listId,
2955
- cusMenuId: talentList.cusMenuId,
2956
- menuName: talentList.menuName || "\u4EBA\u624D\u7BA1\u7406",
2957
- title: "\u4EBA\u624D\u5E93",
2958
- current: toPositiveInt(args.current, "current") ?? 1,
2959
- pageSize: toNumber(args.pageSize, "pageSize") ?? 10,
2960
- conditions
2961
- });
2962
- const { rows, displayRows, total, totalExact, totalNote } = await fetchListRows(env.host, talentObjId, talentList.listId, body);
2963
- let creatorNameMap = {};
2964
- if (!displayRows) {
2965
- const pureIds = [...new Set(rows.map((row) => row?.creator).filter(isPlainId).map((value) => String(value).trim()))];
2966
- if (pureIds.length) {
2967
- creatorNameMap = {};
2968
- for (let index = 0; index < pureIds.length; index += 100) {
2969
- const batch = pureIds.slice(index, index + 100);
2970
- try {
2971
- const response = await env.host.request({
2972
- path: "/api/hrm/common/getEmployeeByIds",
2973
- body: { userIdList: batch, externalIdList: [] },
2974
- headers: { devtype: "5" }
2975
- });
2976
- for (const user of response?.data?.userList || []) {
2977
- if (user?.id != null) creatorNameMap[String(user.id)] = user.name || null;
2978
- }
2979
- } catch {
2980
- }
2981
- }
2982
- }
2983
- }
2984
- const statusMap = cache.options?.recruit_status || {};
2985
- const dictNameMap = {};
2986
- for (const item of cache.dict?.raw || []) {
2987
- if (item.option_id && item.selection_name) dictNameMap[item.option_id] = item.selection_name;
2988
- }
2989
- const dataRows = rows.map((row) => {
2990
- let creator = null;
2991
- if (displayRows) {
2992
- creator = namesOf(row?.creator);
2993
- } else if (row?.creator != null) {
2994
- const raw = String(row.creator).trim();
2995
- creator = isPlainId(raw) ? creatorNameMap[raw] || raw : namesOf(raw) || raw;
2996
- }
2997
- return {
2998
- talentId: row?.form_data_id || row?.id || null,
2999
- name: row?.candidate_name || row?.name || null,
3000
- mobile: row?.telephone || null,
3001
- channel: dictNameMap[row?.channel] || row?.channel || null,
3002
- status: statusMap[row?.recruit_status] || row?.recruit_status || null,
3003
- creator,
3004
- createTime: row?.create_time || null
3005
- };
3006
- });
3007
- return ehrSuccess("ehr.recruit.candidate.search", { total, totalExact, ...totalNote ? { totalNote } : {}, rows: dataRows });
3008
- }
3009
- };
3010
- var candidateList = {
3011
- name: "ehr.recruit.candidate.list",
3012
- resource: "recruit",
3013
- method: "candidate.list",
3014
- action: "ehr.recruit.candidate.list",
3015
- summary: "\u67E5\u8BE2\u62DB\u8058\u4E1A\u52A1\u5217\u8868\uFF08demand \u62DB\u8058\u9700\u6C42 / position \u62DB\u8058\u804C\u4F4D / entry \u5165\u804C\u7BA1\u7406 / offer \u5F55\u7528\u7BA1\u7406\uFF09\uFF0CdisplayData \u663E\u793A\u5C42\u96F6\u7FFB\u8BD1\u8F93\u51FA",
3016
- capability: "recruit",
3017
- risk: READ,
3018
- inputSchema: schemaOf({
3019
- type: { type: "string", enum: ["demand", "position", "entry", "offer"], description: "\u5217\u8868\u7C7B\u578B" },
3020
- current: SCHEMA_ID,
3021
- pageSize: SCHEMA_ID
3022
- }, { required: ["type"] }),
3023
- handler: async (args, env) => {
3024
- const type = typeof args.type === "string" ? args.type : "";
3025
- const listType = LIST_TYPES[type];
3026
- if (!listType) {
3027
- throw ehrValidationError("enum_invalid", `type \u53D6\u503C\u5FC5\u987B\u662F ${Object.keys(LIST_TYPES).join(" / ")} \u4E4B\u4E00`);
3028
- }
3029
- if (!env.recruitContext) {
3030
- throw ehrValidationError("recruit_context_unavailable", "\u62DB\u8058\u4E0A\u4E0B\u6587\u52A0\u8F7D\u5668\u672A\u521D\u59CB\u5316");
3031
- }
3032
- const cache = await env.recruitContext.load(env.host);
3033
- const listParam = cache.lists[listType.listKey];
3034
- if (!listParam?.listId) {
3035
- throw new RecruitContextError(
3036
- "recruit_list_unavailable",
3037
- `\u5F53\u524D\u73AF\u5883\u672A\u542F\u7528\u300C${listType.title}\u300D\u529F\u80FD\uFF08\u672A\u627E\u5230\u5BF9\u5E94\u83DC\u5355/\u5217\u8868\u53C2\u6570\uFF0C\u6309\u80FD\u529B\u63A2\u6D4B\u62E6\u622A\uFF09\u3002`
3038
- );
3039
- }
3040
- const formObjId = cache.forms[listType.formType]?.objId;
3041
- if (!formObjId) {
3042
- throw new RecruitContextError("recruit_context_missing", `\u672A\u89E3\u6790\u5230\u300C${listType.title}\u300D\u5BF9\u5E94\u8868\u5355\uFF0C\u65E0\u6CD5\u67E5\u8BE2\u3002`);
3043
- }
3044
- const body = buildListBody({
3045
- listId: listParam.listId,
3046
- cusMenuId: listParam.cusMenuId,
3047
- menuName: listParam.menuName || listType.title,
3048
- title: listType.title,
3049
- current: toPositiveInt(args.current, "current") ?? 1,
3050
- pageSize: toNumber(args.pageSize, "pageSize") ?? 10
3051
- });
3052
- const { rows, displayRows, total, totalExact, totalNote } = await fetchListRows(env.host, formObjId, listParam.listId, body);
3053
- const outRows = rows.map((row) => {
3054
- const cleaned = { form_data_id: row?.form_data_id || row?.id };
3055
- for (const [key, value] of Object.entries(row || {})) {
3056
- if (displayRows) {
3057
- if (DISPLAY_UI_KEYS.has(key) || key === "form_data_id") continue;
3058
- if (key.endsWith("Span") || key.endsWith("Action")) continue;
3059
- const text2 = String(value ?? "");
3060
- if (!text2) continue;
3061
- if (typeof value === "object" || typeof value === "string" && text2.trimStart().startsWith("[")) {
3062
- const names2 = namesOf(value);
3063
- cleaned[key] = names2 != null ? names2 : text2;
3064
- continue;
3065
- }
3066
- cleaned[key] = text2;
3067
- continue;
3068
- }
3069
- if (INTERNAL_KEYS.has(key)) continue;
3070
- const text = String(value ?? "");
3071
- if (!text) continue;
3072
- if (/^\d{16,}$/.test(text)) continue;
3073
- const names = typeof value === "object" || typeof value === "string" && text.trimStart().startsWith("[") ? namesOf(value) : null;
3074
- cleaned[key] = names != null ? names : text;
3075
- }
3076
- return cleaned;
3077
- });
3078
- return ehrSuccess("ehr.recruit.candidate.list", {
3079
- type,
3080
- total,
3081
- totalExact,
3082
- ...totalNote ? { totalNote } : {},
3083
- current: body.current,
3084
- pageSize: body.pageSize,
3085
- rows: outRows
3086
- });
3087
- }
3088
- };
3089
- function personNames(value) {
3090
- const text = String(value ?? "").trim();
3091
- if (!text) return "";
3092
- if (text.startsWith("[")) {
3093
- try {
3094
- const arr = JSON.parse(text);
3095
- if (Array.isArray(arr)) {
3096
- const names = arr.map((item) => typeof item === "string" ? item : item?.name ?? item?.username ?? "").filter(Boolean);
3097
- if (names.length) return names.join("\u3001");
3098
- }
3099
- } catch {
3100
- }
3101
- }
3102
- return text;
3103
- }
3104
- function nameLike(value) {
3105
- const text = String(value ?? "").trim();
3106
- if (!text || /^\d{16,}$/.test(text)) return null;
3107
- return text;
3108
- }
3109
- async function resolveCurrentUserName(host) {
3110
- try {
3111
- const session = await host.getSession();
3112
- const baseUrl = String(session?.baseUrl || "");
3113
- if (!baseUrl) return "";
3114
- const resp = await fetch(
3115
- `${baseUrl}/api/baseserver/layout/teamsCheck?clientType=not_xinchuang&client=WEB&domainName=${encodeURIComponent(baseUrl)}`,
3116
- {
3117
- method: "POST",
3118
- headers: {
3119
- accept: "application/json",
3120
- "content-type": "application/json",
3121
- eteamsid: String(session?.eteamsId || ""),
3122
- cookie: typeof session?.cookieHeader === "function" ? session.cookieHeader() : "",
3123
- "user-agent": typeof session?.uaHeader === "function" ? session.uaHeader() : "weaver-work-cli",
3124
- origin: baseUrl
3125
- },
3126
- redirect: "manual"
3127
- }
3128
- );
3129
- const data = await resp.json().catch(() => ({}));
3130
- const cu = data.currentUser ?? data.data?.currentUser ?? null;
3131
- return cu ? String(cu.username ?? cu.id ?? "") : "";
3132
- } catch {
3133
- return "";
3134
- }
3135
- }
3136
- var interviewFeedbackTodo = {
3137
- name: "ehr.recruit.interview.feedbackTodo",
3138
- resource: "recruit",
3139
- method: "interview.feedbackTodo",
3140
- action: "ehr.recruit.interview.feedbackTodo",
3141
- summary: "\u9762\u8BD5\u5F85\u529E\uFF1A**\u53EA\u8FD4\u56DE\u6211\u4F5C\u4E3A\u9762\u8BD5\u5B98\u7684 AI \u9762\u8BD5\u5F85\u53CD\u9988\u6E05\u5355**\uFF08\u5019\u9009\u4EBA\u5DF2\u7B54\u5B8C\u3001\u5DF2\u6709\u5F55\u50CF\u3001\u6211\u8FD8\u6CA1\u586B\u610F\u89C1\uFF09\uFF1B\u6309\u9700\u7FFB\u9875 + \u5BA2\u6237\u7AEF\u7B5B\u9009\uFF0C\u4E0D\u8FD4\u56DE\u5168\u91CF\u9762\u8BD5",
3142
- capability: "recruit",
3143
- risk: READ,
3144
- inputSchema: schemaOf({
3145
- maxPages: { type: "integer", minimum: 1, maximum: 50, description: "\u6700\u591A\u7FFB\u9875\u6570\uFF08\u9ED8\u8BA4 5\uFF09" },
3146
- pageSize: { type: "integer", minimum: 1, maximum: 200, description: "\u5355\u9875\u6761\u6570\uFF08\u9ED8\u8BA4 200\uFF0C\u5B9E\u6D4B\u670D\u52A1\u7AEF\u4E0A\u9650 200\uFF09" }
3147
- }),
3148
- handler: async (args, env) => {
3149
- if (!env.recruitContext) throw ehrValidationError("recruit_context_unavailable", "\u62DB\u8058\u4E0A\u4E0B\u6587\u52A0\u8F7D\u5668\u672A\u521D\u59CB\u5316");
3150
- const cache = await env.recruitContext.load(env.host);
3151
- const listParam = cache.lists.interview;
3152
- const form = cache.forms.interview_plan;
3153
- if (!listParam?.listId || !form?.objId) {
3154
- throw new RecruitContextError(
3155
- "recruit_list_unavailable",
3156
- "\u5F53\u524D\u73AF\u5883\u672A\u542F\u7528\u300C\u9762\u8BD5\u7BA1\u7406\u300D\u529F\u80FD\uFF08\u672A\u627E\u5230\u9762\u8BD5\u5217\u8868/\u8868\u5355\u53C2\u6570\uFF0C\u6309\u80FD\u529B\u63A2\u6D4B\u62E6\u622A\uFF09\u3002"
3157
- );
3158
- }
3159
- const pageSize = toNumber(args.pageSize, "pageSize") ?? 200;
3160
- const maxPages = toNumber(args.maxPages, "maxPages") ?? 5;
3161
- const me = await resolveCurrentUserName(env.host);
3162
- const fields = cache.fields[form.objId] || {};
3163
- const fieldOpts = cache.field_options[form.objId] || {};
3164
- const statusOpts = fieldOpts[fields.union_status] || {};
3165
- const typeOpts = fieldOpts[fields.interview_type] || {};
3166
- const toCn = (map, raw) => {
3167
- const text = String(raw ?? "");
3168
- return map[text] ?? text;
3169
- };
3170
- const statusOf = (row) => toCn(statusOpts, row?.union_status_key ?? row?.union_status);
3171
- const typeOf = (row) => toCn(typeOpts, row?.interview_type_key ?? row?.interview_type);
3172
- const interviewerOf = (row) => personNames(row?.interviewer);
3173
- const scanned = [];
3174
- let lastPageCount = 0;
3175
- for (let i = 0; i < maxPages; i++) {
3176
- const body = buildListBody({
3177
- listId: listParam.listId,
3178
- cusMenuId: listParam.cusMenuId,
3179
- menuName: listParam.menuName || "\u9762\u8BD5\u7BA1\u7406",
3180
- title: "\u9762\u8BD5\u7BA1\u7406",
3181
- current: i + 1,
3182
- pageSize
3183
- });
3184
- const page = await fetchListRows(env.host, form.objId, listParam.listId, body);
3185
- const use = page.displayRows && page.displayRows.length ? page.displayRows : page.rows;
3186
- scanned.push(...use);
3187
- lastPageCount = use.length;
3188
- if (use.length < pageSize) break;
3189
- }
3190
- const pending = scanned.filter((row) => /待反馈/.test(statusOf(row)));
3191
- const mineAll = me ? pending.filter((row) => interviewerOf(row).includes(me)) : [];
3192
- const mineAi = mineAll.filter((row) => /AI\s*面试/i.test(typeOf(row)));
3193
- const slim = (row) => ({
3194
- form_data_id: row?.form_data_id ?? row?.id ?? null,
3195
- candidate_name: nameLike(row?.candidate_name) ?? nameLike(row?.talent_id) ?? nameLike(row?.name),
3196
- position_name: nameLike(row?.position_name) ?? nameLike(row?.position_manage_id),
3197
- start_time: row?.start_time ?? null,
3198
- interview_type_key: typeOf(row) || null,
3199
- interview_session: row?.interview_session ?? null,
3200
- interviewer: interviewerOf(row) || null,
3201
- union_status_key: statusOf(row) || null,
3202
- subject: row?.subject ?? null,
3203
- talent_id: row?.talent_id ?? null,
3204
- position_manage_id: row?.position_manage_id ?? null
3205
- });
3206
- const notes = [];
3207
- if (!me) notes.push("\u672A\u80FD\u89E3\u6790\u5F53\u524D\u767B\u5F55\u4EBA\u59D3\u540D\uFF08teamsCheck \u5931\u8D25\uFF09\uFF0C\u65E0\u6CD5\u6309\u9762\u8BD5\u5B98\u8FC7\u6EE4");
3208
- if (lastPageCount >= pageSize && scanned.length >= pageSize * maxPages) {
3209
- notes.push(`\u5DF2\u626B\u63CF ${scanned.length} \u6761\uFF08\u8FBE maxPages=${maxPages} \u4E0A\u9650\uFF09\uFF0C\u5982\u6000\u7591\u9057\u6F0F\u53EF\u52A0\u5927 maxPages`);
3210
- }
3211
- return ehrSuccess("ehr.recruit.interview.feedbackTodo", {
3212
- currentUser: me || null,
3213
- scanned: scanned.length,
3214
- myAiPendingFeedback: { count: mineAi.length, rows: mineAi.map(slim) },
3215
- myOtherPendingFeedback: {
3216
- count: mineAll.length - mineAi.length,
3217
- rows: mineAll.filter((row) => !/AI\s*面试/i.test(typeOf(row))).map(slim)
3218
- },
3219
- ...notes.length ? { note: notes.join("\uFF1B") } : {}
3220
- });
3221
- }
3222
- };
3223
- var candidateCard = {
3224
- name: "ehr.recruit.candidate.card",
3225
- resource: "recruit",
3226
- method: "candidate.card",
3227
- action: "ehr.recruit.candidate.card",
3228
- summary: "\u67E5\u770B\u4EBA\u624D\u8BE6\u60C5\u5361\u7247\uFF1A\u6743\u9650\u6821\u9A8C + \u56DB\u5F20\u5361\u7247\uFF08\u57FA\u672C\u4FE1\u606F/\u5E94\u8058\u8FDB\u5C55/\u9762\u8BD5\u5B89\u6392/\u6C9F\u901A\u5907\u6CE8\uFF09\u5E76\u884C\u62C9\u53D6\uFF0C\u59D3\u540D\u4E0E\u5B57\u5178\u5168\u90E8\u5185\u8054\u89E3\u6790",
3229
- capability: "recruit",
3230
- risk: READ,
3231
- inputSchema: schemaOf(
3232
- { talentId: { oneOf: [{ type: "integer" }, { type: "string", pattern: "^\\d+$" }], description: "\u4EBA\u624D ID\uFF0C\u6765\u81EA candidate.search \u7684 talentId" } },
3233
- { required: ["talentId"] }
3234
- ),
3235
- handler: async (args, env) => {
3236
- const talentId = args.talentId;
3237
- if (talentId === void 0 || talentId === null || talentId === "") {
3238
- throw ehrValidationError("talent_id_required", "talentId \u5FC5\u586B");
3239
- }
3240
- if (!/^\d+$/.test(String(talentId).trim())) {
3241
- throw ehrValidationError("talent_id_invalid", "talentId \u5FC5\u987B\u662F\u6570\u5B57 ID");
3242
- }
3243
- const id = String(talentId).trim();
3244
- if (!env.recruitContext) {
3245
- throw ehrValidationError("recruit_context_unavailable", "\u62DB\u8058\u4E0A\u4E0B\u6587\u52A0\u8F7D\u5668\u672A\u521D\u59CB\u5316");
3246
- }
3247
- const cache = await env.recruitContext.load(env.host);
3248
- const talentListId = cache.lists.talent?.listId || "";
3249
- const extra = talentListId ? { ebBusinessId: talentListId } : {};
3250
- const rk1 = randHex6();
3251
- const [rightsResponse, prepareResponse] = await Promise.all([
3252
- env.host.request({
3253
- path: `/api/recruit/talent/hasRights?formDataId=${id}`,
3254
- method: "POST",
3255
- headers: extra
3256
- }),
3257
- env.host.request({
3258
- path: `/api/recruit/candidate/getCandidateCardPrepareQuery?talentId=${id}&randomkey_${rk1}=${rk1}`,
3259
- headers: extra
3260
- })
3261
- ]);
3262
- const rights = rightsResponse?.data || [];
3263
- if (!rights.includes("READ")) {
3264
- throw ehrValidationError("recruit_rights_denied", "\u5F53\u524D\u8D26\u53F7\u65E0\u8BE5\u4EBA\u624D\u8BE6\u60C5\u7684 READ \u6743\u9650\uFF0C\u65E0\u6CD5\u67E5\u770B\u3002");
3265
- }
3266
- const batchId = prepareResponse?.data?.batchId;
3267
- if (!batchId) {
3268
- throw new RecruitContextError("recruit_batch_id_missing", "\u672A\u53D6\u5230 batchId\uFF08prepareQuery \u8FD4\u56DE\u5F02\u5E38\uFF09\uFF0C\u65E0\u6CD5\u67E5\u770B\u8BE6\u60C5\u5361\u7247\u3002");
3269
- }
3270
- const rk2 = randHex6();
3271
- const v = randHex6();
3272
- const query = `talentId=${id}&batchId=${batchId}&v=${v}&randomkey_${rk2}=${rk2}`;
3273
- const cardBody = { talentId: id, batchId, current: 1, pageSize: 100 };
3274
- const [base, other, interview, remark] = await Promise.all([
3275
- env.host.request({ path: `/api/recruit/candidate/getCandidateCardBaseInfo?${query}`, headers: extra }),
3276
- env.host.request({ path: `/api/recruit/candidate/getCandidateCardOtherInfo?${query}`, headers: extra }),
3277
- env.host.request({ path: "/api/recruit/candidate/getCandidateCardInterviewInfo", body: cardBody, headers: extra }),
3278
- env.host.request({ path: "/api/recruit/candidate/getCandidateCardRemark", body: cardBody, headers: extra })
3279
- ]);
3280
- const statusMap = cache.options?.recruit_status || {};
3281
- const talent = base?.data?.talent || {};
3282
- const currentBatch = other?.data?.currentCandidateBatch || {};
3283
- const interviewList = interview?.data?.list || [];
3284
- const remarkList = remark?.data?.list || [];
3285
- const baseUrl = (await env.host.getSession()).baseUrl.replace(/\/+$/, "");
3286
- return ehrSuccess("ehr.recruit.candidate.card", {
3287
- talentId: id,
3288
- cardLink: cache.ebdDetailPageId ? `${baseUrl}/sp/ebdpage/view/${cache.ebdDetailPageId}?talentId=${id}${String(cache.selfUse ?? "") === "1" ? "&recruitType=useSelf" : ""}` : null,
3289
- baseInfo: {
3290
- name: talent?.hrm?.name,
3291
- mobile: talent?.telephone,
3292
- channel: talent?.channel,
3293
- status: statusMap[base?.data?.recruitStatus] || base?.data?.recruitStatus || null,
3294
- createTime: talent?.createTime
3295
- },
3296
- position: {
3297
- position: currentBatch?.position?.name,
3298
- stage: currentBatch?.currentStageName,
3299
- stages: (currentBatch?.allStage || []).map((stage) => stage?.stageName).filter(Boolean),
3300
- archiveStatus: currentBatch?.archiveStatus?.name,
3301
- employManager: namesOf(currentBatch?.employManager),
3302
- channel: currentBatch?.channel,
3303
- candidateManageId: currentBatch?.id || currentBatch?.candidateManageId || null,
3304
- batchId: currentBatch?.batchId || batchId,
3305
- positionId: currentBatch?.position?.id || null
3306
- },
3307
- interviews: interviewList.map((item) => ({
3308
- subject: item?.subject,
3309
- startTime: item?.startTime || null,
3310
- endTime: item?.endTime || null,
3311
- status: namesOf(item?.unionStatus),
3312
- type: namesOf(item?.interviewType),
3313
- round: namesOf(item?.interviewSession),
3314
- interviewer: namesOf(item?.interviewer),
3315
- arranger: namesOf(item?.creator),
3316
- updater: namesOf(item?.updater),
3317
- position: namesOf(item?.positionManageId),
3318
- feedbacks: (item?.interviewFeedBack || []).map((feedback) => ({
3319
- result: feedback?.result?.[0]?.name || null,
3320
- comment: feedback?.judgement ? feedback.judgement.replace(/<[^>]+>/g, "").trim() : null,
3321
- feedbacker: namesOf(feedback?.updater),
3322
- createTime: feedback?.createTime
3323
- }))
3324
- })),
3325
- remarks: remarkList.map((item) => ({
3326
- time: item?.contactTime || item?.createTime,
3327
- creator: item?.creator?.username || item?.creator?.name || null,
3328
- content: item?.remark
3329
- }))
3330
- });
3331
- }
3332
- };
3333
- var recruitOperations = [
3334
- contextResolve,
3335
- candidateSearch,
3336
- candidateList,
3337
- candidateCard,
3338
- interviewFeedbackTodo
3339
- ];
3340
-
3341
2270
  // src/shortcuts/ehr/operations/recruit-write.ts
3342
2271
  import { createHash as createHash3 } from "node:crypto";
3343
- var CONTINUATION_TTL_SECONDS2 = 600;
3344
2272
  function fingerprint2(value) {
3345
2273
  return createHash3("sha256").update(JSON.stringify(value ?? null)).digest("hex").slice(0, 32);
3346
2274
  }
@@ -3631,21 +2559,25 @@ async function resolveCandidateForWrite(host, cache, talentId) {
3631
2559
  throw ehrValidationError("recruit_batch_id_missing", "\u672A\u53D6\u5230 batchId\uFF08prepareQuery \u8FD4\u56DE\u5F02\u5E38\uFF09\uFF0C\u65E0\u6CD5\u5B9A\u4F4D\u5019\u9009\u4EBA\u5E94\u8058\u6279\u6B21");
3632
2560
  }
3633
2561
  const v = randomHex6();
3634
- const otherResponse = await host.request({
3635
- path: `/api/recruit/candidate/getCandidateCardOtherInfo?talentId=${talentId}&batchId=${batchId}&v=${v}&randomkey_ab=ab`,
3636
- headers: extra
3637
- });
3638
- const batch = otherResponse?.data?.currentCandidateBatch || {};
3639
- let name = batch?.talent?.name || "";
3640
- if (!name) {
3641
- const baseResponse = await host.request({
2562
+ const [otherResponse, baseResponse] = await Promise.all([
2563
+ host.request({
2564
+ path: `/api/recruit/candidate/getCandidateCardOtherInfo?talentId=${talentId}&batchId=${batchId}&v=${v}&randomkey_ab=ab`,
2565
+ headers: extra
2566
+ }),
2567
+ host.request({
3642
2568
  path: `/api/recruit/candidate/getCandidateCardBaseInfo?talentId=${talentId}&batchId=${batchId}&v=${v}&randomkey_cd=cd`,
3643
2569
  headers: extra
3644
- });
3645
- name = baseResponse?.data?.talent?.hrm?.name || "";
3646
- }
2570
+ }).catch(() => null)
2571
+ ]);
2572
+ const batch = otherResponse?.data?.currentCandidateBatch || {};
2573
+ const talentBase = baseResponse?.data?.talent || {};
2574
+ const name = batch?.talent?.name || talentBase?.hrm?.name || talentBase?.name || "";
2575
+ const email = String(talentBase.email || talentBase.hrm?.email || "").trim();
2576
+ const mobile = String(talentBase.telephone || talentBase.mobile || "").trim();
3647
2577
  return {
3648
2578
  name,
2579
+ email,
2580
+ mobile,
3649
2581
  candidateManageId: batch?.id || batch?.candidateManageId || null,
3650
2582
  positionId: batch?.position?.id || null,
3651
2583
  positionName: batch?.position?.name || null,
@@ -3733,14 +2665,14 @@ var candidateCreatePrepare = {
3733
2665
  payload: { name, mobile, channel: channelName, formId: talentObj?.formId || talentObj?.objId, objId: talentObj?.objId, dataDetails },
3734
2666
  fingerprint: fingerprint2({ name, mobile, channel: channelName, dataDetails })
3735
2667
  },
3736
- CONTINUATION_TTL_SECONDS2 * 1e3
2668
+ CONTINUATION_TTL_SECONDS * 1e3
3737
2669
  );
3738
2670
  return ehrSuccess("ehr.recruit.candidate.create.prepare", {
3739
2671
  status: "AWAITING_CONFIRMATION",
3740
2672
  preview,
3741
2673
  willSubmit: { formId: talentObj?.formId || talentObj?.objId, objId: talentObj?.objId, dataDetails },
3742
2674
  continuation: token,
3743
- expiresInSeconds: CONTINUATION_TTL_SECONDS2
2675
+ expiresInSeconds: CONTINUATION_TTL_SECONDS
3744
2676
  });
3745
2677
  }
3746
2678
  };
@@ -3855,6 +2787,7 @@ var candidateCreateApply = {
3855
2787
  }
3856
2788
  };
3857
2789
  var INTERVIEW_TYPES = ["\u73B0\u573A\u9762\u8BD5", "\u89C6\u9891\u9762\u8BD5", "\u7535\u8BDD\u9762\u8BD5", "AI\u9762\u8BD5"];
2790
+ var AI_DEFAULT_PLAN_NAME = "\u5927\u6A21\u578B\u9762\u8BD5";
3858
2791
  var INTERVIEW_DATAKEYS = [
3859
2792
  "subject",
3860
2793
  "start_time",
@@ -3877,15 +2810,150 @@ function defaultInterviewWindow() {
3877
2810
  const end = new Date(now.getTime() + 60 * 60 * 1e3);
3878
2811
  return { start: fmt(now), end: fmt(end) };
3879
2812
  }
2813
+ async function resolveCurrentUserForWrite(host) {
2814
+ try {
2815
+ const session = await host.getSession();
2816
+ const baseUrl = String(session?.baseUrl || "");
2817
+ if (!baseUrl) return null;
2818
+ const resp = await fetch(
2819
+ `${baseUrl}/api/baseserver/layout/teamsCheck?clientType=not_xinchuang&client=WEB&domainName=${encodeURIComponent(baseUrl)}`,
2820
+ {
2821
+ method: "POST",
2822
+ headers: {
2823
+ accept: "application/json",
2824
+ "content-type": "application/json",
2825
+ eteamsid: String(session?.eteamsId || ""),
2826
+ cookie: typeof session?.cookieHeader === "function" ? session.cookieHeader() : "",
2827
+ "user-agent": typeof session?.uaHeader === "function" ? session.uaHeader() : "weaver-work-cli",
2828
+ origin: baseUrl
2829
+ },
2830
+ redirect: "manual"
2831
+ }
2832
+ );
2833
+ const data = await resp.json().catch(() => ({}));
2834
+ const cu = data?.currentUser ?? data?.data?.currentUser ?? null;
2835
+ if (!cu?.id) return null;
2836
+ return { id: String(cu.id), name: String(cu.username || cu.id) };
2837
+ } catch {
2838
+ return null;
2839
+ }
2840
+ }
2841
+ async function fetchLayoutIdForForm(host, formId) {
2842
+ try {
2843
+ const r = await host.request({
2844
+ path: `/api/ebuilder/form/form/core/getFormLayout?formId=${encodeURIComponent(formId)}`,
2845
+ method: "GET"
2846
+ });
2847
+ const id = r?.data?.formLayout?.id;
2848
+ if (id) return String(id);
2849
+ } catch {
2850
+ }
2851
+ try {
2852
+ const r = await host.request({
2853
+ path: "/api/ebuilder/form/form/core/getFormLayout",
2854
+ method: "POST",
2855
+ body: { module: "ebuilderform", formId, terminalType: "PC" }
2856
+ });
2857
+ const id = r?.data?.formLayout?.id;
2858
+ if (id) return String(id);
2859
+ } catch {
2860
+ }
2861
+ return formId;
2862
+ }
2863
+ var DIGITAL_PLAN_NAME_KEYS = ["msfa_name", "digital_name", "plan_name", "scheme_name"];
2864
+ async function listDigitalPlansForWrite(host, cache, formId, layoutId, fieldId) {
2865
+ try {
2866
+ const r = await host.request({
2867
+ path: "/api/ebuilder/form/common/browser/complete/ebuilder",
2868
+ body: {
2869
+ browserMultiple: false,
2870
+ newly: 1,
2871
+ searchValue: "",
2872
+ formParam: JSON.stringify({ formId, layoutId, fieldId, filterItems: [], module: "ebuilderform", dataDetails: [] }),
2873
+ openScroll: true,
2874
+ controlId: fieldId,
2875
+ businessId: formId,
2876
+ variableMap: {}
2877
+ }
2878
+ });
2879
+ if (r?.status !== false && r?.data) {
2880
+ const list = r.data.data || [];
2881
+ const items2 = list.filter((x) => x && x.id).map((x) => ({ id: String(x.id), name: String(x.name || "").trim() }));
2882
+ if (items2.length) return { available: true, items: items2 };
2883
+ }
2884
+ } catch {
2885
+ }
2886
+ const menus = cache.lists?.all_search || [];
2887
+ const menu = menus.find((m) => (m.menuName || "").includes("\u9762\u8BD5\u6570\u5B57\u4EBA")) || menus.find((m) => (m.menuName || "").includes("\u6570\u5B57\u4EBA\u914D\u7F6E"));
2888
+ if (!menu?.listId) {
2889
+ return { available: false, items: [], reason: "\u5173\u8054\u5B57\u6BB5\u5019\u9009\u63A5\u53E3\u4E0D\u53EF\u7528\uFF0C\u4E14\u5F53\u524D\u73AF\u5883\u672A\u914D\u7F6E\u300C\u9762\u8BD5\u6570\u5B57\u4EBA\u914D\u7F6E\u300D\u5217\u8868\u83DC\u5355" };
2890
+ }
2891
+ let objId = "";
2892
+ try {
2893
+ const r = await host.request({
2894
+ path: `/api/ebuilder/form/obj/getObjsByTag?appId=${encodeURIComponent(String(cache.appId || ""))}&tag=uf_rcrt_digital_human`,
2895
+ method: "GET"
2896
+ });
2897
+ const d = r?.data;
2898
+ if (Array.isArray(d) && d.length) objId = String(d[0]?.id || "");
2899
+ } catch {
2900
+ }
2901
+ if (!objId) return { available: false, items: [], reason: "\u672A\u80FD\u89E3\u6790\u300C\u9762\u8BD5\u6570\u5B57\u4EBA\u914D\u7F6E\u300D\u5BF9\u8C61 id" };
2902
+ const rows = [];
2903
+ for (let cur = 1; cur <= 20; cur++) {
2904
+ const r = await host.request({
2905
+ path: `/api/ebuilder/form/list/getListDatas?passid=${objId}&cid=${objId}`,
2906
+ body: {
2907
+ current: cur,
2908
+ pageSize: 100,
2909
+ tableuid: randomHex32(),
2910
+ listId: menu.listId,
2911
+ searchParamData: { searchType: "3", type: "and" },
2912
+ terminal: "PC",
2913
+ browser: "Chrome",
2914
+ requiredMatch: 1,
2915
+ mapResult: 1,
2916
+ recheckQuery: 1,
2917
+ isFollow: 0,
2918
+ isShareToMe: 0,
2919
+ filterCondition: {},
2920
+ cusMenuId: menu.cusMenuId,
2921
+ urlPageTitle: menu.menuName,
2922
+ menuName: menu.menuName
2923
+ },
2924
+ headers: { ebBusinessId: String(menu.listId) }
2925
+ });
2926
+ const page = r?.data?.data || [];
2927
+ rows.push(...page);
2928
+ if (page.length < 100) break;
2929
+ }
2930
+ const items = rows.map((x) => {
2931
+ const nk = DIGITAL_PLAN_NAME_KEYS.find((k) => String(x[k] || "").trim());
2932
+ return { id: String(x.form_data_id || x.id || ""), name: String(nk ? x[nk] : "").trim() };
2933
+ }).filter((x) => x.id);
2934
+ if (!items.length) return { available: false, items: [], reason: "\u300C\u9762\u8BD5\u6570\u5B57\u4EBA\u914D\u7F6E\u300D\u6682\u65E0\u53EF\u9009\u65B9\u6848" };
2935
+ return { available: true, items };
2936
+ }
2937
+ function pickDigitalPlanForWrite(items, key) {
2938
+ const k = String(key || "").trim();
2939
+ if (!k) return { plan: null, ambiguous: [] };
2940
+ const byId = items.filter((x) => x.id === k);
2941
+ if (byId.length === 1) return { plan: byId[0], ambiguous: [] };
2942
+ const byExact = items.filter((x) => x.name === k);
2943
+ if (byExact.length === 1) return { plan: byExact[0], ambiguous: [] };
2944
+ const byLike = items.filter((x) => x.name.includes(k));
2945
+ if (byLike.length === 1) return { plan: byLike[0], ambiguous: [] };
2946
+ return { plan: null, ambiguous: byLike };
2947
+ }
3880
2948
  async function buildInterviewPlan(env, cache, args) {
3881
2949
  const host = env.host;
3882
2950
  const talentId = requiredString(args, "talentId", "talent_id_required", "\u4EBA\u624D ID");
3883
2951
  if (!/^\d+$/.test(talentId)) throw ehrValidationError("talent_id_invalid", "talentId \u5FC5\u987B\u662F\u6570\u5B57 ID");
3884
- const interviewer = requiredString(args, "interviewer", "interviewer_required", "\u9762\u8BD5\u5B98\u59D3\u540D");
3885
2952
  const type = typeof args.type === "string" && args.type.trim() ? args.type.trim() : "\u73B0\u573A\u9762\u8BD5";
3886
2953
  if (!INTERVIEW_TYPES.includes(type)) {
3887
2954
  throw ehrValidationError("enum_invalid", `type\uFF08\u9762\u8BD5\u65B9\u5F0F\uFF09\u53D6\u503C\u5FC5\u987B\u662F ${INTERVIEW_TYPES.join(" / ")} \u4E4B\u4E00`);
3888
2955
  }
2956
+ const isAI = type === "AI\u9762\u8BD5";
3889
2957
  const session = typeof args.session === "string" && args.session.trim() ? args.session.trim() : "\u521D\u8BD5";
3890
2958
  const candidate = await resolveCandidateForWrite(host, cache, talentId);
3891
2959
  const positionId = args.positionId ? String(args.positionId) : candidate.positionId;
@@ -3914,9 +2982,69 @@ async function buildInterviewPlan(env, cache, args) {
3914
2982
  if (!sessionOptionId) {
3915
2983
  throw ehrValidationError("enum_invalid", `\u9762\u8BD5\u8F6E\u6B21\u300C${session}\u300D\u4E0D\u5728\u679A\u4E3E\u4E2D\uFF08${Object.keys(sessionMap).join(" / ")}\uFF09`);
3916
2984
  }
3917
- const interviewerId = await resolvePersonId(host, fieldIdOf("interviewer"), interviewer);
3918
- if (!interviewerId) {
3919
- throw ehrValidationError("interviewer_not_found", `\u9762\u8BD5\u5B98\u300C${interviewer}\u300D\u89E3\u6790\u4E0D\u5230 userId\uFF08browser/complete/resource \u65E0\u5339\u914D\uFF09`);
2985
+ const interviewerInput = typeof args.interviewer === "string" ? args.interviewer.trim() : "";
2986
+ let interviewerId = null;
2987
+ let interviewer = interviewerInput;
2988
+ if (interviewerInput) {
2989
+ interviewerId = await resolvePersonId(host, fieldIdOf("interviewer"), interviewerInput);
2990
+ if (!interviewerId) {
2991
+ throw ehrValidationError("interviewer_not_found", `\u9762\u8BD5\u5B98\u300C${interviewerInput}\u300D\u89E3\u6790\u4E0D\u5230 userId\uFF08browser/complete/resource \u65E0\u5339\u914D\uFF09`);
2992
+ }
2993
+ } else {
2994
+ const me = await resolveCurrentUserForWrite(host);
2995
+ if (!me) {
2996
+ throw ehrValidationError("interviewer_unresolved", "\u672A\u6307\u5B9A\u9762\u8BD5\u5B98\uFF0C\u4E14\u65E0\u6CD5\u89E3\u6790\u5F53\u524D\u767B\u5F55\u4EBA\uFF08teamsCheck \u5931\u8D25\uFF09\uFF1B\u8BF7\u7528 interviewer \u53C2\u6570\u6307\u5B9A");
2997
+ }
2998
+ interviewerId = await resolvePersonId(host, fieldIdOf("interviewer"), me.name);
2999
+ if (!interviewerId) {
3000
+ throw ehrValidationError(
3001
+ "interviewer_unresolved",
3002
+ `\u672A\u6307\u5B9A\u9762\u8BD5\u5B98\uFF0C\u5F53\u524D\u767B\u5F55\u4EBA\u300C${me.name}\u300D\u5728\u4EBA\u5458\u5B57\u6BB5\u4E2D\u89E3\u6790\u4E0D\u5230\uFF1B\u8BF7\u7528 interviewer \u53C2\u6570\u6307\u5B9A`
3003
+ );
3004
+ }
3005
+ interviewer = me.name;
3006
+ }
3007
+ let aiPlan = null;
3008
+ let aiPlans = [];
3009
+ let email = String(args.email || "").trim() || candidate.email;
3010
+ const mobile = candidate.mobile;
3011
+ if (isAI) {
3012
+ const digitalFid = fieldIdOf("digital_id");
3013
+ if (!digitalFid) {
3014
+ throw ehrValidationError("recruit_field_missing", "\u9762\u8BD5\u8BA1\u5212\u8868\u5355\u7F3A\u5C11\u300CAI\u9762\u8BD5\u65B9\u6848\u300D\u5B57\u6BB5\uFF08digital_id\uFF09\uFF0C\u65E0\u6CD5\u5B89\u6392 AI \u9762\u8BD5");
3015
+ }
3016
+ const layoutId = await fetchLayoutIdForForm(host, formId);
3017
+ const plans = await listDigitalPlansForWrite(host, cache, formId, layoutId, digitalFid);
3018
+ aiPlans = plans.items;
3019
+ if (!plans.available) {
3020
+ throw ehrValidationError(
3021
+ "ai_plan_unavailable",
3022
+ `AI \u9762\u8BD5\u5FC5\u987B\u9009\u62E9\u300CAI\u9762\u8BD5\u65B9\u6848\u300D\uFF0C\u4F46${plans.reason || "\u6682\u65E0\u53EF\u9009\u65B9\u6848"}\uFF1B\u8BF7\u5148\u5728\u8BE5\u73AF\u5883\u7EF4\u62A4\u300C\u9762\u8BD5\u6570\u5B57\u4EBA\u914D\u7F6E\u300D`
3023
+ );
3024
+ }
3025
+ const wanted = typeof args.aiPlan === "string" && args.aiPlan.trim() ? args.aiPlan.trim() : AI_DEFAULT_PLAN_NAME;
3026
+ const picked = pickDigitalPlanForWrite(aiPlans, wanted);
3027
+ if (picked.plan) {
3028
+ aiPlan = picked.plan;
3029
+ } else if (picked.ambiguous.length > 1) {
3030
+ throw ehrValidationError(
3031
+ "ai_plan_ambiguous",
3032
+ `AI\u9762\u8BD5\u65B9\u6848\u300C${wanted}\u300D\u547D\u4E2D\u591A\u4E2A\uFF1A${picked.ambiguous.map((x) => x.name).join("\u3001")}\uFF0C\u8BF7\u7528 aiPlan \u6307\u660E\u5177\u4F53\u65B9\u6848`,
3033
+ { candidates: picked.ambiguous }
3034
+ );
3035
+ } else {
3036
+ throw ehrValidationError(
3037
+ "ai_plan_not_found",
3038
+ `\u672A\u627E\u5230 AI\u9762\u8BD5\u65B9\u6848\u300C${wanted}\u300D\uFF0C\u8BF7\u7528 aiPlan \u4ECE\u5019\u9009\u4E2D\u6307\u5B9A\uFF08\u5019\u9009\uFF1A${aiPlans.map((x) => x.name).join("\u3001")}\uFF09`,
3039
+ { candidates: aiPlans }
3040
+ );
3041
+ }
3042
+ if (!email) {
3043
+ throw ehrValidationError("email_required", "AI \u9762\u8BD5\u8981\u6C42\u586B\u5199\u5019\u9009\u4EBA\u90AE\u7BB1\uFF1A\u4EBA\u624D\u8D44\u6599\u91CC\u6CA1\u6709\u90AE\u7BB1\uFF0C\u8BF7\u7528 email \u53C2\u6570\u63D0\u4F9B");
3044
+ }
3045
+ if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) {
3046
+ throw ehrValidationError("email_invalid", `\u5019\u9009\u4EBA\u90AE\u7BB1\u683C\u5F0F\u4E0D\u6B63\u786E\uFF1A${email}`);
3047
+ }
3920
3048
  }
3921
3049
  const window = defaultInterviewWindow();
3922
3050
  const start = typeof args.startTime === "string" && args.startTime.trim() ? args.startTime.trim() : window.start;
@@ -3934,7 +3062,10 @@ async function buildInterviewPlan(env, cache, args) {
3934
3062
  { formField: { id: fieldIdOf("interviewer") }, dataOptions: [{ optionId: interviewerId, content: interviewer }] },
3935
3063
  { formField: { id: fieldIdOf("position_manage_id") }, dataOptions: [{ optionId: positionId, content: candidate.positionName }] },
3936
3064
  { formField: { id: fieldIdOf("talent_id") }, dataOptions: [{ optionId: talentId, content: candidate.name }] },
3937
- { formField: { id: fieldIdOf("candidate_manage_id") }, dataOptions: [{ optionId: candidate.candidateManageId, content: candidate.candidateManageId }] }
3065
+ { formField: { id: fieldIdOf("candidate_manage_id") }, dataOptions: [{ optionId: candidate.candidateManageId, content: candidate.candidateManageId }] },
3066
+ ...mobile ? [{ formField: { id: fieldIdOf("mobile") }, content: mobile }] : [],
3067
+ ...email ? [{ formField: { id: fieldIdOf("email") }, content: email }] : [],
3068
+ ...aiPlan ? [{ formField: { id: fieldIdOf("digital_id") }, dataOptions: [{ optionId: aiPlan.id, content: aiPlan.name }] }] : []
3938
3069
  ];
3939
3070
  return {
3940
3071
  formId,
@@ -3943,13 +3074,20 @@ async function buildInterviewPlan(env, cache, args) {
3943
3074
  candidateName: candidate.name,
3944
3075
  positionName: candidate.positionName,
3945
3076
  interviewTime: `${start} ~ ${end}`,
3946
- interviewer
3077
+ interviewer,
3078
+ email: email || void 0,
3079
+ mobile: mobile || void 0,
3080
+ isAIInterview: isAI,
3081
+ aiPlan,
3082
+ aiPlans: isAI ? aiPlans : void 0
3947
3083
  };
3948
3084
  }
3949
3085
  var interviewArrangeSchema = {
3950
3086
  talentId: { type: "string", pattern: "^\\d+$", description: "\u4EBA\u624D ID\uFF08candidate.search \u8FD4\u56DE\u7684 talentId\uFF09" },
3951
- interviewer: { type: "string", description: "\u9762\u8BD5\u5B98\u59D3\u540D\uFF08\u987B\u53EF\u89E3\u6790\u4E3A\u7CFB\u7EDF\u4EBA\u5458\uFF09" },
3087
+ interviewer: { type: "string", description: "\u9762\u8BD5\u5B98\u59D3\u540D\uFF08\u53EF\u9009\uFF1B\u4E0D\u586B\u9ED8\u8BA4\u5F53\u524D\u767B\u5F55\u4EBA\uFF09" },
3952
3088
  type: { type: "string", enum: [...INTERVIEW_TYPES], description: "\u9762\u8BD5\u65B9\u5F0F\uFF0C\u9ED8\u8BA4\u73B0\u573A\u9762\u8BD5" },
3089
+ aiPlan: { type: "string", description: "AI \u9762\u8BD5\u65B9\u6848\uFF08\u65B9\u6848\u540D\u6216 id\uFF1Btype=AI\u9762\u8BD5 \u65F6\u751F\u6548\uFF0C\u9ED8\u8BA4\u300C\u5927\u6A21\u578B\u9762\u8BD5\u300D\uFF09" },
3090
+ email: { type: "string", description: "\u5019\u9009\u4EBA\u90AE\u7BB1\uFF08AI \u9762\u8BD5\u5FC5\u586B\uFF1B\u4E0D\u586B\u5219\u53D6\u4EBA\u624D\u8D44\u6599\u91CC\u7684\u90AE\u7BB1\uFF09" },
3953
3091
  session: { type: "string", description: "\u9762\u8BD5\u8F6E\u6B21\uFF08\u5982 \u521D\u8BD5/\u590D\u8BD5\uFF09\uFF0C\u9ED8\u8BA4\u521D\u8BD5\uFF1B\u987B\u5728\u679A\u4E3E\u5185" },
3954
3092
  positionId: { type: "string", description: "\u5E94\u8058\u804C\u4F4D ID\uFF1B\u4E0D\u586B\u65F6\u4ECE\u4EBA\u624D\u5F53\u524D\u5E94\u8058\u6279\u6B21\u7EE7\u627F" },
3955
3093
  startTime: { type: "string", pattern: "^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}$", description: "\u5F00\u59CB\u65F6\u95F4 YYYY-MM-DD HH:mm\uFF0C\u9ED8\u8BA4\u5F53\u524D\u65F6\u95F4" },
@@ -3965,7 +3103,7 @@ var interviewArrangePrepare = {
3965
3103
  capability: "recruit",
3966
3104
  risk: WRITE,
3967
3105
  requiresConfirmation: true,
3968
- inputSchema: schemaOf({ ...interviewArrangeSchema }, { required: ["talentId", "interviewer"] }),
3106
+ inputSchema: schemaOf({ ...interviewArrangeSchema }, { required: ["talentId"] }),
3969
3107
  handler: async (args, env) => {
3970
3108
  const cache = await requireRecruitCache(env);
3971
3109
  const plan = await buildInterviewPlan(env, cache, args);
@@ -3981,7 +3119,7 @@ var interviewArrangePrepare = {
3981
3119
  payload,
3982
3120
  fingerprint: fingerprint2({ dataDetails: plan.dataDetails, notify })
3983
3121
  },
3984
- CONTINUATION_TTL_SECONDS2 * 1e3
3122
+ CONTINUATION_TTL_SECONDS * 1e3
3985
3123
  );
3986
3124
  return ehrSuccess("ehr.recruit.candidate.interview.arrange.prepare", {
3987
3125
  status: "AWAITING_CONFIRMATION",
@@ -3993,11 +3131,16 @@ var interviewArrangePrepare = {
3993
3131
  session: args.session || "\u521D\u8BD5",
3994
3132
  time: plan.interviewTime,
3995
3133
  interviewer: plan.interviewer,
3134
+ ...plan.isAIInterview ? {
3135
+ aiPlan: plan.aiPlan ? `${plan.aiPlan.name}\uFF08id=${plan.aiPlan.id}\uFF09` : "(\u672A\u6307\u5B9A)",
3136
+ email: plan.email || "(\u7F3A\u5931)",
3137
+ mobile: plan.mobile || "(\u4EBA\u624D\u8D44\u6599\u65E0\u624B\u673A\u53F7)"
3138
+ } : {},
3996
3139
  notify: notify ? "\u5C06\u89E6\u53D1\u300C\u65B0\u5EFA\u65E5\u7A0B\u300D\u9762\u8BD5\u901A\u77E5\u52A8\u4F5C\u6D41\uFF08\u5916\u90E8\u901A\u77E5\uFF09" : "\u9762\u8BD5\u901A\u77E5\u9ED8\u8BA4\u4E0D\u89E6\u53D1"
3997
3140
  },
3998
3141
  willSubmit: { formId: plan.formId, objId: plan.objId, dataDetails: plan.dataDetails },
3999
3142
  continuation: token,
4000
- expiresInSeconds: CONTINUATION_TTL_SECONDS2
3143
+ expiresInSeconds: CONTINUATION_TTL_SECONDS
4001
3144
  });
4002
3145
  }
4003
3146
  };
@@ -4228,7 +3371,7 @@ var offerSendPrepare = {
4228
3371
  payload: { ...args, fbObjId: plan.fbObjId, fbFormId: plan.fbFormId, dataDetails: plan.dataDetails, offerId: plan.offerId },
4229
3372
  fingerprint: fingerprint2({ dataDetails: plan.dataDetails, offerId: plan.offerId })
4230
3373
  },
4231
- CONTINUATION_TTL_SECONDS2 * 1e3
3374
+ CONTINUATION_TTL_SECONDS * 1e3
4232
3375
  );
4233
3376
  return ehrSuccess("ehr.recruit.offer.send.prepare", {
4234
3377
  status: "AWAITING_CONFIRMATION",
@@ -4244,7 +3387,7 @@ var offerSendPrepare = {
4244
3387
  },
4245
3388
  willSubmit: { formId: plan.fbFormId, objId: plan.fbObjId, dataDetails: plan.dataDetails },
4246
3389
  continuation: token,
4247
- expiresInSeconds: CONTINUATION_TTL_SECONDS2
3390
+ expiresInSeconds: CONTINUATION_TTL_SECONDS
4248
3391
  });
4249
3392
  }
4250
3393
  };
@@ -4498,7 +3641,7 @@ var entryProcessPrepare = {
4498
3641
  },
4499
3642
  fingerprint: fingerprint2({ entryId: plan.entryId, dataDetails: plan.dataDetails })
4500
3643
  },
4501
- CONTINUATION_TTL_SECONDS2 * 1e3
3644
+ CONTINUATION_TTL_SECONDS * 1e3
4502
3645
  );
4503
3646
  return ehrSuccess("ehr.recruit.entry.process.prepare", {
4504
3647
  status: "AWAITING_CONFIRMATION",
@@ -4516,7 +3659,7 @@ var entryProcessPrepare = {
4516
3659
  },
4517
3660
  willSubmit: { formId: plan.emFormId, objId: plan.emObjId, updateTimeStamp: plan.updateTimeStamp, dataDetails: plan.dataDetails },
4518
3661
  continuation: token,
4519
- expiresInSeconds: CONTINUATION_TTL_SECONDS2
3662
+ expiresInSeconds: CONTINUATION_TTL_SECONDS
4520
3663
  });
4521
3664
  }
4522
3665
  };
@@ -4748,7 +3891,7 @@ var feedbackEditPrepare = {
4748
3891
  comment: plan.newComment
4749
3892
  })
4750
3893
  },
4751
- CONTINUATION_TTL_SECONDS2 * 1e3
3894
+ CONTINUATION_TTL_SECONDS * 1e3
4752
3895
  );
4753
3896
  return ehrSuccess("ehr.recruit.candidate.interview.feedback.edit.prepare", {
4754
3897
  status: "AWAITING_CONFIRMATION",
@@ -4764,7 +3907,7 @@ var feedbackEditPrepare = {
4764
3907
  note: "apply \u5C06\u4FDD\u5B58\u53CD\u9988\u8868\u5355\uFF08\u5168\u5B57\u6BB5\u96C6 + \u4E50\u89C2\u9501\uFF09\u5E76\u56DE\u67E5\u6821\u9A8C"
4765
3908
  },
4766
3909
  continuation: token,
4767
- expiresInSeconds: CONTINUATION_TTL_SECONDS2
3910
+ expiresInSeconds: CONTINUATION_TTL_SECONDS
4768
3911
  });
4769
3912
  }
4770
3913
  };
@@ -4924,7 +4067,7 @@ var feedbackUrgePrepare = {
4924
4067
  },
4925
4068
  fingerprint: fingerprint2({ talentId: plan.talentId, feedbackRecordId: plan.feedbackRecordId })
4926
4069
  },
4927
- CONTINUATION_TTL_SECONDS2 * 1e3
4070
+ CONTINUATION_TTL_SECONDS * 1e3
4928
4071
  );
4929
4072
  return ehrSuccess("ehr.recruit.candidate.interview.feedback.urge.prepare", {
4930
4073
  status: "AWAITING_CONFIRMATION",
@@ -4937,7 +4080,7 @@ var feedbackUrgePrepare = {
4937
4080
  note: "\u786E\u8BA4\u540E\u5C06\u5411\u9762\u8BD5\u5B98\u53D1\u9001\u300C\u8BF7\u586B\u5199\u8BC4\u4EF7\u300D\u7CFB\u7EDF\u901A\u77E5\uFF08\u4F1A\u6253\u6270\u771F\u4EBA\uFF0C\u8BF7\u786E\u4FDD\u5DF2\u7ECF\u7528\u6237\u540C\u610F\uFF09"
4938
4081
  },
4939
4082
  continuation: token,
4940
- expiresInSeconds: CONTINUATION_TTL_SECONDS2
4083
+ expiresInSeconds: CONTINUATION_TTL_SECONDS
4941
4084
  });
4942
4085
  }
4943
4086
  };
@@ -5132,6 +4275,7 @@ var OPTION_DEFAULTS = { salary_type: "\u6708\u85AA", recruit_type: "\u793E\u4F1A
5132
4275
  var SET_FIELDS = [
5133
4276
  { arg: "education", key: "education", kind: "dict", label: "\u5B66\u5386\u8981\u6C42\uFF08\u6309\u6570\u636E\u5B57\u5178\u540D\u79F0\uFF09" },
5134
4277
  { arg: "workYears", key: "work_years", kind: "dict", label: "\u5DE5\u4F5C\u5E74\u9650\uFF08\u6309\u6570\u636E\u5B57\u5178\u540D\u79F0\uFF09" },
4278
+ { arg: "workLocation", key: "work_location", kind: "assoc", label: "\u5DE5\u4F5C\u5730\u70B9\uFF08\u529E\u516C\u5730\u70B9\u540D\u79F0/\u8BE6\u7EC6\u5730\u5740\uFF0C\u5982\u300C\u4E0A\u6D77\u300D\u6216\u5B8C\u6574\u5730\u5740\uFF09" },
5135
4279
  { arg: "jobCategory", key: "job_category", kind: "dict", label: "\u804C\u4F4D\u7C7B\u522B\uFF08\u6309\u6570\u636E\u5B57\u5178\u540D\u79F0\uFF09" },
5136
4280
  { arg: "positionNature", key: "position_nature", kind: "dict", label: "\u804C\u4F4D\u5C5E\u6027\uFF08\u6309\u6570\u636E\u5B57\u5178\u540D\u79F0\uFF09" },
5137
4281
  { arg: "salaryType", key: "salary_type", kind: "option", label: "\u85AA\u916C\u7C7B\u578B\uFF08\u6708\u85AA/\u5E74\u85AA\u7B49\uFF09" },
@@ -5181,6 +4325,85 @@ async function fetchReferenceDetails(env, cache, objId, formId) {
5181
4325
  return [];
5182
4326
  }
5183
4327
  }
4328
+ var WORK_PLACE_NAMES = ["\u529E\u516C\u5730\u70B9", "\u5DE5\u4F5C\u5730\u70B9"];
4329
+ async function findWorkPlaceMenu(env, cache) {
4330
+ const ok = (m) => !!(m && m.listId);
4331
+ const pick = (list) => {
4332
+ const hit = list.find((m) => ok(m) && WORK_PLACE_NAMES.some((n) => String(m.menuName || "").includes(n)));
4333
+ return hit ? hit : null;
4334
+ };
4335
+ const hit1 = pick(cache.lists?.all_search || []);
4336
+ if (hit1) return hit1;
4337
+ const hit2 = pick(cache.menus || []);
4338
+ if (hit2) return hit2;
4339
+ try {
4340
+ const r = await env.host.request({
4341
+ path: "/api/cusapp/app/allMenus",
4342
+ query: { isFront: 1, appId: String(cache.appId || ""), terminalType: "PC" }
4343
+ });
4344
+ const flat = [];
4345
+ (function walk(nodes) {
4346
+ for (const n of nodes || []) {
4347
+ if (n && typeof n === "object") {
4348
+ flat.push(n);
4349
+ walk(n.children || n.childs);
4350
+ }
4351
+ }
4352
+ })(r?.data?.cusAppMenus || r?.data);
4353
+ return pick(flat);
4354
+ } catch {
4355
+ return null;
4356
+ }
4357
+ }
4358
+ async function resolveWorkLocation(env, cache, value) {
4359
+ const v = String(value).trim();
4360
+ if (!v) return null;
4361
+ const menu = await findWorkPlaceMenu(env, cache);
4362
+ if (!menu?.listId) return null;
4363
+ let pObj = "";
4364
+ try {
4365
+ const t = await env.host.request({
4366
+ path: "/api/ebuilder/form/obj/getObjsByTag",
4367
+ query: { appId: String(cache.appId || ""), tag: "uf_rcrt_work_place" }
4368
+ });
4369
+ const d = t?.data;
4370
+ if (Array.isArray(d) && d[0]) pObj = String(d[0].id || "");
4371
+ } catch {
4372
+ }
4373
+ if (!pObj) pObj = String(menu.objId || "");
4374
+ if (!pObj) return null;
4375
+ const body = buildListBody({
4376
+ listId: menu.listId,
4377
+ cusMenuId: menu.cusMenuId,
4378
+ menuName: menu.menuName || "\u529E\u516C\u5730\u70B9",
4379
+ title: menu.menuName || "\u529E\u516C\u5730\u70B9",
4380
+ pageSize: 200
4381
+ });
4382
+ const r = await env.host.request({
4383
+ path: `/api/ebuilder/form/list/getListDatas?passid=${pObj}&cid=${pObj}`,
4384
+ body,
4385
+ headers: { ebBusinessId: menu.listId }
4386
+ });
4387
+ const rows = r?.data?.data || r?.data?.displayData || [];
4388
+ const hit = rows.find((x) => {
4389
+ const name = String(x?.name || "");
4390
+ const detail = String(x?.detail_location || "");
4391
+ const area = String(x?.area_text || "");
4392
+ return name.includes(v) || detail.includes(v) || area.includes(v) || !!detail && v.includes(detail);
4393
+ });
4394
+ return hit ? { id: String(hit.form_data_id || hit.id), name: String(hit.detail_location || hit.name || v) } : null;
4395
+ }
4396
+ function detailDisplayValue(detail) {
4397
+ if (!detail) return "";
4398
+ const d = detail;
4399
+ if (d.content !== void 0 && d.content !== null) return String(d.content);
4400
+ if (Array.isArray(d.dataOptions) && d.dataOptions[0]) {
4401
+ const o = d.dataOptions[0];
4402
+ return String(o.content ?? o.optionId ?? "");
4403
+ }
4404
+ if (d.dataText?.content !== void 0) return String(d.dataText.content).replace(/<[^>]+>/g, "").slice(0, 60);
4405
+ return "";
4406
+ }
5184
4407
  async function buildPositionPlan(env, cache, args) {
5185
4408
  const form = cache.forms.position_manage;
5186
4409
  const objId = form?.objId;
@@ -5246,6 +4469,14 @@ async function buildPositionPlan(env, cache, args) {
5246
4469
  }
5247
4470
  put({ formField: { id: fieldId }, dataOptions: [{ optionId: String(optionId), content: value }] });
5248
4471
  applied.push(`${field.key}=${value}`);
4472
+ } else if (field.kind === "assoc") {
4473
+ const loc = await resolveWorkLocation(env, cache, value);
4474
+ if (!loc) {
4475
+ skipped.push(`${field.key}=${value}\uFF08\u672A\u5339\u914D\u5230\u300C\u529E\u516C\u5730\u70B9\u300D\u8BB0\u5F55\uFF0C\u5DF2\u8DF3\u8FC7\uFF09`);
4476
+ continue;
4477
+ }
4478
+ put({ formField: { id: fieldId }, dataOptions: [{ optionId: loc.id, content: loc.name }] });
4479
+ applied.push(`${field.key}=${value}`);
5249
4480
  } else if (field.kind === "dict") {
5250
4481
  const ids = cache.dict.by_name[value] || [];
5251
4482
  const unique = [...new Set(ids.map(String))];
@@ -5304,6 +4535,15 @@ async function buildPositionPlan(env, cache, args) {
5304
4535
  }
5305
4536
  const inverse = {};
5306
4537
  for (const [dataKey, fieldId] of Object.entries(fields)) inverse[String(fieldId)] = dataKey;
4538
+ const inheritedSalaryWarnings = [];
4539
+ for (const key of ["salary_min", "salary_max"]) {
4540
+ if (!inherited.includes(key)) continue;
4541
+ const raw = detailDisplayValue(refMap.get(String(fid(key))));
4542
+ const num = Number(String(raw).replace(/[^\d.]/g, ""));
4543
+ if (raw && Number.isFinite(num) && num > 0 && num < 1e3) {
4544
+ inheritedSalaryWarnings.push(`${key} \u7EE7\u627F\u503C\u300C${raw}\u300D\u660E\u663E\u504F\u4F4E\uFF08\u7591\u5386\u53F2\u810F\u6570\u636E\uFF09\uFF0C\u8BF7\u4EBA\u5DE5\u6838\u5BF9\u540E\u518D\u63D0\u4EA4`);
4545
+ }
4546
+ }
5307
4547
  return {
5308
4548
  objId,
5309
4549
  formId,
@@ -5317,6 +4557,10 @@ async function buildPositionPlan(env, cache, args) {
5317
4557
  explicitApplied: applied,
5318
4558
  explicitSkipped: skipped,
5319
4559
  inheritedFromExistingPosition: inherited,
4560
+ // 带值的继承清单:Agent 必须在确认摘要里逐项点名(尤其 work_location),
4561
+ // 不得因为它是默认值就略过——历史上这里曾静默带出过重复地点等脏数据。
4562
+ inheritedFromRef: inherited.length ? inherited.map((k) => ({ field: k, value: detailDisplayValue(refMap.get(String(fid(k)))) })) : void 0,
4563
+ inheritedSalaryWarnings: inheritedSalaryWarnings.length ? inheritedSalaryWarnings : void 0,
5320
4564
  noReferenceValue: missingRef,
5321
4565
  principalDefault: session.userId ? "\u5F53\u524D\u767B\u5F55\u7528\u6237" : "\u672A\u89E3\u6790\u5230\u5F53\u524D\u7528\u6237"
5322
4566
  }
@@ -5355,14 +4599,14 @@ var positionCreatePrepare = {
5355
4599
  payload: { objId: plan.objId, formId: plan.formId, positionName: String(args.positionName).trim(), dataDetails: plan.dataDetails },
5356
4600
  fingerprint: fingerprint3({ objId: plan.objId, dataDetails: plan.dataDetails })
5357
4601
  },
5358
- 10 * 60 * 1e3
4602
+ CONTINUATION_TTL_MS
5359
4603
  );
5360
4604
  return ehrSuccess("ehr.recruit.position.create.prepare", {
5361
4605
  status: "AWAITING_CONFIRMATION",
5362
4606
  preview: { action: "\u751F\u6210\u804C\u4F4DJD\u5E76\u5EFA\u804C\u4F4D\uFF08saveFormData \u2192 addPosition\uFF09", ...plan.summary },
5363
4607
  willSubmit: { objId: plan.objId, formId: plan.formId, dataDetails: plan.dataDetails },
5364
4608
  continuation,
5365
- expiresInSeconds: 600
4609
+ expiresInSeconds: CONTINUATION_TTL_SECONDS
5366
4610
  });
5367
4611
  }
5368
4612
  };
@@ -5531,6 +4775,93 @@ function joinRange(start, end) {
5531
4775
  if (!s && !e) return void 0;
5532
4776
  return `${s},${e}`;
5533
4777
  }
4778
+ var DATE_ONLY_RE = /^\d{4}-\d{2}-\d{2}$/;
4779
+ var ONGOING_RE = /至今|现在|今|now|present/i;
4780
+ var RE_RANGE_FULL = /^\s*(\d{4}[.\-/年]\d{1,2}[.\-/月]\d{1,2}\s*日?)\s*[-–—~至,,]\s*(\d{4}[.\-/年]\d{1,2}[.\-/月]\d{1,2}\s*日?|至今|现在|今)\s*$/;
4781
+ var RE_RANGE_YM = /^\s*(\d{4}[.\-/年]\d{1,2})\s*[-–—~至,,]\s*(\d{4}[.\-/年]\d{1,2}|至今|现在|今)\s*$/;
4782
+ function normDatePart(raw, isEnd) {
4783
+ const s = String(raw ?? "").trim();
4784
+ if (!s) return "";
4785
+ if (ONGOING_RE.test(s)) return "";
4786
+ if (DATE_ONLY_RE.test(s)) return s;
4787
+ const m = s.match(/^(\d{4})\s*[.\-/年]?\s*(\d{1,2})?\s*[.\-/月]?\s*(\d{1,2})?\s*日?$/);
4788
+ if (!m) return "";
4789
+ const y = Number(m[1]);
4790
+ const mo = m[2] ? Number(m[2]) : 1;
4791
+ if (!y || mo < 1 || mo > 12) return "";
4792
+ const lastDay = new Date(y, mo, 0).getDate();
4793
+ let d;
4794
+ if (m[3]) {
4795
+ d = Number(m[3]);
4796
+ if (d < 1 || d > lastDay) return "";
4797
+ } else {
4798
+ d = isEnd ? lastDay : 1;
4799
+ }
4800
+ return `${y}-${String(mo).padStart(2, "0")}-${String(d).padStart(2, "0")}`;
4801
+ }
4802
+ function normDateRange(raw) {
4803
+ const s = Array.isArray(raw) ? raw.map((x) => String(x ?? "").trim()).filter(Boolean).join(",") : String(raw ?? "").trim();
4804
+ if (!s) return "";
4805
+ const m = s.match(RE_RANGE_FULL) || s.match(RE_RANGE_YM);
4806
+ if (m) {
4807
+ const a = normDatePart(m[1], false);
4808
+ if (!a) return "";
4809
+ const b = normDatePart(m[2], true);
4810
+ return b ? `${a},${b}` : a;
4811
+ }
4812
+ return normDatePart(s, false);
4813
+ }
4814
+ function normalizeImportDates(input, warnings) {
4815
+ if (!input || typeof input !== "object") return;
4816
+ const one = (label, val, isEnd = false) => {
4817
+ const before = String(val ?? "").trim();
4818
+ if (!before) return "";
4819
+ if (ONGOING_RE.test(before)) return "";
4820
+ const after = normDatePart(before, isEnd);
4821
+ if (!after) {
4822
+ warnings.push(`\u65E5\u671F\u65E0\u6CD5\u8BC6\u522B\uFF0C\u5DF2\u8DF3\u8FC7\u8BE5\u5B57\u6BB5\uFF08\u907F\u514D\u63A5\u53E3\u6574\u6279\u6821\u9A8C\u5931\u8D25\uFF09\uFF1A${label} = \u300C${before}\u300D`);
4823
+ return "";
4824
+ }
4825
+ if (after !== before) warnings.push(`\u65E5\u671F\u5DF2\u89C4\u8303\u5316\uFF1A${label} \u300C${before}\u300D\u2192\u300C${after}\u300D`);
4826
+ return after;
4827
+ };
4828
+ for (const k of ["joinworkdate", "graduate_date", "birthday"]) {
4829
+ if (input[k] === void 0 || input[k] === null) continue;
4830
+ input[k] = one(k, input[k], false);
4831
+ }
4832
+ if (Array.isArray(input.academicInformations)) {
4833
+ input.academicInformations.forEach((r, i) => {
4834
+ if (!r || typeof r !== "object" || r.study_date === void 0) return;
4835
+ const before = String(r.study_date ?? "").trim();
4836
+ if (!before) return;
4837
+ const after = normDateRange(before);
4838
+ if (!after) {
4839
+ warnings.push(`\u65E5\u671F\u533A\u95F4\u65E0\u6CD5\u8BC6\u522B\uFF0C\u5DF2\u8DF3\u8FC7\uFF1AacademicInformations[${i}].study_date = \u300C${before}\u300D`);
4840
+ r.study_date = "";
4841
+ } else {
4842
+ if (after !== before) warnings.push(`\u65E5\u671F\u5DF2\u89C4\u8303\u5316\uFF1AacademicInformations[${i}].study_date \u300C${before}\u300D\u2192\u300C${after}\u300D`);
4843
+ r.study_date = after;
4844
+ }
4845
+ });
4846
+ }
4847
+ for (const key of ["jobInformations", "workExperiences", "projectExperiences"]) {
4848
+ const arr = input[key];
4849
+ if (!Array.isArray(arr)) continue;
4850
+ arr.forEach((r, i) => {
4851
+ if (!r || typeof r !== "object") return;
4852
+ if (r.start_date !== void 0 && r.start_date !== null) r.start_date = one(`${key}[${i}].start_date`, r.start_date, false);
4853
+ if (r.end_date !== void 0 && r.end_date !== null) r.end_date = one(`${key}[${i}].end_date`, r.end_date, true);
4854
+ });
4855
+ }
4856
+ for (const [key, field] of [["internshipExperiences", "entry_time"], ["awardExperiences", "award_date"]]) {
4857
+ const arr = input[key];
4858
+ if (!Array.isArray(arr)) continue;
4859
+ arr.forEach((r, i) => {
4860
+ if (!r || typeof r !== "object") return;
4861
+ if (r[field] !== void 0 && r[field] !== null) r[field] = one(`${key}[${i}].${field}`, r[field], false);
4862
+ });
4863
+ }
4864
+ }
5534
4865
  async function resolveSubTableMeta(env, formId) {
5535
4866
  let data = null;
5536
4867
  try {
@@ -5747,42 +5078,106 @@ async function uploadResumeFile(env, filePath, fieldId, formId) {
5747
5078
  }
5748
5079
  return { fileid: String(fileid), name, size };
5749
5080
  }
5750
- async function applyPlatformTags(env, talentId, tagNames) {
5751
- if (!tagNames.length) return { applied: [], skipped: [] };
5752
- const list = await env.host.request({
5081
+ async function queryTagByName(env, name) {
5082
+ const pageSize = 100;
5083
+ const bodyOf = (type) => ({ type, name, order: 8, pageSize, pageNo: 1, search: 1, tagGroup: 0, tagModules: ["ebuilderform"] });
5084
+ const rs = await Promise.all(
5085
+ [0, 1].map(
5086
+ (type) => env.host.request({
5087
+ path: "/api/my/tag/query",
5088
+ method: "POST",
5089
+ body: bodyOf(type),
5090
+ operation: "ehr.recruit.candidate.import.apply"
5091
+ }).catch(() => null)
5092
+ )
5093
+ );
5094
+ const items = [];
5095
+ let filtered = true;
5096
+ for (const r of rs) {
5097
+ const d = r?.data || {};
5098
+ const list = Array.isArray(d.data) ? d.data : [];
5099
+ const total = Number(d.total || 0);
5100
+ if (list.length >= pageSize && total >= pageSize) filtered = false;
5101
+ items.push(...list);
5102
+ }
5103
+ return { items, filtered };
5104
+ }
5105
+ async function fetchTagsOfType(env, type) {
5106
+ const pageSize = 100;
5107
+ const bodyOf = (pageNo) => ({ type, name: "", order: 8, pageSize, pageNo, search: 1, tagGroup: 0, tagModules: ["ebuilderform"] });
5108
+ const requestPage = (pageNo) => env.host.request({
5753
5109
  path: "/api/my/tag/query",
5754
5110
  method: "POST",
5755
- body: { tagModules: ["ebuilderform"], current: 1, pageSize: 500 },
5111
+ body: bodyOf(pageNo),
5756
5112
  operation: "ehr.recruit.candidate.import.apply"
5757
- });
5758
- const rows = list?.data?.data || list?.data?.list || [];
5113
+ }).catch(() => null);
5114
+ const first = await requestPage(1);
5115
+ const d = first?.data || {};
5116
+ const rows = Array.isArray(d.data) ? [...d.data] : [];
5117
+ const total = Number(d.total || 0);
5118
+ const pages = Math.min(40, Math.max(1, Math.ceil(total / pageSize)));
5119
+ if (pages > 1 && rows.length) {
5120
+ const rest = Array.from({ length: pages - 1 }, (_, i) => i + 2);
5121
+ for (let i = 0; i < rest.length; i += 5) {
5122
+ const batch = rest.slice(i, i + 5);
5123
+ const rs = await Promise.all(batch.map((p) => requestPage(p)));
5124
+ for (const r of rs) {
5125
+ const list = r?.data?.data;
5126
+ if (Array.isArray(list)) rows.push(...list);
5127
+ }
5128
+ }
5129
+ }
5130
+ return rows;
5131
+ }
5132
+ async function resolveTagIds(env, tagNames) {
5133
+ const norm = (s) => String(s == null ? "" : s).trim().toLowerCase();
5134
+ const uniqNames = [...new Set(tagNames.map((n) => String(n)).filter(Boolean))];
5759
5135
  const byName = /* @__PURE__ */ new Map();
5760
- for (const row of rows) {
5761
- const name = String(row.name ?? row.tagName ?? "").trim();
5762
- const id = row.tagId ?? row.id;
5763
- if (name && id !== void 0 && !byName.has(name)) byName.set(name, { id: String(id), name });
5136
+ const absorb = (row) => {
5137
+ const name = String(row?.name ?? row?.tagName ?? "").trim();
5138
+ const id = row?.tagId ?? row?.id;
5139
+ if (!name || id === void 0) return;
5140
+ const key = norm(name);
5141
+ const prev = byName.get(key);
5142
+ if (!prev) byName.set(key, { id: String(id), name });
5143
+ else if ((row?.type ?? 0) === 0) byName.set(key, { id: String(id), name });
5144
+ };
5145
+ const probes = await Promise.all(uniqNames.map((n) => queryTagByName(env, n)));
5146
+ const nameQueryUsable = probes.every((p) => p.filtered);
5147
+ if (nameQueryUsable) {
5148
+ for (const p of probes) for (const item of p.items) absorb(item);
5149
+ } else {
5150
+ for (const type of [0, 1]) {
5151
+ const rows = await fetchTagsOfType(env, type).catch(() => []);
5152
+ for (const item of rows) absorb(item);
5153
+ }
5764
5154
  }
5765
- const tags = [];
5766
- const applied = [];
5155
+ const resolved = [];
5156
+ const found = [];
5767
5157
  const skipped = [];
5768
5158
  for (const name of tagNames) {
5769
- const hit = byName.get(name);
5159
+ const hit = byName.get(norm(name));
5770
5160
  if (!hit) {
5771
5161
  skipped.push(name);
5772
5162
  continue;
5773
5163
  }
5774
- tags.push({ id: hit.id, name: hit.name, type: 0 });
5775
- applied.push(name);
5164
+ resolved.push({ id: hit.id, name: hit.name, type: 0 });
5165
+ found.push(name);
5776
5166
  }
5777
- if (tags.length) {
5167
+ return { resolved, found, skipped };
5168
+ }
5169
+ async function applyPlatformTags(env, talentId, tagNames) {
5170
+ if (!tagNames.length) return { applied: [], skipped: [] };
5171
+ const r = await resolveTagIds(env, tagNames);
5172
+ if (r.resolved.length) {
5778
5173
  await env.host.request({
5779
5174
  path: "/api/my/tag/common/batchAddEntityTag",
5780
5175
  method: "POST",
5781
- body: { tags, batchDatas: [{ entityId: talentId, module: "ebuilderform" }] },
5176
+ body: { tags: r.resolved, batchDatas: [{ entityId: talentId, module: "ebuilderform" }] },
5782
5177
  operation: "ehr.recruit.candidate.import.apply"
5783
5178
  });
5784
5179
  }
5785
- return { applied, skipped };
5180
+ return { applied: r.found, skipped: r.skipped };
5786
5181
  }
5787
5182
  async function requireCache2(env) {
5788
5183
  if (!env.recruitContext) throw ehrValidationError("recruit_context_unavailable", "\u62DB\u8058\u4E0A\u4E0B\u6587\u52A0\u8F7D\u5668\u672A\u521D\u59CB\u5316");
@@ -5794,6 +5189,7 @@ function str(value) {
5794
5189
  }
5795
5190
  async function buildImportPlan(env, cache, args) {
5796
5191
  const warnings = [];
5192
+ normalizeImportDates(args, warnings);
5797
5193
  const talent = cache.forms.talent_pool;
5798
5194
  const objId = talent?.objId;
5799
5195
  const formId = talent?.formId || objId;
@@ -5972,7 +5368,11 @@ var candidateImportPrepare = {
5972
5368
  handler: async (args, env) => {
5973
5369
  const cache = await requireCache2(env);
5974
5370
  const plan = await buildImportPlan(env, cache, args);
5975
- const dup = await checkDuplicateByMobile(env, cache, plan.mobile);
5371
+ const tagNames = Array.isArray(args.tags) ? args.tags.map(String).filter(Boolean) : [];
5372
+ const [dup, tagCheck] = await Promise.all([
5373
+ checkDuplicateByMobile(env, cache, plan.mobile),
5374
+ tagNames.length ? resolveTagIds(env, tagNames).then((rt) => ({ requested: tagNames, found: rt.found, missing: rt.skipped })).catch((error) => ({ requested: tagNames, missing: [], error: error?.message || "\u6807\u7B7E\u9884\u68C0\u5931\u8D25" })) : Promise.resolve(null)
5375
+ ]);
5976
5376
  if (dup.length > 1) {
5977
5377
  throw ehrValidationError("duplicate_ambiguous", `\u624B\u673A\u53F7 ${plan.mobile} \u5B58\u5728\u591A\u6761\u5019\u9009\uFF08\u6570\u636E\u5F02\u5E38\uFF09\uFF0C\u8BF7\u4EBA\u5DE5\u6838\u5BF9\u540E\u518D\u51B3\u5B9A\uFF0C\u4E0D\u81EA\u52A8\u65B0\u5EFA`);
5978
5378
  }
@@ -5997,7 +5397,7 @@ var candidateImportPrepare = {
5997
5397
  telephone: plan.mobile
5998
5398
  }
5999
5399
  },
6000
- 10 * 60 * 1e3
5400
+ CONTINUATION_TTL_MS
6001
5401
  );
6002
5402
  return ehrSuccess("ehr.recruit.candidate.import.prepare", {
6003
5403
  status: "AWAITING_CONFIRMATION",
@@ -6012,8 +5412,9 @@ var candidateImportPrepare = {
6012
5412
  details: plan.details,
6013
5413
  tags: Array.isArray(args.tags) ? args.tags : []
6014
5414
  },
5415
+ ...tagCheck ? { tagCheck } : {},
6015
5416
  continuation,
6016
- expiresInSeconds: 600
5417
+ expiresInSeconds: CONTINUATION_TTL_SECONDS
6017
5418
  });
6018
5419
  }
6019
5420
  };
@@ -6077,37 +5478,28 @@ var candidateImportApply = {
6077
5478
  { candidateName: payload.candidateName, telephone: payload.telephone }
6078
5479
  );
6079
5480
  }
6080
- let batchOk = null;
6081
- let batchNote;
6082
- try {
6083
- await env.host.request({
6084
- path: `/api/recruit/candidate/initTalentBatch?formDataId=${encodeURIComponent(talentId)}`,
6085
- method: "POST",
6086
- operation: "ehr.recruit.candidate.import.apply"
6087
- });
6088
- batchOk = true;
6089
- } catch (error) {
6090
- batchOk = false;
6091
- batchNote = `\u4EBA\u624D\u5DF2\u5EFA\u6863\uFF0C\u4F46\u521D\u59CB\u5316\u4EBA\u624D\u6279\u6B21\u5931\u8D25\uFF1A${error?.message || "\u672A\u77E5\u9519\u8BEF"}\uFF08\u53EF\u5728\u4EBA\u624D\u5361\u7247\u624B\u52A8\u5904\u7406\uFF09`;
6092
- }
6093
- let labelMatch = null;
6094
- try {
6095
- const r = await env.host.request({
6096
- path: `/api/recruit/label/matchTalentLabel?talentId=${encodeURIComponent(talentId)}`,
6097
- method: "POST",
6098
- body: {},
6099
- operation: "ehr.recruit.candidate.import.apply"
6100
- });
6101
- labelMatch = r?.data === void 0 ? "TRIGGERED" : String(r.data);
6102
- } catch {
6103
- labelMatch = "FAILED\uFF08\u4E0D\u5F71\u54CD\u5EFA\u6863\uFF0C\u53EF\u7A0D\u540E\u5728\u4EBA\u624D\u5361\u7247\u624B\u52A8\u89E6\u53D1\uFF09";
6104
- }
6105
- let tagResult = { applied: [], skipped: [] };
6106
- try {
6107
- tagResult = await applyPlatformTags(env, talentId, Array.isArray(payload.tags) ? payload.tags.map(String) : []);
6108
- } catch (error) {
6109
- tagResult = { applied: [], skipped: Array.isArray(payload.tags) ? payload.tags.map(String) : [] };
6110
- }
5481
+ const batchTask = env.host.request({
5482
+ path: `/api/recruit/candidate/initTalentBatch?formDataId=${encodeURIComponent(talentId)}`,
5483
+ method: "POST",
5484
+ operation: "ehr.recruit.candidate.import.apply"
5485
+ }).then(() => ({ ok: true, note: void 0 })).catch((error) => ({
5486
+ ok: false,
5487
+ note: `\u4EBA\u624D\u5DF2\u5EFA\u6863\uFF0C\u4F46\u521D\u59CB\u5316\u4EBA\u624D\u6279\u6B21\u5931\u8D25\uFF1A${error?.message || "\u672A\u77E5\u9519\u8BEF"}\uFF08\u53EF\u5728\u4EBA\u624D\u5361\u7247\u624B\u52A8\u5904\u7406\uFF09`
5488
+ }));
5489
+ const labelTask = env.host.request({
5490
+ path: `/api/recruit/label/matchTalentLabel?talentId=${encodeURIComponent(talentId)}`,
5491
+ method: "POST",
5492
+ body: {},
5493
+ operation: "ehr.recruit.candidate.import.apply"
5494
+ }).then((r) => r?.data === void 0 ? "TRIGGERED" : String(r.data)).catch(() => "FAILED\uFF08\u4E0D\u5F71\u54CD\u5EFA\u6863\uFF0C\u53EF\u7A0D\u540E\u5728\u4EBA\u624D\u5361\u7247\u624B\u52A8\u89E6\u53D1\uFF09");
5495
+ const tagTask = applyPlatformTags(
5496
+ env,
5497
+ talentId,
5498
+ Array.isArray(payload.tags) ? payload.tags.map(String) : []
5499
+ ).catch(() => ({ applied: [], skipped: Array.isArray(payload.tags) ? payload.tags.map(String) : [] }));
5500
+ const [batchOutcome, labelMatch, tagResult] = await Promise.all([batchTask, labelTask, tagTask]);
5501
+ const batchOk = batchOutcome.ok;
5502
+ const batchNote = batchOutcome.note;
6111
5503
  const baseUrl = session.baseUrl.replace(/\/+$/, "");
6112
5504
  const extra = String(cache.selfUse) === "1" ? "&recruitType=useSelf" : "";
6113
5505
  const talentCardUrl = cache.ebdDetailPageId ? `${baseUrl}/sp/ebdpage/view/${cache.ebdDetailPageId}?talentId=${talentId}${extra}` : null;
@@ -6115,13 +5507,60 @@ var candidateImportApply = {
6115
5507
  const talentListLocateUrl = talentListId ? `${baseUrl}/sp/ebdfpage/list/${talentListId}?talentId=${talentId}${extra}` : null;
6116
5508
  const warnings = [...payload.warnings || []];
6117
5509
  if (batchNote) warnings.push(batchNote);
5510
+ let detailsState = "complete";
5511
+ const expectedDetailRows = Object.values(payload.subStats || {}).reduce(
5512
+ (sum, n) => sum + Number(n || 0),
5513
+ 0
5514
+ );
5515
+ if (expectedDetailRows > 0) {
5516
+ try {
5517
+ const snapshot = await env.host.request({
5518
+ path: "/api/ebuilder/form/form/core/getFormDataAndLayout",
5519
+ method: "POST",
5520
+ body: {
5521
+ terminalType: "PC",
5522
+ dataId: talentId,
5523
+ formId,
5524
+ module: "ebuilderform",
5525
+ newLayout: true,
5526
+ dataCrossLayout: false,
5527
+ permissionId: "",
5528
+ allReadOnly: true,
5529
+ initialDatas: [],
5530
+ dynamicData: false,
5531
+ cost: false,
5532
+ customParam: { objId, dataId: talentId }
5533
+ },
5534
+ operation: "ehr.recruit.candidate.import.apply"
5535
+ });
5536
+ const detailData = snapshot?.data?.formData?.dataDetails || [];
5537
+ const seenRows = {};
5538
+ for (const d of detailData) {
5539
+ if (!d?.subFormId) continue;
5540
+ const key = String(d.subFormId);
5541
+ (seenRows[key] = seenRows[key] || /* @__PURE__ */ new Set()).add(String(d.dataIndex));
5542
+ }
5543
+ const gotRows = Object.values(seenRows).reduce((sum, set) => sum + set.size, 0);
5544
+ if (gotRows < expectedDetailRows) {
5545
+ detailsState = "missing";
5546
+ warnings.push(
5547
+ `\u660E\u7EC6\u884C\u672A\u5B8C\u6574\u843D\u5E93\uFF08\u671F\u671B ${expectedDetailRows} \u884C\uFF0C\u8BFB\u56DE ${gotRows} \u884C\uFF09\uFF1A\u4E3B\u8868\u5DF2\u5199\u5165\uFF0C\u8BF7\u6838\u5BF9\u540E\u8865\u9F50\u660E\u7EC6`
5548
+ );
5549
+ }
5550
+ } catch (error) {
5551
+ detailsState = "unverified";
5552
+ warnings.push(`\u660E\u7EC6\u8BFB\u56DE\u6821\u9A8C\u5931\u8D25\uFF08\u65E0\u6CD5\u786E\u8BA4\u660E\u7EC6\u662F\u5426\u843D\u5E93\uFF09\uFF1A${error?.message || "\u672A\u77E5\u9519\u8BEF"}`);
5553
+ }
5554
+ }
6118
5555
  return ehrSuccess("ehr.recruit.candidate.import.apply", {
6119
- result: "success",
5556
+ result: detailsState === "complete" ? "success" : "partial",
5557
+ detailsState,
6120
5558
  talentId,
6121
5559
  candidateName: payload.candidateName,
6122
5560
  telephone: payload.telephone,
6123
5561
  mainTableFields: Object.keys(mainTable).length,
6124
5562
  detailRows: payload.subStats || void 0,
5563
+ detailRowsExpected: expectedDetailRows || void 0,
6125
5564
  attachment: uploaded ? { name: uploaded.name, size: uploaded.size } : null,
6126
5565
  batch: { ok: batchOk, note: batchNote },
6127
5566
  labelMatch,
@@ -6484,6 +5923,7 @@ async function executeAndPrint(ctx, operation, input) {
6484
5923
  });
6485
5924
  ctx.output.write(successEnvelope(operation, result), { json: true });
6486
5925
  } catch (error) {
5926
+ reportPlatformError(error);
6487
5927
  console.error(JSON.stringify(failureEnvelope(error), null, 2));
6488
5928
  process.exitCode = isCliError(error) ? error.exitCode : 1 /* GeneralError */;
6489
5929
  }