// ==UserScript== // @name 纷享开发者助手 // @namespace https://docs.scriptcat.org/ // @version 0.2.3 // @description 纷享销客开发者助手,列表页显示数据Id及关联数据Id;AI Hub签到辅助 // @author Kayu Tse // @storageName kayu-scriptcat-shared // @match *://*/XV/UI/Home* // @match https://aihub.firstshare.cn/* // @grant GM_addStyle // @grant GM_setClipboard // @grant GM_getValue // @grant GM_setValue // @grant GM.addStyle // @grant GM.setValue // @grant GM.getValue // @run-at document-end // @license All Rights Reserved // ==/UserScript== (function() { 'use strict'; // 既然你要 a 标签,样式就得重焊,不然丑得批爆 GM_addStyle(` .luo-id-link { display: inline-block !important; height: 16px; line-height: 14px; padding: 0 4px; margin-left: 4px; border: 1px solid #d9d9d9; border-radius: 2px; background: #fafafa; color: #fa8c16 !important; font-size: 10px; font-family: 'Consolas', monospace; text-decoration: none !important; vertical-align: middle; cursor: pointer; transition: all 0.2s; } .luo-id-link:hover { border-color: #fa8c16; background: #fff7e6; color: #e67e22 !important; } .id-copy-ok { background-color: #52c41a !important; color: #fff !important; border-color: #52c41a !important; } `); function processList() { // 抓那个带名字的 div const nameDivs = document.querySelectorAll('.td-name .tb-cell[data-id]:not([data-id-luo-v3])'); nameDivs.forEach(div => { const dataId = div.getAttribute('data-id'); if (!dataId) return; // 找那个该死的新页签图标,我们要插到它前面 const newTabIcon = div.querySelector('.j-icon-newtab'); // 创建你魂牵梦绕的 a 标签 const idLink = document.createElement('a'); idLink.className = 'luo-id-link'; idLink.href = 'javascript:void(0);'; // 免得它乱跳 idLink.title = '完整 ID: ' + dataId + ' (点击复制)'; idLink.innerText = dataId.slice(-6); idLink.onclick = (e) => { // 别让它触发 CRM 的任何原生点击事件,你是要复制,不是要跳转! e.preventDefault(); e.stopPropagation(); GM_setClipboard(dataId); const rawText = idLink.innerText; idLink.innerText = 'OK!'; idLink.classList.add('id-copy-ok'); setTimeout(() => { idLink.innerText = rawText; idLink.classList.remove('id-copy-ok'); }, 800); }; // 如果有新页签图标,就插在它前面;莫得就直接加在末尾 if (newTabIcon) { div.insertBefore(idLink, newTabIcon); } else { div.appendChild(idLink); } // 标记一下,老子可不想看到死循环 div.setAttribute('data-id-luo-v3', 'true'); }); // 处理关联数据的 ID 显示(lookup 字段) const lookupLinks = document.querySelectorAll('.j-show-lookup[data-id]:not([data-lookup-id-processed])'); lookupLinks.forEach(lookupLink => { const lookupId = lookupLink.getAttribute('data-id'); if (!lookupId) return; // 找该关联字段所在的容器 div const parentDiv = lookupLink.closest('.tb-cell'); if (!parentDiv) return; // 找新页签图标,我们要插到它前面 const newTabIcon = parentDiv.querySelector('.j-icon-newtab'); // 创建关联数据的 ID 标签 const lookupIdLink = document.createElement('a'); lookupIdLink.className = 'luo-id-link'; lookupIdLink.href = 'javascript:void(0);'; lookupIdLink.title = '关联数据完整 ID: ' + lookupId + ' (点击复制)'; lookupIdLink.innerText = lookupId.slice(-6); lookupIdLink.onclick = (e) => { e.preventDefault(); e.stopPropagation(); GM_setClipboard(lookupId); const rawText = lookupIdLink.innerText; lookupIdLink.innerText = 'OK!'; lookupIdLink.classList.add('id-copy-ok'); setTimeout(() => { lookupIdLink.innerText = rawText; lookupIdLink.classList.remove('id-copy-ok'); }, 800); }; // 如果有新页签图标,就插在它前面;莫得就直接加在末尾 if (newTabIcon) { parentDiv.insertBefore(lookupIdLink, newTabIcon); } else { parentDiv.appendChild(lookupIdLink); } // 标记已处理,避免重复处理 lookupLink.setAttribute('data-lookup-id-processed', 'true'); }); } // 这种表格动态加载太频繁,MutationObserver 必须稳如老狗 let timer = null; const observer = new MutationObserver(() => { if (timer) clearTimeout(timer); timer = setTimeout(processList, 200); }); // 盯着整个 body 的变动 observer.observe(document.body, { childList: true, subtree: true }); // 初次运行 setTimeout(processList, 800); console.log('%c [老罗]: a标签版整好了,主数据ID和关联数据ID都能看到了,稳得很!', 'color: #52c41a; font-weight: bold;'); // ============================================================ // AI Hub 每日自动签到(页面端辅助:负责把 userId 写入脚本猫存储) // ============================================================ (async function initAiHubCheckIn() { const CHECKIN_HOST = 'aihub.firstshare.cn'; console.debug('[AI Hub CheckIn] initAiHubCheckIn running, host:', location.host, 'pathname:', location.pathname); if (location.host !== CHECKIN_HOST) { console.debug('[AI Hub CheckIn] host mismatch, skip'); return; } if (!/^\/profile/.test(location.pathname)) { console.debug('[AI Hub CheckIn] pathname mismatch, skip'); return; } try { const raw = localStorage.getItem('user'); console.debug('[AI Hub CheckIn] localStorage.user raw:', raw ? raw.slice(0, 100) : null); if (raw) { const user = JSON.parse(raw); console.debug('[AI Hub CheckIn] parsed user:', user ? { id: user.id, display_name: user.display_name } : null); if (user && user.id) { const userId = String(user.id); const saved = await GM.getValue('aihub_user_id', ''); console.debug('[AI Hub CheckIn] current saved:', saved, 'new userId:', userId); if (saved !== userId) { await GM.setValue('aihub_user_id', userId); console.log('[AI Hub CheckIn] user id saved:', userId); // 复用站内可能的 toast,否则自绘一个 if (typeof window.$message === 'function') { window.$message.success('AI Hub 签到用户 ID 已保存'); } else { const el = document.createElement('div'); el.textContent = 'AI Hub 签到用户 ID 已保存'; el.style.cssText = ` position: fixed; top: 20px; right: 20px; z-index: 99999; padding: 12px 20px; border-radius: 8px; background: #52c41a; color: #fff; font-size: 14px; box-shadow: 0 4px 12px rgba(0,0,0,0.15); `; document.body.appendChild(el); setTimeout(() => el.remove(), 3000); } } else { console.debug('[AI Hub CheckIn] userId unchanged, silent'); } } else { console.debug('[AI Hub CheckIn] user object has no id'); } } else { console.debug('[AI Hub CheckIn] no user in localStorage'); } } catch (e) { console.warn('[AI Hub CheckIn] save user id failed:', e); } })(); })();