mirror of
https://github.com/geekgeekrun/geekgeekrun.git
synced 2026-09-07 16:37:06 +08:00
Merge remote-tracking branch 'origin/feature/block-company-config' into feature/multi-process
This commit is contained in:
@@ -35,5 +35,6 @@
|
|||||||
],
|
],
|
||||||
"isSageTimeEnabled": true,
|
"isSageTimeEnabled": true,
|
||||||
"sageTimeOpTimes": 100,
|
"sageTimeOpTimes": 100,
|
||||||
"sageTimePauseMinute": 15
|
"sageTimePauseMinute": 15,
|
||||||
|
"blockCompanyNameRegExpStr": ""
|
||||||
}
|
}
|
||||||
@@ -247,6 +247,19 @@ const recommendJobPageUrl = `https://www.zhipin.com/web/geek/jobs`
|
|||||||
|
|
||||||
const expectCompanySet = new Set(targetCompanyList)
|
const expectCompanySet = new Set(targetCompanyList)
|
||||||
const enableCompanyAllowList = Boolean(expectCompanySet.size)
|
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 }
|
* @type { import('puppeteer').Browser }
|
||||||
@@ -298,6 +311,18 @@ async function markJobAsNotSuitInRecommendPage (reasonCode) {
|
|||||||
let isOptionChosen = false
|
let isOptionChosen = false
|
||||||
if (chooseReasonDialogProxy) {
|
if (chooseReasonDialogProxy) {
|
||||||
switch (reasonCode) {
|
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: {
|
case MarkAsNotSuitReason.BOSS_INACTIVE: {
|
||||||
const opProxy = (await chooseReasonDialogProxy.$(`.zp-type-item[title="BOSS活跃度低"]`))
|
const opProxy = (await chooseReasonDialogProxy.$(`.zp-type-item[title="BOSS活跃度低"]`))
|
||||||
?? (await chooseReasonDialogProxy.$(`.zp-type-item[title="职位停招/招满"]`))
|
?? (await chooseReasonDialogProxy.$(`.zp-type-item[title="职位停招/招满"]`))
|
||||||
@@ -312,7 +337,7 @@ async function markJobAsNotSuitInRecommendPage (reasonCode) {
|
|||||||
case MarkAsNotSuitReason.JOB_WORK_EXP_NOT_SUIT:
|
case MarkAsNotSuitReason.JOB_WORK_EXP_NOT_SUIT:
|
||||||
case MarkAsNotSuitReason.JOB_CITY_NOT_SUIT: {
|
case MarkAsNotSuitReason.JOB_CITY_NOT_SUIT: {
|
||||||
const opProxy = (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*="距离"]`))
|
||||||
?? (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: {
|
case MarkAsNotSuitReason.JOB_SALARY_NOT_SUIT: {
|
||||||
const opProxy = (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$="城市"]`))
|
||||||
?? (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="重复推荐"]`))
|
||||||
@@ -984,6 +1009,14 @@ async function toRecommendPage (hooks) {
|
|||||||
].includes(expectSalaryNotMatchStrategy) &&
|
].includes(expectSalaryNotMatchStrategy) &&
|
||||||
strategyScopeOptionWhenMarkSalaryNotMatch === StrategyScopeOptionWhenMarkJobNotMatch.ALL_JOB
|
strategyScopeOptionWhenMarkSalaryNotMatch === StrategyScopeOptionWhenMarkJobNotMatch.ALL_JOB
|
||||||
) ? !checkIfSalarySuit(it.salaryDesc) : false
|
) ? !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
|
//#region collect not suit reasons
|
||||||
const notSuitReasonIdToStrategyMap = {}
|
const notSuitReasonIdToStrategyMap = {}
|
||||||
const notSuitConditionHandleMap = {
|
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() {
|
async active() {
|
||||||
blockBossNotActive.add(targetJobData.jobInfo.encryptUserId)
|
blockBossNotActive.add(targetJobData.jobInfo.encryptUserId)
|
||||||
if (jobNotActiveStrategy === MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL || !await page.$('.job-detail-box .job-detail-operate .not-suitable')) {
|
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
|
//#region
|
||||||
// null
|
// null
|
||||||
// 刚刚活跃 // 今日活跃 // 昨日活跃 // 3日内活跃 // 本周活跃 // 2周内活跃
|
// 刚刚活跃 // 今日活跃 // 昨日活跃 // 3日内活跃 // 本周活跃 // 2周内活跃
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export enum MarkAsNotSuitReason {
|
|||||||
JOB_CITY_NOT_SUIT = 4,
|
JOB_CITY_NOT_SUIT = 4,
|
||||||
JOB_WORK_EXP_NOT_SUIT = 5,
|
JOB_WORK_EXP_NOT_SUIT = 5,
|
||||||
JOB_SALARY_NOT_SUIT = 6,
|
JOB_SALARY_NOT_SUIT = 6,
|
||||||
|
COMPANY_NAME_NOT_SUIT = 7,
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum MarkAsNotSuitOp {
|
export enum MarkAsNotSuitOp {
|
||||||
|
|||||||
@@ -181,6 +181,12 @@ export default function initIpc() {
|
|||||||
if (hasOwn(payload, 'sageTimePauseMinute')) {
|
if (hasOwn(payload, 'sageTimePauseMinute')) {
|
||||||
bossConfig.sageTimePauseMinute = 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))
|
promiseArr.push(writeConfigFile('boss.json', bossConfig))
|
||||||
|
|
||||||
|
|||||||
@@ -60,7 +60,23 @@ const rechatLlmFallback =
|
|||||||
|
|
||||||
const expectJobTypeRegExpStr = readConfigFile('boss.json').expectJobTypeRegExpStr
|
const expectJobTypeRegExpStr = readConfigFile('boss.json').expectJobTypeRegExpStr
|
||||||
const onlyRemindBossWithExpectJobType =
|
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())
|
const dbInitPromise = initDb(getPublicDbFilePath())
|
||||||
|
|
||||||
@@ -156,7 +172,8 @@ async function saveCurrentChatRecord(page) {
|
|||||||
|
|
||||||
async function checkJobIsClosed() {
|
async function checkJobIsClosed() {
|
||||||
const encryptJobId = await pageMapByName.boss!.evaluate(() => {
|
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) {
|
if (!encryptJobId) {
|
||||||
return false
|
return false
|
||||||
@@ -431,6 +448,9 @@ const mainLoop = async () => {
|
|||||||
const toCheckItemAtIndex = friendListData.findIndex((it, index) => {
|
const toCheckItemAtIndex = friendListData.findIndex((it, index) => {
|
||||||
return (
|
return (
|
||||||
index >= cursorToContinueFind &&
|
index >= cursorToContinueFind &&
|
||||||
|
(onlyRemindBossWithoutBlockCompanyName && blockCompanyNameRegExp
|
||||||
|
? !blockCompanyNameRegExp.test(it.brandName)
|
||||||
|
: true) &&
|
||||||
(rechatLimitDay && it.updateTime
|
(rechatLimitDay && it.updateTime
|
||||||
? +new Date() - it.updateTime < rechatLimitDay * 24 * 60 * 60 * 1000
|
? +new Date() - it.updateTime < rechatLimitDay * 24 * 60 * 60 * 1000
|
||||||
: true) &&
|
: true) &&
|
||||||
@@ -605,11 +625,14 @@ export async function runEntry() {
|
|||||||
})
|
})
|
||||||
initPublicIpc()
|
initPublicIpc()
|
||||||
await connectToDaemon()
|
await connectToDaemon()
|
||||||
await sendToDaemon({
|
await sendToDaemon(
|
||||||
type: 'ping'
|
{
|
||||||
}, {
|
type: 'ping'
|
||||||
needCallback: true
|
},
|
||||||
})
|
{
|
||||||
|
needCallback: true
|
||||||
|
}
|
||||||
|
)
|
||||||
sendToDaemon({
|
sendToDaemon({
|
||||||
type: 'worker-to-gui-message',
|
type: 'worker-to-gui-message',
|
||||||
data: {
|
data: {
|
||||||
@@ -690,7 +713,11 @@ export async function runEntry() {
|
|||||||
process.exit(AUTO_CHAT_ERROR_EXIT_CODE.ACCESS_IS_DENIED)
|
process.exit(AUTO_CHAT_ERROR_EXIT_CODE.ACCESS_IS_DENIED)
|
||||||
break
|
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)
|
process.exit(AUTO_CHAT_ERROR_EXIT_CODE.PUPPETEER_IS_NOT_EXECUTABLE)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -703,7 +730,7 @@ export async function runEntry() {
|
|||||||
buttons: ['退出']
|
buttons: ['退出']
|
||||||
})
|
})
|
||||||
process.exit(AUTO_CHAT_ERROR_EXIT_CODE.LLM_UNAVAILABLE)
|
process.exit(AUTO_CHAT_ERROR_EXIT_CODE.LLM_UNAVAILABLE)
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
@@ -245,14 +245,16 @@
|
|||||||
<div
|
<div
|
||||||
font-size-14px
|
font-size-14px
|
||||||
flex
|
flex
|
||||||
|
mb6px
|
||||||
:style="{
|
:style="{
|
||||||
justifyContent: 'space-between',
|
justifyContent: 'space-between',
|
||||||
alignItems: 'center',
|
alignItems: 'baseline',
|
||||||
width: '100%'
|
width: '100%',
|
||||||
|
lineHeight: '1.25em'
|
||||||
}"
|
}"
|
||||||
>
|
>
|
||||||
<div>
|
<div>
|
||||||
公司白名单(以逗号分隔,不区分大小写;输入框留空表示不筛选)<el-tooltip
|
期望投递公司 <el-tooltip
|
||||||
effect="light"
|
effect="light"
|
||||||
placement="bottom-start"
|
placement="bottom-start"
|
||||||
@show="gtagRenderer('tooltip_show_about_expect_company_figure')"
|
@show="gtagRenderer('tooltip_show_about_expect_company_figure')"
|
||||||
@@ -263,8 +265,10 @@
|
|||||||
<el-button type="text" font-size-12px
|
<el-button type="text" font-size-12px
|
||||||
><span><QuestionFilled w-1em h-1em mr2px /></span
|
><span><QuestionFilled w-1em h-1em mr2px /></span
|
||||||
>公司信息UI位置图示</el-button
|
>公司信息UI位置图示</el-button
|
||||||
>
|
></el-tooltip
|
||||||
</el-tooltip>
|
><br /><span font-size-12px
|
||||||
|
><b color-orange>逗号分隔</b>,不区分大小写;输入框留空表示不筛选</span
|
||||||
|
>
|
||||||
</div>
|
</div>
|
||||||
<el-dropdown @command="handleExpectCompanyTemplateClicked">
|
<el-dropdown @command="handleExpectCompanyTemplateClicked">
|
||||||
<el-button size="small"
|
<el-button size="small"
|
||||||
@@ -291,6 +295,107 @@
|
|||||||
@blur="normalizeExpectCompanies"
|
@blur="normalizeExpectCompanies"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<div class="h-1px bg-#f0f0f0" mt16px mb8px />
|
||||||
|
<div
|
||||||
|
ref="blockCompanyNameRegExpSectionEl"
|
||||||
|
font-size-14px
|
||||||
|
flex
|
||||||
|
:style="{
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'baseline',
|
||||||
|
width: '100%',
|
||||||
|
lineHeight: '1.25em'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div mb6px>
|
||||||
|
不期望投递公司<b color-orange>正则</b> <el-tooltip
|
||||||
|
effect="light"
|
||||||
|
placement="bottom-start"
|
||||||
|
@show="gtagRenderer('tooltip_show_about_expect_company_figure')"
|
||||||
|
>
|
||||||
|
<template #content>
|
||||||
|
<img block h-270px src="../resources/intro-of-job-entry.png" />
|
||||||
|
</template>
|
||||||
|
<el-button type="text" font-size-12px
|
||||||
|
><span><QuestionFilled w-1em h-1em mr2px /></span>公司信息UI位置图示</el-button
|
||||||
|
></el-tooltip
|
||||||
|
><br /><span font-size-12px
|
||||||
|
><b color-orange>正则表达式</b>,不区分大小写;输入框留空表示不筛选;<span
|
||||||
|
color-orange
|
||||||
|
>优先级高于上方“期望投递公司”</span
|
||||||
|
></span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
<!-- <el-dropdown @command="handleExpectCompanyTemplateClicked">
|
||||||
|
<el-button size="small"
|
||||||
|
>公司列表模板 <el-icon class="el-icon--right"><arrow-down /></el-icon
|
||||||
|
></el-button>
|
||||||
|
<template #dropdown>
|
||||||
|
<el-dropdown-menu>
|
||||||
|
<el-dropdown-item
|
||||||
|
v-for="item in expectCompanyTemplateList"
|
||||||
|
:key="item.name"
|
||||||
|
:command="item"
|
||||||
|
>{{ item.name }}</el-dropdown-item
|
||||||
|
>
|
||||||
|
</el-dropdown-menu>
|
||||||
|
</template>
|
||||||
|
</el-dropdown> -->
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="block-company-filter-wrap"
|
||||||
|
:style="{
|
||||||
|
display: 'flex',
|
||||||
|
justifyContent: 'space-between',
|
||||||
|
gap: '10px'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-form-item prop="blockCompanyNameRegExpStr" mb0 w-full>
|
||||||
|
<el-input
|
||||||
|
v-model="formContent.blockCompanyNameRegExpStr"
|
||||||
|
:autosize="{ minRows: 4 }"
|
||||||
|
max-h-8lh
|
||||||
|
type="textarea"
|
||||||
|
placeholder="置空表示“不限公司,任意公司都不会被标记为不合适”"
|
||||||
|
@blur="
|
||||||
|
formContent.blockCompanyNameRegExpStr =
|
||||||
|
formContent.blockCompanyNameRegExpStr?.trim() ?? ''
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
</el-form-item>
|
||||||
|
<div
|
||||||
|
v-if="formContent.expectCityList?.length"
|
||||||
|
:style="{
|
||||||
|
width: '400px',
|
||||||
|
borderLeft: '1px solid #f0f0f0',
|
||||||
|
paddingLeft: '10px',
|
||||||
|
flex: `0 0 auto`
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-form-item
|
||||||
|
mb10px
|
||||||
|
:style="{
|
||||||
|
width: '100%'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<div font-size-12px>当前职位对应公司名称与不期望投递公司正则匹配时:</div>
|
||||||
|
<el-select
|
||||||
|
v-model="formContent.blockCompanyNameRegMatchStrategy"
|
||||||
|
@change="
|
||||||
|
(value) => gtagRenderer('block_company_match_strategy_changed', { value })
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="op in strategyOptionWhenCurrentJobNotMatch"
|
||||||
|
:key="op.value"
|
||||||
|
:label="op.name"
|
||||||
|
:value="op.value"
|
||||||
|
>{{ op.name }}</el-option
|
||||||
|
>
|
||||||
|
</el-select>
|
||||||
|
</el-form-item>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="h-1px bg-#f0f0f0" mt16px mb16px />
|
<div class="h-1px bg-#f0f0f0" mt16px mb16px />
|
||||||
<div mt16px>
|
<div mt16px>
|
||||||
<div font-size-14px mb8px>工作地</div>
|
<div font-size-14px mb8px>工作地</div>
|
||||||
@@ -1213,7 +1318,9 @@ const formContent = ref({
|
|||||||
]),
|
]),
|
||||||
isSageTimeEnabled: true,
|
isSageTimeEnabled: true,
|
||||||
sageTimeOpTimes: 100,
|
sageTimeOpTimes: 100,
|
||||||
sageTimePauseMinute: 15
|
sageTimePauseMinute: 15,
|
||||||
|
blockCompanyNameRegExpStr: '',
|
||||||
|
blockCompanyNameRegMatchStrategy: MarkAsNotSuitOp.NO_OP
|
||||||
})
|
})
|
||||||
|
|
||||||
const anyCombineBossRecommendFilterHasCondition = computed(() => {
|
const anyCombineBossRecommendFilterHasCondition = computed(() => {
|
||||||
@@ -1371,10 +1478,15 @@ electron.ipcRenderer.invoke('fetch-config-file-content').then((res) => {
|
|||||||
parseFloat(res.config['boss.json'].sageTimePauseMinute) < 0
|
parseFloat(res.config['boss.json'].sageTimePauseMinute) < 0
|
||||||
? 15
|
? 15
|
||||||
: parseFloat(res.config['boss.json'].sageTimePauseMinute)
|
: parseFloat(res.config['boss.json'].sageTimePauseMinute)
|
||||||
|
formContent.value.blockCompanyNameRegExpStr =
|
||||||
|
res.config['boss.json'].blockCompanyNameRegExpStr?.trim() ?? ''
|
||||||
|
formContent.value.blockCompanyNameRegMatchStrategy =
|
||||||
|
res.config['boss.json'].blockCompanyNameRegMatchStrategy ?? MarkAsNotSuitOp.NO_OP
|
||||||
})
|
})
|
||||||
|
|
||||||
const jobSourceFormItemSectionEl = ref()
|
const jobSourceFormItemSectionEl = ref()
|
||||||
const jobDetailRegExpSectionEl = ref()
|
const jobDetailRegExpSectionEl = ref()
|
||||||
|
const blockCompanyNameRegExpSectionEl = ref()
|
||||||
const formRules = {
|
const formRules = {
|
||||||
expectJobNameRegExpStr: {
|
expectJobNameRegExpStr: {
|
||||||
trigger: 'blur',
|
trigger: 'blur',
|
||||||
@@ -1489,6 +1601,25 @@ const formRules = {
|
|||||||
}
|
}
|
||||||
cb()
|
cb()
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
blockCompanyNameRegExpStr: {
|
||||||
|
trigger: 'blur',
|
||||||
|
validator(_, value, cb) {
|
||||||
|
if (!value) {
|
||||||
|
cb()
|
||||||
|
gtagRenderer('empty_reg_exp_for_bcn')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
new RegExp(value, 'ig')
|
||||||
|
gtagRenderer('valid_reg_exp_for_bcn', { v: value })
|
||||||
|
cb()
|
||||||
|
} catch (err) {
|
||||||
|
cb(new Error(`正则无效:${err?.message}`))
|
||||||
|
blockCompanyNameRegExpSectionEl.value?.scrollIntoViewIfNeeded()
|
||||||
|
gtagRenderer('invalid_reg_exp_for_bcn', { v: value })
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1671,7 +1802,7 @@ const strategyScopeOptionWhenMarkJobNotMatch = [
|
|||||||
value: StrategyScopeOptionWhenMarkJobNotMatch.ALL_JOB
|
value: StrategyScopeOptionWhenMarkJobNotMatch.ALL_JOB
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: '仅和“公司白名单”匹配的职位',
|
name: '仅和“期望投递公司”匹配的职位',
|
||||||
value: StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB
|
value: StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -1989,7 +2120,8 @@ const handleStopButtonClick = async () => {
|
|||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
line-height: 1.2em;
|
line-height: 1.2em;
|
||||||
}
|
}
|
||||||
.job-detail-filter-wrap .el-form-item__error {
|
.job-detail-filter-wrap .el-form-item__error,
|
||||||
|
.block-company-filter-wrap .el-form-item__error {
|
||||||
position: static;
|
position: static;
|
||||||
word-break: break-word;
|
word-break: break-word;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,6 +50,10 @@
|
|||||||
<strong>{{ markReasonTopicMap[row.markReason] }}</strong>
|
<strong>{{ markReasonTopicMap[row.markReason] }}</strong>
|
||||||
<pre class="m-0 of-auto">{{ formatMarkReason(row) }}</pre>
|
<pre class="m-0 of-auto">{{ formatMarkReason(row) }}</pre>
|
||||||
</template>
|
</template>
|
||||||
|
<template v-if="row.markReason === MarkAsNotSuitReason.COMPANY_NAME_NOT_SUIT">
|
||||||
|
<strong>{{ markReasonTopicMap[row.markReason] }}</strong>
|
||||||
|
<pre class="m-0 of-auto">{{ formatMarkReason(row) }}</pre>
|
||||||
|
</template>
|
||||||
</template>
|
</template>
|
||||||
</ElTableColumn>
|
</ElTableColumn>
|
||||||
<ElTableColumn prop="experienceName" label="工作经验" />
|
<ElTableColumn prop="experienceName" label="工作经验" />
|
||||||
@@ -219,7 +223,8 @@ const markReasonTopicMap = {
|
|||||||
[MarkAsNotSuitReason.JOB_NOT_SUIT]: '职位不合适',
|
[MarkAsNotSuitReason.JOB_NOT_SUIT]: '职位不合适',
|
||||||
[MarkAsNotSuitReason.JOB_CITY_NOT_SUIT]: '工作地不合适',
|
[MarkAsNotSuitReason.JOB_CITY_NOT_SUIT]: '工作地不合适',
|
||||||
[MarkAsNotSuitReason.JOB_WORK_EXP_NOT_SUIT]: '工作经验不合适',
|
[MarkAsNotSuitReason.JOB_WORK_EXP_NOT_SUIT]: '工作经验不合适',
|
||||||
[MarkAsNotSuitReason.JOB_SALARY_NOT_SUIT]: '薪资不合适'
|
[MarkAsNotSuitReason.JOB_SALARY_NOT_SUIT]: '薪资不合适',
|
||||||
|
[MarkAsNotSuitReason.COMPANY_NAME_NOT_SUIT]: '公司名称不匹配'
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatMarkReason(row: VMarkAsNotSuitLog) {
|
function formatMarkReason(row: VMarkAsNotSuitLog) {
|
||||||
@@ -279,6 +284,18 @@ function formatMarkReason(row: VMarkAsNotSuitLog) {
|
|||||||
.filter(Boolean)
|
.filter(Boolean)
|
||||||
.join('\n')
|
.join('\n')
|
||||||
}
|
}
|
||||||
|
case MarkAsNotSuitReason.COMPANY_NAME_NOT_SUIT: {
|
||||||
|
const extInfo = (() => {
|
||||||
|
try {
|
||||||
|
return JSON.parse(row.extInfo)
|
||||||
|
} catch {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
})()
|
||||||
|
return [extInfo?.chosenReasonInUi?.text && `BOSS选项内容:${extInfo.chosenReasonInUi.text}`]
|
||||||
|
.filter(Boolean)
|
||||||
|
.join('\n')
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
return ''
|
return ''
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,21 @@
|
|||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
|
<el-form-item>
|
||||||
|
<div>
|
||||||
|
<el-checkbox v-if="!blockCompanyNameRegExpStr?.trim()" :model-value="false" disabled>
|
||||||
|
发送提醒消息前,先按照“自动开聊-不期望投递公司正则”校验正在与BOSS沟通的岗位是否归属于不期望投递的公司,如果是,则不提醒
|
||||||
|
</el-checkbox>
|
||||||
|
<template v-else>
|
||||||
|
<el-checkbox v-model="formContent.autoReminder.onlyRemindBossWithoutBlockCompanyName">
|
||||||
|
发送提醒消息前,先按照“自动开聊-不期望投递公司正则”校验正在与BOSS沟通的岗位是否归属于不期望投递的公司,如果是,则不提醒
|
||||||
|
</el-checkbox>
|
||||||
|
<div ml1.5em color-gray>
|
||||||
|
<div>当前不期望投递公司正则:{{ blockCompanyNameRegExpStr?.trim() }}</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</div>
|
||||||
|
</el-form-item>
|
||||||
<el-form-item class="mb0" label="跟进话术 - 当发现已读不回的BOSS时,将要向BOSS发出:">
|
<el-form-item class="mb0" label="跟进话术 - 当发现已读不回的BOSS时,将要向BOSS发出:">
|
||||||
<el-radio-group v-model="formContent.autoReminder.rechatContentSource">
|
<el-radio-group v-model="formContent.autoReminder.rechatContentSource">
|
||||||
<div>
|
<div>
|
||||||
@@ -258,7 +273,8 @@ const formContent = ref({
|
|||||||
rechatContentSource: 1,
|
rechatContentSource: 1,
|
||||||
recentMessageQuantityForLlm: 8,
|
recentMessageQuantityForLlm: 8,
|
||||||
rechatLlmFallback: RECHAT_LLM_FALLBACK.SEND_LOOK_FORWARD_EMOTION,
|
rechatLlmFallback: RECHAT_LLM_FALLBACK.SEND_LOOK_FORWARD_EMOTION,
|
||||||
onlyRemindBossWithExpectJobType: true
|
onlyRemindBossWithExpectJobType: true,
|
||||||
|
onlyRemindBossWithoutBlockCompanyName: true
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -296,15 +312,17 @@ electron.ipcRenderer.invoke('fetch-config-file-content').then((res) => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const expectJobTypeRegExpStr = ref('')
|
const expectJobTypeRegExpStr = ref('')
|
||||||
async function fetchExpectJobTypeRegExpStr() {
|
const blockCompanyNameRegExpStr = ref('')
|
||||||
|
async function fetchAutoStartChatConfig() {
|
||||||
await electron.ipcRenderer.invoke('fetch-config-file-content').then((res) => {
|
await electron.ipcRenderer.invoke('fetch-config-file-content').then((res) => {
|
||||||
expectJobTypeRegExpStr.value = res.config['boss.json']?.expectJobTypeRegExpStr
|
expectJobTypeRegExpStr.value = res.config['boss.json']?.expectJobTypeRegExpStr
|
||||||
|
blockCompanyNameRegExpStr.value = res.config['boss.json']?.blockCompanyNameRegExpStr
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
fetchExpectJobTypeRegExpStr()
|
fetchAutoStartChatConfig()
|
||||||
mittBus.on('auto-start-chat-with-boss-config-saved', fetchExpectJobTypeRegExpStr)
|
mittBus.on('auto-start-chat-with-boss-config-saved', fetchAutoStartChatConfig)
|
||||||
onUnmounted(() => {
|
onUnmounted(() => {
|
||||||
mittBus.off('auto-start-chat-with-boss-config-saved', fetchExpectJobTypeRegExpStr)
|
mittBus.off('auto-start-chat-with-boss-config-saved', fetchAutoStartChatConfig)
|
||||||
})
|
})
|
||||||
|
|
||||||
const resumeContent = ref(null)
|
const resumeContent = ref(null)
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 499 KiB After Width: | Height: | Size: 232 KiB |
Reference in New Issue
Block a user