// ==UserScript== // @name 容器插件 // @namespace 可乐 // @version 5.1 // @description 可乐 // @author 可乐 // @match *://manager.bilibili.co/annotation/* // @grant GM_setValue // @grant GM_getValue // @grant GM_deleteValue // @grant GM_listValues // ==/UserScript== (function () { 'use strict'; // ==================== 常量定义 ==================== /** CSS选择器集中管理,避免字符串重复 */ var SELECTORS = { taskInfo: ".task-info", textItem: ".text-item", matchResult: "heis_ss", label: ".label", radio: ".el-radio", checkboxLabel: ".el-checkbox__label", submitBtn: ".el-button.operation-btn.submit-operation-btn.el-button--primary.el-button--medium", topBtn: ".el-button.top-btn.operation-btn.el-button--default.el-button--medium", skipBtn: ".el-button.skip-btn.operation-btn.el-button--default.el-button--medium" }; /** 规则→复选框索引映射表(含全部8种规则) */ var RULE_CHECKBOX_MAP = { "见光死": 0, "主体拦截": 1, "封面拦截": 2, "通过需监控": 3, "通过需进标": 4, "正常通过": 5, "跳过": 6, "根据图片自行判断": 7 }; /** 可选规则列表 */ var RULE_OPTIONS = [ "见光死", "主体拦截", "封面拦截", "通过需监控", "通过需进标", "正常通过", "跳过", "根据图片自行判断" ]; /** 规则标签颜色映射 */ var RULE_TAG_CLASS_MAP = { "见光死": "gc-tag-red", "主体拦截": "gc-tag-orange", "封面拦截": "gc-tag-blue", "通过需监控": "gc-tag-cyan", "通过需进标": "gc-tag-green", "正常通过": "gc-tag-green", "跳过": "gc-tag-gray", "根据图片自行判断": "gc-tag-gray" }; // ==================== 快捷键配置 ==================== /** 默认快捷键: { action: keyCode } */ var DEFAULT_SHORTCUTS = { prioritySubmit: 49, // 数字1 → 优先+提交 rejectSubmit: 50, // 数字2 → 不通过+提交 submitOnly: 13 // Enter → 仅提交 }; /** 快捷键动作显示名称 */ var SHORTCUT_LABELS = { prioritySubmit: "命中+提交", rejectSubmit: "未命中+提交", submitOnly: "仅提交" }; /** keyCode → 可读名称映射 */ function keyNameFromCode(code) { if (code >= 48 && code <= 57) return String.fromCharCode(code); // 0-9 if (code >= 65 && code <= 90) return String.fromCharCode(code); // A-Z if (code === 13) return "Enter"; if (code === 32) return "Space"; if (code === 27) return "Esc"; if (code === 9) return "Tab"; if (code === 8) return "Backspace"; if (code === 37) return "←"; if (code === 38) return "↑"; if (code === 39) return "→"; if (code === 40) return "↓"; if (code === 112) return "F1"; if (code === 113) return "F2"; if (code === 114) return "F3"; if (code === 115) return "F4"; if (code === 116) return "F5"; if (code === 117) return "F6"; if (code === 118) return "F7"; if (code === 119) return "F8"; if (code === 120) return "F9"; if (code === 121) return "F10"; if (code === 122) return "F11"; if (code === 123) return "F12"; if (code === 187) return "="; if (code === 189) return "-"; if (code === 219) return "["; if (code === 221) return "]"; if (code === 186) return ";"; if (code === 222) return "'"; if (code === 188) return ","; if (code === 190) return "."; if (code === 191) return "/"; return "Code:" + code; } /** 快捷键管理器 */ var ShortcutManager = { _cache: null, load: function () { if (this._cache) return this._cache; var saved = GM_getValue("shortcuts_custom", null); if (saved && typeof saved === "object") { this._cache = {}; for (var k in DEFAULT_SHORTCUTS) { this._cache[k] = saved[k] !== undefined ? saved[k] : DEFAULT_SHORTCUTS[k]; } } else { this._cache = {}; for (var d in DEFAULT_SHORTCUTS) { this._cache[d] = DEFAULT_SHORTCUTS[d]; } } return this._cache; }, save: function (shortcuts) { this._cache = shortcuts; GM_setValue("shortcuts_custom", shortcuts); }, reset: function () { GM_deleteValue("shortcuts_custom"); this._cache = null; return this.load(); }, get: function (action) { return this.load()[action]; } }; // ==================== 默认词库 ==================== var DEFAULT_GLOSSARY = "果然很豆 见光死|黄之锋 主体拦截|房辉峰 主体拦截,封面拦截|胡乃文 见光死|黄明志 见光死|孙力军 主体拦截,封面拦截|Vanessa 正常通过|郑圣哲 见光死|杨晶 主体拦截,封面拦截|郭伯雄 主体拦截,封面拦截|孙政才 主体拦截,封面拦截|周永康 见光死|薄熙来 见光死|陈良宇 主体拦截,封面拦截|房峰辉 主体拦截,封面拦截|令计划 见光死|王立军 主体拦截,封面拦截|徐才厚 见光死|傅政华 主体拦截,封面拦截|席明海 主体拦截|林昶佐 见光死|大支 主体拦截|多里坤·艾沙 主体拦截,封面拦截|热比娅 主体拦截|李卓人 主体拦截|黄耀明 主体拦截,封面拦截|何韵诗 主体拦截|罗冠聪 主体拦截|陈秋实 见光死|洛桑桑洁 见光死|达赖 见光死|陈光诚 主体拦截|伊内斯·坎特 主体拦截|李洪志 见光死|江峰 主体拦截|迈克陈 主体拦截,封面拦截|文睿 见光死|石涛 见光死|张华 主体拦截|果果和豆豆 主体拦截|刘晓波 见光死|柴玲 见光死|刘霞 见光死|王丹 见光死|吾尔开希 见光死|郝海东 见光死|郭文贵 见光死|释净空 见光死|cici|li 见光死|叶钊颖 见光死|徐晓冬 见光死|姜光宇 主体拦截|文昭 见光死|周庭 主体拦截|郭竞雄 见光死|彭波 主体拦截,封面拦截|苏荣 主体拦截,封面拦截|赵昕 见光死|陈破空 见光死|刘新云 主体拦截,封面拦截|刘仲敬 主体拦截|池子 主体拦截|cicili 见光死|达赖young 见光死|傅振华 主体拦截,封面拦截|王越池 主体拦截|徐晓东 见光死|梁振英 通过需监控|李小鹏 通过需监控|胡海峰 通过需监控|李小琳 通过需监控|董建华 通过需监控|彭帅 通过需监控|杨洁篪 根据图片自行判断|林郑月娥 通过需监控|华春莹 通过需监控|汪文斌 根据图片自行判断|佩洛西 通过需监控|乔·拜登 正常通过|弗拉基米尔·泽连斯基 通过需监控|张澜澜 通过需监控|马元 通过需监控|李书福 通过需监控|侯德健 通过需监控|崔健 通过需监控|老八 根据图片自行判断|佟丽娅 通过需监控|孟建柱 主体拦截,封面拦截|毛宁 根据图片自行判断|赵立坚 根据图片自行判断|李佳琦 通过需监控|南希佩洛西 通过需监控|戈尔巴乔夫 通过需监控|胡锡进 通过需监控,通过需进标|蔡英文 通过需监控|马英九 通过需监控|金正恩 通过需监控|金日成 通过需监控|金正日 通过需监控|金与正 通过需监控|列宁 通过需监控|弗拉基米尔·弗拉基米罗维奇·普京 通过需监控|唐纳德·特朗普 正常通过|伊丽莎白二世 通过需监控|希特勒 通过需监控|蔡霞 通过需监控|姚文元 通过需监控|江青 通过需监控|张春桥 通过需监控|邓小平mask 通过需监控|毛泽东mask 通过需监控|宋祖英 通过需监控,通过需进标|韩国瑜 正常通过|李登辉(台湾前领导人) 正常通过|赖清德 通过需监控|陈水扁 正常通过|李登辉 正常通过|安倍晋三 通过需进标|斯大林 通过需进标|陈一发儿 通过需进标|马保国 正常通过|古月 通过需监控|贺一诚 正常通过|玄松月 正常通过|付凌晖(国家统计局司长) 正常通过|朱凤莲 正常通过|曾荫权 正常通过|虎子 正常通过|刀哥 正常通过|李云迪 正常通过|虎哥 正常通过|彭清华 正常通过|付凌晖 正常通过|吴尊友 正常通过|孙业礼 正常通过|陈睿 正常通过|罗翔 正常通过|江泽民 通过需监控,通过需进标|邓小平 通过需监控|毛泽东 通过需监控|刘少奇 通过需监控|周恩来 通过需监控|吴亦凡 通过需进标|张哲瀚 通过需进标|赵薇 通过需进标|邓伦 通过需进标|郑爽 通过需进标|江泽民mask 通过需监控,通过需进标|蔡奇 主体拦截,封面拦截|刘鹤 主体拦截,封面拦截|王立科 主体拦截,封面拦截|陈吉宁 主体拦截,封面拦截|慎海雄 主体拦截,封面拦截|俞正声 主体拦截,封面拦截|毛新宇 主体拦截,封面拦截|应勇 根据图片自行判断|江绵恒 主体拦截,封面拦截|张德江 主体拦截,封面拦截|刘云山 主体拦截,封面拦截|华国锋 主体拦截,封面拦截|朱镕基 主体拦截,封面拦截|郭声琨 主体拦截,封面拦截|任志强(贪官) 主体拦截,封面拦截|秦刚(外交部发言人) 根据图片自行判断|黄坤明(中央宣传部部长) 主体拦截,封面拦截|比约克 主体拦截,封面拦截|曾庆红 主体拦截,封面拦截|许其亮 主体拦截,封面拦截|沈彤 主体拦截,封面拦截|张又侠 主体拦截,封面拦截|谢春涛 主体拦截,封面拦截|习近平 主体拦截,封面拦截|汪洋 主体拦截,封面拦截|韩正 主体拦截,封面拦截|栗战书 主体拦截,封面拦截|王沪宁 主体拦截,封面拦截|李克强 主体拦截,封面拦截|王岐山 主体拦截,封面拦截|赵乐际 主体拦截,封面拦截|李强 主体拦截,封面拦截|胡春华 主体拦截,封面拦截|陈希 主体拦截,封面拦截|丁薛祥 主体拦截,封面拦截|孙春兰 主体拦截,封面拦截|杨晓渡 主体拦截,封面拦截|胡锦涛 主体拦截,封面拦截|胡耀邦 主体拦截,封面拦截|张高丽 主体拦截,封面拦截|温家宝 主体拦截,封面拦截|习仲勋 主体拦截,封面拦截|彭丽媛 主体拦截,封面拦截|任志强 主体拦截,封面拦截|陈敏尔 主体拦截,封面拦截|徐若瑄 主体拦截,封面拦截|陈之汉 主体拦截,封面拦截|黎智英 主体拦截,封面拦截|陈方安生 主体拦截,封面拦截|杜汶泽 主体拦截,封面拦截|何俊仁 主体拦截,封面拦截|石光磊 主体拦截,封面拦截|赵紫阳 主体拦截,封面拦截|王洪文 主体拦截,封面拦截|李鹏 主体拦截,封面拦截|瓦列里·萨布林 主体拦截,封面拦截|jreg 主体拦截,封面拦截|乔瑟夫 主体拦截,封面拦截|李志 主体拦截,封面拦截|方舟子 主体拦截,封面拦截|黑手 正常通过|盛嘉奎 主体拦截,封面拦截|黄坤明 主体拦截,封面拦截|贺军科 主体拦截,封面拦截|李希 主体拦截,封面拦截|刘克清 主体拦截,封面拦截|龚正 主体拦截,封面拦截|李锐 主体拦截,封面拦截|秦刚 根据图片自行判断|徐勤根 主体拦截,封面拦截|王晨 主体拦截,封面拦截|李鸿忠 主体拦截,封面拦截|陈全国 主体拦截,封面拦截|胡锦涛mask 主体拦截,封面拦截|李锐1917 主体拦截,封面拦截|习近平mask2 主体拦截,封面拦截|王毅 通过需监控|柯文哲 正常通过|黄之峰 主体拦截|蒋万安 正常通过|赵少康 正常通过|涉政图片 跳过|吴谦 正常通过|庄志刚 封面拦截,主体拦截|萧美琴 正常通过|侯友宜 正常通过|萨沙 封面拦截,主体拦截|石国鹏 封面拦截,主体拦截|吴欣盈 正常通过|涉政图片0 跳过|莫迪 通过需监控|马克龙 通过需监控|董军 通过需监控|罗玉凤 正常通过|马朝旭 通过需监控|柴静 正常通过|刘华清 通过需进标|丁子霖 见光死|周锋锁 见光死|封从德 见光死|李尚福 见光死|魏凤和 见光死|基利安·姆巴佩 正常通过|唐仁健 主体拦截,封面拦截|王小鲁 正常通过|王小洪 通过需监控,通过需进标|彼得森 正常通过|毛泽东卡通 通过需监控|毛泽东橘子洲 通过需监控|习近平左脸 主体拦截,封面拦截|习近平卡通 主体拦截,封面拦截|习近平右脸 主体拦截,封面拦截|蓝佛安 正常通过|刘建超 正常通过|江泽民卡通 通过需监控,通过需进标|戴晴 主体拦截|界立建 见光死|习远平 主体拦截,封面拦截|涉政其他集合 跳过|聊天 正常通过|两会 主体拦截,封面拦截|发布会 主体拦截,封面拦截|天安门 通过需监控,通过需进标|人民大会堂 正常通过|新华门 正常通过|横幅 正常通过|化学实验 正常通过|中国地图 正常通过|青天白日旗 根据图片自行判断|纳粹旗 正常通过|旭日旗 正常通过|isis旗帜 见光死|雪山狮子旗 见光死|全能神旗 见光死|蒙独旗 见光死|蓝星月旗帜 见光死|法轮功旗 见光死|香港区旗 正常通过|壹电视 主体拦截,封面拦截|苹果日报 主体拦截,封面拦截|国际特赦 主体拦截,封面拦截|美国之声 主体拦截|新唐人 见光死|自由亚洲电台 主体拦截,封面拦截|枪支 正常通过|虚拟枪支 正常通过|刀 正常通过|战舰 正常通过|坦克 正常通过|中国地图 正常通过|国旗 正常通过|党徽 正常通过|国徽 正常通过|人民币 正常通过|维尼熊 通过需监控,通过需进标|其他卡通熊 正常通过|64纪念碑 见光死|二维码 正常通过|头巾 正常通过|哔咔 主体拦截,封面拦截|pornhub 主体拦截,封面拦截|坦克人 见光死|民主女神 见光死|民主纪念碑 见光死|党旗 正常通过|变形国旗 正常通过"; // ==================== 词库管理器 ==================== var GlossaryManager = { /** 从GM存储加载词库,若无则使用默认值 */ load: function () { var saved = GM_getValue("glossary_custom", ""); return (saved && saved.trim()) ? saved.trim() : DEFAULT_GLOSSARY; }, /** 将词库保存到GM存储 */ save: function (glossaryStr) { GM_setValue("glossary_custom", glossaryStr); }, /** 重置为默认词库 */ reset: function () { GM_deleteValue("glossary_custom"); return DEFAULT_GLOSSARY; }, /** * 将词库字符串解析为对象数组 * @returns {Array<{name: string, rules: string[]}>} */ parseToArray: function (glossaryStr) { if (!glossaryStr) return []; var entries = glossaryStr.split("|"); var result = []; for (var i = 0; i < entries.length; i++) { var parts = entries[i].split("\t"); if (parts.length >= 2 && parts[0].trim()) { result.push({ name: parts[0].trim(), rules: parts[1].split(",").map(function (s) { return s.trim(); }).filter(function (s) { return s; }) }); } } return result; }, /** 从对象数组还原为词库字符串 */ arrayToString: function (arr) { var parts = []; for (var i = 0; i < arr.length; i++) { if (arr[i].name && arr[i].rules.length > 0) { parts.push(arr[i].name + "\t" + arr[i].rules.join(",")); } } return parts.join("|"); }, /** 搜索词条(支持按名称和规则关键词搜索) */ search: function (glossaryStr, keyword) { keyword = (keyword || "").toLowerCase(); if (!keyword) return this.parseToArray(glossaryStr); var all = this.parseToArray(glossaryStr); return all.filter(function (item) { return item.name.toLowerCase().indexOf(keyword) > -1 || item.rules.some(function (r) { return r.toLowerCase().indexOf(keyword) > -1; }); }); } }; // ==================== 词库查找索引(Map,O(1)匹配) ==================== var Glossary1 = GlossaryManager.load(); /** 哈希索引:name → rulesStr */ var glossaryIndex = new Map(); /** 从词库字符串构建查找索引 */ function buildGlossaryIndex(glossaryStr) { glossaryIndex.clear(); if (!glossaryStr) return; var entries = glossaryStr.split("|"); for (var i = 0; i < entries.length; i++) { var tabIdx = entries[i].indexOf("\t"); if (tabIdx > -1) { var name = entries[i].substring(0, tabIdx).trim(); var rules = entries[i].substring(tabIdx + 1).trim(); if (name) glossaryIndex.set(name, rules); } } } /** 初始化索引 */ buildGlossaryIndex(Glossary1); /** 词库变更后重建索引 */ function onGlossaryChanged() { buildGlossaryIndex(Glossary1); } // ==================== 配置面板UI模块 ==================== var ConfigPanel = { panelEl: null, isOpen: false, editingIndex: -1, /** 样式注入(幂等) */ injectStyles: function () { if (document.getElementById("glossary-config-styles")) return; var css = document.createElement("style"); css.id = "glossary-config-styles"; css.textContent = [ ".gc-settings-btn {", " position: fixed; top: 10px; right: 10px; z-index: 99999;", " width: 40px; height: 40px; border-radius: 50%;", " background: linear-gradient(135deg, #667eea, #764ba2);", " border: none; color: #fff; font-size: 20px;", " cursor: pointer; box-shadow: 0 2px 10px rgba(0,0,0,.3);", " display: flex; align-items: center; justify-content: center;", " transition: transform .2s, box-shadow .2s;", "}", ".gc-settings-btn:hover { transform: scale(1.1); box-shadow: 0 4px 16px rgba(0,0,0,.4); }", ".gc-overlay {", " position: fixed; top: 0; left: 0; right: 0; bottom: 0;", " background: rgba(0,0,0,.5); z-index: 100000;", " display: flex; align-items: center; justify-content: center;", "}", ".gc-panel {", " width: 720px; max-height: 80vh; background: #fff; border-radius: 12px;", " box-shadow: 0 8px 40px rgba(0,0,0,.3);", " display: flex; flex-direction: column; overflow: hidden;", " font-family: -apple-system, 'Microsoft YaHei', sans-serif;", "}", ".gc-header {", " padding: 16px 20px; background: linear-gradient(135deg, #667eea, #764ba2);", " color: #fff; display: flex; justify-content: space-between; align-items: center;", "}", ".gc-header h3 { margin: 0; font-size: 18px; font-weight: 600; }", ".gc-close-btn {", " background: rgba(255,255,255,.2); border: none; color: #fff;", " width: 30px; height: 30px; border-radius: 50%; font-size: 18px;", " cursor: pointer; line-height: 1; transition: background .2s;", "}", ".gc-close-btn:hover { background: rgba(255,255,255,.35); }", ".gc-toolbar {", " padding: 12px 20px; border-bottom: 1px solid #eee; display: flex; gap: 10px; align-items: center; flex-wrap: wrap;", "}", ".gc-search-input {", " flex: 1; min-width: 180px; padding: 7px 14px; border: 1px solid #dcdfe6; border-radius: 6px;", " font-size: 14px; outline: none; transition: border-color .2s;", "}", ".gc-search-input:focus { border-color: #667eea; }", ".gc-toolbar-btn {", " padding: 7px 16px; border-radius: 6px; border: none; font-size: 13px; cursor: pointer;", " transition: opacity .2s; white-space: nowrap; font-weight: 500;", "}", ".gc-btn-primary { background: #667eea; color: #fff; } .gc-btn-primary:hover { opacity: .85; }", ".gc-btn-success { background: #67c23a; color: #fff; } .gc-btn-success:hover { opacity: .85; }", ".gc-btn-warning { background: #e6a23c; color: #fff; } .gc-btn-warning:hover { opacity: .85; }", ".gc-btn-danger { background: #f56c6c; color: #fff; } .gc-btn-danger:hover { opacity: .85; }", ".gc-btn-default { background: #f4f4f5; color: #606266; border: 1px solid #dcdfe6; } .gc-btn-default:hover { opacity: .75; }", ".gc-table-wrap { flex: 1; overflow-y: auto; padding: 0 20px; }", ".gc-table { width: 100%; border-collapse: collapse; font-size: 13px; }", ".gc-table th { position: sticky; top: 0; z-index: 1; background: #fafafa; padding: 10px 12px; text-align: left; border-bottom: 2px solid #ebeef5; font-weight: 600; color: #303133; }", ".gc-table td { padding: 8px 12px; border-bottom: 1px solid #f0f0f0; vertical-align: middle; word-break: break-all; }", ".gc-table tr:hover td { background: #f5f7ff; }", ".gc-name-cell { font-weight: 500; color: #303133; min-width: 120px; }", ".gc-rule-tags { display: flex; flex-wrap: wrap; gap: 4px; }", ".gc-tag { padding: 2px 8px; border-radius: 4px; font-size: 12px; color: #fff; }", ".gc-tag-red { background: #f56c6c; } .gc-tag-orange { background: #e6a23c; }", ".gc-tag-blue { background: #409eff; } .gc-tag-green { background: #67c23a; }", ".gc-tag-cyan { background: #13ce66; } .gc-tag-gray { background: #909399; }", ".gc-action-cell { white-space: nowrap; width: 90px; }", ".gc-action-btn { padding: 3px 10px; margin-right: 4px; border: none; border-radius: 4px; font-size: 12px; cursor: pointer; color: #fff; transition: opacity .2s; }", ".gc-action-btn:hover { opacity: .8; }", ".gc-edit-btn { background: #409eff; } .gc-del-btn { background: #f56c6c; }", ".gc-footer { padding: 10px 20px; border-top: 1px solid #eee; font-size: 13px; color: #909399; display: flex; justify-content: space-between; align-items: center; }", ".gc-modal-overlay { position: fixed; top:0; left:0; right:0; bottom:0; background: rgba(0,0,0,.45); z-index: 200000; display: flex; align-items: center; justify-content: center; }", ".gc-form-modal { width: 420px; background: #fff; border-radius: 10px; padding: 24px; box-shadow: 0 8px 30px rgba(0,0,0,.25); font-family: inherit; }", ".gc-form-title { margin: 0 0 16px; font-size: 16px; color: #303133; }", ".gc-form-group { margin-bottom: 16px; }", ".gc-form-label { display: block; margin-bottom: 6px; font-size: 13px; color: #606266; font-weight: 500; }", ".gc-form-input { width: 100%; padding: 8px 12px; border: 1px solid #dcdfe6; border-radius: 6px; font-size: 14px; outline: none; box-sizing: border-box; font-family: inherit; }", ".gc-form-input:focus { border-color: #667eea; }", ".gc-checkbox-group { display: flex; flex-wrap: wrap; gap: 8px; }", ".gc-checkbox-item { display: flex; align-items: center; gap: 4px; cursor: pointer; font-size: 13px; color: #606266; }", ".gc-checkbox-item input { accent-color: #667eea; }", ".gc-form-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 20px; }", ".gc-toast { position: fixed; top: 20px; left: 50%; transform: translateX(-50%); padding: 10px 24px; border-radius: 6px; color: #fff; font-size: 14px; z-index: 300000; animation: gcFadeIn .3s ease; pointer-events: none; }", "@keyframes gcFadeIn { from{opacity:0;transform:translateX(-50%) translateY(-10px)} to{opacity:1;transform:translateX(-50%) translateY(0)} }", ".gc-toast-success { background: #67c23a; } .gc-toast-error { background: #f56c6c; } .gc-toast-info { background: #909399; }", ".gc-empty { text-align: center; padding: 40px 20px; color: #c0c4cc; }", ".gc-empty-icon { font-size: 48px; margin-bottom: 10px; } .gc-empty-text { font-size: 14px; }", ".gc-import-area { width:100%; height:200px; padding:10px; border:1px solid #dcdfe6;border-radius:6px;font-size:12px;font-family:monospace;resize:vertical;box-sizing:border-box;margin-top:8px; }", ".gc-shortcut-hint { position:fixed; bottom:20px; right:20px; z-index:99998; background:rgba(0,0,0,.75); color:#fff; padding:12px 18px; border-radius:8px; font-size:12px; line-height:1.8; font-family:-apple-system,'Microsoft YaHei',sans-serif; transition:opacity .5s; cursor:pointer; }", ".gc-shortcut-hint .gc-key { display:inline-block; background:#667eea; color:#fff; padding:1px 8px; border-radius:3px; font-weight:600; margin:0 2px; }", ".gc-kb-btn { position:fixed; top:10px; right:58px; z-index:99999; width:40px; height:40px; border-radius:50%; background:linear-gradient(135deg,#409eff,#337ecc); border:none; color:#fff; font-size:18px; cursor:pointer; box-shadow:0 2px 10px rgba(0,0,0,.3); display:flex; align-items:center; justify-content:center; transition:transform .2s,box-shadow .2s; }", ".gc-kb-btn:hover { transform:scale(1.1); box-shadow:0 4px 16px rgba(0,0,0,.4); }", ".gc-kb-row { display:flex; align-items:center; justify-content:space-between; padding:10px 0; border-bottom:1px solid #f0f0f0; }", ".gc-kb-row:last-child { border-bottom:none; }", ".gc-kb-action-name { font-size:14px; color:#303133; font-weight:500; }", ".gc-kb-key-box { display:inline-block; min-width:60px; padding:4px 14px; background:#f4f4f5; border:1px solid #dcdfe6; border-radius:4px; font-size:13px; color:#606266; text-align:center; cursor:pointer; transition:border-color .2s,background .2s; user-select:none; }", ".gc-kb-key-box:hover { border-color:#409eff; }", ".gc-kb-key-box.gc-recording { background:#ecf5ff; border-color:#409eff; color:#409eff; animation:gcPulse 1s infinite; }", "@keyframes gcPulse { 0%,100%{box-shadow:0 0 0 0 rgba(64,158,255,.3)} 50%{box-shadow:0 0 0 6px rgba(64,158,255,0)} }", ].join("\n"); document.head.appendChild(css); }, /** 显示Toast消息 */ showToast: function (msg, type) { type = type || "info"; var toast = document.createElement("div"); toast.className = "gc-toast gc-toast-" + type; toast.textContent = msg; document.body.appendChild(toast); setTimeout(function () { if (toast.parentNode) toast.parentNode.removeChild(toast); }, 2200); }, /** 渲染表格 */ renderTable: function (data) { var tbody = this.panelEl.querySelector(".gc-tbody"); if (!data || data.length === 0) { tbody.innerHTML = '
粘贴词库数据(格式:名称\\t规则|名称\\t规则...)
' + '' + '| 名称(关键词) | 匹配规则 | 操作 |
|---|