8.4 KiB
8.4 KiB
inclusion
| inclusion |
|---|
| always |
项目开发规范与注意事项
技术栈
- Plasmo + React + TypeScript
- 样式:SCSS
项目结构
src/
├── background/
│ └── index.ts # 插件后台脚本(Service Worker)
├── components/
│ ├── SidebarPanel.tsx # 侧边栏面板组件(主操作界面,自动填写入口)
│ └── SidebarPanel.scss # 侧边栏样式
├── contents/
│ └── sidebar.tsx # Content Script 入口(注入侧边栏到页面)
├── lib/
│ ├── types.ts # 所有共享类型定义(简历接口、表单标签、匹配字段、UI组件库配置)
│ ├── constants.ts # 常量数据(JOB_FORM_LABELS标签数组、TEST_FILL_DATA测试数据、UI_LIB_PICKER_CONFIGS组件库配置、SPECIAL_LABEL_PLACEHOLDERS特殊标签修正配置)
│ ├── dom.ts # DOM工具(extractDomStructure提取DOM树、detectPageLanguage语言检测、isJobApplicationForm表单页判断、buildSelector选择器生成)
│ ├── formMatcher.ts # 表单字段匹配(matchFormFields在DOM中匹配标签对应的input、findNearestInput查找input、fixSpecialLabelInput特殊标签修正)
│ ├── pickerDetector.ts # 选择器识别(detectPickerField检测字段是否为选择器类型,通过UI组件库类名/提示文字/主动点击DOM差异对比三种方式)
│ ├── pickerFill.ts # 选择器选项匹配与点击(fuzzyMatchScore模糊匹配、clickBestOptionInDropdown弹出层选项点击、findAndClickOptionInVisiblePopups全局弹出层搜索)
│ ├── datePicker.ts # 日期选择器填写(fillDatePicker日期填写、tryClickMonth月份点击、tryClickDay日期点击)
│ ├── autofill.ts # 自动填写核心(delay/forceSetValue工具函数、fillMatchedField字段填写入口、fillPickerField选择器填写含DOM差异对比、closePopup弹窗关闭、fillAllFields批量填写)
│ ├── resumeUpload.ts # 简历上传(detectAndUploadResume检测上传按钮并从OSS下载注入文件)
│ └── api.ts # API接口模块
└── assets/
├── icon.png # 插件图标
└── icon1.png # 备用图标
编码规范
- 页面结构和ts的常量变量和方法都要加中文注释
- 重要逻辑加【注意】标记防止误删(如fillPickerField的DOM差异对比逻辑)
注意事项
- 项目接口有Java后端和Python AI后端两种,如果是联调加入新接口,一定要确认有没有说是哪个后端的
- fillPickerField中的DOM差异对比弹出层检测是核心机制,不要简化或删除
- detectPickerField的方式3(主动点击检测DOM变化)是自建组件选择器识别的关键,不要删除
- UI_LIB_PICKER_CONFIGS里不要加容易误匹配的配置(如之前Beisen Phoenix被误匹配到新东方自建网站)
填充操作核心规范
- 所有字段填充必须走
fillMatchedField统一入口,禁止在外部自行编写填充逻辑 - 选择器类型字段(下拉、日期、月份、级联等)绝对不能用
forceSetValue直接写值,这类 input 通常是受控组件,直接写值无效 - 选择器类型检测必须走
detectPickerField统一入口(pickerDetector.ts),禁止在外部自行判断字段是否为选择器- detectPickerField 内部已封装三种检测方式:UI组件库类名匹配 → 提示文字检测 → 主动点击DOM差异对比
- 不要自行通过 readonly、class 等属性简单判断是否为选择器,这样会漏判
- 时间字段(开始时间/结束时间/起止时间)如果没有找到
placeholder="年"/"月"的下拉输入框,必须标记isPicker=true走fillMatchedField→fillPickerField→fillDatePicker→tryFillMonthPanel已封装的完整链路 - 禁止在新增代码中自行编写选择器展开、月份点击、日期导航等操作逻辑,必须先查看项目中已封装的方法并直接引用:
- 选择器类型检测 →
pickerDetector.ts(detectPickerField) - 日期/月份选择器操作 →
datePicker.ts(fillDatePicker / tryFillMonthPanel / navigateToYearMonth / clickDayCell) - 下拉选项匹配与点击 →
pickerFill.ts(clickBestOptionInDropdown / findAndClickOptionInVisiblePopups) - 选择器展开与DOM差异检测 →
autofill.ts中的fillPickerField - 单选按钮点击 →
autofill.ts中的fillRadioField - 搜索型选择器 →
autofill.ts中的fillSearchPickerField - 年月下拉选择器 →
autofill.ts中的fillYearMonthPicker
- 选择器类型检测 →
datePicker.ts中的按钮探测逻辑(detectNavButtons:逐个点击观察年月变化)是通用日期选择器适配的核心,不要简化或删除
经历段落定位核心规范
experienceSection.ts中的段落容器定位逻辑(DOM 差异对比 + 特征重建)是5大经历区域填写的核心,不可擅自修改或简化- 核心原理:
- 点击添加按钮前后,用
snapshotElementsInRange/diffSnapshots/findTopLevelNewElements(dom.ts)对比 DOM 快照差异 - 找到新增的顶层容器(一段经历的完整 DOM),记住它的 tag + className 前缀作为段容器特征
- 同时保存新增段容器的 DOM 引用(
lastNewContainerEl) - 所有段添加完后,从
lastNewContainerEl.parentElement出发,在父级 children 中匹配所有同特征兄弟容器 - 按 DOM 顺序重建
segmentRanges数组,确保每段经历的 containerElement 精确对应
- 点击添加按钮前后,用
- 禁止用 input 差集(
beforeInputs)来定位段容器——React 重渲染会导致原始段的 input 节点被重建,差集不可靠 - 禁止依赖
titleElement存活状态来做重建——React 重渲染可能使 titleElement 脱离 DOM - 对于初始有1段且不需要添加的经历:走
detectFirstSegment的 fallback 逻辑(无同级兄弟时 containerElement 可能为 null,matchFormFieldsInRange有 fallback 用 startElement/endElement 范围搜索)
下拉选择器弹出层搜索核心规范
- 弹出层检测不依赖任何固定类名,全部走 DOM 差异对比(点击前后全页面快照对比新增/新可见元素)
- 禁止使用 POPUP_SELECTORS 或任何固定 CSS 选择器来检测弹出层,必须走全页面可见性差异对比(
offsetHeight > 0 && offsetWidth > 0) - pickerDetector.ts 方式3(主动点击检测)的核心约束:
- 检测到弹出层后 禁止关闭弹出层(不调用 dismissPopup)
- 将弹出层 DOM 引用保存到
field.pickerDropdownElement - fillPickerField 步骤0 直接在已有弹出层内搜索,避免二次点击触发 toggle 关闭
- 弹出层由用户选择后自动关闭,无需手动干预
- 选项搜索必须限定在检测到的弹出层元素内,禁止全页面搜:
findAndClickOptionInVisiblePopups(fillValue, labelText, popupEl?)没有popupEl时直接返回 false,不做全页面搜fillPickerField步骤0 用field.pickerDropdownElement(pickerDetector 保存的引用)在弹出层内搜索fillPickerField步骤4 在 DOM 差异检测到的dropdownEl内搜索fillSearchPickerField轮询检测到的newPopupEl传给clickBestOptionInDropdown和findAndClickOptionInVisiblePopups
- fillPickerField 步骤0:pickerDetector 可能已展开弹出层(toggle 冲突问题),所以在步骤1之前先尝试在当前页面搜索匹配选项,避免二次点击关闭弹出层。不可删除此步骤
- isAsyncDropdown 字段的特殊处理(FormLabelItem.isAsyncDropdown = true):
- 接口异步下拉字段(如学校、专业)输入值后需轮询等待接口返回数据(最多3秒)
- 弹出层检测阈值为 ≥1 个可见子元素(普通字段为 ≥2)
- 检测到弹出层后优先用
clickBestOptionInDropdown(newPopupEl)在弹出层内直接做文字匹配 - 禁止对 isAsyncDropdown 字段走
tryClickDropdownListItem全页面搜(选项数可能为1,全页面搜会被其他同规格元素干扰)
pickerFill.ts中groupBySpec/findVisibleListGroups的同规格标签组阈值为 ≥2(不可改回 ≥3,否则只有2个选项的下拉列表会漏匹配)clickBestOptionInDropdown是在指定弹出层 DOM 内递归搜所有可见叶子文字节点做模糊匹配的核心方法,不可简化其递归逻辑