weaver-work-cli 0.1.32 → 0.1.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/chunks/{archive-UMGX72K6.js → archive-FVFY6GZN.js} +2 -2
- package/dist/chunks/{archive-oa-N2IYBLF3.js → archive-oa-NW3OD4UV.js} +2 -2
- package/dist/chunks/{asset-GLEGKFG5.js → asset-7QJKMIDV.js} +2 -2
- package/dist/chunks/{attachment-content-AQNX5N3S.js → attachment-content-OSAVA6K3.js} +3 -2
- package/dist/chunks/{blog-E44OTVDA.js → blog-I7SDPNW4.js} +2 -2
- package/dist/chunks/{caizhilian-DQUFZXZL.js → caizhilian-O37ZIQNY.js} +2 -2
- package/dist/chunks/{calendar-JKPIRKFD.js → calendar-7KXE4ED3.js} +2 -2
- package/dist/chunks/{chunk-4YC43QQ4.js → chunk-2FLWXFVS.js} +4 -4
- package/dist/chunks/{chunk-QWY6PGL6.js → chunk-2LV74IWP.js} +361 -56
- package/dist/chunks/chunk-3SO6QL6U.js +73 -0
- package/dist/chunks/{chunk-DW6AUUKS.js → chunk-6ATGWRZM.js} +6 -4
- package/dist/chunks/chunk-BYATLLEF.js +68 -0
- package/dist/chunks/chunk-BYBSCN4X.js +932 -0
- package/dist/chunks/{chunk-2GA5ZIQL.js → chunk-D223PTXU.js} +1 -0
- package/dist/chunks/{chunk-H7J4DC5R.js → chunk-EEWPQE3O.js} +2 -2
- package/dist/chunks/{chunk-6RKD4DRZ.js → chunk-GFPXQIY2.js} +2 -2
- package/dist/chunks/{chunk-C6R3B2ML.js → chunk-HEL5XTYI.js} +12 -6
- package/dist/chunks/{chunk-CVZ2JOSW.js → chunk-IHUYP6LO.js} +1 -1
- package/dist/chunks/{chunk-YRVDW4WN.js → chunk-ILMBNVSG.js} +2 -2
- package/dist/chunks/{chunk-G3QJULO2.js → chunk-KAS45KNR.js} +1 -1
- package/dist/chunks/{chunk-H6XSTSLM.js → chunk-MEEFGWTM.js} +54 -196
- package/dist/chunks/{chunk-GCG2NMWR.js → chunk-MQ2I5AA3.js} +4 -2
- package/dist/chunks/chunk-NHA62QD7.js +774 -0
- package/dist/chunks/{chunk-WKI2FBIQ.js → chunk-OCU4RLHC.js} +641 -309
- package/dist/chunks/{chunk-WSKBSQ2U.js → chunk-PRHJGPMA.js} +2 -2
- package/dist/chunks/{chunk-6EFWDL7Y.js → chunk-Q6LWB5HX.js} +2 -2
- package/dist/chunks/{chunk-IURUFGZK.js → chunk-RBGOMK4Y.js} +50 -33
- package/dist/chunks/chunk-VBCFFFGT.js +226 -0
- package/dist/chunks/{ebuilder-form-V5FG2EHC.js → chunk-WRRJ4GG2.js} +22 -1148
- package/dist/chunks/{chunk-E4Z23GHM.js → chunk-WY74UBJ6.js} +264 -750
- package/dist/chunks/conflict-SFNEVJY5.js +21 -0
- package/dist/chunks/continuation-RN6PZN2M.js +11 -0
- package/dist/chunks/cowork-CKWYHXYB.js +2508 -0
- package/dist/chunks/ebuilder-form-KOLJRVZD.js +121 -0
- package/dist/chunks/{ehr-HMFY6VIL.js → ehr-WFOC3B4D.js} +1174 -20
- package/dist/chunks/{esb-ZYSVB7SG.js → esb-LJZTN663.js} +4 -4
- package/dist/chunks/{fna-B7RKPAZD.js → fna-F7QRIIZC.js} +2 -2
- package/dist/chunks/{host-45WED2KK.js → host-BCGUVEWX.js} +3 -3
- package/dist/chunks/host-BQBRHVR3.js +23 -0
- package/dist/chunks/{host-I4Z6BFYX.js → host-DGE2TZD4.js} +3 -3
- package/dist/chunks/{host-KNZ52LJZ.js → host-KXPTEWFS.js} +3 -3
- package/dist/chunks/{host-OCH2BCCV.js → host-VQ6JJXGQ.js} +3 -3
- package/dist/chunks/{hrm-2KAZGUHI.js → hrm-NI6XAKW5.js} +3 -3
- package/dist/chunks/{im-ACJJWH4U.js → im-7TRTF3KT.js} +88 -12
- package/dist/chunks/{invoice-ZK3WCX2U.js → invoice-AOXWJKYT.js} +3 -3
- package/dist/chunks/{jiuchuanhui-5PQD3IL2.js → jiuchuanhui-7NQWEZAW.js} +2 -2
- package/dist/chunks/{lazy-dispatch-JQXBW3GM.js → lazy-dispatch-RNS4EE4S.js} +4 -4
- package/dist/chunks/{mail-S2HDDXO2.js → mail-VDHJAB4O.js} +3 -3
- package/dist/chunks/{meeting-QVN3I37L.js → meeting-GA7XCNNP.js} +214 -43
- package/dist/chunks/{okr-QNG4VC2Q.js → okr-TQIRERPQ.js} +2 -2
- package/dist/chunks/operations-5QL3AECO.js +11 -0
- package/dist/chunks/{plan-A25EMW6U.js → plan-4RY4LN2P.js} +2 -2
- package/dist/chunks/{project-G6XV66DZ.js → project-D6XT2OC5.js} +2 -2
- package/dist/chunks/{registry-DC6KR3NH.js → registry-JHRIDQ3A.js} +4 -4
- package/dist/chunks/{registry-2VLUAESA.js → registry-OZSMDVPP.js} +2 -2
- package/dist/chunks/{registry-TI3CIUXF.js → registry-QKMI43Q6.js} +8 -6
- package/dist/chunks/{registry-7C5UMIPL.js → registry-VOGKFFTR.js} +2 -2
- package/dist/chunks/{room-recommend-WRTHO6Y2.js → room-recommend-D4EUOOWY.js} +4 -3
- package/dist/chunks/{schedule-KFIITGSK.js → schedule-XPFBHPCV.js} +4 -3
- package/dist/chunks/{workflow-DJ7SYWAF.js → workflow-HLBZRWIY.js} +172 -6
- package/dist/index.js +30 -25
- package/dist/internal/e10/auth-recovery.js +14 -4
- package/dist/shortcuts/contract/host.js +34 -59
- package/dist/shortcuts/cowork/continuation.js +70 -0
- package/dist/shortcuts/cowork/errors.js +59 -0
- package/dist/shortcuts/cowork/host.js +172 -0
- package/dist/shortcuts/cowork/index.js +166 -0
- package/dist/shortcuts/cowork/manifest.js +65 -0
- package/dist/shortcuts/cowork/operations/discuss-write.js +277 -0
- package/dist/shortcuts/cowork/operations/item-write.js +380 -0
- package/dist/shortcuts/cowork/operations/member-write.js +283 -0
- package/dist/shortcuts/cowork/operations/permission-write.js +286 -0
- package/dist/shortcuts/cowork/operations/read.js +423 -0
- package/dist/shortcuts/cowork/operations/registry.js +39 -0
- package/dist/shortcuts/cowork/operations/review-write.js +157 -0
- package/dist/shortcuts/cowork/operations/shared.js +215 -0
- package/dist/shortcuts/cowork/operations/types.js +24 -0
- package/dist/shortcuts/cowork/operations.js +19 -0
- package/dist/shortcuts/ehr/host.js +4 -1
- package/dist/shortcuts/ehr/operations/recruit-candidate-import.js +757 -0
- package/dist/shortcuts/ehr/operations/recruit-position.js +367 -0
- package/dist/shortcuts/ehr/operations/recruit-stats.js +133 -0
- package/dist/shortcuts/ehr/operations/recruit-write.js +8 -16
- package/dist/shortcuts/ehr/operations/recruit.js +35 -10
- package/dist/shortcuts/ehr/operations/registry.js +6 -0
- package/dist/shortcuts/im/diagnostics.js +97 -0
- package/dist/shortcuts/im/host.js +58 -31
- package/dist/shortcuts/im/index.js +7 -2
- package/dist/shortcuts/im/operations/at-mention.js +127 -0
- package/dist/shortcuts/im/operations/file-user.js +10 -2
- package/dist/shortcuts/im/operations/group-read.js +26 -5
- package/dist/shortcuts/im/operations/group-write.js +35 -28
- package/dist/shortcuts/im/operations/msg-sync.js +7 -2
- package/dist/shortcuts/im/operations/msg-write.js +76 -10
- package/dist/shortcuts/im/operations/quote-mention.js +119 -0
- package/dist/shortcuts/im/operations/session.js +1 -1
- package/dist/shortcuts/im/operations/shared.js +10 -0
- package/dist/shortcuts/im/operations/types.js +13 -0
- package/dist/shortcuts/index.js +5 -0
- package/dist/shortcuts/mail/host.js +4 -1
- package/dist/shortcuts/meeting/host.js +27 -34
- package/dist/shortcuts/meeting/operations/create.js +4 -1
- package/dist/shortcuts/meeting/operations/eb/catalog.js +5 -0
- package/dist/shortcuts/meeting/operations/eb/conflict.js +78 -7
- package/dist/shortcuts/meeting/operations/eb/create-flow.js +168 -26
- package/dist/shortcuts/meeting/operations/eb/factory.js +69 -1
- package/dist/shortcuts/meeting/operations/eb/index.js +16 -3
- package/dist/shortcuts/meeting/operations/eb/room-recommend.js +14 -3
- package/dist/shortcuts/meeting/operations/eb-fallback.js +159 -0
- package/dist/shortcuts/meeting/operations/env.js +93 -46
- package/dist/shortcuts/meeting/operations/form-fields.js +110 -0
- package/dist/shortcuts/meeting/operations/registry.js +2 -0
- package/dist/shortcuts/meeting/operations/standard-guard.js +71 -0
- package/dist/shortcuts/meeting/operations.js +16 -0
- package/dist/shortcuts/workflow/index.js +110 -1
- package/dist/shortcuts/workflow/operations/form.js +24 -3
- package/dist/shortcuts/workflow/operations/read.js +104 -23
- package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupRules.js +448 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupStore.js +106 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/businessRules.js +47 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +30 -23
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.core.js +1 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.group.js +1 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +2 -1
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +2 -4
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +138 -181
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +12 -7
- package/docs/e10-auth.md +1 -1
- package/docs/im.md +8 -1
- package/docs/todo-smart-convert/README.md +1 -1
- package/docs/todo-smart-convert/data-contract.md +2 -2
- package/docs/todo-smart-convert/subgroup-rules.md +6 -0
- package/package.json +1 -1
- package/skill-template/domains/yimiaoban.md +3 -3
- package/skill-template/skill-template.md +1 -1
- package/skills/weaver-e10-blog/SKILL.md +5 -5
- package/skills/weaver-e10-caizhilian/SKILL.md +5 -5
- package/skills/weaver-e10-calendar/SKILL.md +5 -5
- package/skills/weaver-e10-esb/SKILL.md +5 -5
- package/skills/weaver-e10-hrm/SKILL.md +5 -5
- package/skills/weaver-e10-jinchengda/SKILL.md +2 -2
- package/skills/weaver-e10-jiuchuanhui/SKILL.md +5 -5
- package/skills/weaver-e10-jucailin/SKILL.md +18 -12
- package/skills/weaver-e10-jucailin/references/recruit-create.md +104 -0
- package/skills/weaver-e10-mail/SKILL.md +5 -5
- package/skills/weaver-e10-meeting/SKILL.md +171 -25
- package/skills/weaver-e10-meeting/references/meeting-eb.md +4 -3
- package/skills/weaver-e10-meeting/references/meeting-queries.md +9 -6
- package/skills/weaver-e10-meeting/references/meeting-verification.md +8 -6
- package/skills/weaver-e10-meeting.zip +0 -0
- package/skills/weaver-e10-okr/SKILL.md +5 -5
- package/skills/weaver-e10-okr/references/source-manifest.json +3 -3
- package/skills/weaver-e10-plan/SKILL.md +5 -5
- package/skills/weaver-e10-shared/SKILL.md +12 -12
- package/skills/weaver-e10-shared/references/e10-auth-and-session.md +4 -4
- package/skills/weaver-e10-wenshuding/SKILL.md +5 -5
- package/skills/weaver-e10-workflow/SKILL.md +29 -5
- package/skills/weaver-e10-workflow/aigroup/default.json +88 -0
- package/skills/weaver-e10-workflow/references/todo-smart-convert.md +66 -14
- package/skills/weaver-e10-workflow/references/workflow-agent-entry.md +1 -1
- package/skills/weaver-e10-workflow/references/workflow-memory.md +1 -1
- package/skills/weaver-e10-workflow/references/workflow-query.md +12 -10
- package/skills/weaver-e10-workflow/references/workflow-view.md +2 -2
- package/skills/weaver-e10-workflow/tools/todo-serve.cjs +239 -0
- package/skills/weaver-e10-workflow/{scripts → tools}/todo-summary.cjs +218 -28
- package/skills/weaver-e10-yepiaotong/SKILL.md +10 -8
- package/skills/weaver-e10-yepiaotong/references/invoice-reim.md +7 -7
- package/skills/weaver-e10-yepiaotong/references/reim-api-reference.md +10 -10
- package/skills/weaver-e10-yepiaotong/references/reim-examples.md +40 -37
- package/skills/weaver-e10-yepiaotong/references/reim-expense-subject-rules.md +4 -4
- package/skills/weaver-e10-yepiaotong/references/reim-form-fill-rules.md +27 -38
- package/skills/weaver-e10-yepiaotong/references/reim-phone-subsidy-rules.md +4 -4
- package/skills/weaver-e10-yepiaotong/references/reim-workflow.md +37 -29
- package/skills/weaver-e10-yimiaoban/SKILL.md +156 -33
- package/skills/weaver-e10-yimiaoban/references/ding-write.md +1 -1
- package/skills/weaver-e10-yimiaoban/references/error-codes.md +5 -1
- package/skills/weaver-e10-yimiaoban/references/group-read.md +5 -1
- package/skills/weaver-e10-yimiaoban/references/group-write.md +6 -4
- package/skills/weaver-e10-yimiaoban/references/msg-read.md +1 -0
- package/skills/weaver-e10-yimiaoban/references/msg-write.md +34 -2
- package/skills/weaver-e10-yimiaoban/references/safety-boundaries.md +5 -2
- package/skills/weaver-e10-yimiaoban/references/source-manifest.json +79 -58
- package/skills/weaver-e10-yimiaoban/references/user-remind.md +2 -2
- package/skills/weaver-e10-ziguanjia/SKILL.md +5 -5
|
@@ -4,11 +4,11 @@ import {
|
|
|
4
4
|
E10ApiError,
|
|
5
5
|
createE10RequestRuntime,
|
|
6
6
|
requireE10Session
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-6ATGWRZM.js";
|
|
8
8
|
import {
|
|
9
9
|
E10_SESSION_EXPIRED_MESSAGE,
|
|
10
10
|
getActiveProfile
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-D223PTXU.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,6 +3077,8 @@ 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
|
|
@@ -3364,12 +3382,6 @@ async function resolvePersonId(host, fieldId, keyword) {
|
|
|
3364
3382
|
const first = list[0];
|
|
3365
3383
|
return first ? String(first.id || first.value || "") || null : null;
|
|
3366
3384
|
}
|
|
3367
|
-
async function getInterviewPortalFieldIds(host) {
|
|
3368
|
-
const response = await host.request({
|
|
3369
|
-
path: "/api/recruit/candidate/getFieldIdsForInterview"
|
|
3370
|
-
});
|
|
3371
|
-
return response?.data || {};
|
|
3372
|
-
}
|
|
3373
3385
|
async function saveFormData(host, params) {
|
|
3374
3386
|
const layoutId = params.layoutId || params.formId;
|
|
3375
3387
|
const customParam = {
|
|
@@ -3730,11 +3742,10 @@ async function buildInterviewPlan(env, cache, args) {
|
|
|
3730
3742
|
const objId = cacheObjId(cache, "interview_plan", "\u9762\u8BD5\u8BA1\u5212\u8868\u5355");
|
|
3731
3743
|
const formId = cacheFormId(cache, "interview_plan");
|
|
3732
3744
|
const fields = cache.fields[objId] || {};
|
|
3733
|
-
const
|
|
3734
|
-
const fieldIdOf = (key) => fields[key] || portalFields[key] || "";
|
|
3745
|
+
const fieldIdOf = (key) => fields[key] || "";
|
|
3735
3746
|
for (const key of INTERVIEW_DATAKEYS) {
|
|
3736
3747
|
if (!fieldIdOf(key)) {
|
|
3737
|
-
throw ehrValidationError("recruit_field_missing", `\u9762\u8BD5\u8BA1\u5212\u8868\u5355\u7F3A\u5C11\u5B57\u6BB5 ${key}\
|
|
3748
|
+
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
3749
|
}
|
|
3739
3750
|
}
|
|
3740
3751
|
const typeMap = await getDsOptions(host, objId, fieldIdOf("interview_type"), cache.appId);
|
|
@@ -4822,6 +4833,1146 @@ var recruitWriteOperations = [
|
|
|
4822
4833
|
feedbackUrgeApply
|
|
4823
4834
|
];
|
|
4824
4835
|
|
|
4836
|
+
// src/shortcuts/ehr/operations/recruit-stats.ts
|
|
4837
|
+
var STATS_MODULES = {
|
|
4838
|
+
talent: { listKey: "talent", formType: "talent_pool", title: "\u4EBA\u624D\u5E93" },
|
|
4839
|
+
demand: { listKey: "demand", formType: "demand_manage", title: "\u62DB\u8058\u9700\u6C42" },
|
|
4840
|
+
position: { listKey: "position", formType: "position_manage", title: "\u62DB\u8058\u804C\u4F4D" },
|
|
4841
|
+
entry: { listKey: "entry", formType: "entry_manage", title: "\u5165\u804C\u7BA1\u7406" },
|
|
4842
|
+
offer: { listKey: "offer", formType: "offer", title: "\u5F55\u7528\u7BA1\u7406" },
|
|
4843
|
+
interview: {
|
|
4844
|
+
listKey: "interview",
|
|
4845
|
+
formType: "interview_plan",
|
|
4846
|
+
title: "\u9762\u8BD5\u5B89\u6392",
|
|
4847
|
+
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"
|
|
4848
|
+
}
|
|
4849
|
+
};
|
|
4850
|
+
var DEFAULT_MODULES = ["talent", "demand", "position", "entry", "offer"];
|
|
4851
|
+
async function countModule(env, cache, key, pageSize, maxPages) {
|
|
4852
|
+
const cfg = STATS_MODULES[key];
|
|
4853
|
+
const list = cache.lists[cfg.listKey];
|
|
4854
|
+
const objId = cache.forms[cfg.formType]?.objId;
|
|
4855
|
+
if (!list?.listId || !objId) {
|
|
4856
|
+
return {
|
|
4857
|
+
key,
|
|
4858
|
+
module: cfg.title,
|
|
4859
|
+
available: false,
|
|
4860
|
+
total: null,
|
|
4861
|
+
totalExact: false,
|
|
4862
|
+
scannedRows: 0,
|
|
4863
|
+
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"
|
|
4864
|
+
};
|
|
4865
|
+
}
|
|
4866
|
+
const baseBody = buildListBody({
|
|
4867
|
+
listId: list.listId,
|
|
4868
|
+
cusMenuId: list.cusMenuId,
|
|
4869
|
+
menuName: list.menuName || cfg.title,
|
|
4870
|
+
title: cfg.title,
|
|
4871
|
+
pageSize
|
|
4872
|
+
});
|
|
4873
|
+
let scanned = 0;
|
|
4874
|
+
let total = null;
|
|
4875
|
+
let totalExact = false;
|
|
4876
|
+
let note = cfg.note;
|
|
4877
|
+
for (let current = 1; current <= maxPages; current++) {
|
|
4878
|
+
const page = await fetchListRows(env.host, objId, list.listId, { ...baseBody, current, pageSize });
|
|
4879
|
+
if (current === 1 && page.total !== null && page.totalExact) {
|
|
4880
|
+
total = page.total;
|
|
4881
|
+
totalExact = true;
|
|
4882
|
+
break;
|
|
4883
|
+
}
|
|
4884
|
+
scanned += page.rows.length;
|
|
4885
|
+
if (page.rows.length < pageSize) {
|
|
4886
|
+
total = scanned;
|
|
4887
|
+
totalExact = true;
|
|
4888
|
+
break;
|
|
4889
|
+
}
|
|
4890
|
+
}
|
|
4891
|
+
if (total === null) {
|
|
4892
|
+
totalExact = false;
|
|
4893
|
+
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`;
|
|
4894
|
+
}
|
|
4895
|
+
return { key, module: cfg.title, available: true, total, totalExact, scannedRows: scanned, ...note ? { note } : {} };
|
|
4896
|
+
}
|
|
4897
|
+
var recruitStats = {
|
|
4898
|
+
name: "ehr.recruit.stats",
|
|
4899
|
+
resource: "recruit",
|
|
4900
|
+
method: "stats",
|
|
4901
|
+
action: "ehr.recruit.stats",
|
|
4902
|
+
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"',
|
|
4903
|
+
capability: "recruit",
|
|
4904
|
+
risk: READ,
|
|
4905
|
+
inputSchema: schemaOf({
|
|
4906
|
+
modules: {
|
|
4907
|
+
type: "array",
|
|
4908
|
+
items: { type: "string", enum: Object.keys(STATS_MODULES) },
|
|
4909
|
+
uniqueItems: true,
|
|
4910
|
+
description: `\u8981\u7EDF\u8BA1\u7684\u6A21\u5757\uFF0C\u9ED8\u8BA4 ${DEFAULT_MODULES.join(",")}`
|
|
4911
|
+
},
|
|
4912
|
+
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" },
|
|
4913
|
+
maxPages: { type: "integer", minimum: 1, maximum: 20, description: "\u6700\u591A\u7FFB\u9875\u6570\uFF0C\u9ED8\u8BA4 5" }
|
|
4914
|
+
}),
|
|
4915
|
+
handler: async (args, env) => {
|
|
4916
|
+
if (!env.recruitContext) {
|
|
4917
|
+
throw ehrValidationError("recruit_context_unavailable", "\u62DB\u8058\u4E0A\u4E0B\u6587\u52A0\u8F7D\u5668\u672A\u521D\u59CB\u5316");
|
|
4918
|
+
}
|
|
4919
|
+
const requested = args.modules === void 0 ? DEFAULT_MODULES : Array.isArray(args.modules) ? args.modules.map(String) : [];
|
|
4920
|
+
if (!requested.length) {
|
|
4921
|
+
throw ehrValidationError("modules_required", `modules \u5FC5\u987B\u662F\u975E\u7A7A\u6570\u7EC4\uFF0C\u53EF\u9009\u503C\uFF1A${Object.keys(STATS_MODULES).join(" / ")}`);
|
|
4922
|
+
}
|
|
4923
|
+
for (const key of requested) {
|
|
4924
|
+
if (!STATS_MODULES[key]) {
|
|
4925
|
+
throw ehrValidationError("enum_invalid", `modules \u542B\u4E0D\u652F\u6301\u7684\u503C\uFF1A${key}\uFF08\u53EF\u9009 ${Object.keys(STATS_MODULES).join(" / ")}\uFF09`);
|
|
4926
|
+
}
|
|
4927
|
+
}
|
|
4928
|
+
const pageSize = Number.isInteger(args.pageSize) ? Number(args.pageSize) : 100;
|
|
4929
|
+
const maxPages = Number.isInteger(args.maxPages) ? Number(args.maxPages) : 5;
|
|
4930
|
+
const cache = await env.recruitContext.load(env.host);
|
|
4931
|
+
const modules = await Promise.all(
|
|
4932
|
+
requested.map((key) => countModule(env, cache, key, pageSize, maxPages))
|
|
4933
|
+
);
|
|
4934
|
+
const known = modules.filter((m) => m.available && m.total !== null);
|
|
4935
|
+
const unknown = modules.filter((m) => m.available && m.total === null);
|
|
4936
|
+
const unavailable = modules.filter((m) => !m.available);
|
|
4937
|
+
return ehrSuccess("ehr.recruit.stats", {
|
|
4938
|
+
modules,
|
|
4939
|
+
summary: {
|
|
4940
|
+
knownTotal: known.reduce((sum, m) => sum + m.total, 0),
|
|
4941
|
+
knownModules: known.map((m) => m.key),
|
|
4942
|
+
unknownModules: unknown.map((m) => m.key),
|
|
4943
|
+
unavailableModules: unavailable.map((m) => m.key),
|
|
4944
|
+
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
|
|
4945
|
+
}
|
|
4946
|
+
}, { pageSize, maxPages });
|
|
4947
|
+
}
|
|
4948
|
+
};
|
|
4949
|
+
var recruitStatsOperations = [recruitStats];
|
|
4950
|
+
|
|
4951
|
+
// src/shortcuts/ehr/operations/recruit-position.ts
|
|
4952
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
4953
|
+
var TEXT_KEYS = ["position_name"];
|
|
4954
|
+
var MTEXT_KEYS = ["position_duty", "work_request"];
|
|
4955
|
+
var PERSON_DEFAULT_KEYS = ["recr_principal", "employ_manager"];
|
|
4956
|
+
var REF_COPY_KEYS = [
|
|
4957
|
+
"position_nature",
|
|
4958
|
+
"job_category",
|
|
4959
|
+
"education",
|
|
4960
|
+
"work_years",
|
|
4961
|
+
"work_location",
|
|
4962
|
+
"salary_min",
|
|
4963
|
+
"salary_max",
|
|
4964
|
+
"recruit_flow"
|
|
4965
|
+
];
|
|
4966
|
+
var TEXT_DEFAULTS = { recruit_count: "1", number_of_pay_months: "12" };
|
|
4967
|
+
var OPTION_DEFAULTS = { salary_type: "\u6708\u85AA", recruit_type: "\u793E\u4F1A\u62DB\u8058", status: "\u62DB\u8058\u4E2D" };
|
|
4968
|
+
var SET_FIELDS = [
|
|
4969
|
+
{ arg: "education", key: "education", kind: "dict", label: "\u5B66\u5386\u8981\u6C42\uFF08\u6309\u6570\u636E\u5B57\u5178\u540D\u79F0\uFF09" },
|
|
4970
|
+
{ arg: "workYears", key: "work_years", kind: "dict", label: "\u5DE5\u4F5C\u5E74\u9650\uFF08\u6309\u6570\u636E\u5B57\u5178\u540D\u79F0\uFF09" },
|
|
4971
|
+
{ arg: "jobCategory", key: "job_category", kind: "dict", label: "\u804C\u4F4D\u7C7B\u522B\uFF08\u6309\u6570\u636E\u5B57\u5178\u540D\u79F0\uFF09" },
|
|
4972
|
+
{ arg: "positionNature", key: "position_nature", kind: "dict", label: "\u804C\u4F4D\u5C5E\u6027\uFF08\u6309\u6570\u636E\u5B57\u5178\u540D\u79F0\uFF09" },
|
|
4973
|
+
{ arg: "salaryType", key: "salary_type", kind: "option", label: "\u85AA\u916C\u7C7B\u578B\uFF08\u6708\u85AA/\u5E74\u85AA\u7B49\uFF09" },
|
|
4974
|
+
{ arg: "recruitType", key: "recruit_type", kind: "option", label: "\u62DB\u8058\u65B9\u5F0F\uFF08\u793E\u4F1A\u62DB\u8058/\u6821\u56ED\u62DB\u8058\u7B49\uFF09" },
|
|
4975
|
+
{ arg: "recruitCount", key: "recruit_count", kind: "number", label: "\u62DB\u8058\u4EBA\u6570" },
|
|
4976
|
+
{ arg: "salaryMin", key: "salary_min", kind: "number", label: "\u85AA\u916C\u4E0B\u9650" },
|
|
4977
|
+
{ arg: "salaryMax", key: "salary_max", kind: "number", label: "\u85AA\u916C\u4E0A\u9650" },
|
|
4978
|
+
{ arg: "numberOfPayMonths", key: "number_of_pay_months", kind: "number", label: "\u85AA\u916C\u6708\u6570" },
|
|
4979
|
+
{ arg: "recruitPrincipal", key: "recr_principal", kind: "person", label: "\u62DB\u8058\u8D1F\u8D23\u4EBA\uFF08\u6309\u59D3\u540D\uFF09" },
|
|
4980
|
+
{ arg: "employManager", key: "employ_manager", kind: "person", label: "\u7528\u4EBA\u7ECF\u7406\uFF08\u6309\u59D3\u540D\uFF09" },
|
|
4981
|
+
{ arg: "interviewer", key: "interviewer", kind: "person", label: "\u9762\u8BD5\u5B98\uFF08\u6309\u59D3\u540D\uFF09" },
|
|
4982
|
+
{ arg: "recruitHelper", key: "recr_helper", kind: "person", label: "\u62DB\u8058\u534F\u52A9\u4EBA\uFF08\u6309\u59D3\u540D\uFF09" }
|
|
4983
|
+
];
|
|
4984
|
+
var SET_SCHEMA = Object.fromEntries(
|
|
4985
|
+
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 }])
|
|
4986
|
+
);
|
|
4987
|
+
function fingerprint3(value) {
|
|
4988
|
+
return createHash4("sha256").update(JSON.stringify(value ?? null)).digest("hex").slice(0, 32);
|
|
4989
|
+
}
|
|
4990
|
+
function requireConfirm3(args, action) {
|
|
4991
|
+
if (args.confirm !== true) {
|
|
4992
|
+
throw ehrConfirmationError(action, { hint: "\u91CD\u65B0\u8C03\u7528\u65F6\u4F20\u5165 confirm=true \u4E0E prepare \u8FD4\u56DE\u7684 continuation" });
|
|
4993
|
+
}
|
|
4994
|
+
}
|
|
4995
|
+
async function requireCache(env) {
|
|
4996
|
+
if (!env.recruitContext) throw ehrValidationError("recruit_context_unavailable", "\u62DB\u8058\u4E0A\u4E0B\u6587\u52A0\u8F7D\u5668\u672A\u521D\u59CB\u5316");
|
|
4997
|
+
return env.recruitContext.load(env.host);
|
|
4998
|
+
}
|
|
4999
|
+
async function fetchReferenceDetails(env, cache, objId, formId) {
|
|
5000
|
+
const list = cache.lists.position;
|
|
5001
|
+
if (!list?.listId) return [];
|
|
5002
|
+
try {
|
|
5003
|
+
const body = buildListBody({
|
|
5004
|
+
listId: list.listId,
|
|
5005
|
+
cusMenuId: list.cusMenuId,
|
|
5006
|
+
menuName: list.menuName || "\u62DB\u8058\u804C\u4F4D",
|
|
5007
|
+
title: "\u62DB\u8058\u804C\u4F4D",
|
|
5008
|
+
pageSize: 1
|
|
5009
|
+
});
|
|
5010
|
+
const page = await fetchListRows(env.host, objId, list.listId, body);
|
|
5011
|
+
const row = page.rows[0];
|
|
5012
|
+
const recordId = row?.form_data_id || row?.id;
|
|
5013
|
+
if (!recordId) return [];
|
|
5014
|
+
const record = await getFormDataRecord(env.host, formId, String(recordId), objId);
|
|
5015
|
+
return toSubmitDetails(record.dataDetails);
|
|
5016
|
+
} catch {
|
|
5017
|
+
return [];
|
|
5018
|
+
}
|
|
5019
|
+
}
|
|
5020
|
+
async function buildPositionPlan(env, cache, args) {
|
|
5021
|
+
const form = cache.forms.position_manage;
|
|
5022
|
+
const objId = form?.objId;
|
|
5023
|
+
const formId = form?.formId || objId;
|
|
5024
|
+
if (!objId || !formId) {
|
|
5025
|
+
throw ehrValidationError(
|
|
5026
|
+
"position_form_unavailable",
|
|
5027
|
+
"\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"
|
|
5028
|
+
);
|
|
5029
|
+
}
|
|
5030
|
+
const fields = cache.fields[objId] || {};
|
|
5031
|
+
const fid = (key) => fields[key];
|
|
5032
|
+
for (const key of [...TEXT_KEYS, ...MTEXT_KEYS]) {
|
|
5033
|
+
if (!fid(key)) {
|
|
5034
|
+
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`);
|
|
5035
|
+
}
|
|
5036
|
+
}
|
|
5037
|
+
const positionName = String(args.positionName ?? "").trim();
|
|
5038
|
+
if (!positionName) throw ehrValidationError("position_name_required", "positionName \u5FC5\u586B");
|
|
5039
|
+
const data = /* @__PURE__ */ new Map();
|
|
5040
|
+
const put = (entry) => {
|
|
5041
|
+
if (entry && entry.formField?.id) data.set(String(entry.formField.id), entry);
|
|
5042
|
+
};
|
|
5043
|
+
const has = (key) => {
|
|
5044
|
+
const id = fid(key);
|
|
5045
|
+
return !!(id && data.has(String(id)));
|
|
5046
|
+
};
|
|
5047
|
+
put({ formField: { id: fid("position_name") }, content: positionName });
|
|
5048
|
+
const duty = typeof args.duty === "string" ? args.duty : "";
|
|
5049
|
+
const requirement = typeof args.requirement === "string" ? args.requirement : "";
|
|
5050
|
+
if (duty && fid("position_duty")) put({ formField: { id: fid("position_duty") }, dataText: { content: duty } });
|
|
5051
|
+
if (requirement && fid("work_request")) put({ formField: { id: fid("work_request") }, dataText: { content: requirement } });
|
|
5052
|
+
const applied = [];
|
|
5053
|
+
const skipped = [];
|
|
5054
|
+
if (args.demandId !== void 0 && args.demandId !== null && args.demandId !== "") {
|
|
5055
|
+
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");
|
|
5056
|
+
const demandId = String(args.demandId).replace(/[^\d]/g, "");
|
|
5057
|
+
if (!demandId) throw ehrValidationError("demand_id_invalid", "demandId \u5FC5\u987B\u662F\u6570\u5B57 ID");
|
|
5058
|
+
put({
|
|
5059
|
+
formField: { id: fid("demand") },
|
|
5060
|
+
dataOptions: [{ optionId: demandId, content: typeof args.demandName === "string" && args.demandName ? args.demandName : demandId }]
|
|
5061
|
+
});
|
|
5062
|
+
applied.push(`demand=${demandId}`);
|
|
5063
|
+
}
|
|
5064
|
+
for (const field of SET_FIELDS) {
|
|
5065
|
+
const raw = args[field.arg];
|
|
5066
|
+
if (raw === void 0 || raw === null || String(raw).trim() === "") continue;
|
|
5067
|
+
const value = String(raw).trim();
|
|
5068
|
+
const fieldId = fid(field.key);
|
|
5069
|
+
if (!fieldId) {
|
|
5070
|
+
skipped.push(`${field.key}\uFF08\u804C\u4F4D\u8868\u5355\u65E0\u8BE5\u5B57\u6BB5\uFF09`);
|
|
5071
|
+
continue;
|
|
5072
|
+
}
|
|
5073
|
+
if (field.kind === "text" || field.kind === "number") {
|
|
5074
|
+
put({ formField: { id: fieldId }, content: value });
|
|
5075
|
+
applied.push(`${field.key}=${value}`);
|
|
5076
|
+
} else if (field.kind === "option") {
|
|
5077
|
+
const options = await getDsOptions(env.host, objId, fieldId, cache.appId);
|
|
5078
|
+
const optionId = options[value];
|
|
5079
|
+
if (!optionId) {
|
|
5080
|
+
skipped.push(`${field.key}=${value}\uFF08\u9009\u9879\u672A\u5339\u914D\uFF1A${Object.keys(options).slice(0, 8).join("/")}\u2026\uFF09`);
|
|
5081
|
+
continue;
|
|
5082
|
+
}
|
|
5083
|
+
put({ formField: { id: fieldId }, dataOptions: [{ optionId: String(optionId), content: value }] });
|
|
5084
|
+
applied.push(`${field.key}=${value}`);
|
|
5085
|
+
} else if (field.kind === "dict") {
|
|
5086
|
+
const ids = cache.dict.by_name[value] || [];
|
|
5087
|
+
const unique = [...new Set(ids.map(String))];
|
|
5088
|
+
if (unique.length !== 1) {
|
|
5089
|
+
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`);
|
|
5090
|
+
continue;
|
|
5091
|
+
}
|
|
5092
|
+
put({ formField: { id: fieldId }, dataOptions: [{ optionId: unique[0], content: value }] });
|
|
5093
|
+
applied.push(`${field.key}=${value}`);
|
|
5094
|
+
} else {
|
|
5095
|
+
const personId = await resolvePersonId(env.host, fieldId, value);
|
|
5096
|
+
if (!personId) {
|
|
5097
|
+
skipped.push(`${field.key}=${value}\uFF08\u4EBA\u5458\u672A\u5339\u914D\uFF09`);
|
|
5098
|
+
continue;
|
|
5099
|
+
}
|
|
5100
|
+
put({ formField: { id: fieldId }, dataOptions: [{ optionId: String(personId), content: value }] });
|
|
5101
|
+
applied.push(`${field.key}=${value}`);
|
|
5102
|
+
}
|
|
5103
|
+
}
|
|
5104
|
+
for (const [key, name] of Object.entries(OPTION_DEFAULTS)) {
|
|
5105
|
+
const fieldId = fid(key);
|
|
5106
|
+
if (!fieldId || has(key)) continue;
|
|
5107
|
+
const options = await getDsOptions(env.host, objId, fieldId, cache.appId);
|
|
5108
|
+
const optionId = options[name];
|
|
5109
|
+
if (optionId) put({ formField: { id: fieldId }, dataOptions: [{ optionId: String(optionId), content: name }] });
|
|
5110
|
+
}
|
|
5111
|
+
for (const [key, value] of Object.entries(TEXT_DEFAULTS)) {
|
|
5112
|
+
const fieldId = fid(key);
|
|
5113
|
+
if (fieldId && !has(key)) put({ formField: { id: fieldId }, content: value });
|
|
5114
|
+
}
|
|
5115
|
+
const session = await env.host.getSession();
|
|
5116
|
+
for (const key of PERSON_DEFAULT_KEYS) {
|
|
5117
|
+
const fieldId = fid(key);
|
|
5118
|
+
if (fieldId && !has(key) && session.userId) {
|
|
5119
|
+
put({ formField: { id: fieldId }, dataOptions: [{ optionId: session.userId, content: "\u5F53\u524D\u7528\u6237" }] });
|
|
5120
|
+
}
|
|
5121
|
+
}
|
|
5122
|
+
const refDetails = await fetchReferenceDetails(env, cache, objId, formId);
|
|
5123
|
+
const refMap = /* @__PURE__ */ new Map();
|
|
5124
|
+
for (const detail of refDetails) {
|
|
5125
|
+
const id = detail?.formField?.id;
|
|
5126
|
+
if (id) refMap.set(String(id), detail);
|
|
5127
|
+
}
|
|
5128
|
+
const inherited = [];
|
|
5129
|
+
const missingRef = [];
|
|
5130
|
+
for (const key of REF_COPY_KEYS) {
|
|
5131
|
+
const fieldId = fid(key);
|
|
5132
|
+
if (!fieldId || has(key)) continue;
|
|
5133
|
+
const ref = refMap.get(String(fieldId));
|
|
5134
|
+
if (ref) {
|
|
5135
|
+
put(ref);
|
|
5136
|
+
inherited.push(key);
|
|
5137
|
+
} else {
|
|
5138
|
+
missingRef.push(key);
|
|
5139
|
+
}
|
|
5140
|
+
}
|
|
5141
|
+
const inverse = {};
|
|
5142
|
+
for (const [dataKey, fieldId] of Object.entries(fields)) inverse[String(fieldId)] = dataKey;
|
|
5143
|
+
return {
|
|
5144
|
+
objId,
|
|
5145
|
+
formId,
|
|
5146
|
+
dataDetails: [...data.values()],
|
|
5147
|
+
summary: {
|
|
5148
|
+
positionName,
|
|
5149
|
+
dutyLength: duty.length,
|
|
5150
|
+
requirementLength: requirement.length,
|
|
5151
|
+
fieldCount: data.size,
|
|
5152
|
+
filledFields: [...data.keys()].map((id) => inverse[id] || id).sort(),
|
|
5153
|
+
explicitApplied: applied,
|
|
5154
|
+
explicitSkipped: skipped,
|
|
5155
|
+
inheritedFromExistingPosition: inherited,
|
|
5156
|
+
noReferenceValue: missingRef,
|
|
5157
|
+
principalDefault: session.userId ? "\u5F53\u524D\u767B\u5F55\u7528\u6237" : "\u672A\u89E3\u6790\u5230\u5F53\u524D\u7528\u6237"
|
|
5158
|
+
}
|
|
5159
|
+
};
|
|
5160
|
+
}
|
|
5161
|
+
var positionCreatePrepare = {
|
|
5162
|
+
name: "ehr.recruit.position.create.prepare",
|
|
5163
|
+
resource: "recruit",
|
|
5164
|
+
method: "position.create.prepare",
|
|
5165
|
+
action: "ehr.recruit.position.create.prepare",
|
|
5166
|
+
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",
|
|
5167
|
+
capability: "recruit",
|
|
5168
|
+
risk: WRITE,
|
|
5169
|
+
requiresConfirmation: true,
|
|
5170
|
+
inputSchema: schemaOf(
|
|
5171
|
+
{
|
|
5172
|
+
positionName: { type: "string", maxLength: 120, description: "\u804C\u4F4D\u540D\u79F0\uFF08\u5FC5\u586B\uFF09" },
|
|
5173
|
+
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" },
|
|
5174
|
+
requirement: { type: "string", maxLength: 2e4, description: "\u4EFB\u804C\u8981\u6C42\uFF08\u5199\u5165\u5DE5\u4F5C\u4EFB\u804C\u8981\u6C42\u591A\u884C\u6587\u672C\uFF09" },
|
|
5175
|
+
demandId: { ...SCHEMA_ID, description: "\u5173\u8054\u62DB\u8058\u9700\u6C42 id\uFF08\u53EF\u9009\uFF09" },
|
|
5176
|
+
demandName: { type: "string", maxLength: 200, description: "\u5173\u8054\u9700\u6C42\u540D\u79F0\uFF08\u4EC5\u7528\u4E8E\u6458\u8981\u5C55\u793A\uFF09" },
|
|
5177
|
+
...SET_SCHEMA
|
|
5178
|
+
},
|
|
5179
|
+
{ required: ["positionName"] }
|
|
5180
|
+
),
|
|
5181
|
+
handler: async (args, env) => {
|
|
5182
|
+
const cache = await requireCache(env);
|
|
5183
|
+
const plan = await buildPositionPlan(env, cache, args);
|
|
5184
|
+
const session = await env.host.getSession();
|
|
5185
|
+
const continuation = await env.continuation.issue(
|
|
5186
|
+
{
|
|
5187
|
+
operation: "ehr.recruit.position.create.apply",
|
|
5188
|
+
baseUrl: session.baseUrl,
|
|
5189
|
+
profile: session.profile,
|
|
5190
|
+
userId: session.userId,
|
|
5191
|
+
payload: { objId: plan.objId, formId: plan.formId, positionName: String(args.positionName).trim(), dataDetails: plan.dataDetails },
|
|
5192
|
+
fingerprint: fingerprint3({ objId: plan.objId, dataDetails: plan.dataDetails })
|
|
5193
|
+
},
|
|
5194
|
+
10 * 60 * 1e3
|
|
5195
|
+
);
|
|
5196
|
+
return ehrSuccess("ehr.recruit.position.create.prepare", {
|
|
5197
|
+
status: "AWAITING_CONFIRMATION",
|
|
5198
|
+
preview: { action: "\u751F\u6210\u804C\u4F4DJD\u5E76\u5EFA\u804C\u4F4D\uFF08saveFormData \u2192 addPosition\uFF09", ...plan.summary },
|
|
5199
|
+
willSubmit: { objId: plan.objId, formId: plan.formId, dataDetails: plan.dataDetails },
|
|
5200
|
+
continuation,
|
|
5201
|
+
expiresInSeconds: 600
|
|
5202
|
+
});
|
|
5203
|
+
}
|
|
5204
|
+
};
|
|
5205
|
+
var positionCreateApply = {
|
|
5206
|
+
name: "ehr.recruit.position.create.apply",
|
|
5207
|
+
resource: "recruit",
|
|
5208
|
+
method: "position.create.apply",
|
|
5209
|
+
action: "ehr.recruit.position.create.apply",
|
|
5210
|
+
summary: "\u6267\u884C\u5EFA\u804C\u4F4D\uFF08saveFormData \u2192 addPosition\uFF09\uFF1B\u5FC5\u987B\u5148 prepare \u5E76\u7ECF\u7528\u6237\u660E\u786E\u786E\u8BA4",
|
|
5211
|
+
capability: "recruit",
|
|
5212
|
+
risk: WRITE,
|
|
5213
|
+
requiresConfirmation: true,
|
|
5214
|
+
inputSchema: schemaOf(
|
|
5215
|
+
{
|
|
5216
|
+
positionName: { type: "string", maxLength: 120 },
|
|
5217
|
+
confirm: { const: true },
|
|
5218
|
+
continuation: { type: "string", minLength: 1 }
|
|
5219
|
+
},
|
|
5220
|
+
{ required: ["positionName", "confirm", "continuation"] }
|
|
5221
|
+
),
|
|
5222
|
+
handler: async (args, env) => {
|
|
5223
|
+
requireConfirm3(args, "ehr.recruit.position.create.apply");
|
|
5224
|
+
const lease = await env.continuation.verify(args.continuation, "ehr.recruit.position.create.apply");
|
|
5225
|
+
const session = await env.host.getSession();
|
|
5226
|
+
if (lease.baseUrl !== session.baseUrl || lease.profile !== session.profile || lease.userId !== session.userId) {
|
|
5227
|
+
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");
|
|
5228
|
+
}
|
|
5229
|
+
const positionName = String(args.positionName ?? "").trim();
|
|
5230
|
+
const payload = lease.payload || {};
|
|
5231
|
+
if (payload.positionName !== positionName) {
|
|
5232
|
+
throw ehrValidationError("target_changed", "\u804C\u4F4D\u540D\u79F0\u4E0E prepare \u65F6\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C prepare");
|
|
5233
|
+
}
|
|
5234
|
+
const cache = await requireCache(env);
|
|
5235
|
+
const formDataId = await saveFormData(env.host, {
|
|
5236
|
+
appId: cache.appId,
|
|
5237
|
+
formId: String(payload.formId),
|
|
5238
|
+
objId: String(payload.objId),
|
|
5239
|
+
name: `\u804C\u4F4D\u7BA1\u7406-${positionName}`,
|
|
5240
|
+
dataDetails: payload.dataDetails || []
|
|
5241
|
+
});
|
|
5242
|
+
if (!formDataId) {
|
|
5243
|
+
throw ehrValidationError("save_failed", "saveFormData \u672A\u8FD4\u56DE formDataId\uFF0C\u804C\u4F4D\u672A\u521B\u5EFA");
|
|
5244
|
+
}
|
|
5245
|
+
const response = await env.host.request({
|
|
5246
|
+
path: `/api/recruit/position/v2/addPosition?formDataId=${encodeURIComponent(formDataId)}`,
|
|
5247
|
+
method: "POST",
|
|
5248
|
+
operation: "ehr.recruit.position.create.apply"
|
|
5249
|
+
});
|
|
5250
|
+
const data = response?.data || {};
|
|
5251
|
+
const positionPostId = data.positionPostId ? String(data.positionPostId) : "";
|
|
5252
|
+
const created = response?.status !== false && !!positionPostId;
|
|
5253
|
+
const list = cache.lists.position;
|
|
5254
|
+
const baseUrl = session.baseUrl.replace(/\/+$/, "");
|
|
5255
|
+
const cardUrl = `${baseUrl}/sp/ebdfpage/card/0/${payload.objId}/${formDataId}`;
|
|
5256
|
+
const listLocateUrl = list?.listId ? `${baseUrl}/sp/ebdfpage/list/${list.listId}/card/0/${payload.objId}/${formDataId}/${list.listId}?id=${formDataId}&openSource=field&openSourceId=${formDataId}` : null;
|
|
5257
|
+
if (!created) {
|
|
5258
|
+
throw ehrValidationError(
|
|
5259
|
+
"position_create_failed",
|
|
5260
|
+
`\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`
|
|
5261
|
+
);
|
|
5262
|
+
}
|
|
5263
|
+
return ehrSuccess("ehr.recruit.position.create.apply", {
|
|
5264
|
+
result: "success",
|
|
5265
|
+
formDataId,
|
|
5266
|
+
positionPostId,
|
|
5267
|
+
rpaChecked: data.checkRpa === void 0 ? null : !!data.checkRpa,
|
|
5268
|
+
rpaValidMsg: data.rpaValidMsg || null,
|
|
5269
|
+
positionName,
|
|
5270
|
+
cardUrl,
|
|
5271
|
+
listLocateUrl
|
|
5272
|
+
});
|
|
5273
|
+
}
|
|
5274
|
+
};
|
|
5275
|
+
var recruitPositionOperations = [
|
|
5276
|
+
positionCreatePrepare,
|
|
5277
|
+
positionCreateApply
|
|
5278
|
+
];
|
|
5279
|
+
|
|
5280
|
+
// src/shortcuts/ehr/operations/recruit-candidate-import.ts
|
|
5281
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
5282
|
+
import { readFile as readFile2, stat } from "node:fs/promises";
|
|
5283
|
+
import { basename } from "node:path";
|
|
5284
|
+
var SUB_TABLES = [
|
|
5285
|
+
{
|
|
5286
|
+
table: "rcrt_education_exp",
|
|
5287
|
+
input: "academicInformations",
|
|
5288
|
+
cols: {
|
|
5289
|
+
school: (r) => r.school,
|
|
5290
|
+
edu_major: (r) => r.edu_major ?? r.major,
|
|
5291
|
+
edu_education: (r) => r.edu_education ?? r.education,
|
|
5292
|
+
degree: (r) => r.degree,
|
|
5293
|
+
study_date: (r) => r.study_date ?? joinRange(r.start_date, r.end_date),
|
|
5294
|
+
faculty: (r) => r.faculty,
|
|
5295
|
+
research_direction: (r) => r.research_direction,
|
|
5296
|
+
major_courses: (r) => r.major_courses
|
|
5297
|
+
}
|
|
5298
|
+
},
|
|
5299
|
+
{
|
|
5300
|
+
table: "rcrt_work_exp",
|
|
5301
|
+
input: "jobInformations",
|
|
5302
|
+
cols: {
|
|
5303
|
+
co_name: (r) => r.co_name ?? r.company,
|
|
5304
|
+
work_position: (r) => r.work_position ?? r.position,
|
|
5305
|
+
work_dept: (r) => r.work_dept ?? r.department,
|
|
5306
|
+
work_desc: (r) => r.work_desc ?? r.job_description,
|
|
5307
|
+
resign_cause: (r) => r.resign_cause,
|
|
5308
|
+
start_end_date: (r) => r.start_end_date ?? joinRange(r.start_date, r.end_date) ?? r.work_date,
|
|
5309
|
+
work_type: (r) => r.work_type
|
|
5310
|
+
}
|
|
5311
|
+
},
|
|
5312
|
+
{
|
|
5313
|
+
table: "rcrt_sxjl",
|
|
5314
|
+
input: "internshipExperiences",
|
|
5315
|
+
cols: {
|
|
5316
|
+
sx_co_name: (r) => r.sx_co_name ?? r.company,
|
|
5317
|
+
position_job: (r) => r.position_job ?? r.position,
|
|
5318
|
+
job_description: (r) => r.job_description,
|
|
5319
|
+
entry_time: (r) => r.entry_time,
|
|
5320
|
+
sx_work_type: (r) => r.sx_work_type
|
|
5321
|
+
}
|
|
5322
|
+
},
|
|
5323
|
+
{
|
|
5324
|
+
table: "rcrt_project_exp",
|
|
5325
|
+
input: "projectExperiences",
|
|
5326
|
+
cols: {
|
|
5327
|
+
pj_name: (r) => r.pj_name ?? r.project_name,
|
|
5328
|
+
pj_role: (r) => r.pj_role,
|
|
5329
|
+
pj_duty: (r) => r.pj_duty,
|
|
5330
|
+
pj_introduction: (r) => r.pj_introduction ?? r.project_description,
|
|
5331
|
+
pj_date: (r) => r.pj_date ?? joinRange(r.start_date, r.end_date)
|
|
5332
|
+
}
|
|
5333
|
+
},
|
|
5334
|
+
{
|
|
5335
|
+
table: "rcrt_award_exp",
|
|
5336
|
+
input: "awardExperiences",
|
|
5337
|
+
cols: {
|
|
5338
|
+
award_name: (r) => r.award_name,
|
|
5339
|
+
awarded: (r) => r.awarded,
|
|
5340
|
+
credentials: (r) => r.credentials,
|
|
5341
|
+
award_date: (r) => r.award_date
|
|
5342
|
+
}
|
|
5343
|
+
},
|
|
5344
|
+
{
|
|
5345
|
+
table: "rcrt_language_skill",
|
|
5346
|
+
input: "languageAbilities",
|
|
5347
|
+
cols: {
|
|
5348
|
+
language_type: (r) => r.language_type,
|
|
5349
|
+
mastery: (r) => r.mastery,
|
|
5350
|
+
ls_ability: (r) => r.ls_ability,
|
|
5351
|
+
literacy: (r) => r.literacy
|
|
5352
|
+
}
|
|
5353
|
+
}
|
|
5354
|
+
];
|
|
5355
|
+
var DICT_COLS = /* @__PURE__ */ new Set([
|
|
5356
|
+
"edu_education",
|
|
5357
|
+
"degree",
|
|
5358
|
+
"work_type",
|
|
5359
|
+
"sx_work_type",
|
|
5360
|
+
"mastery",
|
|
5361
|
+
"ls_ability",
|
|
5362
|
+
"literacy"
|
|
5363
|
+
]);
|
|
5364
|
+
function joinRange(start, end) {
|
|
5365
|
+
const s = start === void 0 || start === null ? "" : String(start).trim();
|
|
5366
|
+
const e = end === void 0 || end === null ? "" : String(end).trim();
|
|
5367
|
+
if (!s && !e) return void 0;
|
|
5368
|
+
return `${s},${e}`;
|
|
5369
|
+
}
|
|
5370
|
+
async function resolveSubTableMeta(env, formId) {
|
|
5371
|
+
let data = null;
|
|
5372
|
+
try {
|
|
5373
|
+
const r = await env.host.request({
|
|
5374
|
+
path: `/api/ebuilder/form/form/core/getFormLayout?formId=${encodeURIComponent(formId)}`,
|
|
5375
|
+
method: "GET",
|
|
5376
|
+
operation: "ehr.recruit.candidate.import.prepare"
|
|
5377
|
+
});
|
|
5378
|
+
data = r?.data;
|
|
5379
|
+
} catch {
|
|
5380
|
+
}
|
|
5381
|
+
if (!data) {
|
|
5382
|
+
const r = await env.host.request({
|
|
5383
|
+
path: "/api/ebuilder/form/form/core/getFormLayout",
|
|
5384
|
+
method: "POST",
|
|
5385
|
+
body: { module: "ebuilderform", formId, terminalType: "PC" },
|
|
5386
|
+
operation: "ehr.recruit.candidate.import.prepare"
|
|
5387
|
+
});
|
|
5388
|
+
data = r?.data;
|
|
5389
|
+
}
|
|
5390
|
+
const comps = data?.formLayout?.pageLayouts?.[0]?.comps || [];
|
|
5391
|
+
const out = {};
|
|
5392
|
+
for (const comp of comps) {
|
|
5393
|
+
const cfg = comp?.config || {};
|
|
5394
|
+
if (comp?.type !== "DetailTable" || !cfg.dataKey || !cfg.subFormId) continue;
|
|
5395
|
+
out[String(cfg.dataKey)] = {
|
|
5396
|
+
dataKey: String(cfg.dataKey),
|
|
5397
|
+
subFormId: String(cfg.subFormId),
|
|
5398
|
+
title: String(cfg.title || ""),
|
|
5399
|
+
columns: {}
|
|
5400
|
+
};
|
|
5401
|
+
}
|
|
5402
|
+
for (const comp of comps) {
|
|
5403
|
+
const cfg = comp?.config || {};
|
|
5404
|
+
const subFormId = String(cfg.subFormId || "");
|
|
5405
|
+
if (!subFormId || !cfg.dataKey || !cfg.fieldId) continue;
|
|
5406
|
+
const target = Object.values(out).find((t) => t.subFormId === subFormId);
|
|
5407
|
+
if (!target) continue;
|
|
5408
|
+
const column = {
|
|
5409
|
+
id: String(cfg.fieldId),
|
|
5410
|
+
type: String(comp?.type || ""),
|
|
5411
|
+
title: String(cfg.title || "")
|
|
5412
|
+
};
|
|
5413
|
+
if (cfg.start?.dataKey && cfg.end?.dataKey) {
|
|
5414
|
+
column.startKey = String(cfg.start.dataKey);
|
|
5415
|
+
column.endKey = String(cfg.end.dataKey);
|
|
5416
|
+
}
|
|
5417
|
+
target.columns[String(cfg.dataKey)] = column;
|
|
5418
|
+
}
|
|
5419
|
+
return out;
|
|
5420
|
+
}
|
|
5421
|
+
function makeDictResolver(cache, warnings) {
|
|
5422
|
+
const byId = /* @__PURE__ */ new Map();
|
|
5423
|
+
for (const row of cache.dict?.raw || []) {
|
|
5424
|
+
if (row.option_id && row.selection_name) byId.set(String(row.option_id), String(row.selection_name));
|
|
5425
|
+
}
|
|
5426
|
+
return (value, label) => {
|
|
5427
|
+
const raw = value === void 0 || value === null ? "" : String(value).trim();
|
|
5428
|
+
if (!raw) return "";
|
|
5429
|
+
if (/^\d{6,}$/.test(raw)) {
|
|
5430
|
+
if (byId.has(raw)) return raw;
|
|
5431
|
+
warnings.push(`${label}\uFF1A\u5B57\u5178 id ${raw} \u672A\u5728\u672C\u73AF\u5883\u5B57\u5178\u4E2D\uFF0C\u5DF2\u8DF3\u8FC7`);
|
|
5432
|
+
return "";
|
|
5433
|
+
}
|
|
5434
|
+
const ids = [...new Set((cache.dict?.by_name?.[raw] || []).map(String))];
|
|
5435
|
+
if (ids.length === 1) return ids[0];
|
|
5436
|
+
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`);
|
|
5437
|
+
return "";
|
|
5438
|
+
};
|
|
5439
|
+
}
|
|
5440
|
+
function buildSubDetails(structured, meta, nodeOfTable, resolveDict) {
|
|
5441
|
+
const details = {};
|
|
5442
|
+
const stats = {};
|
|
5443
|
+
const nodes = {};
|
|
5444
|
+
const warnings = [];
|
|
5445
|
+
for (const spec of SUB_TABLES) {
|
|
5446
|
+
const sub = meta[spec.table];
|
|
5447
|
+
if (!sub) {
|
|
5448
|
+
stats[spec.table] = 0;
|
|
5449
|
+
continue;
|
|
5450
|
+
}
|
|
5451
|
+
const rows = Array.isArray(structured[spec.input]) ? structured[spec.input] : [];
|
|
5452
|
+
const built = [];
|
|
5453
|
+
for (const row of rows) {
|
|
5454
|
+
if (!row || typeof row !== "object") continue;
|
|
5455
|
+
const out = {};
|
|
5456
|
+
for (const [colKey, pick] of Object.entries(spec.cols)) {
|
|
5457
|
+
const column = sub.columns[colKey];
|
|
5458
|
+
if (!column) continue;
|
|
5459
|
+
let value = pick(row);
|
|
5460
|
+
if (value === void 0 || value === null || String(value).trim() === "") continue;
|
|
5461
|
+
if (DICT_COLS.has(colKey)) {
|
|
5462
|
+
value = resolveDict(value, `${sub.title}.${column.title || colKey}`);
|
|
5463
|
+
if (!value) continue;
|
|
5464
|
+
}
|
|
5465
|
+
if (column.startKey && column.endKey) {
|
|
5466
|
+
const parts = Array.isArray(value) ? value : String(value).split(/[,~]/);
|
|
5467
|
+
const start = String(parts[0] ?? "").trim();
|
|
5468
|
+
const end = String(parts[1] ?? "").trim();
|
|
5469
|
+
if (!start || !end) continue;
|
|
5470
|
+
out[column.startKey] = start;
|
|
5471
|
+
out[column.endKey] = end;
|
|
5472
|
+
continue;
|
|
5473
|
+
}
|
|
5474
|
+
out[colKey] = String(value);
|
|
5475
|
+
}
|
|
5476
|
+
if (Object.keys(out).length > 0) built.push(out);
|
|
5477
|
+
}
|
|
5478
|
+
if (built.length === 0) {
|
|
5479
|
+
stats[spec.table] = 0;
|
|
5480
|
+
continue;
|
|
5481
|
+
}
|
|
5482
|
+
const node = nodeOfTable[sub.subFormId];
|
|
5483
|
+
if (!node) {
|
|
5484
|
+
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`);
|
|
5485
|
+
stats[spec.table] = 0;
|
|
5486
|
+
continue;
|
|
5487
|
+
}
|
|
5488
|
+
details[node] = built;
|
|
5489
|
+
nodes[spec.table] = node;
|
|
5490
|
+
stats[spec.table] = built.length;
|
|
5491
|
+
}
|
|
5492
|
+
return { details, stats, nodes, warnings };
|
|
5493
|
+
}
|
|
5494
|
+
async function datasetSaveFormData(env, objId, mainTable, details) {
|
|
5495
|
+
const record = { mainTable };
|
|
5496
|
+
for (const [node, rows] of Object.entries(details)) {
|
|
5497
|
+
if (rows.length) record[node] = rows;
|
|
5498
|
+
}
|
|
5499
|
+
const response = await env.host.request({
|
|
5500
|
+
path: "/api/ebuilder/form/dataset/v2/saveFormData",
|
|
5501
|
+
method: "POST",
|
|
5502
|
+
body: {
|
|
5503
|
+
datajson: {
|
|
5504
|
+
datas: [record],
|
|
5505
|
+
header: { objId },
|
|
5506
|
+
operationinfo: { fieldNoFindIgnore: "true", doAction: "false" }
|
|
5507
|
+
}
|
|
5508
|
+
},
|
|
5509
|
+
operation: "ehr.recruit.candidate.import.apply"
|
|
5510
|
+
});
|
|
5511
|
+
const datajson = response?.data?.datajson || {};
|
|
5512
|
+
const code = response?.message?.code;
|
|
5513
|
+
const ok = (code === void 0 || String(code) === "0") && datajson.status !== false;
|
|
5514
|
+
if (!ok) {
|
|
5515
|
+
throw ehrValidationError(
|
|
5516
|
+
"save_failed",
|
|
5517
|
+
`dataset saveFormData \u5931\u8D25\uFF1A${datajson.message || response?.message?.msg || JSON.stringify(response).slice(0, 200)}`
|
|
5518
|
+
);
|
|
5519
|
+
}
|
|
5520
|
+
const ids = Array.isArray(datajson.dataIds) ? datajson.dataIds : [];
|
|
5521
|
+
if (!ids.length) {
|
|
5522
|
+
throw ehrValidationError("save_failed", `dataset saveFormData \u672A\u8FD4\u56DE dataIds\uFF1A${JSON.stringify(response).slice(0, 200)}`);
|
|
5523
|
+
}
|
|
5524
|
+
return String(ids[0]);
|
|
5525
|
+
}
|
|
5526
|
+
async function uploadResumeFile(env, filePath, fieldId, formId) {
|
|
5527
|
+
let buffer;
|
|
5528
|
+
let mtimeMs = Date.now();
|
|
5529
|
+
try {
|
|
5530
|
+
buffer = await readFile2(filePath);
|
|
5531
|
+
mtimeMs = (await stat(filePath)).mtimeMs || Date.now();
|
|
5532
|
+
} catch {
|
|
5533
|
+
throw ehrValidationError("resume_file_unreadable", `\u65E0\u6CD5\u8BFB\u53D6\u7B80\u5386\u6587\u4EF6\uFF1A${filePath}`);
|
|
5534
|
+
}
|
|
5535
|
+
const name = basename(filePath);
|
|
5536
|
+
const size = buffer.length;
|
|
5537
|
+
const baseForm = (withFile) => {
|
|
5538
|
+
const fd2 = new FormData();
|
|
5539
|
+
fd2.append("compressImg", "false");
|
|
5540
|
+
fd2.append("source", "form");
|
|
5541
|
+
fd2.append("fieldId", fieldId);
|
|
5542
|
+
fd2.append("sourceRefId", formId);
|
|
5543
|
+
fd2.append("module", "ebuilderform");
|
|
5544
|
+
fd2.append("authModule", "ebuilderform");
|
|
5545
|
+
fd2.append("formId", formId);
|
|
5546
|
+
fd2.append("refId", formId);
|
|
5547
|
+
fd2.append("size", String(size));
|
|
5548
|
+
fd2.append("commonText", JSON.stringify({ fieldId, formId }));
|
|
5549
|
+
if (withFile) fd2.append("file", new Blob([new Uint8Array(buffer)]), name);
|
|
5550
|
+
return fd2;
|
|
5551
|
+
};
|
|
5552
|
+
const pre = await env.host.request({
|
|
5553
|
+
path: "/api/file/preUploadCheck",
|
|
5554
|
+
method: "POST",
|
|
5555
|
+
multipart: baseForm(true),
|
|
5556
|
+
// 预上传检查必须带文件,否则服务端 500
|
|
5557
|
+
headers: { ebBusinessId: formId, langType: "zh_CN", timeZoneOffset: "-480" },
|
|
5558
|
+
operation: "ehr.recruit.candidate.import.apply"
|
|
5559
|
+
});
|
|
5560
|
+
const preUploadId = pre?.data?.preUploadId;
|
|
5561
|
+
const uploadType = pre?.data?.uploadType || "common";
|
|
5562
|
+
if (!preUploadId) {
|
|
5563
|
+
throw ehrValidationError("resume_preupload_failed", `\u7B80\u5386\u9884\u4E0A\u4F20\u68C0\u67E5\u5931\u8D25\uFF1A${JSON.stringify(pre || {}).slice(0, 200)}`);
|
|
5564
|
+
}
|
|
5565
|
+
const fd = baseForm(false);
|
|
5566
|
+
fd.append("name", name);
|
|
5567
|
+
fd.append("MD5", createHash5("md5").update(buffer).digest("hex"));
|
|
5568
|
+
fd.append("lastModified", String(Math.round(mtimeMs)));
|
|
5569
|
+
fd.append("lastModifiedDate", String(Math.round(mtimeMs)));
|
|
5570
|
+
fd.append("preUploadId", String(preUploadId));
|
|
5571
|
+
fd.append("uploadType", String(uploadType));
|
|
5572
|
+
fd.append("file", new Blob([new Uint8Array(buffer)]), name);
|
|
5573
|
+
const res = await env.host.request({
|
|
5574
|
+
path: "/api/file/module/upload",
|
|
5575
|
+
method: "POST",
|
|
5576
|
+
multipart: fd,
|
|
5577
|
+
headers: { ebBusinessId: formId, langType: "zh_CN", timeZoneOffset: "-480" },
|
|
5578
|
+
operation: "ehr.recruit.candidate.import.apply"
|
|
5579
|
+
});
|
|
5580
|
+
const fileid = res?.data?.fileid || res?.data?.uploadModuleDto?.fileObj?.fileId || res?.data?.fileObj?.fileId;
|
|
5581
|
+
if (!fileid) {
|
|
5582
|
+
throw ehrValidationError("resume_upload_failed", `\u7B80\u5386\u4E0A\u4F20\u672A\u8FD4\u56DE fileid\uFF1A${JSON.stringify(res || {}).slice(0, 200)}`);
|
|
5583
|
+
}
|
|
5584
|
+
return { fileid: String(fileid), name, size };
|
|
5585
|
+
}
|
|
5586
|
+
async function applyPlatformTags(env, talentId, tagNames) {
|
|
5587
|
+
if (!tagNames.length) return { applied: [], skipped: [] };
|
|
5588
|
+
const list = await env.host.request({
|
|
5589
|
+
path: "/api/my/tag/query",
|
|
5590
|
+
method: "POST",
|
|
5591
|
+
body: { tagModules: ["ebuilderform"], current: 1, pageSize: 500 },
|
|
5592
|
+
operation: "ehr.recruit.candidate.import.apply"
|
|
5593
|
+
});
|
|
5594
|
+
const rows = list?.data?.data || list?.data?.list || [];
|
|
5595
|
+
const byName = /* @__PURE__ */ new Map();
|
|
5596
|
+
for (const row of rows) {
|
|
5597
|
+
const name = String(row.name ?? row.tagName ?? "").trim();
|
|
5598
|
+
const id = row.tagId ?? row.id;
|
|
5599
|
+
if (name && id !== void 0 && !byName.has(name)) byName.set(name, { id: String(id), name });
|
|
5600
|
+
}
|
|
5601
|
+
const tags = [];
|
|
5602
|
+
const applied = [];
|
|
5603
|
+
const skipped = [];
|
|
5604
|
+
for (const name of tagNames) {
|
|
5605
|
+
const hit = byName.get(name);
|
|
5606
|
+
if (!hit) {
|
|
5607
|
+
skipped.push(name);
|
|
5608
|
+
continue;
|
|
5609
|
+
}
|
|
5610
|
+
tags.push({ id: hit.id, name: hit.name, type: 0 });
|
|
5611
|
+
applied.push(name);
|
|
5612
|
+
}
|
|
5613
|
+
if (tags.length) {
|
|
5614
|
+
await env.host.request({
|
|
5615
|
+
path: "/api/my/tag/common/batchAddEntityTag",
|
|
5616
|
+
method: "POST",
|
|
5617
|
+
body: { tags, batchDatas: [{ entityId: talentId, module: "ebuilderform" }] },
|
|
5618
|
+
operation: "ehr.recruit.candidate.import.apply"
|
|
5619
|
+
});
|
|
5620
|
+
}
|
|
5621
|
+
return { applied, skipped };
|
|
5622
|
+
}
|
|
5623
|
+
async function requireCache2(env) {
|
|
5624
|
+
if (!env.recruitContext) throw ehrValidationError("recruit_context_unavailable", "\u62DB\u8058\u4E0A\u4E0B\u6587\u52A0\u8F7D\u5668\u672A\u521D\u59CB\u5316");
|
|
5625
|
+
return env.recruitContext.load(env.host);
|
|
5626
|
+
}
|
|
5627
|
+
function str(value) {
|
|
5628
|
+
if (value === void 0 || value === null) return "";
|
|
5629
|
+
return String(value).trim();
|
|
5630
|
+
}
|
|
5631
|
+
async function buildImportPlan(env, cache, args) {
|
|
5632
|
+
const warnings = [];
|
|
5633
|
+
const talent = cache.forms.talent_pool;
|
|
5634
|
+
const objId = talent?.objId;
|
|
5635
|
+
const formId = talent?.formId || objId;
|
|
5636
|
+
if (!objId || !formId) {
|
|
5637
|
+
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");
|
|
5638
|
+
}
|
|
5639
|
+
const fields = cache.fields[objId] || {};
|
|
5640
|
+
const name = str(args.candidateName);
|
|
5641
|
+
const mobile = str(args.telephone);
|
|
5642
|
+
if (!name) throw ehrValidationError("candidate_name_required", "candidateName \u5FC5\u586B");
|
|
5643
|
+
if (!/^\d{6,}$/.test(mobile)) throw ehrValidationError("telephone_invalid", "telephone \u5FC5\u987B\u662F 6 \u4F4D\u4EE5\u4E0A\u6570\u5B57\uFF08\u624B\u673A\u53F7\uFF09");
|
|
5644
|
+
if (!fields.candidate_name || !fields.telephone) {
|
|
5645
|
+
throw ehrValidationError("recruit_field_missing", "\u73AF\u5883\u7F13\u5B58\u7F3A\u4EBA\u624D\u59D3\u540D\u5B57\u6BB5(candidate_name)\u6216\u624B\u673A\u5B57\u6BB5(telephone)");
|
|
5646
|
+
}
|
|
5647
|
+
const resolveDict = makeDictResolver(cache, warnings);
|
|
5648
|
+
const main = {};
|
|
5649
|
+
const putText = (key, value, longText = false) => {
|
|
5650
|
+
if (!fields[key]) return;
|
|
5651
|
+
const text = str(value);
|
|
5652
|
+
if (!text) return;
|
|
5653
|
+
main[key] = text;
|
|
5654
|
+
void longText;
|
|
5655
|
+
};
|
|
5656
|
+
putText("candidate_name", name);
|
|
5657
|
+
putText("telephone", mobile);
|
|
5658
|
+
putText("email", args.email);
|
|
5659
|
+
putText("birthday", args.birthday);
|
|
5660
|
+
putText("age", args.age);
|
|
5661
|
+
putText("college", args.college);
|
|
5662
|
+
putText("graduate_date", args.graduateDate);
|
|
5663
|
+
putText("joinworkdate", args.joinworkdate);
|
|
5664
|
+
putText("intend_position", args.intendPosition);
|
|
5665
|
+
putText("intended_workplace", args.intendedWorkplace);
|
|
5666
|
+
putText("self_desc", args.selfDesc, true);
|
|
5667
|
+
putText("work_ability", args.workAbility, true);
|
|
5668
|
+
for (const [key, inputKey, label] of [
|
|
5669
|
+
["gender", "genderName", "\u6027\u522B"],
|
|
5670
|
+
["highest_degree", "highestDegreeName", "\u6700\u9AD8\u5B66\u5386"]
|
|
5671
|
+
]) {
|
|
5672
|
+
if (!fields[key]) continue;
|
|
5673
|
+
const raw = str(args[inputKey]);
|
|
5674
|
+
if (!raw) continue;
|
|
5675
|
+
const id = resolveDict(raw, label);
|
|
5676
|
+
if (id) main[key] = id;
|
|
5677
|
+
}
|
|
5678
|
+
const channel = str(args.channel);
|
|
5679
|
+
if (channel) {
|
|
5680
|
+
if (!fields.channel) warnings.push("\u4EBA\u624D\u8868\u5355\u65E0\u6E20\u9053\u5B57\u6BB5\uFF0Cchannel \u5DF2\u5FFD\u7565");
|
|
5681
|
+
else {
|
|
5682
|
+
const id = resolveDict(channel, "\u6E20\u9053");
|
|
5683
|
+
if (id) main.channel = id;
|
|
5684
|
+
}
|
|
5685
|
+
}
|
|
5686
|
+
if (fields.is_blacklist) {
|
|
5687
|
+
const noId = resolveDict("\u5426", "\u9ED1\u540D\u5355");
|
|
5688
|
+
if (noId) main.is_blacklist = noId;
|
|
5689
|
+
}
|
|
5690
|
+
let subStats = {};
|
|
5691
|
+
let detailNodes = {};
|
|
5692
|
+
let details = {};
|
|
5693
|
+
try {
|
|
5694
|
+
const mappingResponse = await env.host.request({
|
|
5695
|
+
path: `/api/ebuilder/form/dataset/v1/getTableMapping?objId=${encodeURIComponent(objId)}`,
|
|
5696
|
+
method: "GET",
|
|
5697
|
+
operation: "ehr.recruit.candidate.import.prepare"
|
|
5698
|
+
});
|
|
5699
|
+
const mapping = mappingResponse?.data;
|
|
5700
|
+
if (!mapping?.mainTable) throw new Error("getTableMapping \u672A\u8FD4\u56DE mainTable");
|
|
5701
|
+
const nodeOfTable = {};
|
|
5702
|
+
for (const [node, tableId] of Object.entries(mapping)) {
|
|
5703
|
+
if (node === "mainTable") continue;
|
|
5704
|
+
nodeOfTable[String(tableId)] = node;
|
|
5705
|
+
}
|
|
5706
|
+
const meta = await resolveSubTableMeta(env, formId);
|
|
5707
|
+
const built = buildSubDetails(args, meta, nodeOfTable, resolveDict);
|
|
5708
|
+
details = built.details;
|
|
5709
|
+
subStats = built.stats;
|
|
5710
|
+
detailNodes = built.nodes;
|
|
5711
|
+
warnings.push(...built.warnings);
|
|
5712
|
+
} catch (error) {
|
|
5713
|
+
warnings.push(`\u660E\u7EC6\u8868\u672A\u5199\u5165\uFF1A${error?.message || "\u672A\u77E5\u9519\u8BEF"}\uFF08\u4E3B\u8868\u7167\u5E38\u5EFA\u6863\uFF09`);
|
|
5714
|
+
}
|
|
5715
|
+
const subRowTotal = Object.values(subStats).reduce((sum, n) => sum + n, 0);
|
|
5716
|
+
const summary = {
|
|
5717
|
+
candidateName: name,
|
|
5718
|
+
telephone: mobile,
|
|
5719
|
+
email: str(args.email) || "(\u672A\u586B)",
|
|
5720
|
+
channel: channel || "(\u672A\u6307\u5B9A)",
|
|
5721
|
+
mainFieldCount: Object.keys(main).length,
|
|
5722
|
+
mainFields: Object.keys(main).sort(),
|
|
5723
|
+
subTableRows: subStats,
|
|
5724
|
+
subRowTotal,
|
|
5725
|
+
detailNodes,
|
|
5726
|
+
platformTags: Array.isArray(args.tags) ? args.tags : [],
|
|
5727
|
+
resumeFile: str(args.resumeFile) || "(\u672A\u63D0\u4F9B\u539F\u4EF6)",
|
|
5728
|
+
warnings
|
|
5729
|
+
};
|
|
5730
|
+
return {
|
|
5731
|
+
objId,
|
|
5732
|
+
formId,
|
|
5733
|
+
talentObjId: objId,
|
|
5734
|
+
mainTable: main,
|
|
5735
|
+
details,
|
|
5736
|
+
subStats,
|
|
5737
|
+
detailNodes,
|
|
5738
|
+
warnings,
|
|
5739
|
+
talentName: name,
|
|
5740
|
+
mobile,
|
|
5741
|
+
summary
|
|
5742
|
+
};
|
|
5743
|
+
}
|
|
5744
|
+
var candidateImportPrepare = {
|
|
5745
|
+
name: "ehr.recruit.candidate.import.prepare",
|
|
5746
|
+
resource: "recruit",
|
|
5747
|
+
method: "candidate.import.prepare",
|
|
5748
|
+
action: "ehr.recruit.candidate.import.prepare",
|
|
5749
|
+
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",
|
|
5750
|
+
capability: "recruit",
|
|
5751
|
+
risk: WRITE,
|
|
5752
|
+
requiresConfirmation: true,
|
|
5753
|
+
inputSchema: schemaOf({
|
|
5754
|
+
candidateName: { type: "string", maxLength: 60, description: "\u59D3\u540D\uFF08\u5FC5\u586B\uFF09" },
|
|
5755
|
+
telephone: { type: "string", pattern: "^\\d{6,20}$", description: "\u624B\u673A\u53F7\uFF08\u5FC5\u586B\uFF0C\u67E5\u91CD\u4E3B\u952E\uFF09" },
|
|
5756
|
+
email: { type: "string", maxLength: 120 },
|
|
5757
|
+
genderName: { type: "string", description: "\u6027\u522B\u540D\u79F0\uFF08\u5982 \u7537/\u5973\uFF0C\u6309\u672C\u73AF\u5883\u5B57\u5178\u53CD\u67E5\uFF09" },
|
|
5758
|
+
birthday: { type: "string", description: "\u51FA\u751F\u65E5\u671F YYYY-MM-DD" },
|
|
5759
|
+
age: { type: "string", description: "\u5E74\u9F84" },
|
|
5760
|
+
highestDegreeName: { type: "string", description: "\u6700\u9AD8\u5B66\u5386\u540D\u79F0\uFF08\u5982 \u672C\u79D1/\u7855\u58EB\uFF09" },
|
|
5761
|
+
college: { type: "string", maxLength: 120, description: "\u6BD5\u4E1A\u9662\u6821" },
|
|
5762
|
+
graduateDate: { type: "string", description: "\u6BD5\u4E1A\u65F6\u95F4" },
|
|
5763
|
+
joinworkdate: { type: "string", description: "\u53C2\u52A0\u5DE5\u4F5C\u65E5\u671F" },
|
|
5764
|
+
intendPosition: { type: "string", maxLength: 120, description: "\u610F\u5411\u5C97\u4F4D" },
|
|
5765
|
+
intendedWorkplace: { type: "string", maxLength: 120, description: "\u671F\u671B\u5DE5\u4F5C\u5730\u70B9" },
|
|
5766
|
+
selfDesc: { type: "string", maxLength: 2e4, description: "\u81EA\u6211\u8BC4\u4EF7\uFF08\u957F\u6587\u672C\uFF09" },
|
|
5767
|
+
workAbility: { type: "string", maxLength: 2e4, description: "\u804C\u4E1A\u6280\u80FD/\u6280\u672F\u6808\uFF08\u957F\u6587\u672C\uFF09" },
|
|
5768
|
+
channel: { type: "string", maxLength: 60, description: "\u4EBA\u624D\u6765\u6E90\u6E20\u9053\u540D\u79F0\uFF08\u5982 \u667A\u8054\u62DB\u8058/\u5185\u63A8\uFF09" },
|
|
5769
|
+
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" },
|
|
5770
|
+
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" },
|
|
5771
|
+
academicInformations: {
|
|
5772
|
+
type: "array",
|
|
5773
|
+
maxItems: 20,
|
|
5774
|
+
description: "\u6559\u80B2\u7ECF\u5386\uFF08school/edu_major/edu_education/degree/study_date/faculty/research_direction/major_courses\uFF09",
|
|
5775
|
+
items: { type: "object" }
|
|
5776
|
+
},
|
|
5777
|
+
jobInformations: {
|
|
5778
|
+
type: "array",
|
|
5779
|
+
maxItems: 30,
|
|
5780
|
+
description: "\u5DE5\u4F5C\u7ECF\u5386\uFF08co_name/work_position/work_dept/work_desc/resign_cause/start_date/end_date/work_type\uFF09",
|
|
5781
|
+
items: { type: "object" }
|
|
5782
|
+
},
|
|
5783
|
+
internshipExperiences: {
|
|
5784
|
+
type: "array",
|
|
5785
|
+
maxItems: 20,
|
|
5786
|
+
description: "\u5B9E\u4E60\u7ECF\u5386\uFF08sx_co_name/position_job/job_description/entry_time/sx_work_type\uFF09",
|
|
5787
|
+
items: { type: "object" }
|
|
5788
|
+
},
|
|
5789
|
+
projectExperiences: {
|
|
5790
|
+
type: "array",
|
|
5791
|
+
maxItems: 30,
|
|
5792
|
+
description: "\u9879\u76EE\u7ECF\u5386\uFF08pj_name/pj_role/pj_duty/pj_introduction/start_date/end_date\uFF09",
|
|
5793
|
+
items: { type: "object" }
|
|
5794
|
+
},
|
|
5795
|
+
awardExperiences: {
|
|
5796
|
+
type: "array",
|
|
5797
|
+
maxItems: 20,
|
|
5798
|
+
description: "\u83B7\u5956\u7ECF\u5386\uFF08award_name/awarded/credentials/award_date\uFF09",
|
|
5799
|
+
items: { type: "object" }
|
|
5800
|
+
},
|
|
5801
|
+
languageAbilities: {
|
|
5802
|
+
type: "array",
|
|
5803
|
+
maxItems: 10,
|
|
5804
|
+
description: "\u8BED\u8A00\u80FD\u529B\uFF08language_type/mastery/ls_ability/literacy\uFF09",
|
|
5805
|
+
items: { type: "object" }
|
|
5806
|
+
}
|
|
5807
|
+
}, { required: ["candidateName", "telephone"] }),
|
|
5808
|
+
handler: async (args, env) => {
|
|
5809
|
+
const cache = await requireCache2(env);
|
|
5810
|
+
const plan = await buildImportPlan(env, cache, args);
|
|
5811
|
+
const dup = await checkDuplicateByMobile(env, cache, plan.mobile);
|
|
5812
|
+
if (dup.length > 1) {
|
|
5813
|
+
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`);
|
|
5814
|
+
}
|
|
5815
|
+
const dupRow = dup[0];
|
|
5816
|
+
const session = await env.host.getSession();
|
|
5817
|
+
const continuation = await env.continuation.issue(
|
|
5818
|
+
{
|
|
5819
|
+
operation: "ehr.recruit.candidate.import.apply",
|
|
5820
|
+
baseUrl: session.baseUrl,
|
|
5821
|
+
profile: session.profile,
|
|
5822
|
+
userId: session.userId,
|
|
5823
|
+
payload: {
|
|
5824
|
+
objId: plan.objId,
|
|
5825
|
+
formId: plan.formId,
|
|
5826
|
+
mainTable: plan.mainTable,
|
|
5827
|
+
details: plan.details,
|
|
5828
|
+
tags: Array.isArray(args.tags) ? args.tags.map(String) : [],
|
|
5829
|
+
resumeFile: str(args.resumeFile),
|
|
5830
|
+
subStats: plan.subStats,
|
|
5831
|
+
warnings: plan.warnings,
|
|
5832
|
+
candidateName: plan.talentName,
|
|
5833
|
+
telephone: plan.mobile
|
|
5834
|
+
}
|
|
5835
|
+
},
|
|
5836
|
+
10 * 60 * 1e3
|
|
5837
|
+
);
|
|
5838
|
+
return ehrSuccess("ehr.recruit.candidate.import.prepare", {
|
|
5839
|
+
status: "AWAITING_CONFIRMATION",
|
|
5840
|
+
preview: {
|
|
5841
|
+
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",
|
|
5842
|
+
...plan.summary,
|
|
5843
|
+
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"
|
|
5844
|
+
},
|
|
5845
|
+
willSubmit: {
|
|
5846
|
+
objId: plan.objId,
|
|
5847
|
+
mainTable: plan.mainTable,
|
|
5848
|
+
details: plan.details,
|
|
5849
|
+
tags: Array.isArray(args.tags) ? args.tags : []
|
|
5850
|
+
},
|
|
5851
|
+
continuation,
|
|
5852
|
+
expiresInSeconds: 600
|
|
5853
|
+
});
|
|
5854
|
+
}
|
|
5855
|
+
};
|
|
5856
|
+
var candidateImportApply = {
|
|
5857
|
+
name: "ehr.recruit.candidate.import.apply",
|
|
5858
|
+
resource: "recruit",
|
|
5859
|
+
method: "candidate.import.apply",
|
|
5860
|
+
action: "ehr.recruit.candidate.import.apply",
|
|
5861
|
+
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",
|
|
5862
|
+
capability: "recruit",
|
|
5863
|
+
risk: WRITE,
|
|
5864
|
+
requiresConfirmation: true,
|
|
5865
|
+
inputSchema: schemaOf(
|
|
5866
|
+
{
|
|
5867
|
+
candidateName: { type: "string", maxLength: 60 },
|
|
5868
|
+
telephone: { type: "string", pattern: "^\\d{6,20}$" },
|
|
5869
|
+
resumeFile: { type: "string" },
|
|
5870
|
+
tags: { type: "array", items: { type: "string" }, maxItems: 20 },
|
|
5871
|
+
confirm: { const: true },
|
|
5872
|
+
continuation: { type: "string", minLength: 1 }
|
|
5873
|
+
},
|
|
5874
|
+
{ required: ["candidateName", "telephone", "confirm", "continuation"] }
|
|
5875
|
+
),
|
|
5876
|
+
handler: async (args, env) => {
|
|
5877
|
+
if (args.confirm !== true) {
|
|
5878
|
+
throw ehrConfirmationError("ehr.recruit.candidate.import.apply", {
|
|
5879
|
+
hint: "\u91CD\u65B0\u8C03\u7528\u65F6\u4F20\u5165 confirm=true \u4E0E prepare \u8FD4\u56DE\u7684 continuation"
|
|
5880
|
+
});
|
|
5881
|
+
}
|
|
5882
|
+
const lease = await env.continuation.verify(args.continuation, "ehr.recruit.candidate.import.apply");
|
|
5883
|
+
const session = await env.host.getSession();
|
|
5884
|
+
if (lease.baseUrl !== session.baseUrl || lease.profile !== session.profile || lease.userId !== session.userId) {
|
|
5885
|
+
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");
|
|
5886
|
+
}
|
|
5887
|
+
const payload = lease.payload || {};
|
|
5888
|
+
if (payload.candidateName !== str(args.candidateName) || payload.telephone !== str(args.telephone)) {
|
|
5889
|
+
throw ehrValidationError("target_changed", "\u59D3\u540D\u6216\u624B\u673A\u53F7\u4E0E prepare \u65F6\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u6267\u884C prepare");
|
|
5890
|
+
}
|
|
5891
|
+
const cache = await requireCache2(env);
|
|
5892
|
+
const objId = String(payload.objId);
|
|
5893
|
+
const formId = String(payload.formId);
|
|
5894
|
+
const fields = cache.fields[objId] || {};
|
|
5895
|
+
const mainTable = { ...payload.mainTable || {} };
|
|
5896
|
+
const resumeFieldKey = "original_resume";
|
|
5897
|
+
const resumeFile = str(payload.resumeFile);
|
|
5898
|
+
let uploaded = null;
|
|
5899
|
+
if (resumeFile) {
|
|
5900
|
+
if (!fields[resumeFieldKey]) {
|
|
5901
|
+
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");
|
|
5902
|
+
}
|
|
5903
|
+
uploaded = await uploadResumeFile(env, resumeFile, fields[resumeFieldKey], formId);
|
|
5904
|
+
mainTable[resumeFieldKey] = uploaded.fileid;
|
|
5905
|
+
}
|
|
5906
|
+
let talentId;
|
|
5907
|
+
try {
|
|
5908
|
+
talentId = await datasetSaveFormData(env, objId, mainTable, payload.details || {});
|
|
5909
|
+
} catch (error) {
|
|
5910
|
+
if (error?.subtype === "save_failed") throw error;
|
|
5911
|
+
throw ehrPartialError(
|
|
5912
|
+
`\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`,
|
|
5913
|
+
{ candidateName: payload.candidateName, telephone: payload.telephone }
|
|
5914
|
+
);
|
|
5915
|
+
}
|
|
5916
|
+
let batchOk = null;
|
|
5917
|
+
let batchNote;
|
|
5918
|
+
try {
|
|
5919
|
+
await env.host.request({
|
|
5920
|
+
path: `/api/recruit/candidate/initTalentBatch?formDataId=${encodeURIComponent(talentId)}`,
|
|
5921
|
+
method: "POST",
|
|
5922
|
+
operation: "ehr.recruit.candidate.import.apply"
|
|
5923
|
+
});
|
|
5924
|
+
batchOk = true;
|
|
5925
|
+
} catch (error) {
|
|
5926
|
+
batchOk = false;
|
|
5927
|
+
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`;
|
|
5928
|
+
}
|
|
5929
|
+
let labelMatch = null;
|
|
5930
|
+
try {
|
|
5931
|
+
const r = await env.host.request({
|
|
5932
|
+
path: `/api/recruit/label/matchTalentLabel?talentId=${encodeURIComponent(talentId)}`,
|
|
5933
|
+
method: "POST",
|
|
5934
|
+
body: {},
|
|
5935
|
+
operation: "ehr.recruit.candidate.import.apply"
|
|
5936
|
+
});
|
|
5937
|
+
labelMatch = r?.data === void 0 ? "TRIGGERED" : String(r.data);
|
|
5938
|
+
} catch {
|
|
5939
|
+
labelMatch = "FAILED\uFF08\u4E0D\u5F71\u54CD\u5EFA\u6863\uFF0C\u53EF\u7A0D\u540E\u5728\u4EBA\u624D\u5361\u7247\u624B\u52A8\u89E6\u53D1\uFF09";
|
|
5940
|
+
}
|
|
5941
|
+
let tagResult = { applied: [], skipped: [] };
|
|
5942
|
+
try {
|
|
5943
|
+
tagResult = await applyPlatformTags(env, talentId, Array.isArray(payload.tags) ? payload.tags.map(String) : []);
|
|
5944
|
+
} catch (error) {
|
|
5945
|
+
tagResult = { applied: [], skipped: Array.isArray(payload.tags) ? payload.tags.map(String) : [] };
|
|
5946
|
+
}
|
|
5947
|
+
const baseUrl = session.baseUrl.replace(/\/+$/, "");
|
|
5948
|
+
const extra = String(cache.selfUse) === "1" ? "&recruitType=useSelf" : "";
|
|
5949
|
+
const talentCardUrl = cache.ebdDetailPageId ? `${baseUrl}/sp/ebdpage/view/${cache.ebdDetailPageId}?talentId=${talentId}${extra}` : null;
|
|
5950
|
+
const talentListId = cache.lists.talent?.listId;
|
|
5951
|
+
const talentListLocateUrl = talentListId ? `${baseUrl}/sp/ebdfpage/list/${talentListId}?talentId=${talentId}${extra}` : null;
|
|
5952
|
+
const warnings = [...payload.warnings || []];
|
|
5953
|
+
if (batchNote) warnings.push(batchNote);
|
|
5954
|
+
return ehrSuccess("ehr.recruit.candidate.import.apply", {
|
|
5955
|
+
result: "success",
|
|
5956
|
+
talentId,
|
|
5957
|
+
candidateName: payload.candidateName,
|
|
5958
|
+
telephone: payload.telephone,
|
|
5959
|
+
mainTableFields: Object.keys(mainTable).length,
|
|
5960
|
+
detailRows: payload.subStats || void 0,
|
|
5961
|
+
attachment: uploaded ? { name: uploaded.name, size: uploaded.size } : null,
|
|
5962
|
+
batch: { ok: batchOk, note: batchNote },
|
|
5963
|
+
labelMatch,
|
|
5964
|
+
tagsApplied: tagResult.applied,
|
|
5965
|
+
tagsSkipped: tagResult.skipped,
|
|
5966
|
+
talentCardUrl,
|
|
5967
|
+
talentListLocateUrl
|
|
5968
|
+
}, warnings.length ? { warnings } : void 0);
|
|
5969
|
+
}
|
|
5970
|
+
};
|
|
5971
|
+
var recruitCandidateImportOperations = [
|
|
5972
|
+
candidateImportPrepare,
|
|
5973
|
+
candidateImportApply
|
|
5974
|
+
];
|
|
5975
|
+
|
|
4825
5976
|
// src/shortcuts/ehr/operations/salary.ts
|
|
4826
5977
|
function requireMonthRange(value, field) {
|
|
4827
5978
|
if (!Array.isArray(value) || value.length === 0) {
|
|
@@ -5003,7 +6154,10 @@ function buildRegistry() {
|
|
|
5003
6154
|
...hrDataSourceOperations,
|
|
5004
6155
|
...hrReportOperations,
|
|
5005
6156
|
...recruitOperations,
|
|
5006
|
-
...recruitWriteOperations
|
|
6157
|
+
...recruitWriteOperations,
|
|
6158
|
+
...recruitStatsOperations,
|
|
6159
|
+
...recruitPositionOperations,
|
|
6160
|
+
...recruitCandidateImportOperations
|
|
5007
6161
|
];
|
|
5008
6162
|
for (const definition of definitions) {
|
|
5009
6163
|
if (registry.has(definition.name)) {
|
|
@@ -5114,7 +6268,7 @@ async function inputFrom(options, extra = {}) {
|
|
|
5114
6268
|
if (opts.input) {
|
|
5115
6269
|
let raw;
|
|
5116
6270
|
try {
|
|
5117
|
-
raw = stripBom(opts.input === "-" ? await readStdin() : await
|
|
6271
|
+
raw = stripBom(opts.input === "-" ? await readStdin() : await readFile3(String(opts.input), "utf8"));
|
|
5118
6272
|
} catch {
|
|
5119
6273
|
throw ehrValidationError("input_unreadable", `\u65E0\u6CD5\u8BFB\u53D6 --input\uFF1A${String(opts.input)}`);
|
|
5120
6274
|
}
|