mirror of
https://github.com/geekgeekrun/geekgeekrun.git
synced 2026-09-08 17:09:07 +08:00
Merge branch 'feature/static-combine-job-filter' into feature/ui
This commit is contained in:
@@ -124,3 +124,35 @@ export function checkAnyCombineBossRecommendFilterHasCondition(value) {
|
|||||||
return !!value[k]?.length
|
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
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"combineRecommendJobFilterType": 1,
|
||||||
"anyCombineRecommendJobFilter": {
|
"anyCombineRecommendJobFilter": {
|
||||||
"salaryList": [],
|
"salaryList": [],
|
||||||
"experienceList": [],
|
"experienceList": [],
|
||||||
@@ -6,6 +7,7 @@
|
|||||||
"scaleList": [],
|
"scaleList": [],
|
||||||
"industryList": []
|
"industryList": []
|
||||||
},
|
},
|
||||||
|
"staticCombineRecommendJobFilterConditions": [],
|
||||||
"isSkipEmptyConditionForCombineRecommendJobFilter": false,
|
"isSkipEmptyConditionForCombineRecommendJobFilter": false,
|
||||||
"expectJobRegExpStr": "",
|
"expectJobRegExpStr": "",
|
||||||
"jobNotMatchStrategy": 1,
|
"jobNotMatchStrategy": 1,
|
||||||
|
|||||||
@@ -15,12 +15,21 @@ import { readConfigFile, writeStorageFile, ensureConfigFileExist, readStorageFil
|
|||||||
import {
|
import {
|
||||||
calculateTotalCombinations,
|
calculateTotalCombinations,
|
||||||
combineFiltersWithConstraintsGenerator,
|
combineFiltersWithConstraintsGenerator,
|
||||||
checkAnyCombineBossRecommendFilterHasCondition
|
checkAnyCombineBossRecommendFilterHasCondition,
|
||||||
|
formatStaticCombineFilters,
|
||||||
} from './combineCalculator.mjs'
|
} 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'
|
||||||
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 {
|
import {
|
||||||
activeDescList,
|
activeDescList,
|
||||||
RECOMMEND_JOB_ENTRY_SELECTOR,
|
RECOMMEND_JOB_ENTRY_SELECTOR,
|
||||||
@@ -85,8 +94,10 @@ const bossCookies = readStorageFile('boss-cookies.json')
|
|||||||
const bossLocalStorage = readStorageFile('boss-local-storage.json')
|
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 combineRecommendJobFilterType = readConfigFile('boss.json').combineRecommendJobFilterType ?? CombineRecommendJobFilterType.ANY_COMBINE
|
||||||
|
|
||||||
const anyCombineRecommendJobFilter = readConfigFile('boss.json').anyCombineRecommendJobFilter
|
const anyCombineRecommendJobFilter = readConfigFile('boss.json').anyCombineRecommendJobFilter
|
||||||
|
const staticCombineRecommendJobFilterConditions = readConfigFile('boss.json').staticCombineRecommendJobFilterConditions ?? []
|
||||||
let isSkipEmptyConditionForCombineRecommendJobFilter = readConfigFile('boss.json').isSkipEmptyConditionForCombineRecommendJobFilter
|
let isSkipEmptyConditionForCombineRecommendJobFilter = readConfigFile('boss.json').isSkipEmptyConditionForCombineRecommendJobFilter
|
||||||
if (!checkAnyCombineBossRecommendFilterHasCondition(anyCombineRecommendJobFilter)) {
|
if (!checkAnyCombineBossRecommendFilterHasCondition(anyCombineRecommendJobFilter)) {
|
||||||
isSkipEmptyConditionForCombineRecommendJobFilter = false
|
isSkipEmptyConditionForCombineRecommendJobFilter = false
|
||||||
@@ -359,7 +370,7 @@ export function testIfJobTitleOrDescriptionSuit (jobInfo, matchLogic) {
|
|||||||
try {
|
try {
|
||||||
if (expectJobNameRegExpStr.trim()) {
|
if (expectJobNameRegExpStr.trim()) {
|
||||||
const regExp = new RegExp(expectJobNameRegExpStr, 'i')
|
const regExp = new RegExp(expectJobNameRegExpStr, 'i')
|
||||||
isJobNameSuit = regExp.test(jobInfo.jobName)
|
isJobNameSuit = regExp.test(jobInfo.jobName?.replace(/\n/g, '') ?? '')
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
}
|
}
|
||||||
@@ -367,7 +378,7 @@ export function testIfJobTitleOrDescriptionSuit (jobInfo, matchLogic) {
|
|||||||
try {
|
try {
|
||||||
if (expectJobTypeRegExpStr.trim()) {
|
if (expectJobTypeRegExpStr.trim()) {
|
||||||
const regExp = new RegExp(expectJobTypeRegExpStr, 'i')
|
const regExp = new RegExp(expectJobTypeRegExpStr, 'i')
|
||||||
isJobTypeSuit = regExp.test(jobInfo.positionName)
|
isJobTypeSuit = regExp.test(jobInfo.positionName?.replace(/\n/g, '') ?? '')
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
}
|
}
|
||||||
@@ -375,7 +386,7 @@ export function testIfJobTitleOrDescriptionSuit (jobInfo, matchLogic) {
|
|||||||
try {
|
try {
|
||||||
if (expectJobDescRegExpStr.trim()) {
|
if (expectJobDescRegExpStr.trim()) {
|
||||||
const regExp = new RegExp(expectJobDescRegExpStr, 'i')
|
const regExp = new RegExp(expectJobDescRegExpStr, 'i')
|
||||||
isJobDescSuit = regExp.test(jobInfo.postDescription)
|
isJobDescSuit = regExp.test(jobInfo.postDescription?.replace(/\n/g, '') ?? '')
|
||||||
}
|
}
|
||||||
} catch {
|
} catch {
|
||||||
}
|
}
|
||||||
@@ -662,11 +673,13 @@ async function toRecommendPage (hooks) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const filterConditions =
|
||||||
|
combineRecommendJobFilterType === CombineRecommendJobFilterType.STATIC_COMBINE
|
||||||
|
? formatStaticCombineFilters(staticCombineRecommendJobFilterConditions)
|
||||||
|
: combineFiltersWithConstraintsGenerator(anyCombineRecommendJobFilter)
|
||||||
let expectJobList
|
let expectJobList
|
||||||
iterateFilterCondition: for (
|
iterateFilterCondition: for (
|
||||||
const filterCondition of combineFiltersWithConstraintsGenerator(
|
const filterCondition of filterConditions
|
||||||
anyCombineRecommendJobFilter
|
|
||||||
)
|
|
||||||
) {
|
) {
|
||||||
findInCurrentFilterCondition: while(true) {
|
findInCurrentFilterCondition: while(true) {
|
||||||
await sleepWithRandomDelay(2500)
|
await sleepWithRandomDelay(2500)
|
||||||
@@ -691,11 +704,17 @@ async function toRecommendPage (hooks) {
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isSkipEmptyConditionForCombineRecommendJobFilter &&
|
(
|
||||||
Object.keys(filterCondition).length &&
|
combineRecommendJobFilterType === CombineRecommendJobFilterType.STATIC_COMBINE && filterCondition === null
|
||||||
Object.keys(filterCondition).every(k => !filterCondition[k]?.length)
|
)
|
||||||
|
||
|
||||||
|
(
|
||||||
|
combineRecommendJobFilterType === CombineRecommendJobFilterType.ANY_COMBINE &&
|
||||||
|
isSkipEmptyConditionForCombineRecommendJobFilter &&
|
||||||
|
Object.keys(filterCondition).length &&
|
||||||
|
Object.keys(filterCondition).every(k => !filterCondition[k]?.length)
|
||||||
|
)
|
||||||
) {
|
) {
|
||||||
sleep(4000)
|
sleep(4000)
|
||||||
continue iterateFilterCondition
|
continue iterateFilterCondition
|
||||||
|
|||||||
@@ -34,3 +34,8 @@ export enum JobSource {
|
|||||||
recommend = 2,
|
recommend = 2,
|
||||||
search = 3,
|
search = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum CombineRecommendJobFilterType {
|
||||||
|
ANY_COMBINE = 1,
|
||||||
|
STATIC_COMBINE = 2,
|
||||||
|
}
|
||||||
@@ -159,6 +159,13 @@ export default function initIpc() {
|
|||||||
if (hasOwn(payload, 'jobSourceList')) {
|
if (hasOwn(payload, 'jobSourceList')) {
|
||||||
bossConfig.jobSourceList = 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))
|
promiseArr.push(writeConfigFile('boss.json', bossConfig))
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,264 @@
|
|||||||
|
<template>
|
||||||
|
<div>
|
||||||
|
<el-button p-0 h-auto flex size="small" type="text" :icon="Plus" @click="addCondition"
|
||||||
|
>添加条件</el-button
|
||||||
|
>
|
||||||
|
<div class="job-combo-filter" mt-8px>
|
||||||
|
<el-table
|
||||||
|
size="small"
|
||||||
|
:data="props.modelValue"
|
||||||
|
border
|
||||||
|
:style="{ maxWidth: '100%' }"
|
||||||
|
:row-style="
|
||||||
|
({ row }) => {
|
||||||
|
return {
|
||||||
|
backgroundColor:
|
||||||
|
duplicatedMap.get(getStaticCombineFilterKey(row))?.length > 1
|
||||||
|
? '#fcd4b7'
|
||||||
|
: 'transparent'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<template #empty>
|
||||||
|
<div lh-1.5em>
|
||||||
|
列表中没有条件,将仅使用默认的“初始空条件”为您筛选职位<br />
|
||||||
|
你可以点击表格左上角“<el-button
|
||||||
|
p-0
|
||||||
|
h-auto
|
||||||
|
size="small"
|
||||||
|
type="text"
|
||||||
|
:icon="Plus"
|
||||||
|
@click="addCondition"
|
||||||
|
>添加条件</el-button
|
||||||
|
>”按钮,添加更多筛选条件。
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<el-table-column :resizable="false" label="" :width="80">
|
||||||
|
<template #default="{ $index: index }">
|
||||||
|
<div
|
||||||
|
:style="{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
justifyContent: 'center',
|
||||||
|
gap: '2px',
|
||||||
|
height: 'fit-content'
|
||||||
|
}"
|
||||||
|
>
|
||||||
|
<el-button
|
||||||
|
:disabled="index <= 0"
|
||||||
|
style="margin: 0"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
:icon="ArrowUp"
|
||||||
|
@click="moveConditionUp(index)"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
:disabled="index >= modelValue?.length - 1"
|
||||||
|
style="margin: 0"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
:icon="ArrowDown"
|
||||||
|
@click="moveConditionDown(index)"
|
||||||
|
/>
|
||||||
|
<el-button
|
||||||
|
style="margin: 0"
|
||||||
|
circle
|
||||||
|
size="small"
|
||||||
|
:icon="Delete"
|
||||||
|
@click="removeCondition(index)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :resizable="false" label="薪资待遇" prop="salary">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-select
|
||||||
|
v-model="row.salary"
|
||||||
|
:disabled="row.___itemType === 'empty-condition-placeholder'"
|
||||||
|
clearable
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="it in conditions.salaryList.filter((it) => it.code !== 0)"
|
||||||
|
:key="it.code"
|
||||||
|
:value="it.code"
|
||||||
|
:label="it.name"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :resizable="false" label="工作经验" prop="experience">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-select
|
||||||
|
v-model="row.experience"
|
||||||
|
:disabled="row.___itemType === 'empty-condition-placeholder'"
|
||||||
|
clearable
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="it in conditions.experienceList.filter((it) => it.code !== 0)"
|
||||||
|
:key="it.code"
|
||||||
|
:value="it.code"
|
||||||
|
:label="it.name"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :resizable="false" label="学历要求" prop="degree">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-select
|
||||||
|
v-model="row.degree"
|
||||||
|
:disabled="row.___itemType === 'empty-condition-placeholder'"
|
||||||
|
clearable
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="it in conditions.degreeList.filter((it) => it.code !== 0)"
|
||||||
|
:key="it.code"
|
||||||
|
:value="it.code"
|
||||||
|
:label="it.name"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :resizable="false" label="公司行业" :width="200" prop="industry">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-select
|
||||||
|
v-model="row.industry"
|
||||||
|
:disabled="row.___itemType === 'empty-condition-placeholder'"
|
||||||
|
clearable
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<el-option-group
|
||||||
|
v-for="group in industryFilterExemption"
|
||||||
|
:key="group.code"
|
||||||
|
:label="group.name"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="item in group.subLevelModelList"
|
||||||
|
:key="item.code"
|
||||||
|
:label="item.name"
|
||||||
|
:value="item.code"
|
||||||
|
/>
|
||||||
|
</el-option-group>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
<el-table-column :resizable="false" label="公司规模" prop="scale">
|
||||||
|
<template #default="{ row }">
|
||||||
|
<el-select
|
||||||
|
v-model="row.scaleList"
|
||||||
|
:disabled="row.___itemType === 'empty-condition-placeholder'"
|
||||||
|
clearable
|
||||||
|
size="small"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="it in conditions.scaleList.filter((it) => it.code !== 0)"
|
||||||
|
:key="it.code"
|
||||||
|
:value="it.code"
|
||||||
|
:label="it.name"
|
||||||
|
/>
|
||||||
|
</el-select>
|
||||||
|
</template>
|
||||||
|
</el-table-column>
|
||||||
|
</el-table>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
Array.from(duplicatedMap.values()).some((it) => {
|
||||||
|
return it.length > 1
|
||||||
|
})
|
||||||
|
"
|
||||||
|
color-orange
|
||||||
|
font-size-12px
|
||||||
|
>
|
||||||
|
列表中被橙色高亮的条件存在重复项,相关重复项将被合并,运行时遍历顺序以第一次出现为准
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script lang="ts" setup>
|
||||||
|
import conditions from '@geekgeekrun/geek-auto-start-chat-with-boss/internal-config/job-filter-conditions-20241002.json'
|
||||||
|
import industryFilterExemption from '@geekgeekrun/geek-auto-start-chat-with-boss/internal-config/job-filter-industry-filter-exemption-20241002.json'
|
||||||
|
import { ArrowUp, ArrowDown, Delete, Plus } from '@element-plus/icons-vue'
|
||||||
|
import { computed, PropType } from 'vue'
|
||||||
|
|
||||||
|
import { getStaticCombineFilterKey } from '@geekgeekrun/geek-auto-start-chat-with-boss/combineCalculator.mjs'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
modelValue: {
|
||||||
|
type: Array as PropType<
|
||||||
|
Array<{
|
||||||
|
salary: number | null
|
||||||
|
experience: number | null
|
||||||
|
degree: number | null
|
||||||
|
industry: number | null
|
||||||
|
scale: number | null
|
||||||
|
}>
|
||||||
|
>,
|
||||||
|
default: () => []
|
||||||
|
},
|
||||||
|
isSkipEmptyConditionForCombineRecommendJobFilter: {
|
||||||
|
type: Boolean
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
function getNewConditionItem() {
|
||||||
|
return {
|
||||||
|
salary: null,
|
||||||
|
experience: null,
|
||||||
|
degree: null,
|
||||||
|
industry: null,
|
||||||
|
scale: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function addCondition() {
|
||||||
|
props.modelValue?.push(getNewConditionItem())
|
||||||
|
// gtagRenderer('resume_work_exp_added')
|
||||||
|
}
|
||||||
|
function moveConditionUp(index) {
|
||||||
|
;[props.modelValue[index], props.modelValue[index - 1]] = [
|
||||||
|
props.modelValue[index - 1],
|
||||||
|
props.modelValue[index]
|
||||||
|
]
|
||||||
|
// gtagRenderer('resume_work_exp_moved_up')
|
||||||
|
}
|
||||||
|
|
||||||
|
function moveConditionDown(index) {
|
||||||
|
;[props.modelValue[index], props.modelValue[index + 1]] = [
|
||||||
|
props.modelValue[index + 1],
|
||||||
|
props.modelValue[index]
|
||||||
|
]
|
||||||
|
// gtagRenderer('resume_work_exp_moved_down')
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeCondition(index) {
|
||||||
|
props.modelValue?.splice(index, 1)
|
||||||
|
// gtagRenderer('resume_work_exp_removed')
|
||||||
|
}
|
||||||
|
const duplicatedMap = computed(() => {
|
||||||
|
const map = new Map()
|
||||||
|
for (const condition of props.modelValue ?? []) {
|
||||||
|
const key = getStaticCombineFilterKey(condition)
|
||||||
|
if (!map.has(key)) {
|
||||||
|
map.set(key, [])
|
||||||
|
}
|
||||||
|
const arr = map.get(key)
|
||||||
|
arr.push(condition)
|
||||||
|
}
|
||||||
|
return map
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.job-combo-filter {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
gap: 10px;
|
||||||
|
.filter-item {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
+13
-2
@@ -35,7 +35,7 @@ const expectJobFilterTemplateList = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
type: '互联网/AI',
|
type: '互联网/AI',
|
||||||
name: '前端开发工程师、JavaScript',
|
name: '前端开发工程师',
|
||||||
config: {
|
config: {
|
||||||
expectJobNameRegExpStr: '前端|H5|\\bFE\\b',
|
expectJobNameRegExpStr: '前端|H5|\\bFE\\b',
|
||||||
expectJobTypeRegExpStr: '前端开发|javascript',
|
expectJobTypeRegExpStr: '前端开发|javascript',
|
||||||
@@ -43,6 +43,17 @@ const expectJobFilterTemplateList = [
|
|||||||
jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.SOME
|
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',
|
type: '互联网/AI',
|
||||||
name: '测试工程师、测试开发',
|
name: '测试工程师、测试开发',
|
||||||
@@ -193,7 +204,7 @@ const expectJobFilterTemplateList = [
|
|||||||
expectJobNameRegExpStr: '招聘|高招|Recruiter|HR|人力|人资|人事',
|
expectJobNameRegExpStr: '招聘|高招|Recruiter|HR|人力|人资|人事',
|
||||||
expectJobTypeRegExpStr: '招聘|猎头|人力',
|
expectJobTypeRegExpStr: '招聘|猎头|人力',
|
||||||
expectJobDescRegExpStr:
|
expectJobDescRegExpStr:
|
||||||
'招聘|高招|Recruiter|简历|面试|人才引进|Mapping|人才画像|offer|猎头|内推|外推|猎聘|Boss|拉勾|前程无忧|智联|58同城|领英|LinkedIn|ATS|人才库|Moka|北森|iTenant|倍罗|大易|伯乐',
|
'招聘|高招|Recruiter|简历|面试|人才引进|Mapping|人才画像|offer|猎头|内推|外推|猎聘|Boss|拉勾|前程无忧|智联|58同城|领英|LinkedIn|ATS|人才库|Moka|北森|iTenant|倍罗|大易',
|
||||||
jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY
|
jobDetailRegExpMatchLogic: JobDetailRegExpMatchLogic.EVERY
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -49,60 +49,99 @@
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="filter" mt18px>
|
<el-form-item prop="filter" mt18px mb0px w-full>
|
||||||
<div font-size-16px>
|
<div flex-1>
|
||||||
你希望Boss直聘为你展示什么样的职位?
|
<div font-size-16px>
|
||||||
<el-tooltip
|
你希望Boss直聘为你筛选出什么样的职位?
|
||||||
effect="light"
|
<el-tooltip
|
||||||
placement="bottom-start"
|
effect="light"
|
||||||
@show="gtagRenderer('tooltip_show_about_wrongly_mark_not_suit')"
|
placement="bottom-start"
|
||||||
>
|
@show="gtagRenderer('tooltip_show_about_wrongly_mark_not_suit')"
|
||||||
<template #content>
|
|
||||||
<ul m0 line-height-1.5em w-540px pl2em>
|
|
||||||
<li>
|
|
||||||
这个配置决定了下面列表中会展示哪些职位。查找职位时,会在Boss直聘页面上自动组合下方设置的筛选条件。对应UI:<br />
|
|
||||||
<img h-270px src="../resources/intro-of-job-filter-auto-change.png" />
|
|
||||||
</li>
|
|
||||||
<li color-orange>
|
|
||||||
建议不要筛选过多条件,否则最终组合数会成为一个很大的数字。这将在当前职位中尝试太多筛选条件,不能及时进入下一个职位,且会增加命中风控的概率
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</template>
|
|
||||||
<el-button type="text" font-size-12px
|
|
||||||
><span><QuestionFilled w-1em h-1em mr2px /></span
|
|
||||||
>这个配置是如何工作的?</el-button
|
|
||||||
>
|
>
|
||||||
</el-tooltip>
|
<template #content>
|
||||||
|
<ul m0 line-height-1.5em w-540px pl2em>
|
||||||
|
<li>
|
||||||
|
这个配置决定了下面列表中会展示哪些职位。查找职位时,会在Boss直聘页面上自动组合下方设置的筛选条件。对应UI:<br />
|
||||||
|
<img h-270px src="../resources/intro-of-job-filter-auto-change.png" />
|
||||||
|
</li>
|
||||||
|
<li color-orange>
|
||||||
|
建议不要筛选过多条件,否则最终组合数会成为一个很大的数字。这将在当前职位中尝试太多筛选条件,不能及时进入下一个职位,且会增加命中风控的概率
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
<el-button type="text" font-size-12px
|
||||||
|
><span><QuestionFilled w-1em h-1em mr2px /></span
|
||||||
|
>这个配置是如何工作的?</el-button
|
||||||
|
>
|
||||||
|
</el-tooltip>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<div>
|
||||||
|
<div font-size-12px>筛选条件遍历方式</div>
|
||||||
|
<el-select
|
||||||
|
v-model="formContent.combineRecommendJobFilterType"
|
||||||
|
w-320px
|
||||||
|
@change="
|
||||||
|
(v) => {
|
||||||
|
gtagRenderer('crjf_type_changed', { v })
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<el-option
|
||||||
|
v-for="op in combineRecommendJobFilterTypeOptions"
|
||||||
|
:key="op.value"
|
||||||
|
:value="op.value"
|
||||||
|
:label="op.name"
|
||||||
|
>{{ op.name }}</el-option
|
||||||
|
>
|
||||||
|
</el-select>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="
|
||||||
|
formContent.combineRecommendJobFilterType ===
|
||||||
|
CombineRecommendJobFilterType.STATIC_COMBINE
|
||||||
|
"
|
||||||
|
mt8px
|
||||||
|
>
|
||||||
|
<StaticCombineBossRecommendFilter
|
||||||
|
v-model="formContent.staticCombineRecommendJobFilterConditions"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div v-else mt8px>
|
||||||
|
<AnyCombineBossRecommendFilter
|
||||||
|
v-model="formContent.anyCombineRecommendJobFilter"
|
||||||
|
/>
|
||||||
|
<div mb0>
|
||||||
|
<el-checkbox
|
||||||
|
v-if="anyCombineBossRecommendFilterHasCondition"
|
||||||
|
v-model="formContent.isSkipEmptyConditionForCombineRecommendJobFilter"
|
||||||
|
@change="
|
||||||
|
(v) => {
|
||||||
|
gtagRenderer('is_skip_empty_condition_4crjf_changed', { v })
|
||||||
|
}
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<span font-size-12px>跳过初始空条件,直接使用设置的条件查找职位</span>
|
||||||
|
</el-checkbox>
|
||||||
|
<el-checkbox v-else :model-value="false" disabled>
|
||||||
|
<span font-size-12px>跳过初始空条件,直接使用设置的条件查找职位</span>
|
||||||
|
</el-checkbox>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div font-size-12px>
|
||||||
|
当前组合条件数:{{
|
||||||
|
currentAnyCombineRecommendJobFilterCombinationCount.toLocaleString()
|
||||||
|
}}
|
||||||
|
<span
|
||||||
|
v-if="currentAnyCombineRecommendJobFilterCombinationCount >= 5"
|
||||||
|
class="color-orange"
|
||||||
|
>不建议选择太多组合条件 -
|
||||||
|
否则将在当前职位中尝试太多筛选条件,不能及时进入下一个职位,且会增加命中风控的概率</span
|
||||||
|
>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<AnyCombineBossRecommendFilter v-model="formContent.anyCombineRecommendJobFilter" />
|
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item prop="filter" mb0>
|
|
||||||
<el-checkbox
|
|
||||||
v-if="anyCombineBossRecommendFilterHasCondition"
|
|
||||||
v-model="formContent.isSkipEmptyConditionForCombineRecommendJobFilter"
|
|
||||||
@change="
|
|
||||||
(v) => {
|
|
||||||
gtagRenderer('is_skip_empty_condition_4crjf_changed', { v })
|
|
||||||
}
|
|
||||||
"
|
|
||||||
>
|
|
||||||
<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 >= 5"
|
|
||||||
class="color-orange"
|
|
||||||
>不建议选择太多组合条件 -
|
|
||||||
否则将在当前职位中尝试太多筛选条件,不能及时进入下一个职位,且会增加命中风控的概率</span
|
|
||||||
>
|
|
||||||
</div>
|
|
||||||
</el-card>
|
</el-card>
|
||||||
<!-- <el-form-item
|
<!-- <el-form-item
|
||||||
label="钉钉机器人 AccessToken(用于记录开聊,请勿使用公司内部群)"
|
label="钉钉机器人 AccessToken(用于记录开聊,请勿使用公司内部群)"
|
||||||
@@ -926,15 +965,18 @@ import { ElForm, ElMessage } from 'element-plus'
|
|||||||
import { QuestionFilled } from '@element-plus/icons-vue'
|
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 StaticCombineBossRecommendFilter from '@renderer/features/StaticCombineBossRecommendFilter/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 {
|
import {
|
||||||
calculateTotalCombinations,
|
calculateTotalCombinations,
|
||||||
checkAnyCombineBossRecommendFilterHasCondition
|
checkAnyCombineBossRecommendFilterHasCondition,
|
||||||
|
formatStaticCombineFilters
|
||||||
} from '@geekgeekrun/geek-auto-start-chat-with-boss/combineCalculator.mjs'
|
} from '@geekgeekrun/geek-auto-start-chat-with-boss/combineCalculator.mjs'
|
||||||
import { gtagRenderer as baseGtagRenderer } from '@renderer/utils/gtag'
|
import { gtagRenderer as baseGtagRenderer } 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'
|
||||||
import {
|
import {
|
||||||
|
CombineRecommendJobFilterType,
|
||||||
MarkAsNotSuitOp,
|
MarkAsNotSuitOp,
|
||||||
StrategyScopeOptionWhenMarkJobNotMatch,
|
StrategyScopeOptionWhenMarkJobNotMatch,
|
||||||
SalaryCalculateWay,
|
SalaryCalculateWay,
|
||||||
@@ -960,6 +1002,8 @@ const formContent = ref({
|
|||||||
dingtalkRobotAccessToken: '',
|
dingtalkRobotAccessToken: '',
|
||||||
expectCompanies: '',
|
expectCompanies: '',
|
||||||
anyCombineRecommendJobFilter: {},
|
anyCombineRecommendJobFilter: {},
|
||||||
|
combineRecommendJobFilterType: 1,
|
||||||
|
staticCombineRecommendJobFilterConditions: [],
|
||||||
expectJobNameRegExpStr: '',
|
expectJobNameRegExpStr: '',
|
||||||
expectJobTypeRegExpStr: '',
|
expectJobTypeRegExpStr: '',
|
||||||
expectJobDescRegExpStr: '',
|
expectJobDescRegExpStr: '',
|
||||||
@@ -1001,6 +1045,16 @@ const anyCombineBossRecommendFilterHasCondition = computed(() => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const currentAnyCombineRecommendJobFilterCombinationCount = computed(() => {
|
const currentAnyCombineRecommendJobFilterCombinationCount = computed(() => {
|
||||||
|
if (
|
||||||
|
formContent.value.combineRecommendJobFilterType === CombineRecommendJobFilterType.STATIC_COMBINE
|
||||||
|
) {
|
||||||
|
if (!formContent.value.staticCombineRecommendJobFilterConditions?.length) {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return formatStaticCombineFilters(
|
||||||
|
formContent.value.staticCombineRecommendJobFilterConditions
|
||||||
|
)?.filter(Boolean).length
|
||||||
|
}
|
||||||
return calculateTotalCombinations(
|
return calculateTotalCombinations(
|
||||||
formContent.value.anyCombineRecommendJobFilter,
|
formContent.value.anyCombineRecommendJobFilter,
|
||||||
anyCombineBossRecommendFilterHasCondition.value
|
anyCombineBossRecommendFilterHasCondition.value
|
||||||
@@ -1047,6 +1101,12 @@ electron.ipcRenderer.invoke('fetch-config-file-content').then((res) => {
|
|||||||
deep: true
|
deep: true
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
formContent.value.combineRecommendJobFilterType =
|
||||||
|
res.config['boss.json']?.combineRecommendJobFilterType ?? 1
|
||||||
|
formContent.value.staticCombineRecommendJobFilterConditions = res.config['boss.json']
|
||||||
|
?.staticCombineRecommendJobFilterConditions?.length
|
||||||
|
? res.config['boss.json'].staticCombineRecommendJobFilterConditions
|
||||||
|
: []
|
||||||
if (
|
if (
|
||||||
res.config['boss.json']?.expectJobRegExpStr &&
|
res.config['boss.json']?.expectJobRegExpStr &&
|
||||||
typeof res.config['boss.json']?.expectJobNameRegExpStr === 'undefined' &&
|
typeof res.config['boss.json']?.expectJobNameRegExpStr === 'undefined' &&
|
||||||
@@ -1128,6 +1188,7 @@ const jobSourceFormItemSectionEl = ref()
|
|||||||
const jobDetailRegExpSectionEl = ref()
|
const jobDetailRegExpSectionEl = ref()
|
||||||
const formRules = {
|
const formRules = {
|
||||||
expectJobNameRegExpStr: {
|
expectJobNameRegExpStr: {
|
||||||
|
trigger: 'blur',
|
||||||
validator(_, value, cb) {
|
validator(_, value, cb) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
cb()
|
cb()
|
||||||
@@ -1136,16 +1197,17 @@ const formRules = {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
new RegExp(value, 'ig')
|
new RegExp(value, 'ig')
|
||||||
gtagRenderer('valid_reg_exp_for_expect_job_name')
|
gtagRenderer('valid_reg_exp_for_expect_job_name', { v: value })
|
||||||
cb()
|
cb()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
cb(new Error(`正则无效:${err?.message}`))
|
cb(new Error(`正则无效:${err?.message}`))
|
||||||
jobDetailRegExpSectionEl.value?.scrollIntoViewIfNeeded()
|
jobDetailRegExpSectionEl.value?.scrollIntoViewIfNeeded()
|
||||||
gtagRenderer('invalid_reg_exp_for_expect_job_name')
|
gtagRenderer('invalid_reg_exp_for_expect_job_name', { v: value })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
expectJobTypeRegExpStr: {
|
expectJobTypeRegExpStr: {
|
||||||
|
trigger: 'blur',
|
||||||
validator(_, value, cb) {
|
validator(_, value, cb) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
cb()
|
cb()
|
||||||
@@ -1154,16 +1216,17 @@ const formRules = {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
new RegExp(value, 'ig')
|
new RegExp(value, 'ig')
|
||||||
gtagRenderer('valid_reg_exp_for_expect_job_type')
|
gtagRenderer('valid_reg_exp_for_expect_job_type', { v: value })
|
||||||
cb()
|
cb()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
cb(new Error(`正则无效:${err?.message}`))
|
cb(new Error(`正则无效:${err?.message}`))
|
||||||
jobDetailRegExpSectionEl.value?.scrollIntoViewIfNeeded()
|
jobDetailRegExpSectionEl.value?.scrollIntoViewIfNeeded()
|
||||||
gtagRenderer('invalid_reg_exp_for_expect_job_type')
|
gtagRenderer('invalid_reg_exp_for_expect_job_type', { v: value })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
expectJobDescRegExpStr: {
|
expectJobDescRegExpStr: {
|
||||||
|
trigger: 'blur',
|
||||||
validator(_, value, cb) {
|
validator(_, value, cb) {
|
||||||
if (!value) {
|
if (!value) {
|
||||||
cb()
|
cb()
|
||||||
@@ -1172,12 +1235,12 @@ const formRules = {
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
new RegExp(value, 'ig')
|
new RegExp(value, 'ig')
|
||||||
gtagRenderer('valid_reg_exp_for_expect_job_desc')
|
gtagRenderer('valid_reg_exp_for_expect_job_desc', { v: value })
|
||||||
cb()
|
cb()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
cb(new Error(`正则无效:${err?.message}`))
|
cb(new Error(`正则无效:${err?.message}`))
|
||||||
jobDetailRegExpSectionEl.value?.scrollIntoViewIfNeeded()
|
jobDetailRegExpSectionEl.value?.scrollIntoViewIfNeeded()
|
||||||
gtagRenderer('invalid_reg_exp_for_expect_job_desc')
|
gtagRenderer('invalid_reg_exp_for_expect_job_desc', { v: value })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -1217,8 +1280,14 @@ const formRules = {
|
|||||||
const formRef = ref<InstanceType<typeof ElForm>>()
|
const formRef = ref<InstanceType<typeof ElForm>>()
|
||||||
const handleSubmit = async () => {
|
const handleSubmit = async () => {
|
||||||
gtagRenderer('save_config_and_launch_clicked', {
|
gtagRenderer('save_config_and_launch_clicked', {
|
||||||
has_dingtalk_robot_token: !!formContent.value?.dingtalkRobotAccessToken
|
has_dingtalk_robot_token: !!formContent.value?.dingtalkRobotAccessToken,
|
||||||
|
expect_job_name_reg_exp_str: formContent.value?.expectJobNameRegExpStr,
|
||||||
|
expect_job_type_reg_exp_str: formContent.value?.expectJobTypeRegExpStr,
|
||||||
|
expect_job_desc_reg_exp_str: formContent.value?.expectJobDescRegExpStr,
|
||||||
|
crjf_type: formContent.value?.combineRecommendJobFilterType,
|
||||||
|
crjf_cc: currentAnyCombineRecommendJobFilterCombinationCount.value?.toLocaleString?.()
|
||||||
})
|
})
|
||||||
|
// remove the obsolete filter - expectJobRegExpStr
|
||||||
formContent.value.expectJobRegExpStr = undefined
|
formContent.value.expectJobRegExpStr = undefined
|
||||||
try {
|
try {
|
||||||
await formRef.value!.validate()
|
await formRef.value!.validate()
|
||||||
@@ -1574,6 +1643,17 @@ function formatJobSourceFormValueToConfig(formValue = []) {
|
|||||||
return it
|
return it
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const combineRecommendJobFilterTypeOptions = [
|
||||||
|
{
|
||||||
|
name: '使用自由组合条件进行遍历',
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: '使用固定组合条件进行遍历',
|
||||||
|
value: 2
|
||||||
|
}
|
||||||
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped lang="scss">
|
<style scoped lang="scss">
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="flex h100vh">
|
<div class="flex h100vh">
|
||||||
<div class="flex flex-col w200px pt30px pl30px aside-nav of-hidden">
|
<div class="flex flex-col min-w200px w200px pt30px pl30px aside-nav of-hidden">
|
||||||
<div class="nav-list flex-1 of-auto">
|
<div class="nav-list flex-1 of-auto">
|
||||||
<RouterLink to="./GeekAutoStartChatWithBoss">
|
<RouterLink to="./GeekAutoStartChatWithBoss">
|
||||||
Boss炸弹
|
Boss炸弹
|
||||||
|
|||||||
Reference in New Issue
Block a user