diff --git a/packages/geek-auto-start-chat-with-boss/combineCalculator.mjs b/packages/geek-auto-start-chat-with-boss/combineCalculator.mjs index 726066a..a9f3169 100644 --- a/packages/geek-auto-start-chat-with-boss/combineCalculator.mjs +++ b/packages/geek-auto-start-chat-with-boss/combineCalculator.mjs @@ -124,3 +124,35 @@ export function checkAnyCombineBossRecommendFilterHasCondition(value) { return !!value[k]?.length }) } + +export function getStaticCombineFilterKey(condition) { + const kAsO = {} + for (const key of Object.keys(condition ?? []).sort()) { + if (condition[key] === null || condition[key] === undefined) { + continue + } + kAsO[key] = condition[key] + } + return JSON.stringify(kAsO) +} + +export function formatStaticCombineFilters(rawStaticCombineRecommendJobFilterConditions) { + rawStaticCombineRecommendJobFilterConditions = JSON.parse(JSON.stringify(rawStaticCombineRecommendJobFilterConditions)) + const map = new Map() + for (const condition of rawStaticCombineRecommendJobFilterConditions ?? []) { + const key = getStaticCombineFilterKey(condition) + map.set(key, condition) + } + const conditions = Array.from(map.values()) + const result = conditions.map((condition) => { + return { + salaryList: condition.salary ? [condition.salary] : [], + experienceList: condition.experience ? [condition.experience] : [], + degreeList: condition.degree ? [condition.degree] : [], + scaleList: condition.scale ? [condition.scale] : [], + industryList: condition.industry ? [condition.industry] : [] + } + }) + result.unshift(null) + return result +} 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 86602cd..72c9c97 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 @@ -1,4 +1,5 @@ { + "combineRecommendJobFilterType": 1, "anyCombineRecommendJobFilter": { "salaryList": [], "experienceList": [], @@ -6,6 +7,7 @@ "scaleList": [], "industryList": [] }, + "staticCombineRecommendJobFilterConditions": [], "isSkipEmptyConditionForCombineRecommendJobFilter": false, "expectJobRegExpStr": "", "jobNotMatchStrategy": 1, diff --git a/packages/geek-auto-start-chat-with-boss/index.mjs b/packages/geek-auto-start-chat-with-boss/index.mjs index 73cc923..144b9f1 100644 --- a/packages/geek-auto-start-chat-with-boss/index.mjs +++ b/packages/geek-auto-start-chat-with-boss/index.mjs @@ -15,12 +15,21 @@ import { readConfigFile, writeStorageFile, ensureConfigFileExist, readStorageFil import { calculateTotalCombinations, combineFiltersWithConstraintsGenerator, - checkAnyCombineBossRecommendFilterHasCondition + checkAnyCombineBossRecommendFilterHasCondition, + formatStaticCombineFilters, } 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' -import { MarkAsNotSuitReason, MarkAsNotSuitOp, StrategyScopeOptionWhenMarkJobNotMatch, SalaryCalculateWay, JobDetailRegExpMatchLogic, JobSource } from '@geekgeekrun/sqlite-plugin/dist/enums' +import { + MarkAsNotSuitReason, + MarkAsNotSuitOp, + StrategyScopeOptionWhenMarkJobNotMatch, + SalaryCalculateWay, + JobDetailRegExpMatchLogic, + JobSource, + CombineRecommendJobFilterType +} from '@geekgeekrun/sqlite-plugin/dist/enums' import { activeDescList, RECOMMEND_JOB_ENTRY_SELECTOR, @@ -85,8 +94,10 @@ const bossCookies = readStorageFile('boss-cookies.json') const bossLocalStorage = readStorageFile('boss-local-storage.json') const targetCompanyList = readConfigFile('target-company-list.json').filter(it => !!it.trim()); +const combineRecommendJobFilterType = readConfigFile('boss.json').combineRecommendJobFilterType ?? CombineRecommendJobFilterType.ANY_COMBINE const anyCombineRecommendJobFilter = readConfigFile('boss.json').anyCombineRecommendJobFilter +const staticCombineRecommendJobFilterConditions = readConfigFile('boss.json').staticCombineRecommendJobFilterConditions ?? [] let isSkipEmptyConditionForCombineRecommendJobFilter = readConfigFile('boss.json').isSkipEmptyConditionForCombineRecommendJobFilter if (!checkAnyCombineBossRecommendFilterHasCondition(anyCombineRecommendJobFilter)) { isSkipEmptyConditionForCombineRecommendJobFilter = false @@ -108,7 +119,18 @@ const isSalaryFilterEnabled = expectSalaryLow || expectSalaryHigh const strategyScopeOptionWhenMarkSalaryNotMatch = readConfigFile('boss.json').strategyScopeOptionWhenMarkSalaryNotMatch ?? StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB // work exp -const expectWorkExpList = readConfigFile('boss.json').expectWorkExpList ?? [] +let expectWorkExpList = readConfigFile('boss.json').expectWorkExpList ?? [] +const expectWorkExpListSet = new Set(expectWorkExpList) +if ( + expectWorkExpListSet.has('应届生') || + expectWorkExpListSet.has('在校生') +) { + expectWorkExpListSet.delete('应届生') + expectWorkExpListSet.delete('在校生') + expectWorkExpListSet.add('在校/应届') +} +expectWorkExpList = Array.from(expectWorkExpListSet) + const expectWorkExpNotMatchStrategy = readConfigFile('boss.json').expectWorkExpNotMatchStrategy ?? MarkAsNotSuitOp.NO_OP const strategyScopeOptionWhenMarkJobWorkExpNotMatch = readConfigFile('boss.json').strategyScopeOptionWhenMarkJobWorkExpNotMatch ?? StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB @@ -271,8 +293,8 @@ 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="面试过/入职过"]`)) ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title="重复推荐"]`)) if (opProxy) { @@ -282,10 +304,10 @@ async function markJobAsNotSuitInRecommendPage (reasonCode) { break } case MarkAsNotSuitReason.JOB_SALARY_NOT_SUIT: { - const opProxy = (await chooseReasonDialogProxy.$(`xpath///*[contains(@class,'zp-type-item')][contains(@title, "薪资")]`)) + 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="面试过/入职过"]`)) ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title="重复推荐"]`)) if (opProxy) { @@ -296,11 +318,11 @@ async function markJobAsNotSuitInRecommendPage (reasonCode) { } case MarkAsNotSuitReason.JOB_NOT_SUIT: default: { - const jobNotSuitOptionProxy = (await chooseReasonDialogProxy.$(`.zp-type-item[title$="职位"]`)) + const opProxy = (await chooseReasonDialogProxy.$(`.zp-type-item[title$="职位"]`)) ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title="面试过/入职过"]`)) ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title="重复推荐"]`)) - if (jobNotSuitOptionProxy) { - await jobNotSuitOptionProxy.click() + if (opProxy) { + await opProxy.click() isOptionChosen = true } break @@ -348,7 +370,7 @@ export function testIfJobTitleOrDescriptionSuit (jobInfo, matchLogic) { try { if (expectJobNameRegExpStr.trim()) { const regExp = new RegExp(expectJobNameRegExpStr, 'i') - isJobNameSuit = regExp.test(jobInfo.jobName) + isJobNameSuit = regExp.test(jobInfo.jobName?.replace(/\n/g, '') ?? '') } } catch { } @@ -356,7 +378,7 @@ export function testIfJobTitleOrDescriptionSuit (jobInfo, matchLogic) { try { if (expectJobTypeRegExpStr.trim()) { const regExp = new RegExp(expectJobTypeRegExpStr, 'i') - isJobTypeSuit = regExp.test(jobInfo.positionName) + isJobTypeSuit = regExp.test(jobInfo.positionName?.replace(/\n/g, '') ?? '') } } catch { } @@ -364,7 +386,7 @@ export function testIfJobTitleOrDescriptionSuit (jobInfo, matchLogic) { try { if (expectJobDescRegExpStr.trim()) { const regExp = new RegExp(expectJobDescRegExpStr, 'i') - isJobDescSuit = regExp.test(jobInfo.postDescription) + isJobDescSuit = regExp.test(jobInfo.postDescription?.replace(/\n/g, '') ?? '') } } catch { } @@ -651,11 +673,13 @@ async function toRecommendPage (hooks) { } } + const filterConditions = + combineRecommendJobFilterType === CombineRecommendJobFilterType.STATIC_COMBINE + ? formatStaticCombineFilters(staticCombineRecommendJobFilterConditions) + : combineFiltersWithConstraintsGenerator(anyCombineRecommendJobFilter) let expectJobList iterateFilterCondition: for ( - const filterCondition of combineFiltersWithConstraintsGenerator( - anyCombineRecommendJobFilter - ) + const filterCondition of filterConditions ) { findInCurrentFilterCondition: while(true) { await sleepWithRandomDelay(2500) @@ -680,11 +704,17 @@ async function toRecommendPage (hooks) { break } } - if ( - isSkipEmptyConditionForCombineRecommendJobFilter && - Object.keys(filterCondition).length && - Object.keys(filterCondition).every(k => !filterCondition[k]?.length) + ( + combineRecommendJobFilterType === CombineRecommendJobFilterType.STATIC_COMBINE && filterCondition === null + ) + || + ( + combineRecommendJobFilterType === CombineRecommendJobFilterType.ANY_COMBINE && + isSkipEmptyConditionForCombineRecommendJobFilter && + Object.keys(filterCondition).length && + Object.keys(filterCondition).every(k => !filterCondition[k]?.length) + ) ) { sleep(4000) continue iterateFilterCondition @@ -807,7 +837,7 @@ async function toRecommendPage (hooks) { if (expectSalaryHigh && salaryData.high > expectSalaryHigh) { return false } - if (expectSalaryLow && salaryData.low < expectSalaryLow) { + if (expectSalaryLow && salaryData.high < expectSalaryLow) { return false } } else if (expectSalaryCalculateWay === SalaryCalculateWay.ANNUAL_PACKAGE) { @@ -815,7 +845,7 @@ async function toRecommendPage (hooks) { if (expectSalaryHigh && (salaryData.high * salaryDataMonth) / 10 > expectSalaryHigh) { return false } - if (expectSalaryLow && (salaryData.low * salaryDataMonth) / 10 < expectSalaryLow) { + if (expectSalaryLow && (salaryData.high * salaryDataMonth) / 10 < expectSalaryLow) { return false } } @@ -985,7 +1015,8 @@ async function toRecommendPage (hooks) { jobSource: JobSource[computedSourceList[currentSourceIndex]?.type] } ) - } catch { + } catch(err) { + console.log(`mark boss inactive failed`, err) } } }, @@ -1021,7 +1052,8 @@ async function toRecommendPage (hooks) { jobSource: JobSource[computedSourceList[currentSourceIndex]?.type] } ) - } catch { + } catch(err) { + console.log(`mark job city not suit failed`, err) } } }, @@ -1057,7 +1089,8 @@ async function toRecommendPage (hooks) { jobSource: JobSource[computedSourceList[currentSourceIndex]?.type] } ) - } catch { + } catch(err) { + console.log(`mark job work exp not suit failed`, err) } } }, @@ -1094,7 +1127,8 @@ async function toRecommendPage (hooks) { jobSource: JobSource[computedSourceList[currentSourceIndex]?.type] } ) - } catch { + } catch(err) { + console.log(`mark job detail not suit failed`, err) } } }, @@ -1133,7 +1167,8 @@ async function toRecommendPage (hooks) { jobSource: JobSource[computedSourceList[currentSourceIndex]?.type] } ) - } catch { + } catch(err) { + console.log(`mark job salary not suit failed`, err) } } } @@ -1188,6 +1223,12 @@ async function toRecommendPage (hooks) { await notSuitConditionHandleMap[markOnLocalDbCondition]() continue continueFind } + // 3. + const noOpCondition = Object.keys(notSuitReasonIdToStrategyMap).find(k => notSuitReasonIdToStrategyMap[k] === MarkAsNotSuitOp.NO_OP) + if (noOpCondition) { + await notSuitConditionHandleMap[noOpCondition]() + continue continueFind + } // #endregion if ( // test company again - when allow list not include target company, just skip @@ -1250,16 +1291,7 @@ async function toRecommendPage (hooks) { ); const res = await addFriendResponse.json() - if (res.code !== 0) { - // startup chat error, may the chance of today has used out - if (res.zpData.bizCode === 1 && res.zpData.bizData?.chatRemindDialog?.blockLevel === 0 && res.zpData.bizData?.chatRemindDialog?.content === `今日沟通人数已达上限,请明天再试`) { - await storeStorage(page).catch(() => void 0) - throw new Error('STARTUP_CHAT_ERROR_DUE_TO_TODAY_CHANCE_HAS_USED_OUT') - } else { - console.error(res) - throw new Error('STARTUP_CHAT_ERROR_WITH_UNKNOWN_ERROR') - } - } else { + if (res.code === 0) { await hooks.newChatStartup?.promise( targetJobData, { @@ -1275,6 +1307,28 @@ async function toRecommendPage (hooks) { await closeDialogButtonProxy.click() await sleepWithRandomDelay(2000) } + // TODO: + // else if (res.zpData.bizCode === 1 && res.zpData.bizData?.chatRemindDialog?.blockLevel === 0 && /还剩\d+次沟通机会/.test(res.zpData.bizData?.chatRemindDialog?.content)) { + // debugger + // } + else if ( + res.zpData.bizCode === 1 && + res.zpData.bizData?.chatRemindDialog?.blockLevel === 0 && + ( + res.zpData.bizData?.chatRemindDialog?.content === `今日沟通人数已达上限,请明天再试` || + /明天再来/.test(res.zpData.bizData?.chatRemindDialog?.content) + ) + ) { + // startup chat error, may the chance of today has used out + await storeStorage(page).catch(() => void 0) + throw new Error('STARTUP_CHAT_ERROR_DUE_TO_TODAY_CHANCE_HAS_USED_OUT') + } + else { + console.error( + JSON.stringify(res, null, 2) + ) + throw new Error('STARTUP_CHAT_ERROR_WITH_UNKNOWN_ERROR') + } // #endregion } catch (err) { if (err instanceof Error) { diff --git a/packages/sqlite-plugin/src/enums.ts b/packages/sqlite-plugin/src/enums.ts index ca74232..d70ab1e 100644 --- a/packages/sqlite-plugin/src/enums.ts +++ b/packages/sqlite-plugin/src/enums.ts @@ -34,3 +34,8 @@ export enum JobSource { recommend = 2, search = 3, } + +export enum CombineRecommendJobFilterType { + ANY_COMBINE = 1, + STATIC_COMBINE = 2, +} \ No newline at end of file diff --git a/packages/ui/electron.vite.config.ts b/packages/ui/electron.vite.config.ts index 4ae6177..5939052 100644 --- a/packages/ui/electron.vite.config.ts +++ b/packages/ui/electron.vite.config.ts @@ -3,7 +3,7 @@ import { defineConfig, externalizeDepsPlugin, loadEnv } from 'electron-vite' import vue from '@vitejs/plugin-vue' import UnoCSS from 'unocss/vite' import { presetUno, presetAttributify, presetIcons } from 'unocss' -import transformerDirective from "@unocss/transformer-directives"; +import transformerDirective from '@unocss/transformer-directives' import Replace from 'unplugin-replace/vite' process.env = { ...process.env, ...loadEnv(process.env.NODE_ENV!, process.cwd()) } @@ -13,11 +13,17 @@ export default defineConfig({ rollupOptions: { external: [] }, - minify: 'terser' + minify: process.env.NODE_ENV === 'development' ? undefined : 'terser' }, plugins: [ externalizeDepsPlugin({ - exclude: ['@geekgeekrun/geek-auto-start-chat-with-boss', '@geekgeekrun/dingtalk-plugin', '@geekgeekrun/utils', 'find-chrome-bin', '@geekgeekrun/launch-bosszhipin-login-page-with-preload-extension'] + exclude: [ + '@geekgeekrun/geek-auto-start-chat-with-boss', + '@geekgeekrun/dingtalk-plugin', + '@geekgeekrun/utils', + 'find-chrome-bin', + '@geekgeekrun/launch-bosszhipin-login-page-with-preload-extension' + ] }), Replace({ delimiters: ['', ''], @@ -26,11 +32,11 @@ export default defineConfig({ values: [ { find: //g, - replacement: process.env.VITE_APP_GTAG_MEASUREMENT_ID as string, + replacement: process.env.VITE_APP_GTAG_MEASUREMENT_ID as string }, { find: //g, - replacement: process.env.VITE_APP_GTAG_API_SECRET as string, + replacement: process.env.VITE_APP_GTAG_API_SECRET as string } ] }) @@ -39,7 +45,7 @@ export default defineConfig({ preload: { plugins: [externalizeDepsPlugin()], build: { - minify: 'terser' + minify: process.env.NODE_ENV === 'development' ? undefined : 'terser' } }, renderer: { @@ -52,11 +58,11 @@ export default defineConfig({ vue(), UnoCSS({ presets: [presetUno(), presetAttributify(), presetIcons()], - transformers: [transformerDirective()], + transformers: [transformerDirective()] }) ], build: { - minify: 'terser' + minify: process.env.NODE_ENV === 'development' ? undefined : 'terser' } } }) diff --git a/packages/ui/package.json b/packages/ui/package.json index 0f71b88..9a2b989 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -1,6 +1,6 @@ { "name": "geekgeekrun-ui", - "version": "0.9.2", + "version": "0.9.4", "description": "Boss 炸弹 - 自动开聊Boss,助力每位打工人求职!", "main": "./out/main/index.js", "author": "geekgeekrun", diff --git a/packages/ui/src/common/build-info.json b/packages/ui/src/common/build-info.json index 0a39c6a..aaffe6b 100644 --- a/packages/ui/src/common/build-info.json +++ b/packages/ui/src/common/build-info.json @@ -1,7 +1,7 @@ { - "version": "0.9.2", - "buildVersion": 18, - "buildTime": 1755400602067, - "buildHash": "a25b047f99f7b1ac0c8ee55f1e121991e1dd6402", + "version": "0.9.4", + "buildVersion": 20, + "buildTime": 1760377927509, + "buildHash": "51ca5dd71d62de2965fb53cff9d03c0d3552eabb", "name": "geekgeekrun-ui" } \ No newline at end of file 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 c055eb1..a3f78b3 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 @@ -159,6 +159,13 @@ export default function initIpc() { if (hasOwn(payload, 'jobSourceList')) { bossConfig.jobSourceList = payload.jobSourceList } + if (hasOwn(payload, 'combineRecommendJobFilterType')) { + bossConfig.combineRecommendJobFilterType = payload.combineRecommendJobFilterType + } + if (hasOwn(payload, 'staticCombineRecommendJobFilterConditions')) { + bossConfig.staticCombineRecommendJobFilterConditions = + payload.staticCombineRecommendJobFilterConditions + } promiseArr.push(writeConfigFile('boss.json', bossConfig)) diff --git a/packages/ui/src/renderer/src/features/StaticCombineBossRecommendFilter/index.vue b/packages/ui/src/renderer/src/features/StaticCombineBossRecommendFilter/index.vue new file mode 100644 index 0000000..1533584 --- /dev/null +++ b/packages/ui/src/renderer/src/features/StaticCombineBossRecommendFilter/index.vue @@ -0,0 +1,264 @@ + + + + + diff --git a/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/expectJobFilterTemplateList.ts b/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/expectJobFilterTemplateList.ts new file mode 100644 index 0000000..51c5925 --- /dev/null +++ b/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/expectJobFilterTemplateList.ts @@ -0,0 +1,233 @@ +import { JobDetailRegExpMatchLogic } from '@geekgeekrun/sqlite-plugin/src/enums' + +const expectJobFilterTemplateList = [ + { + type: '不限职位', + name: '不限职位(随便投)', + config: { + expectJobNameRegExpStr: '', + expectJobTypeRegExpStr: '', + expectJobDescRegExpStr: '', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.SOME + } + }, + { + type: '互联网/AI', + name: 'Java', + config: { + expectJobNameRegExpStr: '', + expectJobTypeRegExpStr: '\\bJava\\b', + expectJobDescRegExpStr: + '\\bJava\\b|JVM|消息队列|MQ|SQL|Oracle|MongoDB|Redis|Nginx|Dubbo|Docker|K8s|Kubernetes', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.SOME + } + }, + { + type: '互联网/AI', + name: 'Golang', + config: { + expectJobNameRegExpStr: '', + expectJobTypeRegExpStr: '\\bGolang\\b', + expectJobDescRegExpStr: + '\\bGo\\b|\\bGolang\\b|消息队列|MQ|SQL|Oracle|MongoDB|Redis|Nginx|Dubbo|Docker|K8s|Kubernetes', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.SOME + } + }, + { + type: '互联网/AI', + name: '前端开发工程师', + config: { + expectJobNameRegExpStr: '前端|H5|\\bFE\\b', + expectJobTypeRegExpStr: '前端开发|javascript', + expectJobDescRegExpStr: '前端|vue|react|node|\\bjs\\b|javascript|H5', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.SOME + } + }, + { + type: '互联网/AI', + name: '前端开发工程师(不考虑外包、兼职)', + config: { + expectJobNameRegExpStr: '^(?=.*(前端|H5|\\bFE\\b))(?!.*(?:外包|驻场|外派|兼职|短期))', + expectJobTypeRegExpStr: '前端开发|javascript', + expectJobDescRegExpStr: + '^(?=.*(前端|vue|react|node|\\bjs\\b|javascript|H5))(?!.*(?:外包|驻场|外派|兼职|短期))', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY + } + }, + { + type: '互联网/AI', + name: '测试工程师、测试开发', + config: { + expectJobNameRegExpStr: '测试|测开|QA|质量', + expectJobTypeRegExpStr: '测试工程师|测试开发', + expectJobDescRegExpStr: + '测试|测开|QA|线上问题|自动化|复盘|效率|Selenium|Puppeteer|Playwright|Cypress|JMeter|LoadRunner|QTP|TestNG|JUnit|Pytest|Fiddler|Charles|Jenkins|Appium|黑盒|白盒|用例|缺陷|Linux|Ubuntu|Debian|CentOS|Shell|c\\+\\+|Python|PHP|\\bJava\\b|Node|\\bGo\\b|\\bGolang\\b', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.SOME + } + }, + { + type: '互联网/AI', + name: '运维工程师、运维开发工程师', + config: { + expectJobNameRegExpStr: '运维(开发)?|SRE', + expectJobTypeRegExpStr: '运维(开发)?工程师', + expectJobDescRegExpStr: + '运维|SRE|服务器|云计算|Docker|K8s|Kubernetes|Linux|Ubuntu|Debian|CentOS|Shell|Python|\\bGo\\b|\\bGolang\\b|监控|Prometheus|Grafana|ELK|负载均衡|部署|Nginx|Apache|DevOps|harbor', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.SOME + } + }, + { + type: '互联网/AI', + name: '数据开发', + config: { + expectJobNameRegExpStr: '', + expectJobTypeRegExpStr: '数据开发', + expectJobDescRegExpStr: 'c\\+\\+|Python|\\bGo\\b|\\bGolang\\b|\\bJava\\b|Node|数据仓库|ETL|大数据|Hadoop|Spark|Flink|Hive|Presto|数据湖|数仓|SQL|Oracle|MongoDB|Redis|Kafka', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.SOME + } + }, + { + type: '互联网/AI', + name: '实施工程师', + config: { + expectJobNameRegExpStr: '', + expectJobTypeRegExpStr: '实施', + expectJobDescRegExpStr: '', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY + } + }, + { + type: '产品', + name: '产品经理', + config: { + expectJobNameRegExpStr: '', + expectJobTypeRegExpStr: '产品经理', + expectJobDescRegExpStr: '', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY + } + }, + { + type: '产品', + name: '用户研究', + config: { + expectJobNameRegExpStr: '', + expectJobTypeRegExpStr: '用户研究', + expectJobDescRegExpStr: '', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY + } + }, + { + type: '产品', + name: '游戏策划', + config: { + expectJobNameRegExpStr: '', + expectJobTypeRegExpStr: '游戏策划', + expectJobDescRegExpStr: '', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY + } + }, + { + type: '客服/运营', + name: '产品运营', + config: { + expectJobNameRegExpStr: '', + expectJobTypeRegExpStr: '产品运营', + expectJobDescRegExpStr: '', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY + } + }, + { + type: '客服/运营', + name: '用户运营', + config: { + expectJobNameRegExpStr: '', + expectJobTypeRegExpStr: '用户运营', + expectJobDescRegExpStr: '', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY + } + }, + { + type: '客服/运营', + name: '数据标注/AI训练师', + config: { + expectJobNameRegExpStr: '', + expectJobTypeRegExpStr: '数据标注|AI训练师', + expectJobDescRegExpStr: '', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY + } + }, + { + type: '财务/审计/税务', + name: '会计、出纳', + config: { + expectJobNameRegExpStr: '会计|Accountant|出纳|财务', + expectJobTypeRegExpStr: '会计|出纳', + expectJobDescRegExpStr: + '会计|财务|出纳|审计|账务|税务|总账|做账|应付|应收|成本|资产|资金|记账|发票|结算|核算|汇算|利润|对账|报税|回款|SAP|用友|金蝶', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.SOME + } + }, + { + type: '人力/行政/法务', + name: '人力资源专员/助理、人力资源经理/主管', + config: { + expectJobNameRegExpStr: 'HR|人力|人资|人事', + expectJobTypeRegExpStr: '人力', + expectJobDescRegExpStr: '', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.SOME + } + }, + { + type: '人力/行政/法务', + name: 'HRBP', + config: { + expectJobNameRegExpStr: 'BP|HRG|HR|人力|人资|人事', + expectJobTypeRegExpStr: 'HRBP|人力', + expectJobDescRegExpStr: '', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.SOME + } + }, + { + type: '人力/行政/法务', + name: '员工关系', + config: { + expectJobNameRegExpStr: '员工关系|劳动关系|SSC|社保|HR|人力|人资|人事', + expectJobTypeRegExpStr: '员工关系|人力', + expectJobDescRegExpStr: '员工关系|劳动关系|SSC|社保|考勤|入职|离职|入转调离', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY + } + }, + { + type: '人力/行政/法务', + name: '招聘', + config: { + expectJobNameRegExpStr: '招聘|高招|Recruiter|HR|人力|人资|人事', + expectJobTypeRegExpStr: '招聘|猎头|人力', + expectJobDescRegExpStr: + '招聘|高招|Recruiter|简历|面试|人才引进|Mapping|人才画像|offer|猎头|内推|外推|猎聘|Boss|拉勾|前程无忧|智联|58同城|领英|LinkedIn|ATS|人才库|Moka|北森|iTenant|倍罗|大易', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY + } + }, + { + type: '人力/行政/法务', + name: '薪酬绩效', + config: { + expectJobNameRegExpStr: '薪酬|绩效|福利|COE|payroll', + expectJobTypeRegExpStr: '薪酬绩效', + expectJobDescRegExpStr: '', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.SOME + } + }, + { + type: '人力/行政/法务', + name: '企业文化', + config: { + expectJobNameRegExpStr: '企业文化|组织文化|组织|OC|廉洁|反腐', + expectJobTypeRegExpStr: '企业文化', + expectJobDescRegExpStr: '', + jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.SOME + } + }, +] + +export default expectJobFilterTemplateList 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 7a80ce2..1298296 100644 --- a/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/index.vue +++ b/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/index.vue @@ -22,7 +22,7 @@
- 职位来源及其查找顺序 + 你想投递Boss直聘上哪些列表里的职位?
- 拖放条目前方的手柄以调整职位来源查找顺序;点击条目前方的开关以启用/禁用对应的职位来源 + 拖放条目前方的手柄以调整职位列表查找顺序;点击条目前方的开关以启用/禁用对应的职位列表
- - - -
- 职位筛选条件 - - - 这个配置是如何工作的? +
+
+ 你希望Boss直聘为你筛选出什么样的职位? + + + 这个配置是如何工作的? + +
+
+
+
筛选条件遍历方式
+ + {{ op.name }} + +
+
+ +
+
+ +
+ + 跳过初始空条件,直接使用设置的条件查找职位 + + + 跳过初始空条件,直接使用设置的条件查找职位 + +
+
+
+
+ 当前组合条件数:{{ + currentAnyCombineRecommendJobFilterCombinationCount.toLocaleString() + }} + 不建议选择太多组合条件 - + 否则将在当前职位中尝试太多筛选条件,不能及时进入下一个职位,且会增加命中风控的概率 - +
- - - - - 跳过初始空条件,直接使用设置的条件查找职位 - - - 跳过初始空条件,直接使用设置的条件查找职位 - -
- 当前组合条件数:{{ - currentAnyCombineRecommendJobFilterCombinationCount.toLocaleString() - }} - 不建议选择太多组合条件 - - 否则将在当前职位中尝试太多筛选条件,不能及时进入下一个职位,且会增加命中风控的概率 -