feat(annotate): 标注 payload 加窗口身份(编号+窗格标题+内容类型/URL)——接收方无需猜哪个界面;框内文字聚合改相交即入——小框半覆盖文字也能抓到

This commit is contained in:
Aisland
2026-09-02 01:05:27 +08:00
parent 03f5ecdcaf
commit cbd126f766
2 changed files with 41 additions and 15 deletions
+21 -7
View File
@@ -16855,10 +16855,26 @@ function windowLabelOf(row, index) {
const spec = splitStore.spec;
if (!spec) return "\u7A97\u53E3?";
let num = spec.left ? 2 : 1;
if (row === "left") return "\u7A97\u53E31";
if (row === "top") return "\u7A97\u53E3" + (num + index);
num += spec.top?.length ?? 0;
return "\u7A97\u53E3" + (num + index);
if (row === "left") num = 1;
else if (row === "top") num = num + index;
else {
num += (spec.top?.length ?? 0) + index;
}
let label = "\u7A97\u53E3" + num;
const pane = row === "left" ? spec.left : row === "top" ? spec.top?.[index] : spec.main?.[index];
const title = pane?.title;
if (title) label += "\u300C" + title + "\u300D";
const tab = pane?.tabs?.[pane.active ?? 0];
const c = tab?.content;
if (c) {
try {
if (c.kind === "iframe" && c.url) label += "\uFF08\u7F51\u9875 " + new URL(c.url).hostname + "\uFF09";
else if (c.kind === "builtin") label += "\uFF08\u5185\u7F6E\xB7" + c.type + "\uFF09";
else if (c.kind === "file") label += "\uFF08\u6587\u4EF6\uFF09";
} catch {
}
}
return label;
}
function ctxOf(t) {
const el = t instanceof Element ? t : null;
@@ -16881,9 +16897,7 @@ function elementsInBox(x0, y0, x1, y1) {
if (tag === "script" || tag === "style" || tag === "svg" || tag === "path" || tag === "br" || tag === "template" || tag === "iframe") continue;
const rect = el.getBoundingClientRect();
if (rect.width <= 0 || rect.height <= 0) continue;
const cx = rect.left + rect.width / 2;
const cy = rect.top + rect.height / 2;
if (cx < L || cx > R || cy < T2 || cy > B) continue;
if (rect.right < L || rect.left > R || rect.bottom < T2 || rect.top > B) continue;
const text2 = (el.textContent || "").trim().replace(/\s+/g, " ");
if (text2.length < 1 || text2.length > 80) continue;
out.push({ text: text2, area: rect.width * rect.height });
+20 -8
View File
@@ -341,15 +341,28 @@ function cancelAnnot() {
setAnnot({ on: false, started: false, drawing: false })
}
/** 窗口编号(约定:左栏 → 顶行 → 主行,从 1 起) */
/** 窗口身份(约定:左栏 → 顶行 → 主行,从 1 起;附窗格标题与内容类型/URL,让接收方无需猜"这是哪个界面") */
function windowLabelOf(row: PaneRow, index: number): string {
const spec = splitStore.spec
if (!spec) return '窗口?'
let num = spec.left ? 2 : 1
if (row === 'left') return '窗口1'
if (row === 'top') return '窗口' + (num + index)
num += (spec.top?.length ?? 0)
return '窗口' + (num + index)
if (row === 'left') num = 1
else if (row === 'top') num = num + index
else { num += (spec.top?.length ?? 0) + index }
let label = '窗口' + num
const pane = row === 'left' ? spec.left : row === 'top' ? spec.top?.[index] : spec.main?.[index]
const title = pane?.title
if (title) label += '「' + title + '」'
const tab = pane?.tabs?.[pane.active ?? 0]
const c = tab?.content
if (c) {
try {
if (c.kind === 'iframe' && c.url) label += '(网页 ' + new URL(c.url).hostname + ')'
else if (c.kind === 'builtin') label += '(内置·' + c.type + ')'
else if (c.kind === 'file') label += '(文件)'
} catch {}
}
return label
}
/** 被点元素上下文(标签 + 类名 + 文字) */
@@ -376,9 +389,8 @@ function elementsInBox(x0: number, y0: number, x1: number, y1: number): string[]
if (tag === 'script' || tag === 'style' || tag === 'svg' || tag === 'path' || tag === 'br' || tag === 'template' || tag === 'iframe') continue
const rect = el.getBoundingClientRect()
if (rect.width <= 0 || rect.height <= 0) continue
const cx = rect.left + rect.width / 2
const cy = rect.top + rect.height / 2
if (cx < L || cx > R || cy < T || cy > B) continue
// 相交即入:元素矩形与框有任意重叠就收录(小框框住一半文字也能抓到)
if (rect.right < L || rect.left > R || rect.bottom < T || rect.top > B) continue
const text = (el.textContent || '').trim().replace(/\s+/g, ' ')
if (text.length < 1 || text.length > 80) continue
out.push({ text, area: rect.width * rect.height })