add basic ui for expectCityList config

This commit is contained in:
geekgeekrun
2025-05-24 18:30:48 +08:00
parent 217b2bbf2a
commit 64249593b8
6 changed files with 7738 additions and 12 deletions

View File

@@ -10,6 +10,8 @@
"jobNotMatchStrategy": 1,
"jobNotActiveStrategy": 1,
"markAsNotActiveSelectedTimeRange": 7,
"expectCityList": [],
"expectCityNotMatchStrategy": 1,
"autoReminder": {
"throttleIntervalMinutes": 10,
"rechatLimitDay": 21,

File diff suppressed because it is too large Load Diff

View File

@@ -107,6 +107,12 @@ export default function initIpc() {
if (hasOwn(payload, 'autoReminder')) {
bossConfig.autoReminder = payload.autoReminder
}
if (hasOwn(payload, 'expectCityList')) {
bossConfig.expectCityList = payload.expectCityList
}
if (hasOwn(payload, 'expectCityNotMatchStrategy')) {
bossConfig.expectCityNotMatchStrategy = payload.expectCityNotMatchStrategy
}
promiseArr.push(writeConfigFile('boss.json', bossConfig))
if (hasOwn(payload, 'expectCompanies')) {

View File

@@ -0,0 +1,160 @@
<template>
<div>
<div v-if="modelValue?.length">
<div>当前已选择城市</div>
<div flex flex-wrap gap-10px>
<el-tag v-for="it in modelValue" :key="it">
{{ it }}
</el-tag>
</div>
</div>
<div v-else>
<div>当前未选择任何期望城市将不会按照城市进行筛选</div>
</div>
<div>
<el-button size="small" type="primary" @click="isDialogVisible = true">选择城市</el-button>
<el-button
v-if="modelValue?.length"
size="small"
type="danger"
text
@click="handleClearSelectedCitiesInModelValue"
>清空已选择的所有城市</el-button
>
</div>
<el-dialog
v-model="isDialogVisible"
width="1000px"
title="请选择城市"
:show-close="false"
@open="handleDialogOpen"
@closed="handleDialogClosed"
>
<el-tabs v-model="activeTabName">
<el-tab-pane
:style="{ height: '300px', overflow: 'auto' }"
label="热门城市"
name="热门城市"
>
<el-checkbox-group v-model="selectedCities">
<div
:style="{
display: 'grid',
gridTemplateColumns: '1fr 1fr 1fr 1fr'
}"
>
<el-checkbox
v-for="op in hotCityList.filter((it) => it.code !== 100010000)"
:key="op.code"
:label="op.name"
>
{{ op.name }}
</el-checkbox>
</div>
</el-checkbox-group>
</el-tab-pane>
<el-tab-pane
v-for="it in cityGroupsByAlphabetMap.keys()"
:key="it"
:style="{ height: '300px', overflow: 'auto' }"
:label="it"
:value="it"
>
<div v-for="group in cityGroupsByAlphabetMap.get(it)" :key="group.firstChar">
{{ group.firstChar }}
<el-checkbox-group v-model="selectedCities">
<div
:style="{
display: 'grid',
gridTemplateColumns: '1fr 1fr 1fr 1fr'
}"
>
<el-checkbox v-for="op in group.cityList" :key="op.code" :label="op.name">
{{ op.name }}
</el-checkbox>
</div>
</el-checkbox-group>
</div>
</el-tab-pane>
</el-tabs>
<template #footer>
<div
:style="{
display: 'flex',
alignItems: 'center',
justifyContent: 'space-between'
}"
>
<div>
<el-button
v-if="selectedCities.length"
type="danger"
text
@click="handleClearSelectedCitiesInDialog"
>清空已选择的所有城市</el-button
>
</div>
<div>
<el-button type="text" @click="handleCancelClicked">取消</el-button>
<el-button type="primary" @click="handleConfirmClicked">确定</el-button>
</div>
</div>
</template>
</el-dialog>
</div>
</template>
<script lang="ts" setup>
import { PropType, ref } from 'vue'
import cityGroupData from '../../../../../../common/constant/cityGroup.json'
const props = defineProps({
modelValue: {
type: Array as PropType<string[]>
}
})
const emits = defineEmits(['update:modelValue'])
const { hotCityList, cityGroup } = cityGroupData.zpData
const activeTabName = ref('热门城市')
const isDialogVisible = ref(false)
const selectedCities = ref([])
const cityGroupsByAlphabetMap = ref(
new Map(['ABCDE', 'FGHJ', 'KLMN', 'PQRST', 'WXYZ'].map((it) => [it, []]))
)
for (const group of cityGroup) {
const { firstChar } = group
const targetKey =
[...cityGroupsByAlphabetMap.value.keys()].find((it) => it.includes(firstChar)) ?? null
if (!targetKey) {
if (!cityGroupsByAlphabetMap.value.get(targetKey)) {
cityGroupsByAlphabetMap.value.set(targetKey, [])
}
}
cityGroupsByAlphabetMap.value.get(targetKey)?.push(group)
}
function handleDialogOpen() {
activeTabName.value = '热门城市'
selectedCities.value = [...(props.modelValue ?? [])]
}
function handleCancelClicked() {
isDialogVisible.value = false
}
function handleConfirmClicked() {
isDialogVisible.value = false
emits('update:modelValue', [...(selectedCities.value ?? [])])
}
function handleDialogClosed() {
selectedCities.value = []
}
function handleClearSelectedCitiesInModelValue() {
emits('update:modelValue', [])
}
function handleClearSelectedCitiesInDialog() {
selectedCities.value = []
}
</script>

