刷新功能
This commit is contained in:
+20
@@ -0,0 +1,20 @@
|
||||
# Process
|
||||
|
||||
## 2026-04-19
|
||||
|
||||
### 今日战利品
|
||||
- 修复了 163 邮箱顶部“刷新”按钮的识别问题。
|
||||
- 根因不是插件不知道顶部按钮在哪里,而是它用 DOM 文本做识别时,代码只认“刷新”,但 163 实际渲染出来可能是“刷 新”。
|
||||
- 给 `163` 邮箱补上了回归测试,确保以后再次遇到这种带空格的按钮文案时,脚本仍然会优先点击顶部工具栏刷新,而不是误退回到“收件箱”。
|
||||
- 额外补了更直白的刷新分支日志,后续排查时可以直接看出本次命中的是“顶部刷新”“左侧收信”还是“收件箱兜底”。
|
||||
|
||||
### 知识地图
|
||||
- 这一块属于“自动化脚本稳定性”里的 DOM 识别层。
|
||||
- 老板可以把它理解成:脚本不是靠“看见页面上方那个位置”去点按钮,而是靠“读页面结构里的标签文字和属性”去认目标。
|
||||
- 所以这里学到的核心不是某一个按钮怎么点,而是“页面自动化里,视觉上像同一个按钮,DOM 文本却可能有空格、换行、图标包裹等变体”,识别逻辑必须做抗噪处理。
|
||||
- 这部分在大神知识体系里,位置属于:前端页面结构理解 -> 浏览器自动化 -> 选择器与文本匹配鲁棒性。
|
||||
|
||||
### 下一步导航
|
||||
- 可以继续把 163 的删除兜底逻辑也做一次同类检查,因为顶部“删 除”从 DOM 结构看也可能存在同样的空格拆字风险。
|
||||
- 如果老板接下来还想继续提稳收信成功率,可以再查一层:163 顶部“刷新”点击之后,页面到底有没有真正触发新的列表请求,以及请求完成信号该监听什么。
|
||||
- 如果要把这一块做成长期稳定方案,下一步适合补“刷新动作观测点”日志,比如记录刷新前后列表首封邮件 ID、请求时间、是否出现 loading。
|
||||
+13
-2
@@ -461,9 +461,18 @@ if (!isTopFrame) {
|
||||
async function refreshInbox() {
|
||||
const toolbarBtns = document.querySelectorAll('.nui-btn .nui-btn-text');
|
||||
for (const btn of toolbarBtns) {
|
||||
if (normalizeText(btn.textContent || '') === '刷新') {
|
||||
// 163 会把“刷 新”拆成带空格的文字,所以这里要先压平空白,
|
||||
// 不然脚本明明看到了顶部刷新按钮,也会误以为没找到。
|
||||
const compactLabel = String([
|
||||
btn.textContent || '',
|
||||
btn.getAttribute?.('aria-label') || '',
|
||||
btn.getAttribute?.('title') || '',
|
||||
].join('')).replace(/\s+/g, '');
|
||||
|
||||
if (compactLabel === '刷新') {
|
||||
simulateClick(btn.closest('.nui-btn') || btn);
|
||||
console.log(MAIL163_PREFIX, 'Clicked refresh button');
|
||||
console.log(MAIL163_PREFIX, 'Clicked top toolbar refresh button');
|
||||
log('[163 邮箱] 已命中顶部工具栏“刷新”按钮');
|
||||
await sleep(800);
|
||||
return;
|
||||
}
|
||||
@@ -474,6 +483,7 @@ if (!isTopFrame) {
|
||||
if (normalizeText(btn.textContent || '').includes('收信')) {
|
||||
simulateClick(btn);
|
||||
console.log(MAIL163_PREFIX, 'Clicked receive button');
|
||||
log('[163 邮箱] 未找到顶部刷新,改用左侧“收信”按钮');
|
||||
await sleep(800);
|
||||
return;
|
||||
}
|
||||
@@ -482,6 +492,7 @@ if (!isTopFrame) {
|
||||
const inboxLink = findInboxLink();
|
||||
if (inboxLink) {
|
||||
simulateClick(inboxLink);
|
||||
log('[163 邮箱] 未找到顶部刷新或左侧“收信”,回退到点击“收件箱”');
|
||||
await sleep(800);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -146,3 +146,64 @@ return {
|
||||
assert.equal(result.code, '480382');
|
||||
assert.deepEqual(api.getOpenedMailIds(), ['mail-1']);
|
||||
});
|
||||
|
||||
test('refreshInbox prefers the top toolbar refresh button even when 163 renders the label as 刷 新', async () => {
|
||||
const bundle = [
|
||||
extractFunction('normalizeText'),
|
||||
extractFunction('refreshInbox'),
|
||||
].join('\n');
|
||||
|
||||
const api = new Function(`
|
||||
const MAIL163_PREFIX = '[MultiPage:mail-163]';
|
||||
const clickOrder = [];
|
||||
|
||||
const refreshButton = {
|
||||
tagName: 'DIV',
|
||||
textContent: '刷 新',
|
||||
};
|
||||
|
||||
const refreshLabel = {
|
||||
textContent: '刷 新',
|
||||
closest(selector) {
|
||||
return selector === '.nui-btn' ? refreshButton : null;
|
||||
},
|
||||
};
|
||||
|
||||
const inboxLink = {
|
||||
tagName: 'SPAN',
|
||||
textContent: '收件箱',
|
||||
};
|
||||
|
||||
const document = {
|
||||
querySelectorAll(selector) {
|
||||
if (selector === '.nui-btn .nui-btn-text') return [refreshLabel];
|
||||
if (selector === '.ra0') return [];
|
||||
return [];
|
||||
},
|
||||
};
|
||||
|
||||
function simulateClick(node) {
|
||||
clickOrder.push(node.textContent);
|
||||
}
|
||||
|
||||
function findInboxLink() {
|
||||
return inboxLink;
|
||||
}
|
||||
|
||||
async function sleep() {}
|
||||
function log() {}
|
||||
|
||||
${bundle}
|
||||
|
||||
return {
|
||||
refreshInbox,
|
||||
getClickOrder() {
|
||||
return clickOrder.slice();
|
||||
},
|
||||
};
|
||||
`)();
|
||||
|
||||
await api.refreshInbox();
|
||||
|
||||
assert.deepEqual(api.getClickOrder(), ['刷 新']);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user