通用模式兼容摩卡和飞书,添加通信工具组件,添加未开通会员面板
This commit is contained in:
@@ -19,6 +19,8 @@ import { locateExperienceSections, expandExperienceSections, sortExperienceByTim
|
||||
import type { ExperienceSectionLocateResult } from "~lib/experienceSection"
|
||||
import type { MatchedFormField, ResumeData, ExperienceSection, JobInfo, UnmatchedFormField } from "~lib/types"
|
||||
import { setFieldHighlight, isRequiredField } from "~lib/formStyle"
|
||||
import { get as storageGet, set as storageSet } from "~utils/storage"
|
||||
import { findLabelForInput } from "~lib/labelFinder"
|
||||
|
||||
/** 北森模式自动填写的参数 */
|
||||
export interface AutoFillBeisenParams {
|
||||
@@ -957,41 +959,10 @@ export async function handleAutoFillBeisen(params: AutoFillBeisenParams): Promis
|
||||
if (bgColor === "#b7ffc5" || bgColor === "rgb(183, 255, 197)") continue
|
||||
}
|
||||
|
||||
// 查找标签
|
||||
let labelText = ""
|
||||
let container: Element | null = null
|
||||
for (const sel of FORM_ITEM_SELS_JSON) {
|
||||
container = inp.closest(sel)
|
||||
if (container) break
|
||||
}
|
||||
if (container) {
|
||||
const labelEls = container.querySelectorAll("label, span, div, td, th, p, legend, dt")
|
||||
for (const el of Array.from(labelEls)) {
|
||||
const directText = Array.from(el.childNodes)
|
||||
.filter((n) => n.nodeType === Node.TEXT_NODE)
|
||||
.map((n) => n.textContent?.trim())
|
||||
.filter(Boolean)
|
||||
.join("")
|
||||
if (!directText || directText.length > 30) continue
|
||||
if (JSON_EXCLUDE_LABELS.some((ex) => directText === ex)) continue
|
||||
if (el.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_FOLLOWING) {
|
||||
labelText = directText
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!labelText) {
|
||||
let prev: Element | null = inp.previousElementSibling
|
||||
for (let i = 0; i < 3 && prev; i++) {
|
||||
const text = prev.textContent?.trim() || ""
|
||||
if (text && text.length <= 20 && !JSON_EXCLUDE_LABELS.some((ex) => text === ex)) {
|
||||
labelText = text
|
||||
break
|
||||
}
|
||||
prev = prev.previousElementSibling
|
||||
}
|
||||
}
|
||||
if (!labelText) labelText = inputEl.getAttribute("placeholder") || "(未知字段)"
|
||||
// 查找标签(使用统一封装的 labelFinder)
|
||||
const titleElementSet = new Set<Element>(allTitles.map((t) => t.element))
|
||||
const { labelText: detectedLabel } = findLabelForInput(inp, titleElementSet)
|
||||
const labelText = detectedLabel
|
||||
|
||||
// 非经历类型:跳过简历格式字段
|
||||
// 【注意】简历格式字段通过 resumeFormatInputs(阶段A/B实际匹配到的input元素集合)精确跳过
|
||||
@@ -1114,72 +1085,29 @@ export async function handleAutoFillBeisen(params: AutoFillBeisenParams): Promis
|
||||
console.log(JSON.stringify(unfilledFormData, null, 2))
|
||||
console.log("===== OfferPie: JSON 输出完毕 =====")
|
||||
|
||||
// 存 localStorage 缓存,包含简历名字和未填字段数据
|
||||
// 更新规则:以第一次存的版本为基准,可以添加字段、更新 value,但不删除已有字段
|
||||
// 存 chrome.storage 缓存,包含简历名字和未填字段数据(跨域名共享,按简历名区分)
|
||||
const resumeName = currentResumeData?.main?.resumeName || currentResumeData?.main?.name || ""
|
||||
try {
|
||||
const existingRaw = localStorage.getItem("offerpie_unfilled_form")
|
||||
const existing = await storageGet<any>("offerpie_unfilled_form")
|
||||
let cacheData: any = null
|
||||
|
||||
if (existingRaw) {
|
||||
const existing = JSON.parse(existingRaw)
|
||||
if (existing.resumeName === resumeName && existing.unfilledFormData) {
|
||||
// 同一份简历,合并更新(不删除已有字段,只添加新字段和更新 value)
|
||||
const oldSections = existing.unfilledFormData as any[]
|
||||
const newSections = unfilledFormData as any[]
|
||||
if (existing && existing.resumeName === resumeName && existing.unfilledFormData) {
|
||||
// 同一份简历,用新数据替换同名 section(保留其他平台的 section)
|
||||
const oldSections = existing.unfilledFormData as any[]
|
||||
const newSections = unfilledFormData as any[]
|
||||
|
||||
// 遍历新数据,对每个 section 做合并
|
||||
for (const newSec of newSections) {
|
||||
const oldSec = oldSections.find((s: any) => s.title === newSec.title)
|
||||
if (!oldSec) {
|
||||
// 新增的 section,直接追加
|
||||
oldSections.push(newSec)
|
||||
continue
|
||||
}
|
||||
|
||||
if (newSec.isExperience) {
|
||||
// 经历类型:按段合并
|
||||
const oldSegments = oldSec.formItems as any[][]
|
||||
const newSegments = newSec.formItems as any[][]
|
||||
for (let sIdx = 0; sIdx < newSegments.length; sIdx++) {
|
||||
if (sIdx >= oldSegments.length) {
|
||||
// 新增的段,直接追加
|
||||
oldSegments.push(newSegments[sIdx])
|
||||
continue
|
||||
}
|
||||
// 已有的段:合并字段
|
||||
const oldFields = oldSegments[sIdx]
|
||||
const newFields = newSegments[sIdx]
|
||||
for (const newField of newFields) {
|
||||
const oldField = oldFields.find((f: any) => f.label === newField.label)
|
||||
if (oldField) {
|
||||
// 已有字段:如果新值非空则更新
|
||||
if (newField.value) oldField.value = newField.value
|
||||
} else {
|
||||
// 新字段:追加
|
||||
oldFields.push(newField)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 非经历类型:按字段合并
|
||||
const oldFields = oldSec.formItems as any[]
|
||||
const newFields = newSec.formItems as any[]
|
||||
for (const newField of newFields) {
|
||||
const oldField = oldFields.find((f: any) => f.label === newField.label)
|
||||
if (oldField) {
|
||||
if (newField.value) oldField.value = newField.value
|
||||
} else {
|
||||
oldFields.push(newField)
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const newSec of newSections) {
|
||||
const oldSecIdx = oldSections.findIndex((s: any) => s.title === newSec.title)
|
||||
if (oldSecIdx < 0) {
|
||||
oldSections.push(newSec)
|
||||
} else {
|
||||
oldSections[oldSecIdx] = newSec
|
||||
}
|
||||
|
||||
existing.unfilledFormData = oldSections
|
||||
existing.timestamp = Date.now()
|
||||
cacheData = existing
|
||||
}
|
||||
|
||||
existing.unfilledFormData = oldSections
|
||||
existing.timestamp = Date.now()
|
||||
cacheData = existing
|
||||
}
|
||||
|
||||
// 没有已有缓存或不是同一份简历 → 新建
|
||||
@@ -1191,10 +1119,10 @@ export async function handleAutoFillBeisen(params: AutoFillBeisenParams): Promis
|
||||
}
|
||||
}
|
||||
|
||||
localStorage.setItem("offerpie_unfilled_form", JSON.stringify(cacheData))
|
||||
await storageSet("offerpie_unfilled_form", cacheData)
|
||||
console.log(`===== OfferPie: 已缓存未填字段数据(简历: "${resumeName}") =====`)
|
||||
} catch (e) {
|
||||
console.warn("OfferPie: localStorage 缓存失败", e)
|
||||
console.warn("OfferPie: chrome.storage 缓存失败", e)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1503,15 +1431,12 @@ async function handleFillCachedData(params: FillCachedDataParams): Promise<FillC
|
||||
const { lang, resumeName, usedInputs, expandedResults, sectionResults } = params
|
||||
const result: FillCachedDataResult = { success: 0, failed: 0, skipped: 0 }
|
||||
|
||||
const cachedRaw = localStorage.getItem("offerpie_unfilled_form")
|
||||
if (!cachedRaw) {
|
||||
const cacheData = await storageGet<any>("offerpie_unfilled_form")
|
||||
if (!cacheData) {
|
||||
console.log("===== OfferPie: 阶段B2 - 无缓存数据,跳过 =====")
|
||||
return result
|
||||
}
|
||||
|
||||
let cacheData: any
|
||||
try { cacheData = JSON.parse(cachedRaw) } catch { return result }
|
||||
|
||||
if (cacheData.resumeName !== resumeName) {
|
||||
console.log(`===== OfferPie: 阶段B2 - 缓存简历名"${cacheData.resumeName}"与当前"${resumeName}"不匹配,跳过 =====`)
|
||||
return result
|
||||
|
||||
Reference in New Issue
Block a user