Merge branch 'feature/ui'

This commit is contained in:
geekgeekrun
2025-06-08 10:22:48 +08:00
9 changed files with 923 additions and 214 deletions

View File

@@ -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

View File

@@ -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 {
@@ -16,3 +18,8 @@ export enum StrategyScopeOptionWhenMarkJobNotMatch {
ALL_JOB = 1,
ONLY_COMPANY_MATCHED_JOB = 2
}
export enum SalaryCalculateWay {
MONTH_SALARY = 1,
ANNUAL_PACKAGE = 2,
}

View File

@@ -66,7 +66,7 @@
"electron": "28.2.0",
"electron-builder": "^24.9.1",
"electron-vite": "^2.0.0",
"element-plus": "^2.5.5",
"element-plus": "^2.8.4",
"eslint": "^8.56.0",
"eslint-plugin-vue": "^9.20.1",
"find-chrome-bin": "^2.0.1",

View File

@@ -107,6 +107,8 @@ export default function initIpc() {
if (hasOwn(payload, 'autoReminder')) {
bossConfig.autoReminder = payload.autoReminder
}
// city
if (hasOwn(payload, 'expectCityList')) {
bossConfig.expectCityList = payload.expectCityList
}
@@ -117,6 +119,37 @@ export default function initIpc() {
bossConfig.strategyScopeOptionWhenMarkJobCityNotMatch =
payload.strategyScopeOptionWhenMarkJobCityNotMatch
}
// salary
if (hasOwn(payload, 'expectSalaryCalculateWay')) {
bossConfig.expectSalaryCalculateWay = payload.expectSalaryCalculateWay
}
if (hasOwn(payload, 'expectSalaryNotMatchStrategy')) {
bossConfig.expectSalaryNotMatchStrategy = payload.expectSalaryNotMatchStrategy
}
if (hasOwn(payload, 'strategyScopeOptionWhenMarkSalaryNotMatch')) {
bossConfig.strategyScopeOptionWhenMarkSalaryNotMatch =
payload.strategyScopeOptionWhenMarkSalaryNotMatch
}
if (hasOwn(payload, 'expectSalaryLow')) {
bossConfig.expectSalaryLow = payload.expectSalaryLow
}
if (hasOwn(payload, 'expectSalaryHigh')) {
bossConfig.expectSalaryHigh = payload.expectSalaryHigh
}
// work exp
if (hasOwn(payload, 'expectWorkExpList')) {
bossConfig.expectWorkExpList = payload.expectWorkExpList
}
if (hasOwn(payload, 'expectWorkExpNotMatchStrategy')) {
bossConfig.expectWorkExpNotMatchStrategy = payload.expectWorkExpNotMatchStrategy
}
if (hasOwn(payload, 'strategyScopeOptionWhenMarkJobWorkExpNotMatch')) {
bossConfig.strategyScopeOptionWhenMarkJobWorkExpNotMatch =
payload.strategyScopeOptionWhenMarkJobWorkExpNotMatch
}
promiseArr.push(writeConfigFile('boss.json', bossConfig))
if (hasOwn(payload, 'expectCompanies')) {

View File

@@ -10,7 +10,7 @@ export function createMainWindow(): BrowserWindow {
mainWindow = new BrowserWindow({
width: 1280,
height: 720,
minWidth: 1024,
minWidth: 1280,
show: false,
autoHideMenuBar: true,
...(process.platform === 'linux'

View File

@@ -11,8 +11,23 @@
<div v-else>
<div>当前未选择任何期望城市将不会按照城市进行筛选</div>
</div>
<div>
<el-button size="small" type="primary" @click="isDialogVisible = true">选择城市</el-button>
<div
line-height-1
:style="{
marginTop: modelValue?.length ? '10px' : ''
}"
>
<el-button
size="small"
type="primary"
@click="
() => {
isDialogVisible = true
gtagRenderer('choose_city_entry_button_clicked')
}
"
>选择城市</el-button
>
<el-button
v-if="modelValue?.length"
size="small"
@@ -105,6 +120,7 @@
<script lang="ts" setup>
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')
}
</script>

View File

@@ -38,7 +38,7 @@
}"
>
<div>
期望公司白名单以逗号分隔不区分大小写输入框留空表示不筛选<el-tooltip
公司白名单以逗号分隔不区分大小写输入框留空表示不筛选<el-tooltip
effect="light"
placement="bottom-start"
@show="gtagRenderer('tooltip_show_about_expect_company_figure')"
@@ -47,14 +47,13 @@
<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
>期望公司信息位置图示</el-button
><span><QuestionFilled w-1em h-1em mr2px /></span>公司信息UI位置图示</el-button
>
</el-tooltip>
</div>
<el-dropdown @command="handleExpectCompanyTemplateClicked">
<el-button size="small"
>期望公司模板 <el-icon class="el-icon--right"><arrow-down /></el-icon
>公司列表模板 <el-icon class="el-icon--right"><arrow-down /></el-icon
></el-button>
<template #dropdown>
<el-dropdown-menu>
@@ -76,22 +75,9 @@
@blur="normalizeExpectCompanies"
/>
</el-form-item>
<!-- <el-form-item prop="expectSalary" mb10px>
<div
font-size-12px
:style="{
justifyContent: 'space-between',
alignItems: 'center',
width: '100%'
}"
>
<div>期望薪资范围 k 为单位</div>
<el-input />
</div>
</el-form-item> -->
<div class="h-1px bg-#f0f0f0" mt16px mb16px />
<div mt16px>
<div font-size-14px>期望工作地</div>
<div font-size-14px mb8px>工作地</div>
<div
:style="{
display: 'flex',
@@ -114,16 +100,10 @@
<div
v-if="formContent.expectCityList?.length"
:style="{
backgroundColor: '#f0f0f0',
width: '1px'
}"
></div>
<div
v-if="formContent.expectCityList?.length"
prop="expectCityList"
:style="{
flex: 1,
minWidth: '400px'
width: '400px',
borderLeft: '1px solid #f0f0f0',
paddingLeft: '10px',
flex: `0 0 auto`
}"
>
<el-form-item
@@ -132,7 +112,7 @@
width: '100%'
}"
>
<div font-size-12px>当前职位工作地与期望工作地不匹配时</div>
<div font-size-12px>当前职位工作地与选择的工作地不匹配时</div>
<el-select
v-model="formContent.expectCityNotMatchStrategy"
@change="
@@ -178,34 +158,340 @@
</el-form-item>
</div>
</div>
<el-tooltip
effect="light"
placement="bottom-start"
@show="gtagRenderer('tooltip_show_about_wrongly_mark_not_suit')"
</div>
<div class="h-1px bg-#f0f0f0" mt16px mb16px />
<div mt16px>
<div font-size-14px mb8px>
薪资(仅支持按月计算薪资的职位;非按月计算薪资职位(例如兼职职位、实习职位)将直接跳过)
</div>
<div
:style="{
display: 'flex',
justifyContent: 'space-between',
gap: '10px'
}"
>
<template #content>
<ul m0 line-height-1.5em w-400px pl2em>
<li>
如有错误标记,请在左侧“<a
href="javascript:void(0)"
style="color: var(--el-color-primary)"
@click.prevent="
() => {
gtagRenderer('click_view_mansr_from_boss_b_tooltip')
$router.push('/main-layout/MarkAsNotSuitRecord')
}
"
>标记不合适</a
>”记录中找到相关记录,来查看职位详情,或手动对这些职位发起会话
</li>
</ul>
</template>
<el-button type="text" font-size-12px
><span><QuestionFilled w-1em h-1em mr2px /></span
>职位被错误标记不合适时如何处理?</el-button
<div>
<el-form-item prop="expectSalaryLow" mb10px>
<div w-full>
<div font-size-12px>薪资筛选方式</div>
<el-select
v-model="formContent.expectSalaryCalculateWay"
@change="handleExpectSalaryCalculateWayChanged"
>
<el-option
v-for="op in expectSalaryCalculateWayOption"
:key="op.value"
:label="op.name"
:value="op.value"
>{{ op.name }}</el-option
>
</el-select>
</div>
</el-form-item>
<el-form-item prop="expectSalaryLow" mb10px>
<div>
<div font-size-12px>期望薪资范围</div>
<div>
<el-input-number
v-model="formContent.expectSalaryLow"
controls-position="right"
:min="0"
:step="0.25"
placeholder="不设置"
@change="
() => {
gtagRenderer('expect_salary_low_changed')
ensureSalaryRangeCorrect()
}
"
>
<template #prefix>下限</template>
<template #suffix>
<template v-if="formContent.expectSalaryLow">
<template
v-if="
formContent.expectSalaryCalculateWay ===
SalaryCalculateWay.MONTH_SALARY
"
>k</template
>
<template
v-if="
formContent.expectSalaryCalculateWay ===
SalaryCalculateWay.ANNUAL_PACKAGE
"
>W</template
>
</template>
</template>
</el-input-number>
-
<el-input-number
v-model="formContent.expectSalaryHigh"
controls-position="right"
:min="0"
:step="0.25"
placeholder="不设置"
@change="
() => {
gtagRenderer('expect_salary_high_changed')
ensureSalaryRangeCorrect()
}
"
>
<template #prefix>上限</template>
<template #suffix>
<template v-if="formContent.expectSalaryHigh">
<template
v-if="
formContent.expectSalaryCalculateWay ===
SalaryCalculateWay.MONTH_SALARY
"
>k</template
>
<template
v-if="
formContent.expectSalaryCalculateWay ===
SalaryCalculateWay.ANNUAL_PACKAGE
"
>W</template
>
</template>
</template>
</el-input-number>
</div>
</div>
</el-form-item>
<el-form-item
v-if="
formContent.expectSalaryCalculateWay === SalaryCalculateWay.ANNUAL_PACKAGE &&
(formContent.expectSalaryLow || formContent.expectSalaryHigh)
"
mb10px
>
<div>
<div font-size-12px>薪资范围满足以下条件的职位将会被匹配</div>
<div>
<div flex flex-nowrap flex-items-start>
<template
v-for="(mGroup, index) in [
[12, 13, 14, 15, 16, 17, 18],
[19, 20, 21, 22, 23, 24]
]"
:key="index"
>
<table
:style="{
lineHeight: '1.25em'
}"
>
<tr>
<th
v-for="(text, i) in ['月薪下限', '月薪上限', '']"
:key="i"
:style="{
borderBottom: '2px solid #f0f0f0'
}"
>
{{ text }}
</th>
</tr>
<tr v-for="m in mGroup" :key="m">
<td>
{{
formContent.expectSalaryLow
? ((formContent.expectSalaryLow / m) * 10).toFixed(2)
: '无下限'
}}<small
v-if="formContent.expectSalaryLow"
class="color-#999 ml-2px"
>k</small
>
</td>
<td>
{{
formContent.expectSalaryHigh
? ((formContent.expectSalaryHigh / m) * 10).toFixed(2)
: '无上限'
}}<small
v-if="formContent.expectSalaryHigh"
class="color-#999 ml-2px"
>k</small
>
</td>
<td>{{ m }}薪</td>
</tr>
</table>
<div v-if="index !== 1" class="bg-#f0f0f0 w-2px flex-self-stretch"></div>
</template>
</div>
</div>
</div>
</el-form-item>
</div>
<div
v-if="isShowSalaryMarkAsNotSuitStrategy"
:style="{
width: '400px',
borderLeft: '1px solid #f0f0f0',
paddingLeft: '10px',
flex: `0 0 auto`
}"
>
</el-tooltip>
<el-form-item
mb10px
:style="{
width: '100%'
}"
>
<div font-size-12px>当前职位薪资{{ salaryMarkAsNotSuitLabelText }}时:</div>
<el-select
v-model="formContent.expectSalaryNotMatchStrategy"
@change="
(value) => gtagRenderer('expect_salary_not_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>
<el-form-item
v-if="
[
MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS,
MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL
].includes(formContent.expectSalaryNotMatchStrategy)
"
mb0
:style="{
width: '100%'
}"
>
<div font-size-12px>标记不合适针对的职位范围:</div>
<el-select
v-model="formContent.strategyScopeOptionWhenMarkSalaryNotMatch"
@change="
(value) => gtagRenderer('strategy_scope_option_wmjsnm_changed', { value })
"
>
<el-option
v-for="op in strategyScopeOptionWhenMarkJobNotMatch"
:key="op.value"
:label="op.name"
:value="op.value"
>{{ op.name }}</el-option
>
</el-select>
</el-form-item>
</div>
</div>
</div>
<div class="h-1px bg-#f0f0f0" mt16px mb16px />
<div mt16px>
<div font-size-14px mb8px>工作经验(暂不支持按日计算薪资的实习类职位)</div>
<div
:style="{
display: 'flex',
justifyContent: 'space-between',
gap: '10px'
}"
>
<el-form-item prop="expectWorkExpList" mb0>
<div font-size-12px>认为匹配的工作经验</div>
<div
font-size-12px
:style="{
justifyContent: 'space-between',
alignItems: 'center',
width: '100%'
}"
>
<el-select
v-model="formContent.expectWorkExpList"
multiple
placeholder="不限制,都匹配"
@change="(value) => gtagRenderer('expect_work_exp_list_changed', { value })"
>
<template v-for="op in conditions.experienceList" :key="op.code">
<el-option
v-if="!!op.code"
:label="op.name"
:value="op.name"
:disabled="op.code === 108 || op.name === '在校生'"
>
{{ op.name }}</el-option
>
</template>
</el-select>
</div>
</el-form-item>
<div
v-if="formContent.expectWorkExpList?.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.expectWorkExpNotMatchStrategy"
@change="
(value) => gtagRenderer('expect_we_not_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>
<el-form-item
v-if="
[
MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS,
MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL
].includes(formContent.expectWorkExpNotMatchStrategy)
"
mb0
:style="{
width: '100%'
}"
>
<div font-size-12px>标记不合适针对的职位范围:</div>
<el-select
v-model="formContent.strategyScopeOptionWhenMarkJobWorkExpNotMatch"
@change="
(value) => gtagRenderer('strategy_scope_option_wmjwenm_changed', { value })
"
>
<el-option
v-for="op in strategyScopeOptionWhenMarkJobNotMatch"
:key="op.value"
:label="op.name"
:value="op.value"
>{{ op.name }}</el-option
>
</el-select>
</el-form-item>
</div>
</div>
</div>
</el-card>
<el-card class="config-section">
@@ -319,7 +605,7 @@
"
/>
</el-form-item>
<div mb10px font-size-12px flex flex-justify-center>且</div>
<div mb10px font-size-12px flex flex-justify-center fw-800>且</div>
<el-form-item mb0 prop="expectJobTypeRegExpStr">
<div font-size-12px>职位类型正则(推荐填写,不区分大小写)</div>
<el-input
@@ -331,7 +617,7 @@
"
/>
</el-form-item>
<div mb10px font-size-12px flex flex-justify-center>且</div>
<div mb10px font-size-12px flex flex-justify-center fw-800>且</div>
<el-form-item mb0 prop="expectJobDescRegExpStr">
<div font-size-12px>职位描述正则(不区分大小写)</div>
<el-input
@@ -344,32 +630,42 @@
/>
</el-form-item>
</div>
<div class="mt10px lh-2em font-size-12px">当前职位名称/类型/描述不符合投递条件时:</div>
<div
:style="{
display: 'grid',
gridTemplateColumns: '1.25fr 0.75fr',
gap: '10px 0',
width: '100%',
alignItems: 'end'
}"
<template
v-if="
formContent.expectJobNameRegExpStr?.trim() ||
formContent.expectJobTypeRegExpStr?.trim() ||
formContent.expectJobDescRegExpStr?.trim()
"
>
<el-form-item mb0>
<el-select
v-model="formContent.jobNotMatchStrategy"
@change="(value) => gtagRenderer('job_not_match_strategy_changed', { value })"
>
<el-option
v-for="op in strategyOptionWhenCurrentJobNotMatch"
:key="op.value"
:label="op.name"
:value="op.value"
>{{ op.name }}</el-option
<div class="mt10px lh-2em font-size-12px">
当前职位名称/类型/描述不符合投递条件时:
</div>
<div
:style="{
display: 'grid',
gridTemplateColumns: '1.25fr 0.75fr',
gap: '10px 0',
width: '100%',
alignItems: 'end'
}"
>
<el-form-item mb0>
<el-select
v-model="formContent.jobNotMatchStrategy"
@change="(value) => gtagRenderer('job_not_match_strategy_changed', { value })"
>
</el-select>
</el-form-item>
<div />
</div>
<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>
</template>
</div>
<div class="h-1px bg-#f0f0f0" mt16px mb16px />
<div mt16px>
@@ -475,7 +771,7 @@
</template>
<script setup lang="ts">
import { computed, onBeforeUnmount, ref, watch } from 'vue'
import { computed, onBeforeUnmount, ref, watch, nextTick } from 'vue'
import { ElForm, ElMessage } from 'element-plus'
import { QuestionFilled } from '@element-plus/icons-vue'
import { useRouter } from 'vue-router'
@@ -487,11 +783,13 @@ import defaultTargetCompanyListConf from '@geekgeekrun/geek-auto-start-chat-with
import { ArrowDown } from '@element-plus/icons-vue'
import {
MarkAsNotSuitOp,
StrategyScopeOptionWhenMarkJobNotMatch
StrategyScopeOptionWhenMarkJobNotMatch,
SalaryCalculateWay
} from '@geekgeekrun/sqlite-plugin/src/enums'
import { debounce } from 'lodash-es'
import mittBus from '../../../utils/mitt'
import CityChooser from './components/CityChooser.vue'
import conditions from '@geekgeekrun/geek-auto-start-chat-with-boss/internal-config/job-filter-conditions-20241002.json'
const router = useRouter()
@@ -505,9 +803,22 @@ const formContent = ref({
jobNotMatchStrategy: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS,
jobNotActiveStrategy: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS,
markAsNotActiveSelectedTimeRange: 7,
// city
expectCityList: [],
expectCityNotMatchStrategy: MarkAsNotSuitOp.NO_OP,
strategyScopeOptionWhenMarkJobCityNotMatch:
StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB,
// salary
expectSalaryCalculateWay: SalaryCalculateWay.MONTH_SALARY,
expectSalaryNotMatchStrategy: MarkAsNotSuitOp.NO_OP,
strategyScopeOptionWhenMarkSalaryNotMatch:
StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB,
expectSalaryLow: null,
expectSalaryHigh: null,
// work exp
expectWorkExpList: [],
expectWorkExpNotMatchStrategy: MarkAsNotSuitOp.NO_OP,
strategyScopeOptionWhenMarkJobWorkExpNotMatch:
StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB
})
@@ -571,6 +882,7 @@ electron.ipcRenderer.invoke('fetch-config-file-content').then((res) => {
? res.config['boss.json'].jobNotActiveStrategy
: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
// city
formContent.value.expectCityList = res.config['boss.json']?.expectCityList ?? []
formContent.value.expectCityNotMatchStrategy = strategyOptionWhenCurrentJobNotMatch
.map((it) => it.value)
@@ -580,6 +892,33 @@ electron.ipcRenderer.invoke('fetch-config-file-content').then((res) => {
formContent.value.strategyScopeOptionWhenMarkJobCityNotMatch =
res.config['boss.json']?.strategyScopeOptionWhenMarkJobCityNotMatch ??
StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB
// salary
formContent.value.expectSalaryCalculateWay =
res.config['boss.json'].expectSalaryCalculateWay ?? SalaryCalculateWay.MONTH_SALARY
formContent.value.expectSalaryNotMatchStrategy =
res.config['boss.json'].expectSalaryNotMatchStrategy ?? MarkAsNotSuitOp.NO_OP
formContent.value.strategyScopeOptionWhenMarkSalaryNotMatch =
res.config['boss.json'].strategyScopeOptionWhenMarkSalaryNotMatch ??
StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB
formContent.value.expectSalaryLow = parseFloat(res.config['boss.json'].expectSalaryLow) || null
formContent.value.expectSalaryHigh = parseFloat(res.config['boss.json'].expectSalaryHigh) || null
ensureSalaryRangeCorrect()
// work exp
formContent.value.expectWorkExpList =
Array.isArray(res.config['boss.json'].expectWorkExpList) &&
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 =
res.config['boss.json'].strategyScopeOptionWhenMarkJobWorkExpNotMatch ??
StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB
})
const formRules = {
@@ -809,11 +1148,104 @@ const strategyScopeOptionWhenMarkJobNotMatch = [
value: StrategyScopeOptionWhenMarkJobNotMatch.ALL_JOB
},
{
name: '仅和“期望公司白名单”匹配的职位',
name: '仅和“公司白名单”匹配的职位',
value: StrategyScopeOptionWhenMarkJobNotMatch.ONLY_COMPANY_MATCHED_JOB
}
]
async function handleExpectSalaryCalculateWayChanged(value) {
gtagRenderer('expect_salary_calculate_way_changed', { value })
await nextTick()
// convert annual package to month salary as 12-month
if (value === SalaryCalculateWay.MONTH_SALARY) {
if (formContent.value.expectSalaryHigh) {
formContent.value.expectSalaryHigh = Number(
((formContent.value.expectSalaryHigh * 10) / 12).toFixed(2)
)
}
if (formContent.value.expectSalaryLow) {
formContent.value.expectSalaryLow = Number(
((formContent.value.expectSalaryLow * 10) / 12).toFixed(2)
)
}
return
}
// convert month salary to annual package as 12-month
else if (value === SalaryCalculateWay.ANNUAL_PACKAGE) {
if (formContent.value.expectSalaryHigh) {
formContent.value.expectSalaryHigh = Number(
((formContent.value.expectSalaryHigh / 10) * 12).toFixed(2)
)
}
if (formContent.value.expectSalaryLow) {
formContent.value.expectSalaryLow = Number(
((formContent.value.expectSalaryLow / 10) * 12).toFixed(2)
)
}
return
}
}
const expectSalaryCalculateWayOption = [
{
name: '月薪(单位为 千元 - 即“k”',
value: SalaryCalculateWay.MONTH_SALARY
},
{
name: '“年包”(单位为 万元 - 即“W”',
value: SalaryCalculateWay.ANNUAL_PACKAGE
}
]
const salaryMarkAsNotSuitLabelText = computed(() => {
const textSeg = []
if (formContent.value.expectSalaryLow) {
textSeg.push('低于期望薪资下限')
}
if (formContent.value.expectSalaryHigh) {
textSeg.push('高于期望薪资上限')
}
return textSeg.join(' / ')
})
const isShowSalaryMarkAsNotSuitStrategy = computed(() => {
let flag = formContent.value.expectSalaryHigh || formContent.value.expectSalaryLow
if (
formContent.value.expectSalaryHigh &&
formContent.value.expectSalaryLow &&
formContent.value.expectSalaryHigh < formContent.value.expectSalaryLow
) {
flag = false
}
return flag
})
function ensureSalaryRangeCorrect() {
if (
!formContent.value.expectSalaryHigh ||
isNaN(parseFloat(formContent.value.expectSalaryHigh))
) {
formContent.value.expectSalaryHigh = null
} else {
formContent.value.expectSalaryHigh = parseFloat(formContent.value.expectSalaryHigh.toFixed(2))
}
if (!formContent.value.expectSalaryLow || isNaN(parseFloat(formContent.value.expectSalaryLow))) {
formContent.value.expectSalaryLow = null
} else {
formContent.value.expectSalaryLow = parseFloat(formContent.value.expectSalaryLow.toFixed(2))
}
if (
formContent.value.expectSalaryLow &&
formContent.value.expectSalaryHigh &&
formContent.value.expectSalaryLow > formContent.value.expectSalaryHigh
) {
formContent.value.expectSalaryHigh = formContent.value.expectSalaryLow
}
}
const noActiveDefinitionMarks = computed(() => {
let arr = [...activeDescList]
arr.shift()

View File

@@ -42,6 +42,14 @@
<strong>{{ markReasonTopicMap[row.markReason] }}</strong>
<pre class="m-0 of-auto">{{ formatMarkReason(row) }}</pre>
</template>
<template v-if="row.markReason === MarkAsNotSuitReason.JOB_WORK_EXP_NOT_SUIT">
<strong>{{ markReasonTopicMap[row.markReason] }}</strong>
<pre class="m-0 of-auto">{{ formatMarkReason(row) }}</pre>
</template>
<template v-if="row.markReason === MarkAsNotSuitReason.JOB_SALARY_NOT_SUIT">
<strong>{{ markReasonTopicMap[row.markReason] }}</strong>
<pre class="m-0 of-auto">{{ formatMarkReason(row) }}</pre>
</template>
</template>
</ElTableColumn>
<ElTableColumn prop="experienceName" label="工作经验" />
@@ -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 ''
}

15
pnpm-lock.yaml generated
View File

@@ -209,8 +209,8 @@ importers:
specifier: ^2.0.0
version: 2.0.0(vite@5.1.1)
element-plus:
specifier: ^2.5.5
version: 2.5.5(vue@3.4.15)
specifier: ^2.8.4
version: 2.8.4(vue@3.4.15)
eslint:
specifier: ^8.56.0
version: 8.56.0
@@ -3085,6 +3085,11 @@ packages:
/dayjs@1.11.10:
resolution: {integrity: sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==}
dev: false
/dayjs@1.11.13:
resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==}
dev: true
/de-indent@1.0.2:
resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==}
@@ -3360,8 +3365,8 @@ packages:
transitivePeerDependencies:
- supports-color
/element-plus@2.5.5(vue@3.4.15):
resolution: {integrity: sha512-yGU/MruLOWI0ImQPFCyFM4cXtHtILJNAi0hhLImcxjRukjgQLYNkvcvbwqNgBUt808KSeKF9MyxENFyBQLTg+Q==}
/element-plus@2.8.4(vue@3.4.15):
resolution: {integrity: sha512-ZlVAdUOoJliv4kW3ntWnnSHMT+u/Os7mXJjk2xzOlqNeHaI2/ozlF+R58ZCEak8ZnDi6+5A2viWEYRsq64IuiA==}
peerDependencies:
vue: ^3.2.0
dependencies:
@@ -3373,7 +3378,7 @@ packages:
'@types/lodash-es': 4.17.12
'@vueuse/core': 9.13.0(vue@3.4.15)
async-validator: 4.2.5
dayjs: 1.11.10
dayjs: 1.11.13
escape-html: 1.0.3
lodash: 4.17.21
lodash-es: 4.17.21