From bfd39eddcf03f3c61b0d7884dfaea0cc0ef737b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BC=A0=E6=88=90?= Date: Wed, 8 Apr 2026 15:00:49 +0800 Subject: [PATCH] 1 --- api/middleware/job/managers/jobManager.js | 263 +++++++++------------- api/model/pla_account.js | 6 - 2 files changed, 106 insertions(+), 163 deletions(-) diff --git a/api/middleware/job/managers/jobManager.js b/api/middleware/job/managers/jobManager.js index 3fd0d30..e9a5255 100644 --- a/api/middleware/job/managers/jobManager.js +++ b/api/middleware/job/managers/jobManager.js @@ -1,3 +1,4 @@ +const { Op } = require('sequelize'); const aiService = require('../../../services/ai_service'); const { jobFilterService } = require('../services'); const locationService = require('../../../services/locationService'); @@ -5,6 +6,7 @@ const logs = require('../../logProxy'); const db = require('../../dbProxy'); const { v4: uuidv4 } = require('uuid'); + /** * 工作管理模块 * 负责简历获取、分析、存储和匹配度计算 @@ -14,13 +16,19 @@ class JobManager { } /** - * 设备 get_job_list 返回的 response.data:XHR 监听结果数组,每项 data 为接口 JSON(zpData.jobList) + * 解析设备 get_job_list / search_job_list 等返回的 response.data。 + * 实际形态为「多页 XHR 监听结果」数组,与客户端一致,例如: + * `[{ url, method, status, data: { code: 0, message, zpData: { hasMore, jobList: [...] } } }, ...]` + * pageCount=3 时通常 3 条(每页一次 list.json),本方法将所有页的 jobList 合并为一维数组。 */ _jobListFromRecommendMonitorData(responseData) { if (!Array.isArray(responseData)) return []; const jobs = []; for (const item of responseData) { - const list = item?.data?.zpData?.jobList; + const inner = item?.data; + if (!inner || typeof inner !== 'object') continue; + if (inner.code !== undefined && inner.code !== 0) continue; + const list = inner.zpData?.jobList; if (Array.isArray(list)) jobs.push(...list); } return jobs; @@ -164,8 +172,8 @@ class JobManager { * @returns {Promise} 搜索结果 */ async search_jobs_with_params(sn_code, mqttClient, params = {}) { - const { - keyword = '前端', + const { + keyword = '前端', platform = 'boss', city = '', cityName = '', @@ -217,11 +225,9 @@ class JobManager { console.log(`[工作管理] 成功获取岗位数据,共 ${jobs.length} 个岗位`); // 保存职位到数据库 - try { - await this.saveJobsToDatabase(sn_code, platform, keyword, jobs); - } catch (error) { - console.error(`[工作管理] 保存职位到数据库失败:`, error); - } + + await this.saveJobsToDatabase(sn_code, platform, keyword, jobs); + return { jobs: jobs, @@ -239,7 +245,7 @@ class JobManager { * @returns {Promise} 执行结果 */ async search_and_deliver(sn_code, mqttClient, params = {}) { - const { + const { keyword, searchParams = {}, pageCount = 3, @@ -352,8 +358,8 @@ class JobManager { let securityId = jobData.securityId || ''; try { if (jobData.originalData) { - const originalData = typeof jobData.originalData === 'string' - ? JSON.parse(jobData.originalData) + const originalData = typeof jobData.originalData === 'string' + ? JSON.parse(jobData.originalData) : jobData.originalData; securityId = originalData.securityId || securityId; } @@ -419,82 +425,27 @@ class JobManager { } /** - * 获取岗位列表(支持多条件搜索) - * @param {string} sn_code - 设备SN码 - * @param {object} mqttClient - MQTT客户端 - * @param {object} params - 参数 + * 获取岗位列表(与客户端/Electron 约定一致) + * @param {string} sn_code - 设备 SN + * @param {object} mqttClient - MQTT 客户端 + * @param {object} params - { platform?, pageCount?, tabLabel?, keyword? };keyword 仅服务端入库用,下发设备只有 pageCount + tabLabel * @returns {Promise} 岗位列表 */ async get_job_list(sn_code, mqttClient, params = {}) { - const { - platform = 'boss', - pageCount = 3, - city = '', - cityName = '', - salary = '', - experience = '', - education = '', - industry = '', - companySize = '', - financingStage = '', - page = 1, - pageSize = 20, - tabLabel - } = params; - - // 入库用:可与前端一致带 keyword;设备端只收 pageCount + tabLabel(与 Electron get_job_list 一致) + const { platform = 'boss', pageCount = 3, tabLabel } = params; const keyword = String(params.keyword || '').trim() || String(tabLabel || '').trim(); - const multiKeys = ['city', 'cityName', 'salary', 'experience', 'education', 'industry', 'companySize', 'financingStage']; - const hasMultiParams = multiKeys.some((k) => params[k]) || params.page !== undefined || params.pageSize !== undefined; - - const devicePayload = () => ({ + const data = { pageCount, ...(String(tabLabel || '').trim() ? { tabLabel: String(tabLabel).trim() } : {}) - }); + }; - if (hasMultiParams) { - // 使用多条件搜索逻辑 - console.log(`[工作管理] 开始多条件搜索设备 ${sn_code} 的职位,关键词: ${keyword}, 城市: ${cityName || city}`); - - // 通过MQTT指令获取岗位列表(保持action不变,前端已使用) - const response = await mqttClient.publishAndWait(sn_code, { - platform, - action: "get_job_list", // 保持与原有get_job_list相同的action,前端已使用 - data: devicePayload() - }); - - if (!response || response.code !== 200) { - console.error(`[工作管理] 多条件搜索职位失败:`, response); - throw new Error('多条件搜索职位失败'); - } - - const jobs = this._jobListFromRecommendMonitorData(response.data); - - console.log(`[工作管理] 成功获取岗位数据,共 ${jobs.length} 个岗位`); - - // 保存职位到数据库 - try { - await this.saveJobsToDatabase(sn_code, platform, keyword, jobs); - } catch (error) { - console.error(`[工作管理] 保存职位到数据库失败:`, error); - } - - return { - jobs: jobs, - keyword: keyword, - platform: platform, - count: jobs.length - }; - } - - // 简单搜索逻辑(保持原有逻辑) - console.log(`[工作管理] 开始获取设备 ${sn_code} 的岗位列表,关键词: ${keyword}`); + console.log(`[工作管理] get_job_list ${sn_code} → 设备`, data, `入库 keyword=${keyword}`); const response = await mqttClient.publishAndWait(sn_code, { platform, - action: "get_job_list", - data: devicePayload() + action: 'get_job_list', + data }); if (!response || response.code !== 200) { @@ -505,22 +456,16 @@ class JobManager { const jobs = this._jobListFromRecommendMonitorData(response.data); console.log(`[工作管理] 成功获取岗位数据,共 ${jobs.length} 个岗位`); - // 保存职位到数据库 - try { - await this.saveJobsToDatabase(sn_code, platform, keyword, jobs); - } catch (error) { - console.error(`[工作管理] 保存职位到数据库失败:`, error); - // 不影响主流程,继续返回数据 - } - const result = { - jobs: jobs, - keyword: keyword, - platform: platform, + await this.saveJobsToDatabase(sn_code, platform, keyword, jobs); + + + return { + jobs, + keyword, + platform, count: jobs.length }; - - return result; } /** @@ -536,89 +481,93 @@ class JobManager { console.log(`[工作管理] 开始保存 ${jobs.length} 个职位到数据库`); for (const job of jobs) { - try { - // 构建职位信息对象 - const jobInfo = { - sn_code, - platform, - keyword, - // Boss直聘字段映射 - encryptBossId: job.encryptBossId || '', - jobId: job.encryptJobId || '', - jobTitle: job.jobName || '', - companyId: job.encryptBrandId || '', - companyName: job.brandName || '', - companySize: job.brandScaleName || '', - companyIndustry: job.brandIndustry || '', - salary: job.salaryDesc || '', + // 构建职位信息对象 + const jobInfo = { + sn_code, + platform, + keyword, - // 岗位要求(从 jobLabels 和 skills 提取) - jobRequirements: JSON.stringify({ - experience: job.jobExperience || '', - education: job.jobDegree || '', - labels: job.jobLabels || [], - skills: job.skills || [] - }), - - // 工作地点 - location: [job.cityName, job.areaDistrict, job.businessDistrict] - .filter(Boolean).join(' '), + // Boss直聘字段映射 + encryptBossId: job.encryptBossId || '', + jobId: job.encryptJobId || '', + jobTitle: job.jobName || '', + companyId: job.encryptBrandId || '', + companyName: job.brandName || '', + companySize: job.brandScaleName || '', + companyIndustry: job.brandIndustry || '', + salary: job.salaryDesc || '', + // 岗位要求(从 jobLabels 和 skills 提取) + jobRequirements: JSON.stringify({ experience: job.jobExperience || '', education: job.jobDegree || '', + labels: job.jobLabels || [], + skills: job.skills || [] + }), - // 原始数据 - originalData: JSON.stringify(job), + // 工作地点 + location: [job.cityName, job.areaDistrict, job.businessDistrict] + .filter(Boolean).join(' '), - // 默认状态 - applyStatus: 'pending', - chatStatus: 'none' - }; + experience: job.jobExperience || '', + education: job.jobDegree || '', - // 调用位置服务解析 location + companyName 获取坐标 - if (jobInfo.location && jobInfo.companyName) { - const addressToParse = `${jobInfo.location.replaceAll(' ', '')}${jobInfo.companyName}`; + // 原始数据 + originalData: JSON.stringify(job), + + // 默认状态 + applyStatus: 'pending', + chatStatus: 'none' + }; + + // 调用位置服务解析 location + companyName 获取坐标 + if (jobInfo.location && jobInfo.companyName) { + const addressToParse = `${jobInfo.location.replaceAll(' ', '')}${jobInfo.companyName}`; - // 等待 1秒 - // await new Promise(resolve => setTimeout(resolve, 1000)); + // 等待 1秒 + // await new Promise(resolve => setTimeout(resolve, 1000)); + // const location = await locationService.getLocationByAddress(addressToParse).catch(error => { + // console.error(`[工作管理] 获取位置失败:`, error); + // }); - // const location = await locationService.getLocationByAddress(addressToParse).catch(error => { - // console.error(`[工作管理] 获取位置失败:`, error); - // }); + // if (location) { + // jobInfo.latitude = String(location.lat); + // jobInfo.longitude = String(location.lng); + // } + } - // if (location) { - // jobInfo.latitude = String(location.lat); - // jobInfo.longitude = String(location.lng); - // } + // 创建新职位 重复投递时间 从 pla_account 中获取(pla_account 列为 platform_type,不是 platform) + const pla_account = db.getModel('pla_account'); + const account = await pla_account.findOne({ + where: { + sn_code: sn_code, + platform_type: platform } + }); - // 检查是否已存在(根据 jobId 和 sn_code) - const existingJob = await job_postings.findOne({ - where: { - jobId: jobInfo.jobId, - sn_code: sn_code + let repeatDeliverDays = 30; + if (account) { + let dc = account.deliver_config?.repeat_deliver_days||30; + repeatDeliverDays = Number(dc); + } + + const existingJob = await job_postings.findOne({ + where: { + jobId: jobInfo.jobId, + sn_code: sn_code, + last_modify_time: { + [Op.gte]: new Date(Date.now() - repeatDeliverDays * 24 * 60 * 60 * 1000) } - }); - - if (existingJob) { - // 更新现有职位 - await job_postings.update(jobInfo, { - where: { - jobId: jobInfo.jobId, - sn_code: sn_code - } - }); - console.log(`[工作管理] 职位已更新 - ${jobInfo.jobTitle} @ ${jobInfo.companyName}`); - } else { - // 创建新职位 - await job_postings.create(jobInfo); - console.log(`[工作管理] 职位已创建 - ${jobInfo.jobTitle} @ ${jobInfo.companyName}`); } - } catch (error) { - console.error(`[工作管理] 保存职位失败:`, error, job); - // 继续处理下一个职位 + }); + + if (existingJob) { + await job_postings.update(jobInfo, { where: { id: existingJob.id } }); + } else { + await job_postings.create(jobInfo); + console.log(`[工作管理] 职位已创建 - ${jobInfo.jobTitle} @ ${jobInfo.companyName}`); } } diff --git a/api/model/pla_account.js b/api/model/pla_account.js index 740b868..88653ed 100644 --- a/api/model/pla_account.js +++ b/api/model/pla_account.js @@ -21,12 +21,6 @@ module.exports = (db) => { allowNull: true, defaultValue: '' }, - platform_type: { - comment: '平台', - type: Sequelize.STRING(50), - allowNull: false, - defaultValue: '' - }, login_name: { comment: '登录名', type: Sequelize.STRING(50),