weaver-work-cli 0.1.39 → 0.1.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/dist/chunks/{archive-ENZYBBME.js → archive-J4I6MCKF.js} +2 -2
- package/dist/chunks/{archive-oa-YWLEC5V4.js → archive-oa-BRZKKTO4.js} +2 -2
- package/dist/chunks/{asset-OOV6DWPA.js → asset-L7D4FAOZ.js} +2 -2
- package/dist/chunks/{asset-idle-RE632MY5.js → asset-idle-DADLLV75.js} +2 -2
- package/dist/chunks/{attachment-content-RWN2FCLL.js → attachment-content-K4C7VLWQ.js} +3 -3
- package/dist/chunks/{blog-PEPOJAL7.js → blog-BVGQ7NZL.js} +2 -2
- package/dist/chunks/{caizhilian-WYIQDVPJ.js → caizhilian-SAADNFD6.js} +2 -2
- package/dist/chunks/{calendar-CIARBAOX.js → calendar-Q7NQY5Z2.js} +61 -23
- package/dist/chunks/{chunk-F2EQXUEE.js → chunk-3KTFS4IA.js} +397 -159
- package/dist/chunks/{chunk-G2JSIUWF.js → chunk-4PD5NWAX.js} +89 -0
- package/dist/chunks/{chunk-HJYVHXUQ.js → chunk-4RAE6JXP.js} +1 -1
- package/dist/chunks/{chunk-CQHGNCK2.js → chunk-72CKAUAG.js} +41 -8
- package/dist/chunks/{chunk-K3RUEEOL.js → chunk-APVFJUQH.js} +2 -2
- package/dist/chunks/{chunk-BJGXMFGD.js → chunk-BBKDXQEC.js} +2 -2
- package/dist/chunks/chunk-BIPYLLVS.js +501 -0
- package/dist/chunks/{chunk-GVPJZXJ2.js → chunk-EKWAQSLU.js} +92 -50
- package/dist/chunks/{chunk-XXJOSZTQ.js → chunk-FOAA27U5.js} +381 -57
- package/dist/chunks/{chunk-I2HB737U.js → chunk-G4UR6NXN.js} +2 -2
- package/dist/chunks/{chunk-YS5DPN4T.js → chunk-GEWYMQME.js} +1 -1
- package/dist/chunks/{chunk-P2DAISYW.js → chunk-GHXCDPTM.js} +1 -1
- package/dist/chunks/{chunk-L4N7B7ZD.js → chunk-IZ7S7QUS.js} +4 -4
- package/dist/chunks/{chunk-NLK2RZKG.js → chunk-JPRO6ER2.js} +122 -2214
- package/dist/chunks/{chunk-36DIFZAH.js → chunk-LADPYOWC.js} +2 -2
- package/dist/chunks/chunk-LDZQPUIA.js +1238 -0
- package/dist/chunks/chunk-NKZRQXST.js +2546 -0
- package/dist/chunks/{chunk-EINRJHQ3.js → chunk-QKNKR4RH.js} +3 -3
- package/dist/chunks/{chunk-T7JDJJ7H.js → chunk-R4CHUSKC.js} +126 -19
- package/dist/chunks/{chunk-EZGFHJFW.js → chunk-SA6VBIHY.js} +88 -15
- package/dist/chunks/{chunk-ZXRNHZTE.js → chunk-TTPJJJC4.js} +2 -2
- package/dist/chunks/{chunk-KTCB5R5H.js → chunk-W7BEHOSR.js} +2 -2
- package/dist/chunks/{chunk-MUQUHKPG.js → chunk-YRSZQUD2.js} +2 -2
- package/dist/chunks/{conflict-DRMDOL56.js → conflict-F2OMZRTO.js} +2 -2
- package/dist/chunks/{contract-73MERZWN.js → contract-5BETHRSG.js} +2 -2
- package/dist/chunks/{cowork-HNGBPD7A.js → cowork-3MN6EQQO.js} +27 -10
- package/dist/chunks/create-flow-5FQNNMVO.js +55 -0
- package/dist/chunks/{ebuilder-form-OY6DVNRK.js → ebuilder-form-SBHOYBUD.js} +3 -3
- package/dist/chunks/{ehr-RAQNEQO7.js → ehr-KMOJULKG.js} +432 -1234
- package/dist/chunks/env-LB7NBL2O.js +19 -0
- package/dist/chunks/{esb-6XV7C7YV.js → esb-W2PJCFCX.js} +4 -4
- package/dist/chunks/factory-6ZFQXQ46.js +30 -0
- package/dist/chunks/{fna-XTSRB7G7.js → fna-ZQPCUV4R.js} +2 -2
- package/dist/chunks/group-chat-2HHAJN46.js +20 -0
- package/dist/chunks/{host-YMBXWFWX.js → host-4CBHGOHT.js} +3 -3
- package/dist/chunks/{host-A7J6GDUP.js → host-ATKVNZAT.js} +3 -3
- package/dist/chunks/{host-3F5UM5GN.js → host-BQH22NTQ.js} +3 -3
- package/dist/chunks/{host-YAQAPYNP.js → host-X2CSLFM6.js} +3 -3
- package/dist/chunks/{host-VGPVP7YF.js → host-YTODKMSL.js} +3 -3
- package/dist/chunks/{hrm-TLHKC545.js → hrm-FFM4UJFS.js} +4 -4
- package/dist/chunks/{im-YOUCFMUK.js → im-VEHKDQPB.js} +8 -8
- package/dist/chunks/{invoice-WNBS2B4C.js → invoice-LVIKSIIF.js} +3 -3
- package/dist/chunks/{jiuchuanhui-XABWS5RN.js → jiuchuanhui-X6DINO5P.js} +2 -2
- package/dist/chunks/{lazy-dispatch-NLZ5UQQI.js → lazy-dispatch-KSWTN5L6.js} +4 -4
- package/dist/chunks/{mail-LRYMBFNL.js → mail-VDKRGUD3.js} +9 -4
- package/dist/chunks/{meeting-ESXL6MFI.js → meeting-CLC6HP3Z.js} +12 -10
- package/dist/chunks/{okr-EOV65SSF.js → okr-CHG4OO3U.js} +2 -2
- package/dist/chunks/{plan-YFPVKW6Y.js → plan-XWR75667.js} +2 -2
- package/dist/chunks/{project-MDVZUYQW.js → project-5BXOOKMG.js} +40 -23
- package/dist/chunks/recruit-stage-DGMFNNDE.js +4507 -0
- package/dist/chunks/{registry-VT5Y2HLA.js → registry-7FFOXIAW.js} +4 -4
- package/dist/chunks/{registry-QCLZEDAP.js → registry-BKBZPBAJ.js} +10 -8
- package/dist/chunks/{registry-YX4CSEMD.js → registry-RHMW6ANW.js} +2 -2
- package/dist/chunks/{registry-NYPYMZXG.js → registry-Z43434VG.js} +1 -1
- package/dist/chunks/{room-recommend-L3MWH4JW.js → room-recommend-62H7ZQQ6.js} +4 -4
- package/dist/chunks/{schedule-UASAVDVD.js → schedule-FNXKH3DQ.js} +4 -4
- package/dist/chunks/{workflow-KDGIUCNW.js → workflow-ADHKCAJK.js} +4 -4
- package/dist/index.js +33 -28
- package/dist/internal/e10/auth/commands.js +110 -56
- package/dist/internal/e10/auth/messages.js +6 -0
- package/dist/internal/e10/auth/session.js +28 -1
- package/dist/internal/e10/auth/xiaoe.js +315 -48
- package/dist/internal/e10/auth-recovery.js +36 -5
- package/dist/internal/e10/client.js +13 -0
- package/dist/internal/e10/context.js +61 -9
- package/dist/internal/e10/index.js +1 -1
- package/dist/internal/e10/network-error.js +93 -0
- package/dist/internal/e10/request-runtime.js +15 -0
- package/dist/shortcuts/calendar/operations/read.js +31 -22
- package/dist/shortcuts/calendar/operations/write.js +45 -1
- package/dist/shortcuts/cowork/operations/discuss-write.js +5 -1
- package/dist/shortcuts/cowork/operations/item-write.js +5 -3
- package/dist/shortcuts/cowork/operations/member-write.js +3 -1
- package/dist/shortcuts/cowork/operations/permission-write.js +5 -1
- package/dist/shortcuts/cowork/operations/shared.js +7 -0
- package/dist/shortcuts/ehr/operations/attend-write.js +43 -1
- package/dist/shortcuts/ehr/operations/hr-contact.js +7 -4
- package/dist/shortcuts/ehr/operations/hr-report.js +13 -7
- package/dist/shortcuts/ehr/operations/recruit-candidate-import.js +134 -59
- package/dist/shortcuts/ehr/operations/recruit-write.js +262 -17
- package/dist/shortcuts/ehr/operations/recruit.js +10 -4
- package/dist/shortcuts/ehr/operations/shared.js +47 -0
- package/dist/shortcuts/hrm/operations/org.js +118 -0
- package/dist/shortcuts/index.js +5 -0
- package/dist/shortcuts/mail/operations/mail-send.js +8 -2
- package/dist/shortcuts/meeting/operations/eb/catalog.js +9 -2
- package/dist/shortcuts/meeting/operations/eb/create-flow.js +461 -127
- package/dist/shortcuts/meeting/operations/eb/crm-search.js +87 -5
- package/dist/shortcuts/meeting/operations/eb/factory.js +33 -0
- package/dist/shortcuts/meeting/operations/eb/flow-memory.js +49 -0
- package/dist/shortcuts/meeting/operations/eb/group-chat.js +605 -0
- package/dist/shortcuts/meeting/operations/eb/index.js +2 -0
- package/dist/shortcuts/meeting/operations/eb/person-cache.js +96 -0
- package/dist/shortcuts/meeting/operations/eb/room-recommend.js +44 -6
- package/dist/shortcuts/meeting/operations/eb/room-summary.js +2 -0
- package/dist/shortcuts/meeting/operations/eb/usage-cache.js +99 -0
- package/dist/shortcuts/meeting/operations/from-group-chat.js +35 -12
- package/dist/shortcuts/project/operations/read.js +6 -25
- package/dist/shortcuts/project/operations/shared.js +22 -0
- package/dist/shortcuts/project/operations/write.js +28 -2
- package/dist/shortcuts/recruit-stage/context.js +119 -0
- package/dist/shortcuts/recruit-stage/continuation.js +73 -0
- package/dist/shortcuts/recruit-stage/errors.js +65 -0
- package/dist/shortcuts/recruit-stage/host.js +109 -0
- package/dist/shortcuts/recruit-stage/index.js +115 -0
- package/dist/shortcuts/recruit-stage/manifest.js +29 -0
- package/dist/shortcuts/recruit-stage/operations/interview-arrange.js +722 -0
- package/dist/shortcuts/recruit-stage/operations/interview-feedback.js +269 -0
- package/dist/shortcuts/recruit-stage/operations/jd-create.js +630 -0
- package/dist/shortcuts/recruit-stage/operations/list.js +431 -0
- package/dist/shortcuts/recruit-stage/operations/registry.js +38 -0
- package/dist/shortcuts/recruit-stage/operations/resume-import.js +1198 -0
- package/dist/shortcuts/recruit-stage/operations/search.js +158 -0
- package/dist/shortcuts/recruit-stage/operations/types.js +25 -0
- package/dist/shortcuts/recruit-stage/school-tiers.json +318 -0
- package/dist/shortcuts/recruit-stage/shared.js +608 -0
- package/dist/shortcuts/workflow/operations/form.js +21 -2
- package/dist/shortcuts/workflow/operations/todoSmartConvert/aigroupRules.js +52 -1
- package/dist/shortcuts/workflow/operations/todoSmartConvert/detailFieldRules.js +4 -2
- package/dist/shortcuts/workflow/operations/todoSmartConvert/summaryCache.js +19 -11
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailCache.js +17 -24
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoDetailFetcher.js +14 -9
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.collect.js +78 -10
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.core.js +3 -1
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.detail.js +17 -11
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.group.js +16 -40
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.groupSummary.js +3 -2
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.js +52 -15
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.pipeline.js +16 -1
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.smartGroup.js +151 -63
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.subGroup.js +56 -0
- package/dist/shortcuts/workflow/operations/todoSmartConvert/todoSmartConvert.summary.js +53 -16
- package/docs/e10-auth.md +22 -1
- package/docs/operation-manual.md +8 -0
- package/package.json +1 -1
- package/scripts/install-skill-to-xiaoe.mjs +105 -0
- package/scripts/mcp-meeting.mjs +234 -0
- package/scripts/package-skill.mjs +4 -2
- package/skill-template/business-info.json +24 -0
- package/skill-template/domains/recruit-stage.md +29 -0
- package/skills/weaver-e10-calendar/SKILL.md +2 -1
- package/skills/weaver-e10-calendar/references/calendar-write.md +54 -0
- package/skills/weaver-e10-cowork/SKILL.md +1 -1
- package/skills/weaver-e10-cowork/references/cowork-write.md +3 -1
- package/skills/weaver-e10-jucailin/SKILL.md +1 -1
- package/skills/weaver-e10-jucailin/references/attend-write.md +8 -0
- package/skills/weaver-e10-jucailin/references/hr-contact.md +8 -0
- package/skills/weaver-e10-jucailin/references/hr-report.md +8 -0
- package/skills/weaver-e10-jucailin/references/recruit-create.md +2 -2
- package/skills/weaver-e10-jucailin/references/recruit-read.md +1 -1
- package/skills/weaver-e10-jucailin/references/recruit-write.md +4 -3
- package/skills/weaver-e10-mail/SKILL.md +1 -1
- package/skills/weaver-e10-mail/references/mail-send.md +2 -0
- package/skills/weaver-e10-meeting/SKILL.md +119 -26
- package/skills/weaver-e10-meeting/references/meeting-minute-file.md +25 -11
- package/skills/weaver-e10-meeting.zip +0 -0
- package/skills/weaver-e10-recruit-stage/SKILL.md +226 -0
- package/skills/weaver-e10-recruit-stage/agents/openai.yaml +119 -0
- package/skills/weaver-e10-recruit-stage/lib/recruit-xiaoe-file.mjs +188 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-arrange-interview.md +322 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-capability-check.md +127 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-check-install.md +65 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-detail-process.md +63 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-edit-interview-feedback.md +142 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-jd-create.md +73 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-jd-template.md +56 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-list-candidate.md +101 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-list-interview.md +148 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-match-candidates.md +77 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-output-links.md +59 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-resolve-creator.md +69 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-resolve-metadata.md +241 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-resume-import.md +438 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-resume-parse.md +128 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-search-candidate.md +146 -0
- package/skills/weaver-e10-recruit-stage/references/recruit-urge-feedback.md +69 -0
- package/skills/weaver-e10-shared/SKILL.md +2 -2
- package/skills/weaver-e10-shared/references/e10-auth-and-session.md +4 -2
- package/skills/weaver-e10-shijingran/SKILL.md +3 -2
- package/skills/weaver-e10-shijingran/references/operations.md +3 -1
- package/skills/weaver-e10-shijingran/references/source-manifest.json +41 -40
- package/skills/weaver-e10-shijingran/references/write-operations.md +2 -0
- package/skills/weaver-e10-workflow/SKILL.md +7 -1
- package/skills/weaver-e10-workflow/aigroup/default.json +23 -9
- package/skills/weaver-e10-workflow/references/todo-smart-convert.md +37 -21
- package/skills/weaver-e10-workflow/tools/todo-summary.cjs +135 -43
- package/skills/weaver-e10-yepiaotong/SKILL.md +9 -10
- package/skills/weaver-e10-yepiaotong/references/invoice-agent-entry.md +6 -3
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: recruit-resume-import
|
|
3
|
+
description: 简历导入建人才(上传附件 → OCR 解析 → 填充人才基本信息字段 → 新建人才 + 标签识别)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 简历导入建人才
|
|
7
|
+
|
|
8
|
+
> **平台兼容**:本文命令示例在 macOS/Linux 与 Windows PowerShell 下均可执行——JSON 用单引号包裹、内部双引号不转义;PowerShell 下不使用反斜杠续行。
|
|
9
|
+
|
|
10
|
+
> 本文档中的 `${...}` 形参(表单 objId / formId / 字段 id / 文件目录)均为**租户相关值**:表单 objId 与 formId 由 `getObjsByTag` 一次返回;**字段 id 经 `ds/fields` 运行时解析、不写死**(见 `recruit-resolve-metadata.md` §5)。
|
|
11
|
+
|
|
12
|
+
## 1. 基础信息
|
|
13
|
+
- 接口名称:简历导入建人才(解析主通道=大模型 `--structured-file`;原件经上传进附件字段;OCR `resumeExtraction` 仅显式 `--use-ocr` 才调用(闸门=checkResumeExtraction),checkRpaValid 已废弃)
|
|
14
|
+
- 请求方式:`POST`
|
|
15
|
+
- 去域名路径:
|
|
16
|
+
- ① `/api/file/preUploadCheck`(预上传检查,**multipart 必须含 file**)
|
|
17
|
+
- ② `/api/file/module/upload`(正式上传,**必带 name/MD5/lastModified/lastModifiedDate + preUploadId/uploadType + file**)
|
|
18
|
+
- ③ `/api/recruit/ocr/checkRpaValid`、`/api/recruit/ocr/checkResumeExtraction`(预检,body `{}`)
|
|
19
|
+
- ④ `/api/recruit/ocr/resumeExtraction?fileId=<fileid>`(**无 body**,解析)
|
|
20
|
+
- ④′ `/api/recruit/candidate/getCandidateByPhone`(**建前查重主通道,页面代码块同款**:命中即"已绑定人才",给 `/sp/recruit/talentView?batchId=<candidateId>&recruitType=useSelf`)+ `/api/ebuilder/form/form/core/checkUnique`(补充:表单唯一性,捕捉无批次/已删除记录)
|
|
21
|
+
- ⑤ `/api/ebuilder/form/dataset/v2/saveFormData`(**主表 + 明细一次写入**,明细唯一通道);降级时用 `/api/ebuilder/form/form/core/saveFormData` + `/api/ebuilder/form/dataset/v2/updateFormData`;随后 `/api/recruit/candidate/initTalentBatch?formDataId=`
|
|
22
|
+
- ⑤′ 辅助:`/api/ebuilder/form/dataset/v1/getTableMapping?objId=`(明细节点 `detailN` ↔ `subFormId`,**顺序不固定,必须现取**)
|
|
23
|
+
- ⑥ 标签(两层):`/api/recruit/label/matchTalentLabel?talentId=<新人才id>`(触发后台智能标签规则)+ `/api/my/tag/common/batchAddEntityTag`(写入平台标签)+ `/api/my/tag/query`(标签清单)+ `/api/my/tag/common/queryEntityTag`(读回)
|
|
24
|
+
- 所属模块:招聘管理(recruit)
|
|
25
|
+
- 所属分组:人才库 / 写操作
|
|
26
|
+
|
|
27
|
+
## 2. 业务用途
|
|
28
|
+
用户"上传这份简历建人才""把简历导入人才库""解析附件并填充人才信息"时调用。先上传简历拿 `fileid`,OCR 解析出结构化简历,**自动填充「人才基本信息」表单字段并新建人才**(含简历附件),再初始化应聘批次。属写操作,**必须先展示解析结果+映射摘要并获明确确认后再提交**。
|
|
29
|
+
|
|
30
|
+
> **与 `recruit-resume-parse.md` 的关系**:解析步骤同源(③④);本能力在其后**增加"字段映射 + 建档"**,是完整的"简历→人才"链路。仅解析不建档用 `recruit-resume-parse.md`。
|
|
31
|
+
|
|
32
|
+
## 3. 前置条件
|
|
33
|
+
- 已安装招聘服务;人才表单 tag `uf_rcrt_talent_pool` 解析到 objId/formId(缺则阻断)。
|
|
34
|
+
- 字段 id 经环境缓存 `fields[objId]`(`ds/fields`)解析;`original_resume`(简历附件字段)必须存在。
|
|
35
|
+
- **建前查重**:按手机号搜 `recruit-search-candidate`,命中以 `data.data[]` 非空为准(`total` 恒 0 平台缺陷);命中 → 提示已存在并停住,**不新建重复**。
|
|
36
|
+
|
|
37
|
+
## 4. 请求参数
|
|
38
|
+
### 4.1 ① preUploadCheck(multipart)
|
|
39
|
+
| 字段 | 类型 | 必填 | 说明 |
|
|
40
|
+
|---|---|---|---|
|
|
41
|
+
| `compressImg` | string | 是 | `false` |
|
|
42
|
+
| `source` | string | 是 | `form` |
|
|
43
|
+
| `fieldId` | string | 是 | 简历附件字段 id(`original_resume`,运行时解析) |
|
|
44
|
+
| `sourceRefId`/`formId`/`refId` | string | 是 | 人才表单 id |
|
|
45
|
+
| `module`/`authModule` | string | 是 | `ebuilderform` |
|
|
46
|
+
| `customParam` | string(JSON) | 是 | `{"objId":"<人才objId>","ebDefaultParams":{}}` |
|
|
47
|
+
| `folderId` | string | 否 | 上传目录 id(前端上下文提供,可省) |
|
|
48
|
+
| `commonText` | string(JSON) | 是 | `{"fieldId":"<附件字段id>","formId":"<formId>"}` |
|
|
49
|
+
| `size` | string | 是 | 文件字节数 |
|
|
50
|
+
| **`file`** | file | **是** | 简历文件(**必须带,否则服务端 500**) |
|
|
51
|
+
|
|
52
|
+
→ `data.preUploadId`、`data.uploadType`(供②用)。
|
|
53
|
+
|
|
54
|
+
### 4.2 ② module/upload(multipart)
|
|
55
|
+
同 4.1 全部字段,**另加**:
|
|
56
|
+
| 字段 | 类型 | 必填 | 说明 |
|
|
57
|
+
|---|---|---|---|
|
|
58
|
+
| `name` | string | 是 | 文件名(缺则 500) |
|
|
59
|
+
| `MD5` | string | 是 | 文件内容 md5(缺则 500) |
|
|
60
|
+
| `lastModified`/`lastModifiedDate` | string | 是 | 毫秒时间戳(缺则 500) |
|
|
61
|
+
| `preUploadId` | string | 是 | ① 返回 |
|
|
62
|
+
| `uploadType` | string | 是 | ① 返回(通常 `common`) |
|
|
63
|
+
| `file` | file | 是 | 简历文件 |
|
|
64
|
+
|
|
65
|
+
→ `data.fileid`(= 解析入参 & 附件字段 optionId)、`data.name`、`data.size`、`data.extName`。
|
|
66
|
+
|
|
67
|
+
### 4.3 ③④ 预检 + 解析
|
|
68
|
+
- `POST /api/recruit/ocr/checkRpaValid`(`{}`)→ `data=true` 表示 RPA 抽取服务可用;
|
|
69
|
+
- `POST /api/recruit/ocr/checkResumeExtraction`(`{}`)→ `data=true` 表示功能已开启;
|
|
70
|
+
- `POST /api/recruit/ocr/resumeExtraction?fileId=<fileid>`(**query 传 fileId,无 body**)→ `data.data` 结构化简历。
|
|
71
|
+
- 任一预检 `false` → 停止并提示(RPA 不可用 / 未开启抽取)。
|
|
72
|
+
|
|
73
|
+
### 4.4 ⑤ 建前查重 + 建档
|
|
74
|
+
|
|
75
|
+
#### 4.4.1 建前查重(与页面新建同款,**必须先查**)
|
|
76
|
+
|
|
77
|
+
页面新建人才时,手机号重复就**不允许保存**并弹窗引导到已有人才。页面代码块(表单「新建人才」布局)里用的接口是:
|
|
78
|
+
|
|
79
|
+
```http
|
|
80
|
+
POST /api/recruit/candidate/getCandidateByPhone
|
|
81
|
+
{ "phone": "13800000002" }
|
|
82
|
+
```
|
|
83
|
+
→ `data`:`{ "batchNo": "<批次id>", "talentId": "<人才id>", "candidateId": "<批次id>" }`;未命中返回 `{}`。
|
|
84
|
+
|
|
85
|
+
页面弹窗后跳转的地址就是:
|
|
86
|
+
```
|
|
87
|
+
{baseUrl}/sp/recruit/talentView?batchId={candidateId}&recruitType=useSelf
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
**技能侧必须复刻**:`candidateId` 有值 → **不新建**,把 `talentViewUrl` 给用户。
|
|
91
|
+
|
|
92
|
+
**两级查重(推荐都用)**
|
|
93
|
+
|
|
94
|
+
| 级别 | 接口 | 语义 | 用途 |
|
|
95
|
+
|---|---|---|---|
|
|
96
|
+
| ① 主 | `getCandidateByPhone` | 招聘业务:手机号是否**已绑定人才/应聘批次** | 与页面完全一致;命中直接给 `talentViewUrl` |
|
|
97
|
+
| ② 补 | `form/core/checkUnique` | 表单字段唯一性:返回所有同手机号 `formDataIds` | 捕捉**没有应聘批次的历史记录**和**已软删除但仍占用**(这类 ① 查不到,但保存时平台照样拦) |
|
|
98
|
+
|
|
99
|
+
`checkUnique` 请求与坑:
|
|
100
|
+
```http
|
|
101
|
+
POST /api/ebuilder/form/form/core/checkUnique
|
|
102
|
+
{ "dataDetail": { "content": "13800000002", "formField": { "id": "<手机号字段id>" } },
|
|
103
|
+
"module": "ebuilderform", "customParam": { "objId": "<人才表单objId>" } }
|
|
104
|
+
```
|
|
105
|
+
→ `data`:`{ "unique": false, "formDataIds": [<id>, …] }`(编辑场景再带 `dataDetail.formData.id` + `customParam.dataId` 排除自身)
|
|
106
|
+
|
|
107
|
+
1. **`formDataIds` 是 18 位大整数,JSON.parse 会丢精度**(`…448931` → `…449000`)→ 必须从原始响应文本正则提取 `/"formDataIds"\s*:\s*\[([^\]]*)\]/` 再取 `\d{10,}`;用解析后的数字会拿到错误 id(查详情直接 500)。
|
|
108
|
+
2. **范围含已软删除记录**:删了也拦新建。这类 id 读详情失败 → 归 `unreadable`,提示“被已删除记录占用,需清理回收站”。
|
|
109
|
+
|
|
110
|
+
**判定与行为**
|
|
111
|
+
| 情况 | 行为 |
|
|
112
|
+
|---|---|
|
|
113
|
+
| ① 命中(`candidateId`/`talentId` 有值) | **不新建**,`result: "duplicate"`,返回 `existingTalent{talentId, candidateId, talentViewUrl, talentCardUrl}`;若同时存在无批次记录,附在 `otherRecords` |
|
|
114
|
+
| ① 未命中、② 有可读记录 | **不新建**(平台保存会拦),列出 `formConflicts` |
|
|
115
|
+
| ① 未命中、② 只有不可读 id | 阻断:提示被已删除记录占用,清理回收站或改为更新 |
|
|
116
|
+
| 都没有 | 继续建档 |
|
|
117
|
+
|
|
118
|
+
> 不要用列表搜索代替:平台列表 `commonSearchFields` 服务端筛选不可靠(实测「列表查无重复,checkUnique 返回 2 条」)。
|
|
119
|
+
|
|
120
|
+
#### 4.4.2 建档(主表 + 明细一次写入)
|
|
121
|
+
|
|
122
|
+
**首选:OpenAPI 数据集接口**——这是**唯一支持明细表**的写入通道(`form/core/saveFormData` 的 `dataDetails` 不接收 DetailTable,见 §4.10)。
|
|
123
|
+
```http
|
|
124
|
+
POST /api/ebuilder/form/dataset/v2/saveFormData
|
|
125
|
+
```
|
|
126
|
+
```json
|
|
127
|
+
{ "datajson": {
|
|
128
|
+
"datas": [{
|
|
129
|
+
"mainTable": { "candidate_name": "张三", "telephone": "138...", "channel": "<字典optionId>" },
|
|
130
|
+
"detail2": [{ "school": "郑州大学", "edu_education": "<字典optionId>" }],
|
|
131
|
+
"detail6": [{ "sx_co_name": "某公司", "position_job": "助理", "entry_time": "2023-04-01" }]
|
|
132
|
+
}],
|
|
133
|
+
"header": { "objId": "<人才表单 objId>" },
|
|
134
|
+
"operationinfo": { "fieldNoFindIgnore": "true", "doAction": "false" } } }
|
|
135
|
+
```
|
|
136
|
+
- `mainTable` 与明细行的键**必须用 `config.dataKey`**;自定义字段的 `name` 可能等于 id,用 `name` 会被**静默忽略**(响应仍成功)。
|
|
137
|
+
- 明细节点名 `detail1..detailN` 由 `GET /api/ebuilder/form/dataset/v1/getTableMapping?objId=<objId>` 解析,**顺序 ≠ 布局顺序**(人才表单实测 `detail2` 才是教育背景),不得按名称或本地顺序编号。
|
|
138
|
+
- 返回 `data.datajson.dataIds[0]` = 记录 id(即 talentId)。
|
|
139
|
+
|
|
140
|
+
**降级路径(实测会触发,非异常)**:数据集新增被系统校验拦下时——例如系统内置手机号查重返回
|
|
141
|
+
`data.datajson.status=false` + `data.datajson.message="第1条数据查重不通过[【手机号码】…]"`(**外层 `message.msg` 仍为 success,不能拿它判断结果**)——
|
|
142
|
+
改为 `form/core/saveFormData` 建主表 → `POST /api/ebuilder/form/dataset/v2/updateFormData` **追加**明细(新建记录明细为空,不传 `cover`——cover 会重建行并清空关联列,见 §4.10)。
|
|
143
|
+
两条路径记录 id 语义一致;脚本输出 `writeChannel` 标明实际走的通道,`writeWarnings` 记录降级原因。
|
|
144
|
+
|
|
145
|
+
**建档后**:`initTalentBatch?formDataId=`(初始化人才批次)。
|
|
146
|
+
|
|
147
|
+
### 4.5 ⑥ 触发智能标签规则匹配
|
|
148
|
+
| 字段 | 位置 | 类型 | 必填 | 说明 |
|
|
149
|
+
|---|---|---|---|---|
|
|
150
|
+
| `talentId` | **query** | string | 是 | 新人才 id(= ⑤ 的 `formDataId`) |
|
|
151
|
+
| (body) | body | `{}` | — | 空对象;**参数只能放 query,放 body 会 400** |
|
|
152
|
+
|
|
153
|
+
→ `data = "SUCCESS"` 表示已触发后台按「人才自动标签」规则(系统设置 → 自动标签)匹配。
|
|
154
|
+
|
|
155
|
+
### 4.6 写入平台标签(人才卡片上的"公共标签")
|
|
156
|
+
**标签清单**:`POST /api/my/tag/query`,body `{ "type":0, "name":"", "order":8, "pageSize":30, "pageNo":1, "search":1, "tagGroup":0, "tagModules":["ebuilderform"] }`
|
|
157
|
+
→ `data.data[]` = `{ tagId, name, type, color, tagModules, … }`(`type` 0=公共 / 1=个人)。
|
|
158
|
+
|
|
159
|
+
**打标签**:`POST /api/my/tag/common/batchAddEntityTag`
|
|
160
|
+
```json
|
|
161
|
+
{ "tags": [ { "id": "<标签tagId>", "name": "<标签名>", "type": 0 } ],
|
|
162
|
+
"batchDatas": [ { "entityId": "<talentId>", "module": "ebuilderform" } ] }
|
|
163
|
+
```
|
|
164
|
+
→ `{ "code":200, "status":true }`。一次可传多个标签、多个实体。
|
|
165
|
+
|
|
166
|
+
**去标签**:`POST /api/my/tag/common/removeEntityTag`(**请求体结构同上**)→ 已实测可正常移除。
|
|
167
|
+
|
|
168
|
+
**读回**:`POST /api/my/tag/common/queryEntityTag`,body `{ "entityId":"<talentId>", "module":"ebuilderform", "type":0 }`
|
|
169
|
+
→ `data[]` = `{ id, **content**(标签名), type, color, entityId, tagCreateTime }`(`type` 1 为个人标签;为空表示无标签)。
|
|
170
|
+
|
|
171
|
+
> **⚠️ 标签必须动态化(关键)**:**各环境标签 id 不同,绝不写死**。标签一律**按名称**指定,脚本运行时从 `/api/my/tag/query` 拉取本环境清单解析成 `tagId`;
|
|
172
|
+
> 1. **先确认存在再写**:`--prepare` 会输出 `tagCheck {requested, found, missing, availableInEnv}`——`missing` 里的标签本环境没有,提交时**一律跳过(不臆造、不自动创建)**;
|
|
173
|
+
> 2. 查本环境有哪些标签:`node scripts/recruit-resume-import.mjs --list-tags` → `{count, tags:[{name, tagId, type}]}`;
|
|
174
|
+
> 3. 匹配按 `name`(去空格、忽略大小写,`C9` ≡ `c9`);同名同时存在于公共/个人标签时**优先公共**;
|
|
175
|
+
> 4. 脚本参数:`--tag <标签名>`(可重复)。
|
|
176
|
+
|
|
177
|
+
### 4.9 人才表单保存动作(建人才后是否要补动作流)
|
|
178
|
+
|
|
179
|
+
实测某环境「保存」按钮共 **7 条动作,其中 3 条为 `enable=0`(禁用)**:
|
|
180
|
+
|
|
181
|
+
| 顺序 | 类型 | 名称 | enable | 脚本处理 |
|
|
182
|
+
|---|---|---|---|---|
|
|
183
|
+
| 0 | jsCode | 校验 | **0** | 跳过(禁用) |
|
|
184
|
+
| 1 | confirmBox | — | **0** | 跳过(禁用) |
|
|
185
|
+
| 2 | system | 保存 | 1 | = `saveFormData` ✅ |
|
|
186
|
+
| 3 | jsCode | js新建人才批次 | 1 | ecode 内调 `initTalentBatch` ✅ |
|
|
187
|
+
| 4 | jsCode | 关闭新建窗口 | 1 | UI,跳过 |
|
|
188
|
+
| 5 | openpage | — | 1 | 跳页,跳过 |
|
|
189
|
+
| 6 | customInterface | 新建人才初始化批次 | **0** | 跳过(禁用;`interfaceType=init_talent_batch`,与 ③ 同义但页面本就不执行) |
|
|
190
|
+
|
|
191
|
+
**结论**:人才表单**没有 esb 动作流**,写动作只有「保存 + 初始化批次」,脚本均已等价执行;第 6 条因禁用不会造成重复初始化。
|
|
192
|
+
**加固**:`write-op.mjs::runSaveButtonEsbActions()` 在建人才后会执行「保存」按钮里的 **esb** 动作(禁用项自动排除);当前环境返回空数组,将来若配了动作流会自动生效。
|
|
193
|
+
|
|
194
|
+
### 4.10 明细表(教育背景 / 工作经历 / 项目经验 / 实习经历 / 获奖经历 / 语言能力)
|
|
195
|
+
|
|
196
|
+
> **状态(2026-10-21 已打通并实测)**:明细**只能**走 OpenAPI 数据集接口 `dataset/v2/saveFormData` / `updateFormData`。
|
|
197
|
+
> `form/core/saveFormData` 的 `dataDetails` 会**静默丢弃** DetailTable 节点(实测 9 种结构:平铺 `rowId` / 纯 `dataIndex` / `dataStatus` / `id` / `formField+subFormId` / 嵌套 `dataDetails` / 顶层 `subFormData` / 明细组件 id / 换「新建人才」布局,读回子表全为 0)。
|
|
198
|
+
> 某环境实测:一次写入后读回 4 行 11 格(教育 1 行、实习 2 行、语言 1 行),主表 12 字段齐全。
|
|
199
|
+
|
|
200
|
+
**字段来源:布局 + 映射,全部运行时解析,不写死**
|
|
201
|
+
- 子表:`getFormLayoutMeta(talentFormId)` → `formLayout.pageLayouts[0].comps` 中 `type=DetailTable` 的组件:`config.dataKey`(如 `rcrt_education_exp`)+ `config.subFormId`
|
|
202
|
+
- 列:`config.subFormId` 等于该子表 id 的组件 → `config.dataKey`(列名,提交用)+ `config.fieldId`(读回核对用)+ 组件 `type`(Text / Select / EBuilder / **DateRange**…)
|
|
203
|
+
- 节点名:`getTableMapping(objId)` 取 `detailN ↔ subFormId`,再用 `invertTableMapping` 反查。**detailN 编号随表单结构变化,每次运行现取**
|
|
204
|
+
|
|
205
|
+
**日期区间(DateRange / DateInterval)——一个组件 = 两个物理字段**
|
|
206
|
+
布局里该组件的 `start` / `end` 各带独立 `dataKey`,提交时必须拆成两键:
|
|
207
|
+
|
|
208
|
+
| 项 | 值(某环境实测) |
|
|
209
|
+
|---|---|
|
|
210
|
+
| 组件 dataKey | `study_date`(DateRange,fieldId `…708`) |
|
|
211
|
+
| 开始 | `start.dataKey = study_date_0`,fieldId `…709` |
|
|
212
|
+
| 结束 | `end.dataKey = study_date_1`,fieldId `…081` |
|
|
213
|
+
| 提交 | `{ "study_date_0": "2020-09-01", "study_date_1": "2024-06-30" }` |
|
|
214
|
+
|
|
215
|
+
脚本从布局 `config.start.dataKey` / `config.end.dataKey` 运行时取,**不按 `_0/_1` 命名规律硬编码**;值为 `起始,结束` 或数组,脚本拆两键。读回实证:教育背景 4 格(学校 / 学历 / 起 / 止)全部落库。
|
|
216
|
+
|
|
217
|
+
**提交形态(数据集接口,扁平 JSON)**
|
|
218
|
+
```json
|
|
219
|
+
{ "detail2": [ { "school": "郑州大学", "edu_education": "<字典optionId>", "study_date": "…" } ] }
|
|
220
|
+
```
|
|
221
|
+
- 每行一个对象,键 = 列 `dataKey`,值 = 标量
|
|
222
|
+
- 选择/关联类传 `optionId`(不是名称);长文本直接传原文(无需 `dataText`)
|
|
223
|
+
|
|
224
|
+
**固定字段(本能力,已生效)**
|
|
225
|
+
| 字段 | 标题 | 固定值 | 取值方式 |
|
|
226
|
+
|---|---|---|---|
|
|
227
|
+
| `channel` | **简历来源** | **手动录入** | 数据字典 `cache.dict.by_name['手动录入']`(跨环境 id 不同,运行时取;显式 `--channel` 可覆盖) |
|
|
228
|
+
| `is_blacklist` | 是否黑名单 | **否** | `field_options[objId][is_blacklist]` 按名称反查 optionId |
|
|
229
|
+
|
|
230
|
+
**脏值防护**:简历解析对 Select 类字段常返回「序号」(如 `degree=4`、`sx_work_type=2`),不是 optionId → **一律跳过不写**;只有 ≥6 位的字典/关联 id 才写,并从字典反查名称确认存在。
|
|
231
|
+
|
|
232
|
+
**写入语义(实测,容易踩)**
|
|
233
|
+
- `updateFormData` 的明细默认是**追加**,不是覆盖。重复调用会产生多行(曾把教育背景写成 7 行)。
|
|
234
|
+
- 需要覆盖整表时传 `operationinfo.operateType = {"detailN":"cover"}`;但 **cover 会重建整行,把 `EBuilder`(关联)列清空** → 新建记录(明细本来为空)一律走“追加”,不用 cover。
|
|
235
|
+
- 页面 `form/core/saveFormData` 其实**也能写子表**:子表节点字段名是 **`subForm:{id}`**,不是 `subFormId`(此前 9 种结构全部失败,就是因为用了后者)。数据集接口不可用时可按此格式回退:
|
|
236
|
+
```json
|
|
237
|
+
{ "dataIndex": 1, "rowId": "<18位行id>", "formField": { "id": "<列fieldId>" }, "subForm": { "id": "<subFormId>" }, "content": "郑州大学" }
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### 4.11 按简历更新已有人才(`--update-talent <talentId>`)
|
|
241
|
+
|
|
242
|
+
查重命中后(见 §4.4.1),如果用户选择「用这份简历更新这个人」,走本节。
|
|
243
|
+
|
|
244
|
+
**策略(已与用户确认)**
|
|
245
|
+
| 对象 | 策略 | 说明 |
|
|
246
|
+
|---|---|---|
|
|
247
|
+
| 主表 | **B 全量覆盖** | 简历解析出的字段全部写入,覆盖原值(含人工修正) |
|
|
248
|
+
| 明细 | **整表覆盖** | 仅覆盖「这份简历解析出数据的子表」;没解析出数据的表**保留原样**(不因解析缺失清空历史数据) |
|
|
249
|
+
|
|
250
|
+
**接口**:`POST /api/ebuilder/form/dataset/v2/updateFormData`
|
|
251
|
+
```json
|
|
252
|
+
{ "datajson": {
|
|
253
|
+
"datas": [{ "mainTable": { "id": "<talentId>", "<dataKey>": "<值>" },
|
|
254
|
+
"detail2": [ { "school": "…", "study_date_0": "…", "study_date_1": "…" } ] }],
|
|
255
|
+
"header": { "objId": "<人才表单objId>" },
|
|
256
|
+
"operationinfo": {
|
|
257
|
+
"updateType": "ids", "fieldNoFindIgnore": "true", "needAdd": "false", "doAction": "false",
|
|
258
|
+
"operateType": { "detail2": "cover", "detail6": "cover" } } } }
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
**保护字段(简历无权覆盖)**:`is_blacklist`(黑名单是人工判定)、`recruit_status`、`candidate_status`、`data_status` → 写入前剔除,输出 `protectedSkipped`。
|
|
262
|
+
|
|
263
|
+
**流程**:`--prepare` 只出差异,`--commit` 才写。
|
|
264
|
+
|
|
265
|
+
```bash
|
|
266
|
+
node recruit-resume-import.mjs --prepare --update-talent <talentId> --resume-file <简历>
|
|
267
|
+
node recruit-resume-import.mjs --commit --update-talent <talentId> --resume-file <简历>
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
`--prepare` 输出(`mode: "prepare-update"`):
|
|
271
|
+
| 字段 | 含义 |
|
|
272
|
+
|---|---|
|
|
273
|
+
| `changes[]` | 将修改的字段:`{field, old, new, change}`,`change` = `overwrite`(覆盖原值)/ `fill`(原来空)/ `replace-attachment`(附件替换) |
|
|
274
|
+
| `unchanged[]` | 值相同、不会变的字段 |
|
|
275
|
+
| `details[]` | `{table, node, oldRows, newRows, action:"cover"}` |
|
|
276
|
+
| `detailPreview` | 实际要写入的第一行(便于核对字段是否齐全) |
|
|
277
|
+
| `keptTables[]` | 简历没解析出数据、因此保持原样的明细表 |
|
|
278
|
+
| `protectedSkipped[]` | 受保护未写的字段 |
|
|
279
|
+
|
|
280
|
+
`--commit` 输出 `mode: "update"`:`applied[]`(实际写入的差异)、`afterSummary`(读回的主表字段数 + 各子表行数/格数)、`verifyWarnings`(行数或格数不符时才出现)、`talentViewUrl` / `talentCardUrl`。
|
|
281
|
+
|
|
282
|
+
**两个实现坑(都已处理)**
|
|
283
|
+
1. **diff 口径必须统一**:快照里读到的是**展示值**(`本科`),待写的是 **optionId**(`840781591084286006`),直接比较会把「没变」误报成「覆盖」。脚本把待写值反查成展示值(字典 → 字段选项 → 原值)再比。
|
|
284
|
+
2. **自检要比「格数」不只「行数」**:`cover` 重建行时若字段漏传,行数照样对、字段却没了。脚本按 `期望格数 = Σ 该行键数` 校验;落库有短暂延迟,首读不符会等 600ms 重读再判定,避免误报。
|
|
285
|
+
|
|
286
|
+
> 更新不重跑 `initTalentBatch`、不动标签、不触发「保存」按钮动作流——这些属于人事流程,简历更新不应改变。
|
|
287
|
+
|
|
288
|
+
## 5. 响应数据结构
|
|
289
|
+
解析结果 `data.data` 实测字段:
|
|
290
|
+
| 字段 | 说明 |
|
|
291
|
+
|---|---|
|
|
292
|
+
| `candidateName` / `telephone` / `email` | 姓名 / 手机 / 邮箱 |
|
|
293
|
+
| `birthday`(yyyy-MM-dd) / `age` / `gender` / `genderName` | 生日 / 年龄 / 性别 id / 性别名 |
|
|
294
|
+
| `highest_degree` / `highest_degree_name` / `highest_degree_new` | 最高学历 id / 名 / 层级 |
|
|
295
|
+
| `college` / `joinworkdate` / `graduate_date` | 院校 / 参工时间 / 毕业时间 |
|
|
296
|
+
| `intend_position` / `intended_workplace` | 期望职位 / 期望地 |
|
|
297
|
+
| `jobInformations[]`(work_position/co_name/start_end_date/work_desc) | 工作经历 |
|
|
298
|
+
| `academicInformations[]`(school/edu_major/edu_education(_name)/study_date/degree) | 教育经历 |
|
|
299
|
+
| `projectExperiences[]` | 项目经历 |
|
|
300
|
+
| `self_desc` / `nativePlace` / `languageAbilities[]` | 自评 / 籍贯 / 语言能力 |
|
|
301
|
+
|
|
302
|
+
## 6. 请求示例(脚本)
|
|
303
|
+
```bash
|
|
304
|
+
# ① 先看本环境有哪些标签(各环境 id 不同,勿写死)
|
|
305
|
+
node scripts/recruit-resume-import.mjs --list-tags
|
|
306
|
+
|
|
307
|
+
node scripts/recruit-resume-import.mjs --prepare --resume-file <本地简历路径> [--channel <渠道>] [--tag <标签名> ...]
|
|
308
|
+
node scripts/recruit-resume-import.mjs --commit ...同参数...
|
|
309
|
+
# 或复用已上传文件:--fileid <已上传的 fileid>
|
|
310
|
+
# --tag 可重复;按名运行时解析,名字不在本环境标签清单 → 进 tagsSkipped,不写入、不自动创建
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
## 7. 响应示例(脚本)
|
|
314
|
+
```json
|
|
315
|
+
// --prepare(节选)
|
|
316
|
+
{ "mode": "prepare", "action": "简历导入建人才",
|
|
317
|
+
"parsed": { "name": "张三", "mobile": "138…", "degree": "本科", "college": "…", "intendPosition": "…", "jobCount": 2 },
|
|
318
|
+
"mappedFieldCount": 8, "dup": "无重复", "willTag": ["双一流", "985"] }
|
|
319
|
+
// --commit(节选,某环境实测)
|
|
320
|
+
{ "mode": "commit", "result": "success",
|
|
321
|
+
"newCandidateFormDataId": "1328698422856851556", "talentId": "1328698422856851556",
|
|
322
|
+
"writeChannel": "form/core/saveFormData(主表)+ dataset/v2/updateFormData(明细)",
|
|
323
|
+
"writeWarnings": ["数据集新增未通过(dataset saveFormData 失败:第1条数据查重不通过[【手机号码】…]),改为建主表后用数据集 update 补明细"],
|
|
324
|
+
"subTablesExpected": { "rcrt_education_exp": 1, "rcrt_sxjl": 2, "rcrt_language_skill": 1 },
|
|
325
|
+
"subTableVerify": { "cells": 11, "rowTotal": 4,
|
|
326
|
+
"rowsBySubFormId": { "902648950010994690": 2, "840760953917423619": 1, "840760953917423617": 1 } },
|
|
327
|
+
"initTalentBatch": "操作成功",
|
|
328
|
+
"labelMatch": "SUCCESS",
|
|
329
|
+
"tagsApplied": ["211", "双一流", "本科"], "tagsSkipped": [], "tags": ["双一流", "本科", "211"],
|
|
330
|
+
"talentCardUrl": "…/sp/ebdpage/view/<ebdDetailPageId>?talentId=1328698422856851556",
|
|
331
|
+
"artifactMark": "<artifact>[{\"file_name\":\"张三的人才卡片\",\"file_type\":\"url\",\"url\":\"…\"}]</artifact>" }
|
|
332
|
+
```
|
|
333
|
+
> `subTableVerify` 是**读回**结果(不是写入返回),行数与 `subTablesExpected` 对不上时 `writeWarnings` 会明确写出“明细行未落库”。
|
|
334
|
+
|
|
335
|
+
查重命中(手机号已绑定人才)时**不写入任何数据**,直接给页面同款跳转地址:
|
|
336
|
+
```json
|
|
337
|
+
{ "mode": "commit", "result": "duplicate",
|
|
338
|
+
"message": "当前手机号已绑定人才信息,按页面规则不新建(未写入任何数据)",
|
|
339
|
+
"existingTalent": {
|
|
340
|
+
"talentId": "1328706583328448931",
|
|
341
|
+
"candidateId": "1328706587556308193",
|
|
342
|
+
"talentViewUrl": "…/sp/recruit/talentView?batchId=1328706587556308193&recruitType=useSelf",
|
|
343
|
+
"talentCardUrl": "…/sp/ebdpage/view/<ebdDetailPageId>?talentId=1328706583328448931"
|
|
344
|
+
},
|
|
345
|
+
"talentViewUrl": "…/sp/recruit/talentView?batchId=1328706587556308193&recruitType=useSelf",
|
|
346
|
+
"otherRecords": [ { "talentId": "1127868230445834244", "name": "张三", "mobile": "13800000002" } ],
|
|
347
|
+
"nextStep": "如需按这份简历更新该人才,明确说明即可(走 dataset/v2/updateFormData)" }
|
|
348
|
+
```
|
|
349
|
+
> `talentViewUrl` 与页面代码块 `window.open` 的地址完全一致;`otherRecords` 是人才库里同号但**没有应聘批次**的记录(页面不提示,但保存时表单纯唯一性会拦)。
|
|
350
|
+
|
|
351
|
+
## 8. 错误码
|
|
352
|
+
| 错误码 | 含义 | 处理 |
|
|
353
|
+
|---|---|---|
|
|
354
|
+
| 上传 500 `exception_…` | ① 未带 file / ② 缺 name·MD5·lastModified | 补全 multipart 字段后重试(**非参数名错误,是本能力实测踩过的坑**) |
|
|
355
|
+
| 预检 `data=false` | RPA 不可用 / 未开启抽取 | 停止,提示在 E10 后台启用或手动录入 |
|
|
356
|
+
| 解析空 `data.data` | 文件非简历 / 解析失败 | 提示"未能解析出简历信息,请确认文件为简历" |
|
|
357
|
+
| 查重命中 | 手机号已存在 | **不新建重复**,提示已存在并询问是否改为修改 |
|
|
358
|
+
|
|
359
|
+
## 9. 调用参考(含标签识别)
|
|
360
|
+
- **流程**:上传(①②)→ 预检(③)→ 解析(④)→ **字段映射**(解析字段 → 人才表单 dataKey)→ 查重 → 展示摘要 → 用户确认 → 建档(⑤)。
|
|
361
|
+
- **字段映射规则**:
|
|
362
|
+
- **文本类** → `content`:`candidate_name` / `telephone` / `email` / `birthday` / `age` / `college` / `joinworkdate` / `graduate_date` / `intend_position` / `current_position`(取 `jobInformations[0].work_position`);
|
|
363
|
+
- **字典引用类** → `dataOptions[{optionId,content}]`:`gender`(用解析返回的 `gender` id)、`highest_degree`(用 `highest_degree` id);
|
|
364
|
+
- **未映射到的字段不传**(避免写错)。
|
|
365
|
+
- **标签(识别 + 自动打标签)**:分两套体系,**不要混用**——
|
|
366
|
+
| 体系 | 清单 | 写入 | 读取 |
|
|
367
|
+
|---|---|---|---|
|
|
368
|
+
| **招聘智能标签**(规则自动打标,系统设置→自动标签;如 c9/双一流/211/985) | `GET /api/recruit/label/getSystemLabels` → `[{id,labelId,labelName,labelKey,…}]` | **`POST /api/recruit/label/matchTalentLabel?talentId=<id>`**(body `{}`)→ `data:"SUCCESS"`(触发后台按规则匹配) | — |
|
|
369
|
+
| **平台标签**(人才卡片上的"公共标签/个人标签") | `POST /api/my/tag/query`(§4.6) | **`POST /api/my/tag/common/batchAddEntityTag`**(§4.6,`tags:[{id,name,type}]` + `batchDatas:[{entityId,module}]`)/去标签 `removeEntityTag` | `POST /api/my/tag/common/queryEntityTag`(`data[].content`=标签名) |
|
|
370
|
+
- **AI(脚本 `--tag`)**:AI 读解析结果判标签名(技能/年限/行业/院校层级,如"上海交通大学"→"985"/"双一流"),传给脚本 → 脚本**运行时按名解析本环境 tagId** → `batchAddEntityTag` 写入 → 读回回显。**提交前先看 `--prepare` 的 `tagCheck`(found/missing)确认标签确实存在**;不在清单的进 `tagsSkipped`,不写、不自动创建。
|
|
371
|
+
- ⚠️ **早期误用的接口**:曾试 `POST /api/recruit/label/batchAddTagIdsForEntityIds {tagIds,entityIds}` — **不要再用**(两种 id 口径均无效果:`labelId`→"批量添加标签失败",记录 `id`→返回成功但读不到)。**正确入口是 `/api/my/tag/common/batchAddEntityTag`**(2026-10-13 由页面打标签抓包坐实)。
|
|
372
|
+
- **简历卡片**:解析结果按"姓名→手机→学历/院校→期望职位→工作/教育经历"结构化展示为卡片,不贴原始 JSON。
|
|
373
|
+
|
|
374
|
+
## 10. 注意事项
|
|
375
|
+
- **写操作确认**:必须展示"解析结果 + 字段映射 + 查重结果"摘要并获确认后再提交。
|
|
376
|
+
- **上传两步缺一不可**:`preUploadCheck`(带 file)→ `module/upload`(带 name/MD5/lastModified + preUploadId/uploadType + file);**任一必填缺失即 500**(本能力实测结论)。
|
|
377
|
+
- **附件字段**:`original_resume` 为 `FileComponent`,写法 `dataOptions:[{optionId:<fileid>,content:<文件名>,type:'file'}]`。
|
|
378
|
+
- **不臆造**:字段 id 运行时解析;字典类字段用解析返回的 id 或字典反查,不硬编码。
|
|
379
|
+
- **标签 id 绝不写死**:各环境标签 id 不同;一律按名称 → 运行时查 `/api/my/tag/query` 解析 → 写入前先确认存在(`tagCheck`);不存在则跳过,**不自动创建标签**。查清单用 `--list-tags`(公共+个人都在清单里,同名优先公共)。
|
|
380
|
+
- **「自动打标签」的口径(2026-10-22)**:平台标签来源 = `--tag`(显式传入)+ **学校归属自动推导**(脚本按内置教育部权威名单 `scripts/school-tiers.json` 从毕业院校判 985/211/双一流,校名也作候选;`--no-school-tags` 关闭)。推导结果与清单求交后写入:系统里不存在的自动 skip(`tagsSkipped`),不臆造、不自动创建。`matchTalentLabel` 只触发 E10 后台**预配置**的智能标签规则,未配置/未命中时不会有标签——两者互不影响。
|
|
381
|
+
- **标签清单勿全量回灌**:自用环境公共标签量巨大,`--prepare` 的 tagCheck 只输出 `found/missing/availableCount`(不回灌全量清单);确需清单用 `--list-tags`。
|
|
382
|
+
- **依赖**:完整流程需浏览器/小E 侧能提供简历文件(本地路径或已上传 `fileid`)。
|
|
383
|
+
- 数据依据:2026-10-13 真机实测 `--prepare`(解析英文简历 → 映射 8 字段)与 `--commit`(新建人才 `newCandidateFormDataId=1325731833091235842`、`initTalentBatch=操作成功`)全通过;同日实测 `--commit` 新输出(talentId=`1325740272676806661`、`labelMatch=SUCCESS`、`talentCardUrl`/`artifactMark` 生成正常),并用浏览器打开 `talentCardUrl` 验证人才卡片正常渲染;同日**标签写/读/删闭环实测通过**(`--tag 双一流 --tag 985 --tag 不存在标签` → `tagsApplied=["双一流","985"]`、`tagsSkipped=["不存在标签"]`、读回 `tags=["双一流","985"]`;`removeEntityTag` 移除后读回同步消失)。
|
|
384
|
+
|
|
385
|
+
## 11. 产物输出(小E 场景,等同"人才管理里点姓名")
|
|
386
|
+
`--commit` 成功后额外输出产物,用于对话里给用户可点击入口:
|
|
387
|
+
|
|
388
|
+
| 产物 | 值 |
|
|
389
|
+
|---|---|
|
|
390
|
+
| `talentId` | 新人才 id(= `saveFormData` 的 formDataId) |
|
|
391
|
+
| `talentCardUrl` | `{baseUrl}/sp/ebdpage/view/{ebdDetailPageId}?talentId={talentId}`(`ebdDetailPageId` 来自环境缓存;**自用系统**(缓存 selfUse='1')自动追加 `&recruitType=useSelf`,与 EHR 口径一致)——**人才卡片单页**(基本信息/应聘信息/备注/应聘过程 + 标签区 + 简历预览),效果与在「人才管理」列表点姓名完全一致 |
|
|
392
|
+
| `talentListLocateUrl` | `{baseUrl}/sp/ebdfpage/list/{listId}?talentId={talentId}&recruitType=useSelf`(`listId` 取环境缓存 `lists.talent.listId`;自用系统自动追加 `&recruitType=useSelf`)——**人才库列表并滑出该人才的详情单页**(2026-10-22 用户指定形态) |
|
|
393
|
+
| `talentListUrl` | 人才管理列表页(备用,不带定位) |
|
|
394
|
+
|
|
395
|
+
**用法(小E)**:在回答正文里以**两个普通 Markdown 链接**给出(输出契约见 `recruit-output-links.md`):
|
|
396
|
+
① `[查看 <姓名> 的人才卡片](<talentCardUrl>)` ② `[在人才库中打开](<talentListLocateUrl>)`;缺失哪个就只给另一个。
|
|
397
|
+
|
|
398
|
+
> ⚠️ **不要再用正文 `<artifact>` 标记**:2026-10-16 起平台自动打开桥改读 `clientFillResult.artifact`(平台 `save_artifact` 工具写入),正文标记会被剥离、不再生成卡片。脚本输出里的 `artifactMark` 字段**忽略即可**(保留只为兼容旧输出,勿搬运到正文)。
|
|
399
|
+
|
|
400
|
+
## 12. 小E 附件桥(上传简历触发时的文件通道,实验性)
|
|
401
|
+
小E 对话里上传简历后,平台侧只给**小E fileId**(`/rpa/api/upload` 服务族),不是 E10 `fileid`、也不是本地路径。桥接两步:
|
|
402
|
+
|
|
403
|
+
```bash
|
|
404
|
+
# ① 小E fileId → 本地文件(加密信封 + Authorization 已按平台前端契约复刻,见脚本头注释)
|
|
405
|
+
node scripts/recruit-xiaoe-file.mjs --fileid <小E文件id> --name "<原始文件名>.pdf"
|
|
406
|
+
# → { ok, localPath, size, contentType }
|
|
407
|
+
# ② 本地文件走既有导入链
|
|
408
|
+
node scripts/recruit-resume-import.mjs --prepare --resume-file <localPath> [--tag <标签名> ...]
|
|
409
|
+
node scripts/recruit-resume-import.mjs --commit ...同参数...
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
- **凭据已实测打通(2026-10-22)**:客户端 `user_settings.json` 自带 `authToken`(网页端同款下载鉴权)与 `public_key`(环境 RSA 公钥,密文/明文自适应),桥自动读取;平台注入与显式参数仍可覆盖。信封+鉴权已过服务端校验(复测错误从 4001 变为业务码)。
|
|
413
|
+
- **fileId 口径**:必须是**对话附件原件**(uploadFile 返回的 fileId);产物 id / aidoc 文档 id 会回 2001「文件不存在」。
|
|
414
|
+
- **降级路径(桥不通时必用)**:
|
|
415
|
+
1. 桌面端:请用户直接给简历**本地路径**(脚本在小E 客户端本机执行,路径可直接用)→ `--resume-file`;
|
|
416
|
+
2. 或请用户**粘贴简历文本**,AI 提取结构化信息后按 `recruit-new-candidate` 口径人工建档(本包未含该脚本时,如实告知改走 E10 页面建档)。
|
|
417
|
+
- 简历文件上传 E10 走脚本内部链路(`/api/file/preUploadCheck` → `/api/file/module/upload`),**沙箱里的小E fileId 不能直接传给 E10 接口**——两套文件服务 id 不互通,这就是需要桥的原因。
|
|
418
|
+
|
|
419
|
+
## 13. 文本直建模式(--structured-file):结构化简历 JSON schema
|
|
420
|
+
仅当原件拿不到、且用户明确同意「先建档、后补原件」时使用(附件字段会留空)。AI 从对话上下文按下面 schema 写 JSON 临时文件(拿不准的字段**留空或省略,不编造**;telephone 必填——查重主键):
|
|
421
|
+
|
|
422
|
+
```json
|
|
423
|
+
{
|
|
424
|
+
"candidateName": "姓名", "telephone": "手机号(必填)", "email": "",
|
|
425
|
+
"genderName": "男", "birthday": "YYYY-MM-DD", "age": 24,
|
|
426
|
+
"college": "毕业院校", "highest_degree_name": "本科",
|
|
427
|
+
"graduate_date": "2026-06", "joinworkdate": "", "intend_position": "", "intended_workplace": "",
|
|
428
|
+
"self_desc": "自我评价", "work_ability": "职业技能/技术栈",
|
|
429
|
+
"academicInformations": [{ "school": "", "edu_major": "", "edu_education": "本科", "study_date": "2022.09-2026.06", "faculty": "" }],
|
|
430
|
+
"jobInformations": [{ "co_name": "", "work_position": "", "work_desc": "", "start_date": "2025.06", "end_date": "" }],
|
|
431
|
+
"internshipExperiences": [{ "sx_co_name": "", "position_job": "", "job_description": "", "entry_time": "" }],
|
|
432
|
+
"projectExperiences": [{ "pj_name": "", "pj_role": "", "pj_duty": "", "pj_introduction": "", "start_date": "", "end_date": "" }],
|
|
433
|
+
"awardExperiences": [{ "award_name": "", "award_date": "" }],
|
|
434
|
+
"languageAbilities": [{ "language_type": "", "mastery": "" }]
|
|
435
|
+
}
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
脚本侧数据安全:字典类字段(学历/性别/工作类型/语言掌握度等)AI 给**名称** → 按数据字典**唯一命中**反查 optionId;歧义或缺失自动跳过(`structuredWarnings` 明示),绝不写脏值。原件后补:人才卡片页的简历附件字段可手工上传,或拿到原件后走 `--update-talent` 补。
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: recruit-resume-parse
|
|
3
|
+
description: 解析上传的简历文件(OCR 抽取),返回结构化简历数据(姓名/手机/邮箱/学历/工作/项目),用于快速建档前的信息预填(checkRpaValid + checkResumeExtraction + resumeExtraction)
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# 简历解析(OCR 导入)
|
|
7
|
+
|
|
8
|
+
> 本文档中的 `${...}` 形参(表单 objId / 列表 listId / EB 页面 viewId·pageId / 应用 appId / 动作流 id / 菜单 id cusMenuId)为**租户相关值**:表单 objId 经 `recruit-resolve-metadata.md` 的 tag 链运行时解析;列表/页面/菜单 id 由部署参数提供(**可经 `allMenus` 菜单树自动发现**,见 `recruit-resolve-metadata.md` §3.1);**字段 id(`formField.id`)经 `ds/fields` 运行时解析,不写死**(见 `recruit-resolve-metadata.md` §5)。本接口路径本身不含租户 ID,无需 token 化。
|
|
9
|
+
|
|
10
|
+
> **与「查看标准简历」区分**:本接口是**上传简历文件 → OCR 解析出结构化数据**(用于建档预填),属解析/导入能力;「查看标准简历」是人才库 EB 子表单(OBJID `${TALENT_FORM_OBJID}`,运行时按 tag 解析)的**浏览器显示**,由 EB 详情链接承载,无独立 API,仍属已知缺口(见 SKILL.md「已知缺口」),二者不是同一件事。
|
|
11
|
+
|
|
12
|
+
## 1. 基础信息
|
|
13
|
+
- 接口名称:简历解析(OCR 抽取,三步:RPA 可用性预检 → 功能开启预检 → 解析)
|
|
14
|
+
- 请求方式:`POST`(三步)
|
|
15
|
+
- 去域名路径:
|
|
16
|
+
- ① `/api/recruit/ocr/checkRpaValid`(RPA 抽取服务可用性预检)
|
|
17
|
+
- ② `/api/recruit/ocr/checkResumeExtraction`(简历抽取功能是否开启预检)
|
|
18
|
+
- ③ `/api/recruit/ocr/resumeExtraction`(上传/引用简历文件,返回结构化数据)
|
|
19
|
+
- 所属模块:招聘管理(recruit)
|
|
20
|
+
- 所属分组:人才库 / 解析(非写操作)
|
|
21
|
+
|
|
22
|
+
## 2. 业务用途
|
|
23
|
+
用户说"解析这份简历""把这份简历导入""从附件里提取候选人信息"时调用。先把简历文件上传拿到 `fileid`/`docId`,再做两步预检确认抽取能力可用,最后调 `resumeExtraction` 得到结构化简历(姓名/手机/邮箱/学历/工作/项目等)。解析结果**仅用于展示与建档预填**,本接口**不写库**;若要据此新建人才,须转入 `recruit-new-candidate.md` 并走查重 + 确认门。
|
|
24
|
+
|
|
25
|
+
## 3. 前置条件
|
|
26
|
+
- 已安装招聘服务(第 0 步闸门通过,见 `recruit-check-install.md`)。
|
|
27
|
+
- 简历文件已上传:先调 `/api/file/module/upload`(multipart,返回 `data.fileid` 与 `data.docId`),解析时引用该文件。(HAR 中 `resumeExtraction` 请求体未被文本捕获,其入参字段以实际返回为准,见 §4。)
|
|
28
|
+
- 两步预检:① `checkRpaValid` 返回 `data=true` 表示 RPA 抽取服务可达;② `checkResumeExtraction` 返回 `data=true` 表示简历抽取功能已开启。任一为 `false` 应停止并提示用户「当前环境未开通简历抽取,请在 E10 后台启用或手动录入」。
|
|
29
|
+
- `appId` 来自安装闸门 `getAppIds` 返回的 `data[0]`(上传接口的 `source=form` 等通用参数按现有实现传)。
|
|
30
|
+
|
|
31
|
+
## 4. 请求参数
|
|
32
|
+
|
|
33
|
+
### 4.1 第①步 checkRpaValid
|
|
34
|
+
| 字段 | 位置 | 类型 | 必填 | 业务说明 |
|
|
35
|
+
|---|---|---|---|---|
|
|
36
|
+
| (无) | body | json | — | 空对象 `{}`(实测) |
|
|
37
|
+
|
|
38
|
+
### 4.2 第②步 checkResumeExtraction
|
|
39
|
+
| 字段 | 位置 | 类型 | 必填 | 业务说明 |
|
|
40
|
+
|---|---|---|---|---|
|
|
41
|
+
| (无) | body | json | — | 空对象 `{}`(实测) |
|
|
42
|
+
|
|
43
|
+
### 4.3 第③步 resumeExtraction
|
|
44
|
+
| 字段 | 位置 | 类型 | 必填 | 业务说明 |
|
|
45
|
+
|---|---|---|---|---|
|
|
46
|
+
| `fileId` | **query** | string | 是 | 上传返回的 `fileid`(**实测:走 query 传参、无 body**) |
|
|
47
|
+
|
|
48
|
+
> 实测(HAR 2026-10-13):`POST /api/recruit/ocr/resumeExtraction?fileId=1300450135282491397`(无请求体)→ 返回结构化简历。
|
|
49
|
+
> 上传链路为**两步**:`POST /api/file/preUploadCheck`(multipart,**须含 file**)→ `POST /api/file/module/upload`(multipart,**须带 name/MD5/lastModified + preUploadId/uploadType + file**)→ `data.fileid`。完整"简历→人才"链路见 `recruit-resume-import.md`。
|
|
50
|
+
|
|
51
|
+
## 5. 响应数据结构
|
|
52
|
+
- 第①/②步:`data` = 布尔(`true` 表示可用/已开启)。
|
|
53
|
+
- 第③步:`data.data` 为结构化简历对象,实测字段:
|
|
54
|
+
| 字段 | 类型 | 说明 |
|
|
55
|
+
|---|---|---|
|
|
56
|
+
| `candidateName` | string | 姓名 |
|
|
57
|
+
| `telephone` | string | 手机号 |
|
|
58
|
+
| `email` | string | 邮箱(可能为空) |
|
|
59
|
+
| `birthday` | string | 出生日期 `yyyy-MM-dd` |
|
|
60
|
+
| `age` | number | 年龄 |
|
|
61
|
+
| `gender` / `genderName` | string | 性别 ID / 性别名称(`gender` 为枚举选项 ID,见 `data-dictionary.md`) |
|
|
62
|
+
| `highest_degree` / `highest_degree_name` / `highest_degree_new` | string | 最高学历 ID / 名称 / 层级 |
|
|
63
|
+
| `college` | string | 毕业院校 |
|
|
64
|
+
| `joinworkdate` | string | 参加工作时间 `yyyy-MM-dd` |
|
|
65
|
+
| `graduate_date` | string | 毕业时间 |
|
|
66
|
+
| `intend_position` | string | 期望职位 |
|
|
67
|
+
| `jobInformations` | array | 工作经历:`work_position`/`work_desc`/`start_end_date`/`co_name` |
|
|
68
|
+
| `academicInformations` | array | 教育经历:`school`/`edu_major`/`edu_education`(学历ID)/`edu_education_name`/`study_date`/`degree` |
|
|
69
|
+
| `projectExperiences` | array | 项目经历:`pj_name`/`pj_duty`/`pj_date`/`pj_introduction` |
|
|
70
|
+
|
|
71
|
+
## 6. 请求示例
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
// 第①步 RPA 可用性预检
|
|
75
|
+
POST /api/recruit/ocr/checkRpaValid
|
|
76
|
+
{}
|
|
77
|
+
|
|
78
|
+
// 第②步 功能开启预检
|
|
79
|
+
POST /api/recruit/ocr/checkResumeExtraction
|
|
80
|
+
{}
|
|
81
|
+
|
|
82
|
+
// 第③步 简历解析(先上传取 fileid,再以该 fileid 调解析)
|
|
83
|
+
// 上传(通用文件接口,返回 data.fileid / data.docId):
|
|
84
|
+
POST /api/file/module/upload (multipart: file=<简历.pdf>, source=form, ...)
|
|
85
|
+
// 解析(入参字段 HAR 未捕获,以下为示意,以实际返回为准,不臆测):
|
|
86
|
+
POST /api/recruit/ocr/resumeExtraction
|
|
87
|
+
{ "fileId": "<上传返回的 fileid>", "docId": "<上传返回的 docId>" }
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## 7. 响应示例
|
|
91
|
+
```json
|
|
92
|
+
// 第①/②步
|
|
93
|
+
{ "code": 200, "msg": "接口返回成功", "status": true, "data": true, "fail": false }
|
|
94
|
+
// 第③步(实测,节选)
|
|
95
|
+
{
|
|
96
|
+
"code": 200, "status": true,
|
|
97
|
+
"data": { "data": {
|
|
98
|
+
"candidateName": "刘航", "telephone": "13800000004", "email": "",
|
|
99
|
+
"birthday": "2001-01-01", "gender": "937153853968544578", "genderName": "女",
|
|
100
|
+
"highest_degree": "937153853968544595", "highest_degree_name": "本科",
|
|
101
|
+
"college": "齐鲁理工学院", "joinworkdate": "2022-06-01", "intend_position": "全栈工程师",
|
|
102
|
+
"jobInformations": [ { "work_position": "java全栈工程师", "co_name": "天津信之鸥科技有限公司",
|
|
103
|
+
"start_end_date": "2022-06-01,2025-08-01", "work_desc": "..." } ],
|
|
104
|
+
"academicInformations": [ { "school": "天津大学", "edu_major": "软件工程", "edu_education_name": "本科" } ],
|
|
105
|
+
"projectExperiences": [ { "pj_name": "天津联通安全生产管理信息化平台", "pj_duty": "JAVA全栈工程师" } ]
|
|
106
|
+
} }
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
## 8. 错误码
|
|
111
|
+
| 错误码 | 含义 | AI 处理建议 |
|
|
112
|
+
|---|---|---|
|
|
113
|
+
| `data=false`(预检) | RPA 服务不可用 / 功能未开启 | 停止解析,提示用户「当前环境未开通简历抽取,请在 E10 后台启用或手动录入」 |
|
|
114
|
+
| 非 200 / 重定向 | 认证过期或接口异常 | 提示走 `weaver-work-cli auth login` 登录;不臆测错误,原样回退 |
|
|
115
|
+
| 解析返回空 `data.data` | 文件非简历 / 解析失败 | 提示「未能从文件中解析出简历信息,请确认文件为简历或手动录入」 |
|
|
116
|
+
|
|
117
|
+
## 9. 调用参考
|
|
118
|
+
- 用户场景:"解析这份简历""把附件里的候选人信息提取出来"。
|
|
119
|
+
- **流程**:① `/api/file/module/upload` 上传简历 → ② `checkRpaValid` → ③ `checkResumeExtraction` → ④ `resumeExtraction` 取结构化数据 → 展示给用户(姓名/手机/邮箱/学历/工作/项目)。
|
|
120
|
+
- **展示要点**:姓名→手机→邮箱首行(邮箱空不拼);学历/性别以 `*Name` 标签字段为准(枚举 ID 见 `data-dictionary.md`);工作经历/教育/项目用简洁列表,不贴原始 JSON。
|
|
121
|
+
- **不写库**:本接口只解析;据此建档必须转入 `recruit-new-candidate.md`,并先走手机号查重 + 确认门。
|
|
122
|
+
|
|
123
|
+
## 10. 注意事项
|
|
124
|
+
- **非写操作**:解析本身不入人才库,无需确认门;但解析结果用于建档时,建档仍须走 `recruit-new-candidate.md` 的查重与确认门。
|
|
125
|
+
- **预检不可省**:两步 `check*` 任一为 `false` 即停止,避免对未开通环境空跑解析。
|
|
126
|
+
- **入参已实证(2026-10-13)**:`resumeExtraction` 的 `fileId` 走 **query**、**无 body**;上传为两步(`preUploadCheck`(须带 file)→ `module/upload`(须带 name/MD5/lastModified + preUploadId/uploadType)),任一必填缺失即 500。完整"简历→人才"链路(含字段映射/建档/标签识别)见 `recruit-resume-import.md`。
|
|
127
|
+
- **枚举 ID 处理**:`gender`/`highest_degree` 等为租户枚举选项 ID,显示用 `*Name` 标签字段,原始 ID 见 `data-dictionary.md`,未知 ID 原样回退。
|
|
128
|
+
- **认证**:由 `weaver-work-cli` 托管的登录态提供地址与 `eteamsid` 头,本 Skill 不写死域名/凭证。
|