您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Mark Order ID gray when POD is viewed (row click + modal fallback) with debug logs
// ==UserScript== // @name Optimoroute POD - Gray Order ID by Darrien // @namespace pod-gray-debug // @version 1.2.0 // @description Mark Order ID gray when POD is viewed (row click + modal fallback) with debug logs // @match https://*.optimoroute.com/* // @match https://optimoroute.com/* // @run-at document-idle // @inject-into content // @license MIT // ==/UserScript== (function () { 'use strict'; const DEBUG = true; const log = (...a) => DEBUG && console.debug('[POD]', ...a); /* 文案(如界面是中文可替换) */ const TXT_ORDER_DETAILS = 'Order Details'; const TXT_POD = 'Proof of Delivery'; const TXT_ORDER_ID_LBL = 'Order ID'; /* 宽松一点:2~3个大写字母 + ≥5位数字(ZX..., WP... 都能匹配)*/ const ORDER_ID_REGEX = /[A-Z]{2,3}\d{5,}/; /* 颜色样式(尽量提高优先级) */ const style = document.createElement('style'); style.textContent = ` td .x-grid-cell-inner.pod-orderid-viewed, td.pod-orderid-viewed .x-grid-cell-inner, .x-grid-cell-inner.pod-orderid-viewed { color: #9ca3af !important; }`; document.head.appendChild(style); /* 按天存储 */ const STORAGE_PREFIX = 'podViewedIDs:'; const todayKey = () => { const d = new Date(); return `${STORAGE_PREFIX}${d.getFullYear()}-${String(d.getMonth()+1).padStart(2,'0')}-${String(d.getDate()).padStart(2,'0')}`; }; const loadSet = () => { try { return new Set(JSON.parse(localStorage.getItem(todayKey())||'[]')); } catch { return new Set(); } }; const saveSet = (s) => localStorage.setItem(todayKey(), JSON.stringify([...s])); const viewed = loadSet(); /* 小工具 */ const byTextEq = (el,t)=>!!el && (el.textContent||'').trim()===t; const findByText= (root,t)=>[...root.querySelectorAll('*')].find(el=>byTextEq(el,t)); // 从行里拿 Order ID:优先“第3列”,不行再全行正则 function getOrderIdFromRow(tr) { if (!tr) return null; const third = tr.querySelector('td:nth-child(3) .x-grid-cell-inner, td:nth-child(3)'); const s = (third?.textContent || '').trim(); if (s) { const m = s.match(ORDER_ID_REGEX); if (m) return m[0]; } const text = (tr.textContent || ''); const m2 = text.match(ORDER_ID_REGEX); return m2 ? m2[0] : null; } // 找到“Order ID 那格”的 DOM function findOrderIdCellInRow(tr, orderId) { if (!tr || !orderId) return null; // 精确匹配 let cell = [...tr.querySelectorAll('td .x-grid-cell-inner, td')].find(c => (c.textContent||'').trim() === orderId); if (cell) return cell; // 包含匹配 cell = [...tr.querySelectorAll('td .x-grid-cell-inner, td')].find(c => (c.textContent||'').includes(orderId)); return cell || null; } function grayCell(cell) { if (!cell) return; if (cell.classList.contains('x-grid-cell-inner')) cell.classList.add('pod-orderid-viewed'); else { cell.classList.add('pod-orderid-viewed'); const inner = cell.querySelector('.x-grid-cell-inner'); inner && inner.classList.add('pod-orderid-viewed'); } } // 扫描整表,应用灰色 function markTable() { const rows = document.querySelectorAll('tr.x-grid-row, table tr'); rows.forEach(tr => { const oid = getOrderIdFromRow(tr); if (!oid) return; const cell = findOrderIdCellInRow(tr, oid); if (!cell) return; if (viewed.has(oid)) grayCell(cell); else { cell.classList.remove('pod-orderid-viewed'); cell.querySelector?.('.x-grid-cell-inner')?.classList.remove('pod-orderid-viewed'); } }); } // —— A. 行内点击(相机/POD 列)立即记录 —— // // 兼容多种点击目标:相机图标、整个 POD 列、Action 列等;用捕获阶段拿到被阻止冒泡的点击 ['pointerdown','click','mousedown'].forEach(evt => { document.addEventListener(evt, (e) => { const icon = e.target.closest('.podIndicatorPhotoIconSmall, .pod-indicator-icon, [data-qtip*="Photo attached"]'); const podCell = icon ? icon.closest('td') : e.target.closest('td[class*="pod-indicator-column"], td.x-action-col-cell'); if (!icon && !podCell) return; const tr = (podCell || icon)?.closest('tr.x-grid-row, tr'); if (!tr) return; const oid = getOrderIdFromRow(tr); log('row-click:', {evt, oid, tr}); if (!oid) return; viewed.add(oid); saveSet(viewed); const cell = findOrderIdCellInRow(tr, oid); grayCell(cell); }, true); // capture }); // —— B. 弹窗兜底(打开详情时也记录) —— // function extractOrderIdFromModal(modalRoot) { const label = findByText(modalRoot, TXT_ORDER_ID_LBL); if (!label) return null; const valueEl = label.parentElement?.querySelector(':scope > *:nth-child(2)'); const raw = (valueEl?.textContent || '').trim(); if (!raw) return null; const m = raw.match(ORDER_ID_REGEX); return m ? m[0] : raw; } function tryRecordFromNode(node) { const candidates = [...(node.querySelectorAll?.('div') || [])].filter(el => { const t = (el.textContent || ''); return t.includes(TXT_ORDER_DETAILS) && t.includes(TXT_POD); }); candidates.forEach(modalRoot => { const oid = extractOrderIdFromModal(modalRoot); log('modal-detect:', {oid, modalRoot}); if (!oid) return; if (!viewed.has(oid)) { viewed.add(oid); saveSet(viewed); markTable(); } }); } // 初次/监听 markTable(); tryRecordFromNode(document); const mo = new MutationObserver(muts => { let needMark = false; muts.forEach(m => { m.addedNodes && m.addedNodes.forEach(n => { if (n.nodeType !== 1) return; tryRecordFromNode(n); // 可能是弹窗 if (n.matches?.('table,tbody,tr,td,div')) needMark = true; // 表格更新 }); }); if (needMark) markTable(); }); mo.observe(document.body, { childList:true, subtree:true }); // 便捷:Alt+Shift+V 将“当前选中行”置灰(用于测试) document.addEventListener('keydown', (e) => { if (e.altKey && e.shiftKey && e.key.toLowerCase() === 'v') { const tr = document.querySelector('tr.x-grid-row-selected, tr.x-grid-row-focused') || document.querySelector('tr.x-grid-row'); const oid = getOrderIdFromRow(tr); log('hotkey Alt+Shift+V:', {tr, oid}); if (oid) { viewed.add(oid); saveSet(viewed); grayCell(findOrderIdCellInRow(tr, oid)); } } }); })();