增强版筛选,支持黑名单,支持心愿单
// ==UserScript== // @name CPP便捷快速扫本 // @license MIT // @namespace http://tampermonkey.net/ // @version 1.3 // @description 增强版筛选,支持黑名单,支持心愿单 // @author AnchorCat // @match https://www.allcpp.cn/allcpp/event/eventdoujinshi.do?* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @grant GM_getValue // @grant GM_setValue // ==/UserScript== (function () { 'use strict'; // 本地默认黑名单值 const DEFAULT_BLACKLIST = []; // 配置参数 const CONFIG = { REQUEST_SIZE: 30, LOAD_DELAY: 500, // 检查GM中是否存在BLACKLIST数据,不存在则使用默认值并存储 BLACKLIST: (function () { const storedBlacklist = GM_getValue("BLACKLIST", []); if (storedBlacklist) { return storedBlacklist; } else { GM_setValue("BLACKLIST", DEFAULT_BLACKLIST); return DEFAULT_BLACKLIST; } })(), API_URL: "https://www.allcpp.cn/api/doujinshi/search.do", COVER_PREFIX: "https://imagecdn3.allcpp.cn/upload" }; // 从GM中获取缓存 const CACHE = GM_getValue('REQUEST_CACHE', {}); // 用于存储正在进行的请求 const activeRequests = new Set(); // 请求暂停标记 let isRequestPaused = false; // 获取页面勾选的 typeIds function getCheckedTypeIds() { const activeTypeBoxes = document.querySelectorAll('.type-box .active'); const typeIds = []; activeTypeBoxes.forEach(box => { const id = box.getAttribute('data-id'); if (id) { typeIds.push(id); } }); return typeIds.join('%2C'); } // 获取当前活动的eventID function getActiveEventDayId() { const activeEventDay = document.querySelector('.event-days .active'); return activeEventDay ? activeEventDay.getAttribute('data-id') : null; } // 创建悬浮按钮 const floatBtn = document.createElement('div'); floatBtn.id = 'float-btn'; floatBtn.textContent = '打开作品筛选\n(按照当前类型)'; document.body.appendChild(floatBtn); // 悬浮按钮点击处理 document.body.addEventListener('click', async (e) => { if (e.target.id === 'float-btn') { const filterPage = createFilterPage(); filterPage.currentRequestPage = 1; const checkedTypeIds = getCheckedTypeIds(); const eventId = getActiveEventDayId(); CONFIG.BASE_PARAMS = `eventId=${eventId}&orderBy=1&typeIds=${checkedTypeIds}&pageSize=30`; CONFIG.CURRENT_EVENTID = eventId; setupIntersectionObserver(filterPage); // 设置曝光监听,用于获取更多数据 } }); // 创建筛选页面 function createFilterPage() { const existing = document.querySelector('.filter-page'); if (existing) existing.remove(); const filterPage = document.createElement('div'); filterPage.className = 'filter-page'; filterPage.innerHTML = ` <div class="close-btn">关闭</div> <div class="blacklist-btn">管理Tag黑名单</div> <div class="force-refresh-btn">强制刷新</div> <h1>作品筛选列表(总计 <span id="total-count">0</span> 页)</h1> <div id="works-container"></div> <div id="loading-status" style="padding: 20px; text-align: center;"></div> `; // 黑名单面板交互 let blacklistPanel = null; filterPage.querySelector('.blacklist-btn').addEventListener('click', (e) => { if (!blacklistPanel) { blacklistPanel = createBlacklistPanel(filterPage); filterPage.appendChild(blacklistPanel); // 点击外部关闭 const clickHandler = (event) => { const isDeleteButton = event.target.classList.contains('delete-btn'); if (isDeleteButton) return; if (!blacklistPanel.contains(event.target) && event.target !== e.target) { blacklistPanel.remove(); blacklistPanel = null; document.removeEventListener('click', clickHandler); } }; document.addEventListener('click', clickHandler); } }); // 绑定关闭事件 filterPage.querySelector('.close-btn').addEventListener('click', () => { filterPage.remove(); }); // 绑定强制刷新事件 filterPage.querySelector('.force-refresh-btn').addEventListener('click', () => { isRequestPaused = true; // 暂停新请求 // 取消所有正在进行的请求 activeRequests.forEach(request => { if (request.abort) { request.abort(); } }); activeRequests.clear(); // 清空请求队列 GM_setValue('REQUEST_CACHE', {}); Object.keys(CACHE).forEach(key => delete CACHE[key]); filterPage.querySelector('#works-container').innerHTML = ''; filterPage.currentRequestPage = 1; setTimeout(() => { isRequestPaused = false; // 恢复请求 loadMoreData(filterPage, 1); }, 100); // 短暂延迟后重新发起请求 }); document.body.appendChild(filterPage); return filterPage; } // 单页加载逻辑 async function loadPage(page) { if (isRequestPaused) { return null; } const url = `${CONFIG.API_URL}?${CONFIG.BASE_PARAMS}&pageIndex=${page}`; if (CACHE[url]) { console.log(`使用缓存数据,第${page}页`); return CACHE[url]; } console.log(`正在请求第${page}页数据`); return new Promise((resolve, reject) => { const request = GM_xmlhttpRequest({ method: 'GET', url, onload: (response) => { activeRequests.delete(request); // 请求完成,从队列中移除 if (response.status >= 200 && response.status < 300) { const data = JSON.parse(response.responseText); const r###lt = { works: data.r###lt?.list || [], total: data.r###lt?.total || 0 }; CACHE[url] = r###lt; GM_setValue('REQUEST_CACHE', CACHE); resolve(r###lt); } else { reject(new Error(`HTTP error: ${response.status}`)); } }, onerror: (error) => { activeRequests.delete(request); // 请求出错,从队列中移除 reject(new Error(`Network error: ${error.message}`)); } }); activeRequests.add(request); // 将请求添加到队列中 }); } function setupIntersectionObserver(filterPage) { const placeholder = filterPage.querySelector('#loading-status'); let isLoading = false; const observer = new IntersectionObserver(async (entries, observer) => { entries.forEach(entry => { if (entry.isIntersecting && !isLoading) { isLoading = true; loadMoreData(filterPage, filterPage.currentRequestPage).then(() => { isLoading = false; }); } }); }); observer.observe(placeholder); } // 加载更多数据(每次加载CONFIG.REQUEST_SIZE条) async function loadMoreData(filterPage, startPage) { if (isRequestPaused) { return; } const container = filterPage.querySelector('#works-container'); const status = filterPage.querySelector('#loading-status'); let currentPage = startPage; let loadedCount = 0; let hasMore = true; while (loadedCount < CONFIG.REQUEST_SIZE && hasMore) { if (isRequestPaused) { break; } status.textContent = `正在加载第 ${currentPage} 页...`; const r###lt = await loadPage(currentPage); currentPage++; filterPage.currentRequestPage = currentPage; if (!r###lt || r###lt.works.length === 0) { hasMore = false; status.textContent = "没有更多数据"; break; } // 初始化数据存储 if (!filterPage.allWorks) filterPage.allWorks = []; // 添加原始数据并建立索引 r###lt.works.forEach((work, index) => { work.index = filterPage.allWorks.length + 1; work.pageIndex = currentPage; filterPage.allWorks.push(work); }); // 渲染过滤后的数据 r###lt.works.forEach(work => { if (checkWorkInBlackList(work)) { return; } renderWorkItem(container, work, filterPage); loadedCount++; }); updateCounter(filterPage, r###lt.total); await new Promise(r => setTimeout(r, CONFIG.LOAD_DELAY)); } status.textContent = hasMore ? "滚动到底部加载更多" : "已加载全部数据"; } // 更新计数器 function updateCounter(filterPage, total) { const counter = filterPage.querySelector('#total-count'); if (counter) counter.textContent = Math.ceil(total / 30); } // 创建黑名单管理面板 function createBlacklistPanel(filterPage) { const panel = document.createElement('div'); panel.className = 'blacklist-panel'; panel.innerHTML = ` <div class="blacklist-controls"> <input type="text" class="blacklist-input" placeholder="添加/搜索黑名单词"> <button class="blacklist-add-btn">添加</button> </div> <div class="blacklist-items"></div> <button class="blacklist-export-btn">导出Json文件</button> <button class="blacklist-import-btn">导入Json文件</button> `; // 事件绑定 const addBtn = panel.querySelector('.blacklist-add-btn'); const input = panel.querySelector('.blacklist-input'); const itemsContainer = panel.querySelector('.blacklist-items'); const exportBtn = panel.querySelector('.blacklist-export-btn'); const importBtn = panel.querySelector('.blacklist-import-btn'); // 添加黑名单 function addToBlacklist() { const word = input.value.trim(); if (word && !CONFIG.BLACKLIST.includes(word)) { CONFIG.BLACKLIST.push(word); GM_setValue('BLACKLIST', CONFIG.BLACKLIST); input.value = ''; refreshBlacklistItems(); updateWorksByBlacklist(filterPage); } } // 搜索过滤 function searchBlacklist() { const keyword = input.value.trim().toLowerCase(); refreshBlacklistItems(keyword); } // 导出黑名单为 JSON 文件 function exportBlacklist() { const jsonData = JSON.stringify(CONFIG.BLACKLIST, null, 2); const blob = new Blob([jsonData], { type: 'application/json' }); const url = URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = 'blacklist.json'; a.click(); URL.revokeObjectURL(url); } // 导入 JSON 文件到黑名单 function importBlacklist() { const inputElement = document.createElement('input'); inputElement.type = 'file'; inputElement.accept = 'application/json'; inputElement.onchange = function (event) { const file = event.target.files[0]; if (file) { const reader = new FileReader(); reader.onload = function (e) { try { const importedData = JSON.parse(e.target.r###lt); if (Array.isArray(importedData)) { CONFIG.BLACKLIST = [...new Set([...GM_getValue('BLACKLIST', CONFIG.BLACKLIST), ...importedData])]; GM_setValue('BLACKLIST', CONFIG.BLACKLIST); refreshBlacklistItems(); updateWorksByBlacklist(filterPage); } else { alert('导入的文件格式不正确,必须是 JSON 数组。'); } } catch (error) { alert('导入失败,请确保文件是有效的 JSON 格式。'); } }; reader.readAsText(file); } }; inputElement.click(); } // 点击添加按钮 addBtn.addEventListener('click', addToBlacklist); // 输入框输入时自动搜索 input.addEventListener('input', searchBlacklist); // 点击导出按钮 exportBtn.addEventListener('click', exportBlacklist); // 点击导入按钮 importBtn.addEventListener('click', importBlacklist); // 刷新黑名单列表 function refreshBlacklistItems(keyword = '') { itemsContainer.innerHTML = ''; CONFIG.BLACKLIST .filter(word => word.toLowerCase().includes(keyword)).reverse() .forEach(word => { const item = document.createElement('div'); item.className = 'blacklist-item'; item.innerHTML = ` <span>${word}</span> <span class="delete-btn">删除</span> `; item.querySelector('.delete-btn').addEventListener('click', () => { CONFIG.BLACKLIST = CONFIG.BLACKLIST.filter(w => w !== word); GM_setValue('BLACKLIST', CONFIG.BLACKLIST); refreshBlacklistItems(input.value.trim().toLowerCase()); updateWorksByBlacklist(filterPage); }); itemsContainer.appendChild(item); }); } // 初始加载 refreshBlacklistItems(); return panel; } // 根据黑名单,从当前的container中移除作品,不刷新全部作品 function updateWorksByBlacklist(filterPage) { const container = filterPage.querySelector('#works-container'); const works = container.querySelectorAll('.work-item'); works.forEach(work => { const tags = work.querySelectorAll('.tag-text'); const tagTexts = Array.from(tags).map(tag => tag.textContent); // 检查标签文本是否包含黑名单中的词 if (tagTexts.some(tag => CONFIG.BLACKLIST.includes(tag))) { // 若包含,则隐藏该作品项 work.style.display = 'none'; } else { // 若不包含,则确保该作品项是显示的 work.style.display = ''; } }); } // 全局刷新作品列表 function refreshWorks(filterPage) { const container = filterPage.querySelector('#works-container'); container.innerHTML = ''; filterPage.allWorks.forEach(work => { if (!checkWorkInBlackList(work)) { renderWorkItem(container, work, filterPage); } }); } // 判断作品是否命中黑名单 function checkWorkInBlackList(work) { if (CONFIG.BLACKLIST.some(word => work.tag.includes(word)) || CONFIG.BLACKLIST.some(word => work.themeAlias.includes(word))) { return true; } return false; } // 独立渲染单个作品的方法 function renderWorkItem(container, work, filterPage) { if (CONFIG.BLACKLIST.some(word => work.tag.includes(word))) return; const item = document.createElement('div'); item.className = 'work-item'; const coverUrl = `${CONFIG.COVER_PREFIX}${work.coverPicUrl}?x-oss-process=style/rectangle_450-600_60`; // 添加 type 图标 const typeIcon = document.createElement('div'); typeIcon.className = 'type-icon'; typeIcon.textContent = work.type; // 划分标签并生成可点击按钮 let tags = []; if (work.tag) { tags = work.tag.split('|'); } tags.unshift(work.themeAlias); // 存在没写tag的作品,添加原作作为tag标签 tags.unshift(`圈子: ${work.circleName}(${work.circleID})`); // 存在没写tag的作品,添加原作作为tag标签 tags.unshift(`作者: ${work.nickname}(${work.userID})`); tags = [...new Set(tags)]; const tagButtons = tags.map(tag => { const button = document.createElement('button'); button.innerHTML = ` <span class="tag-content"> <span class="tag-text">${tag}</span> <span class="close-emoji">❌</span> </span> `; button.classList.add('tag-button'); // 鼠标悬停事件 button.addEventListener('mouseover', () => { button.classList.add('hovered'); }); // 鼠标移出事件 button.addEventListener('mouseout', () => { button.classList.remove('hovered'); }); // 点击事件 button.addEventListener('click', () => { if (!CONFIG.BLACKLIST.includes(tag)) { CONFIG.BLACKLIST.push(tag); GM_setValue('BLACKLIST', CONFIG.BLACKLIST); const rect = button.getBoundingClientRect(); showToast(`已将 ${tag} 加入到黑名单`, rect.left, rect.bottom); updateWorksByBlacklist(filterPage); } }); return button; }); const tagDiv = document.createElement('div'); tagDiv.classList.add('tags'); tagButtons.forEach(button => tagDiv.appendChild(button)); item.innerHTML = ` <div class="count-box"> <div class="count">${work.index}</div> <div class="page-index">(页面:${work.pageIndex})</div> </div> <img class="cover-img" src="${coverUrl}" onerror="this.src='https://placehold.co/100x140?text=封面加载失败'"> <div> <h2> <a class="title-link" href="https://www.allcpp.cn/d/${work.doujinshiId}.do#tabType=0" target="_blank"> ${work.doujinshiName} </a> </h2> </div> `; // 将 type 图标插入到标题上方 const titleDiv = item.querySelector('div:nth-child(3)'); titleDiv.insertBefore(typeIcon, titleDiv.firstChild); // 添加标签按钮到作品项中 item.querySelector('div:nth-child(3)').appendChild(tagDiv); // 添加心愿单按钮和显示区域 const wishlistContainer = document.createElement('div'); wishlistContainer.className = 'wishlist-container'; const currentWork = work; const wishlistInfoContainer = document.createElement('div'); wishlistInfoContainer.className = 'wishlist-info'; renderWishlistInfo(currentWork.doujinshiId, wishlistInfoContainer); wishlistContainer.appendChild(wishlistInfoContainer); item.appendChild(wishlistContainer); container.appendChild(item); } // 显示 toast 提示的函数 function showToast(message, left, top) { const toast = document.createElement('div'); toast.classList.add('toast'); toast.textContent = message; // 设置位置并留出空隙 toast.style.left = `${left}px`; toast.style.top = `${top + 5}px`; document.body.appendChild(toast); // 添加淡入效果 setTimeout(() => { toast.classList.add('toast-fade-in'); }, 50); // 定时移除 toast 并添加淡出效果 setTimeout(() => { toast.classList.add('toast-fade-out'); setTimeout(() => { toast.remove(); }, 300); }, 2000); } // 查询该作品目前适用于哪个心愿单 async function getCouldBuyEventList(doujinshiid) { const url = `https://www.allcpp.cn/allcpp/djswb/getCouldBuyEventList.do?doujinshiid=${doujinshiid}`; return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url, onload: (response) => { if (response.status >= 200 && response.status < 300) { const data = JSON.parse(response.responseText); const validEvents = data.r###lt.filter(event => event.eventId > 0); resolve(validEvents); } else { reject(new Error(`HTTP error: ${response.status}`)); } }, onerror: (error) => { reject(new Error(`Network error: ${error.message}`)); } }); }); } // 添加该作品到对应心愿单 async function addToWishlist(doujinshiid, eventids) { const url = `https://www.allcpp.cn/api/djswb/addDoujinshiWannaBuy.do?doujinshiid=${doujinshiid}&eventids=${eventids}`; return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url, onload: (response) => { if (response.status >= 200 && response.status < 300) { resolve(); } else { reject(new Error(`HTTP error: ${response.status}`)); } }, onerror: (error) => { reject(new Error(`Network error: ${error.message}`)); } }); }); } // 删除该作品到对应心愿单 async function deleteFromWishlist(doujinshiid, eventids) { const url = `https://www.allcpp.cn/api/djswb/deleteDoujinshiWannaBuy.do?doujinshiid=${doujinshiid}&eventids=${eventids}`; return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'GET', url, onload: (response) => { if (response.status >= 200 && response.status < 300) { resolve(); } else { reject(new Error(`HTTP error: ${response.status}`)); } }, onerror: (error) => { reject(new Error(`Network error: ${error.message}`)); } }); }); } // 渲染心愿单信息 async function renderWishlistInfo(doujinshiid, container) { const eventList = await getCouldBuyEventList(doujinshiid); container.innerHTML = ''; eventList.forEach(event => { const eventInfo = document.createElement('div'); if (event.isWannaBuy) { const deleteBtn = document.createElement('button'); deleteBtn.className = 'wishlist-btn del_wish_button'; deleteBtn.textContent = `${event.eventId == CONFIG.CURRENT_EVENTID ? `⭐️` : ``} 从【${event.eventName}】心愿单里删除`; deleteBtn.addEventListener('click', async () => { await deleteFromWishlist(doujinshiid, event.eventId); // 刷新心愿单显示 renderWishlistInfo(doujinshiid, container); }); eventInfo.appendChild(deleteBtn); } else { const addBtn = document.createElement('button'); addBtn.className = 'wishlist-btn add_wish_button'; addBtn.textContent = `${event.eventId == CONFIG.CURRENT_EVENTID ? `⭐️` : ``} 添加到【${event.eventName}】心愿单`; addBtn.addEventListener('click', async () => { await addToWishlist(doujinshiid, event.eventId); // 刷新心愿单显示 renderWishlistInfo(doujinshiid, container); }); eventInfo.appendChild(addBtn); } container.appendChild(eventInfo); }); } })(); // 添加 toast 样式,包含淡入淡出效果 GM_addStyle(` .toast { position: fixed; background-color: rgba(0, 0, 0, 0.7); color: white; padding: 10px 20px; border-radius: 5px; z-index: 10003; opacity: 0; transition: opacity 0.3s; } .toast-fade-in { opacity: 1; } .toast-fade-out { opacity: 0; } `); GM_addStyle(` .type-icon { font-family: 'Microsoft YaHei','Helvetica'; line-height: 20px; -webkit-font-smoothing: antialiased; display: inline-block; margin: 3px 10px 5px 0; border-radius: 5px; border: 1px solid #e1ca82; font-size: 14px; padding: 3px 5px; cursor: pointer; background: #e1ca82; color: #fff; } `); // 添加按钮样式 GM_addStyle(` .tag-button { margin: 2px; padding: 4px 8px; background-color: #e0e0e0; border: none; border-radius: 4px; cursor: pointer; position: relative; white-space: nowrap; font-family: 'Microsoft YaHei','Helvetica'; line-height: 20px; -webkit-font-smoothing: antialiased; display: inline-block; font-size: 14px; } .tag-button:hover { background-color: #bdbdbd; } .tag-button .tag-content { display: flex; justify-content: center; align-items: center; } .tag-button .tag-text { opacity: 1; transition: opacity 0.2s; } .tag-button .close-emoji { opacity: 0; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); transition: opacity 0.2s; } .tag-button.hovered .tag-text { opacity: 0; } .tag-button.hovered .close-emoji { opacity: 1; } `); // 关闭按钮 GM_addStyle(` .close-btn { position: fixed; top: 20px; right: 20px; padding: 8px 16px; background: #ff4444; color: white; border-radius: 4px; cursor: pointer; z-index: 10001; } `); GM_addStyle(` /* 黑名单管理按钮 */ .blacklist-btn { position: fixed; top: 20px; right: 80px; padding: 8px 16px; background: #ff9800; color: white; border-radius: 4px; cursor: pointer; z-index: 10001; } .force-refresh-btn { position: fixed; top: 20px; right: 195px; padding: 8px 16px; background:rgb(69, 37, 215); color: white; border-radius: 4px; cursor: pointer; z-index: 10001; } /* 黑名单管理面板 */ .blacklist-panel { position: fixed; top: 60px; right: 20px; width: 300px; background: white; box-shadow: 0 2px 10px rgba(0,0,0,0.2); z-index: 10002; padding: 15px; border-radius: 8px; } .blacklist-controls { margin-bottom: 10px; display: flex; gap: 10px; } .blacklist-add-btn { padding: 6px 12px; background-color: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer; transition: background-color 0.3s; font-size: 14px; font-weight: 500; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .blacklist-add-btn:hover { background-color: #1976D2; } .blacklist-add-btn:active { background-color: #1565C0; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); } .blacklist-export-btn { padding: 6px 12px; background-color: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer; transition: background-color 0.3s; font-size: 14px; font-weight: 500; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .blacklist-export-btn:hover { background-color: #1976D2; } .blacklist-export-btn:active { background-color: #1565C0; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); } .blacklist-import-btn { padding: 6px 12px; background-color: #2196F3; color: white; border: none; border-radius: 4px; cursor: pointer; transition: background-color 0.3s; font-size: 14px; font-weight: 500; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .blacklist-import-btn:hover { background-color: #1976D2; } .blacklist-import-btn:active { background-color: #1565C0; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); } .blacklist-input { flex: 1; padding: 6px; border: 1px solid #ddd; border-radius: 4px; } .blacklist-items { max-height: 300px; overflow-y: auto; } .blacklist-item { display: flex; justify-content: space-between; align-items: center; padding: 8px; border-bottom: 1px solid #eee; } .blacklist-item:hover { background: #f5f5f5; } .delete-btn { color: #ff4444; cursor: pointer; margin-left: 10px; /* 原样式中的左外边距 */ position: relative; left: -10px; /* 往左移动 10px */ } `); GM_addStyle(` /* 调整序号样式 */ .count-box { position: absolute; left: 15px; top: 50%; text-align: center; font-size: 25px; /* 使用 transform 进行偏移 */ transform: translate(0%, -50%); } .page-index { font-size: 0.8em; color: #999; margin-top:10px; } #float-btn { position: fixed; right: 20px; bottom: 20px; padding: 12px 24px; background: #2196F3; color: white; border-radius: 25px; cursor: pointer; box-shadow: 0 4px 6px rgba(0,0,0,0.1); z-index: 9999; transition: 0.3s; } #float-btn:hover { background: #1976D2; transform: translateY(-2px); } .filter-page { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: white; z-index: 10000; overflow-y: auto; padding: 20px; } .work-item { display: flex; align-items: center; padding: 15px; border-bottom: 1px solid #eee; gap: 20px; } .cover-img { width: 100px; height: 140px; object-fit: cover; border-radius: 4px; margin-left: 35px; } .tags { color: #666; font-size: 0.9em; margin-top:5px; max-width: 600px; } .count { min-width: 80px; color: #666; font-weight: bold; } .work-item { position: relative; padding-left: 100px; } .title-link { color: #2196F3; text-decoration: none; } .title-link:hover { text-decoration: underline; } `); GM_addStyle(` /* 心愿单容器整体样式 */ .wishlist-container { border: 1px solid #e0e0e0; border-radius: 8px; padding: 15px; background: #f8f9fa; } /* 单个活动条目样式 */ .wishlist-event { display: flex; align-items: center; justify-content: space-between; padding: 10px; margin: 8px 0; background: white; border-radius: 6px; box-shadow: 0 2px 4px rgba(0,0,0,0.05); transition: box-shadow 0.2s; } .wishlist-event:hover { box-shadow: 0 4px 8px rgba(0,0,0,0.1); } /* 活动名称样式 */ .wishlist-event-name { flex: 1; font-weight: 500; color: #2c3e50; font-size: 14px; margin-right: 15px; overflow: hidden; text-overflow: ellipsis; } /* 通用按钮基础样式 */ .wishlist-btn { padding: 6px 12px; border: none; border-radius: 20px; font-size: 12px; font-weight: 500; cursor: pointer; transition: all 0.2s; display: flex; align-items: center; gap: 6px; margin-top: 5px; margin-bottom: 5px; } /* 删除按钮特定样式 */ .del_wish_button { background: #ff4757; color: white; min-width: 70px; } .del_wish_button:hover { background: #ff6b81; transform: translateY(-1px); } /* 添加按钮特定样式 */ .add_wish_button { background: #2ecc71; color: white; min-width: 100px; } .add_wish_button:hover { background: #27ae60; transform: translateY(-1px); } /* 按钮图标样式 */ .wishlist-btn::before { content: ''; display: inline-block; width: 14px; height: 14px; background-size: contain; } .del_wish_button::before { background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>'); } .add_wish_button::before { background-image: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="white"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>'); } `);