// ==UserScript==
// @name 0x3f-problem-solution
// @namespace https://greasyfork.org/zh-CN/scripts/501134-0x3f-problem-solution
// @version 0.0.5.2-a
// @author wuxin0011
// @description 自定义分数区间显示题目 标记题目状态 配合灵茶山艾府题单解题
// @license MIT
// @icon https://assets.leetcode.cn/aliyun-lc-upload/users/endlesscheng/avatar_1690721039.png
// @source https://github.com/wuxin0011/tampermonkey-script/tree/main/0x3f-leetcode
// @supportURL https://greasyfork.org/zh-CN/scripts/501134-0x3f-problem-solution/feedback
// @match https://leetcode.cn/circle/discuss/*
// @match https://leetcode.cn/problems/*
// @match https://leetcode.cn/contest/*/problems/*
// @require https://unpkg.com/vue@3.4.31/dist/vue.global.prod.js
// @require data:application/javascript,%3Bwindow.Vue%3DVue%3B
// @require https://unpkg.com/element-plus@2.7.6/dist/index.full.js
// @resource elementPlusCss https://unpkg.com/element-plus@2.7.6/dist/index.css
// @grant GM_addStyle
// @grant GM_deleteValue
// @grant GM_getResourceText
// @grant GM_getValue
// @grant GM_registerMenuCommand
// @grant GM_setValue
// ==/UserScript==
(t=>{if(typeof GM_addStyle=="function"){GM_addStyle(t);return}const e=document.createElement("style");e.textContent=t,document.head.append(e)})(" h2[data-v-49e5e62d]{color:#000;margin:10px 0}em[data-v-49e5e62d]{color:red}.m-setting-button[data-v-333abb74]{position:fixed;top:200px;right:0;z-index:100000}.m-button[data-v-333abb74]{margin-left:16px!important;padding:5px!important;font-size:14px!important}.processs-flex[data-v-333abb74]{display:flex;justify-content:center;align-items:center}.m-setting-button[data-v-6868725a]{position:fixed;top:200px;right:0;z-index:100000}.m-button[data-v-6868725a]{margin-left:16px!important;padding:5px!important;font-size:14px!important}.processs-flex[data-v-6868725a]{display:flex;justify-content:center;align-items:center} ");
(function (ElementPlus, vue) {
'use strict';
var _GM_deleteValue = /* @__PURE__ */ (() => typeof GM_deleteValue != "undefined" ? GM_deleteValue : void 0)();
var _GM_getValue = /* @__PURE__ */ (() => typeof GM_getValue != "undefined" ? GM_getValue : void 0)();
var _GM_registerMenuCommand = /* @__PURE__ */ (() => typeof GM_registerMenuCommand != "undefined" ? GM_registerMenuCommand : void 0)();
var _GM_setValue = /* @__PURE__ */ (() => typeof GM_setValue != "undefined" ? GM_setValue : void 0)();
let Cache$1 = class Cache2 {
set(k, v) {
_GM_setValue(k, v);
}
get(k, parse = true, name = String.name) {
try {
let v = _GM_getValue(k);
switch (name) {
case String.name:
if (v == null) {
return "null";
}
return v;
case Object.name:
if (v == null || v == void 0 || typeof v != "object") {
return {};
}
return v;
case Boolean.name:
if (v === null || v == void 0) {
return false;
}
if (v == false || v == "false" || v == "" || v == "null") {
return false;
}
return v;
case Array.name:
if (v === null || v == void 0 || !Array.isArray(v)) {
return [];
}
return v;
default:
return v;
}
} catch (E) {
return null;
}
}
remove(k) {
_GM_deleteValue(k);
}
};
const Cache$2 = new Cache$1();
const isHttp = (url) => /^https?:\/\/.*$/.test(url);
const isLeetCodeCircleUrl = (url = window.location.href) => /^https?:\/\/leetcode\.cn\/circle\/discuss\/.*/i.test(url);
const isProblem = (url = window.location.href) => /^https?:\/\/leetcode\.cn\/problems\/.*/i.test(url);
const isContest = (url = window.location.href) => /^https?:\/\/leetcode\.cn\/contest\/.*\/problems\/.*/.test(url);
const isBilibili = (url = window.location.href) => /.*bilibili.*/.test(url);
const sleep = async (time = 500) => new Promise((resolove) => setTimeout(resolove, time));
const isDev = () => false;
const width = 14;
const height = 14;
const bilibiliSVG = () => {
return `
`;
};
const problemContenst = () => `
`;
const problemFinsh = () => `
`;
const problemsTry = () => `
`;
const problemsNo = () => install_pos() ? `
` : ``;
const createStatus = (status, link) => {
var _a;
let node;
if (!link) {
return;
}
const curUrl = (link == null ? void 0 : link.href) ?? ((_a = link.querySelector("a")) == null ? void 0 : _a.href);
node = link instanceof HTMLAnchorElement ? link.parentElement : link;
if (node) {
node.status = status;
}
let installSVG = "";
if (isContest(curUrl)) {
installSVG = problemContenst();
} else if (isLeetCodeCircleUrl(curUrl)) ;
else if (isBilibili(curUrl)) {
installSVG = bilibiliSVG();
} else {
if (status == STATUS["AC"]) {
installSVG = problemFinsh();
} else if (status == STATUS["notac"]) {
installSVG = problemsTry();
} else if (status == STATUS["NO"]) {
installSVG = problemsNo();
}
}
let svg = node.querySelector("svg");
if (svg) {
if (svg.getAttribute("status") == status || svg.getAttribute("status") == STATUS["AC"]) {
return false;
}
svg.remove();
}
if (isBilibili(curUrl)) {
node.innerHTML = node.innerHTML + " " + installSVG;
} else {
node.innerHTML = install_pos() ? installSVG + node.innerHTML : node.innerHTML + installSVG;
}
return true;
};
const inf = 4e3;
const mi = 1e3;
const __0X3F_PROBLEM_KEYS__$1 = {
"__0x3f_problmes_solution__": "__0x3f_problmes_solution__",
// 基本信息
"__0x3f_problmes_urls__": "__0x3f_problmes_urls__",
// 题单key
"__0x3f_problmes_update__": "__0x3f_problmes_update__",
// 是否修改了默认题单key
"__0x3f_problmes_button_is_none__": "__is_none_0x3f_problmes_button__",
// 是否隐藏设置按钮
"__0x3f_problmes_insert_pos__": "__0x3f_problmes_insert_pos__",
// 安装位置
"__0x3f_problmes_status_update__": "__0x3f_problmes_status_update__",
"__0x3f_problmes_plugin_load_ok__": "__0x3f_problmes_plugin_load_ok__",
// 是否使用插件
"__0x3f_problmes_add_cur__": "__0x3f_problmes_add_cur__",
// 添加 url
"__0x3f_problmes_ac_key__": "__local_ok_problem_key__",
// ac key
"__0x3f_problmes_ac_version__": "__0x3f_problmes_ac_version__",
// TODO ac key version
"__0x3f_problmes_all_problems__": "__0x3f_problmes_all_problems__",
// all problems
"__0x3f_problmes_random_problems_key__": "__0x3f_problmes_random_problems_key__",
//随机题目快捷键
"__0x3f_problmes_random_problems__": "__0x3f_problmes_random_problems__"
//随机题目
};
const STATUS = {
"AC": "ac",
"NO": "null",
"notac": "notac",
"Accepted": "ac",
"Wrong Answer": "notac"
};
const defaultObj = {
min: mi,
max: inf,
visiableMember: true,
onlyUrls: false,
useDefaultSetting: true,
hiddenAc: false,
showAcConfig: true,
sortedType: 0
};
function install_pos() {
return !Cache$2.get(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_insert_pos__"], false, Boolean.name);
}
function isShow(text, min, max) {
if (!text) {
return true;
}
let res = text.match(/\d+/ig);
if (!res) {
return true;
}
if (Array.isArray(res) && res.length < 2) {
return true;
}
let s = 0;
for (let i = res.length - 1; i >= 0; i--) {
s = res[i];
if (s >= mi && s <= inf) {
return s >= min && s <= max;
}
}
return true;
}
let A = void 0;
const linkCssSelector = `#lc-content [class*="CollapsibleMarkdownContent"] [class*="MarkdownContent"] li>a`;
const queryProblem = () => Array.from(document.querySelectorAll(linkCssSelector)).filter((item) => item && item instanceof HTMLAnchorElement && (isProblem(item.href) || isContest(item.href)));
function loadProblems() {
A = queryProblem();
return A;
}
function handlerProblem(data) {
var _a;
try {
loadProblems();
let { min, max, visiableMember, useDefaultSetting, onlyUrls, hiddenAc } = data;
if (isNaN(min) || isNaN(max)) {
min = mi;
max = inf;
}
if (min < mi) {
min = mi;
}
if (max < min) {
max = inf;
}
min = Number(min);
max = Number(max);
data.min = min;
data.max = max;
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_solution__"], data);
for (let i = 0; i < A.length; i++) {
if (!(A[i] instanceof HTMLAnchorElement)) {
continue;
}
let d = (_a = A[i]) == null ? void 0 : _a.parentNode;
if (!d) {
continue;
}
let none = false;
let Nohidden = isShow(d.textContent, min, max);
d.style.display = Nohidden ? "" : "none";
if (!Nohidden) {
continue;
}
if (hiddenAc) {
const svg = d.querySelector("svg");
if (svg && svg.getAttribute("status")) {
d.style.display = svg.getAttribute("status") == STATUS["AC"] ? "none" : "";
}
} else {
d.style.display = "";
}
let c = d.textContent && d.textContent.indexOf("会员") != -1;
if (!c) {
continue;
}
d.style.display = visiableMember ? "" : "none";
}
} catch (e) {
console.log("error", e);
}
}
function computeAcInfo(saveUrls = [], deleteOk = true) {
let infos = [];
let set = /* @__PURE__ */ new Set();
for (let i = 0, u = null; Array.isArray(saveUrls) && i < saveUrls.length; i++) {
try {
u = saveUrls[i];
if (!(u == null ? void 0 : u.link) || !(u == null ? void 0 : u.title) || !(u == null ? void 0 : u.id) || set.has(u.link)) {
continue;
}
if (u["select"] == void 0) u.select = true;
if (u["loading"] == void 0 || u["loading"]) u["loading"] = false;
let s = Object.values(u).join("");
if (s == "null" || !Cache$2.get(u.link) || !getAcCountKey(u.link) || !Cache$2.get(getAcCountKey(u.link))) {
continue;
}
let o = Cache$2.get(getAcCountKey(u.link));
u["ac"] = isNaN(o["ac"]) ? 0 : parseInt(o["ac"]);
u["tot"] = isNaN(o["tot"]) ? 0 : parseInt(o["tot"]);
set.add(u.link);
} catch (e) {
}
infos.push(Object.assign({}, u));
}
if (deleteOk) {
for (let i = 0; i < saveUrls[i]; i++) {
delete saveUrls[i];
}
for (let info of infos) {
saveUrls.push(info);
}
}
return infos;
}
const initUrls = () => {
let saveUrls = Cache$2.get(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_update__"], true, Boolean.name) ? Cache$2.get(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_urls__"], true, Array.name) : defaultUrls;
return computeAcInfo(saveUrls);
};
const initObj = () => {
let obj = Cache$2.get(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_solution__"]) ? Object.assign(defaultObj, Cache$2.get(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_solution__"])) : defaultObj;
if (obj["showAcConfig"] == null || obj["showAcConfig"] == void 0) {
obj.showAcConfig = true;
}
if (obj["sortedType"] == null || obj["sortedType"] == void 0) {
obj.sortedType = 0;
}
let temp = {};
for (let key of Object.keys(obj)) {
if (!isNaN(key) || defaultObj[`${key}`] == void 0) continue;
temp[`${key}`] = obj[`${key}`];
}
return temp;
};
const support_plugins = () => {
const u = initObj();
if (!u || !u.onlyUrls) return true;
let url = window.location.href;
if (isLeetCodeCircleUrl(url) && url.indexOf("view") != -1) {
try {
url = url.split("view")[0];
} catch (e) {
url = window.location.href;
}
}
const urls = initUrls();
for (let info of urls) {
if (!info || !(info == null ? void 0 : info.link)) {
continue;
}
if (info.link.indexOf(url) != -1) {
return true;
}
}
return false;
};
const defaultUrls = [
{ "title": "数学算法(数论/组合/概率期望/博弈/计算几何/随机算法", "link": "https://leetcode.cn/circle/discuss/IYT3ss/", "tot": 0, "ac": 0, "id": 1, "disabled": false, "select": true },
{ "title": "常用数据结构(前缀和/差分/栈/队列/堆/字典树/并查集/树状数组/线段树)", "link": "https://leetcode.cn/circle/discuss/mOr1u6/", "tot": 0, "ac": 0, "id": 2, "disabled": false, "select": true },
{ "title": "动态规划(入门/背包/状态机/划分/区间/状压/数位/树形/数据结构优化)", "link": "https://leetcode.cn/circle/discuss/tXLS3i/", "tot": 0, "ac": 0, "id": 3, "disabled": false, "select": true },
{ "title": "图论算法(DFS/BFS/拓扑排序/最短路/最小生成树/二分图/基环树/欧拉路径)", "link": "https://leetcode.cn/circle/discuss/01LUak/", "tot": 0, "ac": 0, "id": 4, "disabled": false, "select": true },
{ "title": "位运算(基础/性质/拆位/试填/恒等式/贪心/脑筋急转弯)", "link": "https://leetcode.cn/circle/discuss/dHn9Vk/", "tot": 0, "ac": 0, "id": 5, "disabled": false, "select": true },
{ "title": "网格图(DFS/BFS/综合应用)", "link": "https://leetcode.cn/circle/discuss/YiXPXW/", "tot": 0, "ac": 0, "id": 6, "disabled": false, "select": true },
{ "title": "单调栈(矩形面积/贡献法/最小字典序", "link": "https://leetcode.cn/circle/discuss/9oZFK9/", "tot": 0, "ac": 0, "id": 7, "disabled": false, "select": true },
{ "title": "二分算法(二分答案/最小化最大值/最大化最小值/第K小", "link": "https://leetcode.cn/circle/discuss/SqopEo/", "tot": 0, "ac": 0, "id": 8, "disabled": true, "select": true },
{ "title": "滑动窗口(定长/不定长/多指针", "link": "https://leetcode.cn/circle/discuss/0viNMK/", "tot": 0, "ac": 0, "id": 9, "disabled": false, "select": true },
{ "title": "贪心算法(基本贪心策略/反悔/区间/字典序/数学/思维/构造)", "link": "https://leetcode.cn/circle/discuss/g6KTKL/", "tot": 0, "ac": 0, "id": 10, "disabled": false, "select": true },
{ "title": "链表、二叉树与一般树(前后指针/快慢指针/DFS/BFS/直径/LCA)", "link": "https://leetcode.cn/circle/discuss/K0n2gO/", "tot": 0, "ac": 0, "id": 11, "disabled": false, "select": true },
{ "title": "字符串(KMP/Z函数/Manacher/字符串哈希/AC自动机/后缀数组/子序列自动机)", "link": "https://leetcode.cn/circle/discuss/SJFwQI/", "tot": 0, "ac": 0, "id": 12, "disabled": false, "select": true }
// { 'title': '灵茶题单完成情况', 'link': 'https://leetcode.cn/u/endlesscheng/', 'tot': 0, 'ac': 0, 'id': 0x3f3f3f3f,'disabled':true,'select':false },
];
function getId(problemUrl) {
if (isContest(problemUrl) || isProblem(problemUrl)) {
try {
return problemUrl.split("problems")[1].split("/")[1];
} catch (e) {
return "";
}
}
return "";
}
function postData(ID2) {
return {
"query": "\n query userQuestionStatus($titleSlug: String!) {\n question(titleSlug: $titleSlug) {\n status\n }\n}\n ",
"variables": {
"titleSlug": ID2
},
"operationName": "userQuestionStatus"
};
}
async function queryStatus(ID2 = "", cache = {}, cur = void 0, watch2 = false) {
var _a, _b, _c;
if (!ID2) {
return;
}
if (cache[ID2] == void 0 || cache[ID2] != STATUS["AC"]) {
const response = await getProblemAcInfo(ID2);
if ((_a = response == null ? void 0 : response.data) == null ? void 0 : _a.question) {
const status = (_c = (_b = response == null ? void 0 : response.data) == null ? void 0 : _b.question) == null ? void 0 : _c.status;
if (cache[ID2] == void 0 || cache[ID2] != status) {
cache[ID2] = status == null ? "null" : status;
if (watch2) {
watchSaveStatus(ID2, cache[ID2]);
}
createStatus(cache[ID2], cur);
}
} else {
console.warn("query result is undefined");
createStatus(cache[ID2], cur);
}
}
}
async function addProcess(reload = true, doms = void 0, asyncAc = false) {
var _a;
let problems_doms = Array.isArray(doms) ? doms : loadProblems();
const cache = getLocalProblemStatus();
let query_cnt = 0;
for (let i = 0; i < problems_doms.length; i++) {
let cur = problems_doms[i].parentElement;
if (!(cur instanceof HTMLElement)) {
continue;
}
const ID2 = getId((_a = problems_doms[i]) == null ? void 0 : _a.href);
if (!ID2) {
continue;
}
if (install_pos()) {
cur.style.listStyleType = "none";
}
if (!cache[ID2] || cache[ID2] != STATUS["AC"] && asyncAc) {
await sleep(50);
await queryStatus(ID2, cache, cur, false);
query_cnt++;
if (query_cnt % 10 == 0) {
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_ac_key__"], cache);
}
} else {
let status = cache[ID2];
createStatus(status, cur);
}
}
getProcess();
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_ac_key__"], cache);
let other = Array.from(document.querySelectorAll('#lc-content [class*="CollapsibleMarkdownContent"] [class*="MarkdownContent"] p>a')).filter((item) => item && item instanceof HTMLAnchorElement && isBilibili(item.href));
for (let i = 0; i < other.length; i++) {
createStatus("null", other[i]);
}
}
const submitProblems = (url = window.location.href, timeout = 500) => {
const ID2 = getId(url);
if (!ID2) {
return;
}
setTimeout(() => {
const cache = getLocalProblemStatus();
console.log("ID:", ID2, "query status: ", cache[ID2]);
queryStatus(ID2, cache, void 0, true);
}, timeout);
};
const watchSaveStatus = (ID2, status) => {
const cache = getLocalProblemStatus();
if (cache[ID2] != "ac") {
cache[ID2] = status;
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_ac_key__"], cache);
window.localStorage.setItem(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_status_update__"], JSON.stringify({
"id": ID2,
"status": status
}));
}
};
const watchLinkStatusUpdate = (e) => {
var _a;
if (e.key != __0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_status_update__"]) {
return;
}
let { id, status } = JSON.parse(e.newValue);
if (!id || !status) {
return;
}
let thisLink = `https://leetcode.cn/problems/${id}`;
let link = document.querySelector(`${linkCssSelector}[href^="https://leetcode.cn/problems/${id}"]`);
if (!link || !(link == null ? void 0 : link.parentElement)) {
let doms = loadProblems();
for (let i = 0; i < doms.length; i++) {
if (!doms[i] || !((_a = doms[i]) == null ? void 0 : _a.parentElement)) {
continue;
}
if (doms[i].href.indexOf(thisLink) != -1) {
link = doms[i];
break;
}
}
}
createStatus(status, link);
};
function getAcCountKey(k) {
if (!k) return "";
return `0x3f_ac_key_${k}`;
}
function deleteAllACCountKeys() {
let urls = initUrls();
let keys = [];
for (let urlInfo of urls) {
let key = getAcCountKey(urlInfo.link);
Cache$2.remove(key);
keys.push(key);
}
Cache$2.remove(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_ac_key__"]);
return keys;
}
function getProcess() {
loadProblems();
const cache = getLocalProblemStatus();
let cnt = 0;
for (let i = 0; i < A.length; i++) {
let ID2 = getId(A[i].href);
if (ID2 && cache[ID2] == STATUS["AC"]) {
cnt++;
}
}
let url = window.location.href;
if (A.length > 0 && getAcCountKey(url)) {
Cache$2.set(getAcCountKey(url), { "tot": A.length, "ac": cnt });
}
return [cnt, A.length];
}
function getLocalProblemStatus() {
return Cache$2.get(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_ac_key__"], true, Object.name);
}
function getRandomInfo(array) {
if (!Array.isArray(array)) return void 0;
return array[Math.floor(Math.random() * array.length)];
}
async function randomProblem() {
let allProbmems;
if (!Array.isArray(allProbmems) || allProbmems.length == 0) {
let response = await getProblemsJSON();
if (Array.isArray(response)) {
allProbmems = [...response];
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_all_problems__"], [...response]);
}
} else {
allProbmems = Cache$2.get(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_all_problems__"], true, Array.name);
}
if (!Array.isArray(allProbmems)) {
ElementPlus.ElMessage({
type: "error",
message: "随机题目失败获取不到任何信息 !请如果出现这种情况,请前往 https://github.com/wuxin0011/tampermonkey-script/issues 反馈",
duration: 6e3
});
return;
}
let config = initObj();
let urlsData = initUrls();
let set = /* @__PURE__ */ new Set();
for (let info of urlsData) {
if (info.link && info.select) {
set.add(info.link);
}
}
let infos = [];
let acMap = Cache$2.get(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_ac_key__"], true, Object.name);
for (let info of allProbmems) {
if (!(info == null ? void 0 : info.problemUrl) || !set.has(info == null ? void 0 : info.problemUrl) || !Array.isArray(info.problems) || info.problems.length == 0) {
continue;
}
for (let i = 0; Array.isArray(info.problems) && i < info.problems.length; i++) {
try {
let { title, url, member, score, titleSlug } = info.problems[i];
if (!url || !title) continue;
if (isDev()) ;
if (!(config == null ? void 0 : config.showAcConfig) && acMap[titleSlug] == "ac") {
continue;
}
if (!(config == null ? void 0 : config.visiableMember) && member) {
continue;
}
if (score != 0 && (score < (config == null ? void 0 : config.min) || score > (config == null ? void 0 : config.max))) {
continue;
}
infos.push({ title, url, member, score, titleSlug, "status": acMap[titleSlug] });
} catch (e) {
console.log("error", e);
}
}
}
let data = getRandomInfo(infos);
ElementPlus.ElMessage({
dangerouslyUseHTMLString: !!(data && (data == null ? void 0 : data.url) && (data == null ? void 0 : data.title)),
type: (data == null ? void 0 : data.url) && (data == null ? void 0 : data.title) ? "success" : "error",
message: (data == null ? void 0 : data.url) && (data == null ? void 0 : data.title) ? `
随机题目☕:
${data.title} ${(data == null ? void 0 : data.score) && (data == null ? void 0 : data.score) > 0 ? ` 分值${data.score}` : ""}
` : `没有符合条件的题目,请重新配置条件!`,
duration: 6e3
});
}
async function GetHubJSONInfo(url) {
return fetch(url, {
method: "get",
mode: "cors"
}).then((res) => res.json());
}
async function getProblemsJSON() {
return GetHubJSONInfo("https://raw.githubusercontent.com/wuxin0011/tampermonkey-script/main/0x3f-leetcode/0x3f.json");
}
async function PostLeetCodeApi(data) {
return fetch("https://leetcode.cn/graphql/", {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json"
},
body: JSON.stringify(data)
}).then((res) => res.json());
}
async function getProblemAcInfo(titleSlug) {
return PostLeetCodeApi(postData(titleSlug));
}
const _export_sfc = (sfc, props) => {
const target = sfc.__vccOpts || sfc;
for (const [key, val] of props) {
target[key] = val;
}
return target;
};
const _sfc_main$1 = {};
const _hoisted_1$1 = /* @__PURE__ */ vue.createStaticVNode(' 0. 同步功能使用前请确保为登录状态
1. 为什么部分题单出现统计数量为 0 情况 ?
防止一次性访问题单太多,对服务器产生压力,所以采用单个题单访问然后保存状态 , 这样避免访问量问题
默认情况下会缓存访问的题单情况,对于没有访问的题单,可以手动在对应题单中同步
2.题单有时候会出现不同步
这个没啥问题,题目状态根据用户提交题目情况会实时更新,只会在提交访问一次
3. 如何使用随机题目?
这个可以根据自己喜好来配置,配置好之后,可以使用 ctrl + alt + j 触发
4.反馈
', 9);
function _sfc_render(_ctx, _cache) {
const _component_el_link = vue.resolveComponent("el-link");
return vue.openBlock(), vue.createElementBlock("div", null, [
_hoisted_1$1,
vue.createElementVNode("p", null, [
vue.createTextVNode("你可以"),
vue.createVNode(_component_el_link, {
underline: false,
href: "https://greasyfork.org/zh-CN/scripts/501134-0x3f-problem-solution/feedback",
type: "primary",
target: "_blank"
}, {
default: vue.withCtx(() => [
vue.createTextVNode("点击")
]),
_: 1
}),
vue.createTextVNode("这里反馈 ,或者访问 github 提一个 "),
vue.createVNode(_component_el_link, {
target: "_blank",
underline: false,
href: "https://github.com/wuxin0011/tampermonkey-script/issues",
type: "primary"
}, {
default: vue.withCtx(() => [
vue.createTextVNode("issues")
]),
_: 1
})
])
]);
}
const Q1 = /* @__PURE__ */ _export_sfc(_sfc_main$1, [["render", _sfc_render], ["__scopeId", "data-v-49e5e62d"]]);
function Message(title = "确认操作", callback = () => {
}, canlcelCallback = () => {
}) {
ElementPlus.ElMessageBox.confirm(
`${title} ?`,
"警告",
{
confirmButtonText: "确认",
cancelButtonText: "取消",
type: "warning"
}
).then(() => {
callback();
}).catch(() => {
ElementPlus.ElMessage({
type: "info",
message: "已取消"
});
canlcelCallback();
});
}
const _hoisted_1 = { class: "dialog-footer" };
const _hoisted_2 = { class: "processs-flex" };
const _hoisted_3 = { style: { "text-align": "center", "color": "#121212" } };
const TARGET_URL = "https://leetcode.cn/u/endlesscheng/";
const formLabelWidth = "44px";
const _sfc_main = {
__name: "App",
setup(__props) {
const fromData = vue.reactive(initObj());
const tableButtonSize = vue.ref("default");
let tableData = vue.reactive(initUrls());
const keywords = vue.ref("");
const dialogTableVisible = vue.ref(false);
const showAddLocalButton = vue.computed(() => isLeetCodeCircleUrl());
let urlsData = vue.computed(() => {
let map = /* @__PURE__ */ new Map();
let infos = tableData.filter((info2) => {
if ((info2 == null ? void 0 : info2.title) && (info2 == null ? void 0 : info2.link) && !map.has(info2.link)) {
map.set(info2.link, info2);
return info2 && (info2.title && info2.title.indexOf(keywords.value) != -1 || info2.link && info2.link.indexOf(keywords.value) != -1);
} else {
return false;
}
});
let tot = 0, ac = 0;
for (let i = 0, c = info.length; i < infos.length; i++) {
let info2 = infos[i];
if (info2["ac"] && info2["tot"]) {
tot += info2["tot"];
ac += info2["ac"];
}
if (!info2["id"]) {
info2["id"] = c + 1;
c++;
}
}
let type = isNaN(fromData.sortType) ? 0 : fromData.sortType;
if (type == 0) {
infos.sort((info1, info2) => info2.id - info1.id);
} else if (type == 1) {
infos.sort((info1, info2) => info2.tot - info1.tot);
} else if (type == 2) {
infos.sort((info1, info2) => info2.ac - info1.ac);
} else if (type == 3) {
infos.sort((info1, info2) => computeProcess(info2.ac, info2.tot) - computeProcess(info1.ac, info1.tot));
}
infos.unshift({ "title": "灵茶题单完成情况", "link": TARGET_URL, "tot": tot, "ac": ac, "id": 67108863 });
return infos;
});
const rowIsDisabled = vue.computed(() => (info2) => asyncButtonLoad.value || info2 && info2.link == TARGET_URL);
const isDisabbled = vue.computed(() => !!tableData.find((v) => (v == null ? void 0 : v.link) && (v == null ? void 0 : v.link.indexOf(window.location.href)) != -1));
const dialogFormVisible = vue.ref(false);
const computeProcess = (ac = 0, tot = 0) => {
if (isNaN(ac) || isNaN(tot) || tot === 0) return 0;
let p = 0;
if (tot == ac) {
return 100;
}
const s = String(ac / tot);
try {
let x1 = s.split(".")[1] || "";
x1 = x1.padEnd(3, "0").substring(0, 3);
p = Math.min(100, Number(x1) / 10);
} catch (e) {
console.log("calc error", e.message, s == void 0, ac, tot);
p = (ac / tot).toFixed(3) * 100;
}
return isNaN(p) ? 0 : p;
};
const processColors = [
{ color: "#f56c6c", percentage: 20 },
{ color: "#1989fa", percentage: 40 },
{ color: "#e6a23c", percentage: 60 },
{ color: "#6f7ad3", percentage: 80 },
{ color: "#67c23a", percentage: 100 }
];
vue.watch(fromData, () => {
handlerProblem(vue.toRaw(Object.assign({}, fromData)));
});
const info = vue.reactive({
title: "",
link: "",
status: "add"
});
const addlocal = () => {
if (!isDisabbled) {
return;
}
let [cur, tot] = getProcess();
tableData.unshift({ title: document.title, link: window.location.href, "ac": cur, "tot": tot, "id": tableData.length + 10 });
};
const updateIndex = vue.ref(-1);
const handlerProblems = (status, updateInfo = { title: "", link: "", id: 0 }, index = -1) => {
dialogFormVisible.value = true;
info.status = status;
updateIndex.value = updateInfo.id;
Object.assign(info, updateInfo);
};
const handlerMessage = (u, title, link) => {
const a = u ? "添加" : "修改";
const error = !(!!title && isHttp(link));
if (error) {
ElementPlus.ElMessage.error(`${a} 失败 请保证标题或者链接有效 `);
} else {
ElementPlus.ElMessage.success(`${a} 成功 `);
}
return !error;
};
const addOrUpdate = () => {
if (!handlerMessage(info.status == "add", info.title, info.link)) {
return;
}
if (info.status == "add") {
tableData.unshift({ title: info.title, link: info.link, "ac": 0, "tot": 0, "id": tableData.length + 10 });
} else {
let id = updateIndex.value;
for (let i = 0; i < tableData.length; i++) {
if (tableData[i] && tableData[i].id && tableData[i]["id"] == id) {
tableData[i]["title"] = info.title;
tableData[i]["link"] = info.link;
break;
}
}
}
dialogFormVisible.value = false;
};
const deleteProblems = (id) => {
for (let i = 0; i < tableData.length; i++) {
if (tableData[i] && tableData[i].id && tableData[i]["id"] == id) {
delete tableData[i];
break;
}
}
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_urls__"], vue.toRaw(tableData));
};
const handlerDefault = () => {
Message("确认使用默认题单,将会重置题单", () => {
for (let i = 0; i < tableData.length; i++) {
delete tableData[i];
}
let infos = computeAcInfo(defaultUrls);
for (let item of infos) {
tableData.unshift(item);
}
ElementPlus.ElMessage({
type: "success",
message: "重置成功"
});
});
};
window.addEventListener("beforeunload", () => {
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_urls__"], vue.toRaw(tableData).filter((u) => u != null && u != void 0));
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_update__"], true);
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_add_cur__"], false);
});
vue.onMounted(async () => {
if (support_plugins()) {
let times = 30;
let loadTimeId = setInterval(() => {
let a = queryProblem();
times--;
if (Array.isArray(a) && a.length > 0) {
handlerProblem(vue.toRaw(Object.assign({}, fromData)));
addProcess();
window.clearInterval(loadTimeId);
}
if (times == 0) {
window.clearInterval(loadTimeId);
}
}, 200);
}
window.addEventListener("storage", (e) => {
watchLinkStatusUpdate(e);
});
});
_GM_registerMenuCommand(`题单配置信息🛠`, () => {
dialogTableVisible.value = !dialogTableVisible.value;
}, { title: "AC标记安装位置,默认左侧,刷新生效" });
const selectHandlerChange = (row) => {
let infos = [];
for (let i = 0; i < urlsData.value.length; i++) {
if (urlsData.value[i]["link"] == TARGET_URL) continue;
infos.push(vue.toRaw(Object.assign({}, urlsData.value[i])));
}
for (let i = 0; i < tableData.length; i++) {
if (row.id == tableData[i].id) {
tableData[i].select = row.select;
break;
}
}
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_urls__"], infos);
};
const asyncButtonLoad = vue.ref(false);
const asyncButtonLoadBreak = vue.ref(false);
const showProcess = vue.ref(false);
const allProblemNum = vue.ref(0);
const asyncProblemNum = vue.ref(0);
const asyncVisableDialog = vue.ref(false);
const showProblemsProcessInfo = vue.reactive({
title: "",
link: "",
cnt: "",
ac: "",
id: "",
select: true
});
const showProblemsInfo = (info2 = {}) => {
asyncVisableDialog.value = !asyncVisableDialog.value;
Object.assign(showProblemsProcessInfo, info2);
};
const loadProcess = vue.computed(() => computeProcess(asyncProblemNum.value, allProblemNum.value));
const asyncProblemStatus = async (row = {}) => {
if (!(row == null ? void 0 : row.link)) return;
let callback = async () => {
var _a, _b, _c, _d, _e;
let rowData = void 0;
let asyncAll = (row == null ? void 0 : row.link) == TARGET_URL;
let cache = Cache$2.get(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_ac_key__"], true, Object.name);
let map = /* @__PURE__ */ new Map();
try {
for (let info2 of tableData) {
if ((info2 == null ? void 0 : info2.link) && (info2 == null ? void 0 : info2.title) && (info2 == null ? void 0 : info2.id)) {
if (rowData == void 0 && (info2 == null ? void 0 : info2.id) == row.id) {
rowData = info2;
}
if (!map.has(info2.link)) {
map.set(info2.link, info2);
}
}
}
if (rowData) {
rowData.loading = true;
}
asyncButtonLoad.value = true;
asyncButtonLoadBreak.value = false;
allProblemNum.value = 0;
asyncProblemNum.value = 0;
showProcess.value = true;
await sleep(500);
let jsonInfo = await getProblemsJSON();
if (!Array.isArray(jsonInfo)) {
jsonInfo = Cache$2.get(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_all_problems__"], true, Array.name);
} else {
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_all_problems__"], jsonInfo);
}
let datas = [];
for (let i = 0; Array.isArray(jsonInfo) && i < jsonInfo.length; i++) {
let key = `${(_a = jsonInfo[i]) == null ? void 0 : _a.problemUrl}`;
let origin = map.get(key);
if (!origin) {
continue;
}
if (asyncAll) {
for (let p of jsonInfo[i].problems) {
datas.push(Object.assign({ "origin": jsonInfo[i].problemUrl }, p));
}
origin.tot = Math.max(jsonInfo[i].problems.length, (origin == null ? void 0 : origin.tot) ?? 0);
origin.ac = 0;
} else if (jsonInfo[i].problemUrl == row.link) {
for (let p of jsonInfo[i].problems) {
datas.push(Object.assign({ "origin": jsonInfo[i].problemUrl }, p));
}
origin.tot = Math.max(jsonInfo[i].problems.length, (origin == null ? void 0 : origin.tot) ?? 0);
origin.ac = 0;
break;
}
}
if (Array.isArray(datas) && datas.length > 0) {
allProblemNum.value = datas.length;
asyncProblemNum.value = 0;
let pre = 0;
for (let i = 0; i < datas.length; i++) {
let info2 = datas[i];
try {
if (asyncButtonLoadBreak.value) {
break;
}
await sleep(100);
let ID2 = info2.titleSlug;
let key = `${info2.origin}`;
let origin = map.get(key);
if (cache[ID2] != "ac") {
let response = await getProblemAcInfo(ID2);
const status = (_c = (_b = response == null ? void 0 : response.data) == null ? void 0 : _b.question) == null ? void 0 : _c.status;
cache[ID2] = status == null ? "null" : status;
}
if (origin) {
if (cache[ID2] == "ac") {
origin.ac = origin.ac + 1;
}
}
if (isDev()) ;
asyncProblemNum.value += 1;
if (loadProcess.value < pre && isDev()) {
console.warn("calc result is error");
}
pre = loadProcess.value;
} catch (e) {
if (isDev()) ;
}
if (i % 100 == 0) {
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_ac_key__"], Object.assign({}, cache));
}
}
}
} catch (e) {
console.log("error", e);
} finally {
if (rowData) {
rowData.loading = false;
}
asyncButtonLoad.value = false;
for (let i = 0; i < tableData.length; i++) {
if (getAcCountKey((_d = tableData[i]) == null ? void 0 : _d.link)) {
Cache$2.set(getAcCountKey(tableData[i].link), { "tot": tableData[i].tot, "ac": tableData[i].ac });
}
if ((_e = tableData[i]) == null ? void 0 : _e.loading) {
tableData[i].loading = false;
}
}
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_urls__"], vue.toRaw(tableData));
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_ac_key__"], Object.assign({}, cache));
await sleep(500);
ElementPlus.ElMessage({
type: allProblemNum.value == asyncProblemNum.value ? "success" : asyncButtonLoadBreak.value ? "error" : "warning",
message: allProblemNum.value == asyncProblemNum.value ? `同步完成🥰` : asyncButtonLoadBreak.value ? `同步中断 ${loadProcess.value}% ` : `同步率 ${loadProcess.value}% `,
duration: 3e3
});
await sleep(6e3);
allProblemNum.value = 0;
asyncProblemNum.value = 0;
showProcess.value = false;
asyncButtonLoadBreak.value = false;
}
};
if (row.link == TARGET_URL) {
Message("该操作将同步所有题单,耗时可能较长 确认操作?", callback);
} else {
callback();
}
};
const q1 = vue.ref(false);
vue.ref(false);
return (_ctx, _cache) => {
const _component_el_dialog = vue.resolveComponent("el-dialog");
const _component_el_input = vue.resolveComponent("el-input");
const _component_el_form_item = vue.resolveComponent("el-form-item");
const _component_el_form = vue.resolveComponent("el-form");
const _component_el_button = vue.resolveComponent("el-button");
const _component_el_progress = vue.resolveComponent("el-progress");
const _component_el_col = vue.resolveComponent("el-col");
const _component_el_option = vue.resolveComponent("el-option");
const _component_el_select = vue.resolveComponent("el-select");
const _component_el_tooltip = vue.resolveComponent("el-tooltip");
const _component_el_row = vue.resolveComponent("el-row");
const _component_el_table_column = vue.resolveComponent("el-table-column");
const _component_el_link = vue.resolveComponent("el-link");
const _component_el_switch = vue.resolveComponent("el-switch");
const _component_el_table = vue.resolveComponent("el-table");
return vue.openBlock(), vue.createElementBlock("div", null, [
vue.createVNode(_component_el_dialog, {
modelValue: q1.value,
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => q1.value = $event)
}, {
default: vue.withCtx(() => [
vue.createVNode(Q1)
]),
_: 1
}, 8, ["modelValue"]),
vue.createVNode(_component_el_dialog, {
modelValue: dialogFormVisible.value,
"onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => dialogFormVisible.value = $event),
title: `${info.status == "add" ? "添加" : "编辑"}`,
width: "400"
}, {
footer: vue.withCtx(() => [
vue.createElementVNode("div", _hoisted_1, [
vue.createVNode(_component_el_button, {
onClick: _cache[3] || (_cache[3] = ($event) => dialogFormVisible.value = false)
}, {
default: vue.withCtx(() => [
vue.createTextVNode("取消")
]),
_: 1
}),
vue.createVNode(_component_el_button, { onClick: addOrUpdate }, {
default: vue.withCtx(() => [
vue.createTextVNode(" 确认 ")
]),
_: 1
})
])
]),
default: vue.withCtx(() => [
vue.createVNode(_component_el_form, null, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_form_item, {
label: "标题",
"label-width": formLabelWidth
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_input, {
modelValue: info.title,
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => info.title = $event),
autocomplete: "off"
}, null, 8, ["modelValue"])
]),
_: 1
}),
vue.createVNode(_component_el_form_item, {
label: "链接",
"label-width": formLabelWidth
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_input, {
modelValue: info.link,
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => info.link = $event),
autocomplete: "off"
}, null, 8, ["modelValue"])
]),
_: 1
})
]),
_: 1
})
]),
_: 1
}, 8, ["modelValue", "title"]),
vue.createVNode(_component_el_dialog, {
modelValue: dialogTableVisible.value,
"onUpdate:modelValue": _cache[16] || (_cache[16] = ($event) => dialogTableVisible.value = $event),
title: asyncButtonLoadBreak.value ? `同步已中断 ${asyncProblemNum.value}/${allProblemNum.value}` : showProcess.value ? loadProcess.value < 100 ? `同步中...${asyncProblemNum.value}/${allProblemNum.value}` : "统计完成" : "题单信息",
width: "60%"
}, {
default: vue.withCtx(() => [
showProcess.value ? (vue.openBlock(), vue.createBlock(_component_el_progress, {
key: 0,
color: processColors,
percentage: loadProcess.value,
"stroke-width": 15,
striped: "",
"striped-flow": "",
style: { "margin-bottom": "20px" },
status: `${loadProcess.value == 100 ? "success" : ""}`
}, null, 8, ["percentage", "status"])) : vue.createCommentVNode("", true),
vue.createVNode(_component_el_row, { gutter: 10 }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_col, { span: 4 }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_input, {
modelValue: keywords.value,
"onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => keywords.value = $event),
placeholder: "请输入关键词过滤",
clearable: ""
}, null, 8, ["modelValue"])
]),
_: 1
}),
vue.createVNode(_component_el_col, { span: 20 }, {
default: vue.withCtx(() => [
showAddLocalButton.value ? (vue.openBlock(), vue.createBlock(_component_el_button, {
key: 0,
plain: "",
onClick: addlocal,
disabled: isDisabbled.value,
size: tableButtonSize.value
}, {
default: vue.withCtx(() => [
vue.createTextVNode(" 添加本页 ")
]),
_: 1
}, 8, ["disabled", "size"])) : vue.createCommentVNode("", true),
showAddLocalButton.value ? (vue.openBlock(), vue.createBlock(_component_el_button, {
key: 1,
plain: "",
onClick: _cache[6] || (_cache[6] = ($event) => handlerProblems("add")),
size: tableButtonSize.value
}, {
default: vue.withCtx(() => [
vue.createTextVNode(" 自定义 ")
]),
_: 1
}, 8, ["size"])) : vue.createCommentVNode("", true),
vue.createVNode(_component_el_select, {
modelValue: fromData.sortType,
"onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => fromData.sortType = $event),
style: { "margin": "0 5px", "width": "100px" },
disabled: asyncButtonLoad.value
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_option, {
label: "默认排序",
value: 0
}, {
default: vue.withCtx(() => [
vue.createTextVNode("默认排序")
]),
_: 1
}),
vue.createVNode(_component_el_option, {
label: "题目数量",
value: 1
}, {
default: vue.withCtx(() => [
vue.createTextVNode("题目数量")
]),
_: 1
}),
vue.createVNode(_component_el_option, {
label: "AC数量",
value: 2
}, {
default: vue.withCtx(() => [
vue.createTextVNode("AC数量")
]),
_: 1
}),
vue.createVNode(_component_el_option, {
label: "完成度",
value: 3
}, {
default: vue.withCtx(() => [
vue.createTextVNode("完成度")
]),
_: 1
})
]),
_: 1
}, 8, ["modelValue", "disabled"]),
vue.createVNode(_component_el_tooltip, { content: "同步所有题单" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_button, {
type: asyncButtonLoad.value ? "success" : "danger",
onClick: _cache[8] || (_cache[8] = ($event) => asyncProblemStatus({ "link": "https://leetcode.cn/u/endlesscheng/" })),
size: tableButtonSize.value,
loading: asyncButtonLoad.value
}, {
default: vue.withCtx(() => [
vue.createTextVNode(vue.toDisplayString(asyncButtonLoad.value ? "同步中" : "同步题单"), 1)
]),
_: 1
}, 8, ["type", "size", "loading"])
]),
_: 1
}),
asyncButtonLoad.value ? (vue.openBlock(), vue.createBlock(_component_el_tooltip, {
key: 2,
content: "点击中断同步"
}, {
default: vue.withCtx(() => [
asyncButtonLoad.value ? (vue.openBlock(), vue.createBlock(_component_el_button, {
key: 0,
type: "warning",
text: "",
onClick: _cache[9] || (_cache[9] = ($event) => asyncButtonLoadBreak.value = !asyncButtonLoadBreak.value),
size: tableButtonSize.value
}, {
default: vue.withCtx(() => [
vue.createTextVNode(" 中断同步 ")
]),
_: 1
}, 8, ["size"])) : vue.createCommentVNode("", true)
]),
_: 1
})) : vue.createCommentVNode("", true),
vue.createVNode(_component_el_tooltip, { content: "随机一道灵茶题单中题目,快捷键 Ctrl + Alt + J 可以触发" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_button, {
type: "primary",
text: "",
onClick: vue.unref(randomProblem),
size: tableButtonSize.value
}, {
default: vue.withCtx(() => [
vue.createTextVNode(" 随机题目 ")
]),
_: 1
}, 8, ["onClick", "size"])
]),
_: 1
})
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_table, {
data: vue.unref(urlsData),
height: "300",
style: { "width": "100%", "margin-top": "10px" }
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_table_column, { type: "index" }),
vue.createVNode(_component_el_table_column, {
label: "标题",
width: "auto",
align: "center"
}, {
default: vue.withCtx((scope) => [
vue.createVNode(_component_el_link, {
href: scope.row.link,
target: "_blank",
type: "default"
}, {
default: vue.withCtx(() => [
vue.createTextVNode(vue.toDisplayString(scope.row.title), 1)
]),
_: 2
}, 1032, ["href"])
]),
_: 1
}),
vue.createVNode(_component_el_table_column, {
label: "随机",
width: "70",
align: "center"
}, {
default: vue.withCtx((scope) => [
vue.createVNode(_component_el_switch, {
modelValue: scope.row.select,
"onUpdate:modelValue": ($event) => scope.row.select = $event,
onChange: ($event) => selectHandlerChange(scope.row),
disabled: rowIsDisabled.value(scope.row),
size: "small"
}, null, 8, ["modelValue", "onUpdate:modelValue", "onChange", "disabled"])
]),
_: 1
}),
vue.createVNode(_component_el_table_column, {
label: "AC",
width: "70",
align: "center"
}, {
default: vue.withCtx((scope) => [
vue.createVNode(_component_el_link, {
type: "success",
underline: false,
onClick: ($event) => showProblemsInfo(scope.row)
}, {
default: vue.withCtx(() => [
vue.createTextVNode(vue.toDisplayString(isNaN(scope.row.ac) ? 0 : scope.row.ac), 1)
]),
_: 2
}, 1032, ["onClick"])
]),
_: 1
}),
vue.createVNode(_component_el_table_column, {
label: "Total",
width: "70",
align: "center"
}, {
default: vue.withCtx((scope) => [
vue.createVNode(_component_el_link, {
type: "primary",
underline: false,
onClick: ($event) => showProblemsInfo(scope.row)
}, {
default: vue.withCtx(() => [
vue.createTextVNode(vue.toDisplayString(isNaN(scope.row.tot) ? 0 : scope.row.tot), 1)
]),
_: 2
}, 1032, ["onClick"])
]),
_: 1
}),
vue.createVNode(_component_el_table_column, {
label: "进度",
width: "70",
align: "center"
}, {
default: vue.withCtx((scope) => [
vue.createVNode(_component_el_link, {
onClick: ($event) => showProblemsInfo(scope.row),
type: "warning",
underline: false
}, {
default: vue.withCtx(() => {
var _a, _b, _c;
return [
vue.createTextVNode(vue.toDisplayString(((_a = scope == null ? void 0 : scope.row) == null ? void 0 : _a.tot) == 0 ? 0 : `${computeProcess((_b = scope == null ? void 0 : scope.row) == null ? void 0 : _b.ac, (_c = scope == null ? void 0 : scope.row) == null ? void 0 : _c.tot)}%`), 1)
];
}),
_: 2
}, 1032, ["onClick"])
]),
_: 1
}),
vue.createVNode(_component_el_table_column, {
label: "操作",
width: "200px",
align: "center"
}, {
default: vue.withCtx((scope) => [
vue.createVNode(_component_el_button, {
loading: scope.row.loading,
onClick: ($event) => asyncProblemStatus(scope.row),
size: "small",
type: "success",
disabled: rowIsDisabled.value(scope.row),
link: ""
}, {
default: vue.withCtx(() => [
vue.createTextVNode(vue.toDisplayString(scope.row.loading ? "" : "同步"), 1)
]),
_: 2
}, 1032, ["loading", "onClick", "disabled"]),
vue.createVNode(_component_el_button, {
onClick: ($event) => handlerProblems("update", scope.row, scope.$index),
size: "small",
type: "primary",
disabled: rowIsDisabled.value(scope.row),
link: ""
}, {
default: vue.withCtx(() => [
vue.createTextVNode("编辑")
]),
_: 2
}, 1032, ["onClick", "disabled"]),
vue.createVNode(_component_el_button, {
onClick: ($event) => deleteProblems(scope.row.id),
size: "small",
type: "danger",
link: "",
disabled: rowIsDisabled.value(scope.row)
}, {
default: vue.withCtx(() => [
vue.createTextVNode("删除")
]),
_: 2
}, 1032, ["onClick", "disabled"])
]),
_: 1
})
]),
_: 1
}, 8, ["data"]),
vue.createVNode(_component_el_row, {
gutter: 10,
style: { "margin": "10px 0" }
}, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_col, { span: 10 }, {
default: vue.withCtx(() => [
vue.createTextVNode(" 会员 "),
vue.createVNode(_component_el_tooltip, { content: "过滤会员题目,会员题不会出现在随机题目中和讨论区显示,默认显示" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: fromData.visiableMember,
"onUpdate:modelValue": _cache[10] || (_cache[10] = ($event) => fromData.visiableMember = $event)
}, null, 8, ["modelValue"])
]),
_: 1
}),
showAddLocalButton.value ? (vue.openBlock(), vue.createElementBlock(vue.Fragment, { key: 0 }, [
vue.createTextVNode(" 隐藏AC "),
vue.createVNode(_component_el_tooltip, { content: "是否在讨论区显示AC题目,默认显示 " }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: fromData.hiddenAc,
"onUpdate:modelValue": _cache[11] || (_cache[11] = ($event) => fromData.hiddenAc = $event)
}, null, 8, ["modelValue"])
]),
_: 1
})
], 64)) : vue.createCommentVNode("", true),
vue.createTextVNode(" 随机ac "),
vue.createVNode(_component_el_tooltip, { content: "随机题目配置: 过滤AC的题目,AC题目出现在随机题目中,默认不过滤" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_switch, {
modelValue: fromData.showAcConfig,
"onUpdate:modelValue": _cache[12] || (_cache[12] = ($event) => fromData.showAcConfig = $event)
}, null, 8, ["modelValue"])
]),
_: 1
})
]),
_: 1
}),
vue.createVNode(_component_el_col, { span: 8 }, {
default: vue.withCtx(() => [
vue.createTextVNode(" "),
vue.createVNode(_component_el_tooltip, { content: "随机题目和讨论区题目将会在这个区间(没有分数题目无法操作)" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_link, {
underline: false,
type: "primary"
}, {
default: vue.withCtx(() => [
vue.createTextVNode("分数区间")
]),
_: 1
})
]),
_: 1
}),
vue.createTextVNode(" "),
vue.createVNode(_component_el_input, {
modelValue: fromData.min,
"onUpdate:modelValue": _cache[13] || (_cache[13] = ($event) => fromData.min = $event),
"aria-placeholder": "",
placeholder: " min ",
style: { "width": "60px" }
}, null, 8, ["modelValue"]),
vue.createTextVNode("- "),
vue.createVNode(_component_el_input, {
modelValue: fromData.max,
"onUpdate:modelValue": _cache[14] || (_cache[14] = ($event) => fromData.max = $event),
"aria-placeholder": "",
placeholder: " max",
style: { "width": "60px" }
}, null, 8, ["modelValue"])
]),
_: 1
}),
vue.createVNode(_component_el_col, { span: 6 }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_tooltip, { content: "重置题单" }, {
default: vue.withCtx(() => [
vue.createVNode(_component_el_button, {
plain: "",
onClick: handlerDefault,
size: tableButtonSize.value,
disabled: showProcess.value
}, {
default: vue.withCtx(() => [
vue.createTextVNode(" 默认 ")
]),
_: 1
}, 8, ["size", "disabled"])
]),
_: 1
}),
vue.createVNode(_component_el_button, {
plain: "",
onClick: _cache[15] || (_cache[15] = ($event) => q1.value = !q1.value),
size: tableButtonSize.value
}, {
default: vue.withCtx(() => [
vue.createTextVNode(" 使用说明 ")
]),
_: 1
}, 8, ["size"])
]),
_: 1
})
]),
_: 1
})
]),
_: 1
}, 8, ["modelValue", "title"]),
vue.createVNode(_component_el_dialog, {
modelValue: asyncVisableDialog.value,
"onUpdate:modelValue": _cache[17] || (_cache[17] = ($event) => asyncVisableDialog.value = $event),
width: "35%"
}, {
default: vue.withCtx(() => [
vue.createElementVNode("p", null, [
vue.createVNode(_component_el_link, {
href: showProblemsProcessInfo.link,
type: "info",
underline: false
}, {
default: vue.withCtx(() => [
vue.createTextVNode(vue.toDisplayString(showProblemsProcessInfo.title), 1)
]),
_: 1
}, 8, ["href"])
]),
vue.createElementVNode("div", _hoisted_2, [
vue.createVNode(_component_el_progress, {
type: "circle",
percentage: computeProcess(showProblemsProcessInfo.ac, showProblemsProcessInfo.tot),
color: processColors
}, {
default: vue.withCtx(({ percentage }) => [
vue.createElementVNode("p", null, vue.toDisplayString(percentage) + "%", 1)
]),
_: 1
}, 8, ["percentage"])
]),
vue.createElementVNode("p", _hoisted_3, vue.toDisplayString(showProblemsProcessInfo.ac) + " / " + vue.toDisplayString(showProblemsProcessInfo.tot), 1)
]),
_: 1
}, 8, ["modelValue"])
]);
};
}
};
const App = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-333abb74"]]);
const cssLoader = (e) => {
const t = GM_getResourceText(e);
return GM_addStyle(t), t;
};
cssLoader("elementPlusCss");
const stopRankingKey = "__is_stop_rating_ranking__";
let conetstTimeId = null;
function run$1() {
const container = document.querySelector(".contest-question-info .list-group");
if (!container) return;
const ls = Array.from(container.querySelectorAll(".list-group-item .pull-right"));
for (let i = 0; i < 4; i++) {
if (i >= ls.length) {
break;
}
if (ls[i] instanceof HTMLElement) {
ls[i].textContent = "0";
}
}
window.clearInterval(conetstTimeId);
}
function startStopRanking() {
if (!isContest(window.location.href)) {
return;
}
const isNext = !!document.querySelector("#__next");
if (isNext) {
return;
}
const use = Cache$2.get(stopRankingKey);
if (use) {
conetstTimeId = setInterval(() => {
run$1();
}, 10);
}
_GM_registerMenuCommand(`${use ? "使用" : "关闭"} 排行榜`, () => {
Cache$2.set(stopRankingKey, !use);
window.location.reload();
}, { title: "对于不想看到排行榜的可以使用此功能 默认开启" });
}
const local_url$1 = window.location.href;
let loadID$1 = 0;
let submitCnt = 0;
let submitbutton = null;
function watchDom(dom) {
if (!(dom instanceof HTMLElement)) {
return;
}
let m = new MutationObserver(() => {
if (submitCnt % 2 == 1) {
submitProblems(local_url$1);
}
submitCnt++;
});
m.observe(dom, {
childList: true,
attributes: true
});
}
function handler() {
loadID$1++;
let findSubmitButton = function(sel) {
if (!sel) return null;
return Array.from(document.querySelectorAll(sel && { length: 0 })).find((e) => {
return e && e.innerText == "提交解答" || e.innerText == "提交";
});
};
const isNext = !!document.querySelector("#__next");
submitbutton = findSubmitButton(isProblem(local_url$1) || isNext ? "" : ".question-detail-bottom .pull-right button");
if (!submitbutton) {
submitbutton = document.querySelector('[data-e2e-locator="console-submit-button"]');
}
if (submitbutton) {
watchDom(submitbutton);
submitbutton.addEventListener("click", () => {
submitProblems(local_url$1, 10 * 1e3);
});
} else if (loadID$1 < 10) {
setTimeout(() => {
handlerNotFound();
}, 3e3);
}
}
function watchSubmit() {
if (!isProblem()) {
return;
}
try {
if ((window == null ? void 0 : window.fetch) && (window == null ? void 0 : window.unsafeWindow)) {
let originalFetch = window == null ? void 0 : window.fetch;
window.unsafeWindow.fetch = function() {
return originalFetch.apply(this, arguments).then(function(response) {
let res = response.clone();
res.text().then(function(bodyText) {
let url = res.url;
if (!/https:\/\/leetcode\.cn\/submissions\/detail\/\d+\/check\/.*/.test(url)) {
return;
}
if (res.status == 200 && res.ok) {
let result = JSON.parse(bodyText);
const ID2 = getId(local_url$1);
const status = (result == null ? void 0 : result.status_msg) == "Accepted" ? "ac" : (result == null ? void 0 : result.status_msg) == "Wrong Answer" ? "notac" : "null";
watchSaveStatus(ID2, status);
}
const cache = Cache.get(__0X3F_PROBLEM_KEYS__["__0x3f_problmes_ac_key__"], true, Object.name);
if (cache[ID] == null || cache[Id] == void 0) {
submitProblems(local_url$1);
}
});
return response;
});
};
} else {
console.warn("浏览器当前环境不支持 unsafeWindow 将做兼容处理 ");
handler();
}
} catch (e) {
console.error(e);
}
}
const local_url = window.location.href;
const randomProblemKey = () => Cache$2.get(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_random_problems_key__"]) == void 0 ? true : Cache$2.get(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_random_problems_key__"]);
let Container = null;
Cache$2.get(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_button_is_none__"], true, Boolean.name);
if (isProblem() || isLeetCodeCircleUrl()) {
const start = () => {
Container = document.createElement("div");
const body = document.querySelector("body");
body.append(Container);
Container.style.display = "block";
return Container;
};
let dom = start();
const VueApp = vue.createApp(App);
VueApp.use(ElementPlus).mount(dom);
}
if (isProblem() || isLeetCodeCircleUrl()) {
_GM_registerMenuCommand(`随机一道题 ☕`, randomProblem, { title: "随机一道题目,你可以通过ctrl+atl+j显示一道题目" });
_GM_registerMenuCommand(`${randomProblemKey() ? "关闭" : "启用"} 随机题目快捷键 ☕`, () => {
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_random_problems_key__"], !randomProblemKey());
window.location.reload();
}, { title: "该功能是随机一道题的快捷键,你可以通过ctrl+atl+j显示一道题目" });
if (randomProblemKey()) {
document.addEventListener("keydown", async function(event) {
if (event.ctrlKey && event.altKey && event.key === "j") {
randomProblem();
}
});
}
}
let loadID = 0;
async function run() {
loadID++;
if (isProblem(local_url)) {
await sleep(3e3);
if (isProblem(local_url) && loadID == 1) {
submitProblems(local_url);
}
} else if (isLeetCodeCircleUrl(local_url)) {
_GM_registerMenuCommand(`安装到${install_pos() ? "右侧" : "左侧"} 🎁`, () => {
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_insert_pos__"], install_pos());
window.location.reload();
}, { title: "AC标记安装位置,默认左侧,刷新生效" });
_GM_registerMenuCommand(`清空题目状态缓存 🚀`, () => {
Message("确认清空题目状态缓存", () => {
deleteAllACCountKeys();
window.location.reload();
});
}, { title: "如果题目状态出现问题,可以试试,一般情况下不建议使用" });
_GM_registerMenuCommand(`同步题目状态 🚀`, () => {
Message("确认同步题目状态", async () => {
await addProcess(true, void 0, true);
});
}, { title: "如果不在同一个浏览器答题,会出现ac题目状态没有及时同步,可以使用此功能" });
_GM_registerMenuCommand(`${initObj().onlyUrls ? "仅在收藏题单页面生效" : "所有题单生效"}`, () => {
const u = initObj();
u.onlyUrls = !u.onlyUrls;
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_solution__"], u);
}, { title: "插件默认会在所有讨论发布页生效,如果只想在收藏链接生效,可以使用此功能" });
_GM_registerMenuCommand(`添加本页`, () => {
const urls = initUrls();
let ok = false;
let url = window.location.href;
for (let info of urls) {
if (!info || !(info == null ? void 0 : info.link)) {
continue;
}
if (info.link.indexOf(url) != -1) {
ok = true;
break;
}
}
if (ok) {
ElementPlus.ElMessage({
message: "收藏失败,链接已经存在!",
type: "error"
});
} else {
if (isLeetCodeCircleUrl(url) && url.indexOf("view") != -1) {
try {
url = url.split("view")[0];
} catch (e) {
url = window.location.href;
}
}
urls.unshift({
title: document.title,
link: url
});
Container.style.display = "block";
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_urls__"], urls);
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_update__"], true);
Cache$2.set(__0X3F_PROBLEM_KEYS__$1["__0x3f_problmes_add_cur__"], true);
ElementPlus.ElMessage({
message: "收藏成功!刷新生效",
type: "success"
});
}
});
}
}
watchSubmit();
run();
startStopRanking();
})(ElementPlus, Vue);