diff --git a/packages/geek-auto-start-chat-with-boss/default-config-file/boss.json b/packages/geek-auto-start-chat-with-boss/default-config-file/boss.json index 437e47f..2b202d4 100644 --- a/packages/geek-auto-start-chat-with-boss/default-config-file/boss.json +++ b/packages/geek-auto-start-chat-with-boss/default-config-file/boss.json @@ -35,5 +35,6 @@ ], "isSageTimeEnabled": true, "sageTimeOpTimes": 100, - "sageTimePauseMinute": 15 + "sageTimePauseMinute": 15, + "blockCompanyNameRegExpStr": "" } \ No newline at end of file diff --git a/packages/geek-auto-start-chat-with-boss/index.mjs b/packages/geek-auto-start-chat-with-boss/index.mjs index 237a03d..40bf6f0 100644 --- a/packages/geek-auto-start-chat-with-boss/index.mjs +++ b/packages/geek-auto-start-chat-with-boss/index.mjs @@ -247,6 +247,19 @@ const recommendJobPageUrl = `https://www.zhipin.com/web/geek/jobs` const expectCompanySet = new Set(targetCompanyList) const enableCompanyAllowList = Boolean(expectCompanySet.size) +const blockCompanyNameRegExpStr = readConfigFile('boss.json').blockCompanyNameRegExpStr ?? '' +const blockCompanyNameRegExp = (() => { + if (!blockCompanyNameRegExpStr?.trim()) { + return null + } + try { + return new RegExp(blockCompanyNameRegExpStr, 'im') + } + catch { + return null + } +})() +const blockCompanyNameRegMatchStrategy = readConfigFile('boss.json').blockCompanyNameRegMatchStrategy ?? MarkAsNotSuitOp.NO_OP /** * @type { import('puppeteer').Browser } @@ -298,6 +311,18 @@ async function markJobAsNotSuitInRecommendPage (reasonCode) { let isOptionChosen = false if (chooseReasonDialogProxy) { switch (reasonCode) { + case MarkAsNotSuitReason.COMPANY_NAME_NOT_SUIT: { + const opProxy = (await chooseReasonDialogProxy.$(`.zp-type-item[title*="公司"]`)) + ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title="面试过/入职过"]`)) + ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title="重复推荐"]`)) + ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title*="距离"]`)) + ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title*="薪资"]`)) + if (opProxy) { + await opProxy.click() + isOptionChosen = true + } + break + } case MarkAsNotSuitReason.BOSS_INACTIVE: { const opProxy = (await chooseReasonDialogProxy.$(`.zp-type-item[title="BOSS活跃度低"]`)) ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title="职位停招/招满"]`)) @@ -312,7 +337,7 @@ async function markJobAsNotSuitInRecommendPage (reasonCode) { case MarkAsNotSuitReason.JOB_WORK_EXP_NOT_SUIT: case MarkAsNotSuitReason.JOB_CITY_NOT_SUIT: { const opProxy = (await chooseReasonDialogProxy.$(`.zp-type-item[title$="城市"]`)) - ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title*="距离远"]`)) + ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title*="距离"]`)) ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title*="公司"]`)) ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title="面试过/入职过"]`)) ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title="重复推荐"]`)) @@ -325,7 +350,7 @@ async function markJobAsNotSuitInRecommendPage (reasonCode) { case MarkAsNotSuitReason.JOB_SALARY_NOT_SUIT: { const opProxy = (await chooseReasonDialogProxy.$(`.zp-type-item[title*="薪资"]`)) ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title$="城市"]`)) - ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title*="距离远"]`)) + ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title*="距离"]`)) ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title*="公司"]`)) ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title="面试过/入职过"]`)) ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title="重复推荐"]`)) @@ -984,6 +1009,14 @@ async function toRecommendPage (hooks) { ].includes(expectSalaryNotMatchStrategy) && strategyScopeOptionWhenMarkSalaryNotMatch === StrategyScopeOptionWhenMarkJobNotMatch.ALL_JOB ) ? !checkIfSalarySuit(it.salaryDesc) : false + ) || ( + // enter job detail to mark as not suit for company name filter + !!blockCompanyNameRegExp && + blockCompanyNameRegExp.test(it.brandName?.toLowerCase?.() ?? '') && + [ + MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS, + MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL + ].includes(blockCompanyNameRegMatchStrategy) ) ) }) @@ -1077,6 +1110,47 @@ async function toRecommendPage (hooks) { //#region collect not suit reasons const notSuitReasonIdToStrategyMap = {} const notSuitConditionHandleMap = { + async companyName() { + blockJobNotSuit.add(targetJobData.jobInfo.encryptId) + if (blockCompanyNameRegMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL && !await page.$('.job-detail-box .job-detail-operate .not-suitable')) { + try { + await hooks.jobMarkedAsNotSuit.promise( + targetJobData, + { + markFrom: ChatStartupFrom.AutoFromRecommendList, + markReason: MarkAsNotSuitReason.COMPANY_NAME_NOT_SUIT, + extInfo: null, + markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL, + jobSource: JobSource[computedSourceList[currentSourceIndex]?.type] + } + ) + } catch { + } + } + else if (blockCompanyNameRegMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS) { + try { + await waitForSageTimeOrJustContinue({ + tag: 'beforeJobNotSuitMarked', + hooks + }) + const { chosenReasonInUi } = await markJobAsNotSuitInRecommendPage(MarkAsNotSuitReason.COMPANY_NAME_NOT_SUIT) + await hooks.jobMarkedAsNotSuit.promise( + targetJobData, + { + markFrom: ChatStartupFrom.AutoFromRecommendList, + markReason: MarkAsNotSuitReason.COMPANY_NAME_NOT_SUIT, + extInfo: { + chosenReasonInUi + }, + markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS, + jobSource: JobSource[computedSourceList[currentSourceIndex]?.type] + } + ) + } catch(err) { + console.log(`mark boss inactive failed`, err) + } + } + }, async active() { blockBossNotActive.add(targetJobData.jobInfo.encryptUserId) if (jobNotActiveStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL || !await page.$('.job-detail-box .job-detail-operate .not-suitable')) { @@ -1289,6 +1363,11 @@ async function toRecommendPage (hooks) { } } + if ( + !!blockCompanyNameRegExp && blockCompanyNameRegExp.test(selectedJobData.brandName ?? '') + ) { + notSuitReasonIdToStrategyMap.companyName = blockCompanyNameRegMatchStrategy + } //#region // null // 刚刚活跃 // 今日活跃 // 昨日活跃 // 3日内活跃 // 本周活跃 // 2周内活跃 diff --git a/packages/sqlite-plugin/src/enums.ts b/packages/sqlite-plugin/src/enums.ts index c2ad8e1..0a32b27 100644 --- a/packages/sqlite-plugin/src/enums.ts +++ b/packages/sqlite-plugin/src/enums.ts @@ -6,6 +6,7 @@ export enum MarkAsNotSuitReason { JOB_CITY_NOT_SUIT = 4, JOB_WORK_EXP_NOT_SUIT = 5, JOB_SALARY_NOT_SUIT = 6, + COMPANY_NAME_NOT_SUIT = 7, } export enum MarkAsNotSuitOp { diff --git a/packages/ui/src/main/flow/OPEN_SETTING_WINDOW/ipc/index.ts b/packages/ui/src/main/flow/OPEN_SETTING_WINDOW/ipc/index.ts index 012747a..3eb9a96 100644 --- a/packages/ui/src/main/flow/OPEN_SETTING_WINDOW/ipc/index.ts +++ b/packages/ui/src/main/flow/OPEN_SETTING_WINDOW/ipc/index.ts @@ -181,6 +181,12 @@ export default function initIpc() { if (hasOwn(payload, 'sageTimePauseMinute')) { bossConfig.sageTimePauseMinute = payload.sageTimePauseMinute } + if (hasOwn(payload, 'blockCompanyNameRegExpStr')) { + bossConfig.blockCompanyNameRegExpStr = payload.blockCompanyNameRegExpStr + } + if (hasOwn(payload, 'blockCompanyNameRegMatchStrategy')) { + bossConfig.blockCompanyNameRegMatchStrategy = payload.blockCompanyNameRegMatchStrategy + } promiseArr.push(writeConfigFile('boss.json', bossConfig)) diff --git a/packages/ui/src/main/flow/READ_NO_REPLY_AUTO_REMINDER_MAIN/index.ts b/packages/ui/src/main/flow/READ_NO_REPLY_AUTO_REMINDER_MAIN/index.ts index d444f1e..c28430d 100644 --- a/packages/ui/src/main/flow/READ_NO_REPLY_AUTO_REMINDER_MAIN/index.ts +++ b/packages/ui/src/main/flow/READ_NO_REPLY_AUTO_REMINDER_MAIN/index.ts @@ -60,7 +60,23 @@ const rechatLlmFallback = const expectJobTypeRegExpStr = readConfigFile('boss.json').expectJobTypeRegExpStr const onlyRemindBossWithExpectJobType = - readConfigFile('boss.json').autoReminder?.onlyRemindBossWithExpectJobType ?? !!expectJobTypeRegExpStr + readConfigFile('boss.json').autoReminder?.onlyRemindBossWithExpectJobType ?? + !!expectJobTypeRegExpStr + +const blockCompanyNameRegExpStr = readConfigFile('boss.json').blockCompanyNameRegExpStr ?? '' +const blockCompanyNameRegExp = (() => { + if (!blockCompanyNameRegExpStr?.trim()) { + return null + } + try { + return new RegExp(blockCompanyNameRegExpStr, 'im') + } catch { + return null + } +})() +const onlyRemindBossWithoutBlockCompanyName = + readConfigFile('boss.json').autoReminder?.onlyRemindBossWithoutBlockCompanyName ?? + !!blockCompanyNameRegExp const dbInitPromise = initDb(getPublicDbFilePath()) @@ -156,7 +172,8 @@ async function saveCurrentChatRecord(page) { async function checkJobIsClosed() { const encryptJobId = await pageMapByName.boss!.evaluate(() => { - return document.querySelector('.chat-conversation .chat-im.chat-editor')?.__vue__?.conversation$.encryptJobId + return document.querySelector('.chat-conversation .chat-im.chat-editor')?.__vue__?.conversation$ + .encryptJobId }) if (!encryptJobId) { return false @@ -431,6 +448,9 @@ const mainLoop = async () => { const toCheckItemAtIndex = friendListData.findIndex((it, index) => { return ( index >= cursorToContinueFind && + (onlyRemindBossWithoutBlockCompanyName && blockCompanyNameRegExp + ? !blockCompanyNameRegExp.test(it.brandName) + : true) && (rechatLimitDay && it.updateTime ? +new Date() - it.updateTime < rechatLimitDay * 24 * 60 * 60 * 1000 : true) && @@ -605,11 +625,14 @@ export async function runEntry() { }) initPublicIpc() await connectToDaemon() - await sendToDaemon({ - type: 'ping' - }, { - needCallback: true - }) + await sendToDaemon( + { + type: 'ping' + }, + { + needCallback: true + } + ) sendToDaemon({ type: 'worker-to-gui-message', data: { @@ -690,7 +713,11 @@ export async function runEntry() { process.exit(AUTO_CHAT_ERROR_EXIT_CODE.ACCESS_IS_DENIED) break } - if (err.message.includes(`PUPPETEER_IS_NOT_EXECUTABLE`) || err.message.includes(`Could not find Chrome`) || err.message.includes(`no executable was found`)) { + if ( + err.message.includes(`PUPPETEER_IS_NOT_EXECUTABLE`) || + err.message.includes(`Could not find Chrome`) || + err.message.includes(`no executable was found`) + ) { process.exit(AUTO_CHAT_ERROR_EXIT_CODE.PUPPETEER_IS_NOT_EXECUTABLE) break } @@ -703,7 +730,7 @@ export async function runEntry() { buttons: ['退出'] }) process.exit(AUTO_CHAT_ERROR_EXIT_CODE.LLM_UNAVAILABLE) - break; + break } } } finally { diff --git a/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/index.vue b/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/index.vue index 9c63d91..c54bdfd 100644 --- a/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/index.vue +++ b/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/index.vue @@ -245,14 +245,16 @@
+
+ {{ formatMarkReason(row) }}
+
+ {{ markReasonTopicMap[row.markReason] }}
+ {{ formatMarkReason(row) }}
+