mirror of
https://github.com/geekgeekrun/geekgeekrun.git
synced 2026-09-06 16:07:17 +08:00
WIP: add the logic to save job mark as not suit to db TODO: fix issue about retrieving and showing items
This commit is contained in:
+9
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"3": "学历不匹配",
|
||||||
|
"5": "其他反馈",
|
||||||
|
"13": "同城距离远",
|
||||||
|
"30": "公司不感兴趣",
|
||||||
|
"34": "BOSS活跃度低",
|
||||||
|
"41": "职位停招/招满",
|
||||||
|
"42": "面试过/入职过"
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ import { calculateTotalCombinations, combineFiltersWithConstraintsGenerator } fr
|
|||||||
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 } from '@geekgeekrun/sqlite-plugin/dist/entity/MarkAsNotSuitLog'
|
||||||
|
|
||||||
const jobFilterConditionsMapByCode = {}
|
const jobFilterConditionsMapByCode = {}
|
||||||
Object.values(jobFilterConditions).forEach(arr => {
|
Object.values(jobFilterConditions).forEach(arr => {
|
||||||
@@ -113,10 +114,14 @@ const blockBossNotNewChat = new Set()
|
|||||||
const blockBossNotActive = new Set()
|
const blockBossNotActive = new Set()
|
||||||
|
|
||||||
async function markJobAsNotSuitInRecommendPage () {
|
async function markJobAsNotSuitInRecommendPage () {
|
||||||
|
/**
|
||||||
|
* @type {{chosenReasonInUi?: { code: number, text: string}}}
|
||||||
|
*/
|
||||||
|
const result = {}
|
||||||
const notSuitableFeedbackButtonProxy = await page.$('.job-detail-box .job-detail-operate .not-suitable')
|
const notSuitableFeedbackButtonProxy = await page.$('.job-detail-box .job-detail-operate .not-suitable')
|
||||||
if (notSuitableFeedbackButtonProxy) {
|
if (notSuitableFeedbackButtonProxy) {
|
||||||
await notSuitableFeedbackButtonProxy.click()
|
await notSuitableFeedbackButtonProxy.click()
|
||||||
const rawRes = await (await page.waitForResponse(
|
const rawReasonResData = (await (await page.waitForResponse(
|
||||||
response => {
|
response => {
|
||||||
if (
|
if (
|
||||||
response.url().startsWith('https://www.zhipin.com/wapi/zpgeek/negativefeedback/reasons.json')
|
response.url().startsWith('https://www.zhipin.com/wapi/zpgeek/negativefeedback/reasons.json')
|
||||||
@@ -125,7 +130,12 @@ async function markJobAsNotSuitInRecommendPage () {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
)).json();
|
)).json())?.zpData?.result ?? [];
|
||||||
|
const reasonCodeToTextMap = await readStorageFile('job-not-suit-reason-code-to-text-cache.json')
|
||||||
|
for(const it of rawReasonResData) {
|
||||||
|
reasonCodeToTextMap[it.code] = it.text?.content ?? ''
|
||||||
|
}
|
||||||
|
await writeStorageFile('job-not-suit-reason-code-to-text-cache.json', reasonCodeToTextMap)
|
||||||
await sleepWithRandomDelay(2000)
|
await sleepWithRandomDelay(2000)
|
||||||
const chooseReasonDialogProxy = await(async() => {
|
const chooseReasonDialogProxy = await(async() => {
|
||||||
const alls = await page.$$('.zp-dialog-wrap.zp-feedback-dialog.v-transfer-dom')
|
const alls = await page.$$('.zp-dialog-wrap.zp-feedback-dialog.v-transfer-dom')
|
||||||
@@ -149,7 +159,7 @@ async function markJobAsNotSuitInRecommendPage () {
|
|||||||
await sleepWithRandomDelay(1500)
|
await sleepWithRandomDelay(1500)
|
||||||
const confirmButtonProxy = await chooseReasonDialogProxy.$(`.zp-dialog-footer .zp-btn.zp-btn-sure`)
|
const confirmButtonProxy = await chooseReasonDialogProxy.$(`.zp-dialog-footer .zp-btn.zp-btn-sure`)
|
||||||
await confirmButtonProxy.click()
|
await confirmButtonProxy.click()
|
||||||
await page.waitForResponse(
|
const response = await page.waitForResponse(
|
||||||
response => {
|
response => {
|
||||||
if (
|
if (
|
||||||
response.url().startsWith('https://www.zhipin.com/wapi/zpgeek/negativefeedback/save.json')
|
response.url().startsWith('https://www.zhipin.com/wapi/zpgeek/negativefeedback/save.json')
|
||||||
@@ -159,6 +169,17 @@ async function markJobAsNotSuitInRecommendPage () {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
/**
|
||||||
|
* scene=4&code=41&feedbackReason=&securityId=
|
||||||
|
*/
|
||||||
|
const requestBody = response.request().postData()
|
||||||
|
const chosenCode = Number(new URLSearchParams(requestBody).get('code'))
|
||||||
|
if (chosenCode) {
|
||||||
|
result.chosenReasonInUi = {
|
||||||
|
code: chosenCode,
|
||||||
|
text: reasonCodeToTextMap[chosenCode]
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
const cancelButtonProxy = await chooseReasonDialogProxy.$(`.zp-close`)
|
const cancelButtonProxy = await chooseReasonDialogProxy.$(`.zp-close`)
|
||||||
await cancelButtonProxy.click()
|
await cancelButtonProxy.click()
|
||||||
@@ -167,6 +188,7 @@ async function markJobAsNotSuitInRecommendPage () {
|
|||||||
await sleepWithRandomDelay(2500)
|
await sleepWithRandomDelay(2500)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setFilterCondition (selectedFilters) {
|
async function setFilterCondition (selectedFilters) {
|
||||||
@@ -528,7 +550,18 @@ async function toRecommendPage (hooks) {
|
|||||||
blockBossNotActive.add(targetJobData.jobInfo.encryptUserId)
|
blockBossNotActive.add(targetJobData.jobInfo.encryptUserId)
|
||||||
// click prevent recommend button
|
// click prevent recommend button
|
||||||
try {
|
try {
|
||||||
await markJobAsNotSuitInRecommendPage()
|
const { chosenReasonInUi } = await markJobAsNotSuitInRecommendPage()
|
||||||
|
await hooks.jobMarkedAsNotSuit.promise(
|
||||||
|
targetJobData,
|
||||||
|
{
|
||||||
|
markFrom: ChatStartupFrom.AutoFromRecommendList,
|
||||||
|
markReason: MarkAsNotSuitReason.BOSS_INACTIVE,
|
||||||
|
extInfo: {
|
||||||
|
bossActiveTimeDesc: targetJobData.bossInfo.activeTimeDesc,
|
||||||
|
chosenReasonInUi
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
} catch {
|
} catch {
|
||||||
}
|
}
|
||||||
continue continueFind
|
continue continueFind
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import defaultTargetCompanyListConf from './default-config-file/target-company-l
|
|||||||
|
|
||||||
import defaultBossCookieStorage from './default-storage-file/boss-cookies.json' assert { type: 'json' }
|
import defaultBossCookieStorage from './default-storage-file/boss-cookies.json' assert { type: 'json' }
|
||||||
import defaultBossLocalStorageStorage from './default-storage-file/boss-local-storage.json' assert { type: 'json' }
|
import defaultBossLocalStorageStorage from './default-storage-file/boss-local-storage.json' assert { type: 'json' }
|
||||||
|
import defaultJobNotSuitReasonCodeToTextCacheStorage from './default-storage-file/job-not-suit-reason-code-to-text-cache.json' assert { type: 'json' }
|
||||||
export const configFileNameList = ['boss.json', 'dingtalk.json', 'target-company-list.json']
|
export const configFileNameList = ['boss.json', 'dingtalk.json', 'target-company-list.json']
|
||||||
|
|
||||||
const defaultConfigFileContentMap = {
|
const defaultConfigFileContentMap = {
|
||||||
@@ -88,11 +89,12 @@ export const storageFilePath = path.join(
|
|||||||
runtimeFolderPath,
|
runtimeFolderPath,
|
||||||
'storage'
|
'storage'
|
||||||
)
|
)
|
||||||
export const storageFileNameList = ['boss-cookies.json', 'boss-local-storage.json']
|
export const storageFileNameList = ['boss-cookies.json', 'boss-local-storage.json', 'job-not-suit-reason-code-to-text-cache.json']
|
||||||
|
|
||||||
const defaultStorageFileContentMap = {
|
const defaultStorageFileContentMap = {
|
||||||
'boss-cookies.json': JSON.stringify(defaultBossCookieStorage),
|
'boss-cookies.json': JSON.stringify(defaultBossCookieStorage),
|
||||||
'boss-local-storage.json': JSON.stringify(defaultBossLocalStorageStorage)
|
'boss-local-storage.json': JSON.stringify(defaultBossLocalStorageStorage),
|
||||||
|
'job-not-suit-reason-code-to-text-cache.json': JSON.stringify(defaultJobNotSuitReasonCodeToTextCacheStorage)
|
||||||
}
|
}
|
||||||
export const ensureStorageFileExist = () => {
|
export const ensureStorageFileExist = () => {
|
||||||
ensureRuntimeFolderPathExist()
|
ensureRuntimeFolderPathExist()
|
||||||
|
|||||||
@@ -2,6 +2,12 @@ import { requireTypeorm } from "../utils/module-loader";
|
|||||||
import { ChatStartupFrom } from "./ChatStartupLog";
|
import { ChatStartupFrom } from "./ChatStartupLog";
|
||||||
const { Entity, Column, PrimaryGeneratedColumn } = requireTypeorm()
|
const { Entity, Column, PrimaryGeneratedColumn } = requireTypeorm()
|
||||||
|
|
||||||
|
export enum MarkAsNotSuitReason {
|
||||||
|
UNKNOWN = 0,
|
||||||
|
BOSS_INACTIVE = 1,
|
||||||
|
OTHER = 2
|
||||||
|
}
|
||||||
|
|
||||||
@Entity()
|
@Entity()
|
||||||
export class MarkAsNotSuitLog {
|
export class MarkAsNotSuitLog {
|
||||||
@PrimaryGeneratedColumn()
|
@PrimaryGeneratedColumn()
|
||||||
@@ -21,6 +27,16 @@ export class MarkAsNotSuitLog {
|
|||||||
})
|
})
|
||||||
markFrom?: ChatStartupFrom;
|
markFrom?: ChatStartupFrom;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
nullable: true
|
||||||
|
})
|
||||||
|
markReason?: MarkAsNotSuitReason
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
nullable: true
|
||||||
|
})
|
||||||
|
extInfo?: string
|
||||||
|
|
||||||
@Column({
|
@Column({
|
||||||
nullable: true
|
nullable: true
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import { ChatStartupLog } from "./entity/ChatStartupLog";
|
|||||||
import { BossInfoChangeLog } from "./entity/BossInfoChangeLog";
|
import { BossInfoChangeLog } from "./entity/BossInfoChangeLog";
|
||||||
import { CompanyInfoChangeLog } from "./entity/CompanyInfoChangeLog";
|
import { CompanyInfoChangeLog } from "./entity/CompanyInfoChangeLog";
|
||||||
import { JobInfoChangeLog } from "./entity/JobInfoChangeLog";
|
import { JobInfoChangeLog } from "./entity/JobInfoChangeLog";
|
||||||
|
import { MarkAsNotSuitLog } from "./entity/MarkAsNotSuitLog";
|
||||||
|
|
||||||
function getBossInfoIfIsEqual (savedOne, currentOne) {
|
function getBossInfoIfIsEqual (savedOne, currentOne) {
|
||||||
if (savedOne === currentOne) {
|
if (savedOne === currentOne) {
|
||||||
@@ -262,3 +263,30 @@ export async function saveChatStartupRecord(
|
|||||||
//#endregion
|
//#endregion
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function saveMarkAsNotSuitRecord(
|
||||||
|
ds: DataSource,
|
||||||
|
_jobInfo,
|
||||||
|
{ encryptUserId },
|
||||||
|
{ autoStartupChatRecordId = undefined, markFrom = undefined, extInfo = undefined, markReason = undefined } = {}
|
||||||
|
) {
|
||||||
|
const { jobInfo } = _jobInfo;
|
||||||
|
|
||||||
|
//#region mark-as-not-suit-log
|
||||||
|
const markAsNotSuitLog = new MarkAsNotSuitLog()
|
||||||
|
const markAsNotSuitLogPayload: Partial<MarkAsNotSuitLog> = {
|
||||||
|
date: new Date(),
|
||||||
|
encryptCurrentUserId: encryptUserId,
|
||||||
|
encryptJobId: jobInfo.encryptId,
|
||||||
|
autoStartupChatRecordId,
|
||||||
|
markFrom,
|
||||||
|
markReason,
|
||||||
|
extInfo: extInfo ? JSON.stringify(extInfo) : undefined
|
||||||
|
}
|
||||||
|
Object.assign(markAsNotSuitLog, markAsNotSuitLogPayload)
|
||||||
|
|
||||||
|
const markAsNotSuitLogRepository = ds.getRepository(MarkAsNotSuitLog);
|
||||||
|
await markAsNotSuitLogRepository.save(markAsNotSuitLog);
|
||||||
|
//#endregion
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import { VMarkAsNotSuitLog } from "./entity/VMarkAsNotSuitLog"
|
|||||||
|
|
||||||
import sqlite3 from 'sqlite3';
|
import sqlite3 from 'sqlite3';
|
||||||
import * as cliHighlight from 'cli-highlight';
|
import * as cliHighlight from 'cli-highlight';
|
||||||
import { saveChatStartupRecord, saveJobInfoFromRecommendPage } from "./handlers";
|
import { saveChatStartupRecord, saveJobInfoFromRecommendPage, saveMarkAsNotSuitRecord } from "./handlers";
|
||||||
import { UpdateChatStartupLogTable1729182577167 } from "./migrations/1729182577167-UpdateChatStartupLogTable";
|
import { UpdateChatStartupLogTable1729182577167 } from "./migrations/1729182577167-UpdateChatStartupLogTable";
|
||||||
|
|
||||||
Boolean(cliHighlight);
|
Boolean(cliHighlight);
|
||||||
@@ -119,5 +119,15 @@ export default class SqlitePlugin {
|
|||||||
chatStartupFrom
|
chatStartupFrom
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
hooks.jobMarkedAsNotSuit.tapPromise("SqlitePlugin", async (_jobInfo, { markFrom = ChatStartupFrom.AutoFromRecommendList, markReason = undefined, extInfo = undefined } = {}) => {
|
||||||
|
const ds = await this.initPromise;
|
||||||
|
return await saveMarkAsNotSuitRecord(ds, _jobInfo, this.userInfo, {
|
||||||
|
autoStartupChatRecordId: this.runRecordId,
|
||||||
|
markFrom,
|
||||||
|
markReason,
|
||||||
|
extInfo
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ const runAutoChat = async () => {
|
|||||||
jobDetailIsGetFromRecommendList: new AsyncSeriesHook(['userInfo']),
|
jobDetailIsGetFromRecommendList: new AsyncSeriesHook(['userInfo']),
|
||||||
newChatWillStartup: new AsyncSeriesHook(['positionInfoDetail']),
|
newChatWillStartup: new AsyncSeriesHook(['positionInfoDetail']),
|
||||||
newChatStartup: new AsyncSeriesHook(['positionInfoDetail', 'chatRunningContext']),
|
newChatStartup: new AsyncSeriesHook(['positionInfoDetail', 'chatRunningContext']),
|
||||||
|
jobMarkedAsNotSuit: new AsyncSeriesHook(['positionInfoDetail', 'markDetail']),
|
||||||
noPositionFoundForCurrentJob: new SyncHook(),
|
noPositionFoundForCurrentJob: new SyncHook(),
|
||||||
noPositionFoundAfterTraverseAllJob: new SyncHook(),
|
noPositionFoundAfterTraverseAllJob: new SyncHook(),
|
||||||
errorEncounter: new SyncHook(['errorInfo'])
|
errorEncounter: new SyncHook(['errorInfo'])
|
||||||
|
|||||||
Reference in New Issue
Block a user