View File

@@ -14,10 +14,7 @@
</el-form-item> -->
<div>
<el-form-item mb0>
<div>
是否查看职位详情的条件
<span font-size-12px>以下条件为空表示不筛选</span>
</div>
<div>是否查看职位详情的条件</div>
</el-form-item>
<el-form-item prop="expectCompanies" mb10px>
<div
@@ -31,13 +28,13 @@
}"
>
<div>
期望公司以逗号分隔不区分大小写<el-tooltip
期望公司以逗号分隔不区分大小写为空表示不筛选<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" />
<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
@@ -68,6 +65,67 @@
@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
:style="{
display: 'grid',
gridTemplateColumns: '1fr 1fr'
}"
>
<el-form-item prop="expectCityList" mb10px>
<div
font-size-12px
:style="{
justifyContent: 'space-between',
alignItems: 'center',
width: '100%'
}"
>
<div>期望工作地</div>
<city-chooser v-model="formContent.expectCityList" />
</div>
</el-form-item>
<el-form-item v-if="formContent.expectCityList?.length" prop="expectCityList" mb10px>
<div
font-size-12px
:style="{
justifyContent: 'space-between',
alignItems: 'center',
width: '100%'
}"
>
<div>当找到的工作和期望工作地不匹配时将要执行的操作</div>
<el-form-item mb0>
<el-select
v-model="formContent.expectCityNotMatchStrategy"
@change="
(value) => gtagRenderer('expect_city_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>
</div>
</el-form-item>
</div>
</div>
<div mb42px>
<el-form-item mb0>
@@ -88,7 +146,7 @@
@show="gtagRenderer('tooltip_show_about_expect_job_info_figure')"
>
<template #content>
<img block h-270px src="./resources/intro-of-job-info.png" />
<img block h-270px src="../resources/intro-of-job-info.png" />
</template>
<el-button type="text" font-size-12px
><span><QuestionFilled w-1em h-1em mr2px /></span>如下各信息位置图示</el-button
@@ -125,6 +183,7 @@
<div font-size-12px>职位名称正则不区分大小写</div>
<el-input
v-model="formContent.expectJobNameRegExpStr"
placeholder="true"
@blur="
formContent.expectJobNameRegExpStr =
formContent.expectJobNameRegExpStr?.trim() ?? ''
@@ -136,6 +195,7 @@
<div font-size-12px>职位类型正则推荐填写不区分大小写</div>
<el-input
v-model="formContent.expectJobTypeRegExpStr"
placeholder="true"
@blur="
formContent.expectJobTypeRegExpStr =
formContent.expectJobTypeRegExpStr?.trim() ?? ''
@@ -147,6 +207,7 @@
<div font-size-12px>职位描述正则不区分大小写</div>
<el-input
v-model="formContent.expectJobDescRegExpStr"
placeholder="true"
@blur="
formContent.expectJobDescRegExpStr =
formContent.expectJobDescRegExpStr?.trim() ?? ''
@@ -323,7 +384,8 @@ import defaultTargetCompanyListConf from '@geekgeekrun/geek-auto-start-chat-with
import { ArrowDown } from '@element-plus/icons-vue'
import { MarkAsNotSuitOp } from '@geekgeekrun/sqlite-plugin/src/enums'
import { debounce } from 'lodash-es'
import mittBus from '../../utils/mitt'
import mittBus from '../../../utils/mitt'
import CityChooser from './components/CityChooser.vue'
const router = useRouter()
@@ -336,7 +398,9 @@ const formContent = ref({
expectJobDescRegExpStr: '',
jobNotMatchStrategy: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS,
jobNotActiveStrategy: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS,
markAsNotActiveSelectedTimeRange: 7
markAsNotActiveSelectedTimeRange: 7,
expectCityList: [],
expectCityNotMatchStrategy: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
})
const currentAnyCombineRecommendJobFilterCombinationCount = computed(() => {
@@ -398,6 +462,8 @@ electron.ipcRenderer.invoke('fetch-config-file-content').then((res) => {
.includes(res.config['boss.json'].jobNotActiveStrategy)
? res.config['boss.json'].jobNotActiveStrategy
: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
formContent.value.expectCityList = res.config['boss.json']?.expectCityList ?? []
})
const formRules = {
@@ -612,11 +678,11 @@ const strategyOptionWhenCurrentJobNotMatch = [
value: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_BOSS
},
{
name: '本地记录且1周内再次遇到这个职位时直接跳过',
name: '7天内再次遇到这个职位时直接跳过',
value: MarkAsNotSuitOp.MARK_AS_NOT_SUIT_ON_LOCAL
},
{
name: '本地不记录,但本次运行再次遇到这个职位时直接跳过',
name: '本次运行再次遇到这个职位时直接跳过',
value: MarkAsNotSuitOp.NO_OP
}
]

View File

@@ -45,7 +45,7 @@ const routes: Array<RouteRecordRaw> = [
children: [
{
path: 'GeekAutoStartChatWithBoss',
component: () => import('@renderer/page/MainLayout/GeekAutoStartChatWithBoss.vue'),
component: () => import('@renderer/page/MainLayout/GeekAutoStartChatWithBoss/index.vue'),
meta: {
title: 'BOSS炸弹'
}