diff --git a/packages/geek-auto-start-chat-with-boss/combineCalculator.mjs b/packages/geek-auto-start-chat-with-boss/combineCalculator.mjs index 84a637e..726066a 100644 --- a/packages/geek-auto-start-chat-with-boss/combineCalculator.mjs +++ b/packages/geek-auto-start-chat-with-boss/combineCalculator.mjs @@ -90,7 +90,7 @@ export function* combineFiltersWithConstraintsGenerator(selectedFilters) { //#region get count of combinations // 计算符合限制条件的组合数量 -export function calculateTotalCombinations(selectedFilters) { +export function calculateTotalCombinations(selectedFilters, includeEmptyCondition) { const { salaryList = [], experienceList = [], @@ -106,8 +106,21 @@ export function calculateTotalCombinations(selectedFilters) { const scaleComb = combineWithZero(scaleList, 0, scaleList.length) // Scale: 0 个或更多 const industryComb = combineWithZero(industryList, 0, 3) // Industry: 0-3 个 - return [salaryComb, experienceComb, degreeComb, scaleComb, industryComb].reduce((accu, cur) => { + let result = [salaryComb, experienceComb, degreeComb, scaleComb, industryComb].reduce((accu, cur) => { return accu * cur.length }, 1) + if (!includeEmptyCondition) { + result -= 1 + } + return result } //#endregion + +export function checkAnyCombineBossRecommendFilterHasCondition(value) { + if (!Object.keys(value ?? {}).length) { + return false + } + return Object.keys(value).some((k) => { + return !!value[k]?.length + }) +} 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 b765b21..7f8215a 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 @@ -6,6 +6,7 @@ "scaleList": [], "industryList": [] }, + "isSkipEmptyConditionForCombineRecommendJobFilter": false, "expectJobRegExpStr": "", "jobNotMatchStrategy": 1, "jobNotActiveStrategy": 1, diff --git a/packages/geek-auto-start-chat-with-boss/index.mjs b/packages/geek-auto-start-chat-with-boss/index.mjs index 66a224d..17028af 100644 --- a/packages/geek-auto-start-chat-with-boss/index.mjs +++ b/packages/geek-auto-start-chat-with-boss/index.mjs @@ -12,7 +12,11 @@ import { EventEmitter } from 'node:events' import { setDomainLocalStorage } from '@geekgeekrun/utils/puppeteer/local-storage.mjs' import { readConfigFile, writeStorageFile, ensureConfigFileExist, readStorageFile, ensureStorageFileExist } from './runtime-file-utils.mjs' -import { calculateTotalCombinations, combineFiltersWithConstraintsGenerator } from './combineCalculator.mjs' +import { + calculateTotalCombinations, + combineFiltersWithConstraintsGenerator, + checkAnyCombineBossRecommendFilterHasCondition +} from './combineCalculator.mjs' import { default as jobFilterConditions } from './internal-config/job-filter-conditions-20241002.json' import { default as rawIndustryFilterExemption } from './internal-config/job-filter-industry-filter-exemption-20241002.json' import { ChatStartupFrom } from '@geekgeekrun/sqlite-plugin/dist/entity/ChatStartupLog' @@ -78,6 +82,10 @@ const bossLocalStorage = readStorageFile('boss-local-storage.json') const targetCompanyList = readConfigFile('target-company-list.json').filter(it => !!it.trim()); const anyCombineRecommendJobFilter = readConfigFile('boss.json').anyCombineRecommendJobFilter +let isSkipEmptyConditionForCombineRecommendJobFilter = readConfigFile('boss.json').isSkipEmptyConditionForCombineRecommendJobFilter +if (!checkAnyCombineBossRecommendFilterHasCondition(anyCombineRecommendJobFilter)) { + isSkipEmptyConditionForCombineRecommendJobFilter = false +} const expectJobRegExpStr = readConfigFile('boss.json').expectJobRegExpStr const jobNotMatchStrategy = readConfigFile('boss.json').jobNotMatchStrategy ?? MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS @@ -495,14 +503,25 @@ async function toRecommendPage (hooks) { await sleepWithRandomDelay(2500) await Promise.all([ - page.waitForSelector('.c-expect-select .expect-list .expect-item'), - page.waitForSelector('.job-list-container .rec-job-list') + page.waitForSelector('.c-expect-select .expect-list .expect-item'), + Promise.race([ + page.waitForSelector(".job-list-container .rec-job-list"), + page.waitForSelector(".recommend-result-job .job-empty-wrapper") + ]) ]) await page.click(`.c-expect-select .expect-list .expect-item`) const currentActiveJobIndex = await page.evaluate(` [...document.querySelectorAll('.c-expect-select .expect-list .expect-item')].findIndex(it => it.classList.contains('active')) `) + if ( + isSkipEmptyConditionForCombineRecommendJobFilter && + Object.keys(filterCondition).length && + Object.keys(filterCondition).every(k => !filterCondition[k]?.length) + ) { + sleep(4000) + continue iterateFilterCondition + } expectJobList = await page.evaluate(`document.querySelector('.c-expect-select')?.__vue__?.expectList`) if (currentActiveJobIndex === currentExceptJobIndex) { // first navigation and can immediately start chat (recommend job) @@ -524,9 +543,12 @@ async function toRecommendPage (hooks) { await storeStorage(page).catch(() => void 0) await sleepWithRandomDelay(2000) } - await sleepWithRandomDelay(3000) + await sleepWithRandomDelay(1500) await setFilterCondition(filterCondition) - + await sleep(1500) // TODO: accurately check if job list request sent and response received after set condition + await page.waitForFunction(() => { + return !document.querySelector('.job-recommend-result .job-rec-loading') + }) try { const { targetJobIndex, targetJobData } = await new Promise(async (resolve, reject) => { try { @@ -557,9 +579,17 @@ async function toRecommendPage (hooks) { } } ) - // job list - const recommendJobListElProxy = await page.$('.job-list-container .rec-job-list') + let recommendJobListElProxy + try { + recommendJobListElProxy= await page.waitForSelector('.job-list-container .rec-job-list', { timeout: 5 * 1000 }) + } catch {} + if (!recommendJobListElProxy){ + await hooks.encounterEmptyRecommendJobList?.promise({ + pageQuery: await page.evaluate(() => new URL(location.href).searchParams.toString()) + }) + throw new Error('CANNOT_FIND_EXCEPT_JOB_IN_THIS_FILTER_CONDITION') + } let jobListData = [] async function updateJobListData () { jobListData = await page.evaluate(`document.querySelector('.page-jobs-main')?.__vue__?.jobList`) diff --git a/packages/run-core-of-geek-auto-start-chat-with-boss/main.mjs b/packages/run-core-of-geek-auto-start-chat-with-boss/main.mjs index 473e0a4..7945286 100644 --- a/packages/run-core-of-geek-auto-start-chat-with-boss/main.mjs +++ b/packages/run-core-of-geek-auto-start-chat-with-boss/main.mjs @@ -56,7 +56,8 @@ const main = async () => { newChatStartup: new AsyncSeriesHook(['positionInfoDetail', 'chatRunningContext']), noPositionFoundForCurrentJob: new SyncHook(), noPositionFoundAfterTraverseAllJob: new SyncHook(), - errorEncounter: new SyncHook(['errorInfo']) + errorEncounter: new SyncHook(['errorInfo']), + encounterEmptyRecommendJobList: new AsyncSeriesHook(['args']) } initPlugins(hooks) await hooks.daemonInitialized.callAsync() diff --git a/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS_MAIN/index.ts b/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS_MAIN/index.ts index 0ec7ff4..5108946 100644 --- a/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS_MAIN/index.ts +++ b/packages/ui/src/main/flow/GEEK_AUTO_START_CHAT_WITH_BOSS_MAIN/index.ts @@ -93,7 +93,8 @@ const runAutoChat = async () => { jobMarkedAsNotSuit: new AsyncSeriesHook(['positionInfoDetail', 'markDetail']), noPositionFoundForCurrentJob: new SyncHook(), noPositionFoundAfterTraverseAllJob: new SyncHook(), - errorEncounter: new SyncHook(['errorInfo']) + errorEncounter: new SyncHook(['errorInfo']), + encounterEmptyRecommendJobList: new AsyncSeriesHook(['args']) } initPlugins(hooks) 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 dd723a7..67600d2 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 @@ -152,6 +152,10 @@ export default function initIpc() { if (hasOwn(payload, 'jobDetailRegExpMatchLogic')) { bossConfig.jobDetailRegExpMatchLogic = payload.jobDetailRegExpMatchLogic } + if (hasOwn(payload, 'isSkipEmptyConditionForCombineRecommendJobFilter')) { + bossConfig.isSkipEmptyConditionForCombineRecommendJobFilter = + payload.isSkipEmptyConditionForCombineRecommendJobFilter + } promiseArr.push(writeConfigFile('boss.json', bossConfig)) diff --git a/packages/ui/src/main/utils/gtag/GtagPlugin.ts b/packages/ui/src/main/utils/gtag/GtagPlugin.ts index e0401d0..a0ab201 100644 --- a/packages/ui/src/main/utils/gtag/GtagPlugin.ts +++ b/packages/ui/src/main/utils/gtag/GtagPlugin.ts @@ -23,5 +23,8 @@ export default class GtagPlugin { hooks.noPositionFoundAfterTraverseAllJob.tap('GtagPlugin', () => { gtag('no_position_found_after_traverse_all_job') }) + hooks.encounterEmptyRecommendJobList.tap('GtagPlugin', ({ pageQuery }) => { + gtag('encounter_empty_rec_job_list', { pageQuery }) + }) } } 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 8add4a1..4836b0d 100644 --- a/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/index.vue +++ b/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/index.vue @@ -791,7 +791,7 @@ - +
职位备选筛选条件
-
- 当前组合条件数:{{ - currentAnyCombineRecommendJobFilterCombinationCount.toLocaleString() - }} - 不建议选择太多组合条件 -
+ + + 跳过初始空条件,直接使用备选条件查找职位 + + + 跳过初始空条件,直接使用备选条件查找职位 + + +
+ 当前组合条件数:{{ + currentAnyCombineRecommendJobFilterCombinationCount.toLocaleString() + }} + 不建议选择太多组合条件 +
@@ -850,7 +861,10 @@ import { QuestionFilled } from '@element-plus/icons-vue' import { useRouter } from 'vue-router' import AnyCombineBossRecommendFilter from '@renderer/features/AnyCombineBossRecommendFilter/index.vue' import { activeDescList } from '@geekgeekrun/geek-auto-start-chat-with-boss/constant.mjs' -import { calculateTotalCombinations } from '@geekgeekrun/geek-auto-start-chat-with-boss/combineCalculator.mjs' +import { + calculateTotalCombinations, + checkAnyCombineBossRecommendFilterHasCondition +} from '@geekgeekrun/geek-auto-start-chat-with-boss/combineCalculator.mjs' import { gtagRenderer } from '@renderer/utils/gtag' import defaultTargetCompanyListConf from '@geekgeekrun/geek-auto-start-chat-with-boss/default-config-file/target-company-list.json' import { ArrowDown } from '@element-plus/icons-vue' @@ -894,11 +908,24 @@ const formContent = ref({ expectWorkExpNotMatchStrategy: MarkAsNotSuitOp.NO_OP, strategyScopeOptionWhenMarkJobWorkExpNotMatch: StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB, - jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY, + + isSkipEmptyConditionForCombineRecommendJobFilter: false +}) + +const anyCombineBossRecommendFilterHasCondition = computed(() => { + return checkAnyCombineBossRecommendFilterHasCondition( + formContent.value.anyCombineRecommendJobFilter + ) }) const currentAnyCombineRecommendJobFilterCombinationCount = computed(() => { - return calculateTotalCombinations(formContent.value.anyCombineRecommendJobFilter) + return calculateTotalCombinations( + formContent.value.anyCombineRecommendJobFilter, + anyCombineBossRecommendFilterHasCondition.value + ? !formContent.value.isSkipEmptyConditionForCombineRecommendJobFilter + : true + ) }) const unwatchAnyCombineRecommendJobFilter = ref void)>(null) @@ -996,6 +1023,8 @@ electron.ipcRenderer.invoke('fetch-config-file-content').then((res) => { StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB formContent.value.jobDetailRegExpMatchLogic = res.config['boss.json'].jobDetailRegExpMatchLogic ?? JobDetailRegExpMatchLogic.EVERY + formContent.value.isSkipEmptyConditionForCombineRecommendJobFilter = + res.config['boss.json'].isSkipEmptyConditionForCombineRecommendJobFilter ?? false }) const formRules = {