function textOf(node) { return ((node && (node.innerText || node.textContent || '')) || '').replace(/\s+/g, ' ').trim(); } function isVisible(el) { if (!el || !el.getBoundingClientRect) return false; const rect = el.getBoundingClientRect(); const style = window.getComputedStyle(el); return rect.width > 0 && rect.height > 0 && style.display !== 'none' && style.visibility !== 'hidden'; } function clickElement(el) { el.scrollIntoView({ block: 'center', inline: 'nearest' }); if (el.focus) el.focus(); for (const eventName of ['pointerdown', 'mousedown', 'pointerup', 'mouseup']) { el.dispatchEvent(new MouseEvent(eventName, { bubbles: true, cancelable: true, view: window })); } el.click(); } function summarize(el) { return { tag: el.tagName, text: textOf(el).slice(0, 500), attrs: Array.from(el.attributes || []).reduce((acc, attr) => { acc[attr.name] = attr.value; return acc; }, {}), outerHTML: (el.outerHTML || '').slice(0, 1000), }; } const view = document.querySelector('[data-testid="complete-drafts-view"]'); if (!view) return { ok: false, reason: 'complete drafts view not found' }; const selectedRows = Array.from(view.querySelectorAll('.ag-center-cols-container [role="row"]')) .filter((row) => isVisible(row) && (row.getAttribute('aria-selected') === 'true' || row.classList.contains('ag-row-selected'))); if (!selectedRows.length) return { ok: false, reason: 'no selected complete draft rows' }; const bulkDropdown = view.querySelector('#bulk-dropdown'); if (!bulkDropdown) { return { ok: false, reason: 'bulk dropdown not found', selectedCount: selectedRows.length, }; } const toggle = bulkDropdown.shadowRoot && bulkDropdown.shadowRoot.querySelector('button[part="dropdown-button-toggle-button"], button'); clickElement(toggle || bulkDropdown); function findBulkDeleteAction() { const all = []; const seen = new Set(); function walk(root) { if (!root || seen.has(root)) return; seen.add(root); const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT); let node = walker.currentNode; while (node) { if (node.nodeType === Node.ELEMENT_NODE && node.tagName) all.push(node); if (node.shadowRoot) walk(node.shadowRoot); if ((node.tagName || '').toLowerCase() === 'slot' && node.assignedElements) { for (const assigned of node.assignedElements({ flatten: true })) walk(assigned); } node = walker.nextNode(); } } walk(document); const exactAction = all.find((el) => { const action = String(el.getAttribute && el.getAttribute('data-action') || ''); const text = textOf(el); return isVisible(el) && action === 'DELETE_DRAFTS' && /删除商品信息草稿/.test(text); }); if (exactAction) return exactAction; return all.find((el) => { const text = textOf(el); const attrs = Array.from(el.attributes || []).map((attr) => `${attr.name}=${attr.value}`).join(' '); const haystack = `${text} ${attrs}`; if (!isVisible(el) || !/删除商品信息草稿/.test(haystack)) return false; if (/^(HTML|BODY|KAT-DATA-GRID)$/i.test(el.tagName || '') && text.length > 80) return false; if (/^DIV$/i.test(el.tagName || '') && text !== '删除商品信息草稿') return false; if ((el.tagName || '').toLowerCase() === 'kat-icon') return false; return /^(BUTTON|KAT-BUTTON|KAT-OPTION|KAT-DROPDOWN-OPTION|LI|A|SPAN|DIV)$/i.test(el.tagName || ''); }); } const deleteAction = findBulkDeleteAction(); if (!deleteAction) { const candidates = []; const seen = new Set(); function walkCandidates(root) { if (!root || seen.has(root)) return; seen.add(root); const walker = document.createTreeWalker(root, NodeFilter.SHOW_ELEMENT); let node = walker.currentNode; while (node) { if (node.nodeType === Node.ELEMENT_NODE && node.tagName && isVisible(node)) { const text = textOf(node); const attrs = Array.from(node.attributes || []).map((attr) => `${attr.name}=${attr.value}`).join(' '); if (/删除|草稿|选择组操作|menu|option/i.test(`${text} ${attrs}`)) candidates.push(summarize(node)); } if (node.shadowRoot) walkCandidates(node.shadowRoot); node = walker.nextNode(); } } walkCandidates(document); return { ok: false, reason: 'bulk delete draft action not found', menuOpened: true, selectedCount: selectedRows.length, bulkDropdown: summarize(bulkDropdown), candidates: candidates.slice(0, 50), }; } clickElement(deleteAction); return { ok: true, selectedCount: selectedRows.length, bulkDropdown: summarize(bulkDropdown), clicked: summarize(deleteAction), rows: selectedRows.slice(0, 10).map(summarize), };