您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
在极客页面中,点击设备列表,调用API获取设备和规则列表,并生成设备规则映射并显示在当前页面上
当前为
// ==UserScript== // @name 米家极客版油猴插件 // @namespace http://tampermonkey.net/ // @version v0.6 // @description 在极客页面中,点击设备列表,调用API获取设备和规则列表,并生成设备规则映射并显示在当前页面上 // @author 王丰,sk163 // @license MIT // @match http://*/* // @icon data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw== // @grant none // ==/UserScript== (async () => { const callAPI = (api, params) => { return new Promise(res => editor.gateway.callAPI(api, params, res)); }; let selectCardIds = ''; const executeScript = async () => { // 检查是否已经存在结果容器,避免重复生成 if (document.getElementById('device-rule-map')) { return; } if (typeof editor === 'undefined' || typeof editor.gateway === 'undefined' || typeof editor.gateway.callAPI === 'undefined') { console.error('editor.gateway.callAPI 方法未定义。请确保在正确的环境中运行此脚本。'); return; } try { const devListResponse = await callAPI('getDevList'); const devList = devListResponse.devList; const ruleList = await callAPI('getGraphList'); let devRuleMap = {}; for (const rule of ruleList) { const content = await callAPI('getGraph', {id: rule.id}); const dids = new Set(content.nodes.map(n => n.props?.did).filter(d => d !== undefined)); const cards = new Set(content.nodes.map(n => { return (n.props && n.cfg) ? {did: n.props.did, oriId: n.cfg.oriId} : undefined; }).filter(d => d !== undefined)); dids.forEach(d => { devRuleMap[d] = devRuleMap[d] ?? []; const cardIds = Array.from(cards) .filter(card => card.did === d) .map(card => card.oriId).join(','); devRuleMap[d].push(rule.id + "#" + cardIds); }); } const result = Object.fromEntries(Object.entries(devRuleMap).map(([k, v]) => [ devList[k]?.name ?? `did: ${k}`, v.map(r => { const ruleId = r.split('#')[0]; const cardIds = r.split('#')[1]; return ({ id: ruleId, cardIds: cardIds, name: ruleList.find(rr => rr.id === ruleId).userData.name }); }) ])); // 创建结果容器 const container = document.createElement('div'); container.id = 'device-rule-map'; container.style.position = 'fixed'; container.style.top = '10px'; container.style.right = '10px'; container.style.width = '800px'; container.style.height = '600px'; container.style.overflowY = 'scroll'; container.style.backgroundColor = 'white'; container.style.border = '1px solid #ccc'; container.style.paddingTop = '50px'; container.style.zIndex = 10000; container.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.1)'; // 创建固定的顶部栏 const topBar = document.createElement('div'); topBar.style.position = 'fixed'; topBar.style.top = '0'; topBar.style.right = '10px'; topBar.style.width = '800px'; topBar.style.height = '50px'; topBar.style.backgroundColor = 'white'; topBar.style.zIndex = 10001; topBar.style.boxShadow = '0 4px 8px rgba(0, 0, 0, 0.1)'; topBar.style.display = 'flex'; topBar.style.justifyContent = 'space-between'; topBar.style.alignItems = 'center'; topBar.style.padding = '0 10px'; // 创建标题 const title = document.createElement('h1'); title.style.margin = '0'; title.textContent = '设备规则映射结果'; // 创建按钮容器 const buttonContainer = document.createElement('div'); buttonContainer.style.display = 'flex'; buttonContainer.style.gap = '10px'; // 创建折叠按钮 const collapseButton = document.createElement('button'); collapseButton.textContent = '折叠'; collapseButton.onclick = () => { if (container.style.height === '600px') { container.style.height = '50px'; collapseButton.textContent = '展开'; } else { container.style.height = '600px'; collapseButton.textContent = '折叠'; } }; // 创建关闭按钮 const closeButton = document.createElement('button'); closeButton.textContent = '关闭'; closeButton.onclick = () => document.body.removeChild(container); buttonContainer.appendChild(collapseButton); buttonContainer.appendChild(closeButton); topBar.appendChild(title); topBar.appendChild(buttonContainer); // 创建表格 const table = document.createElement('table'); table.border = '1'; table.cellSpacing = '0'; table.cellPadding = '5'; table.style.width = '100%'; // 表头 const thead = document.createElement('thead'); const headerRow = document.createElement('tr'); const deviceHeader = document.createElement('th'); const ruleHeader = document.createElement('th'); let deviceSortOrder = 'asc'; // 初始排序顺序 let ruleSortOrder = 'asc'; // 初始排序顺序 const updateSortMarkers = () => { deviceHeader.innerHTML = `设备 ${deviceSortOrder === 'asc' ? '⬆️' : '⬇️'}`; ruleHeader.innerHTML = `规则 ${ruleSortOrder === 'asc' ? '⬆️' : '⬇️'}`; }; deviceHeader.textContent = '设备'; ruleHeader.textContent = '规则'; // 添加点击事件进行排序 deviceHeader.onclick = () => { deviceSortOrder = deviceSortOrder === 'asc' ? 'desc' : 'asc'; sortTable(0, deviceSortOrder); updateSortMarkers(); }; ruleHeader.onclick = () => { ruleSortOrder = ruleSortOrder === 'asc' ? 'desc' : 'asc'; sortTable(1, ruleSortOrder); updateSortMarkers(); }; headerRow.appendChild(deviceHeader); headerRow.appendChild(ruleHeader); thead.appendChild(headerRow); table.appendChild(thead); // 表体 const tbody = document.createElement('tbody'); Object.entries(result).forEach(([device, rules]) => { const row = document.createElement('tr'); const deviceCell = document.createElement('td'); deviceCell.textContent = device; const ruleCell = document.createElement('td'); // 获取当前主机名 const host = window.location.host; // 创建规则链接 rules.forEach(rule => { const link = document.createElement('a'); link.href = `http://${host}/#/graph/${rule.id}`; link.target = '_self'; link.textContent = rule.name; link.onclick = () => { window.location.hash = '#/'; selectCardIds = rule.cardIds; }; ruleCell.appendChild(link); ruleCell.appendChild(document.createTextNode(', ')); // 添加逗号分隔符 }); ruleCell.removeChild(ruleCell.lastChild); row.appendChild(deviceCell); row.appendChild(ruleCell); tbody.appendChild(row); }); table.appendChild(tbody); container.appendChild(topBar); container.appendChild(table); document.body.appendChild(container); // 排序函数 function sortTable(columnIndex, sortOrder) { const rows = Array.from(tbody.rows); const sortedRows = rows.sort((a, b) => { const aText = a.cells[columnIndex].textContent; const bText = b.cells[columnIndex].textContent; if (sortOrder === 'asc') { return aText.localeCompare(bText); } else { return bText.localeCompare(aText); } }); // 清空并重新添加排序后的行 tbody.innerHTML = ''; sortedRows.forEach(row => tbody.appendChild(row)); } // 初始化排序标记 updateSortMarkers(); } catch (error) { console.error('调用 API 时出错:', error); } }; const selectDevices = async () => { await sleep(1000); const cardIds = selectCardIds.split(','); for (const cardId of cardIds) { if (cardId.trim() !== '') { let targetElement = document.querySelector("#" + cardId.trim() + " > div > div"); if (targetElement) { targetElement.style.backgroundColor = '#F08080'; } } } selectCardIds = ''; function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } }; function isMiJiaJiKePage(){ return document.title==="米家自动化极客版"; } // 检查初始的 hash 值 if (isMiJiaJiKePage() && window.location.hash === '#/device') { executeScript(); } // 监听 hash 值变化 window.addEventListener('hashchange', () => { if (isMiJiaJiKePage() && window.location.hash === '#/device') { executeScript(); } if (isMiJiaJiKePage() && window.location.hash.match(/^#\/graph\/.*/g) ) { selectDevices(); } }); })();