diff --git a/admin/src/views/account/pla_account_detail.vue b/admin/src/views/account/pla_account_detail.vue
index b0646be..9f6f3a4 100644
--- a/admin/src/views/account/pla_account_detail.vue
+++ b/admin/src/views/account/pla_account_detail.vue
@@ -229,6 +229,12 @@
+
+ 同公司重复投递间隔(天):
+ {{ deliverConfig.repeat_deliver_days != null ? deliverConfig.repeat_deliver_days : '-' }}
+
+
+
过滤关键词:
{{ deliverConfig.filter_keywords || '-' }}
@@ -560,6 +566,7 @@ export default {
max_salary: 0,
page_count: 3,
max_deliver: 10,
+ repeat_deliver_days: 30,
filter_keywords: '',
exclude_keywords: ''
},
@@ -908,6 +915,7 @@ export default {
max_salary: deliverConfig.max_salary || 0,
page_count: deliverConfig.page_count || 3,
max_deliver: deliverConfig.max_deliver || 10,
+ repeat_deliver_days: deliverConfig.repeat_deliver_days != null ? deliverConfig.repeat_deliver_days : 30,
filter_keywords: Array.isArray(deliverConfig.filter_keywords)
? deliverConfig.filter_keywords.join(',')
: (deliverConfig.filter_keywords || ''),
@@ -926,6 +934,7 @@ export default {
max_salary: 0,
page_count: 3,
max_deliver: 10,
+ repeat_deliver_days: 30,
filter_keywords: '',
exclude_keywords: '',
deliver_start_time: '09:00',
diff --git a/admin/src/views/account/pla_account_edit.vue b/admin/src/views/account/pla_account_edit.vue
index 3610813..9aa3990 100644
--- a/admin/src/views/account/pla_account_edit.vue
+++ b/admin/src/views/account/pla_account_edit.vue
@@ -148,6 +148,9 @@
+
+
+
} 岗位列表
*/
async get_job_list(sn_code, mqttClient, params = {}) {
- const {
- keyword: paramKeyword = '',
- platform = 'boss',
+ const {
+ platform = 'boss',
pageCount = 3,
city = '',
cityName = '',
@@ -439,77 +439,29 @@ class JobManager {
financingStage = '',
page = 1,
pageSize = 20,
- tabLabel,
- tabIndex,
- job_type_id
+ tabLabel
} = params;
- // 推荐列表实际按期望 tab 拉取,入库 keyword 应与「职位来源」一致:显式 keyword > deliver_tab_label > 空(不再默认「前端」)
- let keyword = paramKeyword != null && String(paramKeyword).trim() !== ''
- ? String(paramKeyword).trim()
- : '';
- if (!keyword && tabLabel != null && String(tabLabel).trim() !== '') {
- keyword = String(tabLabel).trim();
- }
+ // 入库用:可与前端一致带 keyword;设备端只收 pageCount + tabLabel(与 Electron get_job_list 一致)
+ const keyword = String(params.keyword || '').trim() || String(tabLabel || '').trim();
- // 仅当调用方显式传入筛选/分页字段时才走多条件分支(避免 page/pageSize 默认值把简单拉列表永远判成「多条件」)
- const hasMultiParams = Boolean(
- (params.city != null && params.city !== '') ||
- (params.cityName != null && params.cityName !== '') ||
- (params.salary != null && params.salary !== '') ||
- (params.experience != null && params.experience !== '') ||
- (params.education != null && params.education !== '') ||
- (params.industry != null && params.industry !== '') ||
- (params.companySize != null && params.companySize !== '') ||
- (params.financingStage != null && params.financingStage !== '') ||
- params.page !== undefined ||
- params.pageSize !== undefined
- );
+ const multiKeys = ['city', 'cityName', 'salary', 'experience', 'education', 'industry', 'companySize', 'financingStage'];
+ const hasMultiParams = multiKeys.some((k) => params[k]) || params.page !== undefined || params.pageSize !== undefined;
- /** 期望 tab 与职位类型需原样带给设备端 get_job_list,否则不会切换 .c-expect-select 标签 */
- const appendExpectTabToData = (data) => {
- if (tabLabel != null && String(tabLabel).trim() !== '') {
- data.tabLabel = String(tabLabel).trim();
- }
- if (tabIndex !== undefined && tabIndex !== null && String(tabIndex).trim() !== '') {
- const ti = Number(tabIndex);
- if (!Number.isNaN(ti)) {
- data.tabIndex = ti;
- }
- }
- if (job_type_id != null && job_type_id !== '') {
- data.job_type_id = job_type_id;
- }
- return data;
- };
+ const devicePayload = () => ({
+ pageCount,
+ ...(String(tabLabel || '').trim() ? { tabLabel: String(tabLabel).trim() } : {})
+ });
if (hasMultiParams) {
// 使用多条件搜索逻辑
console.log(`[工作管理] 开始多条件搜索设备 ${sn_code} 的职位,关键词: ${keyword}, 城市: ${cityName || city}`);
-
- // 构建完整的搜索参数对象
- const searchData = appendExpectTabToData({
- keyword,
- pageCount
- });
-
- // 添加可选搜索条件
- if (city) searchData.city = city;
- if (cityName) searchData.cityName = cityName;
- if (salary) searchData.salary = salary;
- if (experience) searchData.experience = experience;
- if (education) searchData.education = education;
- if (industry) searchData.industry = industry;
- if (companySize) searchData.companySize = companySize;
- if (financingStage) searchData.financingStage = financingStage;
- if (page) searchData.page = page;
- if (pageSize) searchData.pageSize = pageSize;
// 通过MQTT指令获取岗位列表(保持action不变,前端已使用)
const response = await mqttClient.publishAndWait(sn_code, {
platform,
action: "get_job_list", // 保持与原有get_job_list相同的action,前端已使用
- data: searchData
+ data: devicePayload()
});
if (!response || response.code !== 200) {
@@ -517,19 +469,7 @@ class JobManager {
throw new Error('多条件搜索职位失败');
}
- // 处理职位列表数据
- let jobs = [];
- if (Array.isArray(response.data)) {
- for (const item of response.data) {
- if (item.data?.zpData?.jobList && Array.isArray(item.data.zpData.jobList)) {
- jobs = jobs.concat(item.data.zpData.jobList);
- }
- }
- } else if (response.data?.data?.zpData?.jobList) {
- jobs = response.data.data.zpData.jobList || [];
- } else if (response.data?.zpData?.jobList) {
- jobs = response.data.zpData.jobList || [];
- }
+ const jobs = this._jobListFromRecommendMonitorData(response.data);
console.log(`[工作管理] 成功获取岗位数据,共 ${jobs.length} 个岗位`);
@@ -551,11 +491,10 @@ class JobManager {
// 简单搜索逻辑(保持原有逻辑)
console.log(`[工作管理] 开始获取设备 ${sn_code} 的岗位列表,关键词: ${keyword}`);
- // 通过MQTT指令获取岗位列表(须带上 tabLabel/tabIndex,与 schedule/deliver 下发一致)
const response = await mqttClient.publishAndWait(sn_code, {
platform,
action: "get_job_list",
- data: appendExpectTabToData({ keyword, pageCount })
+ data: devicePayload()
});
if (!response || response.code !== 200) {
@@ -563,25 +502,7 @@ class JobManager {
throw new Error('获取岗位列表失败');
}
- // 处理职位列表数据:response.data 可能是数组(职位列表.json 格式)或单个对象
- let jobs = [];
-
- if (Array.isArray(response.data)) {
- // 如果是数组格式(职位列表.json),遍历每个元素提取岗位数据
- for (const item of response.data) {
- if (item.data?.zpData?.jobList && Array.isArray(item.data.zpData.jobList)) {
- jobs = jobs.concat(item.data.zpData.jobList);
- }
- }
- console.log(`[工作管理] 从 ${response.data.length} 个响应中提取岗位数据`);
- } else if (response.data?.data?.zpData?.jobList) {
- // 如果是单个对象格式,从 data.zpData.jobList 获取
- jobs = response.data.data.zpData.jobList || [];
- } else if (response.data?.zpData?.jobList) {
- // 兼容旧格式:直接从 zpData.jobList 获取
- jobs = response.data.zpData.jobList || [];
- }
-
+ const jobs = this._jobListFromRecommendMonitorData(response.data);
console.log(`[工作管理] 成功获取岗位数据,共 ${jobs.length} 个岗位`);
// 保存职位到数据库
diff --git a/api/middleware/schedule/handlers/deliverHandler.js b/api/middleware/schedule/handlers/deliverHandler.js
index 56a2f4a..7b1e19f 100644
--- a/api/middleware/schedule/handlers/deliverHandler.js
+++ b/api/middleware/schedule/handlers/deliverHandler.js
@@ -89,17 +89,9 @@ class DeliverHandler extends BaseHandler {
mqttClient: this.mqttClient
});
- // 6. 下发 get_job_list 拉取职位列表(tabLabel 切换期望 tab,job_type_id 随指令下发供设备使用)
+ // 6. 下发 get_job_list(与前端一致:command 只带 pageCount + tabLabel,设备端不接收 keyword/job_type_id)
const tabLabel = resume.deliver_tab_label || '';
- await this.getJobList(
- sn_code,
- platform,
- pageCount,
- task.id,
- tabLabel,
- accountConfig.job_type_id,
- accountConfig.keyword
- );
+ await this.getJobList(sn_code, platform, pageCount, task.id, tabLabel);
// 7. 从数据库获取待投递职位
const pendingJobs = await this.getPendingJobs(sn_code, platform, actualMaxCount * 3);
@@ -114,8 +106,9 @@ class DeliverHandler extends BaseHandler {
// 8. 合并过滤配置
const filterConfig = this.mergeFilterConfig(deliverConfig, filterRules, jobTypeConfig);
- // 9. 过滤已投递的公司
- const recentCompanies = await this.getRecentDeliveredCompanies(sn_code, 30);
+ // 9. 过滤已投递的公司(repeat_deliver_days 由投递配置给出,缺省 30,上限 365)
+ const repeatDeliverDays = Math.min(365, Math.max(1, Number(deliverConfig.repeat_deliver_days) || 30));
+ const recentCompanies = await this.getRecentDeliveredCompanies(sn_code, repeatDeliverDays);
// 10. 过滤 + 评分 + 按 60 分阈值筛(入口在 jobFilterEngine,便于阅读)
const filteredJobs = await jobFilterEngine.filterAndScoreJobsForDeliver(
@@ -281,28 +274,16 @@ class DeliverHandler extends BaseHandler {
}
/**
- * 下发 get_job_list 命令拉取职位列表
- * @param {string} tabLabel - 投递用期望标签文案,对应 resume_info.deliver_tab_label,get_job_list 会按此选择 tab
- * @param {number} jobTypeId - 职位类型 ID,随指令下发供设备使用
+ * 下发 get_job_list 命令拉取职位列表(command_params 与前端约定:pageCount、tabLabel + sn_code、platform)
*/
- async getJobList(sn_code, platform, pageCount, taskId, tabLabel = '', jobTypeId = null, accountKeyword = '') {
+ async getJobList(sn_code, platform, pageCount, taskId, tabLabel = '') {
const label = tabLabel != null && String(tabLabel).trim() !== '' ? String(tabLabel).trim() : '';
- const accKw = accountKeyword != null && String(accountKeyword).trim() !== '' ? String(accountKeyword).trim() : '';
- // 与 jobManager 一致:优先期望职位文案,其次账户搜索词,用于 job_postings.keyword
- const keyword = label || accKw;
-
const params = {
sn_code,
platform,
pageCount,
- keyword
+ ...(label ? { tabLabel: label } : {})
};
- if (label) {
- params.tabLabel = label;
- }
- if (jobTypeId != null && jobTypeId !== '') {
- params.job_type_id = jobTypeId;
- }
const getJobListCommand = {
command_type: 'get_job_list',
command_name: '获取职位列表',
diff --git a/api/middleware/schedule/handlers/searchHandler.js b/api/middleware/schedule/handlers/searchHandler.js
index 5450924..72dd4ad 100644
--- a/api/middleware/schedule/handlers/searchHandler.js
+++ b/api/middleware/schedule/handlers/searchHandler.js
@@ -77,18 +77,12 @@ class SearchHandler extends BaseHandler {
console.warn('[自动搜索] 读取 resume_info.deliver_tab_label 失败:', e.message);
}
- let listKeyword = (keyword && String(keyword).trim()) || (accountConfig.keyword && String(accountConfig.keyword).trim()) || '';
- if (!listKeyword && tabLabel) {
- listKeyword = tabLabel;
- }
-
const commandParams = {
sn_code,
- keyword: listKeyword,
platform: platformType,
- pageCount: pageCount || searchConfig.page_count || 3
+ pageCount: pageCount || searchConfig.page_count || 3,
+ ...(tabLabel ? { tabLabel } : {})
};
- if (tabLabel) commandParams.tabLabel = tabLabel;
const searchCommand = {
command_type: 'get_job_list',
diff --git a/api/middleware/schedule/services/configManager.js b/api/middleware/schedule/services/configManager.js
index 1e0cc36..188b3d8 100644
--- a/api/middleware/schedule/services/configManager.js
+++ b/api/middleware/schedule/services/configManager.js
@@ -43,6 +43,7 @@ class ConfigManager {
max_salary: 0, // 最高薪资
page_count: 3, // 搜索页数
max_deliver: 10, // 最大投递数
+ repeat_deliver_days: 30, // 多少天内已投递过的公司不再投递(与 getRecentDeliveredCompanies 一致)
filter_keywords: [], // 过滤关键词
exclude_keywords: [], // 排除关键词
time_range: null, // 时间范围
diff --git a/api/services/pla_account_service.js b/api/services/pla_account_service.js
index c8dc68b..1b75ba5 100644
--- a/api/services/pla_account_service.js
+++ b/api/services/pla_account_service.js
@@ -481,12 +481,11 @@ class PlaAccountService {
? { ...baseParams, ...commandParams }
: baseParams;
- // 如果有关键词相关的操作,添加关键词
- if (['search_jobs', 'get_job_list'].includes(commandTypeSnake) && account.keyword) {
+ if (commandTypeSnake === 'search_jobs' && account.keyword) {
finalParams.keyword = account.keyword;
}
- // get_job_list 从 resume_info 取 deliver_tab_label 作为 tabLabel;入库 keyword 优先用期望职位而非写死
+ // get_job_list:command 只约定 pageCount + tabLabel(与前端一致),入库 keyword 由 jobManager 用 tabLabel 推导
if (commandTypeSnake === 'get_job_list') {
try {
const resume_info = db.getModel('resume_info');
@@ -496,11 +495,7 @@ class PlaAccountService {
attributes: ['deliver_tab_label']
});
if (resume && resume.deliver_tab_label) {
- const tab = String(resume.deliver_tab_label).trim();
- finalParams.tabLabel = tab;
- if (!finalParams.keyword || String(finalParams.keyword).trim() === '') {
- finalParams.keyword = tab;
- }
+ finalParams.tabLabel = String(resume.deliver_tab_label).trim();
}
} catch (e) {
console.warn('[pla_account_service] 读取 resume_info.deliver_tab_label 失败:', e.message);