# Boss直聘搜索列表和投递功能开发规划 ## 📋 功能概述 基于Boss直聘Web端职位搜索页面(`https://www.zhipin.com/web/geek/jobs`),完善搜索列表获取和职位投递功能,包括服务端任务创建、指令生成和完整流程实现。 ## 🎯 目标功能 ### 1. 搜索列表功能 - 支持多条件搜索(关键词、城市、薪资、经验、学历等) - 支持分页获取职位列表 - 自动保存职位到数据库 - 支持职位去重和更新 ### 2. 投递功能 - 单个职位投递 - 批量职位投递 - 投递状态跟踪 - 投递记录管理 ## 📊 Boss直聘响应数据结构 ### 响应格式示例 Boss直聘搜索职位列表的响应数据结构如下: ```json { "code": 0, "message": "Success", "zpData": { "resCount": 450, // 搜索结果总数 "hasMore": true, // 是否还有更多 "totalCount": 300, // 总职位数 "jobList": [ // 职位列表 { "encryptJobId": "5ae70dfe114c23ab0nR-2ti-FFpU", // 职位ID(投递必需) "encryptBossId": "b55854108ac215180XZ62N-_FlNT", // Boss ID(投递必需) "securityId": "HP23zbQfaslvy-c1...", // 安全ID(投递必需) "jobName": "全栈软件工程师", // 职位名称 "salaryDesc": "25-50K·19薪", // 薪资描述(需解析) "jobExperience": "在校/应届", // 工作经验(需解析) "jobDegree": "学历不限", // 学历要求 "city": 101020100, // 城市代码 "cityName": "上海", // 城市名称 "areaDistrict": "长宁区", // 区域 "businessDistrict": "新华路", // 商圈 "gps": { // 位置信息(优先使用) "longitude": 121.41902537687392, "latitude": 31.210308153576566 }, "encryptBrandId": "d283b66de3cefd891H1529q5Flc~", // 公司ID "brandName": "上海大裂谷智能科技", // 公司名称 "brandScaleName": "100-499人", // 公司规模 "brandIndustry": "人工智能", // 公司行业 "brandStageName": "天使轮", // 融资阶段 "bossName": "杨明雨", // Boss姓名 "bossTitle": "HR", // Boss职位 "bossOnline": true, // Boss是否在线 "jobLabels": ["在校/应届", "学历不限"], // 职位标签 "skills": [], // 技能要求 "welfareList": ["带薪年假", "五险一金"], // 福利列表 "proxyJob": 0, // 是否外包(0否1是) "industry": 100028 // 行业代码 } ] } } ``` ### 关键字段说明 1. **投递必需字段**: - `encryptJobId`: 职位ID,投递时必须 - `encryptBossId`: Boss ID,投递时必须 - `securityId`: 安全ID,投递时必须(每次搜索可能不同) 2. **位置信息**: - `gps.longitude` 和 `gps.latitude`: 直接使用,无需调用位置服务API - 如果没有gps字段,再使用 `cityName + areaDistrict + businessDistrict + brandName` 调用位置服务 3. **薪资解析**: - `salaryDesc` 格式多样:`"25-50K·19薪"`、`"20-30K"`、`"面议"` 等 - 需要解析出 `salaryMin` 和 `salaryMax`(单位:元) 4. **工作年限解析**: - `jobExperience` 可能为:`"在校/应届"`、`"3-5年"`、`"1-3年"` 等 - 需要解析出 `experienceMin` 和 `experienceMax` ## 📊 功能架构 ``` 用户/系统触发 ↓ 创建任务 (task_status) ↓ 生成指令序列 (task_commands) ↓ 执行指令 (通过MQTT发送到设备) ↓ 设备执行并返回结果 ↓ 保存数据到数据库 ↓ 更新任务和指令状态 ``` ## 🔧 技术实现 ### 一、搜索列表功能完善 #### 1.1 指令参数扩展 **文件**: `api/middleware/job/jobManager.js` **方法**: `get_job_list()` **需要支持的参数**: ```javascript { keyword: '全栈工程师', // 搜索关键词 city: '101020100', // 城市代码(上海) cityName: '上海', // 城市名称 salary: '20-30K', // 薪资范围 experience: '3-5年', // 工作经验 education: '本科', // 学历要求 industry: '互联网', // 公司行业 companySize: '100-499人', // 公司规模 financingStage: 'B轮', // 融资阶段 page: 1, // 页码 pageSize: 20, // 每页数量 pageCount: 3 // 获取页数(用于批量获取) } ``` #### 1.2 任务创建接口 **文件**: `api/services/pla_account_service.js` **新增方法**: `createSearchJobListTask()` ```javascript /** * 创建搜索职位列表任务 * @param {Object} params - 任务参数 * @param {number} params.id - 账号ID * @param {string} params.keyword - 搜索关键词 * @param {string} params.city - 城市代码 * @param {Object} params.searchParams - 搜索条件(薪资、经验、学历等) * @param {number} params.pageCount - 获取页数 * @returns {Promise} 任务创建结果 */ async createSearchJobListTask(params) { // 1. 验证账号和授权 // 2. 创建任务记录 // 3. 生成搜索指令 // 4. 执行指令 // 5. 返回任务ID } ``` #### 1.3 指令生成逻辑 **文件**: `api/middleware/schedule/taskHandlers.js` **需要完善**: `handleAutoDeliverTask()` 中的搜索指令生成 **当前实现**: ```javascript const getJobListCommand = { command_type: 'getJobList', command_name: '获取职位列表', command_params: JSON.stringify({ sn_code: sn_code, keyword: keyword || accountConfig.keyword || '', platform: platform || 'boss', pageCount: pageCount || 3 }), priority: config.getTaskPriority('search_jobs') || 5 }; ``` **需要扩展为**: ```javascript const getJobListCommand = { command_type: 'get_job_list', // 统一使用下划线命名 command_name: '获取职位列表', command_params: JSON.stringify({ sn_code: sn_code, platform: platform || 'boss', keyword: keyword || accountConfig.keyword || '', city: city || accountConfig.city || '101020100', // 默认上海 cityName: cityName || accountConfig.cityName || '上海', salary: searchParams?.salary || '', experience: searchParams?.experience || '', education: searchParams?.education || '', industry: searchParams?.industry || '', companySize: searchParams?.companySize || '', financingStage: searchParams?.financingStage || '', page: 1, pageSize: 20, pageCount: pageCount || 3 }), priority: config.getTaskPriority('get_job_list') || 5, sequence: 1 }; ``` #### 1.4 职位数据保存优化 **文件**: `api/middleware/job/jobManager.js` **方法**: `saveJobsToDatabase()` **需要完善**: - 支持更多字段映射(从Boss直聘响应数据) - 优化位置解析逻辑 - 支持职位状态更新(已投递、已查看等) - 添加职位匹配度计算 ### 二、投递功能完善 #### 2.1 单个职位投递 **文件**: `api/middleware/job/jobManager.js` **方法**: `applyJob()` **当前状态**: ✅ 已实现基础功能 **需要完善**: - 支持更多投递参数(期望薪资、求职信等) - 优化错误处理 - 添加投递前检查(是否已投递、是否满足条件等) #### 2.2 批量职位投递任务 **文件**: `api/middleware/schedule/taskHandlers.js` **方法**: `handleAutoDeliverTask()` **当前状态**: ✅ 已实现基础功能 **需要完善**: 1. **搜索条件完善** - 支持城市、薪资、经验、学历等筛选条件 - 从账号配置中读取默认搜索条件 - 支持任务参数覆盖账号配置 2. **职位匹配算法优化** - 完善距离计算(基于经纬度) - 完善薪资匹配(解析薪资范围字符串) - 完善工作年限匹配 - 完善学历匹配 - 完善权重评分系统 3. **投递指令生成** - 为每个匹配的职位生成投递指令 - 支持批量投递(一次任务投递多个职位) - 添加投递间隔控制(避免频繁投递) #### 2.3 投递任务创建接口 **文件**: `api/services/pla_account_service.js` **新增方法**: `createDeliverTask()` ```javascript /** * 创建投递任务 * @param {Object} params - 任务参数 * @param {number} params.id - 账号ID * @param {string} params.keyword - 搜索关键词 * @param {Object} params.searchParams - 搜索条件 * @param {Object} params.filterRules - 过滤规则 * @param {number} params.maxCount - 最大投递数量 * @returns {Promise} 任务创建结果 */ async createDeliverTask(params) { // 1. 验证账号和授权 // 2. 创建任务记录 // 3. 生成搜索指令(获取职位列表) // 4. 生成投递指令序列(根据匹配结果) // 5. 执行任务 // 6. 返回任务ID } ``` ## 📝 具体开发任务 ### 任务1: 完善搜索参数支持 **文件**: `api/middleware/job/jobManager.js` **修改方法**: `get_job_list()` **任务内容**: 1. 扩展参数支持(城市、薪资、经验、学历等) 2. 构建完整的搜索参数对象 3. 传递给MQTT指令 **代码位置**: 第153-206行 **预计工作量**: 2小时 --- ### 任务2: 优化职位数据保存 **文件**: `api/middleware/job/jobManager.js` **修改方法**: `saveJobsToDatabase()` **任务内容**: 1. 完善字段映射(从Boss直聘响应数据提取更多字段) 2. 优化位置解析(优先使用响应中的gps字段,减少API调用) 3. 解析薪资范围(从salaryDesc提取min/max) 4. 解析工作年限(从jobExperience提取min/max) 5. 添加职位状态管理 6. 添加职位匹配度字段 **Boss直聘响应数据字段映射表**: | 响应字段 | 数据库字段 | 说明 | 示例值 | |---------|-----------|------|--------| | `encryptJobId` | `jobId` | 职位ID(加密) | "5ae70dfe114c23ab0nR-2ti-FFpU" | | `jobName` | `jobTitle` | 职位名称 | "全栈软件工程师" | | `encryptBrandId` | `companyId` | 公司ID(加密) | "d283b66de3cefd891H1529q5Flc~" | | `brandName` | `companyName` | 公司名称 | "上海大裂谷智能科技" | | `brandScaleName` | `companySize` | 公司规模 | "100-499人" | | `brandIndustry` | `companyIndustry` | 公司行业 | "人工智能" | | `brandStageName` | `brandStage` | 融资阶段 | "天使轮" | | `salaryDesc` | `salary` | 薪资描述 | "25-50K·19薪" | | `salaryDesc` | `salaryMin`, `salaryMax` | 薪资范围(需解析) | 25000, 50000 | | `jobExperience` | `experience` | 工作经验 | "在校/应届" | | `jobExperience` | `experienceMin`, `experienceMax` | 工作年限范围(需解析) | - | | `jobDegree` | `education` | 学历要求 | "学历不限" | | `jobDegree` | `educationLevel` | 学历等级(需映射) | - | | `city` | `city` | 城市代码 | 101020100 | | `cityName` | `cityName` | 城市名称 | "上海" | | `areaDistrict` | `areaDistrict` | 区域 | "长宁区" | | `businessDistrict` | `businessDistrict` | 商圈 | "新华路" | | `gps.longitude` | `longitude` | 经度(优先使用) | 121.41902537687392 | | `gps.latitude` | `latitude` | 纬度(优先使用) | 31.210308153576566 | | `encryptBossId` | `encryptBossId` | Boss ID(投递需要) | "b55854108ac215180XZ62N-_FlNT" | | `securityId` | `securityId` | 安全ID(投递需要) | "HP23zbQfaslvy-c1..." | | `bossName` | `bossName` | Boss姓名 | "杨明雨" | | `bossTitle` | `bossTitle` | Boss职位 | "HR" | | `bossOnline` | `bossOnline` | Boss是否在线 | true | | `jobLabels` | `jobLabels` | 职位标签(JSON) | ["在校/应届", "学历不限"] | | `skills` | `skills` | 技能要求(JSON) | ["Java", "MySQL"] | | `welfareList` | `welfareList` | 福利列表(JSON) | ["带薪年假", "五险一金"] | | `proxyJob` | `isOutsourcing` | 是否外包 | 0/1 | | `industry` | `industry` | 行业代码 | 100028 | **关键优化点**: 1. **位置信息**: 优先使用响应中的 `gps.longitude` 和 `gps.latitude`,避免调用位置服务API - 如果 `gps` 字段存在,直接使用 - 如果不存在,再使用 `cityName + areaDistrict + businessDistrict + brandName` 调用位置服务 2. **薪资解析**: 从 `salaryDesc` 解析薪资范围 - 格式示例:`"25-50K·19薪"` → min: 25000, max: 50000 - 格式示例:`"20-30K"` → min: 20000, max: 30000 - 格式示例:`"面议"` → min: 0, max: 0 - 格式示例:`"15K以上"` → min: 15000, max: 999999 - 需要处理:K(千)、W(万)、薪(年终奖倍数) 3. **工作年限解析**: 从 `jobExperience` 解析年限范围 - `"在校/应届"` → min: 0, max: 0 - `"1-3年"` → min: 1, max: 3 - `"3-5年"` → min: 3, max: 5 - `"5-10年"` → min: 5, max: 10 - `"10年以上"` → min: 10, max: 99 4. **学历映射**: 将学历描述映射为等级 - `"学历不限"` → `"unlimited"` - `"高中"` → `"high_school"` - `"大专"` → `"college"` - `"本科"` → `"bachelor"` - `"硕士"` → `"master"` - `"博士"` → `"doctor"` 5. **投递必需字段**: 确保保存 `encryptJobId`、`encryptBossId` 和 `securityId` - 这些字段在投递时必须使用 - `securityId` 每次搜索可能不同,需要实时保存 **代码位置**: 第215-308行 **预计工作量**: 4小时(增加字段解析逻辑) --- ### 任务3: 完善自动投递任务搜索条件 **文件**: `api/middleware/schedule/taskHandlers.js` **修改方法**: `handleAutoDeliverTask()` **任务内容**: 1. 从账号配置读取默认搜索条件 2. 支持任务参数覆盖 3. 构建完整的搜索参数 4. 传递给搜索指令 **代码位置**: 第220-233行 **预计工作量**: 2小时 --- ### 任务4: 优化职位匹配算法 **文件**: `api/middleware/schedule/taskHandlers.js` **修改方法**: `handleAutoDeliverTask()` **任务内容**: 1. 完善距离计算(使用经纬度计算实际距离) 2. 完善薪资匹配(解析"20-30K"格式,转换为数值范围) 3. 完善工作年限匹配(解析"3-5年"格式) 4. 完善学历匹配(学历等级映射) 5. 优化权重评分计算 **代码位置**: 第255-400行(职位评分和过滤逻辑) **预计工作量**: 4小时 --- ### 任务5: 创建搜索任务接口(支持可选投递) **文件**: `api/services/pla_account_service.js` **新增方法**: `createSearchJobListTask()` **方法签名**: ```javascript /** * 创建搜索职位列表任务(支持可选投递) * @param {Object} params - 任务参数 * @param {number} params.id - 账号ID * @param {string} params.keyword - 搜索关键词 * @param {Object} params.searchParams - 搜索条件(城市、薪资、经验、学历等) * @param {number} params.pageCount - 获取页数 * @param {boolean} params.autoDeliver - 是否自动投递(默认false) * @param {Object} params.filterRules - 过滤规则(autoDeliver=true时使用) * @param {number} params.maxCount - 最大投递数量(autoDeliver=true时使用) * @returns {Promise} 任务创建结果 { taskId, message, jobCount, deliveredCount } */ async createSearchJobListTask(params) { // 1. 验证账号和授权 // 2. 创建任务记录 (taskType: 'search_jobs' 或 'auto_deliver') // 3. 生成搜索指令 // 4. 执行搜索指令 // 5. 等待搜索完成(职位会自动保存到数据库) // 6. 如果 autoDeliver=true: // - 从数据库获取刚搜索到的职位列表 // - 根据简历信息和过滤规则匹配职位 // - 生成投递指令序列 // - 执行投递指令(带间隔控制) // - 保存投递记录 // - 更新职位状态 // 7. 返回任务信息 } ``` **任务内容**: 1. 验证账号和授权 2. 创建任务记录(根据autoDeliver参数设置taskType: 'search_jobs' 或 'auto_deliver') 3. 生成搜索指令(command_type: 'get_job_list') 4. 执行搜索指令(通过MQTT发送到设备) 5. 等待搜索完成(职位会自动保存到数据库) 6. 如果 `autoDeliver=true`,继续执行投递流程: - 从数据库获取刚搜索到的职位列表(applyStatus = 'pending') - 根据简历信息和过滤规则匹配职位(距离、薪资、工作年限、学历等) - 为每个匹配的职位生成投递指令(command_type: 'apply_job') - 批量执行投递指令(带间隔控制,避免频繁投递) - 保存投递记录 (apply_records) - 更新职位状态 (job_postings.applyStatus = 'applied') 7. 返回任务信息(包含搜索到的职位数量和投递数量) **代码位置**: 在 `runCommand()` 方法后添加 **预计工作量**: 5小时(增加投递逻辑) --- --- ### 任务6: 完善指令类型映射 **文件**: `api/middleware/schedule/command.js` **修改位置**: 指令执行逻辑 **任务内容**: 1. 确保 `get_job_list` 指令类型正确映射到 `jobManager.get_job_list()` 2. 确保 `search_jobs` 指令类型正确映射到 `jobManager.search_jobs()` 3. 确保 `apply_job` 指令类型正确映射到 `jobManager.applyJob()` **代码位置**: 第150-250行(指令执行逻辑) **预计工作量**: 1小时 --- ### 任务7: 添加搜索条件配置管理 **文件**: `api/model/pla_account.js` **任务内容**: 1. 添加搜索条件配置字段(如果不存在) 2. 支持在账号配置中保存默认搜索条件 3. 支持在任务参数中覆盖搜索条件 **相关字段**: - `search_config` (JSON): 搜索条件配置 ```json { "city": "101020100", "cityName": "上海", "defaultSalary": "20-30K", "defaultExperience": "3-5年", "defaultEducation": "本科" } ``` **预计工作量**: 1小时 --- ## 🔄 工作流程 ### 搜索职位列表流程(支持可选投递) ``` 1. 用户/系统调用 createSearchJobListTask() - 参数: { id, keyword, searchParams, pageCount, autoDeliver: true/false, filterRules, maxCount } ↓ 2. 创建任务记录 (task_status) - taskType: 'search_jobs' 或 'auto_deliver'(根据autoDeliver参数) ↓ 3. 生成搜索指令 (task_commands) - command_type: 'get_job_list' - command_params: { keyword, city, salary, experience, education, ... } ↓ 4. 执行指令 (通过MQTT发送到设备) ↓ 5. 设备执行搜索并返回职位列表 ↓ 6. 保存职位到数据库 (job_postings) - 去重处理 - 位置解析(优先使用gps字段) - 字段映射 - 状态: applyStatus = 'pending'(待投递) ↓ 7. 更新搜索指令状态为完成 ↓ 8. 如果 autoDeliver=true,继续执行投递流程: ↓ 8.1 从数据库获取刚搜索到的职位列表 - 筛选条件: applyStatus = 'pending', sn_code = 账号SN码 ↓ 8.2 根据简历信息和过滤规则匹配职位 - 距离匹配(基于经纬度) - 薪资匹配(解析salaryDesc) - 工作年限匹配(解析jobExperience) - 学历匹配(解析jobDegree) - 权重评分 ↓ 8.3 为每个匹配的职位生成投递指令 - command_type: 'apply_job' - command_params: { jobId: job.encryptJobId, // 职位ID(必需) encryptBossId: job.encryptBossId, // Boss ID(必需) securityId: job.securityId, // 安全ID(必需,从最新搜索结果获取) brandName: job.brandName, // 公司名称(可选) jobTitle: job.jobName // 职位名称(可选) } ↓ 8.4 批量执行投递指令(带间隔控制,避免频繁投递) ↓ 8.5 保存投递记录 (apply_records) ↓ 8.6 更新职位状态 (job_postings.applyStatus = 'applied') ↓ 9. 更新任务状态为完成 ↓ 10. 返回任务信息(包含搜索到的职位数量和投递数量) ``` **说明**: - 此接口支持两种模式: - `autoDeliver=false`: 仅搜索,不投递。职位保存到数据库,状态为'pending' - `autoDeliver=true`: 搜索完成后立即投递匹配的职位 - **重要**: 投递必须在搜索完成后立即执行,因为 `securityId` 等字段可能有时效性,前端页面变化后这些字段可能失效 - 不支持从已保存的职位中选择投递,因为职位信息可能已过期 ## 📊 数据库字段说明 ### job_postings 表需要完善的字段 | 字段名 | 类型 | 说明 | 状态 | 数据来源 | |--------|------|------|------|----------| | `city` | VARCHAR | 城市代码 | 待添加 | `job.city` | | `cityName` | VARCHAR | 城市名称 | 待添加 | `job.cityName` | | `areaDistrict` | VARCHAR | 区域 | 待添加 | `job.areaDistrict` | | `businessDistrict` | VARCHAR | 商圈 | 待添加 | `job.businessDistrict` | | `salaryMin` | INT | 最低薪资(元) | 待添加 | 从 `salaryDesc` 解析 | | `salaryMax` | INT | 最高薪资(元) | 待添加 | 从 `salaryDesc` 解析 | | `experienceMin` | INT | 最低工作年限 | 待添加 | 从 `jobExperience` 解析 | | `experienceMax` | INT | 最高工作年限 | 待添加 | 从 `jobExperience` 解析 | | `educationLevel` | VARCHAR | 学历等级 | 待添加 | 从 `jobDegree` 映射 | | `matchScore` | DECIMAL | 匹配度评分 | 待添加 | 计算得出 | | `encryptBossId` | VARCHAR | Boss ID | 已有 | `job.encryptBossId` | | `securityId` | VARCHAR | 安全ID | 待添加 | `job.securityId`(投递必需) | | `bossName` | VARCHAR | Boss姓名 | 待添加 | `job.bossName` | | `bossTitle` | VARCHAR | Boss职位 | 待添加 | `job.bossTitle` | | `bossOnline` | TINYINT | Boss是否在线 | 待添加 | `job.bossOnline` | | `brandStage` | VARCHAR | 融资阶段 | 待添加 | `job.brandStageName` | | `jobLabels` | JSON | 职位标签 | 待添加 | `job.jobLabels` | | `skills` | JSON | 技能要求 | 待添加 | `job.skills` | | `welfareList` | JSON | 福利列表 | 待添加 | `job.welfareList` | | `isOutsourcing` | TINYINT | 是否外包 | 待添加 | `job.proxyJob` | | `industry` | INT | 行业代码 | 待添加 | `job.industry` | ### pla_account 表需要添加的字段 | 字段名 | 类型 | 说明 | 状态 | |--------|------|------|------| | `search_config` | JSON | 搜索条件配置 | 待添加 | | `city` | VARCHAR | 默认城市代码 | 待添加 | | `cityName` | VARCHAR | 默认城市名称 | 待添加 | ## 🧪 测试计划 ### 单元测试 1. 测试搜索参数构建 2. 测试职位数据保存 3. 测试职位匹配算法 4. 测试投递指令生成 ### 集成测试 1. 测试完整搜索流程 2. 测试完整投递流程 3. 测试任务创建和执行 4. 测试MQTT通信 ### 功能测试 1. 测试多条件搜索 2. 测试分页获取 3. 测试批量投递 4. 测试错误处理 ## 📅 开发时间估算 | 任务 | 预计时间 | 优先级 | |------|----------|--------| | 任务1: 完善搜索参数支持 | 2小时 | 高 | | 任务2: 优化职位数据保存 | 4小时 | 高 | | 任务3: 完善自动投递任务搜索条件 | 2小时 | 高 | | 任务4: 优化职位匹配算法 | 4小时 | 高 | | 任务5: 创建搜索任务接口(支持可选投递) | 5小时 | 高 | | 任务6: 完善指令类型映射 | 1小时 | 中 | | 任务7: 添加搜索条件配置管理 | 1小时 | 低 | **总计**: 约19小时 ## 🚀 开发优先级 ### 第一阶段(核心功能) 1. 任务1: 完善搜索参数支持 2. 任务2: 优化职位数据保存 3. 任务3: 完善自动投递任务搜索条件 4. 任务4: 优化职位匹配算法 5. 任务5: 创建搜索任务接口(支持可选投递) ### 第二阶段(接口完善) 6. 任务6: 完善指令类型映射 ### 第三阶段(配置管理) 7. 任务7: 添加搜索条件配置管理 ## 💡 使用场景说明 ### 场景1: 仅搜索职位列表 ```javascript // 只搜索职位,不投递 const result = await plaAccountService.createSearchJobListTask({ id: accountId, keyword: '全栈工程师', searchParams: { city: '101020100', cityName: '上海', salary: '20-30K', experience: '3-5年', education: '本科' }, pageCount: 3, autoDeliver: false // 不自动投递 }); // 返回: { taskId: 123, message: '搜索任务已创建', jobCount: 45 } // 职位会自动保存到数据库,状态为 'pending'(待投递) ``` ### 场景2: 搜索并自动投递(推荐) ```javascript // 搜索职位并自动投递匹配的职位 const result = await plaAccountService.createSearchJobListTask({ id: accountId, keyword: '全栈工程师', searchParams: { city: '101020100', cityName: '上海', salary: '20-30K', experience: '3-5年', education: '本科' }, pageCount: 3, autoDeliver: true, // 自动投递 filterRules: { minSalary: 20000, maxSalary: 30000, keywords: ['Vue', 'React'], excludeKeywords: ['外包', '外派'] }, maxCount: 10 // 最多投递10个职位 }); // 返回: { taskId: 123, message: '搜索并投递任务已创建', jobCount: 45, deliveredCount: 8 } ``` **重要说明**: - **投递必须在搜索完成后立即执行**,因为 `securityId` 等字段可能有时效性 - 前端页面变化后,已保存的职位信息中的 `securityId` 可能失效,无法用于投递 - 因此不支持从已保存的职位中选择投递,必须在搜索后立即投递 - 如果只需要搜索不投递,设置 `autoDeliver: false` - 如果需要搜索并投递,设置 `autoDeliver: true`,系统会根据匹配规则自动投递 ## 📌 注意事项 1. **命名规范**: 统一使用下划线命名(`get_job_list` 而不是 `getJobList`) 2. **错误处理**: 所有方法都需要完善的错误处理和日志记录 3. **数据验证**: 所有输入参数都需要验证 4. **性能优化**: 批量操作需要考虑性能,避免阻塞 5. **MQTT通信**: 确保指令参数格式正确,与客户端协议一致 6. **数据库事务**: 批量操作需要使用事务保证数据一致性 7. **投递时机**: 投递必须在搜索完成后立即执行,因为 `securityId` 等字段可能有时效性,前端页面变化后这些字段可能失效 8. **职位状态验证**: 投递前必须验证职位状态(applyStatus = 'pending'),避免重复投递 9. **投递必需字段**: 投递时需要 `encryptJobId`、`encryptBossId` 和 `securityId`,这些字段必须从最新搜索结果中获取 10. **位置信息**: 优先使用响应中的 `gps` 字段,避免不必要的API调用 11. **接口设计**: 搜索和投递在同一接口中完成,不支持单独的投递接口,因为已保存的职位信息可能已过期 ## 🔗 相关文件 - `api/middleware/job/jobManager.js` - 工作管理核心逻辑 - `api/middleware/schedule/taskHandlers.js` - 任务处理器 - `api/middleware/schedule/command.js` - 指令管理器 - `api/services/pla_account_service.js` - 账号服务 - `api/model/job_postings.js` - 职位数据模型 - `api/model/pla_account.js` - 账号数据模型