weaver-work-cli 0.1.32 → 0.1.36
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/chunks/{archive-UMGX72K6.js → archive-XBVH7JU7.js} +2 -2
- package/dist/chunks/{archive-oa-N2IYBLF3.js → archive-oa-MZM3EKFQ.js} +2 -2
- package/dist/chunks/{asset-GLEGKFG5.js → asset-4XO7UOUW.js} +2 -2
- package/dist/chunks/{attachment-content-AQNX5N3S.js → attachment-content-VXSWANAC.js} +3 -2
- package/dist/chunks/{blog-E44OTVDA.js → blog-PGZKOPSC.js} +2 -2
- package/dist/chunks/{caizhilian-DQUFZXZL.js → caizhilian-BH4ZVGUN.js} +2 -2
- package/dist/chunks/{calendar-JKPIRKFD.js → calendar-MXEMTIO4.js} +2 -2
- package/dist/chunks/{chunk-QWY6PGL6.js → chunk-2LV74IWP.js} +361 -56
- package/dist/chunks/chunk-3SO6QL6U.js +73 -0
- package/dist/chunks/chunk-5DQEEGCC.js +229 -0
- package/dist/chunks/{chunk-G3QJULO2.js → chunk-6LLJFKJE.js} +1 -1
- package/dist/chunks/{chunk-C6R3B2ML.js → chunk-BPE37FPB.js} +35 -7
- package/dist/chunks/chunk-BYATLLEF.js +68 -0
- package/dist/chunks/chunk-BYBSCN4X.js +932 -0
- package/dist/chunks/{chunk-CVZ2JOSW.js → chunk-F746NKNF.js} +1 -1
- package/dist/chunks/{chunk-GCG2NMWR.js → chunk-HXJQI5NM.js} +4 -2
- package/dist/chunks/{chunk-YRVDW4WN.js → chunk-I6QGIBDM.js} +2 -2
- package/dist/chunks/{chunk-H7J4DC5R.js → chunk-JCSN3JGM.js} +2 -2
- package/dist/chunks/{chunk-2GA5ZIQL.js → chunk-JNG42JKG.js} +30 -1
- package/dist/chunks/{chunk-DW6AUUKS.js → chunk-JUXVYKII.js} +9 -4
- package/dist/chunks/{chunk-6RKD4DRZ.js → chunk-JYKABYCV.js} +2 -2
- package/dist/chunks/{chunk-6EFWDL7Y.js → chunk-NCOVUAZK.js} +2 -2
- package/dist/chunks/{chunk-E4Z23GHM.js → chunk-QHFANTX7.js} +1114 -904
- package/dist/chunks/{ebuilder-form-V5FG2EHC.js → chunk-QYGO5EE2.js} +22 -1148
- package/dist/chunks/{chunk-IURUFGZK.js → chunk-T72N74ZT.js} +50 -33
- package/dist/chunks/{chunk-H6XSTSLM.js → chunk-TC6MZAO3.js} +137 -204
- package/dist/chunks/{chunk-WKI2FBIQ.js → chunk-VPUTVEMC.js} +737 -341
- package/dist/chunks/{chunk-WSKBSQ2U.js → chunk-VPXOPQJI.js} +2 -2
- package/dist/chunks/chunk-WXFPWCXG.js +774 -0
- package/dist/chunks/{chunk-4YC43QQ4.js → chunk-XMGSYD6S.js} +4 -4
- package/dist/chunks/conflict-JAB2LJEZ.js +21 -0
- package/dist/chunks/continuation-RN6PZN2M.js +11 -0
- package/dist/chunks/contract-XI2EEIZU.js +9110 -0
- package/dist/chunks/cowork-SCPGLBA4.js +2527 -0
- package/dist/chunks/ebuilder-form-EYLHNOTA.js +121 -0
- package/dist/chunks/{ehr-HMFY6VIL.js → ehr-EAP77IMT.js} +1344 -27
- package/dist/chunks/{esb-ZYSVB7SG.js → esb-2TGGXEE7.js} +4 -4
- package/dist/chunks/{fna-B7RKPAZD.js → fna-2X7ZE7BU.js} +13 -8
- package/dist/chunks/{host-OCH2BCCV.js → host-C6EL2RKL.js} +3 -3
- package/dist/chunks/{host-45WED2KK.js → host-I4NRK4MX.js} +3 -3
- package/dist/chunks/{host-I4Z6BFYX.js → host-Q4LZGCRU.js} +3 -3
- package/dist/chunks/host-UEI5FGDM.js +23 -0
- package/dist/chunks/{host-KNZ52LJZ.js → host-XCLDDXKQ.js} +3 -3
- package/dist/chunks/{hrm-2KAZGUHI.js → hrm-YXERJM76.js} +3 -3
- package/dist/chunks/{im-ACJJWH4U.js → im-A4VZN2TQ.js} +88 -12
- package/dist/chunks/{invoice-ZK3WCX2U.js → invoice-2Z6YPMIS.js} +3 -3
- package/dist/chunks/{jiuchuanhui-5PQD3IL2.js → jiuchuanhui-AR5GMKZB.js} +2 -2
- package/dist/chunks/{lazy-dispatch-JQXBW3GM.js → lazy-dispatch-QXW7P4X3.js} +4 -4
- package/dist/chunks/{mail-S2HDDXO2.js → mail-7GZ6CPBJ.js} +45 -24
- package/dist/chunks/{meeting-QVN3I37L.js → meeting-3NMGA3MB.js} +278 -43
- package/dist/chunks/{okr-QNG4VC2Q.js → okr-BZ6XUOAG.js} +2 -2
- package/dist/chunks/operations-5QL3AECO.js +11 -0
- package/dist/chunks/{plan-A25EMW6U.js → plan-DR5CMUYP.js} +2 -2
- package/dist/chunks/{project-G6XV66DZ.js → project-6J63MK33.js} +2 -2
- package/dist/chunks/{registry-DC6KR3NH.js → registry-KDD7DHNK.js} +4 -4
- package/dist/chunks/{registry-2VLUAESA.js → registry-OZSMDVPP.js} +2 -2
- package/dist/chunks/{registry-7C5UMIPL.js → registry-TKX2E7C7.js} +2 -2
- package/dist/chunks/{registry-TI3CIUXF.js → registry-VRTNC6UR.js} +8 -6
- package/dist/chunks/{room-recommend-WRTHO6Y2.js → room-recommend-XCWRMB5P.js} +4 -3
- package/dist/chunks/{schedule-KFIITGSK.js → schedule-IVBICP32.js} +4 -3
- package/dist/chunks/{workflow-DJ7SYWAF.js → workflow-D74NFK3C.js} +179 -6
- package/dist/index.js +35 -25
- package/dist/internal/e10/auth-recovery.js +14 -4
- package/dist/internal/e10/fetch-timing.js +31 -0
- package/dist/internal/e10/request-runtime.js +5 -0
- package/dist/shortcuts/contract/host.js +34 -59
- package/dist/shortcuts/cowork/continuation.js +70 -0
- package/dist/shortcuts/cowork/errors.js +59 -0
- package/dist/shortcuts/cowork/host.js +180 -0
- package/dist/shortcuts/cowork/index.js +166 -0
- package/dist/shortcuts/cowork/manifest.js +65 -0
- package/dist/shortcuts/cowork/operations/discuss-write.js +277 -0
- package/dist/shortcuts/cowork/operations/item-write.js +380 -0
- package/dist/shortcuts/cowork/operations/member-write.js +283 -0
- package/dist/shortcuts/cowork/operations/permission-write.js +286 -0
- package/dist/shortcuts/cowork/operations/read.js +423 -0
- package/dist/shortcuts/cowork/operations/registry.js +39 -0
- package/dist/shortcuts/cowork/operations/review-write.js +157 -0
- package/dist/shortcuts/cowork/operations/shared.js +215 -0
- package/dist/shortcuts/cowork/operations/types.js +39 -0
- package/dist/shortcuts/cowork/operations.js +19 -0
- package/dist/shortcuts/ehr/host.js +4 -1
- package/dist/shortcuts/ehr/operations/recruit-candidate-import.js +757 -0
- package/dist/shortcuts/ehr/operations/recruit-position.js +367 -0
- package/dist/shortcuts/ehr/operations/recruit-stats.js +133 -0
- package/dist/shortcuts/ehr/operations/recruit-write.js +43 -16
- package/dist/shortcuts/ehr/operations/recruit.js +182 -10
- package/dist/shortcuts/ehr/operations/registry.js +6 -0
- package/dist/shortcuts/fna/operations/expense-chart.js +19 -7
- package/dist/shortcuts/im/diagnostics.js +97 -0
- package/dist/shortcuts/im/host.js +58 -31
- package/dist/shortcuts/im/index.js +7 -2
- package/dist/shortcuts/im/operations/at-mention.js +127 -0
- package/dist/shortcuts/im/operations/file-user.js +10 -2
- package/dist/shortcuts/im/operations/group-read.js +26 -5
- package/dist/shortcuts/im/operations/group-write.js +35 -28
- package/dist/shortcuts/im/operations/msg-sync.js +7 -2
- package/dist/shortcuts/im/operations/msg-write.js +76 -10
- package/dist/shortcuts/im/operations/quote-mention.js +119 -0
- package/dist/shortcuts/im/operations/session.js +1 -1
- package/dist/shortcuts/im/operations/shared.js +10 -0
- package/dist/shortcuts/im/operations/types.js +13 -0
- package/dist/shortcuts/index.js +10 -0
- package/dist/shortcuts/mail/host.js +12 -1
- package/dist/shortcuts/mail/operations/types.js +17 -2
- package/dist/shortcuts/meeting/host.js +27 -34
- package/dist/shortcuts/meeting/index.js +79 -1
- package/dist/shortcuts/meeting/manifest.js +10 -0
- package/dist/shortcuts/meeting/operations/create.js +4 -1
- package/dist/shortcuts/meeting/operations/eb/catalog.js +10 -0
- package/dist/shortcuts/meeting/operations/eb/conflict.js +84 -8
- package/dist/shortcuts/meeting/operations/eb/create-flow.js +1195 -140
- package/dist/shortcuts/meeting/operations/eb/factory.js +170 -8
- package/dist/shortcuts/meeting/operations/eb/index.js +16 -3
- package/dist/shortcuts/meeting/operations/eb/room-recommend.js +50 -5
- package/dist/shortcuts/meeting/operations/eb-fallback.js +163 -0
- package/dist/shortcuts/meeting/operations/env.js +99 -46
- package/dist/shortcuts/meeting/operations/form-fields.js +110 -0
- package/dist/shortcuts/meeting/operations/invitation.js +79 -20
- package/dist/shortcuts/meeting/operations/registry.js +2 -0
- package/dist/shortcuts/meeting/operations/standard-guard.js +71 -0
- package/dist/shortcuts/meeting/operations.js +16 -0
- package/dist/shortcuts/workflow/endpoints.js +8 -3
- package/dist/shortcuts/workflow/index.js +110 -1
- package/dist/shortcuts/workflow/operations/form.js +204 -36
- package/dist/shortcuts/workflow/operations/read.js +104 -23
- package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupRules.js +448 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupStore.js +106 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/businessRules.js +47 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +30 -23
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.core.js +1 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.group.js +1 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +2 -1
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +2 -4
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +138 -181
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +12 -7
- package/dist/shortcuts/workflow/operations.js +23 -1
- package/docs/e10-auth.md +1 -1
- package/docs/ehr.md +1 -1
- package/docs/fna.md +2 -1
- package/docs/im.md +8 -1
- package/docs/todo-smart-convert/README.md +1 -1
- package/docs/todo-smart-convert/data-contract.md +2 -2
- package/docs/todo-smart-convert/subgroup-rules.md +6 -0
- package/package.json +1 -1
- package/skill-template/business-info.json +18 -0
- package/skill-template/domains/cowork.md +14 -0
- package/skill-template/domains/yimiaoban.md +3 -3
- package/skill-template/skill-template.md +1 -1
- package/skills/weaver-e10-blog/SKILL.md +5 -5
- package/skills/weaver-e10-caizhilian/SKILL.md +5 -5
- package/skills/weaver-e10-calendar/SKILL.md +5 -5
- package/skills/weaver-e10-cowork/SKILL.md +101 -0
- package/skills/weaver-e10-cowork/references/cowork-read.md +90 -0
- package/skills/weaver-e10-cowork/references/cowork-write.md +131 -0
- package/skills/weaver-e10-cowork/references/safety-boundaries.md +45 -0
- package/skills/weaver-e10-esb/SKILL.md +5 -5
- package/skills/weaver-e10-hrm/SKILL.md +5 -5
- package/skills/weaver-e10-jinchengda/SKILL.md +2 -2
- package/skills/weaver-e10-jiuchuanhui/SKILL.md +5 -5
- package/skills/weaver-e10-jucailin/SKILL.md +38 -14
- package/skills/weaver-e10-jucailin/references/recruit-create.md +104 -0
- package/skills/weaver-e10-jucailin/references/recruit-read.md +25 -0
- package/skills/weaver-e10-jucailin/references/recruit-write.md +13 -0
- package/skills/weaver-e10-jucailin/references/salary.md +15 -11
- package/skills/weaver-e10-mail/SKILL.md +17 -14
- package/skills/weaver-e10-meeting/SKILL.md +442 -46
- package/skills/weaver-e10-meeting/references/meeting-eb.md +135 -3
- package/skills/weaver-e10-meeting/references/meeting-invitation.md +28 -2
- package/skills/weaver-e10-meeting/references/meeting-queries.md +9 -6
- package/skills/weaver-e10-meeting/references/meeting-verification.md +8 -6
- package/skills/weaver-e10-meeting.zip +0 -0
- package/skills/weaver-e10-okr/SKILL.md +5 -5
- package/skills/weaver-e10-okr/references/source-manifest.json +3 -3
- package/skills/weaver-e10-plan/SKILL.md +5 -5
- package/skills/weaver-e10-qiyecheng/SKILL.md +5 -2
- package/skills/weaver-e10-qiyecheng/references/catalog.md +2 -2
- package/skills/weaver-e10-qiyecheng/references/expense-chart.md +15 -1
- package/skills/weaver-e10-qiyecheng/references/source-manifest.json +22 -21
- package/skills/weaver-e10-shared/SKILL.md +12 -12
- package/skills/weaver-e10-shared/references/e10-auth-and-session.md +4 -4
- package/skills/weaver-e10-wenshuding/SKILL.md +5 -5
- package/skills/weaver-e10-workflow/SKILL.md +29 -5
- package/skills/weaver-e10-workflow/aigroup/default.json +88 -0
- package/skills/weaver-e10-workflow/references/todo-smart-convert.md +66 -14
- package/skills/weaver-e10-workflow/references/workflow-agent-entry.md +1 -1
- package/skills/weaver-e10-workflow/references/workflow-memory.md +1 -1
- package/skills/weaver-e10-workflow/references/workflow-query.md +12 -10
- package/skills/weaver-e10-workflow/references/workflow-view.md +2 -2
- package/skills/weaver-e10-workflow/tools/todo-serve.cjs +239 -0
- package/skills/weaver-e10-workflow/{scripts → tools}/todo-summary.cjs +218 -28
- package/skills/weaver-e10-yepiaotong/SKILL.md +10 -8
- package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +7 -7
- package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +10 -10
- package/skills/weaver-e10-yepiaotong/references/reim-examples.md +40 -37
- package/skills/weaver-e10-yepiaotong/references/reim-expense-subject-rules.md +4 -4
- package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +27 -38
- package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +4 -4
- package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +37 -29
- package/skills/weaver-e10-yimiaoban/SKILL.md +156 -33
- package/skills/weaver-e10-yimiaoban/references/ding-write.md +1 -1
- package/skills/weaver-e10-yimiaoban/references/error-codes.md +5 -1
- package/skills/weaver-e10-yimiaoban/references/group-read.md +5 -1
- package/skills/weaver-e10-yimiaoban/references/group-write.md +6 -4
- package/skills/weaver-e10-yimiaoban/references/msg-read.md +1 -0
- package/skills/weaver-e10-yimiaoban/references/msg-write.md +34 -2
- package/skills/weaver-e10-yimiaoban/references/safety-boundaries.md +5 -2
- package/skills/weaver-e10-yimiaoban/references/source-manifest.json +79 -58
- package/skills/weaver-e10-yimiaoban/references/user-remind.md +2 -2
- package/skills/weaver-e10-ziguanjia/SKILL.md +5 -5
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
E10ApiError,
|
|
5
5
|
createE10RequestRuntime,
|
|
6
6
|
requireE10Session
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-JUXVYKII.js";
|
|
8
8
|
import {
|
|
9
9
|
E10_SESSION_EXPIRED_MESSAGE,
|
|
10
10
|
getActiveProfile
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-JNG42JKG.js";
|
|
12
12
|
import {
|
|
13
13
|
CliError,
|
|
14
14
|
isCliError,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import "./chunk-BUSC6UAE.js";
|
|
18
18
|
|
|
19
19
|
// src/shortcuts/ehr/index.ts
|
|
20
|
-
import { readFile as
|
|
20
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
21
21
|
|
|
22
22
|
// src/shortcuts/ehr/continuation.ts
|
|
23
23
|
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
@@ -221,7 +221,7 @@ function mapRuntimeNetworkError(error) {
|
|
|
221
221
|
function createEhrHost(ctx, dependencies = {}) {
|
|
222
222
|
let e10Session = null;
|
|
223
223
|
let sessionContext = null;
|
|
224
|
-
const requireSession = dependencies.requireSession || requireE10Session;
|
|
224
|
+
const requireSession = dependencies.requireSession || ((innerCtx) => requireE10Session(innerCtx, { skipProfileEnrichment: true }));
|
|
225
225
|
async function ensureSession() {
|
|
226
226
|
if (!e10Session) {
|
|
227
227
|
e10Session = await requireSession(ctx);
|
|
@@ -2876,8 +2876,24 @@ async function fetchListRows(host, objId, listId, body) {
|
|
|
2876
2876
|
const hasDisplay = Array.isArray(displayRows) && displayRows.length > 0;
|
|
2877
2877
|
const rows = hasDisplay ? displayRows : rawRows;
|
|
2878
2878
|
const countData = countResponse ? normalizePaged(countResponse).data : null;
|
|
2879
|
-
const
|
|
2880
|
-
|
|
2879
|
+
const pageSize = typeof body.pageSize === "number" ? body.pageSize : typeof body.pageSize === "string" ? Number(body.pageSize) || rows.length : rows.length;
|
|
2880
|
+
const countUsable = countData !== null && typeof countData.total === "number";
|
|
2881
|
+
let total;
|
|
2882
|
+
let totalExact;
|
|
2883
|
+
let totalNote;
|
|
2884
|
+
if (countUsable) {
|
|
2885
|
+
total = countData.total;
|
|
2886
|
+
totalExact = true;
|
|
2887
|
+
} else if (rows.length < pageSize) {
|
|
2888
|
+
total = rows.length;
|
|
2889
|
+
totalExact = true;
|
|
2890
|
+
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";
|
|
2891
|
+
} else {
|
|
2892
|
+
total = null;
|
|
2893
|
+
totalExact = false;
|
|
2894
|
+
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";
|
|
2895
|
+
}
|
|
2896
|
+
return { rows, displayRows: hasDisplay ? displayRows : null, total, totalExact, totalNote };
|
|
2881
2897
|
}
|
|
2882
2898
|
var contextResolve = {
|
|
2883
2899
|
name: "ehr.recruit.context.resolve",
|
|
@@ -2942,7 +2958,7 @@ var candidateSearch = {
|
|
|
2942
2958
|
pageSize: toNumber(args.pageSize, "pageSize") ?? 10,
|
|
2943
2959
|
conditions
|
|
2944
2960
|
});
|
|
2945
|
-
const { rows, displayRows, total } = await fetchListRows(env.host, talentObjId, talentList.listId, body);
|
|
2961
|
+
const { rows, displayRows, total, totalExact, totalNote } = await fetchListRows(env.host, talentObjId, talentList.listId, body);
|
|
2946
2962
|
let creatorNameMap = {};
|
|
2947
2963
|
if (!displayRows) {
|
|
2948
2964
|
const pureIds = [...new Set(rows.map((row) => row?.creator).filter(isPlainId).map((value) => String(value).trim()))];
|
|
@@ -2987,7 +3003,7 @@ var candidateSearch = {
|
|
|
2987
3003
|
createTime: row?.create_time || null
|
|
2988
3004
|
};
|
|
2989
3005
|
});
|
|
2990
|
-
return ehrSuccess("ehr.recruit.candidate.search", { total, rows: dataRows });
|
|
3006
|
+
return ehrSuccess("ehr.recruit.candidate.search", { total, totalExact, ...totalNote ? { totalNote } : {}, rows: dataRows });
|
|
2991
3007
|
}
|
|
2992
3008
|
};
|
|
2993
3009
|
var candidateList = {
|
|
@@ -3032,7 +3048,7 @@ var candidateList = {
|
|
|
3032
3048
|
current: toPositiveInt(args.current, "current") ?? 1,
|
|
3033
3049
|
pageSize: toNumber(args.pageSize, "pageSize") ?? 10
|
|
3034
3050
|
});
|
|
3035
|
-
const { rows, displayRows, total } = await fetchListRows(env.host, formObjId, listParam.listId, body);
|
|
3051
|
+
const { rows, displayRows, total, totalExact, totalNote } = await fetchListRows(env.host, formObjId, listParam.listId, body);
|
|
3036
3052
|
const outRows = rows.map((row) => {
|
|
3037
3053
|
const cleaned = { form_data_id: row?.form_data_id || row?.id };
|
|
3038
3054
|
for (const [key, value] of Object.entries(row || {})) {
|
|
@@ -3061,12 +3077,148 @@ var candidateList = {
|
|
|
3061
3077
|
return ehrSuccess("ehr.recruit.candidate.list", {
|
|
3062
3078
|
type,
|
|
3063
3079
|
total,
|
|
3080
|
+
totalExact,
|
|
3081
|
+
...totalNote ? { totalNote } : {},
|
|
3064
3082
|
current: body.current,
|
|
3065
3083
|
pageSize: body.pageSize,
|
|
3066
3084
|
rows: outRows
|
|
3067
3085
|
});
|
|
3068
3086
|
}
|
|
3069
3087
|
};
|
|
3088
|
+
function personNames(value) {
|
|
3089
|
+
const text = String(value ?? "").trim();
|
|
3090
|
+
if (!text) return "";
|
|
3091
|
+
if (text.startsWith("[")) {
|
|
3092
|
+
try {
|
|
3093
|
+
const arr = JSON.parse(text);
|
|
3094
|
+
if (Array.isArray(arr)) {
|
|
3095
|
+
const names = arr.map((item) => typeof item === "string" ? item : item?.name ?? item?.username ?? "").filter(Boolean);
|
|
3096
|
+
if (names.length) return names.join("\u3001");
|
|
3097
|
+
}
|
|
3098
|
+
} catch {
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3101
|
+
return text;
|
|
3102
|
+
}
|
|
3103
|
+
function nameLike(value) {
|
|
3104
|
+
const text = String(value ?? "").trim();
|
|
3105
|
+
if (!text || /^\d{16,}$/.test(text)) return null;
|
|
3106
|
+
return text;
|
|
3107
|
+
}
|
|
3108
|
+
async function resolveCurrentUserName(host) {
|
|
3109
|
+
try {
|
|
3110
|
+
const session = await host.getSession();
|
|
3111
|
+
const baseUrl = String(session?.baseUrl || "");
|
|
3112
|
+
if (!baseUrl) return "";
|
|
3113
|
+
const resp = await fetch(
|
|
3114
|
+
`${baseUrl}/api/baseserver/layout/teamsCheck?clientType=not_xinchuang&client=WEB&domainName=${encodeURIComponent(baseUrl)}`,
|
|
3115
|
+
{
|
|
3116
|
+
method: "POST",
|
|
3117
|
+
headers: {
|
|
3118
|
+
accept: "application/json",
|
|
3119
|
+
"content-type": "application/json",
|
|
3120
|
+
eteamsid: String(session?.eteamsId || ""),
|
|
3121
|
+
cookie: typeof session?.cookieHeader === "function" ? session.cookieHeader() : "",
|
|
3122
|
+
"user-agent": typeof session?.uaHeader === "function" ? session.uaHeader() : "weaver-work-cli",
|
|
3123
|
+
origin: baseUrl
|
|
3124
|
+
},
|
|
3125
|
+
redirect: "manual"
|
|
3126
|
+
}
|
|
3127
|
+
);
|
|
3128
|
+
const data = await resp.json().catch(() => ({}));
|
|
3129
|
+
const cu = data.currentUser ?? data.data?.currentUser ?? null;
|
|
3130
|
+
return cu ? String(cu.username ?? cu.id ?? "") : "";
|
|
3131
|
+
} catch {
|
|
3132
|
+
return "";
|
|
3133
|
+
}
|
|
3134
|
+
}
|
|
3135
|
+
var interviewFeedbackTodo = {
|
|
3136
|
+
name: "ehr.recruit.interview.feedbackTodo",
|
|
3137
|
+
resource: "recruit",
|
|
3138
|
+
method: "interview.feedbackTodo",
|
|
3139
|
+
action: "ehr.recruit.interview.feedbackTodo",
|
|
3140
|
+
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",
|
|
3141
|
+
capability: "recruit",
|
|
3142
|
+
risk: READ,
|
|
3143
|
+
inputSchema: schemaOf({
|
|
3144
|
+
maxPages: { type: "integer", minimum: 1, maximum: 50, description: "\u6700\u591A\u7FFB\u9875\u6570\uFF08\u9ED8\u8BA4 5\uFF09" },
|
|
3145
|
+
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" }
|
|
3146
|
+
}),
|
|
3147
|
+
handler: async (args, env) => {
|
|
3148
|
+
if (!env.recruitContext) throw ehrValidationError("recruit_context_unavailable", "\u62DB\u8058\u4E0A\u4E0B\u6587\u52A0\u8F7D\u5668\u672A\u521D\u59CB\u5316");
|
|
3149
|
+
const cache = await env.recruitContext.load(env.host);
|
|
3150
|
+
const listParam = cache.lists.interview;
|
|
3151
|
+
const form = cache.forms.interview_plan;
|
|
3152
|
+
if (!listParam?.listId || !form?.objId) {
|
|
3153
|
+
throw new RecruitContextError(
|
|
3154
|
+
"recruit_list_unavailable",
|
|
3155
|
+
"\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"
|
|
3156
|
+
);
|
|
3157
|
+
}
|
|
3158
|
+
const pageSize = toNumber(args.pageSize, "pageSize") ?? 200;
|
|
3159
|
+
const maxPages = toNumber(args.maxPages, "maxPages") ?? 5;
|
|
3160
|
+
const me = await resolveCurrentUserName(env.host);
|
|
3161
|
+
const fields = cache.fields[form.objId] || {};
|
|
3162
|
+
const fieldOpts = cache.field_options[form.objId] || {};
|
|
3163
|
+
const statusOpts = fieldOpts[fields.union_status] || {};
|
|
3164
|
+
const typeOpts = fieldOpts[fields.interview_type] || {};
|
|
3165
|
+
const toCn = (map, raw) => {
|
|
3166
|
+
const text = String(raw ?? "");
|
|
3167
|
+
return map[text] ?? text;
|
|
3168
|
+
};
|
|
3169
|
+
const statusOf = (row) => toCn(statusOpts, row?.union_status_key ?? row?.union_status);
|
|
3170
|
+
const typeOf = (row) => toCn(typeOpts, row?.interview_type_key ?? row?.interview_type);
|
|
3171
|
+
const interviewerOf = (row) => personNames(row?.interviewer);
|
|
3172
|
+
const scanned = [];
|
|
3173
|
+
let lastPageCount = 0;
|
|
3174
|
+
for (let i = 0; i < maxPages; i++) {
|
|
3175
|
+
const body = buildListBody({
|
|
3176
|
+
listId: listParam.listId,
|
|
3177
|
+
cusMenuId: listParam.cusMenuId,
|
|
3178
|
+
menuName: listParam.menuName || "\u9762\u8BD5\u7BA1\u7406",
|
|
3179
|
+
title: "\u9762\u8BD5\u7BA1\u7406",
|
|
3180
|
+
current: i + 1,
|
|
3181
|
+
pageSize
|
|
3182
|
+
});
|
|
3183
|
+
const page = await fetchListRows(env.host, form.objId, listParam.listId, body);
|
|
3184
|
+
const use = page.displayRows && page.displayRows.length ? page.displayRows : page.rows;
|
|
3185
|
+
scanned.push(...use);
|
|
3186
|
+
lastPageCount = use.length;
|
|
3187
|
+
if (use.length < pageSize) break;
|
|
3188
|
+
}
|
|
3189
|
+
const pending = scanned.filter((row) => /待反馈/.test(statusOf(row)));
|
|
3190
|
+
const mineAll = me ? pending.filter((row) => interviewerOf(row).includes(me)) : [];
|
|
3191
|
+
const mineAi = mineAll.filter((row) => /AI\s*面试/i.test(typeOf(row)));
|
|
3192
|
+
const slim = (row) => ({
|
|
3193
|
+
form_data_id: row?.form_data_id ?? row?.id ?? null,
|
|
3194
|
+
candidate_name: nameLike(row?.candidate_name) ?? nameLike(row?.talent_id) ?? nameLike(row?.name),
|
|
3195
|
+
position_name: nameLike(row?.position_name) ?? nameLike(row?.position_manage_id),
|
|
3196
|
+
start_time: row?.start_time ?? null,
|
|
3197
|
+
interview_type_key: typeOf(row) || null,
|
|
3198
|
+
interview_session: row?.interview_session ?? null,
|
|
3199
|
+
interviewer: interviewerOf(row) || null,
|
|
3200
|
+
union_status_key: statusOf(row) || null,
|
|
3201
|
+
subject: row?.subject ?? null,
|
|
3202
|
+
talent_id: row?.talent_id ?? null,
|
|
3203
|
+
position_manage_id: row?.position_manage_id ?? null
|
|
3204
|
+
});
|
|
3205
|
+
const notes = [];
|
|
3206
|
+
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");
|
|
3207
|
+
if (lastPageCount >= pageSize && scanned.length >= pageSize * maxPages) {
|
|
3208
|
+
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`);
|
|
3209
|
+
}
|
|
3210
|
+
return ehrSuccess("ehr.recruit.interview.feedbackTodo", {
|
|
3211
|
+
currentUser: me || null,
|
|
3212
|
+
scanned: scanned.length,
|
|
3213
|
+
myAiPendingFeedback: { count: mineAi.length, rows: mineAi.map(slim) },
|
|
3214
|
+
myOtherPendingFeedback: {
|
|
3215
|
+
count: mineAll.length - mineAi.length,
|
|
3216
|
+
rows: mineAll.filter((row) => !/AI\s*面试/i.test(typeOf(row))).map(slim)
|
|
3217
|
+
},
|
|
3218
|
+
...notes.length ? { note: notes.join("\uFF1B") } : {}
|
|
3219
|
+
});
|
|
3220
|
+
}
|
|
3221
|
+
};
|
|
3070
3222
|
var candidateCard = {
|
|
3071
3223
|
name: "ehr.recruit.candidate.card",
|
|
3072
3224
|
resource: "recruit",
|
|
@@ -3181,7 +3333,8 @@ var recruitOperations = [
|
|
|
3181
3333
|
contextResolve,
|
|
3182
3334
|
candidateSearch,
|
|
3183
3335
|
candidateList,
|
|
3184
|
-
candidateCard
|
|
3336
|
+
candidateCard,
|
|
3337
|
+
interviewFeedbackTodo
|
|
3185
3338
|
];
|
|
3186
3339
|
|
|
3187
3340
|
// src/shortcuts/ehr/operations/recruit-write.ts
|
|
@@ -3212,6 +3365,24 @@ async function requireRecruitCache(env) {
|
|
|
3212
3365
|
}
|
|
3213
3366
|
return env.recruitContext.load(env.host);
|
|
3214
3367
|
}
|
|
3368
|
+
function recruitTalentCardUrl(cache, baseUrl, talentId) {
|
|
3369
|
+
if (!cache.ebdDetailPageId || !talentId) return null;
|
|
3370
|
+
const extra = String(cache.selfUse) === "1" ? "&recruitType=useSelf" : "";
|
|
3371
|
+
return `${baseUrl.replace(/\/+$/, "")}/sp/ebdpage/view/${cache.ebdDetailPageId}?talentId=${talentId}${extra}`;
|
|
3372
|
+
}
|
|
3373
|
+
function recruitSlideLocateUrl(cache, baseUrl, listKey, formKey, dataId) {
|
|
3374
|
+
const listId = cache.lists?.[listKey]?.listId;
|
|
3375
|
+
const objId = cache.forms?.[formKey]?.objId;
|
|
3376
|
+
if (!listId || !objId || !dataId || !cache.appId) return null;
|
|
3377
|
+
const base = baseUrl.replace(/\/+$/, "");
|
|
3378
|
+
return `${base}/sp/ebdfpage/list/${listId}/card/0/${objId}/${dataId}/${listId}?id=${dataId}&openSource=field&openSourceId=${dataId}&openSourceAppId=${cache.appId}`;
|
|
3379
|
+
}
|
|
3380
|
+
function recruitOpenListUrl(cache, baseUrl, listKey, talentId) {
|
|
3381
|
+
const menu = cache.lists?.[listKey];
|
|
3382
|
+
if (!menu?.listId) return null;
|
|
3383
|
+
const extra = talentId ? `?talentId=${talentId}${String(cache.selfUse) === "1" ? "&recruitType=useSelf" : ""}` : "";
|
|
3384
|
+
return `${baseUrl.replace(/\/+$/, "")}/sp/ebdfpage/list/${menu.listId}${extra}`;
|
|
3385
|
+
}
|
|
3215
3386
|
async function checkDuplicateByMobile(env, cache, mobile) {
|
|
3216
3387
|
const talent = cache.lists.talent;
|
|
3217
3388
|
const objId = cache.forms.talent_pool?.objId;
|
|
@@ -3364,12 +3535,6 @@ async function resolvePersonId(host, fieldId, keyword) {
|
|
|
3364
3535
|
const first = list[0];
|
|
3365
3536
|
return first ? String(first.id || first.value || "") || null : null;
|
|
3366
3537
|
}
|
|
3367
|
-
async function getInterviewPortalFieldIds(host) {
|
|
3368
|
-
const response = await host.request({
|
|
3369
|
-
path: "/api/recruit/candidate/getFieldIdsForInterview"
|
|
3370
|
-
});
|
|
3371
|
-
return response?.data || {};
|
|
3372
|
-
}
|
|
3373
3538
|
async function saveFormData(host, params) {
|
|
3374
3539
|
const layoutId = params.layoutId || params.formId;
|
|
3375
3540
|
const customParam = {
|
|
@@ -3682,7 +3847,9 @@ var candidateCreateApply = {
|
|
|
3682
3847
|
status: "COMPLETE",
|
|
3683
3848
|
talentId: newId,
|
|
3684
3849
|
initTalentBatch: initMsg,
|
|
3685
|
-
searchHint: `\u53EF\u7528 ehr.recruit.candidate.search \u6309 name=${name} \u6216 mobile=${mobile} \u56DE\u67E5
|
|
3850
|
+
searchHint: `\u53EF\u7528 ehr.recruit.candidate.search \u6309 name=${name} \u6216 mobile=${mobile} \u56DE\u67E5`,
|
|
3851
|
+
talentCardUrl: recruitTalentCardUrl(cache, lease.baseUrl, newId),
|
|
3852
|
+
talentListLocateUrl: recruitOpenListUrl(cache, lease.baseUrl, "talent", newId)
|
|
3686
3853
|
});
|
|
3687
3854
|
}
|
|
3688
3855
|
};
|
|
@@ -3730,11 +3897,10 @@ async function buildInterviewPlan(env, cache, args) {
|
|
|
3730
3897
|
const objId = cacheObjId(cache, "interview_plan", "\u9762\u8BD5\u8BA1\u5212\u8868\u5355");
|
|
3731
3898
|
const formId = cacheFormId(cache, "interview_plan");
|
|
3732
3899
|
const fields = cache.fields[objId] || {};
|
|
3733
|
-
const
|
|
3734
|
-
const fieldIdOf = (key) => fields[key] || portalFields[key] || "";
|
|
3900
|
+
const fieldIdOf = (key) => fields[key] || "";
|
|
3735
3901
|
for (const key of INTERVIEW_DATAKEYS) {
|
|
3736
3902
|
if (!fieldIdOf(key)) {
|
|
3737
|
-
throw ehrValidationError("recruit_field_missing", `\u9762\u8BD5\u8BA1\u5212\u8868\u5355\u7F3A\u5C11\u5B57\u6BB5 ${key}\
|
|
3903
|
+
throw ehrValidationError("recruit_field_missing", `\u9762\u8BD5\u8BA1\u5212\u8868\u5355\u7F3A\u5C11\u5B57\u6BB5 ${key}\uFF08\u73AF\u5883\u7F13\u5B58 ds/fields \u672A\u89E3\u6790\u5230\uFF0C\u8BF7\u91CD\u5EFA\u73AF\u5883\u7F13\u5B58\u540E\u91CD\u8BD5\uFF09`);
|
|
3738
3904
|
}
|
|
3739
3905
|
}
|
|
3740
3906
|
const typeMap = await getDsOptions(host, objId, fieldIdOf("interview_type"), cache.appId);
|
|
@@ -3907,7 +4073,9 @@ var interviewArrangeApply = {
|
|
|
3907
4073
|
assigned: assigned?.data || {},
|
|
3908
4074
|
candidate: `${plan.candidateName}\uFF08talentId=${args.talentId}\uFF09`,
|
|
3909
4075
|
time: plan.interviewTime,
|
|
3910
|
-
interviewer: plan.interviewer
|
|
4076
|
+
interviewer: plan.interviewer,
|
|
4077
|
+
talentCardUrl: recruitTalentCardUrl(cache, lease.baseUrl, args.talentId),
|
|
4078
|
+
interviewLocateUrl: recruitSlideLocateUrl(cache, lease.baseUrl, "interview", "interview_plan", planFormId)
|
|
3911
4079
|
});
|
|
3912
4080
|
}
|
|
3913
4081
|
};
|
|
@@ -4158,7 +4326,9 @@ var offerSendApply = {
|
|
|
4158
4326
|
validateOffer: "\u901A\u8FC7",
|
|
4159
4327
|
sendOffer: "SUCCESS",
|
|
4160
4328
|
runEsb: { successNum: esbResult.successNum, failNum: esbResult.failNum, msg: esbResult.successMsg },
|
|
4161
|
-
nextStep: "\u56DE\u67E5 offer_status_select \u5E94\u5DF2\u53D8\u66F4\u4E3A\u300C\u5DF2\u53D1\u9001\u5F85\u53CD\u9988\u300D"
|
|
4329
|
+
nextStep: "\u56DE\u67E5 offer_status_select \u5E94\u5DF2\u53D8\u66F4\u4E3A\u300C\u5DF2\u53D1\u9001\u5F85\u53CD\u9988\u300D",
|
|
4330
|
+
talentCardUrl: recruitTalentCardUrl(cache, lease.baseUrl, payload.talentId),
|
|
4331
|
+
offerListUrl: recruitOpenListUrl(cache, lease.baseUrl, "offer")
|
|
4162
4332
|
});
|
|
4163
4333
|
}
|
|
4164
4334
|
};
|
|
@@ -4437,7 +4607,8 @@ var entryProcessApply = {
|
|
|
4437
4607
|
saveFormData: "\u5DF2\u66F4\u65B0",
|
|
4438
4608
|
saveEstPreEntry: "\u5DF2\u843D\u8D26\u53F7",
|
|
4439
4609
|
runEsb: { successNum: esbResult.successNum, failNum: esbResult.failNum, msg: esbResult.successMsg },
|
|
4440
|
-
nextStep: "\u56DE\u67E5\u5165\u804C\u5217\u8868 transact_status \u5E94\u7531 1 \u53D8\u4E3A 2"
|
|
4610
|
+
nextStep: "\u56DE\u67E5\u5165\u804C\u5217\u8868 transact_status \u5E94\u7531 1 \u53D8\u4E3A 2",
|
|
4611
|
+
entryListUrl: recruitOpenListUrl(cache, lease.baseUrl, "entry")
|
|
4441
4612
|
});
|
|
4442
4613
|
}
|
|
4443
4614
|
};
|
|
@@ -4666,7 +4837,8 @@ var feedbackEditApply = {
|
|
|
4666
4837
|
feedbackId: payload.feedbackId,
|
|
4667
4838
|
saved: Boolean(savedId),
|
|
4668
4839
|
verify: backFeedback ? { result: backFeedback.result, comment: backFeedback.judgement, changed } : "\u56DE\u67E5\u672A\u53D6\u5230\u8BE5\u53CD\u9988",
|
|
4669
|
-
...changed ? {} : { warning: "\u56DE\u67E5\u672A\u786E\u8BA4\u53D8\u66F4\u751F\u6548\uFF0C\u8BF7\u4EBA\u5DE5\u5728 E10 \u4E2D\u6838\u5BF9\u9762\u8BD5\u53CD\u9988\uFF0C\u7981\u6B62\u81EA\u52A8\u91CD\u8BD5" }
|
|
4840
|
+
...changed ? {} : { warning: "\u56DE\u67E5\u672A\u786E\u8BA4\u53D8\u66F4\u751F\u6548\uFF0C\u8BF7\u4EBA\u5DE5\u5728 E10 \u4E2D\u6838\u5BF9\u9762\u8BD5\u53CD\u9988\uFF0C\u7981\u6B62\u81EA\u52A8\u91CD\u8BD5" },
|
|
4841
|
+
talentCardUrl: recruitTalentCardUrl(cache, lease.baseUrl, payload.talentId)
|
|
4670
4842
|
});
|
|
4671
4843
|
}
|
|
4672
4844
|
};
|
|
@@ -4785,6 +4957,7 @@ var feedbackUrgeApply = {
|
|
|
4785
4957
|
requireConfirm2(args, "ehr.recruit.candidate.interview.feedback.urge.apply");
|
|
4786
4958
|
const lease = await verifyLease2(args, "ehr.recruit.candidate.interview.feedback.urge.apply", env);
|
|
4787
4959
|
const payload = lease.payload || {};
|
|
4960
|
+
const cache = await requireRecruitCache(env);
|
|
4788
4961
|
if (!payload.feedbackRecordId || !payload.esbActionId || !payload.interviewDetailObjId) {
|
|
4789
4962
|
throw ehrValidationError("continuation_payload_invalid", "continuation \u7F3A\u5C11\u50AC\u8BC4\u53C2\u6570\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C prepare");
|
|
4790
4963
|
}
|
|
@@ -4803,7 +4976,8 @@ var feedbackUrgeApply = {
|
|
|
4803
4976
|
return ehrSuccess("ehr.recruit.candidate.interview.feedback.urge.apply", {
|
|
4804
4977
|
status: "COMPLETE",
|
|
4805
4978
|
feedbackRecordId: payload.feedbackRecordId,
|
|
4806
|
-
runEsb: { successNum: esbResult.successNum, failNum: esbResult.failNum, msg: esbResult.successMsg }
|
|
4979
|
+
runEsb: { successNum: esbResult.successNum, failNum: esbResult.failNum, msg: esbResult.successMsg },
|
|
4980
|
+
talentCardUrl: recruitTalentCardUrl(cache, lease.baseUrl, payload.talentId)
|
|
4807
4981
|
});
|
|
4808
4982
|
}
|
|
4809
4983
|
};
|
|
@@ -4822,6 +4996,1146 @@ var recruitWriteOperations = [
|
|
|
4822
4996
|
feedbackUrgeApply
|
|
4823
4997
|
];
|
|
4824
4998
|
|
|
4999
|
+
// src/shortcuts/ehr/operations/recruit-stats.ts
|
|
5000
|
+
var STATS_MODULES = {
|
|
5001
|
+
talent: { listKey: "talent", formType: "talent_pool", title: "\u4EBA\u624D\u5E93" },
|
|
5002
|
+
demand: { listKey: "demand", formType: "demand_manage", title: "\u62DB\u8058\u9700\u6C42" },
|
|
5003
|
+
position: { listKey: "position", formType: "position_manage", title: "\u62DB\u8058\u804C\u4F4D" },
|
|
5004
|
+
entry: { listKey: "entry", formType: "entry_manage", title: "\u5165\u804C\u7BA1\u7406" },
|
|
5005
|
+
offer: { listKey: "offer", formType: "offer", title: "\u5F55\u7528\u7BA1\u7406" },
|
|
5006
|
+
interview: {
|
|
5007
|
+
listKey: "interview",
|
|
5008
|
+
formType: "interview_plan",
|
|
5009
|
+
title: "\u9762\u8BD5\u5B89\u6392",
|
|
5010
|
+
note: "\u9762\u8BD5\u7BA1\u7406\u5217\u8868\u53EF\u80FD\u6309\u9875\u9762\u914D\u7F6E\u53EA\u663E\u793A\u8FD1\u671F\u8BB0\u5F55\uFF0C\u8BA1\u6570\u4EC5\u4F9B\u91CF\u7EA7\u53C2\u8003"
|
|
5011
|
+
}
|
|
5012
|
+
};
|
|
5013
|
+
var DEFAULT_MODULES = ["talent", "demand", "position", "entry", "offer"];
|
|
5014
|
+
async function countModule(env, cache, key, pageSize, maxPages) {
|
|
5015
|
+
const cfg = STATS_MODULES[key];
|
|
5016
|
+
const list = cache.lists[cfg.listKey];
|
|
5017
|
+
const objId = cache.forms[cfg.formType]?.objId;
|
|
5018
|
+
if (!list?.listId || !objId) {
|
|
5019
|
+
return {
|
|
5020
|
+
key,
|
|
5021
|
+
module: cfg.title,
|
|
5022
|
+
available: false,
|
|
5023
|
+
total: null,
|
|
5024
|
+
totalExact: false,
|
|
5025
|
+
scannedRows: 0,
|
|
5026
|
+
note: "\u5F53\u524D\u73AF\u5883\u672A\u542F\u7528\u8BE5\u529F\u80FD\u83DC\u5355\uFF08\u672A\u627E\u5230\u5217\u8868\u6216\u8868\u5355\uFF09\uFF0C\u5DF2\u8DF3\u8FC7"
|
|
5027
|
+
};
|
|
5028
|
+
}
|
|
5029
|
+
const baseBody = buildListBody({
|
|
5030
|
+
listId: list.listId,
|
|
5031
|
+
cusMenuId: list.cusMenuId,
|
|
5032
|
+
menuName: list.menuName || cfg.title,
|
|
5033
|
+
title: cfg.title,
|
|
5034
|
+
pageSize
|
|
5035
|
+
});
|
|
5036
|
+
let scanned = 0;
|
|
5037
|
+
let total = null;
|
|
5038
|
+
let totalExact = false;
|
|
5039
|
+
let note = cfg.note;
|
|
5040
|
+
for (let current = 1; current <= maxPages; current++) {
|
|
5041
|
+
const page = await fetchListRows(env.host, objId, list.listId, { ...baseBody, current, pageSize });
|
|
5042
|
+
if (current === 1 && page.total !== null && page.totalExact) {
|
|
5043
|
+
total = page.total;
|
|
5044
|
+
totalExact = true;
|
|
5045
|
+
break;
|
|
5046
|
+
}
|
|
5047
|
+
scanned += page.rows.length;
|
|
5048
|
+
if (page.rows.length < pageSize) {
|
|
5049
|
+
total = scanned;
|
|
5050
|
+
totalExact = true;
|
|
5051
|
+
break;
|
|
5052
|
+
}
|
|
5053
|
+
}
|
|
5054
|
+
if (total === null) {
|
|
5055
|
+
totalExact = false;
|
|
5056
|
+
note = `\u8BA1\u6570\u63A5\u53E3\u4E0D\u53EF\u7528\u4E14\u8FBE\u626B\u63CF\u4E0A\u9650\uFF08${maxPages} \u9875 \xD7 ${pageSize} \u884C\uFF09\u4ECD\u672A\u53D6\u5B8C\uFF0C\u603B\u6570\u4E0D\u53EF\u77E5\uFF1B\u53EF\u8C03\u5927 pageSize/maxPages \u91CD\u8BD5`;
|
|
5057
|
+
}
|
|
5058
|
+
return { key, module: cfg.title, available: true, total, totalExact, scannedRows: scanned, ...note ? { note } : {} };
|
|
5059
|
+
}
|
|
5060
|
+
var recruitStats = {
|
|
5061
|
+
name: "ehr.recruit.stats",
|
|
5062
|
+
resource: "recruit",
|
|
5063
|
+
method: "stats",
|
|
5064
|
+
action: "ehr.recruit.stats",
|
|
5065
|
+
summary: '\u62DB\u8058\u5DE5\u4F5C\u7EDF\u8BA1\uFF1A\u6309\u6A21\u5757\u7EDF\u8BA1\u8BB0\u5F55\u6570\uFF08\u4EBA\u624D\u5E93/\u62DB\u8058\u9700\u6C42/\u62DB\u8058\u804C\u4F4D/\u5165\u804C\u7BA1\u7406/\u5F55\u7528\u7BA1\u7406/\u9762\u8BD5\u5B89\u6392\uFF09\uFF0C\u8BA1\u6570\u4E0D\u53EF\u7528\u65F6\u5982\u5B9E\u6807"\u603B\u6570\u4E0D\u53EF\u77E5"',
|
|
5066
|
+
capability: "recruit",
|
|
5067
|
+
risk: READ,
|
|
5068
|
+
inputSchema: schemaOf({
|
|
5069
|
+
modules: {
|
|
5070
|
+
type: "array",
|
|
5071
|
+
items: { type: "string", enum: Object.keys(STATS_MODULES) },
|
|
5072
|
+
uniqueItems: true,
|
|
5073
|
+
description: `\u8981\u7EDF\u8BA1\u7684\u6A21\u5757\uFF0C\u9ED8\u8BA4 ${DEFAULT_MODULES.join(",")}`
|
|
5074
|
+
},
|
|
5075
|
+
pageSize: { type: "integer", minimum: 1, maximum: 200, description: "\u5355\u9875\u884C\u6570\uFF0C\u9ED8\u8BA4 100\uFF08\u8BA1\u6570\u63A5\u53E3\u4E0D\u53EF\u7528\u65F6\u7528\u4E8E\u5206\u9875\u5B9E\u63A2\uFF09" },
|
|
5076
|
+
maxPages: { type: "integer", minimum: 1, maximum: 20, description: "\u6700\u591A\u7FFB\u9875\u6570\uFF0C\u9ED8\u8BA4 5" }
|
|
5077
|
+
}),
|
|
5078
|
+
handler: async (args, env) => {
|
|
5079
|
+
if (!env.recruitContext) {
|
|
5080
|
+
throw ehrValidationError("recruit_context_unavailable", "\u62DB\u8058\u4E0A\u4E0B\u6587\u52A0\u8F7D\u5668\u672A\u521D\u59CB\u5316");
|
|
5081
|
+
}
|
|
5082
|
+
const requested = args.modules === void 0 ? DEFAULT_MODULES : Array.isArray(args.modules) ? args.modules.map(String) : [];
|
|
5083
|
+
if (!requested.length) {
|
|
5084
|
+
throw ehrValidationError("modules_required", `modules \u5FC5\u987B\u662F\u975E\u7A7A\u6570\u7EC4\uFF0C\u53EF\u9009\u503C\uFF1A${Object.keys(STATS_MODULES).join(" / ")}`);
|
|
5085
|
+
}
|
|
5086
|
+
for (const key of requested) {
|
|
5087
|
+
if (!STATS_MODULES[key]) {
|
|
5088
|
+
throw ehrValidationError("enum_invalid", `modules \u542B\u4E0D\u652F\u6301\u7684\u503C\uFF1A${key}\uFF08\u53EF\u9009 ${Object.keys(STATS_MODULES).join(" / ")}\uFF09`);
|
|
5089
|
+
}
|
|
5090
|
+
}
|
|
5091
|
+
const pageSize = Number.isInteger(args.pageSize) ? Number(args.pageSize) : 100;
|
|
5092
|
+
const maxPages = Number.isInteger(args.maxPages) ? Number(args.maxPages) : 5;
|
|
5093
|
+
const cache = await env.recruitContext.load(env.host);
|
|
5094
|
+
const modules = await Promise.all(
|
|
5095
|
+
requested.map((key) => countModule(env, cache, key, pageSize, maxPages))
|
|
5096
|
+
);
|
|
5097
|
+
const known = modules.filter((m) => m.available && m.total !== null);
|
|
5098
|
+
const unknown = modules.filter((m) => m.available && m.total === null);
|
|
5099
|
+
const unavailable = modules.filter((m) => !m.available);
|
|
5100
|
+
return ehrSuccess("ehr.recruit.stats", {
|
|
5101
|
+
modules,
|
|
5102
|
+
summary: {
|
|
5103
|
+
knownTotal: known.reduce((sum, m) => sum + m.total, 0),
|
|
5104
|
+
knownModules: known.map((m) => m.key),
|
|
5105
|
+
unknownModules: unknown.map((m) => m.key),
|
|
5106
|
+
unavailableModules: unavailable.map((m) => m.key),
|
|
5107
|
+
note: unknown.length ? "\u5B58\u5728\u603B\u6570\u4E0D\u53EF\u77E5\u7684\u6A21\u5757\uFF08\u89C1\u5BF9\u5E94 note\uFF09\uFF0C\u672A\u8BA1\u5165 knownTotal" : void 0
|
|
5108
|
+
}
|
|
5109
|
+
}, { pageSize, maxPages });
|
|
5110
|
+
}
|
|
5111
|
+
};
|
|
5112
|
+
var recruitStatsOperations = [recruitStats];
|
|
5113
|
+
|
|
5114
|
+
// src/shortcuts/ehr/operations/recruit-position.ts
|
|
5115
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
5116
|
+
var TEXT_KEYS = ["position_name"];
|
|
5117
|
+
var MTEXT_KEYS = ["position_duty", "work_request"];
|
|
5118
|
+
var PERSON_DEFAULT_KEYS = ["recr_principal", "employ_manager"];
|
|
5119
|
+
var REF_COPY_KEYS = [
|
|
5120
|
+
"position_nature",
|
|
5121
|
+
"job_category",
|
|
5122
|
+
"education",
|
|
5123
|
+
"work_years",
|
|
5124
|
+
"work_location",
|
|
5125
|
+
"salary_min",
|
|
5126
|
+
"salary_max",
|
|
5127
|
+
"recruit_flow"
|
|
5128
|
+
];
|
|
5129
|
+
var TEXT_DEFAULTS = { recruit_count: "1", number_of_pay_months: "12" };
|
|
5130
|
+
var OPTION_DEFAULTS = { salary_type: "\u6708\u85AA", recruit_type: "\u793E\u4F1A\u62DB\u8058", status: "\u62DB\u8058\u4E2D" };
|
|
5131
|
+
var SET_FIELDS = [
|
|
5132
|
+
{ arg: "education", key: "education", kind: "dict", label: "\u5B66\u5386\u8981\u6C42\uFF08\u6309\u6570\u636E\u5B57\u5178\u540D\u79F0\uFF09" },
|
|
5133
|
+
{ arg: "workYears", key: "work_years", kind: "dict", label: "\u5DE5\u4F5C\u5E74\u9650\uFF08\u6309\u6570\u636E\u5B57\u5178\u540D\u79F0\uFF09" },
|
|
5134
|
+
{ arg: "jobCategory", key: "job_category", kind: "dict", label: "\u804C\u4F4D\u7C7B\u522B\uFF08\u6309\u6570\u636E\u5B57\u5178\u540D\u79F0\uFF09" },
|
|
5135
|
+
{ arg: "positionNature", key: "position_nature", kind: "dict", label: "\u804C\u4F4D\u5C5E\u6027\uFF08\u6309\u6570\u636E\u5B57\u5178\u540D\u79F0\uFF09" },
|
|
5136
|
+
{ arg: "salaryType", key: "salary_type", kind: "option", label: "\u85AA\u916C\u7C7B\u578B\uFF08\u6708\u85AA/\u5E74\u85AA\u7B49\uFF09" },
|
|
5137
|
+
{ arg: "recruitType", key: "recruit_type", kind: "option", label: "\u62DB\u8058\u65B9\u5F0F\uFF08\u793E\u4F1A\u62DB\u8058/\u6821\u56ED\u62DB\u8058\u7B49\uFF09" },
|
|
5138
|
+
{ arg: "recruitCount", key: "recruit_count", kind: "number", label: "\u62DB\u8058\u4EBA\u6570" },
|
|
5139
|
+
{ arg: "salaryMin", key: "salary_min", kind: "number", label: "\u85AA\u916C\u4E0B\u9650" },
|
|
5140
|
+
{ arg: "salaryMax", key: "salary_max", kind: "number", label: "\u85AA\u916C\u4E0A\u9650" },
|
|
5141
|
+
{ arg: "numberOfPayMonths", key: "number_of_pay_months", kind: "number", label: "\u85AA\u916C\u6708\u6570" },
|
|
5142
|
+
{ arg: "recruitPrincipal", key: "recr_principal", kind: "person", label: "\u62DB\u8058\u8D1F\u8D23\u4EBA\uFF08\u6309\u59D3\u540D\uFF09" },
|
|
5143
|
+
{ arg: "employManager", key: "employ_manager", kind: "person", label: "\u7528\u4EBA\u7ECF\u7406\uFF08\u6309\u59D3\u540D\uFF09" },
|
|
5144
|
+
{ arg: "interviewer", key: "interviewer", kind: "person", label: "\u9762\u8BD5\u5B98\uFF08\u6309\u59D3\u540D\uFF09" },
|
|
5145
|
+
{ arg: "recruitHelper", key: "recr_helper", kind: "person", label: "\u62DB\u8058\u534F\u52A9\u4EBA\uFF08\u6309\u59D3\u540D\uFF09" }
|
|
5146
|
+
];
|
|
5147
|
+
var SET_SCHEMA = Object.fromEntries(
|
|
5148
|
+
SET_FIELDS.map((f) => [f.arg, f.kind === "number" ? { type: "string", description: `${f.label}\uFF08\u6570\u5B57\uFF0C\u6309\u5B57\u7B26\u4E32\u4F20\uFF09` } : { type: "string", description: f.label }])
|
|
5149
|
+
);
|
|
5150
|
+
function fingerprint3(value) {
|
|
5151
|
+
return createHash4("sha256").update(JSON.stringify(value ?? null)).digest("hex").slice(0, 32);
|
|
5152
|
+
}
|
|
5153
|
+
function requireConfirm3(args, action) {
|
|
5154
|
+
if (args.confirm !== true) {
|
|
5155
|
+
throw ehrConfirmationError(action, { hint: "\u91CD\u65B0\u8C03\u7528\u65F6\u4F20\u5165 confirm=true \u4E0E prepare \u8FD4\u56DE\u7684 continuation" });
|
|
5156
|
+
}
|
|
5157
|
+
}
|
|
5158
|
+
async function requireCache(env) {
|
|
5159
|
+
if (!env.recruitContext) throw ehrValidationError("recruit_context_unavailable", "\u62DB\u8058\u4E0A\u4E0B\u6587\u52A0\u8F7D\u5668\u672A\u521D\u59CB\u5316");
|
|
5160
|
+
return env.recruitContext.load(env.host);
|
|
5161
|
+
}
|
|
5162
|
+
async function fetchReferenceDetails(env, cache, objId, formId) {
|
|
5163
|
+
const list = cache.lists.position;
|
|
5164
|
+
if (!list?.listId) return [];
|
|
5165
|
+
try {
|
|
5166
|
+
const body = buildListBody({
|
|
5167
|
+
listId: list.listId,
|
|
5168
|
+
cusMenuId: list.cusMenuId,
|
|
5169
|
+
menuName: list.menuName || "\u62DB\u8058\u804C\u4F4D",
|
|
5170
|
+
title: "\u62DB\u8058\u804C\u4F4D",
|
|
5171
|
+
pageSize: 1
|
|
5172
|
+
});
|
|
5173
|
+
const page = await fetchListRows(env.host, objId, list.listId, body);
|
|
5174
|
+
const row = page.rows[0];
|
|
5175
|
+
const recordId = row?.form_data_id || row?.id;
|
|
5176
|
+
if (!recordId) return [];
|
|
5177
|
+
const record = await getFormDataRecord(env.host, formId, String(recordId), objId);
|
|
5178
|
+
return toSubmitDetails(record.dataDetails);
|
|
5179
|
+
} catch {
|
|
5180
|
+
return [];
|
|
5181
|
+
}
|
|
5182
|
+
}
|
|
5183
|
+
async function buildPositionPlan(env, cache, args) {
|
|
5184
|
+
const form = cache.forms.position_manage;
|
|
5185
|
+
const objId = form?.objId;
|
|
5186
|
+
const formId = form?.formId || objId;
|
|
5187
|
+
if (!objId || !formId) {
|
|
5188
|
+
throw ehrValidationError(
|
|
5189
|
+
"position_form_unavailable",
|
|
5190
|
+
"\u5F53\u524D\u73AF\u5883\u672A\u542F\u7528\u300C\u62DB\u8058\u804C\u4F4D\u300D\u529F\u80FD\uFF08\u672A\u89E3\u6790\u5230 position_manage \u8868\u5355\uFF09\uFF0C\u65E0\u6CD5\u5EFA\u804C\u4F4D"
|
|
5191
|
+
);
|
|
5192
|
+
}
|
|
5193
|
+
const fields = cache.fields[objId] || {};
|
|
5194
|
+
const fid = (key) => fields[key];
|
|
5195
|
+
for (const key of [...TEXT_KEYS, ...MTEXT_KEYS]) {
|
|
5196
|
+
if (!fid(key)) {
|
|
5197
|
+
throw ehrValidationError("recruit_field_missing", `\u804C\u4F4D\u7BA1\u7406\u7F3A\u5C11\u5B57\u6BB5 ${key}\uFF08ds/fields \u89E3\u6790\u4E0D\u5230\uFF09\uFF0C\u65E0\u6CD5\u5EFA\u804C\u4F4D`);
|
|
5198
|
+
}
|
|
5199
|
+
}
|
|
5200
|
+
const positionName = String(args.positionName ?? "").trim();
|
|
5201
|
+
if (!positionName) throw ehrValidationError("position_name_required", "positionName \u5FC5\u586B");
|
|
5202
|
+
const data = /* @__PURE__ */ new Map();
|
|
5203
|
+
const put = (entry) => {
|
|
5204
|
+
if (entry && entry.formField?.id) data.set(String(entry.formField.id), entry);
|
|
5205
|
+
};
|
|
5206
|
+
const has = (key) => {
|
|
5207
|
+
const id = fid(key);
|
|
5208
|
+
return !!(id && data.has(String(id)));
|
|
5209
|
+
};
|
|
5210
|
+
put({ formField: { id: fid("position_name") }, content: positionName });
|
|
5211
|
+
const duty = typeof args.duty === "string" ? args.duty : "";
|
|
5212
|
+
const requirement = typeof args.requirement === "string" ? args.requirement : "";
|
|
5213
|
+
if (duty && fid("position_duty")) put({ formField: { id: fid("position_duty") }, dataText: { content: duty } });
|
|
5214
|
+
if (requirement && fid("work_request")) put({ formField: { id: fid("work_request") }, dataText: { content: requirement } });
|
|
5215
|
+
const applied = [];
|
|
5216
|
+
const skipped = [];
|
|
5217
|
+
if (args.demandId !== void 0 && args.demandId !== null && args.demandId !== "") {
|
|
5218
|
+
if (!fid("demand")) throw ehrValidationError("recruit_field_missing", "\u804C\u4F4D\u7BA1\u7406\u7F3A\u5C11\u5B57\u6BB5 demand\uFF0C\u65E0\u6CD5\u5173\u8054\u62DB\u8058\u9700\u6C42");
|
|
5219
|
+
const demandId = String(args.demandId).replace(/[^\d]/g, "");
|
|
5220
|
+
if (!demandId) throw ehrValidationError("demand_id_invalid", "demandId \u5FC5\u987B\u662F\u6570\u5B57 ID");
|
|
5221
|
+
put({
|
|
5222
|
+
formField: { id: fid("demand") },
|
|
5223
|
+
dataOptions: [{ optionId: demandId, content: typeof args.demandName === "string" && args.demandName ? args.demandName : demandId }]
|
|
5224
|
+
});
|
|
5225
|
+
applied.push(`demand=${demandId}`);
|
|
5226
|
+
}
|
|
5227
|
+
for (const field of SET_FIELDS) {
|
|
5228
|
+
const raw = args[field.arg];
|
|
5229
|
+
if (raw === void 0 || raw === null || String(raw).trim() === "") continue;
|
|
5230
|
+
const value = String(raw).trim();
|
|
5231
|
+
const fieldId = fid(field.key);
|
|
5232
|
+
if (!fieldId) {
|
|
5233
|
+
skipped.push(`${field.key}\uFF08\u804C\u4F4D\u8868\u5355\u65E0\u8BE5\u5B57\u6BB5\uFF09`);
|
|
5234
|
+
continue;
|
|
5235
|
+
}
|
|
5236
|
+
if (field.kind === "text" || field.kind === "number") {
|
|
5237
|
+
put({ formField: { id: fieldId }, content: value });
|
|
5238
|
+
applied.push(`${field.key}=${value}`);
|
|
5239
|
+
} else if (field.kind === "option") {
|
|
5240
|
+
const options = await getDsOptions(env.host, objId, fieldId, cache.appId);
|
|
5241
|
+
const optionId = options[value];
|
|
5242
|
+
if (!optionId) {
|
|
5243
|
+
skipped.push(`${field.key}=${value}\uFF08\u9009\u9879\u672A\u5339\u914D\uFF1A${Object.keys(options).slice(0, 8).join("/")}\u2026\uFF09`);
|
|
5244
|
+
continue;
|
|
5245
|
+
}
|
|
5246
|
+
put({ formField: { id: fieldId }, dataOptions: [{ optionId: String(optionId), content: value }] });
|
|
5247
|
+
applied.push(`${field.key}=${value}`);
|
|
5248
|
+
} else if (field.kind === "dict") {
|
|
5249
|
+
const ids = cache.dict.by_name[value] || [];
|
|
5250
|
+
const unique = [...new Set(ids.map(String))];
|
|
5251
|
+
if (unique.length !== 1) {
|
|
5252
|
+
skipped.push(`${field.key}=${value}\uFF08\u5B57\u5178${unique.length === 0 ? "\u65E0\u6B64\u9879" : "\u540C\u540D\u591A\u9879\uFF0C\u6B67\u4E49"}\uFF0C\u672A\u5199\u5165\uFF09`);
|
|
5253
|
+
continue;
|
|
5254
|
+
}
|
|
5255
|
+
put({ formField: { id: fieldId }, dataOptions: [{ optionId: unique[0], content: value }] });
|
|
5256
|
+
applied.push(`${field.key}=${value}`);
|
|
5257
|
+
} else {
|
|
5258
|
+
const personId = await resolvePersonId(env.host, fieldId, value);
|
|
5259
|
+
if (!personId) {
|
|
5260
|
+
skipped.push(`${field.key}=${value}\uFF08\u4EBA\u5458\u672A\u5339\u914D\uFF09`);
|
|
5261
|
+
continue;
|
|
5262
|
+
}
|
|
5263
|
+
put({ formField: { id: fieldId }, dataOptions: [{ optionId: String(personId), content: value }] });
|
|
5264
|
+
applied.push(`${field.key}=${value}`);
|
|
5265
|
+
}
|
|
5266
|
+
}
|
|
5267
|
+
for (const [key, name] of Object.entries(OPTION_DEFAULTS)) {
|
|
5268
|
+
const fieldId = fid(key);
|
|
5269
|
+
if (!fieldId || has(key)) continue;
|
|
5270
|
+
const options = await getDsOptions(env.host, objId, fieldId, cache.appId);
|
|
5271
|
+
const optionId = options[name];
|
|
5272
|
+
if (optionId) put({ formField: { id: fieldId }, dataOptions: [{ optionId: String(optionId), content: name }] });
|
|
5273
|
+
}
|
|
5274
|
+
for (const [key, value] of Object.entries(TEXT_DEFAULTS)) {
|
|
5275
|
+
const fieldId = fid(key);
|
|
5276
|
+
if (fieldId && !has(key)) put({ formField: { id: fieldId }, content: value });
|
|
5277
|
+
}
|
|
5278
|
+
const session = await env.host.getSession();
|
|
5279
|
+
for (const key of PERSON_DEFAULT_KEYS) {
|
|
5280
|
+
const fieldId = fid(key);
|
|
5281
|
+
if (fieldId && !has(key) && session.userId) {
|
|
5282
|
+
put({ formField: { id: fieldId }, dataOptions: [{ optionId: session.userId, content: "\u5F53\u524D\u7528\u6237" }] });
|
|
5283
|
+
}
|
|
5284
|
+
}
|
|
5285
|
+
const refDetails = await fetchReferenceDetails(env, cache, objId, formId);
|
|
5286
|
+
const refMap = /* @__PURE__ */ new Map();
|
|
5287
|
+
for (const detail of refDetails) {
|
|
5288
|
+
const id = detail?.formField?.id;
|
|
5289
|
+
if (id) refMap.set(String(id), detail);
|
|
5290
|
+
}
|
|
5291
|
+
const inherited = [];
|
|
5292
|
+
const missingRef = [];
|
|
5293
|
+
for (const key of REF_COPY_KEYS) {
|
|
5294
|
+
const fieldId = fid(key);
|
|
5295
|
+
if (!fieldId || has(key)) continue;
|
|
5296
|
+
const ref = refMap.get(String(fieldId));
|
|
5297
|
+
if (ref) {
|
|
5298
|
+
put(ref);
|
|
5299
|
+
inherited.push(key);
|
|
5300
|
+
} else {
|
|
5301
|
+
missingRef.push(key);
|
|
5302
|
+
}
|
|
5303
|
+
}
|
|
5304
|
+
const inverse = {};
|
|
5305
|
+
for (const [dataKey, fieldId] of Object.entries(fields)) inverse[String(fieldId)] = dataKey;
|
|
5306
|
+
return {
|
|
5307
|
+
objId,
|
|
5308
|
+
formId,
|
|
5309
|
+
dataDetails: [...data.values()],
|
|
5310
|
+
summary: {
|
|
5311
|
+
positionName,
|
|
5312
|
+
dutyLength: duty.length,
|
|
5313
|
+
requirementLength: requirement.length,
|
|
5314
|
+
fieldCount: data.size,
|
|
5315
|
+
filledFields: [...data.keys()].map((id) => inverse[id] || id).sort(),
|
|
5316
|
+
explicitApplied: applied,
|
|
5317
|
+
explicitSkipped: skipped,
|
|
5318
|
+
inheritedFromExistingPosition: inherited,
|
|
5319
|
+
noReferenceValue: missingRef,
|
|
5320
|
+
principalDefault: session.userId ? "\u5F53\u524D\u767B\u5F55\u7528\u6237" : "\u672A\u89E3\u6790\u5230\u5F53\u524D\u7528\u6237"
|
|
5321
|
+
}
|
|
5322
|
+
};
|
|
5323
|
+
}
|
|
5324
|
+
var positionCreatePrepare = {
|
|
5325
|
+
name: "ehr.recruit.position.create.prepare",
|
|
5326
|
+
resource: "recruit",
|
|
5327
|
+
method: "position.create.prepare",
|
|
5328
|
+
action: "ehr.recruit.position.create.prepare",
|
|
5329
|
+
summary: "\u751F\u6210\u804C\u4F4D\u5E76\u5EFA\u5230\u62DB\u8058\u804C\u4F4D\u5217\u8868\u524D\u7684\u786E\u8BA4\u6458\u8981\uFF1A\u89E3\u6790\u804C\u4F4D\u8868\u5355\u5B57\u6BB5\u3001\u5957\u7528\u9ED8\u8BA4\u503C\uFF08\u72B6\u6001/\u6D41\u7A0B/\u8D1F\u8D23\u4EBA/\u5173\u8054\u5B57\u6BB5\uFF09\uFF0C\u4E0D\u5199\u5165\u4EFB\u4F55\u6570\u636E",
|
|
5330
|
+
capability: "recruit",
|
|
5331
|
+
risk: WRITE,
|
|
5332
|
+
requiresConfirmation: true,
|
|
5333
|
+
inputSchema: schemaOf(
|
|
5334
|
+
{
|
|
5335
|
+
positionName: { type: "string", maxLength: 120, description: "\u804C\u4F4D\u540D\u79F0\uFF08\u5FC5\u586B\uFF09" },
|
|
5336
|
+
duty: { type: "string", maxLength: 2e4, description: "\u5C97\u4F4D\u804C\u8D23 / JD \u6B63\u6587\uFF08\u5199\u5165\u804C\u4F4D\u804C\u8D23\u591A\u884C\u6587\u672C\uFF09" },
|
|
5337
|
+
requirement: { type: "string", maxLength: 2e4, description: "\u4EFB\u804C\u8981\u6C42\uFF08\u5199\u5165\u5DE5\u4F5C\u4EFB\u804C\u8981\u6C42\u591A\u884C\u6587\u672C\uFF09" },
|
|
5338
|
+
demandId: { ...SCHEMA_ID, description: "\u5173\u8054\u62DB\u8058\u9700\u6C42 id\uFF08\u53EF\u9009\uFF09" },
|
|
5339
|
+
demandName: { type: "string", maxLength: 200, description: "\u5173\u8054\u9700\u6C42\u540D\u79F0\uFF08\u4EC5\u7528\u4E8E\u6458\u8981\u5C55\u793A\uFF09" },
|
|
5340
|
+
...SET_SCHEMA
|
|
5341
|
+
},
|
|
5342
|
+
{ required: ["positionName"] }
|
|
5343
|
+
),
|
|
5344
|
+
handler: async (args, env) => {
|
|
5345
|
+
const cache = await requireCache(env);
|
|
5346
|
+
const plan = await buildPositionPlan(env, cache, args);
|
|
5347
|
+
const session = await env.host.getSession();
|
|
5348
|
+
const continuation = await env.continuation.issue(
|
|
5349
|
+
{
|
|
5350
|
+
operation: "ehr.recruit.position.create.apply",
|
|
5351
|
+
baseUrl: session.baseUrl,
|
|
5352
|
+
profile: session.profile,
|
|
5353
|
+
userId: session.userId,
|
|
5354
|
+
payload: { objId: plan.objId, formId: plan.formId, positionName: String(args.positionName).trim(), dataDetails: plan.dataDetails },
|
|
5355
|
+
fingerprint: fingerprint3({ objId: plan.objId, dataDetails: plan.dataDetails })
|
|
5356
|
+
},
|
|
5357
|
+
10 * 60 * 1e3
|
|
5358
|
+
);
|
|
5359
|
+
return ehrSuccess("ehr.recruit.position.create.prepare", {
|
|
5360
|
+
status: "AWAITING_CONFIRMATION",
|
|
5361
|
+
preview: { action: "\u751F\u6210\u804C\u4F4DJD\u5E76\u5EFA\u804C\u4F4D\uFF08saveFormData \u2192 addPosition\uFF09", ...plan.summary },
|
|
5362
|
+
willSubmit: { objId: plan.objId, formId: plan.formId, dataDetails: plan.dataDetails },
|
|
5363
|
+
continuation,
|
|
5364
|
+
expiresInSeconds: 600
|
|
5365
|
+
});
|
|
5366
|
+
}
|
|
5367
|
+
};
|
|
5368
|
+
var positionCreateApply = {
|
|
5369
|
+
name: "ehr.recruit.position.create.apply",
|
|
5370
|
+
resource: "recruit",
|
|
5371
|
+
method: "position.create.apply",
|
|
5372
|
+
action: "ehr.recruit.position.create.apply",
|
|
5373
|
+
summary: "\u6267\u884C\u5EFA\u804C\u4F4D\uFF08saveFormData \u2192 addPosition\uFF09\uFF1B\u5FC5\u987B\u5148 prepare \u5E76\u7ECF\u7528\u6237\u660E\u786E\u786E\u8BA4",
|
|
5374
|
+
capability: "recruit",
|
|
5375
|
+
risk: WRITE,
|
|
5376
|
+
requiresConfirmation: true,
|
|
5377
|
+
inputSchema: schemaOf(
|
|
5378
|
+
{
|
|
5379
|
+
positionName: { type: "string", maxLength: 120 },
|
|
5380
|
+
confirm: { const: true },
|
|
5381
|
+
continuation: { type: "string", minLength: 1 }
|
|
5382
|
+
},
|
|
5383
|
+
{ required: ["positionName", "confirm", "continuation"] }
|
|
5384
|
+
),
|
|
5385
|
+
handler: async (args, env) => {
|
|
5386
|
+
requireConfirm3(args, "ehr.recruit.position.create.apply");
|
|
5387
|
+
const lease = await env.continuation.verify(args.continuation, "ehr.recruit.position.create.apply");
|
|
5388
|
+
const session = await env.host.getSession();
|
|
5389
|
+
if (lease.baseUrl !== session.baseUrl || lease.profile !== session.profile || lease.userId !== session.userId) {
|
|
5390
|
+
throw ehrValidationError("context_mismatch", "\u786E\u8BA4\u4E0A\u4E0B\u6587\u5DF2\u53D8\u5316\uFF08\u79DF\u6237\u6216\u767B\u5F55\u8D26\u53F7\u4E0D\u540C\uFF09\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C prepare");
|
|
5391
|
+
}
|
|
5392
|
+
const positionName = String(args.positionName ?? "").trim();
|
|
5393
|
+
const payload = lease.payload || {};
|
|
5394
|
+
if (payload.positionName !== positionName) {
|
|
5395
|
+
throw ehrValidationError("target_changed", "\u804C\u4F4D\u540D\u79F0\u4E0E prepare \u65F6\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C prepare");
|
|
5396
|
+
}
|
|
5397
|
+
const cache = await requireCache(env);
|
|
5398
|
+
const formDataId = await saveFormData(env.host, {
|
|
5399
|
+
appId: cache.appId,
|
|
5400
|
+
formId: String(payload.formId),
|
|
5401
|
+
objId: String(payload.objId),
|
|
5402
|
+
name: `\u804C\u4F4D\u7BA1\u7406-${positionName}`,
|
|
5403
|
+
dataDetails: payload.dataDetails || []
|
|
5404
|
+
});
|
|
5405
|
+
if (!formDataId) {
|
|
5406
|
+
throw ehrValidationError("save_failed", "saveFormData \u672A\u8FD4\u56DE formDataId\uFF0C\u804C\u4F4D\u672A\u521B\u5EFA");
|
|
5407
|
+
}
|
|
5408
|
+
const response = await env.host.request({
|
|
5409
|
+
path: `/api/recruit/position/v2/addPosition?formDataId=${encodeURIComponent(formDataId)}`,
|
|
5410
|
+
method: "POST",
|
|
5411
|
+
operation: "ehr.recruit.position.create.apply"
|
|
5412
|
+
});
|
|
5413
|
+
const data = response?.data || {};
|
|
5414
|
+
const positionPostId = data.positionPostId ? String(data.positionPostId) : "";
|
|
5415
|
+
const created = response?.status !== false && !!positionPostId;
|
|
5416
|
+
const list = cache.lists.position;
|
|
5417
|
+
const baseUrl = session.baseUrl.replace(/\/+$/, "");
|
|
5418
|
+
const cardUrl = `${baseUrl}/sp/ebdfpage/card/0/${payload.objId}/${formDataId}`;
|
|
5419
|
+
const listLocateUrl = list?.listId ? `${baseUrl}/sp/ebdfpage/list/${list.listId}/card/0/${payload.objId}/${formDataId}/${list.listId}?id=${formDataId}&openSource=field&openSourceId=${formDataId}` : null;
|
|
5420
|
+
if (!created) {
|
|
5421
|
+
throw ehrValidationError(
|
|
5422
|
+
"position_create_failed",
|
|
5423
|
+
`\u804C\u4F4D\u8868\u5355\u5DF2\u4FDD\u5B58\uFF08formDataId=${formDataId}\uFF09\uFF0C\u4F46 addPosition \u672A\u8FD4\u56DE\u804C\u4F4D id\uFF1A${response?.msg || "\u672A\u77E5\u539F\u56E0"}\uFF1B\u8BF7\u5230\u804C\u4F4D\u7BA1\u7406\u6838\u5BF9\u540E\u518D\u51B3\u5B9A\u662F\u5426\u91CD\u8BD5`
|
|
5424
|
+
);
|
|
5425
|
+
}
|
|
5426
|
+
return ehrSuccess("ehr.recruit.position.create.apply", {
|
|
5427
|
+
result: "success",
|
|
5428
|
+
formDataId,
|
|
5429
|
+
positionPostId,
|
|
5430
|
+
rpaChecked: data.checkRpa === void 0 ? null : !!data.checkRpa,
|
|
5431
|
+
rpaValidMsg: data.rpaValidMsg || null,
|
|
5432
|
+
positionName,
|
|
5433
|
+
cardUrl,
|
|
5434
|
+
listLocateUrl
|
|
5435
|
+
});
|
|
5436
|
+
}
|
|
5437
|
+
};
|
|
5438
|
+
var recruitPositionOperations = [
|
|
5439
|
+
positionCreatePrepare,
|
|
5440
|
+
positionCreateApply
|
|
5441
|
+
];
|
|
5442
|
+
|
|
5443
|
+
// src/shortcuts/ehr/operations/recruit-candidate-import.ts
|
|
5444
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
5445
|
+
import { readFile as readFile2, stat } from "node:fs/promises";
|
|
5446
|
+
import { basename } from "node:path";
|
|
5447
|
+
var SUB_TABLES = [
|
|
5448
|
+
{
|
|
5449
|
+
table: "rcrt_education_exp",
|
|
5450
|
+
input: "academicInformations",
|
|
5451
|
+
cols: {
|
|
5452
|
+
school: (r) => r.school,
|
|
5453
|
+
edu_major: (r) => r.edu_major ?? r.major,
|
|
5454
|
+
edu_education: (r) => r.edu_education ?? r.education,
|
|
5455
|
+
degree: (r) => r.degree,
|
|
5456
|
+
study_date: (r) => r.study_date ?? joinRange(r.start_date, r.end_date),
|
|
5457
|
+
faculty: (r) => r.faculty,
|
|
5458
|
+
research_direction: (r) => r.research_direction,
|
|
5459
|
+
major_courses: (r) => r.major_courses
|
|
5460
|
+
}
|
|
5461
|
+
},
|
|
5462
|
+
{
|
|
5463
|
+
table: "rcrt_work_exp",
|
|
5464
|
+
input: "jobInformations",
|
|
5465
|
+
cols: {
|
|
5466
|
+
co_name: (r) => r.co_name ?? r.company,
|
|
5467
|
+
work_position: (r) => r.work_position ?? r.position,
|
|
5468
|
+
work_dept: (r) => r.work_dept ?? r.department,
|
|
5469
|
+
work_desc: (r) => r.work_desc ?? r.job_description,
|
|
5470
|
+
resign_cause: (r) => r.resign_cause,
|
|
5471
|
+
start_end_date: (r) => r.start_end_date ?? joinRange(r.start_date, r.end_date) ?? r.work_date,
|
|
5472
|
+
work_type: (r) => r.work_type
|
|
5473
|
+
}
|
|
5474
|
+
},
|
|
5475
|
+
{
|
|
5476
|
+
table: "rcrt_sxjl",
|
|
5477
|
+
input: "internshipExperiences",
|
|
5478
|
+
cols: {
|
|
5479
|
+
sx_co_name: (r) => r.sx_co_name ?? r.company,
|
|
5480
|
+
position_job: (r) => r.position_job ?? r.position,
|
|
5481
|
+
job_description: (r) => r.job_description,
|
|
5482
|
+
entry_time: (r) => r.entry_time,
|
|
5483
|
+
sx_work_type: (r) => r.sx_work_type
|
|
5484
|
+
}
|
|
5485
|
+
},
|
|
5486
|
+
{
|
|
5487
|
+
table: "rcrt_project_exp",
|
|
5488
|
+
input: "projectExperiences",
|
|
5489
|
+
cols: {
|
|
5490
|
+
pj_name: (r) => r.pj_name ?? r.project_name,
|
|
5491
|
+
pj_role: (r) => r.pj_role,
|
|
5492
|
+
pj_duty: (r) => r.pj_duty,
|
|
5493
|
+
pj_introduction: (r) => r.pj_introduction ?? r.project_description,
|
|
5494
|
+
pj_date: (r) => r.pj_date ?? joinRange(r.start_date, r.end_date)
|
|
5495
|
+
}
|
|
5496
|
+
},
|
|
5497
|
+
{
|
|
5498
|
+
table: "rcrt_award_exp",
|
|
5499
|
+
input: "awardExperiences",
|
|
5500
|
+
cols: {
|
|
5501
|
+
award_name: (r) => r.award_name,
|
|
5502
|
+
awarded: (r) => r.awarded,
|
|
5503
|
+
credentials: (r) => r.credentials,
|
|
5504
|
+
award_date: (r) => r.award_date
|
|
5505
|
+
}
|
|
5506
|
+
},
|
|
5507
|
+
{
|
|
5508
|
+
table: "rcrt_language_skill",
|
|
5509
|
+
input: "languageAbilities",
|
|
5510
|
+
cols: {
|
|
5511
|
+
language_type: (r) => r.language_type,
|
|
5512
|
+
mastery: (r) => r.mastery,
|
|
5513
|
+
ls_ability: (r) => r.ls_ability,
|
|
5514
|
+
literacy: (r) => r.literacy
|
|
5515
|
+
}
|
|
5516
|
+
}
|
|
5517
|
+
];
|
|
5518
|
+
var DICT_COLS = /* @__PURE__ */ new Set([
|
|
5519
|
+
"edu_education",
|
|
5520
|
+
"degree",
|
|
5521
|
+
"work_type",
|
|
5522
|
+
"sx_work_type",
|
|
5523
|
+
"mastery",
|
|
5524
|
+
"ls_ability",
|
|
5525
|
+
"literacy"
|
|
5526
|
+
]);
|
|
5527
|
+
function joinRange(start, end) {
|
|
5528
|
+
const s = start === void 0 || start === null ? "" : String(start).trim();
|
|
5529
|
+
const e = end === void 0 || end === null ? "" : String(end).trim();
|
|
5530
|
+
if (!s && !e) return void 0;
|
|
5531
|
+
return `${s},${e}`;
|
|
5532
|
+
}
|
|
5533
|
+
async function resolveSubTableMeta(env, formId) {
|
|
5534
|
+
let data = null;
|
|
5535
|
+
try {
|
|
5536
|
+
const r = await env.host.request({
|
|
5537
|
+
path: `/api/ebuilder/form/form/core/getFormLayout?formId=${encodeURIComponent(formId)}`,
|
|
5538
|
+
method: "GET",
|
|
5539
|
+
operation: "ehr.recruit.candidate.import.prepare"
|
|
5540
|
+
});
|
|
5541
|
+
data = r?.data;
|
|
5542
|
+
} catch {
|
|
5543
|
+
}
|
|
5544
|
+
if (!data) {
|
|
5545
|
+
const r = await env.host.request({
|
|
5546
|
+
path: "/api/ebuilder/form/form/core/getFormLayout",
|
|
5547
|
+
method: "POST",
|
|
5548
|
+
body: { module: "ebuilderform", formId, terminalType: "PC" },
|
|
5549
|
+
operation: "ehr.recruit.candidate.import.prepare"
|
|
5550
|
+
});
|
|
5551
|
+
data = r?.data;
|
|
5552
|
+
}
|
|
5553
|
+
const comps = data?.formLayout?.pageLayouts?.[0]?.comps || [];
|
|
5554
|
+
const out = {};
|
|
5555
|
+
for (const comp of comps) {
|
|
5556
|
+
const cfg = comp?.config || {};
|
|
5557
|
+
if (comp?.type !== "DetailTable" || !cfg.dataKey || !cfg.subFormId) continue;
|
|
5558
|
+
out[String(cfg.dataKey)] = {
|
|
5559
|
+
dataKey: String(cfg.dataKey),
|
|
5560
|
+
subFormId: String(cfg.subFormId),
|
|
5561
|
+
title: String(cfg.title || ""),
|
|
5562
|
+
columns: {}
|
|
5563
|
+
};
|
|
5564
|
+
}
|
|
5565
|
+
for (const comp of comps) {
|
|
5566
|
+
const cfg = comp?.config || {};
|
|
5567
|
+
const subFormId = String(cfg.subFormId || "");
|
|
5568
|
+
if (!subFormId || !cfg.dataKey || !cfg.fieldId) continue;
|
|
5569
|
+
const target = Object.values(out).find((t) => t.subFormId === subFormId);
|
|
5570
|
+
if (!target) continue;
|
|
5571
|
+
const column = {
|
|
5572
|
+
id: String(cfg.fieldId),
|
|
5573
|
+
type: String(comp?.type || ""),
|
|
5574
|
+
title: String(cfg.title || "")
|
|
5575
|
+
};
|
|
5576
|
+
if (cfg.start?.dataKey && cfg.end?.dataKey) {
|
|
5577
|
+
column.startKey = String(cfg.start.dataKey);
|
|
5578
|
+
column.endKey = String(cfg.end.dataKey);
|
|
5579
|
+
}
|
|
5580
|
+
target.columns[String(cfg.dataKey)] = column;
|
|
5581
|
+
}
|
|
5582
|
+
return out;
|
|
5583
|
+
}
|
|
5584
|
+
function makeDictResolver(cache, warnings) {
|
|
5585
|
+
const byId = /* @__PURE__ */ new Map();
|
|
5586
|
+
for (const row of cache.dict?.raw || []) {
|
|
5587
|
+
if (row.option_id && row.selection_name) byId.set(String(row.option_id), String(row.selection_name));
|
|
5588
|
+
}
|
|
5589
|
+
return (value, label) => {
|
|
5590
|
+
const raw = value === void 0 || value === null ? "" : String(value).trim();
|
|
5591
|
+
if (!raw) return "";
|
|
5592
|
+
if (/^\d{6,}$/.test(raw)) {
|
|
5593
|
+
if (byId.has(raw)) return raw;
|
|
5594
|
+
warnings.push(`${label}\uFF1A\u5B57\u5178 id ${raw} \u672A\u5728\u672C\u73AF\u5883\u5B57\u5178\u4E2D\uFF0C\u5DF2\u8DF3\u8FC7`);
|
|
5595
|
+
return "";
|
|
5596
|
+
}
|
|
5597
|
+
const ids = [...new Set((cache.dict?.by_name?.[raw] || []).map(String))];
|
|
5598
|
+
if (ids.length === 1) return ids[0];
|
|
5599
|
+
warnings.push(`${label}\u300C${raw}\u300D${ids.length === 0 ? "\u5728\u5B57\u5178\u4E2D\u4E0D\u5B58\u5728" : "\u547D\u4E2D\u591A\u4E2A\u540C\u540D\u9009\u9879\uFF08\u6B67\u4E49\uFF09"}\uFF0C\u5DF2\u8DF3\u8FC7`);
|
|
5600
|
+
return "";
|
|
5601
|
+
};
|
|
5602
|
+
}
|
|
5603
|
+
function buildSubDetails(structured, meta, nodeOfTable, resolveDict) {
|
|
5604
|
+
const details = {};
|
|
5605
|
+
const stats = {};
|
|
5606
|
+
const nodes = {};
|
|
5607
|
+
const warnings = [];
|
|
5608
|
+
for (const spec of SUB_TABLES) {
|
|
5609
|
+
const sub = meta[spec.table];
|
|
5610
|
+
if (!sub) {
|
|
5611
|
+
stats[spec.table] = 0;
|
|
5612
|
+
continue;
|
|
5613
|
+
}
|
|
5614
|
+
const rows = Array.isArray(structured[spec.input]) ? structured[spec.input] : [];
|
|
5615
|
+
const built = [];
|
|
5616
|
+
for (const row of rows) {
|
|
5617
|
+
if (!row || typeof row !== "object") continue;
|
|
5618
|
+
const out = {};
|
|
5619
|
+
for (const [colKey, pick] of Object.entries(spec.cols)) {
|
|
5620
|
+
const column = sub.columns[colKey];
|
|
5621
|
+
if (!column) continue;
|
|
5622
|
+
let value = pick(row);
|
|
5623
|
+
if (value === void 0 || value === null || String(value).trim() === "") continue;
|
|
5624
|
+
if (DICT_COLS.has(colKey)) {
|
|
5625
|
+
value = resolveDict(value, `${sub.title}.${column.title || colKey}`);
|
|
5626
|
+
if (!value) continue;
|
|
5627
|
+
}
|
|
5628
|
+
if (column.startKey && column.endKey) {
|
|
5629
|
+
const parts = Array.isArray(value) ? value : String(value).split(/[,~]/);
|
|
5630
|
+
const start = String(parts[0] ?? "").trim();
|
|
5631
|
+
const end = String(parts[1] ?? "").trim();
|
|
5632
|
+
if (!start || !end) continue;
|
|
5633
|
+
out[column.startKey] = start;
|
|
5634
|
+
out[column.endKey] = end;
|
|
5635
|
+
continue;
|
|
5636
|
+
}
|
|
5637
|
+
out[colKey] = String(value);
|
|
5638
|
+
}
|
|
5639
|
+
if (Object.keys(out).length > 0) built.push(out);
|
|
5640
|
+
}
|
|
5641
|
+
if (built.length === 0) {
|
|
5642
|
+
stats[spec.table] = 0;
|
|
5643
|
+
continue;
|
|
5644
|
+
}
|
|
5645
|
+
const node = nodeOfTable[sub.subFormId];
|
|
5646
|
+
if (!node) {
|
|
5647
|
+
warnings.push(`\u5B50\u8868\u300C${sub.title || spec.table}\u300D\u5728 getTableMapping \u4E2D\u65E0\u5BF9\u5E94\u8282\u70B9\uFF0C\u672C\u6B21\u4E0D\u5199\u5165\uFF08${built.length} \u884C\uFF09`);
|
|
5648
|
+
stats[spec.table] = 0;
|
|
5649
|
+
continue;
|
|
5650
|
+
}
|
|
5651
|
+
details[node] = built;
|
|
5652
|
+
nodes[spec.table] = node;
|
|
5653
|
+
stats[spec.table] = built.length;
|
|
5654
|
+
}
|
|
5655
|
+
return { details, stats, nodes, warnings };
|
|
5656
|
+
}
|
|
5657
|
+
async function datasetSaveFormData(env, objId, mainTable, details) {
|
|
5658
|
+
const record = { mainTable };
|
|
5659
|
+
for (const [node, rows] of Object.entries(details)) {
|
|
5660
|
+
if (rows.length) record[node] = rows;
|
|
5661
|
+
}
|
|
5662
|
+
const response = await env.host.request({
|
|
5663
|
+
path: "/api/ebuilder/form/dataset/v2/saveFormData",
|
|
5664
|
+
method: "POST",
|
|
5665
|
+
body: {
|
|
5666
|
+
datajson: {
|
|
5667
|
+
datas: [record],
|
|
5668
|
+
header: { objId },
|
|
5669
|
+
operationinfo: { fieldNoFindIgnore: "true", doAction: "false" }
|
|
5670
|
+
}
|
|
5671
|
+
},
|
|
5672
|
+
operation: "ehr.recruit.candidate.import.apply"
|
|
5673
|
+
});
|
|
5674
|
+
const datajson = response?.data?.datajson || {};
|
|
5675
|
+
const code = response?.message?.code;
|
|
5676
|
+
const ok = (code === void 0 || String(code) === "0") && datajson.status !== false;
|
|
5677
|
+
if (!ok) {
|
|
5678
|
+
throw ehrValidationError(
|
|
5679
|
+
"save_failed",
|
|
5680
|
+
`dataset saveFormData \u5931\u8D25\uFF1A${datajson.message || response?.message?.msg || JSON.stringify(response).slice(0, 200)}`
|
|
5681
|
+
);
|
|
5682
|
+
}
|
|
5683
|
+
const ids = Array.isArray(datajson.dataIds) ? datajson.dataIds : [];
|
|
5684
|
+
if (!ids.length) {
|
|
5685
|
+
throw ehrValidationError("save_failed", `dataset saveFormData \u672A\u8FD4\u56DE dataIds\uFF1A${JSON.stringify(response).slice(0, 200)}`);
|
|
5686
|
+
}
|
|
5687
|
+
return String(ids[0]);
|
|
5688
|
+
}
|
|
5689
|
+
async function uploadResumeFile(env, filePath, fieldId, formId) {
|
|
5690
|
+
let buffer;
|
|
5691
|
+
let mtimeMs = Date.now();
|
|
5692
|
+
try {
|
|
5693
|
+
buffer = await readFile2(filePath);
|
|
5694
|
+
mtimeMs = (await stat(filePath)).mtimeMs || Date.now();
|
|
5695
|
+
} catch {
|
|
5696
|
+
throw ehrValidationError("resume_file_unreadable", `\u65E0\u6CD5\u8BFB\u53D6\u7B80\u5386\u6587\u4EF6\uFF1A${filePath}`);
|
|
5697
|
+
}
|
|
5698
|
+
const name = basename(filePath);
|
|
5699
|
+
const size = buffer.length;
|
|
5700
|
+
const baseForm = (withFile) => {
|
|
5701
|
+
const fd2 = new FormData();
|
|
5702
|
+
fd2.append("compressImg", "false");
|
|
5703
|
+
fd2.append("source", "form");
|
|
5704
|
+
fd2.append("fieldId", fieldId);
|
|
5705
|
+
fd2.append("sourceRefId", formId);
|
|
5706
|
+
fd2.append("module", "ebuilderform");
|
|
5707
|
+
fd2.append("authModule", "ebuilderform");
|
|
5708
|
+
fd2.append("formId", formId);
|
|
5709
|
+
fd2.append("refId", formId);
|
|
5710
|
+
fd2.append("size", String(size));
|
|
5711
|
+
fd2.append("commonText", JSON.stringify({ fieldId, formId }));
|
|
5712
|
+
if (withFile) fd2.append("file", new Blob([new Uint8Array(buffer)]), name);
|
|
5713
|
+
return fd2;
|
|
5714
|
+
};
|
|
5715
|
+
const pre = await env.host.request({
|
|
5716
|
+
path: "/api/file/preUploadCheck",
|
|
5717
|
+
method: "POST",
|
|
5718
|
+
multipart: baseForm(true),
|
|
5719
|
+
// 预上传检查必须带文件,否则服务端 500
|
|
5720
|
+
headers: { ebBusinessId: formId, langType: "zh_CN", timeZoneOffset: "-480" },
|
|
5721
|
+
operation: "ehr.recruit.candidate.import.apply"
|
|
5722
|
+
});
|
|
5723
|
+
const preUploadId = pre?.data?.preUploadId;
|
|
5724
|
+
const uploadType = pre?.data?.uploadType || "common";
|
|
5725
|
+
if (!preUploadId) {
|
|
5726
|
+
throw ehrValidationError("resume_preupload_failed", `\u7B80\u5386\u9884\u4E0A\u4F20\u68C0\u67E5\u5931\u8D25\uFF1A${JSON.stringify(pre || {}).slice(0, 200)}`);
|
|
5727
|
+
}
|
|
5728
|
+
const fd = baseForm(false);
|
|
5729
|
+
fd.append("name", name);
|
|
5730
|
+
fd.append("MD5", createHash5("md5").update(buffer).digest("hex"));
|
|
5731
|
+
fd.append("lastModified", String(Math.round(mtimeMs)));
|
|
5732
|
+
fd.append("lastModifiedDate", String(Math.round(mtimeMs)));
|
|
5733
|
+
fd.append("preUploadId", String(preUploadId));
|
|
5734
|
+
fd.append("uploadType", String(uploadType));
|
|
5735
|
+
fd.append("file", new Blob([new Uint8Array(buffer)]), name);
|
|
5736
|
+
const res = await env.host.request({
|
|
5737
|
+
path: "/api/file/module/upload",
|
|
5738
|
+
method: "POST",
|
|
5739
|
+
multipart: fd,
|
|
5740
|
+
headers: { ebBusinessId: formId, langType: "zh_CN", timeZoneOffset: "-480" },
|
|
5741
|
+
operation: "ehr.recruit.candidate.import.apply"
|
|
5742
|
+
});
|
|
5743
|
+
const fileid = res?.data?.fileid || res?.data?.uploadModuleDto?.fileObj?.fileId || res?.data?.fileObj?.fileId;
|
|
5744
|
+
if (!fileid) {
|
|
5745
|
+
throw ehrValidationError("resume_upload_failed", `\u7B80\u5386\u4E0A\u4F20\u672A\u8FD4\u56DE fileid\uFF1A${JSON.stringify(res || {}).slice(0, 200)}`);
|
|
5746
|
+
}
|
|
5747
|
+
return { fileid: String(fileid), name, size };
|
|
5748
|
+
}
|
|
5749
|
+
async function applyPlatformTags(env, talentId, tagNames) {
|
|
5750
|
+
if (!tagNames.length) return { applied: [], skipped: [] };
|
|
5751
|
+
const list = await env.host.request({
|
|
5752
|
+
path: "/api/my/tag/query",
|
|
5753
|
+
method: "POST",
|
|
5754
|
+
body: { tagModules: ["ebuilderform"], current: 1, pageSize: 500 },
|
|
5755
|
+
operation: "ehr.recruit.candidate.import.apply"
|
|
5756
|
+
});
|
|
5757
|
+
const rows = list?.data?.data || list?.data?.list || [];
|
|
5758
|
+
const byName = /* @__PURE__ */ new Map();
|
|
5759
|
+
for (const row of rows) {
|
|
5760
|
+
const name = String(row.name ?? row.tagName ?? "").trim();
|
|
5761
|
+
const id = row.tagId ?? row.id;
|
|
5762
|
+
if (name && id !== void 0 && !byName.has(name)) byName.set(name, { id: String(id), name });
|
|
5763
|
+
}
|
|
5764
|
+
const tags = [];
|
|
5765
|
+
const applied = [];
|
|
5766
|
+
const skipped = [];
|
|
5767
|
+
for (const name of tagNames) {
|
|
5768
|
+
const hit = byName.get(name);
|
|
5769
|
+
if (!hit) {
|
|
5770
|
+
skipped.push(name);
|
|
5771
|
+
continue;
|
|
5772
|
+
}
|
|
5773
|
+
tags.push({ id: hit.id, name: hit.name, type: 0 });
|
|
5774
|
+
applied.push(name);
|
|
5775
|
+
}
|
|
5776
|
+
if (tags.length) {
|
|
5777
|
+
await env.host.request({
|
|
5778
|
+
path: "/api/my/tag/common/batchAddEntityTag",
|
|
5779
|
+
method: "POST",
|
|
5780
|
+
body: { tags, batchDatas: [{ entityId: talentId, module: "ebuilderform" }] },
|
|
5781
|
+
operation: "ehr.recruit.candidate.import.apply"
|
|
5782
|
+
});
|
|
5783
|
+
}
|
|
5784
|
+
return { applied, skipped };
|
|
5785
|
+
}
|
|
5786
|
+
async function requireCache2(env) {
|
|
5787
|
+
if (!env.recruitContext) throw ehrValidationError("recruit_context_unavailable", "\u62DB\u8058\u4E0A\u4E0B\u6587\u52A0\u8F7D\u5668\u672A\u521D\u59CB\u5316");
|
|
5788
|
+
return env.recruitContext.load(env.host);
|
|
5789
|
+
}
|
|
5790
|
+
function str(value) {
|
|
5791
|
+
if (value === void 0 || value === null) return "";
|
|
5792
|
+
return String(value).trim();
|
|
5793
|
+
}
|
|
5794
|
+
async function buildImportPlan(env, cache, args) {
|
|
5795
|
+
const warnings = [];
|
|
5796
|
+
const talent = cache.forms.talent_pool;
|
|
5797
|
+
const objId = talent?.objId;
|
|
5798
|
+
const formId = talent?.formId || objId;
|
|
5799
|
+
if (!objId || !formId) {
|
|
5800
|
+
throw ehrValidationError("talent_form_unavailable", "\u5F53\u524D\u73AF\u5883\u672A\u542F\u7528\u300C\u4EBA\u624D\u5E93\u300D\u529F\u80FD\uFF08\u672A\u89E3\u6790\u5230 talent_pool \u8868\u5355\uFF09");
|
|
5801
|
+
}
|
|
5802
|
+
const fields = cache.fields[objId] || {};
|
|
5803
|
+
const name = str(args.candidateName);
|
|
5804
|
+
const mobile = str(args.telephone);
|
|
5805
|
+
if (!name) throw ehrValidationError("candidate_name_required", "candidateName \u5FC5\u586B");
|
|
5806
|
+
if (!/^\d{6,}$/.test(mobile)) throw ehrValidationError("telephone_invalid", "telephone \u5FC5\u987B\u662F 6 \u4F4D\u4EE5\u4E0A\u6570\u5B57\uFF08\u624B\u673A\u53F7\uFF09");
|
|
5807
|
+
if (!fields.candidate_name || !fields.telephone) {
|
|
5808
|
+
throw ehrValidationError("recruit_field_missing", "\u73AF\u5883\u7F13\u5B58\u7F3A\u4EBA\u624D\u59D3\u540D\u5B57\u6BB5(candidate_name)\u6216\u624B\u673A\u5B57\u6BB5(telephone)");
|
|
5809
|
+
}
|
|
5810
|
+
const resolveDict = makeDictResolver(cache, warnings);
|
|
5811
|
+
const main = {};
|
|
5812
|
+
const putText = (key, value, longText = false) => {
|
|
5813
|
+
if (!fields[key]) return;
|
|
5814
|
+
const text = str(value);
|
|
5815
|
+
if (!text) return;
|
|
5816
|
+
main[key] = text;
|
|
5817
|
+
void longText;
|
|
5818
|
+
};
|
|
5819
|
+
putText("candidate_name", name);
|
|
5820
|
+
putText("telephone", mobile);
|
|
5821
|
+
putText("email", args.email);
|
|
5822
|
+
putText("birthday", args.birthday);
|
|
5823
|
+
putText("age", args.age);
|
|
5824
|
+
putText("college", args.college);
|
|
5825
|
+
putText("graduate_date", args.graduateDate);
|
|
5826
|
+
putText("joinworkdate", args.joinworkdate);
|
|
5827
|
+
putText("intend_position", args.intendPosition);
|
|
5828
|
+
putText("intended_workplace", args.intendedWorkplace);
|
|
5829
|
+
putText("self_desc", args.selfDesc, true);
|
|
5830
|
+
putText("work_ability", args.workAbility, true);
|
|
5831
|
+
for (const [key, inputKey, label] of [
|
|
5832
|
+
["gender", "genderName", "\u6027\u522B"],
|
|
5833
|
+
["highest_degree", "highestDegreeName", "\u6700\u9AD8\u5B66\u5386"]
|
|
5834
|
+
]) {
|
|
5835
|
+
if (!fields[key]) continue;
|
|
5836
|
+
const raw = str(args[inputKey]);
|
|
5837
|
+
if (!raw) continue;
|
|
5838
|
+
const id = resolveDict(raw, label);
|
|
5839
|
+
if (id) main[key] = id;
|
|
5840
|
+
}
|
|
5841
|
+
const channel = str(args.channel);
|
|
5842
|
+
if (channel) {
|
|
5843
|
+
if (!fields.channel) warnings.push("\u4EBA\u624D\u8868\u5355\u65E0\u6E20\u9053\u5B57\u6BB5\uFF0Cchannel \u5DF2\u5FFD\u7565");
|
|
5844
|
+
else {
|
|
5845
|
+
const id = resolveDict(channel, "\u6E20\u9053");
|
|
5846
|
+
if (id) main.channel = id;
|
|
5847
|
+
}
|
|
5848
|
+
}
|
|
5849
|
+
if (fields.is_blacklist) {
|
|
5850
|
+
const noId = resolveDict("\u5426", "\u9ED1\u540D\u5355");
|
|
5851
|
+
if (noId) main.is_blacklist = noId;
|
|
5852
|
+
}
|
|
5853
|
+
let subStats = {};
|
|
5854
|
+
let detailNodes = {};
|
|
5855
|
+
let details = {};
|
|
5856
|
+
try {
|
|
5857
|
+
const mappingResponse = await env.host.request({
|
|
5858
|
+
path: `/api/ebuilder/form/dataset/v1/getTableMapping?objId=${encodeURIComponent(objId)}`,
|
|
5859
|
+
method: "GET",
|
|
5860
|
+
operation: "ehr.recruit.candidate.import.prepare"
|
|
5861
|
+
});
|
|
5862
|
+
const mapping = mappingResponse?.data;
|
|
5863
|
+
if (!mapping?.mainTable) throw new Error("getTableMapping \u672A\u8FD4\u56DE mainTable");
|
|
5864
|
+
const nodeOfTable = {};
|
|
5865
|
+
for (const [node, tableId] of Object.entries(mapping)) {
|
|
5866
|
+
if (node === "mainTable") continue;
|
|
5867
|
+
nodeOfTable[String(tableId)] = node;
|
|
5868
|
+
}
|
|
5869
|
+
const meta = await resolveSubTableMeta(env, formId);
|
|
5870
|
+
const built = buildSubDetails(args, meta, nodeOfTable, resolveDict);
|
|
5871
|
+
details = built.details;
|
|
5872
|
+
subStats = built.stats;
|
|
5873
|
+
detailNodes = built.nodes;
|
|
5874
|
+
warnings.push(...built.warnings);
|
|
5875
|
+
} catch (error) {
|
|
5876
|
+
warnings.push(`\u660E\u7EC6\u8868\u672A\u5199\u5165\uFF1A${error?.message || "\u672A\u77E5\u9519\u8BEF"}\uFF08\u4E3B\u8868\u7167\u5E38\u5EFA\u6863\uFF09`);
|
|
5877
|
+
}
|
|
5878
|
+
const subRowTotal = Object.values(subStats).reduce((sum, n) => sum + n, 0);
|
|
5879
|
+
const summary = {
|
|
5880
|
+
candidateName: name,
|
|
5881
|
+
telephone: mobile,
|
|
5882
|
+
email: str(args.email) || "(\u672A\u586B)",
|
|
5883
|
+
channel: channel || "(\u672A\u6307\u5B9A)",
|
|
5884
|
+
mainFieldCount: Object.keys(main).length,
|
|
5885
|
+
mainFields: Object.keys(main).sort(),
|
|
5886
|
+
subTableRows: subStats,
|
|
5887
|
+
subRowTotal,
|
|
5888
|
+
detailNodes,
|
|
5889
|
+
platformTags: Array.isArray(args.tags) ? args.tags : [],
|
|
5890
|
+
resumeFile: str(args.resumeFile) || "(\u672A\u63D0\u4F9B\u539F\u4EF6)",
|
|
5891
|
+
warnings
|
|
5892
|
+
};
|
|
5893
|
+
return {
|
|
5894
|
+
objId,
|
|
5895
|
+
formId,
|
|
5896
|
+
talentObjId: objId,
|
|
5897
|
+
mainTable: main,
|
|
5898
|
+
details,
|
|
5899
|
+
subStats,
|
|
5900
|
+
detailNodes,
|
|
5901
|
+
warnings,
|
|
5902
|
+
talentName: name,
|
|
5903
|
+
mobile,
|
|
5904
|
+
summary
|
|
5905
|
+
};
|
|
5906
|
+
}
|
|
5907
|
+
var candidateImportPrepare = {
|
|
5908
|
+
name: "ehr.recruit.candidate.import.prepare",
|
|
5909
|
+
resource: "recruit",
|
|
5910
|
+
method: "candidate.import.prepare",
|
|
5911
|
+
action: "ehr.recruit.candidate.import.prepare",
|
|
5912
|
+
summary: "\u7B80\u5386\u5BFC\u5165\u5EFA\u4EBA\u624D\u7684\u786E\u8BA4\u6458\u8981\uFF1A\u624B\u673A\u53F7\u67E5\u91CD + \u4E3B\u8868\u5B57\u6BB5\u6620\u5C04 + 6 \u5F20\u660E\u7EC6\u8868\u884C\u6570 + \u6807\u7B7E\u6838\u9A8C\uFF0C\u4E0D\u5199\u5165\u4EFB\u4F55\u6570\u636E",
|
|
5913
|
+
capability: "recruit",
|
|
5914
|
+
risk: WRITE,
|
|
5915
|
+
requiresConfirmation: true,
|
|
5916
|
+
inputSchema: schemaOf({
|
|
5917
|
+
candidateName: { type: "string", maxLength: 60, description: "\u59D3\u540D\uFF08\u5FC5\u586B\uFF09" },
|
|
5918
|
+
telephone: { type: "string", pattern: "^\\d{6,20}$", description: "\u624B\u673A\u53F7\uFF08\u5FC5\u586B\uFF0C\u67E5\u91CD\u4E3B\u952E\uFF09" },
|
|
5919
|
+
email: { type: "string", maxLength: 120 },
|
|
5920
|
+
genderName: { type: "string", description: "\u6027\u522B\u540D\u79F0\uFF08\u5982 \u7537/\u5973\uFF0C\u6309\u672C\u73AF\u5883\u5B57\u5178\u53CD\u67E5\uFF09" },
|
|
5921
|
+
birthday: { type: "string", description: "\u51FA\u751F\u65E5\u671F YYYY-MM-DD" },
|
|
5922
|
+
age: { type: "string", description: "\u5E74\u9F84" },
|
|
5923
|
+
highestDegreeName: { type: "string", description: "\u6700\u9AD8\u5B66\u5386\u540D\u79F0\uFF08\u5982 \u672C\u79D1/\u7855\u58EB\uFF09" },
|
|
5924
|
+
college: { type: "string", maxLength: 120, description: "\u6BD5\u4E1A\u9662\u6821" },
|
|
5925
|
+
graduateDate: { type: "string", description: "\u6BD5\u4E1A\u65F6\u95F4" },
|
|
5926
|
+
joinworkdate: { type: "string", description: "\u53C2\u52A0\u5DE5\u4F5C\u65E5\u671F" },
|
|
5927
|
+
intendPosition: { type: "string", maxLength: 120, description: "\u610F\u5411\u5C97\u4F4D" },
|
|
5928
|
+
intendedWorkplace: { type: "string", maxLength: 120, description: "\u671F\u671B\u5DE5\u4F5C\u5730\u70B9" },
|
|
5929
|
+
selfDesc: { type: "string", maxLength: 2e4, description: "\u81EA\u6211\u8BC4\u4EF7\uFF08\u957F\u6587\u672C\uFF09" },
|
|
5930
|
+
workAbility: { type: "string", maxLength: 2e4, description: "\u804C\u4E1A\u6280\u80FD/\u6280\u672F\u6808\uFF08\u957F\u6587\u672C\uFF09" },
|
|
5931
|
+
channel: { type: "string", maxLength: 60, description: "\u4EBA\u624D\u6765\u6E90\u6E20\u9053\u540D\u79F0\uFF08\u5982 \u667A\u8054\u62DB\u8058/\u5185\u63A8\uFF09" },
|
|
5932
|
+
tags: { type: "array", items: { type: "string" }, maxItems: 20, description: "\u5E73\u53F0\u6807\u7B7E\u540D\u79F0\uFF08\u987B\u4E3A\u672C\u73AF\u5883\u5DF2\u6709\u6807\u7B7E\uFF0C\u540C\u540D\u4F18\u5148\u516C\u5171\uFF1B\u4E0D\u81EA\u52A8\u521B\u5EFA\uFF09" },
|
|
5933
|
+
resumeFile: { type: "string", description: "\u7B80\u5386\u539F\u4EF6\u672C\u5730\u8DEF\u5F84\uFF08\u53EF\u9009\uFF1B\u63D0\u4F9B\u5219\u4E0A\u4F20\u5230\u539F\u59CB\u7B80\u5386\u9644\u4EF6\u5B57\u6BB5\uFF09" },
|
|
5934
|
+
academicInformations: {
|
|
5935
|
+
type: "array",
|
|
5936
|
+
maxItems: 20,
|
|
5937
|
+
description: "\u6559\u80B2\u7ECF\u5386\uFF08school/edu_major/edu_education/degree/study_date/faculty/research_direction/major_courses\uFF09",
|
|
5938
|
+
items: { type: "object" }
|
|
5939
|
+
},
|
|
5940
|
+
jobInformations: {
|
|
5941
|
+
type: "array",
|
|
5942
|
+
maxItems: 30,
|
|
5943
|
+
description: "\u5DE5\u4F5C\u7ECF\u5386\uFF08co_name/work_position/work_dept/work_desc/resign_cause/start_date/end_date/work_type\uFF09",
|
|
5944
|
+
items: { type: "object" }
|
|
5945
|
+
},
|
|
5946
|
+
internshipExperiences: {
|
|
5947
|
+
type: "array",
|
|
5948
|
+
maxItems: 20,
|
|
5949
|
+
description: "\u5B9E\u4E60\u7ECF\u5386\uFF08sx_co_name/position_job/job_description/entry_time/sx_work_type\uFF09",
|
|
5950
|
+
items: { type: "object" }
|
|
5951
|
+
},
|
|
5952
|
+
projectExperiences: {
|
|
5953
|
+
type: "array",
|
|
5954
|
+
maxItems: 30,
|
|
5955
|
+
description: "\u9879\u76EE\u7ECF\u5386\uFF08pj_name/pj_role/pj_duty/pj_introduction/start_date/end_date\uFF09",
|
|
5956
|
+
items: { type: "object" }
|
|
5957
|
+
},
|
|
5958
|
+
awardExperiences: {
|
|
5959
|
+
type: "array",
|
|
5960
|
+
maxItems: 20,
|
|
5961
|
+
description: "\u83B7\u5956\u7ECF\u5386\uFF08award_name/awarded/credentials/award_date\uFF09",
|
|
5962
|
+
items: { type: "object" }
|
|
5963
|
+
},
|
|
5964
|
+
languageAbilities: {
|
|
5965
|
+
type: "array",
|
|
5966
|
+
maxItems: 10,
|
|
5967
|
+
description: "\u8BED\u8A00\u80FD\u529B\uFF08language_type/mastery/ls_ability/literacy\uFF09",
|
|
5968
|
+
items: { type: "object" }
|
|
5969
|
+
}
|
|
5970
|
+
}, { required: ["candidateName", "telephone"] }),
|
|
5971
|
+
handler: async (args, env) => {
|
|
5972
|
+
const cache = await requireCache2(env);
|
|
5973
|
+
const plan = await buildImportPlan(env, cache, args);
|
|
5974
|
+
const dup = await checkDuplicateByMobile(env, cache, plan.mobile);
|
|
5975
|
+
if (dup.length > 1) {
|
|
5976
|
+
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`);
|
|
5977
|
+
}
|
|
5978
|
+
const dupRow = dup[0];
|
|
5979
|
+
const session = await env.host.getSession();
|
|
5980
|
+
const continuation = await env.continuation.issue(
|
|
5981
|
+
{
|
|
5982
|
+
operation: "ehr.recruit.candidate.import.apply",
|
|
5983
|
+
baseUrl: session.baseUrl,
|
|
5984
|
+
profile: session.profile,
|
|
5985
|
+
userId: session.userId,
|
|
5986
|
+
payload: {
|
|
5987
|
+
objId: plan.objId,
|
|
5988
|
+
formId: plan.formId,
|
|
5989
|
+
mainTable: plan.mainTable,
|
|
5990
|
+
details: plan.details,
|
|
5991
|
+
tags: Array.isArray(args.tags) ? args.tags.map(String) : [],
|
|
5992
|
+
resumeFile: str(args.resumeFile),
|
|
5993
|
+
subStats: plan.subStats,
|
|
5994
|
+
warnings: plan.warnings,
|
|
5995
|
+
candidateName: plan.talentName,
|
|
5996
|
+
telephone: plan.mobile
|
|
5997
|
+
}
|
|
5998
|
+
},
|
|
5999
|
+
10 * 60 * 1e3
|
|
6000
|
+
);
|
|
6001
|
+
return ehrSuccess("ehr.recruit.candidate.import.prepare", {
|
|
6002
|
+
status: "AWAITING_CONFIRMATION",
|
|
6003
|
+
preview: {
|
|
6004
|
+
action: "\u7B80\u5386\u5BFC\u5165\u5EFA\u4EBA\u624D\uFF08dataset/v2/saveFormData \u4E3B\u8868+\u660E\u7EC6 \u2192 \u6279\u6B21 \u2192 \u667A\u80FD\u6807\u7B7E \u2192 \u5E73\u53F0\u6807\u7B7E\uFF09",
|
|
6005
|
+
...plan.summary,
|
|
6006
|
+
duplicate: dupRow ? `\u5DF2\u5B58\u5728\u540C\u624B\u673A\u53F7\u4EBA\u624D\u300C${dupRow.candidate_name || dupRow.name || ""}\u300D\uFF08id=${dupRow.form_data_id || dupRow.id}\uFF09\u2192 apply \u5C06\u963B\u65AD` : "\u65E0\u91CD\u590D"
|
|
6007
|
+
},
|
|
6008
|
+
willSubmit: {
|
|
6009
|
+
objId: plan.objId,
|
|
6010
|
+
mainTable: plan.mainTable,
|
|
6011
|
+
details: plan.details,
|
|
6012
|
+
tags: Array.isArray(args.tags) ? args.tags : []
|
|
6013
|
+
},
|
|
6014
|
+
continuation,
|
|
6015
|
+
expiresInSeconds: 600
|
|
6016
|
+
});
|
|
6017
|
+
}
|
|
6018
|
+
};
|
|
6019
|
+
var candidateImportApply = {
|
|
6020
|
+
name: "ehr.recruit.candidate.import.apply",
|
|
6021
|
+
resource: "recruit",
|
|
6022
|
+
method: "candidate.import.apply",
|
|
6023
|
+
action: "ehr.recruit.candidate.import.apply",
|
|
6024
|
+
summary: "\u6267\u884C\u7B80\u5386\u5BFC\u5165\u5EFA\u4EBA\u624D\uFF08\u4E3B\u8868+\u660E\u7EC6 \u2192 \u6279\u6B21 \u2192 \u667A\u80FD\u6807\u7B7E \u2192 \u5E73\u53F0\u6807\u7B7E \u2192 \u53CC\u94FE\u63A5\uFF09\uFF1B\u5FC5\u987B\u5148 prepare \u5E76\u7ECF\u7528\u6237\u660E\u786E\u786E\u8BA4",
|
|
6025
|
+
capability: "recruit",
|
|
6026
|
+
risk: WRITE,
|
|
6027
|
+
requiresConfirmation: true,
|
|
6028
|
+
inputSchema: schemaOf(
|
|
6029
|
+
{
|
|
6030
|
+
candidateName: { type: "string", maxLength: 60 },
|
|
6031
|
+
telephone: { type: "string", pattern: "^\\d{6,20}$" },
|
|
6032
|
+
resumeFile: { type: "string" },
|
|
6033
|
+
tags: { type: "array", items: { type: "string" }, maxItems: 20 },
|
|
6034
|
+
confirm: { const: true },
|
|
6035
|
+
continuation: { type: "string", minLength: 1 }
|
|
6036
|
+
},
|
|
6037
|
+
{ required: ["candidateName", "telephone", "confirm", "continuation"] }
|
|
6038
|
+
),
|
|
6039
|
+
handler: async (args, env) => {
|
|
6040
|
+
if (args.confirm !== true) {
|
|
6041
|
+
throw ehrConfirmationError("ehr.recruit.candidate.import.apply", {
|
|
6042
|
+
hint: "\u91CD\u65B0\u8C03\u7528\u65F6\u4F20\u5165 confirm=true \u4E0E prepare \u8FD4\u56DE\u7684 continuation"
|
|
6043
|
+
});
|
|
6044
|
+
}
|
|
6045
|
+
const lease = await env.continuation.verify(args.continuation, "ehr.recruit.candidate.import.apply");
|
|
6046
|
+
const session = await env.host.getSession();
|
|
6047
|
+
if (lease.baseUrl !== session.baseUrl || lease.profile !== session.profile || lease.userId !== session.userId) {
|
|
6048
|
+
throw ehrValidationError("context_mismatch", "\u786E\u8BA4\u4E0A\u4E0B\u6587\u5DF2\u53D8\u5316\uFF08\u79DF\u6237\u6216\u767B\u5F55\u8D26\u53F7\u4E0D\u540C\uFF09\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C prepare");
|
|
6049
|
+
}
|
|
6050
|
+
const payload = lease.payload || {};
|
|
6051
|
+
if (payload.candidateName !== str(args.candidateName) || payload.telephone !== str(args.telephone)) {
|
|
6052
|
+
throw ehrValidationError("target_changed", "\u59D3\u540D\u6216\u624B\u673A\u53F7\u4E0E prepare \u65F6\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C prepare");
|
|
6053
|
+
}
|
|
6054
|
+
const cache = await requireCache2(env);
|
|
6055
|
+
const objId = String(payload.objId);
|
|
6056
|
+
const formId = String(payload.formId);
|
|
6057
|
+
const fields = cache.fields[objId] || {};
|
|
6058
|
+
const mainTable = { ...payload.mainTable || {} };
|
|
6059
|
+
const resumeFieldKey = "original_resume";
|
|
6060
|
+
const resumeFile = str(payload.resumeFile);
|
|
6061
|
+
let uploaded = null;
|
|
6062
|
+
if (resumeFile) {
|
|
6063
|
+
if (!fields[resumeFieldKey]) {
|
|
6064
|
+
throw ehrValidationError("resume_field_missing", "\u4EBA\u624D\u8868\u5355\u65E0\u300C\u539F\u59CB\u7B80\u5386\u300D\u9644\u4EF6\u5B57\u6BB5\uFF08original_resume\uFF09\uFF0C\u65E0\u6CD5\u4E0A\u4F20\u539F\u4EF6");
|
|
6065
|
+
}
|
|
6066
|
+
uploaded = await uploadResumeFile(env, resumeFile, fields[resumeFieldKey], formId);
|
|
6067
|
+
mainTable[resumeFieldKey] = uploaded.fileid;
|
|
6068
|
+
}
|
|
6069
|
+
let talentId;
|
|
6070
|
+
try {
|
|
6071
|
+
talentId = await datasetSaveFormData(env, objId, mainTable, payload.details || {});
|
|
6072
|
+
} catch (error) {
|
|
6073
|
+
if (error?.subtype === "save_failed") throw error;
|
|
6074
|
+
throw ehrPartialError(
|
|
6075
|
+
`\u7B80\u5386\u5EFA\u6863\u5199\u5165\u7ED3\u679C\u4E0D\u786E\u5B9A\uFF08${error?.message || "\u672A\u77E5\u9519\u8BEF"}\uFF09\uFF1A\u8BF7\u5148\u7528\u4EBA\u624D\u5E93\u641C\u7D22\u624B\u673A\u53F7 ${payload.telephone} \u6838\u5BF9\u662F\u5426\u5DF2\u5EFA\u6863\uFF0C\u7981\u6B62\u76F4\u63A5\u91CD\u8BD5`,
|
|
6076
|
+
{ candidateName: payload.candidateName, telephone: payload.telephone }
|
|
6077
|
+
);
|
|
6078
|
+
}
|
|
6079
|
+
let batchOk = null;
|
|
6080
|
+
let batchNote;
|
|
6081
|
+
try {
|
|
6082
|
+
await env.host.request({
|
|
6083
|
+
path: `/api/recruit/candidate/initTalentBatch?formDataId=${encodeURIComponent(talentId)}`,
|
|
6084
|
+
method: "POST",
|
|
6085
|
+
operation: "ehr.recruit.candidate.import.apply"
|
|
6086
|
+
});
|
|
6087
|
+
batchOk = true;
|
|
6088
|
+
} catch (error) {
|
|
6089
|
+
batchOk = false;
|
|
6090
|
+
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`;
|
|
6091
|
+
}
|
|
6092
|
+
let labelMatch = null;
|
|
6093
|
+
try {
|
|
6094
|
+
const r = await env.host.request({
|
|
6095
|
+
path: `/api/recruit/label/matchTalentLabel?talentId=${encodeURIComponent(talentId)}`,
|
|
6096
|
+
method: "POST",
|
|
6097
|
+
body: {},
|
|
6098
|
+
operation: "ehr.recruit.candidate.import.apply"
|
|
6099
|
+
});
|
|
6100
|
+
labelMatch = r?.data === void 0 ? "TRIGGERED" : String(r.data);
|
|
6101
|
+
} catch {
|
|
6102
|
+
labelMatch = "FAILED\uFF08\u4E0D\u5F71\u54CD\u5EFA\u6863\uFF0C\u53EF\u7A0D\u540E\u5728\u4EBA\u624D\u5361\u7247\u624B\u52A8\u89E6\u53D1\uFF09";
|
|
6103
|
+
}
|
|
6104
|
+
let tagResult = { applied: [], skipped: [] };
|
|
6105
|
+
try {
|
|
6106
|
+
tagResult = await applyPlatformTags(env, talentId, Array.isArray(payload.tags) ? payload.tags.map(String) : []);
|
|
6107
|
+
} catch (error) {
|
|
6108
|
+
tagResult = { applied: [], skipped: Array.isArray(payload.tags) ? payload.tags.map(String) : [] };
|
|
6109
|
+
}
|
|
6110
|
+
const baseUrl = session.baseUrl.replace(/\/+$/, "");
|
|
6111
|
+
const extra = String(cache.selfUse) === "1" ? "&recruitType=useSelf" : "";
|
|
6112
|
+
const talentCardUrl = cache.ebdDetailPageId ? `${baseUrl}/sp/ebdpage/view/${cache.ebdDetailPageId}?talentId=${talentId}${extra}` : null;
|
|
6113
|
+
const talentListId = cache.lists.talent?.listId;
|
|
6114
|
+
const talentListLocateUrl = talentListId ? `${baseUrl}/sp/ebdfpage/list/${talentListId}?talentId=${talentId}${extra}` : null;
|
|
6115
|
+
const warnings = [...payload.warnings || []];
|
|
6116
|
+
if (batchNote) warnings.push(batchNote);
|
|
6117
|
+
return ehrSuccess("ehr.recruit.candidate.import.apply", {
|
|
6118
|
+
result: "success",
|
|
6119
|
+
talentId,
|
|
6120
|
+
candidateName: payload.candidateName,
|
|
6121
|
+
telephone: payload.telephone,
|
|
6122
|
+
mainTableFields: Object.keys(mainTable).length,
|
|
6123
|
+
detailRows: payload.subStats || void 0,
|
|
6124
|
+
attachment: uploaded ? { name: uploaded.name, size: uploaded.size } : null,
|
|
6125
|
+
batch: { ok: batchOk, note: batchNote },
|
|
6126
|
+
labelMatch,
|
|
6127
|
+
tagsApplied: tagResult.applied,
|
|
6128
|
+
tagsSkipped: tagResult.skipped,
|
|
6129
|
+
talentCardUrl,
|
|
6130
|
+
talentListLocateUrl
|
|
6131
|
+
}, warnings.length ? { warnings } : void 0);
|
|
6132
|
+
}
|
|
6133
|
+
};
|
|
6134
|
+
var recruitCandidateImportOperations = [
|
|
6135
|
+
candidateImportPrepare,
|
|
6136
|
+
candidateImportApply
|
|
6137
|
+
];
|
|
6138
|
+
|
|
4825
6139
|
// src/shortcuts/ehr/operations/salary.ts
|
|
4826
6140
|
function requireMonthRange(value, field) {
|
|
4827
6141
|
if (!Array.isArray(value) || value.length === 0) {
|
|
@@ -5003,7 +6317,10 @@ function buildRegistry() {
|
|
|
5003
6317
|
...hrDataSourceOperations,
|
|
5004
6318
|
...hrReportOperations,
|
|
5005
6319
|
...recruitOperations,
|
|
5006
|
-
...recruitWriteOperations
|
|
6320
|
+
...recruitWriteOperations,
|
|
6321
|
+
...recruitStatsOperations,
|
|
6322
|
+
...recruitPositionOperations,
|
|
6323
|
+
...recruitCandidateImportOperations
|
|
5007
6324
|
];
|
|
5008
6325
|
for (const definition of definitions) {
|
|
5009
6326
|
if (registry.has(definition.name)) {
|
|
@@ -5114,7 +6431,7 @@ async function inputFrom(options, extra = {}) {
|
|
|
5114
6431
|
if (opts.input) {
|
|
5115
6432
|
let raw;
|
|
5116
6433
|
try {
|
|
5117
|
-
raw = stripBom(opts.input === "-" ? await readStdin() : await
|
|
6434
|
+
raw = stripBom(opts.input === "-" ? await readStdin() : await readFile3(String(opts.input), "utf8"));
|
|
5118
6435
|
} catch {
|
|
5119
6436
|
throw ehrValidationError("input_unreadable", `\u65E0\u6CD5\u8BFB\u53D6 --input\uFF1A${String(opts.input)}`);
|
|
5120
6437
|
}
|