mirror of
https://github.com/geekgeekrun/geekgeekrun.git
synced 2026-09-07 08:27:13 +08:00
allow skip empty filter condition when set backup filter condition to search job
This commit is contained in:
@@ -90,7 +90,7 @@ export function* combineFiltersWithConstraintsGenerator(selectedFilters) {
|
|||||||
//#region get count of combinations
|
//#region get count of combinations
|
||||||
|
|
||||||
// 计算符合限制条件的组合数量
|
// 计算符合限制条件的组合数量
|
||||||
export function calculateTotalCombinations(selectedFilters) {
|
export function calculateTotalCombinations(selectedFilters, includeEmptyCondition) {
|
||||||
const {
|
const {
|
||||||
salaryList = [],
|
salaryList = [],
|
||||||
experienceList = [],
|
experienceList = [],
|
||||||
@@ -106,8 +106,21 @@ export function calculateTotalCombinations(selectedFilters) {
|
|||||||
const scaleComb = combineWithZero(scaleList, 0, scaleList.length) // Scale: 0 个或更多
|
const scaleComb = combineWithZero(scaleList, 0, scaleList.length) // Scale: 0 个或更多
|
||||||
const industryComb = combineWithZero(industryList, 0, 3) // Industry: 0-3 个
|
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
|
return accu * cur.length
|
||||||
}, 1)
|
}, 1)
|
||||||
|
if (!includeEmptyCondition) {
|
||||||
|
result -= 1
|
||||||
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
export function checkAnyCombineBossRecommendFilterHasCondition(value) {
|
||||||
|
if (!Object.keys(value ?? {}).length) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return Object.keys(value).some((k) => {
|
||||||
|
return !!value[k]?.length
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
"scaleList": [],
|
"scaleList": [],
|
||||||
"industryList": []
|
"industryList": []
|
||||||
},
|
},
|
||||||
|
"isSkipEmptyConditionForCombineRecommendJobFilter": false,
|
||||||
"expectJobRegExpStr": "",
|
"expectJobRegExpStr": "",
|
||||||
"jobNotMatchStrategy": 1,
|
"jobNotMatchStrategy": 1,
|
||||||
"jobNotActiveStrategy": 1,
|
"jobNotActiveStrategy": 1,
|
||||||
|
|||||||
@@ -12,7 +12,11 @@ import { EventEmitter } from 'node:events'
|
|||||||
import { setDomainLocalStorage } from '@geekgeekrun/utils/puppeteer/local-storage.mjs'
|
import { setDomainLocalStorage } from '@geekgeekrun/utils/puppeteer/local-storage.mjs'
|
||||||
|
|
||||||
import { readConfigFile, writeStorageFile, ensureConfigFileExist, readStorageFile, ensureStorageFileExist } from './runtime-file-utils.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 jobFilterConditions } from './internal-config/job-filter-conditions-20241002.json'
|
||||||
import { default as rawIndustryFilterExemption } from './internal-config/job-filter-industry-filter-exemption-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'
|
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 targetCompanyList = readConfigFile('target-company-list.json').filter(it => !!it.trim());
|
||||||
|
|
||||||
const anyCombineRecommendJobFilter = readConfigFile('boss.json').anyCombineRecommendJobFilter
|
const anyCombineRecommendJobFilter = readConfigFile('boss.json').anyCombineRecommendJobFilter
|
||||||
|
let isSkipEmptyConditionForCombineRecommendJobFilter = readConfigFile('boss.json').isSkipEmptyConditionForCombineRecommendJobFilter
|
||||||
|
if (!checkAnyCombineBossRecommendFilterHasCondition(anyCombineRecommendJobFilter)) {
|
||||||
|
isSkipEmptyConditionForCombineRecommendJobFilter = false
|
||||||
|
}
|
||||||
const expectJobRegExpStr = readConfigFile('boss.json').expectJobRegExpStr
|
const expectJobRegExpStr = readConfigFile('boss.json').expectJobRegExpStr
|
||||||
const jobNotMatchStrategy = readConfigFile('boss.json').jobNotMatchStrategy ?? MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
|
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 sleepWithRandomDelay(2500)
|
||||||
|
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
page.waitForSelector('.c-expect-select .expect-list .expect-item'),
|
page.waitForSelector('.c-expect-select .expect-list .expect-item'),
|
||||||
page.waitForSelector('.job-list-container .rec-job-list')
|
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`)
|
await page.click(`.c-expect-select .expect-list .expect-item`)
|
||||||
const currentActiveJobIndex = await page.evaluate(`
|
const currentActiveJobIndex = await page.evaluate(`
|
||||||
[...document.querySelectorAll('.c-expect-select .expect-list .expect-item')].findIndex(it => it.classList.contains('active'))
|
[...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`)
|
expectJobList = await page.evaluate(`document.querySelector('.c-expect-select')?.__vue__?.expectList`)
|
||||||
if (currentActiveJobIndex === currentExceptJobIndex) {
|
if (currentActiveJobIndex === currentExceptJobIndex) {
|
||||||
// first navigation and can immediately start chat (recommend job)
|
// first navigation and can immediately start chat (recommend job)
|
||||||
@@ -524,9 +543,12 @@ async function toRecommendPage (hooks) {
|
|||||||
await storeStorage(page).catch(() => void 0)
|
await storeStorage(page).catch(() => void 0)
|
||||||
await sleepWithRandomDelay(2000)
|
await sleepWithRandomDelay(2000)
|
||||||
}
|
}
|
||||||
await sleepWithRandomDelay(3000)
|
await sleepWithRandomDelay(1500)
|
||||||
await setFilterCondition(filterCondition)
|
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 {
|
try {
|
||||||
const { targetJobIndex, targetJobData } = await new Promise(async (resolve, reject) => {
|
const { targetJobIndex, targetJobData } = await new Promise(async (resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
@@ -557,9 +579,17 @@ async function toRecommendPage (hooks) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
// job list
|
// 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 = []
|
let jobListData = []
|
||||||
async function updateJobListData () {
|
async function updateJobListData () {
|
||||||
jobListData = await page.evaluate(`document.querySelector('.page-jobs-main')?.__vue__?.jobList`)
|
jobListData = await page.evaluate(`document.querySelector('.page-jobs-main')?.__vue__?.jobList`)
|
||||||
|
|||||||
@@ -56,7 +56,8 @@ const main = async () => {
|
|||||||
newChatStartup: new AsyncSeriesHook(['positionInfoDetail', 'chatRunningContext']),
|
newChatStartup: new AsyncSeriesHook(['positionInfoDetail', 'chatRunningContext']),
|
||||||
noPositionFoundForCurrentJob: new SyncHook(),
|
noPositionFoundForCurrentJob: new SyncHook(),
|
||||||
noPositionFoundAfterTraverseAllJob: new SyncHook(),
|
noPositionFoundAfterTraverseAllJob: new SyncHook(),
|
||||||
errorEncounter: new SyncHook(['errorInfo'])
|
errorEncounter: new SyncHook(['errorInfo']),
|
||||||
|
encounterEmptyRecommendJobList: new AsyncSeriesHook(['args'])
|
||||||
}
|
}
|
||||||
initPlugins(hooks)
|
initPlugins(hooks)
|
||||||
await hooks.daemonInitialized.callAsync()
|
await hooks.daemonInitialized.callAsync()
|
||||||
|
|||||||
@@ -93,7 +93,8 @@ const runAutoChat = async () => {
|
|||||||
jobMarkedAsNotSuit: new AsyncSeriesHook(['positionInfoDetail', 'markDetail']),
|
jobMarkedAsNotSuit: new AsyncSeriesHook(['positionInfoDetail', 'markDetail']),
|
||||||
noPositionFoundForCurrentJob: new SyncHook(),
|
noPositionFoundForCurrentJob: new SyncHook(),
|
||||||
noPositionFoundAfterTraverseAllJob: new SyncHook(),
|
noPositionFoundAfterTraverseAllJob: new SyncHook(),
|
||||||
errorEncounter: new SyncHook(['errorInfo'])
|
errorEncounter: new SyncHook(['errorInfo']),
|
||||||
|
encounterEmptyRecommendJobList: new AsyncSeriesHook(['args'])
|
||||||
}
|
}
|
||||||
initPlugins(hooks)
|
initPlugins(hooks)
|
||||||
|
|
||||||
|
|||||||
@@ -152,6 +152,10 @@ export default function initIpc() {
|
|||||||
if (hasOwn(payload, 'jobDetailRegExpMatchLogic')) {
|
if (hasOwn(payload, 'jobDetailRegExpMatchLogic')) {
|
||||||
bossConfig.jobDetailRegExpMatchLogic = payload.jobDetailRegExpMatchLogic
|
bossConfig.jobDetailRegExpMatchLogic = payload.jobDetailRegExpMatchLogic
|
||||||
}
|
}
|
||||||
|
if (hasOwn(payload, 'isSkipEmptyConditionForCombineRecommendJobFilter')) {
|
||||||
|
bossConfig.isSkipEmptyConditionForCombineRecommendJobFilter =
|
||||||
|
payload.isSkipEmptyConditionForCombineRecommendJobFilter
|
||||||
|
}
|
||||||
|
|
||||||
promiseArr.push(writeConfigFile('boss.json', bossConfig))
|
promiseArr.push(writeConfigFile('boss.json', bossConfig))
|
||||||
|
|
||||||
|
|||||||
@@ -23,5 +23,8 @@ export default class GtagPlugin {
|
|||||||
hooks.noPositionFoundAfterTraverseAllJob.tap('GtagPlugin', () => {
|
hooks.noPositionFoundAfterTraverseAllJob.tap('GtagPlugin', () => {
|
||||||
gtag('no_position_found_after_traverse_all_job')
|
gtag('no_position_found_after_traverse_all_job')
|
||||||
})
|
})
|
||||||
|
hooks.encounterEmptyRecommendJobList.tap('GtagPlugin', ({ pageQuery }) => {
|
||||||
|
gtag('encounter_empty_rec_job_list', { pageQuery })
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -791,7 +791,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
<el-card class="config-section">
|
<el-card class="config-section">
|
||||||
<el-form-item prop="filter" mb0>
|
<el-form-item prop="filter">
|
||||||
<div font-size-16px>
|
<div font-size-16px>
|
||||||
职位备选筛选条件
|
职位备选筛选条件
|
||||||
<el-tooltip
|
<el-tooltip
|
||||||
@@ -811,17 +811,28 @@
|
|||||||
</el-tooltip>
|
</el-tooltip>
|
||||||
</div>
|
</div>
|
||||||
<AnyCombineBossRecommendFilter v-model="formContent.anyCombineRecommendJobFilter" />
|
<AnyCombineBossRecommendFilter v-model="formContent.anyCombineRecommendJobFilter" />
|
||||||
<div font-size-12px>
|
|
||||||
当前组合条件数:{{
|
|
||||||
currentAnyCombineRecommendJobFilterCombinationCount.toLocaleString()
|
|
||||||
}}
|
|
||||||
<span
|
|
||||||
v-if="currentAnyCombineRecommendJobFilterCombinationCount >= 20"
|
|
||||||
class="color-orange"
|
|
||||||
>不建议选择太多组合条件</span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item prop="filter" mb0>
|
||||||
|
<el-checkbox
|
||||||
|
v-if="anyCombineBossRecommendFilterHasCondition"
|
||||||
|
v-model="formContent.isSkipEmptyConditionForCombineRecommendJobFilter"
|
||||||
|
>
|
||||||
|
<span font-size-12px>跳过初始空条件,直接使用备选条件查找职位</span>
|
||||||
|
</el-checkbox>
|
||||||
|
<el-checkbox v-else :model-value="false" disabled>
|
||||||
|
<span font-size-12px>跳过初始空条件,直接使用备选条件查找职位</span>
|
||||||
|
</el-checkbox>
|
||||||
|
</el-form-item>
|
||||||
|
<div font-size-12px mt10px>
|
||||||
|
当前组合条件数:{{
|
||||||
|
currentAnyCombineRecommendJobFilterCombinationCount.toLocaleString()
|
||||||
|
}}
|
||||||
|
<span
|
||||||
|
v-if="currentAnyCombineRecommendJobFilterCombinationCount >= 20"
|
||||||
|
class="color-orange"
|
||||||
|
>不建议选择太多组合条件</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</el-card>
|
</el-card>
|
||||||
</el-form>
|
</el-form>
|
||||||
</div>
|
</div>
|
||||||
@@ -850,7 +861,10 @@ import { QuestionFilled } from '@element-plus/icons-vue'
|
|||||||
import { useRouter } from 'vue-router'
|
import { useRouter } from 'vue-router'
|
||||||
import AnyCombineBossRecommendFilter from '@renderer/features/AnyCombineBossRecommendFilter/index.vue'
|
import AnyCombineBossRecommendFilter from '@renderer/features/AnyCombineBossRecommendFilter/index.vue'
|
||||||
import { activeDescList } from '@geekgeekrun/geek-auto-start-chat-with-boss/constant.mjs'
|
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 { gtagRenderer } from '@renderer/utils/gtag'
|
||||||
import defaultTargetCompanyListConf from '@geekgeekrun/geek-auto-start-chat-with-boss/default-config-file/target-company-list.json'
|
import defaultTargetCompanyListConf from '@geekgeekrun/geek-auto-start-chat-with-boss/default-config-file/target-company-list.json'
|
||||||
import { ArrowDown } from '@element-plus/icons-vue'
|
import { ArrowDown } from '@element-plus/icons-vue'
|
||||||
@@ -894,11 +908,24 @@ const formContent = ref({
|
|||||||
expectWorkExpNotMatchStrategy: MarkAsNotSuitOp.NO_OP,
|
expectWorkExpNotMatchStrategy: MarkAsNotSuitOp.NO_OP,
|
||||||
strategyScopeOptionWhenMarkJobWorkExpNotMatch:
|
strategyScopeOptionWhenMarkJobWorkExpNotMatch:
|
||||||
StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB,
|
StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB,
|
||||||
jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY
|
jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY,
|
||||||
|
|
||||||
|
isSkipEmptyConditionForCombineRecommendJobFilter: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const anyCombineBossRecommendFilterHasCondition = computed(() => {
|
||||||
|
return checkAnyCombineBossRecommendFilterHasCondition(
|
||||||
|
formContent.value.anyCombineRecommendJobFilter
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const currentAnyCombineRecommendJobFilterCombinationCount = computed(() => {
|
const currentAnyCombineRecommendJobFilterCombinationCount = computed(() => {
|
||||||
return calculateTotalCombinations(formContent.value.anyCombineRecommendJobFilter)
|
return calculateTotalCombinations(
|
||||||
|
formContent.value.anyCombineRecommendJobFilter,
|
||||||
|
anyCombineBossRecommendFilterHasCondition.value
|
||||||
|
? !formContent.value.isSkipEmptyConditionForCombineRecommendJobFilter
|
||||||
|
: true
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
const unwatchAnyCombineRecommendJobFilter = ref<null | (() => void)>(null)
|
const unwatchAnyCombineRecommendJobFilter = ref<null | (() => void)>(null)
|
||||||
@@ -996,6 +1023,8 @@ electron.ipcRenderer.invoke('fetch-config-file-content').then((res) => {
|
|||||||
StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB
|
StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB
|
||||||
formContent.value.jobDetailRegExpMatchLogic =
|
formContent.value.jobDetailRegExpMatchLogic =
|
||||||
res.config['boss.json'].jobDetailRegExpMatchLogic ?? JobDetailRegExpMatchLogic.EVERY
|
res.config['boss.json'].jobDetailRegExpMatchLogic ?? JobDetailRegExpMatchLogic.EVERY
|
||||||
|
formContent.value.isSkipEmptyConditionForCombineRecommendJobFilter =
|
||||||
|
res.config['boss.json'].isSkipEmptyConditionForCombineRecommendJobFilter ?? false
|
||||||
})
|
})
|
||||||
|
|
||||||
const formRules = {
|
const formRules = {
|
||||||
|
|||||||
Reference in New Issue
Block a user