输入框修改颜色微调,弹出层下拉选项数据收集修改关闭弹出层的办法,飞书经历添加按钮添加专属兼容
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
|
||||
import { EXPERIENCE_SECTION_CONFIGS, JOB_FORM_LABELS } from "./constants"
|
||||
import { delay } from "~utils/delay"
|
||||
import { simulateClick } from "~utils/domEvent"
|
||||
import { snapshotElementsInRange, diffSnapshots, findTopLevelNewElements } from "./dom"
|
||||
import { findNearestInput } from "./formMatcher"
|
||||
import type { ExperienceSection, ExperienceSectionConfig, ResumeData } from "./types"
|
||||
@@ -732,12 +733,50 @@ function getDirectText(el: Element): string {
|
||||
*
|
||||
* 【注意】验证 fullText 不能包含其他经历类型的标题关键词,防止跨区域误匹配
|
||||
*/
|
||||
|
||||
/**
|
||||
* 【飞书专用】在大标题到下一大标题范围内查找添加按钮
|
||||
* 飞书招聘平台的添加按钮使用 ud__button ud__button--text 类名的 button 标签
|
||||
* 通用 findAddButton 在飞书上第二次定位时会误匹配到包含字段文字的大容器,因此飞书走此独立逻辑
|
||||
*
|
||||
* @param titleEl - 当前经历区块的大标题元素
|
||||
* @param nextTitleEl - 下一个大标题元素(范围边界)
|
||||
* @returns 找到的添加按钮 button 元素,未找到返回 null
|
||||
*/
|
||||
function findFeishuAddButton(titleEl: Element, nextTitleEl: Element | null): Element | null {
|
||||
// 在范围内查找所有 button.ud__button.ud__button--text
|
||||
const allButtons = document.querySelectorAll("button.ud__button.ud__button--text")
|
||||
for (const btn of Array.from(allButtons)) {
|
||||
// 判断是否在 titleEl 之后
|
||||
const afterTitle = !!(titleEl.compareDocumentPosition(btn) & Node.DOCUMENT_POSITION_FOLLOWING)
|
||||
if (!afterTitle) continue
|
||||
// 判断是否在 nextTitleEl 之前(如果有下一大标题)
|
||||
if (nextTitleEl) {
|
||||
const beforeNext = !!(nextTitleEl.compareDocumentPosition(btn) & Node.DOCUMENT_POSITION_PRECEDING)
|
||||
if (!beforeNext) continue
|
||||
}
|
||||
// 确认按钮文字含"添加"关键词(排除删除等其他操作按钮)
|
||||
const btnText = btn.textContent?.trim() || ""
|
||||
if (btnText.includes("添加") || btnText.includes("Add")) {
|
||||
return btn
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export function findAddButton(
|
||||
titleEl: Element,
|
||||
nextTitleEl: Element | null,
|
||||
config: ExperienceSectionConfig,
|
||||
lang: "zh" | "en"
|
||||
): Element | null {
|
||||
// 【飞书特有逻辑】飞书招聘平台的添加按钮是 button.ud__button.ud__button--text
|
||||
// 通用逻辑在飞书上第二次查找会误匹配到整个段容器,因此飞书走独立的定位策略
|
||||
if (window.location.hostname.includes("feishu.cn")) {
|
||||
const feishuBtn = findFeishuAddButton(titleEl, nextTitleEl)
|
||||
if (feishuBtn) return feishuBtn
|
||||
}
|
||||
|
||||
const addKeywords = lang === "zh" ? config.addButtonZh : config.addButtonEn
|
||||
// 当前经历类型的标题关键词(用于验证按钮确实属于本区块)
|
||||
const sectionKeywords = lang === "zh" ? config.zh : config.en
|
||||
@@ -842,7 +881,7 @@ export async function clickAddButton(
|
||||
|
||||
// 逐层点击,每层点击后检测 input 数量是否增加
|
||||
for (const target of clickTargets) {
|
||||
target.click()
|
||||
simulateClick(target)
|
||||
await delay("high")
|
||||
|
||||
const afterInputs = findInputsInRange(titleEl, nextTitleEl)
|
||||
|
||||
+25
-2
@@ -15,6 +15,7 @@ import type { MatchedFormField, UnmatchedFormField } from "./types"
|
||||
import { isRequiredField, setFieldHighlight } from "./formStyle"
|
||||
import { findLabelForInput } from "./labelFinder"
|
||||
import { delay } from "~utils/delay"
|
||||
import { simulateClick } from "~utils/domEvent"
|
||||
|
||||
// ====================================================================
|
||||
// 一、类型定义
|
||||
@@ -1236,12 +1237,34 @@ export async function collectPickerOptionTexts(fieldStats: TitleStat[]): Promise
|
||||
await delay("midH")
|
||||
}
|
||||
|
||||
// 循环结束后,点击 document.documentElement 关闭最后一个可能残留的弹出层
|
||||
document.documentElement.dispatchEvent(new MouseEvent("click", { bubbles: true, clientX: 0, clientY: 0 }))
|
||||
// 循环结束后,点击第一个已识别字段的输入框,通过 simulateClick 完整事件链关闭所有残留弹出层
|
||||
const firstInputEl = findFirstVisibleInput(fieldStats)
|
||||
if (firstInputEl) {
|
||||
simulateClick(firstInputEl)
|
||||
await delay("mid")
|
||||
}
|
||||
|
||||
return optionTexts
|
||||
}
|
||||
|
||||
/**
|
||||
* 从字段统计列表中找到第一个可见的 input 元素
|
||||
* 用于点击关闭残留弹出层(simulateClick 触发完整事件链,兼容所有 UI 组件库)
|
||||
*
|
||||
* @param fieldStats - scanPageFields 返回的按大标题分组的字段统计数组
|
||||
* @returns 第一个可见的 input HTMLElement,找不到返回 null
|
||||
*/
|
||||
function findFirstVisibleInput(fieldStats: TitleStat[]): HTMLElement | null {
|
||||
for (const ts of fieldStats) {
|
||||
for (const f of ts.fields) {
|
||||
if (!f.inputElement) continue
|
||||
const el = f.inputElement as HTMLElement
|
||||
if (el.offsetHeight > 0 && el.offsetWidth > 0) return el
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归收集指定元素内所有可见叶子节点的文字
|
||||
* 只收集有效文字(长度 2-30,至少含1个汉字或2个英文字母),排除纯数字/纯符号
|
||||
|
||||
@@ -12,7 +12,7 @@ const COLOR_MAP: Record<HighlightColor, string> = {
|
||||
green: "#b7ffc5", // 淡绿色
|
||||
greenTwo: "#b7ffc6", // 淡绿色2
|
||||
red: "#ffb7b7", // 淡红色
|
||||
yellow: "#fff", // 白色
|
||||
yellow: "transparent", // 透明色
|
||||
}
|
||||
|
||||
/** 常见的表单项容器选择器(与 formMatcher.ts 保持一致) */
|
||||
|
||||
Reference in New Issue
Block a user