增加其他3种特殊平台模式就,处理下表单下拉组件输入框不绑定选项值识别故障问题
This commit is contained in:
@@ -11,10 +11,14 @@ import { getCustomizeResume } from "~api/aiApi"
|
||||
import { getMemberStatus } from "~api/dataApi"
|
||||
import { handleAutoFillCommon } from "~handlers/handleAutoFillCommon"
|
||||
import { handleAutoFillBeisen } from "~handlers/handleAutoFillBeisen"
|
||||
import { scanPageFields, extractNonResumeFields, printFieldStats } from "~lib/fillStats"
|
||||
import { handleAutoFillMoka } from "~handlers/handleAutoFillMoka"
|
||||
import { handleAutoFillFeishu } from "~handlers/handleAutoFillFeishu"
|
||||
import { handleAutoFillHotjob } from "~handlers/handleAutoFillHotjob"
|
||||
import { scanPageFields, extractNonResumeFields, printFieldStats, collectPickerOptionTexts, getPickerDisplayValue } from "~lib/fillStats"
|
||||
import type { TitleStat } from "~lib/fillStats"
|
||||
import type { MatchedFormField, ResumeData, JobInfo } from "~lib/types"
|
||||
import { createChannelBridge } from "~lib/channelBridge"
|
||||
import { buildResumeExcludeTexts } from "~lib/resumeDataHelper"
|
||||
import logoImg from "data-base64:~/../assets/logo-offerpai.png"
|
||||
import { config as appConfig } from "~config"
|
||||
import "./SidebarPanel.scss"
|
||||
@@ -96,6 +100,9 @@ export function SidebarPanel({ sourceUrl, jobInfo, onClose }: SidebarPanelProps)
|
||||
isDragging: false, startX: 0, startY: 0, startOffsetX: 0, startOffsetY: 0, longPressTimer: null, isLongPress: false
|
||||
})
|
||||
|
||||
/** 选择器选项文字缓存(collectPickerOptionTexts 收集后存入,handleSaveUserInput 用于排除) */
|
||||
const pickerOptionTextsRef = useRef<Set<string>>(new Set())
|
||||
|
||||
/** 停止当前循环扫描 */
|
||||
const stopScanLoop = () => {
|
||||
if (scanIntervalRef.current) {
|
||||
@@ -128,17 +135,67 @@ export function SidebarPanel({ sourceUrl, jobInfo, onClose }: SidebarPanelProps)
|
||||
}
|
||||
|
||||
/** 开启循环扫描(每秒执行一次) */
|
||||
const startScanLoop = (params: { siteMode?: "beisen"; sectionResults?: any[]; expandedResults?: any[]; excludeTexts?: Set<string> }) => {
|
||||
const startScanLoop = (params: { siteMode?: "beisen" | "moka" | "feishu" | "hotjob"; sectionResults?: any[]; expandedResults?: any[]; excludeTexts?: Set<string> }) => {
|
||||
stopScanLoop()
|
||||
const hasFullData = !!(params.sectionResults && params.expandedResults)
|
||||
|
||||
/**
|
||||
* 同步构建排除集合:合并 params.excludeTexts + 当前 resumeData 中的所有值
|
||||
* 避免将已填入表单的简历值(如"汉族"、"广州"等)误认为表单标签
|
||||
*/
|
||||
const buildExcludeTexts = (): Set<string> => {
|
||||
const baseSet = buildResumeExcludeTexts(resumeData)
|
||||
// 合并外部传入的静态排除集合(第二次调用时由 fillResult.resumeData 构建)
|
||||
if (params.excludeTexts) {
|
||||
for (const t of params.excludeTexts) baseSet.add(t)
|
||||
}
|
||||
return baseSet
|
||||
}
|
||||
|
||||
/**
|
||||
* 补充选择器展示值:遍历已识别字段,对 value 为空的字段调用 getPickerDisplayValue
|
||||
* 从 DOM 中提取展示文字与已收集的弹出层选项比对,匹配成功则更新字段 value
|
||||
*/
|
||||
const fillPickerDisplayValues = (fieldStats: TitleStat[]) => {
|
||||
const options = pickerOptionTextsRef.current
|
||||
if (options.size === 0) return
|
||||
// 北森模式(zhiye.com)的选择器值直接写在输入框里,不需要额外提取展示值
|
||||
if (window.location.hostname.includes("zhiye.com")) return
|
||||
for (const ts of fieldStats) {
|
||||
for (let fIdx = 0; fIdx < ts.fields.length; fIdx++) {
|
||||
const f = ts.fields[fIdx]
|
||||
// 已有值的跳过
|
||||
if (f.value) continue
|
||||
if (!f.inputElement) continue
|
||||
const inputEl = f.inputElement as HTMLElement
|
||||
// input.value 有值的跳过
|
||||
if ((inputEl as HTMLInputElement).value?.trim()) continue
|
||||
// 找同大标题内下一个字段的标签文字作为边界
|
||||
const nextField = ts.fields[fIdx + 1]
|
||||
const nextLabelText = nextField?.labelText || null
|
||||
// 调用 getPickerDisplayValue 比对
|
||||
const displayVal = getPickerDisplayValue(inputEl, f.labelText, nextLabelText, options)
|
||||
if (displayVal) {
|
||||
f.value = displayVal
|
||||
f.filled = true
|
||||
f.color = "green"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 立即执行一次
|
||||
const stats = scanPageFields(params)
|
||||
const stats = scanPageFields({ ...params, excludeTexts: buildExcludeTexts() })
|
||||
// 补充选择器展示值:对 value 为空的字段,从 DOM 中提取展示文字与选项比对
|
||||
fillPickerDisplayValues(stats)
|
||||
setFieldStats(stats)
|
||||
findUpdatedField(stats) // 初始化快照,不滚动
|
||||
if (hasFullData) handleSaveUserInput()
|
||||
// 每秒循环
|
||||
scanIntervalRef.current = setInterval(() => {
|
||||
const s = scanPageFields(params)
|
||||
const s = scanPageFields({ ...params, excludeTexts: buildExcludeTexts() })
|
||||
// 补充选择器展示值
|
||||
fillPickerDisplayValues(s)
|
||||
setFieldStats(s)
|
||||
if (ENABLE_AUTO_SCROLL_TO_UPDATED) {
|
||||
const updatedEl = findUpdatedField(s)
|
||||
@@ -440,14 +497,27 @@ export function SidebarPanel({ sourceUrl, jobInfo, onClose }: SidebarPanelProps)
|
||||
// 检测当前页面域名,判断走哪个处理模式
|
||||
const currentHost = window.location.hostname
|
||||
const isBeisen = currentHost.includes("zhiye.com") // 北森招聘平台域名特征
|
||||
const scanSiteMode = isBeisen ? "beisen" as const : undefined
|
||||
const isMoka = currentHost.includes("mokahr.com") // 摩卡招聘平台域名特征
|
||||
const isFeishu = currentHost.includes("feishu.cn") // 飞书招聘平台域名特征
|
||||
const isHotjob = currentHost.includes("hotjob.cn") // Hotjob招聘平台域名特征
|
||||
const scanSiteMode = isBeisen ? "beisen" as const
|
||||
: isMoka ? "moka" as const
|
||||
: isFeishu ? "feishu" as const
|
||||
: isHotjob ? "hotjob" as const
|
||||
: undefined
|
||||
|
||||
// 第一次开启循环扫描(不传 sectionResults,阶段A之前就开始展示)
|
||||
startScanLoop({ siteMode: scanSiteMode })
|
||||
|
||||
const fillResult = isBeisen
|
||||
? await handleAutoFillBeisen({ resumeData, jobInfo })
|
||||
: await handleAutoFillCommon({ resumeData, jobInfo })
|
||||
: isMoka
|
||||
? await handleAutoFillMoka({ resumeData, jobInfo })
|
||||
: isFeishu
|
||||
? await handleAutoFillFeishu({ resumeData, jobInfo })
|
||||
: isHotjob
|
||||
? await handleAutoFillHotjob({ resumeData, jobInfo })
|
||||
: await handleAutoFillCommon({ resumeData, jobInfo })
|
||||
|
||||
// 将处理器返回的结果同步到组件状态
|
||||
setPageLang(fillResult.lang) // 页面语言(影响后续标签匹配用中文还是英文)
|
||||
@@ -481,6 +551,22 @@ export function SidebarPanel({ sourceUrl, jobInfo, onClose }: SidebarPanelProps)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 收集页面上所有选择器字段的下拉选项文字,合并到排除集合
|
||||
// 避免选择器已选值(如"维吾尔族")被误认为表单标签
|
||||
// 北森模式(zhiye.com)选择器值直接写在输入框里,跳过整套弹出层收集逻辑
|
||||
if (!isBeisen) {
|
||||
const preFieldStats = scanPageFields({
|
||||
siteMode: scanSiteMode,
|
||||
sectionResults: fillResult.sectionResults,
|
||||
expandedResults: fillResult.expandedResults,
|
||||
excludeTexts: scanExcludeTexts,
|
||||
})
|
||||
const pickerOptionTexts = await collectPickerOptionTexts(preFieldStats)
|
||||
for (const t of pickerOptionTexts) scanExcludeTexts.add(t)
|
||||
// 存入 ref,供 handleSaveUserInput 使用
|
||||
pickerOptionTextsRef.current = pickerOptionTexts
|
||||
}
|
||||
|
||||
startScanLoop({
|
||||
siteMode: scanSiteMode,
|
||||
sectionResults: fillResult.sectionResults,
|
||||
@@ -508,7 +594,11 @@ export function SidebarPanel({ sourceUrl, jobInfo, onClose }: SidebarPanelProps)
|
||||
|
||||
// 检测当前网站模式
|
||||
const currentHost = window.location.hostname
|
||||
const siteMode = currentHost.includes("zhiye.com") ? "beisen" as const : undefined
|
||||
const siteMode = currentHost.includes("zhiye.com") ? "beisen" as const
|
||||
: currentHost.includes("mokahr.com") ? "moka" as const
|
||||
: currentHost.includes("feishu.cn") ? "feishu" as const
|
||||
: currentHost.includes("hotjob.cn") ? "hotjob" as const
|
||||
: undefined
|
||||
|
||||
// 从简历数据和缓存数据中提取所有已填值,构建排除集合
|
||||
// 避免 findLabelForInput 把这些值文字误认为是表单字段标签
|
||||
@@ -550,10 +640,32 @@ export function SidebarPanel({ sourceUrl, jobInfo, onClose }: SidebarPanelProps)
|
||||
}
|
||||
}
|
||||
}
|
||||
// 合并选择器选项文字(collectPickerOptionTexts 收集的下拉选项)
|
||||
for (const t of pickerOptionTextsRef.current) excludeTexts.add(t)
|
||||
|
||||
// 调用 fillStats 扫描页面所有字段
|
||||
const titleStats = scanPageFields({ siteMode, excludeTexts })
|
||||
|
||||
// 补充选择器展示值(与 startScanLoop 逻辑一致)
|
||||
const pickerOpts = pickerOptionTextsRef.current
|
||||
if (pickerOpts.size > 0) {
|
||||
for (const ts of titleStats) {
|
||||
for (let fIdx = 0; fIdx < ts.fields.length; fIdx++) {
|
||||
const f = ts.fields[fIdx]
|
||||
if (f.value) continue
|
||||
if (!f.inputElement) continue
|
||||
if ((f.inputElement as HTMLInputElement).value?.trim()) continue
|
||||
const nextField = ts.fields[fIdx + 1]
|
||||
const nextLabelText = nextField?.labelText || null
|
||||
const displayVal = getPickerDisplayValue(f.inputElement as HTMLElement, f.labelText, nextLabelText, pickerOpts)
|
||||
if (displayVal) {
|
||||
f.value = displayVal
|
||||
f.filled = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 提取非简历格式字段(B2阶段字段)
|
||||
const nonResumeData = extractNonResumeFields(titleStats)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user