diff --git a/README.md b/README.md
index 07520a2..2291d54 100644
--- a/README.md
+++ b/README.md
@@ -156,8 +156,8 @@ Boss不明原因已读不回?简历就是投不出去?
一个岗位可以收到一堆简历投递,大部分简历最终的归宿都是人才库或者垃圾场
当然,如果运气好:
-- 好不容易过了 HR 面,到了 Offer 阶段,HR / 用人部门 几乎都在极限压缩用人成本,经常能被恶心到,但你又没有其它更好 Offer ,不敢贸然放弃这个烂 Offer
-- 终于你自我催眠(类似:“领导看我薪资低,所以一定会争取给我涨薪”、“领导看我薪资低,所以假设我加倍努力工作绩效一定会向我倾斜”、“领导画的饼很好,吃了一定能有好结果”),接了烂 Offer 入了职,然而经过一段时间的接触,最终结果完全不符合期望(诸如:“团队很难融入”、“协作方经常踢皮球”、“你需要做很多脏活累活,而且要帮前人擦屁股”、“领导希望用最小成本把你招来,这样裁员时可以最小成本把你打发走”、“团队需要新人来背C/M-/3.25/裁员指标”、“领导分配的工作和领导入职时画的诱人的饼完全不一致”)
+- 好不容易过了 HR 面,到了 Offer 阶段,HR / 用人部门 几乎都在极限压缩用人成本,经常能被恶心到,但你又没有其它更好 Offer ,不敢贸然放弃这个不满意的 Offer
+- 终于你自我催眠(类似:“领导看我薪资低,所以一定会争取给我涨薪”、“领导看我薪资低,所以假设我加倍努力工作绩效一定会向我倾斜”、“领导画的饼很好,吃了一定能有好结果”),接了不满意的 Offer 入了职,然而经过一段时间的接触,最终结果完全不符合期望(诸如:“团队很难融入”、“协作方经常踢皮球”、“你需要做很多脏活累活,而且要帮前人擦屁股”、“领导希望用最小成本把你招来,这样裁员时可以最小成本把你打发走”、“团队需要新人来背C/M-/3.25/裁员指标”、“领导分配的工作和领导入职时画的诱人的饼完全不一致”)
为了避免这种情况的发生,找工作时还是需要尽可能多的面试,多个选择。如果真的不慎遭遇了这些情况,让你认为在当前岗位继续做下去的收益不如离职换工作的收益,那就做好走的准备吧
@@ -170,7 +170,19 @@ Boss不明原因已读不回?简历就是投不出去?
人工筛选这些职位会有很大的心智负担,真的会吐……
-因此,我在Boss炸弹代码中,加入了清理机制,将通过标记不合适的方式,尝试让这些不活跃职位、不合适职位消失;保证只开聊符合你口味的职位
+因此,我在Boss炸弹代码中,加入了清理机制,将通过标记不合适的方式,尝试让这些不活跃职位、不合适职位消失;保证只开聊符合你口味的职位。
+
+## 使用必读及免责声明
+如下是使用必读及免责声明,请您务必逐条阅读;本程序首次启动时,您还会再看到一次;若您不接受如下提到的任何内容,请不要使用本程序。
+- 本程序从某种程度上说属于辅助工具,与《Boss直聘用户协议》(2023年3月版)相关条款相违背,您在注册Boss直聘时已签署过这一条款;根据该条款`七、用户的平台使用义务`、`八、违约责任` 章节,如果一些非正常用户行为被风控监测到,您需要承受包括不仅限于**账号被强制退出登录**、**账号被限制使用**、**账号被封禁**等对您不利的风险;因此使用本程序即意味着**您愿意接受以上风险**,且如果相关风险发生,您需要自行承担相关后果,**本程序概不负责** 。
+- 本程序会通过尽可能模仿用户行为来规避相关风险,但并不能保证可以完全规避。建议您使用本程序时**注意节制**,建议当天开聊次数用尽后,隔几天再使用。建议您**注册一个本程序专用的新的Boss直聘账号**进行求职。
+- 本程序原理是模拟用户在Boss直聘网页上进行点击操作;Boss直聘网站每过一段时间会发生改版,且有可能包含A/B实验,这将导致本程序相关脚本失效。如果您在使用过程中遇上程序未按照预期执行的情况,请[点击这里](https://github.com/geekgeekrun/geekgeekrun/issues/new)进行反馈。
+- 您的雇主可能会对您的计算机终端或网络进行监控,从而审计、跟踪您的行为;建议您**不要在您雇主提供的计算机终端或网络上使用本程序**。
+- 本程序需要存储您的登录凭据,即Cookie,来模拟您在Boss直聘上开聊Boss的行为;本程序仅会把您的Cookie存储在本地,并在您访问Boss直聘时将其传输到Boss直聘,**不会泄露给第三方**,也不会进行除自动开聊Boss以外的行为;**请勿向他人泄漏您的Cookie**。
+- 本程序**不会上报能够识别出您身份的信息**,**不会向您的雇主报告您的求职行为**。
+- 本程序**不对您的求职过程与结果负责**,为您开聊的职位均在Boss直聘上发布;请**自行甄别为您开聊的公司、认真决定是否参加面试、慎重选择Offer**。
+- 请在Boss直聘上自行**屏蔽您不期望投递的公司**。
+- 本程序经历过了多次测试,理论上来说大部分情况下可以正常运行;如果您有顾虑,建议通过VMWare WorkStation/Fusion、VirtualBox、Hyper-V/Windows沙盒等虚拟化技术运行本程序。如发生问题,请[点击这里](https://github.com/geekgeekrun/geekgeekrun/issues/new)进行反馈。
--------
@@ -180,10 +192,12 @@ Boss不明原因已读不回?简历就是投不出去?
祝你求职成功,事业顺利,事事顺心
-## Star 数据 感谢支持
+## Star
+
+ 感谢支持
diff --git a/packages/geek-auto-start-chat-with-boss/index.mjs b/packages/geek-auto-start-chat-with-boss/index.mjs
index 6866e80..f433826 100644
--- a/packages/geek-auto-start-chat-with-boss/index.mjs
+++ b/packages/geek-auto-start-chat-with-boss/index.mjs
@@ -16,9 +16,9 @@ import { calculateTotalCombinations, combineFiltersWithConstraintsGenerator } fr
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 } from '@geekgeekrun/sqlite-plugin/dist/enums'
+import { MarkAsNotSuitReason, MarkAsNotSuitOp, StrategyScopeOptionWhenMarkJobNotMatch, SalaryCalculateWay } from '@geekgeekrun/sqlite-plugin/dist/enums'
import { activeDescList } from './constant.mjs'
-
+import { parseSalary } from "@geekgeekrun/sqlite-plugin/dist/utils/parser"
const jobFilterConditionsMapByCode = {}
Object.values(jobFilterConditions).forEach(arr => {
arr.forEach(option => {
@@ -86,6 +86,19 @@ const expectCityList = readConfigFile('boss.json').expectCityList ?? []
const strategyScopeOptionWhenMarkJobCityNotMatch = readConfigFile('boss.json').strategyScopeOptionWhenMarkJobCityNotMatch ?? StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB
+// salary
+const expectSalaryLow = parseFloat(readConfigFile('boss.json').expectSalaryLow) || null
+const expectSalaryHigh = parseFloat(readConfigFile('boss.json').expectSalaryHigh) || null
+const expectSalaryCalculateWay = readConfigFile('boss.json').expectSalaryCalculateWay ?? SalaryCalculateWay.MONTH_SALARY
+const expectSalaryNotMatchStrategy = readConfigFile('boss.json').expectSalaryNotMatchStrategy ?? MarkAsNotSuitOp.NO_OP
+const isSalaryFilterEnabled = expectSalaryLow || expectSalaryHigh
+const strategyScopeOptionWhenMarkSalaryNotMatch = readConfigFile('boss.json').strategyScopeOptionWhenMarkSalaryNotMatch ?? StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB
+
+// work exp
+const expectWorkExpList = readConfigFile('boss.json').expectWorkExpList ?? []
+const expectWorkExpNotMatchStrategy = readConfigFile('boss.json').expectWorkExpNotMatchStrategy ?? MarkAsNotSuitOp.NO_OP
+const strategyScopeOptionWhenMarkJobWorkExpNotMatch = readConfigFile('boss.json').strategyScopeOptionWhenMarkJobWorkExpNotMatch ?? StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB
+
const markAsNotActiveSelectedTimeRange = (() => {
let n = readConfigFile('boss.json').markAsNotActiveSelectedTimeRange
if (
@@ -189,19 +202,16 @@ async function markJobAsNotSuitInRecommendPage (reasonCode) {
}
break
}
- case MarkAsNotSuitReason.JOB_CITY_NOT_SUIT: {
- const bossNotActiveOptionProxy = await chooseReasonDialogProxy.$(`.zp-type-item[title$="城市"]`)
- if (bossNotActiveOptionProxy) {
- await bossNotActiveOptionProxy.click()
+ case MarkAsNotSuitReason.JOB_WORK_EXP_NOT_SUIT:
+ case MarkAsNotSuitReason.JOB_CITY_NOT_SUIT:
+ 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="面试过/入职过"]`))
+ if (opProxy) {
+ await opProxy.click()
isOptionChosen = true
- } else {
- const fallbackOptionProxy = (await chooseReasonDialogProxy.$(`.zp-type-item[title="同城距离远"]`))
- ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title="公司不感兴趣"]`))
- ?? (await chooseReasonDialogProxy.$(`.zp-type-item[title="面试过/入职过"]`))
- if (fallbackOptionProxy) {
- await fallbackOptionProxy.click()
- isOptionChosen = true
- }
}
break
}
@@ -539,10 +549,29 @@ async function toRecommendPage (hooks) {
// due to city can get from list immediately
// so just set those job which city is not suit to blockJobNotSuit
// to skip view detail
+
+ // skip invalid salaryData (兼职、日结、实习 etc)
+ jobListData.forEach(it => {
+ const salaryData = parseSalary(it.salaryDesc)
+ if (!salaryData.high || !salaryData.low) {
+ blockJobNotSuit.add(it.encryptJobId)
+ }
+ })
if (
- expectCityNotMatchStrategy === MarkAsNotSuitOp.NO_OP &&
- Array.isArray(expectCityList) &&
- expectCityList.length
+ (
+ expectCityNotMatchStrategy === MarkAsNotSuitOp.NO_OP &&
+ Array.isArray(expectCityList) &&
+ expectCityList.length
+ ) ||
+ (
+ expectWorkExpNotMatchStrategy === MarkAsNotSuitOp.NO_OP &&
+ Array.isArray(expectWorkExpList) &&
+ expectWorkExpList.length
+ ) ||
+ (
+ strategyScopeOptionWhenMarkSalaryNotMatch === MarkAsNotSuitOp.NO_OP &&
+ isSalaryFilterEnabled
+ )
) {
console.log(`add job city not suit into blockJobNotSuit set`)
for (const it of jobListData) {
@@ -557,6 +586,26 @@ async function toRecommendPage (hooks) {
let hasReachLastPage = false
let targetJobIndex = -1
let targetJobData, selectedJobData // they show be same; one is from list, another is from detail
+ function checkIfSalarySuit(salaryDesc) {
+ const salaryData = parseSalary(salaryDesc)
+ if (expectSalaryCalculateWay === SalaryCalculateWay.MONTH_SALARY) {
+ if (expectSalaryHigh && salaryData.high > expectSalaryHigh) {
+ return false
+ }
+ if (expectSalaryLow && salaryData.low < expectSalaryLow) {
+ return false
+ }
+ } else if (expectSalaryCalculateWay === SalaryCalculateWay.ANNUAL_PACKAGE) {
+ const salaryDataMonth = salaryData.month || 12
+ if (expectSalaryHigh && (salaryData.high * salaryDataMonth) / 10 > expectSalaryHigh) {
+ return false
+ }
+ if (expectSalaryLow && (salaryData.low * salaryDataMonth) / 10 < expectSalaryLow) {
+ return false
+ }
+ }
+ return true
+ }
function getTempTargetJobIndexToCheckDetail () {
return jobListData.findIndex(it => {
return !blockBossNotNewChat.has(it.encryptBossId) &&
@@ -571,7 +620,7 @@ async function toRecommendPage (hooks) {
:
true
) || (
- // enter job detail to mark as not suit
+ // enter job detail to mark as not suit for city filter
(
Array.isArray(expectCityList) &&
expectCityList.length &&
@@ -581,6 +630,27 @@ async function toRecommendPage (hooks) {
].includes(expectCityNotMatchStrategy) &&
strategyScopeOptionWhenMarkJobCityNotMatch === StrategyScopeOptionWhenMarkJobNotMatch.ALL_JOB
) ? !expectCityList.includes(it.cityName) : false
+ ) || (
+ // enter job detail to mark as not suit for work exp filter
+ (
+ Array.isArray(expectWorkExpList) &&
+ expectWorkExpList.length &&
+ [
+ MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS,
+ MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL
+ ].includes(expectWorkExpNotMatchStrategy) &&
+ strategyScopeOptionWhenMarkJobWorkExpNotMatch === StrategyScopeOptionWhenMarkJobNotMatch.ALL_JOB
+ ) ? !expectWorkExpList.includes(it.jobExperience) : false
+ ) || (
+ // enter job detail to mark as not suit for salary filter
+ (
+ isSalaryFilterEnabled &&
+ [
+ MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS,
+ MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL
+ ].includes(expectSalaryNotMatchStrategy) &&
+ strategyScopeOptionWhenMarkSalaryNotMatch === StrategyScopeOptionWhenMarkJobNotMatch.ALL_JOB
+ ) ? !checkIfSalarySuit(it.salaryDesc) : false
)
)
})
@@ -664,6 +734,186 @@ async function toRecommendPage (hooks) {
// save the job detail info
await hooks.jobDetailIsGetFromRecommendList?.promise(targetJobData)
+ //#region collect not suit reasons
+ const notSuitReasonIdToStrategyMap = {}
+ const notSuitConditionHandleMap = {
+ async active() {
+ blockBossNotActive.add(targetJobData.jobInfo.encryptUserId)
+ if (jobNotActiveStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS) {
+ try {
+ const { chosenReasonInUi } = await markJobAsNotSuitInRecommendPage(MarkAsNotSuitReason.BOSS_INACTIVE)
+ await hooks.jobMarkedAsNotSuit.promise(
+ targetJobData,
+ {
+ markFrom: ChatStartupFrom.AutoFromRecommendList,
+ markReason: MarkAsNotSuitReason.BOSS_INACTIVE,
+ extInfo: {
+ bossActiveTimeDesc: targetJobData.bossInfo.activeTimeDesc,
+ chosenReasonInUi
+ },
+ markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
+ }
+ )
+ } catch {
+ }
+ }
+ else if (jobNotActiveStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL) {
+ try {
+ await hooks.jobMarkedAsNotSuit.promise(
+ targetJobData,
+ {
+ markFrom: ChatStartupFrom.AutoFromRecommendList,
+ markReason: MarkAsNotSuitReason.BOSS_INACTIVE,
+ extInfo: null,
+ markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL
+ }
+ )
+ } catch {
+ }
+ }
+ },
+ async city() {
+ blockJobNotSuit.add(targetJobData.jobInfo.encryptId)
+ if (expectCityNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS) {
+ try {
+ const { chosenReasonInUi } = await markJobAsNotSuitInRecommendPage(MarkAsNotSuitReason.JOB_CITY_NOT_SUIT)
+ await hooks.jobMarkedAsNotSuit.promise(
+ targetJobData,
+ {
+ markFrom: ChatStartupFrom.AutoFromRecommendList,
+ markReason: MarkAsNotSuitReason.JOB_CITY_NOT_SUIT,
+ extInfo: {
+ chosenReasonInUi
+ },
+ markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
+ }
+ )
+ } catch {
+ }
+ }
+ else if (expectCityNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL) {
+ try {
+ await hooks.jobMarkedAsNotSuit.promise(
+ targetJobData,
+ {
+ markFrom: ChatStartupFrom.AutoFromRecommendList,
+ markReason: MarkAsNotSuitReason.JOB_CITY_NOT_SUIT,
+ extInfo: null,
+ markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL
+ }
+ )
+ } catch {
+ }
+ }
+ },
+ async workExp() {
+ blockJobNotSuit.add(targetJobData.jobInfo.encryptId)
+ if (expectWorkExpNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS) {
+ try {
+ const { chosenReasonInUi } = await markJobAsNotSuitInRecommendPage(MarkAsNotSuitReason.JOB_WORK_EXP_NOT_SUIT)
+ await hooks.jobMarkedAsNotSuit.promise(
+ targetJobData,
+ {
+ markFrom: ChatStartupFrom.AutoFromRecommendList,
+ markReason: MarkAsNotSuitReason.JOB_WORK_EXP_NOT_SUIT,
+ extInfo: {
+ chosenReasonInUi
+ },
+ markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
+ }
+ )
+ } catch {
+ }
+ }
+ else if (expectWorkExpNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL) {
+ try {
+ await hooks.jobMarkedAsNotSuit.promise(
+ targetJobData,
+ {
+ markFrom: ChatStartupFrom.AutoFromRecommendList,
+ markReason: MarkAsNotSuitReason.JOB_WORK_EXP_NOT_SUIT,
+ extInfo: null,
+ markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL
+ }
+ )
+ } catch {
+ }
+ }
+ },
+ async jobDetail() {
+ blockJobNotSuit.add(targetJobData.jobInfo.encryptId)
+ if (jobNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS) {
+ try {
+ const { chosenReasonInUi } = await markJobAsNotSuitInRecommendPage(MarkAsNotSuitReason.JOB_NOT_SUIT)
+ await hooks.jobMarkedAsNotSuit.promise(
+ targetJobData,
+ {
+ markFrom: ChatStartupFrom.AutoFromRecommendList,
+ markReason: MarkAsNotSuitReason.JOB_NOT_SUIT,
+ extInfo: {
+ bossActiveTimeDesc: targetJobData.bossInfo.activeTimeDesc,
+ chosenReasonInUi
+ },
+ markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
+ }
+ )
+ } catch {
+ }
+ }
+ else if (jobNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL) {
+ try {
+ await hooks.jobMarkedAsNotSuit.promise(
+ targetJobData,
+ {
+ markFrom: ChatStartupFrom.AutoFromRecommendList,
+ markReason: MarkAsNotSuitReason.JOB_NOT_SUIT,
+ extInfo: null,
+ markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL
+ }
+ )
+ } catch {
+ }
+ }
+ },
+ async salary() {
+ blockJobNotSuit.add(targetJobData.jobInfo.encryptId)
+ if (expectSalaryNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS) {
+ try {
+ const { chosenReasonInUi } = await markJobAsNotSuitInRecommendPage(MarkAsNotSuitReason.JOB_SALARY_NOT_SUIT)
+ await hooks.jobMarkedAsNotSuit.promise(
+ targetJobData,
+ {
+ markFrom: ChatStartupFrom.AutoFromRecommendList,
+ markReason: MarkAsNotSuitReason.JOB_SALARY_NOT_SUIT,
+ extInfo: {
+ salaryDesc: selectedJobData.salaryDesc,
+ chosenReasonInUi
+ },
+ markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
+ }
+ )
+ } catch {
+ }
+ }
+ else if (expectSalaryNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL) {
+ try {
+ await hooks.jobMarkedAsNotSuit.promise(
+ targetJobData,
+ {
+ markFrom: ChatStartupFrom.AutoFromRecommendList,
+ markReason: MarkAsNotSuitReason.JOB_SALARY_NOT_SUIT,
+ extInfo: {
+ salaryDesc: selectedJobData.salaryDesc,
+ },
+ markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL
+ }
+ )
+ } catch {
+ }
+ }
+ }
+ }
+
//#region
// null
// 刚刚活跃 // 今日活跃 // 昨日活跃 // 3日内活跃 // 本周活跃 // 2周内活跃
@@ -674,122 +924,56 @@ async function toRecommendPage (hooks) {
markAsNotActiveSelectedTimeRange > 0 &&
indexOfActiveText > 0 && indexOfActiveText <= markAsNotActiveSelectedTimeRange
) {
- blockBossNotActive.add(targetJobData.jobInfo.encryptUserId)
// click prevent recommend button
- if (jobNotActiveStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS) {
- try {
- const { chosenReasonInUi } = await markJobAsNotSuitInRecommendPage(MarkAsNotSuitReason.BOSS_INACTIVE)
- await hooks.jobMarkedAsNotSuit.promise(
- targetJobData,
- {
- markFrom: ChatStartupFrom.AutoFromRecommendList,
- markReason: MarkAsNotSuitReason.BOSS_INACTIVE,
- extInfo: {
- bossActiveTimeDesc: targetJobData.bossInfo.activeTimeDesc,
- chosenReasonInUi
- },
- markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
- }
- )
- } catch {
- }
- }
- else if (jobNotActiveStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL) {
- try {
- await hooks.jobMarkedAsNotSuit.promise(
- targetJobData,
- {
- markFrom: ChatStartupFrom.AutoFromRecommendList,
- markReason: MarkAsNotSuitReason.BOSS_INACTIVE,
- extInfo: null,
- markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL
- }
- )
- } catch {
- }
- }
- continue continueFind
+ notSuitReasonIdToStrategyMap.active = jobNotActiveStrategy
}
if (
(Array.isArray(expectCityList) && expectCityList.length) && !expectCityList.includes(selectedJobData.cityName)
) {
- blockJobNotSuit.add(targetJobData.jobInfo.encryptId)
- if (expectCityNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS) {
- try {
- const { chosenReasonInUi } = await markJobAsNotSuitInRecommendPage(MarkAsNotSuitReason.JOB_CITY_NOT_SUIT)
- await hooks.jobMarkedAsNotSuit.promise(
- targetJobData,
- {
- markFrom: ChatStartupFrom.AutoFromRecommendList,
- markReason: MarkAsNotSuitReason.JOB_CITY_NOT_SUIT,
- extInfo: {
- chosenReasonInUi
- },
- markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
- }
- )
- } catch {
- }
- }
- else if (expectCityNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL) {
- try {
- await hooks.jobMarkedAsNotSuit.promise(
- targetJobData,
- {
- markFrom: ChatStartupFrom.AutoFromRecommendList,
- markReason: MarkAsNotSuitReason.JOB_CITY_NOT_SUIT,
- extInfo: null,
- markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL
- }
- )
- } catch {
- }
- }
- continue continueFind
+ notSuitReasonIdToStrategyMap.city = expectCityNotMatchStrategy
+ }
+ if (
+ (Array.isArray(expectWorkExpList) && expectWorkExpList.length) && !expectWorkExpList.includes(selectedJobData.jobExperience)
+ ) {
+ notSuitReasonIdToStrategyMap.workExp = expectWorkExpNotMatchStrategy
}
if (
!testIfJobTitleOrDescriptionSuit(targetJobData.jobInfo)
) {
- blockJobNotSuit.add(targetJobData.jobInfo.encryptId)
- if (jobNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS) {
- try {
- const { chosenReasonInUi } = await markJobAsNotSuitInRecommendPage(MarkAsNotSuitReason.JOB_NOT_SUIT)
- await hooks.jobMarkedAsNotSuit.promise(
- targetJobData,
- {
- markFrom: ChatStartupFrom.AutoFromRecommendList,
- markReason: MarkAsNotSuitReason.JOB_NOT_SUIT,
- extInfo: {
- bossActiveTimeDesc: targetJobData.bossInfo.activeTimeDesc,
- chosenReasonInUi
- },
- markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
- }
- )
- } catch {
- }
- }
- else if (jobNotMatchStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL) {
- try {
- await hooks.jobMarkedAsNotSuit.promise(
- targetJobData,
- {
- markFrom: ChatStartupFrom.AutoFromRecommendList,
- markReason: MarkAsNotSuitReason.JOB_NOT_SUIT,
- extInfo: null,
- markOp: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL
- }
- )
- } catch {
- }
- }
+ notSuitReasonIdToStrategyMap.jobDetail = jobNotMatchStrategy
+ }
+ if (
+ !checkIfSalarySuit(selectedJobData.salaryDesc)
+ ) {
+ notSuitReasonIdToStrategyMap.salary = expectSalaryNotMatchStrategy
+ }
+ // #endregion
+ console.log('not suit reason and related strategy: ', notSuitReasonIdToStrategyMap)
+
+ // #region execute mark logic
+ // 1. find the one mark on Boss
+ const markOnBossCondition = Object.keys(notSuitReasonIdToStrategyMap).find(k => notSuitReasonIdToStrategyMap[k] === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS)
+ if (markOnBossCondition) {
+ await notSuitConditionHandleMap[markOnBossCondition]()
continue continueFind
}
- // test company again - when allow list not include target company, just skip
+ // 2. if there is no condition to mark Boss, then find the one mark on local db
+ const markOnLocalDbCondition = Object.keys(notSuitReasonIdToStrategyMap).find(k => notSuitReasonIdToStrategyMap[k] === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL)
+ if (markOnLocalDbCondition) {
+ await notSuitConditionHandleMap[markOnBossCondition]()
+ continue continueFind
+ }
+ // #endregion
if (
+ // test company again - when allow list not include target company, just skip
enableCompanyAllowList && ![...expectCompanySet].find(
name => selectedJobData.brandName?.toLowerCase?.()?.includes(name.toLowerCase())
- )
+ ) ||
+ // check if job has been marked as not suit or not active
+ [
+ ...blockJobNotSuit,
+ ...blockBossNotActive
+ ].includes(targetJobData.jobInfo.encryptId)
) {
// just skip
continue continueFind
diff --git a/packages/sqlite-plugin/src/enums.ts b/packages/sqlite-plugin/src/enums.ts
index b887896..ddab6c5 100644
--- a/packages/sqlite-plugin/src/enums.ts
+++ b/packages/sqlite-plugin/src/enums.ts
@@ -4,6 +4,8 @@ export enum MarkAsNotSuitReason {
USER_MANUAL_OPERATION_WITH_UNKNOWN_REASON = 2,
JOB_NOT_SUIT = 3,
JOB_CITY_NOT_SUIT = 4,
+ JOB_WORK_EXP_NOT_SUIT = 5,
+ JOB_SALARY_NOT_SUIT = 6,
}
export enum MarkAsNotSuitOp {
@@ -19,5 +21,5 @@ export enum StrategyScopeOptionWhenMarkJobNotMatch {
export enum SalaryCalculateWay {
MONTH_SALARY = 1,
- ANNUAL_PACKAGE = 2
+ ANNUAL_PACKAGE = 2,
}
\ No newline at end of file
diff --git a/packages/ui/package.json b/packages/ui/package.json
index 48306f9..b76d3f1 100644
--- a/packages/ui/package.json
+++ b/packages/ui/package.json
@@ -1,6 +1,6 @@
{
"name": "geekgeekrun-ui",
- "version": "0.7.1",
+ "version": "0.8.0",
"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 bed7016..73f43bc 100644
--- a/packages/ui/src/common/build-info.json
+++ b/packages/ui/src/common/build-info.json
@@ -1,7 +1,7 @@
{
- "version": "0.7.1",
- "buildVersion": 14,
- "buildTime": 1748459396794,
- "buildHash": "d479687b8ba13c6a7bb81dbade1c29317add46e7",
+ "version": "0.8.0",
+ "buildVersion": 15,
+ "buildTime": 1749349412239,
+ "buildHash": "9b64f05cb6205fc89bd3ad1c08a59993cd6ac127",
"name": "geekgeekrun-ui"
}
\ No newline at end of file
diff --git a/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/components/CityChooser.vue b/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/components/CityChooser.vue
index d31609c..b07f057 100644
--- a/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/components/CityChooser.vue
+++ b/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/components/CityChooser.vue
@@ -11,8 +11,23 @@
-
-
选择城市
+
+
{
+ isDialogVisible = true
+ gtagRenderer('choose_city_entry_button_clicked')
+ }
+ "
+ >选择城市
import { PropType, ref } from 'vue'
import cityGroupData from '../../../../../../common/constant/cityGroup.json'
+import { gtagRenderer } from '@renderer/utils/gtag'
const props = defineProps({
modelValue: {
@@ -136,23 +152,29 @@ for (const group of cityGroup) {
function handleDialogOpen() {
activeTabName.value = '热门城市'
selectedCities.value = [...(props.modelValue ?? [])]
+ gtagRenderer('choose_city_dialog_open')
}
function handleCancelClicked() {
+ gtagRenderer('choose_city_cancel_button_clicked')
isDialogVisible.value = false
}
function handleConfirmClicked() {
+ gtagRenderer('choose_city_confirm_button_clicked', { value: selectedCities.value.join(',') })
isDialogVisible.value = false
emits('update:modelValue', [...(selectedCities.value ?? [])])
}
function handleDialogClosed() {
selectedCities.value = []
+ gtagRenderer('choose_city_dialog_closed')
}
function handleClearSelectedCitiesInModelValue() {
emits('update:modelValue', [])
+ gtagRenderer('clear_selected_cities_in_mv_clicked')
}
function handleClearSelectedCitiesInDialog() {
selectedCities.value = []
+ gtagRenderer('clear_selected_cities_in_dialog_clicked')
}
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 e4f87ab..b7c0628 100644
--- a/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/index.vue
+++ b/packages/ui/src/renderer/src/page/MainLayout/GeekAutoStartChatWithBoss/index.vue
@@ -77,7 +77,7 @@
-
工作地
+
工作地
-
-
+
薪资(仅支持按月计算薪资的职位;非按月计算薪资职位(例如兼职职位、实习职位)将直接跳过)
-
-
工作经验
+
工作经验(暂不支持按日计算薪资的实习类职位)
gtagRenderer('expect_work_exp_list_changed', { value })"
>
- {{
- op.name
- }}
+
+ {{ op.name }}
@@ -439,15 +434,10 @@
-
-
且
+
且
职位类型正则(推荐填写,不区分大小写)
-
且
+
且
职位描述正则(不区分大小写)
-
当前职位名称/类型/描述不符合投递条件时:
-
-
- gtagRenderer('job_not_match_strategy_changed', { value })"
- >
- {{ op.name }}
+ 当前职位名称/类型/描述不符合投递条件时:
+
+
+
+ gtagRenderer('job_not_match_strategy_changed', { value })"
>
-
-
-
-
+
{{ op.name }}
+
+
+
+
+
@@ -905,6 +911,9 @@ electron.ipcRenderer.invoke('fetch-config-file-content').then((res) => {
res.config['boss.json'].expectWorkExpList.length
? res.config['boss.json'].expectWorkExpList
: []
+ const s = new Set([...(formContent.value?.expectWorkExpList ?? [])])
+ s.delete('在校生')
+ formContent.value.expectWorkExpList = [...s]
formContent.value.expectWorkExpNotMatchStrategy =
res.config['boss.json'].expectWorkExpNotMatchStrategy ?? MarkAsNotSuitOp.NO_OP
formContent.value.strategyScopeOptionWhenMarkJobWorkExpNotMatch =
@@ -1139,7 +1148,7 @@ const strategyScopeOptionWhenMarkJobNotMatch = [
value: StrategyScopeOptionWhenMarkJobNotMatch.ALL_JOB
},
{
- name: '仅和“期望公司白名单”匹配的职位',
+ name: '仅和“公司白名单”匹配的职位',
value: StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB
}
]
diff --git a/packages/ui/src/renderer/src/page/MainLayout/MarkAsNotSuitRecord.vue b/packages/ui/src/renderer/src/page/MainLayout/MarkAsNotSuitRecord.vue
index e28e0ce..3c85806 100644
--- a/packages/ui/src/renderer/src/page/MainLayout/MarkAsNotSuitRecord.vue
+++ b/packages/ui/src/renderer/src/page/MainLayout/MarkAsNotSuitRecord.vue
@@ -42,6 +42,14 @@
{{ markReasonTopicMap[row.markReason] }}
{{ formatMarkReason(row) }}
+
+ {{ markReasonTopicMap[row.markReason] }}
+ {{ formatMarkReason(row) }}
+
+
+ {{ markReasonTopicMap[row.markReason] }}
+ {{ formatMarkReason(row) }}
+
@@ -209,7 +217,9 @@ const markReasonTopicMap = {
[MarkAsNotSuitReason.BOSS_INACTIVE]: 'Boss不活跃',
[MarkAsNotSuitReason.USER_MANUAL_OPERATION_WITH_UNKNOWN_REASON]: '手动标记不合适',
[MarkAsNotSuitReason.JOB_NOT_SUIT]: '职位不合适',
- [MarkAsNotSuitReason.JOB_CITY_NOT_SUIT]: '工作地不合适'
+ [MarkAsNotSuitReason.JOB_CITY_NOT_SUIT]: '工作地不合适',
+ [MarkAsNotSuitReason.JOB_WORK_EXP_NOT_SUIT]: '工作经验不合适',
+ [MarkAsNotSuitReason.JOB_SALARY_NOT_SUIT]: '薪资不合适'
}
function formatMarkReason(row: VMarkAsNotSuitLog) {
@@ -241,6 +251,7 @@ function formatMarkReason(row: VMarkAsNotSuitLog) {
.filter(Boolean)
.join('\n')
}
+ case MarkAsNotSuitReason.JOB_WORK_EXP_NOT_SUIT:
case MarkAsNotSuitReason.JOB_CITY_NOT_SUIT: {
const extInfo = (() => {
try {
@@ -253,6 +264,21 @@ function formatMarkReason(row: VMarkAsNotSuitLog) {
.filter(Boolean)
.join('\n')
}
+ case MarkAsNotSuitReason.JOB_SALARY_NOT_SUIT: {
+ const extInfo = (() => {
+ try {
+ return JSON.parse(row.extInfo)
+ } catch {
+ return null
+ }
+ })()
+ return [
+ extInfo?.salaryDesc && `薪资:${extInfo.salaryDesc}`,
+ extInfo?.chosenReasonInUi?.text && `Boss选项内容:${extInfo.chosenReasonInUi.text}`
+ ]
+ .filter(Boolean)
+ .join('\n')
+ }
default: {
return ''
}