From e8c306946fbee88527b9f7c2e4ac7f29f69e2ff6 Mon Sep 17 00:00:00 2001 From: xuxin <15279969124@163.com> Date: Tue, 4 Aug 2026 16:29:58 +0800 Subject: [PATCH] =?UTF-8?q?=E7=BC=93=E5=AD=98=E8=A1=A8=E5=8D=95=E5=A1=AB?= =?UTF-8?q?=E5=86=99=E9=98=B6=E6=AE=B5=E5=8E=BB=E6=8E=89=E7=B1=BB=E5=90=8D?= =?UTF-8?q?=E9=99=90=E5=88=B6=E7=94=A8findLabelForInput=E8=A7=84=E5=88=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/handlers/handleAutoFillBeisen.ts | 7 +-- src/handlers/handleAutoFillCommon.ts | 83 ++++++---------------------- src/handlers/handleAutoFillFeishu.ts | 83 ++++++---------------------- src/handlers/handleAutoFillHotjob.ts | 83 ++++++---------------------- src/handlers/handleAutoFillMoka.ts | 83 ++++++---------------------- 5 files changed, 69 insertions(+), 270 deletions(-) diff --git a/src/handlers/handleAutoFillBeisen.ts b/src/handlers/handleAutoFillBeisen.ts index f3a6b5f..75b463b 100644 --- a/src/handlers/handleAutoFillBeisen.ts +++ b/src/handlers/handleAutoFillBeisen.ts @@ -926,12 +926,7 @@ export async function handleAutoFillBeisen(params: AutoFillBeisenParams): Promis if (allTitles.length > 0) { const INPUT_SEL_JSON = "input:not([type='hidden']):not([type='submit']):not([type='button']):not([type='checkbox']):not([type='radio']):not([type='file']):not([disabled]), textarea:not([disabled])" - const FORM_ITEM_SELS_JSON = [ - ".form-item", ".form-group", ".form-field", - ".el-form-item", ".ant-form-item", ".ant-row", - ".arco-form-item", ".t-form-item", ".n-form-item", - "[class*='form-item']", "[class*='form-group']", "[class*='formItem']", - ] + const JSON_EXCLUDE_LABELS = ["请输入", "输入", ":", ":", "请选择", "选择", "*", "必填"] for (let tIdx = 0; tIdx < allTitles.length; tIdx++) { diff --git a/src/handlers/handleAutoFillCommon.ts b/src/handlers/handleAutoFillCommon.ts index 8992bdc..3bb3ae7 100644 --- a/src/handlers/handleAutoFillCommon.ts +++ b/src/handlers/handleAutoFillCommon.ts @@ -910,12 +910,7 @@ export async function handleAutoFillCommon(params: AutoFillCommonParams): Promis if (allTitles.length > 0) { const INPUT_SEL_JSON = "input:not([type='hidden']):not([type='submit']):not([type='button']):not([type='checkbox']):not([type='radio']):not([type='file']):not([disabled]), textarea:not([disabled])" - const FORM_ITEM_SELS_JSON = [ - ".form-item", ".form-group", ".form-field", - ".el-form-item", ".ant-form-item", ".ant-row", - ".arco-form-item", ".t-form-item", ".n-form-item", - "[class*='form-item']", "[class*='form-group']", "[class*='formItem']", - ] + const JSON_EXCLUDE_LABELS = ["请输入", "输入", ":", ":", "请选择", "选择", "*", "必填"] for (let tIdx = 0; tIdx < allTitles.length; tIdx++) { @@ -1151,13 +1146,7 @@ export async function handleAutoFillCommon(params: AutoFillCommonParams): Promis // 【独立模块】可以通过注释 handleAutoFillCommon 中的调用行来禁用 // ============================================================ -/** 阶段B2 表单项容器选择器 */ -const B2_FORM_ITEM_SELS = [ - ".form-item", ".form-group", ".form-field", - ".el-form-item", ".ant-form-item", ".ant-row", - ".arco-form-item", ".t-form-item", ".n-form-item", - "[class*='form-item']", "[class*='form-group']", "[class*='formItem']", -] + /** 阶段B2 input 选择器 */ const B2_INPUT_SEL = "input:not([type='hidden']):not([type='submit']):not([type='button']):not([type='checkbox']):not([type='radio']):not([type='file']):not([disabled]), textarea:not([disabled])" @@ -1188,6 +1177,7 @@ interface FillCachedDataResult { /** * 阶段B2:在指定大标题范围内,通过标签文字查找对应的 input 元素 + * 使用 findLabelForInput 统一标签定位(和缓存收集时一致),不依赖容器类名 */ function b2FindInputByLabel( labelText: string, @@ -1202,27 +1192,10 @@ function b2FindInputByLabel( const beforeNext = !nextTitleEl || !!(nextTitleEl.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_PRECEDING) if (!afterTitle || !beforeNext) continue - let container: Element | null = null - for (const sel of B2_FORM_ITEM_SELS) { - 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 (B2_EXCLUDE_LABELS.some((ex) => directText === ex)) continue - // 标签文字必须严格全名匹配,不走 includes - if (directText === labelText && - (el.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_FOLLOWING)) { - return inp as HTMLInputElement | HTMLTextAreaElement - } - } + // 用 findLabelForInput 获取该 input 对应的标签文字,和缓存收集时逻辑一致 + const { labelText: detectedLabel } = findLabelForInput(inp) + if (detectedLabel && detectedLabel.trim() === labelText) { + return inp as HTMLInputElement | HTMLTextAreaElement } } return null @@ -1230,6 +1203,7 @@ function b2FindInputByLabel( /** * 阶段B2:在指定容器内,通过标签文字查找对应的 input 元素 + * 使用 findLabelForInput 统一标签定位(和缓存收集时一致),不依赖容器类名 */ function b2FindInputByLabelInContainer( labelText: string, @@ -1239,27 +1213,10 @@ function b2FindInputByLabelInContainer( const allInputs = containerEl.querySelectorAll(B2_INPUT_SEL) for (const inp of Array.from(allInputs)) { if (usedInputs.has(inp)) continue - let formItem: Element | null = null - for (const sel of B2_FORM_ITEM_SELS) { - formItem = inp.closest(sel) - if (formItem) break - } - if (formItem) { - const labelEls = formItem.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 (B2_EXCLUDE_LABELS.some((ex) => directText === ex)) continue - // 标签文字必须严格全名匹配,不走 includes - if (directText === labelText && - (el.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_FOLLOWING)) { - return inp as HTMLInputElement | HTMLTextAreaElement - } - } + // 用 findLabelForInput 获取该 input 对应的标签文字,和缓存收集时逻辑一致 + const { labelText: detectedLabel } = findLabelForInput(inp) + if (detectedLabel && detectedLabel.trim() === labelText) { + return inp as HTMLInputElement | HTMLTextAreaElement } } return null @@ -1428,23 +1385,17 @@ async function handleFillCachedData(params: FillCachedDataParams): Promise n.nodeType === Node.TEXT_NODE).map((n) => n.textContent?.trim()).filter(Boolean).join("") - if (t && t.length <= 30 && !B2_EXCLUDE_LABELS.some((ex) => t === ex) && (el.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_FOLLOWING)) { - labelsInRange.push(t) - break - } + // 用 findLabelForInput 获取标签文字,和缓存收集时逻辑一致 + const { labelText: detectedLabel } = findLabelForInput(inp) + if (detectedLabel && detectedLabel.trim() && !B2_EXCLUDE_LABELS.some((ex) => detectedLabel.trim() === ex)) { + labelsInRange.push(detectedLabel.trim()) } } const labelCounts = new Map() diff --git a/src/handlers/handleAutoFillFeishu.ts b/src/handlers/handleAutoFillFeishu.ts index 050d50d..ba4df3d 100644 --- a/src/handlers/handleAutoFillFeishu.ts +++ b/src/handlers/handleAutoFillFeishu.ts @@ -916,12 +916,7 @@ export async function handleAutoFillFeishu(params: AutoFillFeishuParams): Promis if (allTitles.length > 0) { const INPUT_SEL_JSON = "input:not([type='hidden']):not([type='submit']):not([type='button']):not([type='checkbox']):not([type='radio']):not([type='file']):not([disabled]), textarea:not([disabled])" - const FORM_ITEM_SELS_JSON = [ - ".form-item", ".form-group", ".form-field", - ".el-form-item", ".ant-form-item", ".ant-row", - ".arco-form-item", ".t-form-item", ".n-form-item", - "[class*='form-item']", "[class*='form-group']", "[class*='formItem']", - ] + const JSON_EXCLUDE_LABELS = ["请输入", "输入", ":", ":", "请选择", "选择", "*", "必填"] for (let tIdx = 0; tIdx < allTitles.length; tIdx++) { @@ -1157,13 +1152,7 @@ export async function handleAutoFillFeishu(params: AutoFillFeishuParams): Promis // 【独立模块】可以通过注释 handleAutoFillFeishu 中的调用行来禁用 // ============================================================ -/** 阶段B2 表单项容器选择器 */ -const B2_FORM_ITEM_SELS = [ - ".form-item", ".form-group", ".form-field", - ".el-form-item", ".ant-form-item", ".ant-row", - ".arco-form-item", ".t-form-item", ".n-form-item", - "[class*='form-item']", "[class*='form-group']", "[class*='formItem']", -] + /** 阶段B2 input 选择器 */ const B2_INPUT_SEL = "input:not([type='hidden']):not([type='submit']):not([type='button']):not([type='checkbox']):not([type='radio']):not([type='file']):not([disabled]), textarea:not([disabled])" @@ -1194,6 +1183,7 @@ interface FillCachedDataResult { /** * 阶段B2:在指定大标题范围内,通过标签文字查找对应的 input 元素 + * 使用 findLabelForInput 统一标签定位(和缓存收集时一致),不依赖容器类名 */ function b2FindInputByLabel( labelText: string, @@ -1208,27 +1198,10 @@ function b2FindInputByLabel( const beforeNext = !nextTitleEl || !!(nextTitleEl.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_PRECEDING) if (!afterTitle || !beforeNext) continue - let container: Element | null = null - for (const sel of B2_FORM_ITEM_SELS) { - 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 (B2_EXCLUDE_LABELS.some((ex) => directText === ex)) continue - // 标签文字必须严格全名匹配,不走 includes - if (directText === labelText && - (el.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_FOLLOWING)) { - return inp as HTMLInputElement | HTMLTextAreaElement - } - } + // 用 findLabelForInput 获取该 input 对应的标签文字,和缓存收集时逻辑一致 + const { labelText: detectedLabel } = findLabelForInput(inp) + if (detectedLabel && detectedLabel.trim() === labelText) { + return inp as HTMLInputElement | HTMLTextAreaElement } } return null @@ -1236,6 +1209,7 @@ function b2FindInputByLabel( /** * 阶段B2:在指定容器内,通过标签文字查找对应的 input 元素 + * 使用 findLabelForInput 统一标签定位(和缓存收集时一致),不依赖容器类名 */ function b2FindInputByLabelInContainer( labelText: string, @@ -1245,27 +1219,10 @@ function b2FindInputByLabelInContainer( const allInputs = containerEl.querySelectorAll(B2_INPUT_SEL) for (const inp of Array.from(allInputs)) { if (usedInputs.has(inp)) continue - let formItem: Element | null = null - for (const sel of B2_FORM_ITEM_SELS) { - formItem = inp.closest(sel) - if (formItem) break - } - if (formItem) { - const labelEls = formItem.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 (B2_EXCLUDE_LABELS.some((ex) => directText === ex)) continue - // 标签文字必须严格全名匹配,不走 includes - if (directText === labelText && - (el.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_FOLLOWING)) { - return inp as HTMLInputElement | HTMLTextAreaElement - } - } + // 用 findLabelForInput 获取该 input 对应的标签文字,和缓存收集时逻辑一致 + const { labelText: detectedLabel } = findLabelForInput(inp) + if (detectedLabel && detectedLabel.trim() === labelText) { + return inp as HTMLInputElement | HTMLTextAreaElement } } return null @@ -1434,23 +1391,17 @@ async function handleFillCachedData(params: FillCachedDataParams): Promise n.nodeType === Node.TEXT_NODE).map((n) => n.textContent?.trim()).filter(Boolean).join("") - if (t && t.length <= 30 && !B2_EXCLUDE_LABELS.some((ex) => t === ex) && (el.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_FOLLOWING)) { - labelsInRange.push(t) - break - } + // 用 findLabelForInput 获取标签文字,和缓存收集时逻辑一致 + const { labelText: detectedLabel } = findLabelForInput(inp) + if (detectedLabel && detectedLabel.trim() && !B2_EXCLUDE_LABELS.some((ex) => detectedLabel.trim() === ex)) { + labelsInRange.push(detectedLabel.trim()) } } const labelCounts = new Map() diff --git a/src/handlers/handleAutoFillHotjob.ts b/src/handlers/handleAutoFillHotjob.ts index e452edf..6d7786b 100644 --- a/src/handlers/handleAutoFillHotjob.ts +++ b/src/handlers/handleAutoFillHotjob.ts @@ -916,12 +916,7 @@ export async function handleAutoFillHotjob(params: AutoFillHotjobParams): Promis if (allTitles.length > 0) { const INPUT_SEL_JSON = "input:not([type='hidden']):not([type='submit']):not([type='button']):not([type='checkbox']):not([type='radio']):not([type='file']):not([disabled]), textarea:not([disabled])" - const FORM_ITEM_SELS_JSON = [ - ".form-item", ".form-group", ".form-field", - ".el-form-item", ".ant-form-item", ".ant-row", - ".arco-form-item", ".t-form-item", ".n-form-item", - "[class*='form-item']", "[class*='form-group']", "[class*='formItem']", - ] + const JSON_EXCLUDE_LABELS = ["请输入", "输入", ":", ":", "请选择", "选择", "*", "必填"] for (let tIdx = 0; tIdx < allTitles.length; tIdx++) { @@ -1157,13 +1152,7 @@ export async function handleAutoFillHotjob(params: AutoFillHotjobParams): Promis // 【独立模块】可以通过注释 handleAutoFillHotjob 中的调用行来禁用 // ============================================================ -/** 阶段B2 表单项容器选择器 */ -const B2_FORM_ITEM_SELS = [ - ".form-item", ".form-group", ".form-field", - ".el-form-item", ".ant-form-item", ".ant-row", - ".arco-form-item", ".t-form-item", ".n-form-item", - "[class*='form-item']", "[class*='form-group']", "[class*='formItem']", -] + /** 阶段B2 input 选择器 */ const B2_INPUT_SEL = "input:not([type='hidden']):not([type='submit']):not([type='button']):not([type='checkbox']):not([type='radio']):not([type='file']):not([disabled]), textarea:not([disabled])" @@ -1194,6 +1183,7 @@ interface FillCachedDataResult { /** * 阶段B2:在指定大标题范围内,通过标签文字查找对应的 input 元素 + * 使用 findLabelForInput 统一标签定位(和缓存收集时一致),不依赖容器类名 */ function b2FindInputByLabel( labelText: string, @@ -1208,27 +1198,10 @@ function b2FindInputByLabel( const beforeNext = !nextTitleEl || !!(nextTitleEl.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_PRECEDING) if (!afterTitle || !beforeNext) continue - let container: Element | null = null - for (const sel of B2_FORM_ITEM_SELS) { - 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 (B2_EXCLUDE_LABELS.some((ex) => directText === ex)) continue - // 标签文字必须严格全名匹配,不走 includes - if (directText === labelText && - (el.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_FOLLOWING)) { - return inp as HTMLInputElement | HTMLTextAreaElement - } - } + // 用 findLabelForInput 获取该 input 对应的标签文字,和缓存收集时逻辑一致 + const { labelText: detectedLabel } = findLabelForInput(inp) + if (detectedLabel && detectedLabel.trim() === labelText) { + return inp as HTMLInputElement | HTMLTextAreaElement } } return null @@ -1236,6 +1209,7 @@ function b2FindInputByLabel( /** * 阶段B2:在指定容器内,通过标签文字查找对应的 input 元素 + * 使用 findLabelForInput 统一标签定位(和缓存收集时一致),不依赖容器类名 */ function b2FindInputByLabelInContainer( labelText: string, @@ -1245,27 +1219,10 @@ function b2FindInputByLabelInContainer( const allInputs = containerEl.querySelectorAll(B2_INPUT_SEL) for (const inp of Array.from(allInputs)) { if (usedInputs.has(inp)) continue - let formItem: Element | null = null - for (const sel of B2_FORM_ITEM_SELS) { - formItem = inp.closest(sel) - if (formItem) break - } - if (formItem) { - const labelEls = formItem.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 (B2_EXCLUDE_LABELS.some((ex) => directText === ex)) continue - // 标签文字必须严格全名匹配,不走 includes - if (directText === labelText && - (el.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_FOLLOWING)) { - return inp as HTMLInputElement | HTMLTextAreaElement - } - } + // 用 findLabelForInput 获取该 input 对应的标签文字,和缓存收集时逻辑一致 + const { labelText: detectedLabel } = findLabelForInput(inp) + if (detectedLabel && detectedLabel.trim() === labelText) { + return inp as HTMLInputElement | HTMLTextAreaElement } } return null @@ -1434,23 +1391,17 @@ async function handleFillCachedData(params: FillCachedDataParams): Promise n.nodeType === Node.TEXT_NODE).map((n) => n.textContent?.trim()).filter(Boolean).join("") - if (t && t.length <= 30 && !B2_EXCLUDE_LABELS.some((ex) => t === ex) && (el.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_FOLLOWING)) { - labelsInRange.push(t) - break - } + // 用 findLabelForInput 获取标签文字,和缓存收集时逻辑一致 + const { labelText: detectedLabel } = findLabelForInput(inp) + if (detectedLabel && detectedLabel.trim() && !B2_EXCLUDE_LABELS.some((ex) => detectedLabel.trim() === ex)) { + labelsInRange.push(detectedLabel.trim()) } } const labelCounts = new Map() diff --git a/src/handlers/handleAutoFillMoka.ts b/src/handlers/handleAutoFillMoka.ts index 140c1d9..e294838 100644 --- a/src/handlers/handleAutoFillMoka.ts +++ b/src/handlers/handleAutoFillMoka.ts @@ -916,12 +916,7 @@ export async function handleAutoFillMoka(params: AutoFillMokaParams): Promise 0) { const INPUT_SEL_JSON = "input:not([type='hidden']):not([type='submit']):not([type='button']):not([type='checkbox']):not([type='radio']):not([type='file']):not([disabled]), textarea:not([disabled])" - const FORM_ITEM_SELS_JSON = [ - ".form-item", ".form-group", ".form-field", - ".el-form-item", ".ant-form-item", ".ant-row", - ".arco-form-item", ".t-form-item", ".n-form-item", - "[class*='form-item']", "[class*='form-group']", "[class*='formItem']", - ] + const JSON_EXCLUDE_LABELS = ["请输入", "输入", ":", ":", "请选择", "选择", "*", "必填"] for (let tIdx = 0; tIdx < allTitles.length; tIdx++) { @@ -1157,13 +1152,7 @@ export async function handleAutoFillMoka(params: AutoFillMokaParams): Promise n.nodeType === Node.TEXT_NODE) - .map((n) => n.textContent?.trim()) - .filter(Boolean) - .join("") - if (!directText || directText.length > 30) continue - if (B2_EXCLUDE_LABELS.some((ex) => directText === ex)) continue - // 标签文字必须严格全名匹配,不走 includes - if (directText === labelText && - (el.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_FOLLOWING)) { - return inp as HTMLInputElement | HTMLTextAreaElement - } - } + // 用 findLabelForInput 获取该 input 对应的标签文字,和缓存收集时逻辑一致 + const { labelText: detectedLabel } = findLabelForInput(inp) + if (detectedLabel && detectedLabel.trim() === labelText) { + return inp as HTMLInputElement | HTMLTextAreaElement } } return null @@ -1236,6 +1209,7 @@ function b2FindInputByLabel( /** * 阶段B2:在指定容器内,通过标签文字查找对应的 input 元素 + * 使用 findLabelForInput 统一标签定位(和缓存收集时一致),不依赖容器类名 */ function b2FindInputByLabelInContainer( labelText: string, @@ -1245,27 +1219,10 @@ function b2FindInputByLabelInContainer( const allInputs = containerEl.querySelectorAll(B2_INPUT_SEL) for (const inp of Array.from(allInputs)) { if (usedInputs.has(inp)) continue - let formItem: Element | null = null - for (const sel of B2_FORM_ITEM_SELS) { - formItem = inp.closest(sel) - if (formItem) break - } - if (formItem) { - const labelEls = formItem.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 (B2_EXCLUDE_LABELS.some((ex) => directText === ex)) continue - // 标签文字必须严格全名匹配,不走 includes - if (directText === labelText && - (el.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_FOLLOWING)) { - return inp as HTMLInputElement | HTMLTextAreaElement - } - } + // 用 findLabelForInput 获取该 input 对应的标签文字,和缓存收集时逻辑一致 + const { labelText: detectedLabel } = findLabelForInput(inp) + if (detectedLabel && detectedLabel.trim() === labelText) { + return inp as HTMLInputElement | HTMLTextAreaElement } } return null @@ -1434,23 +1391,17 @@ async function handleFillCachedData(params: FillCachedDataParams): Promise n.nodeType === Node.TEXT_NODE).map((n) => n.textContent?.trim()).filter(Boolean).join("") - if (t && t.length <= 30 && !B2_EXCLUDE_LABELS.some((ex) => t === ex) && (el.compareDocumentPosition(inp) & Node.DOCUMENT_POSITION_FOLLOWING)) { - labelsInRange.push(t) - break - } + // 用 findLabelForInput 获取标签文字,和缓存收集时逻辑一致 + const { labelText: detectedLabel } = findLabelForInput(inp) + if (detectedLabel && detectedLabel.trim() && !B2_EXCLUDE_LABELS.some((ex) => detectedLabel.trim() === ex)) { + labelsInRange.push(detectedLabel.trim()) } } const labelCounts = new Map()