您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
深空之眼弥弥尔论坛签到脚本
// ==UserScript== // @name MyYs4funTools // @namespace http://tampermonkey.net/ // @version 1.10.0 // @description 深空之眼弥弥尔论坛签到脚本 // @author MakoStar [https://space.bilibili.com/7709386] // @match *://bbs.ys4fun.com/* // @match *://m.bbs.ys4fun.com/* // @icon https://www.google.com/s2/favicons?sz=64&domain=ys4fun.com // @require https://code.jquery.com/jquery-2.1.4.min.js // @resource css https://wiki.biligame.com/dhmmr/index.php?title=User:7709386/MyYs4funTools.css&action=raw&ctype=text/css // @run-at document-end // @license MIT // @grant unsafeWindow // @grant GM_addStyle // @grant GM_getResourceText // ==/UserScript== this.$ = this.jQuery = jQuery.noConflict(true); (function () { 'use strict'; // 工具元素结构模板 const ElementTemplate = class { constructor() { this.snapUpTimerList = []; const _userInfo = this.toolsLocalStorage({ handle: "getItem", key: "userInfo", type: "parse" }); const localData = this.toolsLocalStorage({ handle: "getItem", type: "parse", uid: _userInfo ? _userInfo.id : "" }); this.toolsDefaultStateConfig = { stateConfig: { isGlobalDayTask: false, isGlobalCheckLogin: true, isGlobalCheckLogout: true, isIgnoreCheckState: false, isRunSignInTask: false, isRunLikeTask: false, isCancelLike: false, isRunBrowseTask: false, isRunPostedTask: false, isDeletePost: false, isRunCommentTask: false, isRunShareTask: false, isDeleteComment: false, isOpenCycleCancelLike: false, isPostCustomComment: false, isPostCustomContent: false, isDeleteMyAllPost: false, isDeleteMyAllComment: false, isCancelMyAllLikeState: false, isResetToolsDefaultState: false, isClearUserLocalData: false, isOpenRandomPostCustomContentList: false, isOpenRandomCustomCommentListContent: false }, customContentConfig: { customPostContent: { id: "", content: "", contentJson: "", title: "", cacheList: [] }, customCommentContent: { id: "", content: "", contentJson: "", title: "", cacheList: [] } } }; if (localData !== null && typeof localData === "object" && Object.keys(localData).length !== 0 ) { this.toolsStateDataConfig = localData; } else { this.toolsStateDataConfig = this.toolsDefaultStateConfig; }; // 工具菜单选项列表 this.toolsMenuOptionList = [ { id: "ys4fun-tools-menu-button__setting", class: "ys4fun-tools-menu__item", style: "--i:0; --c:#a529ff;", title: "工具设置", link: "javascript:void(0)", target: "", icon: '<ion-icon name="settings-outline"></ion-icon>', isShowContent: true }, { id: "ys4fun-tools-menu-button__userInfo", class: "ys4fun-tools-menu__item", style: "--i:1; --c:#00b0fe;", title: "用户信息", link: "javascript:void(0)", target: "", icon: '<ion-icon name="person-circle-outline"></ion-icon>', isShowContent: true }, { id: "ys4fun-tools-menu-button__homePage", class: "ys4fun-tools-menu__item", style: "--i:2; --c:#ff2972;", title: "返回首页", link: "https://bbs.ys4fun.com/", target: "", icon: '<ion-icon name="home-outline"></ion-icon>', isShowContent: false }, { id: "ys4fun-tools-menu-button__rerunScript", class: "ys4fun-tools-menu__item", style: "--i:3; --c:#fe00f1;", title: "重新运行脚本", link: "javascript:void(0)", target: "", icon: '<ion-icon name="refresh-circle-outline"></ion-icon>', isShowContent: false }, { id: "ys4fun-tools-menu-button__snapUp", class: "ys4fun-tools-menu__item", style: "--i:4; --c:#04fc43;", title: "神秘商人", link: "javascript:void(0)", target: "", icon: '<ion-icon name="cart-outline"></ion-icon>', isShowContent: true }, { id: "ys4fun-tools-menu-button__versionInfo", class: "ys4fun-tools-menu__item", style: "--i:5; --c:#ff4c00;", title: "使用说明", link: "javascript:void(0)", target: "", icon: '<ion-icon name="alert-circle-outline"></ion-icon>', isShowContent: false }, { id: "ys4fun-tools-menu-button__bwiki", class: "ys4fun-tools-menu__item", style: "--i:6; --c:#01bdab;", title: "深空之眼Bwiki", link: "https://wiki.biligame.com/dhmmr/", target: "_blank", icon: '<ion-icon name="game-controller-outline"></ion-icon>', isShowContent: false }, { id: "ys4fun-tools-menu-button__feedback", class: "ys4fun-tools-menu__item", style: "--i:7; --c:#fea600;", title: "意见反馈", link: "javascript:void(0)", target: "", icon: '<ion-icon name="mail-outline"></ion-icon>', isShowContent: false } ]; // 工具菜单选项:"工具设置" 子菜单列表 this.settingSubMenuList = [ { id: 0, attr: { id: "basic-setting" }, text: "基础设置", subitemList: [ { id: 0, attr: { id: "basic-0", }, text: "全局" }, { id: 1, attr: { id: "basic-1", }, text: "特殊" } ] }, { id: 1, attr: { id: "daytask" }, text: "每日任务", subitemList: [ { id: 0, attr: { id: "task-signIn", }, text: "签到" }, { id: 1, attr: { id: "task-like", }, text: "点赞" }, { id: 2, attr: { id: "task-browse", }, text: "浏览" }, { id: 3, attr: { id: "task-share", }, text: "分享" }, { id: 4, attr: { id: "task-posted", }, text: "发帖" }, { id: 5, attr: { id: "task-comment", }, text: "评论" } ] } ]; // 工具菜单选项:"工具设置" 子菜单 "基础设置" 子选项内容列表 this.basicSettingContentList = [ { id: 0, name: "basic-0", text: "全局功能", subitemList: [ { id: 0, attr: { id: "isGlobalDayTask", class: "basic-stting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isGlobalDayTask"] }, text: "开启每日任务脚本功能" }, { id: 1, attr: { id: "isGlobalCheckLogin", class: "basic-stting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isGlobalCheckLogin"] }, text: "开启检查用户登录功能" }, { id: 2, attr: { id: "isGlobalCheckLogout", class: "basic-stting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isGlobalCheckLogout"] }, text: "开启检查用户注销功能" }, { id: 3, attr: { id: "isIgnoreCheckState", class: "basic-stting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isIgnoreCheckState"] }, text: "开启无限制执行任务脚本功能(默认关闭,非重新执行脚本不要开启)" } ] }, { id: 1, name: "basic-1", text: "特殊功能", subitemList: [ { id: 0, attr: { id: "isDeleteMyAllPost", class: "basic-stting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isDeleteMyAllPost"] }, text: "开启删除所有个人帖子功能" }, { id: 1, attr: { id: "isDeleteMyAllComment", class: "basic-stting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isDeleteMyAllComment"] }, text: "开启删除所有个人评论功能" }, { id: 2, attr: { id: "isCancelMyAllLikeState", class: "basic-stting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isCancelMyAllLikeState"] }, text: "开启撤销所有个人已点赞帖子功能" }, { id: 3, attr: { id: "isClearUserLocalData", class: "basic-stting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isClearUserLocalData"] }, text: "开启清除当前用户本地存储数据功能" }, { id: 4, attr: { id: "isResetToolsDefaultState", class: "basic-stting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isResetToolsDefaultState"] }, text: "开启重置工具至默认配置并刷新页面功能" } ] } ]; // 工具菜单选项:"工具设置" 子菜单 "每日任务" 子选项内容列表 this.daytaskSettingContentList = [ { id: 0, name: "task-signIn", text: "签到任务", subitemList: [ { id: 0, attr: { id: "isRunSignInTask", class: "daytask-setting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isRunSignInTask"] }, text: "开启签到任务" } ] }, { id: 1, name: "task-like", text: "点赞任务", subitemList: [ { id: 0, attr: { id: "isRunLikeTask", class: "daytask-setting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isRunLikeTask"] }, text: "开启点赞任务" }, { id: 1, attr: { id: "isCancelLike", class: "daytask-setting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isCancelLike"] }, text: "点赞后撤销点赞状态" }, { id: 2, attr: { id: "isOpenCycleCancelLike", class: "daytask-setting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isOpenCycleCancelLike"] }, text: "开启强制循环撤销点赞直到成功状态" } ] }, { id: 2, name: "task-browse", text: "浏览任务", subitemList: [ { id: 0, attr: { id: "isRunBrowseTask", class: "daytask-setting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isRunBrowseTask"] }, text: "开启浏览任务" } ] }, { id: 3, name: "task-share", text: "分享任务", subitemList: [ { id: 0, attr: { id: "isRunShareTask", class: "daytask-setting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isRunShareTask"] }, text: "开启分享任务" } ] }, { id: 4, name: "task-posted", text: "发帖任务", subitemList: [ { id: 0, attr: { id: "isRunPostedTask", class: "daytask-setting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isRunPostedTask"] }, text: "开启发帖任务" }, { id: 1, attr: { id: "isDeletePost", class: "daytask-setting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isDeletePost"] }, text: "发帖后删除帖子" }, { id: 2, attr: { id: "isPostCustomContent", class: "daytask-setting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isPostCustomContent"] }, text: "开启自定义帖子内容" }, { id: 3, attr: { id: "isOpenRandomPostCustomContentList", class: "daytask-setting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isOpenRandomPostCustomContentList"] }, text: "开启随机自定义帖子草稿列表内容" } ] }, { id: 5, name: "task-comment", text: "评论任务", subitemList: [ { id: 0, attr: { id: "isRunCommentTask", class: "daytask-setting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isRunCommentTask"] }, text: "开启评论任务" }, { id: 1, attr: { id: "isDeleteComment", class: "daytask-setting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isDeleteComment"] }, text: "发表评论后删除" }, { id: 2, attr: { id: "isPostCustomComment", class: "daytask-setting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isPostCustomComment"] }, text: "开启自定义评论内容" }, { id: 3, attr: { id: "isOpenRandomCustomCommentListContent", class: "daytask-setting-input", type: "checkbox", labelClass: "basic-setting-label", checked: this.toolsStateDataConfig.stateConfig["isOpenRandomCustomCommentListContent"] }, text: "开启随机自定义评论草稿列表内容" } ] } ]; // 创建 "工具设置" 子菜单子选项内容结构 const dayTaskSettingContentList = this.createDaytaskContainerBody(); const basicSettingContentList = this.createBasicSettingContainerBody(); // 工具菜单选项:"工具设置" 子菜单所有子菜单选项内容结构体列表 this.settingSubitemContainerList = [ { id: 0, attr: { index: "0", bindId: "basic-setting" }, subitemList: [ { id: 0, content: basicSettingContentList["basic-0"].html, appendBody: "" }, { id: 1, content: basicSettingContentList["basic-1"].html, appendBody: this.createAppendBasicSpecialBody() } ] }, { id: 1, attr: { index: "1", bindId: "daytask" }, subitemList: [ { id: 0, content: dayTaskSettingContentList["task-signIn"].html, appendBody: "" }, { id: 1, content: dayTaskSettingContentList["task-like"].html, appendBody: "" }, { id: 2, content: dayTaskSettingContentList["task-browse"].html, appendBody: "" }, { id: 3, content: dayTaskSettingContentList["task-share"].html, appendBody: "" }, { id: 4, content: dayTaskSettingContentList["task-posted"].html, appendBody: this.createAppendPostedCustomBody() }, { id: 6, content: dayTaskSettingContentList["task-comment"].html, appendBody: this.createAppendCommentCustomBody() } ] } ]; // 工具菜单选项:"用户信息" 内容结构列表 this.userInfoConfigList = [ { id: 0, key: "论坛id", value: "" }, { id: 1, key: "论坛昵称", value: "" }, { id: 2, key: "论坛等级", value: "" }, { id: 3, key: "弥尔币数量", value: "" }, { id: 4, key: "用户创建日期", value: "" }, { id: 5, key: "游戏服务器", value: "" }, { id: 6, key: "游戏uid", value: "" }, { id: 7, key: "游戏昵称", value: "" }, { id: 8, key: "游戏等级", value: "" }, { id: 9, key: "游戏创建日期", value: "" }, { id: 10, key: "我的地址", value: "" } ]; // 工具菜单所有选项主体内容结构列表 this.containerList = [ { id: 0, attr: { id: "setting", index: "0", title: "工具设置", }, style: {}, containerbody: this.createSettingContainerBody() }, { id: 1, attr: { id: "userInfo", index: "1", title: "用户信息", }, style: {}, containerbody: this.createUserInfoContainerBody() }, { id: 4, attr: { id: "snapUp", index: "4", title: "神秘商人", }, style: { width: "90vw", height: "90vh" }, containerbody: this.createSnapUpContainerBody() }, { id: 5, attr: { id: "versionInfo", index: "5", title: "使用说明", }, style: {}, containerbody: "" }, { id: 7, attr: { id: "feedback", index: "7", title: "意见反馈", }, style: {}, containerbody: "" } ]; } // 创建工具菜单面板 createToolsMenuPanel() { const $toolsMenuPanel = $("<div>").attr({ class: "ys4fun-tools-menu-panel" }); const $menuOpenButton = $("<div>").attr({ class: "ys4fun-tools-menu__open-button", role: "button", title: "论坛工具菜单" }); $menuOpenButton.on("click", (event) => { event.stopPropagation(); $(event.target).parents(".ys4fun-tools-menu-panel").toggleClass("active"); }); const $openButtonIcon = $("<div>").attr({ class: "ys4fun-tools-menu__button-icon" }); const $menuItemList = this.createToolsMenuList(); $menuOpenButton.append($openButtonIcon); $toolsMenuPanel.append($menuOpenButton, $menuItemList); return $toolsMenuPanel; } // 创建工具菜单列表 createToolsMenuList() { const $menuListUl = $("<ul>").attr({ class: "ys4fun-tools-menu__item-list" }); this.toolsMenuOptionList.forEach((optionMap, optionIdx) => { const $subitemLi = $("<li>").attr({ id: optionMap.id, class: optionMap.class, style: optionMap.style, title: optionMap.title, "data-index": optionIdx, "data-show-content": optionMap.isShowContent ? true : "" }); const $subitemA = $("<a>").attr({ href: optionMap.link, target: optionMap.target }); $subitemA.append(optionMap.icon); $subitemLi.append($subitemA); $menuListUl.append($subitemLi); }); $menuListUl.on("click", "li", (event) => { event = event || window.event; event.stopPropagation(); const $event = $(event.target); const $panel = $event.parents("#ys4fun-tools-panel"); const $menu = $event.parents(".ys4fun-tools-menu-panel"); const $container = $panel.find(".ys4fun-tools-container-panel"); const $option = $event.parents(".ys4fun-tools-menu__item"); if ($option.attr("data-show-content")) { $menu.hide().removeClass("active"); const index = $option.attr("data-index"); $container.find(`.ys4fun-tools-container[data-index="${index}"]`).show("fast").siblings().hide(); $panel.addClass("show-container-panel"); $container.show("fast").css("display", "flex"); } else { let timer = null; if ($option.attr("id") === "ys4fun-tools-menu-button__rerunScript") { if (!this.toolsStateDataConfig.stateConfig.isIgnoreCheckState) { alert(this.message[113]); return; }; const $a = $option.find("a"); const $ionEle = $a.find("ion-icon"); const title = $option.attr("title"); $a.css("pointer-events", "none"); $ionEle.css("opacity", "0.2"); if (!$a.hasClass("active")) { const rerunTitle = "请等待一分钟后再执行!"; const $timingDiv = $("<div>").attr({ class: "rerun-timing-text", title: rerunTitle }); $option.attr("title", rerunTitle); $a.append($timingDiv); $a.attr("class", "active"); }; clearInterval(timer); let timeCount = 60; timer = setInterval(() => { timeCount--; if (timeCount === 0) { $a.css("pointer-events", "unset"); $a.removeClass("active"); $a.find(".rerun-timing-text").remove(); $ionEle.css("opacity", "1"); $option.attr("title", title); clearInterval(timer); timer = null; }; $a.find(".rerun-timing-text").text(timeCount); }, 1000) if (!this.toolsStateDataConfig.stateConfig.isGlobalDayTask) { alert("您并未开启每日任务脚本功能!"); return; }; this.init(true).then(() => { this.checkDayTaskState(); }); } console.log("该设置选项没有设置显示内容的容器"); }; }); return $menuListUl; } // 创建工具菜单选项的内容容器结构面板 createToolsContainerPanel() { const $containerPanelUl = $("<ul>").attr({ class: "ys4fun-tools-container-panel" }); this.containerList.forEach(containerMap => { const $templateLi = this.createContainerTemplate({ id: containerMap.attr.id, index: containerMap.attr.index, title: containerMap.attr.title, body: containerMap.containerbody, style: containerMap.style }); $containerPanelUl.append($templateLi); }); return $containerPanelUl; } // 创建工具菜单子元素内容模板 createContainerTemplate({ id, index, title, body, style }) { const $containerLi = $("<li>").attr({ id: id, class: "ys4fun-tools-container", "data-index": index }); if (style && typeof style === "object" && Object.keys(style).length !== 0) { $containerLi.css({ ...style }); }; const $header = $("<div>").attr({ class: "ys4fun-tools-container__header" }); const $headerTitle = $("<h2>").attr({ class: "ys4fun-tools-container-header__title", title: title }).text(title); const $closeButton = $("<div>").attr({ class: "ys4fun-tools-container-header__closeButton", role: "button", title: "关闭" }); const $closeButtonIcon = $('<ion-icon name="close-circle-outline"></ion-icon>'); $closeButton.on("click", (event) => { event = event || window.event; const $panel = $(event.target).parents("#ys4fun-tools-panel"); const $container = $(event.target).parents(".ys4fun-tools-container-panel"); const $settingOptionMenuUl = $container.find(".ys4fun-tools-setting-container-menu"); const $settingOptionLi = $settingOptionMenuUl.children("li"); const $settingOptionLiItem = $settingOptionLi.find(".ys4fun-tools-setting-container-item-subitem__item"); const $settingOptionLiItemSubitemList = $settingOptionLi.find(".ys4fun-tools-setting-container-item-subitem-list"); const $settingOptionItemContainerUl = $settingOptionMenuUl.siblings(".ys4fun-tools-setting-container-item-content-list"); $container.hide("fast"); $panel.removeClass("show-container-panel"); $panel.find(".ys4fun-tools-menu-panel").show("fast", "linear"); $settingOptionLi.removeClass("active"); $settingOptionLiItem.removeClass("active"); $settingOptionLiItemSubitemList.hide(); $settingOptionItemContainerUl.find(".ys4fun-tools-setting-container-item-content-item").hide(); }); const $containerBody = $("<div>").attr({ class: "ys4fun-tools-container__body" }); body && $containerBody.append(body); $closeButton.append($closeButtonIcon); $header.append($headerTitle, $closeButton); $containerLi.append($header, $containerBody); return $containerLi; } // 创建工具设置选项的内容主体部分 createSettingContainerBody() { const $settingContainer = $("<div>").attr({ class: "ys4fun-tools-setting-container" }); const $optionMenu = this.createSettingOptionsMenu(); const $optionContainer = this.createBodySubitemContent(); $settingContainer.append($optionMenu, $optionContainer); return $settingContainer; } // 创建工具设置选项的内容主体的子项内容部分 createBodySubitemContent() { const $optionContainer = $("<ul>").attr({ class: "ys4fun-tools-setting-container-item-content-list" }); this.settingSubitemContainerList.forEach(containerMap => { const $contentLi = $("<li>").attr({ class: "ys4fun-tools-setting-container-item-content-item", "data-index": containerMap.attr.index, "data-bind-id": containerMap.attr.bindId }); const $contentLiSubitemListUl = $("<ul>").attr({ class: "ys4fun-tools-setting-container-item-content-item-subitem-list" }); containerMap.subitemList.forEach((subitemMap, subitemIdx) => { const $subitemLi = $("<li>").attr({ class: "ys4fun-tools-setting-container-item-content-item-subitem__item", "data-index": subitemIdx, }).html(subitemMap.content); if (subitemMap.appendBody) { $subitemLi.append(subitemMap.appendBody); }; $contentLiSubitemListUl.append($subitemLi); }); $contentLi.append($contentLiSubitemListUl); $optionContainer.append($contentLi); }); return $optionContainer; } // 创建基础设置内容主体部分 createBasicSettingContainerBody() { const templateObject = {}; this.basicSettingContentList.forEach(contentMap => { const $div = $("<div>").attr({ class: "basic-setting-container" }); contentMap.subitemList.forEach(subitemMap => { const $lable = this.createChangeStateLabel({ inputId: subitemMap.attr.id, spanText: subitemMap.text, inputClass: subitemMap.attr.class, inputType: subitemMap.attr.type, inputState: subitemMap.attr.checked, labelClass: subitemMap.attr.labelClass }); $lable.on("click", (event) => { event = event || window.event; event.stopPropagation(); const $event = $(event.delegateTarget); const $input = $event.find("input"); const id = $event.attr("for") || $input.attr("id"); const state = $input.is(":checked"); const $button = id ? $(`button[id=${id}]`) : []; return $button.length > 0 ? state ? $button.attr({ disabled: !state }) : $button.attr({ disabled: !state }) : null; }); $div.append($lable); }); templateObject[contentMap.name] = { id: contentMap.id, name: contentMap.text, html: $div }; }); return templateObject; } // 创建每日任务设置内容主体部分 createDaytaskContainerBody() { const templateObject = {}; this.daytaskSettingContentList.forEach(contentMap => { const $table = $("<table>").attr({ class: "daytask-setting-table" }); const $caption = $("<caption>").attr({ class: "daytask-setting-table-caption" }).text(contentMap.text); const $tbody = $("<tbody>"); contentMap.subitemList.forEach(subitemMap => { const $tr = $("<tr>"); const $td = $("<td>"); const $label = this.createChangeStateLabel({ inputId: subitemMap.attr.id, spanText: subitemMap.text, inputClass: subitemMap.attr.class, inputType: subitemMap.attr.type, inputState: subitemMap.attr.checked, labelClass: subitemMap.attr.labelClass }); $td.append($label); $tr.append($td); $tbody.append($tr); }); $table.append($caption, $tbody); templateObject[contentMap.name] = { id: contentMap.id, name: contentMap.text, html: $table }; }); return templateObject; } // 创建商城抢购内容主体部分 createSnapUpContainerBody() { const $snapUpContainer = $("<div>").attr({ class: "ys4fun-tools-snapUp-container" }).css("padding", "11px"); const $snapUpButtonListBox = $("<div>").attr({ class: "snapUp-container-button-list" }).css({ "display": "flex", "align-content": "center", "align-items": "center", "justify-content": "center" }); const $getUserInfoButton = this.createToolsButton({ id: "getUserInfo", cls: "tools-button", text: "获取用户信息", style: { color: "#646464" }, disabled: false }); $getUserInfoButton.on("click", (event) => { event = event || window.event; $(event.target).toggleClass("active"); const $tipsBox = $(".snap-up-tips-text"); if ($tipsBox && $tipsBox.length > 0) { $tipsBox.hide(); }; if ($(event.target).hasClass("active")) { const { bbsId, bbsNickName, bbsLevel, bbsCoin, gameServer, gameUid, gameNickName, gameLevel } = this.userInfoCacheMap; const noFoundStr = "您还未设置有收货地址或该收货地址未设置为默认地址"; const addressStr = this.userAddressInfoMap ? this.userAddressInfoMap.addressStr : noFoundStr; const fontColor = addressStr === noFoundStr ? "red" : "#5c5b5b"; const $userInfoTable = $(`<table id="snapUp-userInfo-table" class="tools-table" style="display:none;"> <caption>用户信息</caption> <thead> <th>论坛id</th> <th>论坛昵称</th> <th>论坛等级</th> <th>游戏区服</th> <th>游戏id</th> <th>游戏昵称</th> <th>游戏等级</th> <th>弥尔币数量</th> <th>收货地址(仅获取默认地址)</th> </thead> <tbody> <tr> <td name="bbsid">${bbsId}</td> <td name="bbsNickName">${bbsNickName}</td> <td name="bbsLevel">${bbsLevel}</td> <td name="gameServer">${gameServer}</td> <td name="gameUid">${gameUid}</td> <td name="gameNickName">${gameNickName}</td> <td name="gameLevel">${gameLevel}</td> <td name="bbsCoinNum">${bbsCoin}</td> <td name="userAddress"> <font name="userAddressFont" color="${fontColor}"> ${addressStr} </font> </td> </tr> </tbody> </table>`); $snapUpContainer.find(".snapUp-container-button-list").after($userInfoTable); const $button = this.createToolsButton({ id: "refreshUserAddress", cls: "tools-button", text: "", html: '<ion-icon name="sync-outline"></ion-icon>', style: { color: "rgb(100, 100, 100)", width: "25px", height: "25px", padding: "0" } }); $button.on("click", (event) => { event = event || window.event; const $evnet = $(event.delegateTarget); const $eventFont = $evnet.siblings("font"); const $ionIcon = $evnet.children("ion-icon"); $evnet.attr("disabled", "disabled"); $evnet.css("opacity", "0"); $ionIcon.css("opacity", "0"); setTimeout(() => { $evnet.removeAttr("disabled"); $evnet.css("opacity", "1"); $ionIcon.css("opacity", "1"); }, 1200); $eventFont.fadeOut(800); this.getUserAddressList().then(res => { if (!this.userAddressInfoMap || !this.userAddressInfoMap.addressStr) { $eventFont.fadeIn(800); $eventFont.text(noFoundStr).attr("color", "red"); } else { $eventFont.text(this.userAddressInfoMap.addressStr).attr("color", "#5c5b5b"); $eventFont.fadeIn(800); }; }); }); if (!addressStr || addressStr === "") { $('[name="userAddress"]').children().remove(); $('[name="userAddress"]').append($button); } else { $('[name="userAddress"]').append($button) }; if (this.clientType === "2") { $userInfoTable.css({ "overflow": "scroll", "width": "400%" }); $snapUpContainer.css({ "overflow": "scroll" }); }; $userInfoTable.show(100); } else { $snapUpContainer.find("#snapUp-userInfo-table").hide(100, () => { $snapUpContainer.find("#snapUp-userInfo-table").remove(); }); }; }); const $getCommodityListButton = this.createToolsButton({ id: "getCommodityList", cls: "tools-button", text: "获取商品列表", style: { color: "#646464" }, disabled: false }); $getCommodityListButton.on("click", (event) => { event = event || window.event; const $evnet = $(event.target); const $tipsBox = $(".snap-up-tips-text"); if ($tipsBox && $tipsBox.length > 0) { $tipsBox.hide(); }; $evnet.toggleClass("active"); if ($evnet.hasClass("active")) { const $commodityListTable = $(`<table id="commodity-list-table" class="tools-table" style="display:none;"> <caption>商品列表</caption> <thead> <tr> <th rowspan="2">商品id</th> <th rowspan="2">商品名称</th> <th rowspan="2">可购状态</th> <th rowspan="2">商品类型</th> <th rowspan="2">可购数量</th> <th rowspan="2">已购数量</th> <th rowspan="2">总计数量</th> <th rowspan="2">剩余数量</th> <th colspan="2">所需条件</th> <th rowspan="2">开始时间</th> <th rowspan="2">结束时间</th> <th rowspan="2">需要弥尔币</th> <th rowspan="2">条件满足状态</th> <th rowspan="2">是否抢购</th> </tr> <tr> <th>游戏等级</th> <th>论坛等级</th> </tr> </thead> <tbody class="ys4fun-tools-shop-list-tbody"> </tbody> </table>`); $snapUpContainer.append($commodityListTable); this.getCommodityList().then(commodityList => { this.commodityList = commodityList; this.snapUpQueryDataList = []; this.snapUpCommodityTotalPrice = 0; commodityList.forEach(commodityMap => { const conditions = JSON.parse(commodityMap.restrictionCondition); const commodityConditionGameLevel = conditions.skzyLevel; const commodityConditionForumLevel = conditions.mimierLevel; const userGameLevel = this.userInfoCacheMap.gameLevel; const userForumLevel = this.userInfoCacheMap.bbsLevel; const userCoinNumber = this.userInfoCacheMap.bbsCoin; const currentDate = this.convertDateByTimestamp(new Date().getTime()).match(/\d{4}-\d{2}-\d{2}/)[0] const buyStartDate = this.convertDateByTimestamp(commodityMap.validStartDate).match(/\d{4}-\d{2}-\d{2}/)[0] const isSatisfyBuy = commodityMap.commodityBuyFlag ? commodityMap.commodityBuyFlag : currentDate === buyStartDate const isSatisfy = isSatisfyBuy && userGameLevel >= commodityConditionGameLevel && userForumLevel >= commodityConditionForumLevel && userCoinNumber >= commodityMap.price && commodityMap.restrictionNumber >= commodityMap.cycleBuyNumber; const $tr = this.createCommodityTrLine({ id: commodityMap.id, name: commodityMap.name, state: commodityMap.commodityBuyFlag, type: commodityMap.commodityTypeVO.type.text, rnum: commodityMap.restrictionNumber, cnum: commodityMap.cycleBuyNumber, tnum: commodityMap.number, snum: commodityMap.surplusNumber, gl: commodityConditionGameLevel, fl: commodityConditionForumLevel, startTime: this.convertDateByTimestamp(commodityMap.validStartDate), endTime: this.convertDateByTimestamp(commodityMap.validEndDate), price: commodityMap.price, isSatisfy: isSatisfy, snapUpInput: { id: commodityMap.id, name: commodityMap.name }, extraParams: { commodityConditionGameLevel: commodityConditionGameLevel, commodityConditionForumLevel: commodityConditionForumLevel, userGameLevel: userGameLevel, userForumLevel: userForumLevel, validStartDate: commodityMap.validStartDate, validEndDate: commodityMap.validEndDate, userCoinNumber: userCoinNumber } }); $(".ys4fun-tools-shop-list-tbody").append($tr); }); }); if (this.clientType === "2") { $commodityListTable.css({ "overflow": "scroll", "width": "400%" }); $snapUpContainer.css({ "overflow": "scroll" }); }; $commodityListTable.show("low"); } else { $snapUpContainer.find("#commodity-list-table").hide("low", () => { $snapUpContainer.find("#commodity-list-table").remove(); }); }; }); const $executeSnapUpButton = this.createToolsButton({ id: "executeSnapUp", cls: "tools-button", text: "执行抢购脚本", style: { color: "#646464" }, disabled: false }); $executeSnapUpButton.on("click", (event) => { event = event || window.event; const $evnet = $(event.target); const $tipsBox = $(".snap-up-tips-text"); if ($tipsBox && $tipsBox.length > 0) { $tipsBox.hide(); }; const userCoinNumber = this.userInfoCacheMap ? this.userInfoCacheMap.bbsCoin : this.userInfo ? this.userInfo.coin : "0"; // const userCoinNumber = 999999999999; const snapUpTotalCoinNumber = this.snapUpCommodityTotalPrice ? this.snapUpCommodityTotalPrice : "0"; if (snapUpTotalCoinNumber > userCoinNumber) { const title = "您所拥有的弥尔币数量低于选购的商品弥尔币总和\n"; const content1 = `您的弥尔币数量:${userCoinNumber}\n`; const content2 = `商品弥尔币总和:${snapUpTotalCoinNumber}`; alert(title + content1 + content2); return; }; if (!this.snapUpQueryDataList || this.snapUpQueryDataList.length === 0) { alert("当前没有可供操作的数据对象,请检查是否勾选了商品"); return; }; $evnet.toggleClass("active"); if ($evnet.hasClass("active")) { $evnet.text("取消执行抢购脚本"); $evnet.attr("disabled", "disabled"); setTimeout(() => { $evnet.removeAttr("disabled"); }, 5000); $evnet.siblings("#getCommodityList").prop("disabled", true); const consoleStyle = { 0: "padding:5px 0;background: blue;color: #fff;", 1: "padding: 5px 5px 5px 0;background: #e5e5ff;color:blue", 2: "padding:5px 0;background: #00bc12;color: #fff;", 3: "padding: 5px 5px 5px 0;background: #e6ffe5;color:#00bc12", 4: "padding:5px 0;background: #ffa400;color: #fff;", 5: "padding: 5px 5px 5px 0;background: #fff0e5;color:#ffa400", }; // timeout this.snapUpTimeOut = this.snapUpTimeOut > 0 ? this.snapUpTimeOut : 0; const snapUpHandler = (commoditySnapUpDataMap) => { const now = new Date().getTime(); const id = commoditySnapUpDataMap.id; const name = commoditySnapUpDataMap.name; const startTime = commoditySnapUpDataMap.startTime; // const startTime = new Date("2023-04-28 18:22").getTime(); const formatStarTime = this.convertDateByTimestamp(startTime); const formatNowTime = this.convertDateByTimestamp(now); if (now >= startTime || formatStarTime == formatNowTime) { const timerDataMap = this.snapUpTimerList.find(timerDataMap => timerDataMap.id === id); clearInterval(timerDataMap.timer); timerDataMap.timer = null; this.snapUpTimerList = this.snapUpTimerList.filter(timerDataMap => timerDataMap.id != id); const $input = $(`input[id=${id}]`); const messageTemplate = `%c 已执行抢购: %c id:${id} \tname:${name} \t state:$state$ \t message:$message$`; this.snapUpQuery(commoditySnapUpDataMap.params, this.snapUpTimeOut * 1000) .then(res => { const $success = $(`<ion-icon>`).attr({ class: "snap-up-state-success", name: "checkmark-outline", title: "商品抢购成功-" + res }).css({ "display": "inline-block", "width": "15px", "height": "15px", "color": "#36cb2d", "cursor": "pointer" }); const printMessage = messageTemplate.replace("$state$", "成功").replace("$message$", res) console.log(printMessage, consoleStyle[2], consoleStyle[3]); $input.siblings(".snapUp-loading-box").remove(); if ($input.css("display") !== "none") return; if ($input.siblings(".snap-up-state-success").length > 0) { $input.siblings(".snap-up-state-success").remove(); }; $input.after($success); }) .catch(err => { const $failed = $(`<ion-icon>`).attr({ class: "snap-up-state-failed", name: "close-outline", title: "商品抢购失败-" + err }).css({ "display": "inline-block", "width": "15px", "height": "15px", "color": "#ff0000", "cursor": "pointer" }); const printMessage = messageTemplate.replace("$state$", "失败").replace("$message$", err) console.log(printMessage, consoleStyle[4], consoleStyle[5]); $input.siblings(".snapUp-loading-box").remove(); if ($input.css("display") !== "none") return; if ($input.siblings(".snap-up-state-failed").length > 0) { $input.siblings(".snap-up-state-failed").remove(); }; $input.after($failed); }); this.snapUpTimeOut += 5; return; }; const printMessage = `%c 正在抢购中: %c id:${id} \tname:${name} \t start:${formatStarTime} \t now:${formatNowTime}`; console.log(printMessage, consoleStyle[0], consoleStyle[1]) }; this.snapUpQueryDataList.map(commoditySnapUpDataMap => { let timer = setInterval(() => { snapUpHandler(commoditySnapUpDataMap); }, 500); this.snapUpTimerList.push({ id: commoditySnapUpDataMap.id, timer: timer }); }); const $snapUpLoadingDiv = $("<div>").attr({ class: "snapUp-loading-box", title: "商品抢购中...点击取消" }); $snapUpLoadingDiv.on("click", (event) => { event = event || window.event; const $event = $(event.delegateTarget); const id = $event.siblings("input").attr("id"); $event.toggleClass("active"); if ($event.hasClass("active")) { const $ion = $("<ion-icon>").attr({ class: "rerun-commodity-snapUp", name: "play-circle-outline", title: "重新运行该商品抢购" }); try { const snapUpTimerMap = this.snapUpTimerList.find(timerMap => { return timerMap.id === id; }); clearInterval(snapUpTimerMap.timer); } catch (error) { if (error) { console.log("已经执行到发送请求步骤,无法取消计时器。") }; }; this.snapUpTimerList = this.snapUpTimerList.filter(timerMap => { return timerMap.id != id; }); $event.children().hide(); $event.append($ion); } else { const snapUpCommodityMap = this.snapUpQueryDataList.find(commodityMap => { return commodityMap.id === id; }); this.snapUpTimeOut -= 5; let timer = setInterval(() => { snapUpHandler(snapUpCommodityMap); }, 500); this.snapUpTimerList.push({ id: snapUpCommodityMap.id, timer: timer }); $event.find(".snap-up-loading-svg").show(100); $event.find(".rerun-commodity-snapUp").remove(); }; }); const $snapUpLoadingSvg = $(`<svg class="snap-up-loading-svg" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0" width="15px" height="15px" viewBox="0 0 128 143" xml:space="preserve" > <path fill="#096aec" d="M119.8 31.3l-.6-.6a2.8 2.8 0 0 1-.4.5L116 34a2.8 2.8 0 0 1-4 0v-.2l-1.5 1.5a64 64 0 1 1-48.4-20v-2.6h-.6A3.7 3.7 0 0 1 57.6 9V3.7A3.7 3.7 0 0 1 61.4 0h5.2a3.7 3.7 0 0 1 3.8 3.7V9a3.7 3.7 0 0 1-3.8 3.7H66v2.6a63.8 63.8 0 0 1 42 17.4l1.4-1.5a2.8 2.8 0 0 1 0-4l2.7-2.7a2.8 2.8 0 0 1 .5-.4l-.6-.5a2 2 0 1 1 2.7-2.8l8 8a2 2 0 0 1-3 2.6zM64 19.3a59.7 59.7 0 1 0 60 60 59.8 59.8 0 0 0-60-60zM109.7 80v-1.6h7V80h-7zm-6.5-24.3l6-3.5 1 1.3-6.3 3.5zm-17 63.3l1.3-.8 3.5 6.2-1.3.7zm0-79.7l3.5-6 1.3.6-3.5 6zM64 86a6.7 6.7 0 1 1 6.7-6.8A6.7 6.7 0 0 1 64 86zm0-11.7a5 5 0 1 0 5 5 5 5 0 0 0-5-5zm-.7-47.8h1.5v7h-1.5v-7zm-26.3 98l3.5-6.3 1.3.8-3.5 6zm0-90.6l1.3-.8 3.5 6-1.3 1zm-19 70.8l6-3.5.8 1.3-6 3.5zm0-51.3l.7-1.3 6 3.5-.6 1.3zm.3 26.4h-7v-1.6h7V80zm46.4 51.8h-1.5v-7h1.5v7zm45.4-27l-.7 1.3-6-3.4.6-1.3z"/> <path fill="#096aec" d="M64 73.6l-3-.4.8-34 2.2-3.7 2.2 3.7.8 34z"> <animateTransform attributeName="transform" type="rotate" from="0 64 79" to="360 64 79" dur="2160ms" repeatCount="indefinite"/> </path> </svg>`); $snapUpLoadingDiv.append($snapUpLoadingSvg); const $commodityCheckedInput = $(".commodity-isSnapUp input:checked"); $commodityCheckedInput.hide().after($snapUpLoadingDiv); } else { $evnet.text("执行抢购脚本"); $evnet.siblings("#getCommodityList").removeAttr("disabled"); const $commodityCheckedInput = $(".commodity-isSnapUp input:checked"); $commodityCheckedInput.show(100).siblings(".snapUp-loading-box").remove(); $commodityCheckedInput.siblings('[class^="snap-up-state-"]').remove(); this.snapUpTimerList.map(commoditySnapUpTimerMap => { clearInterval(commoditySnapUpTimerMap.timer); }); }; }); $snapUpButtonListBox.append( $getUserInfoButton, $getCommodityListButton, $executeSnapUpButton ); const tipsText1 = "论坛购买商城商品大概有5秒的时间差,如果小于这个间隔则购买请求提示“访问频繁,请稍后再试!”<br>"; const tipsText2 = "保险一点的就是抢一件,如果勾选多个,有可能在请求间隔外被别人抢完了(贪心不足蛇吞象)"; const $tipsDiv = $("<div>").attr({ class: "snap-up-tips-text", title: "商品抢购提示语" }).html(tipsText1 + tipsText2); $snapUpContainer.append($snapUpButtonListBox, $tipsDiv); return $snapUpContainer; } // 创建商城商品展示表格tr行 createCommodityTrLine(params) { const { id, name, state, type, rnum, cnum, tnum, snum, gl, fl, startTime, endTime, price, isSatisfy, snapUpInput, extraParams } = params; const satisfy_yes = '<ion-icon class="satisfy-icon yes" name="checkmark-circle-outline"></ion-icon>'; const satisfy_no = '<ion-icon class="satisfy-icon no" name="close-circle-outline"></ion-icon>'; const surplusClass = tnum > 0 ? snum > 0 ? "satisfy-yes" : "satisfy-no" : "satisfy-yes"; const glClass = extraParams.userGameLevel > extraParams.commodityConditionGameLevel ? "satisfy-yes" : "satisfy-no"; const flClass = extraParams.userForumLevel > extraParams.commodityConditionForumLevel ? "satisfy-yes" : "satisfy-no"; const startTimeClass = extraParams.validStartDate > new Date().getTime() ? "satisfy-future" : "satisfy-past del"; const endTimeClass = extraParams.validEndDate > new Date().getTime() ? "satisfy-future" : "satisfy-past del"; const coinClass = extraParams.userCoinNumber > price ? "satisfy-yes" : "satisfy-no"; const $tr = $(`<tr> <td class="commodity-id">${id}</td> <td class="commodity-name">${name}</td> <td class="commodity-state"></td> <td class="commodity-type">${type}</td> <td class="commodity-restrictionNumber ${rnum > 0 ? cnum == rnum ? "satisfy-yes satisfy-line-red" : "satisfy-yes" : "satisfy-no"}"> ${rnum} </td> <td class="commodity-cycleBuyNumber ${rnum > 0 ? cnum == rnum ? "satisfy-yes satisfy-line-red" : "satisfy-unused" : "satisfy-no"}"> ${cnum} </td> <td class="commodity-totalNumber satisfy-yes"> ${tnum !== 0 ? tnum : "∞"} </td> <td class="commodity-surplusNumber ${surplusClass}"> ${tnum == 0 && snum == 0 ? "∞" : snum} </td> <td class="commodity-condition_gl ${glClass}">${gl}</td> <td class="commodity-condition_fl ${flClass}">${fl}</td> <td class="commodity-startTime ${startTimeClass}">${startTime}</td> <td class="commodity-endTime ${endTimeClass}">${endTime}</td> <td class="commodity-price ${coinClass}">${price}</td> <td class="commodity-isSatisfy"></td> </tr>`); $tr.find(".commodity-state").append(state ? $(satisfy_yes) : $(satisfy_no)); $tr.find(".commodity-isSatisfy").append(isSatisfy ? $(satisfy_yes) : $(satisfy_no)); if (snapUpInput) { const $td = $("<td>").attr({ class: "commodity-isSnapUp" }); const $input = $("<input>").attr({ id: snapUpInput.id, name: snapUpInput.name, type: "checkbox", "data-price": price }); $input.on("change", (event) => { event = event || window.event; const commodityid = $(event.target).attr("id"); const commodityName = $(event.target).attr("name"); const inputState = $(event.target).prop("checked"); const price = $(event.target).attr("data-price"); if (inputState) { const commodityObj = this.commodityList.find(commodityMap => { return commodityMap.id === commodityid && commodityMap.name === commodityName; }); const paramsMap = { buyNum: commodityObj.restrictionNumber || 1, commodityId: commodityObj.id || commodityid, totalPrice: commodityObj.price, uid: this.userInfoCacheMap.gameUid, userAddressId: this.userAddressInfoMap ? this.userAddressInfoMap.id : "" }; const params = this.convertUrlParams("", paramsMap).replace("?", ""); const dataMap = { id: commodityObj.id, name: commodityObj.name, price: commodityObj.price, startTime: commodityObj.validStartDate, params: params }; this.snapUpQueryDataList.push(dataMap); this.snapUpCommodityTotalPrice += commodityObj.price; } else { const filterList = this.snapUpQueryDataList.filter(queryDataMap => { return queryDataMap.id !== commodityid && queryDataMap.name !== commodityName; }); this.snapUpQueryDataList = filterList; this.snapUpCommodityTotalPrice -= price; }; }) if (!isSatisfy) { $input.prop("disabled", true); }; $td.append($input); $tr.append($td); }; return $tr; } // 创建草稿箱选项下拉菜单 createDraftSelect({ id, configKey }) { const $select = $("<select>").attr({ id: id, class: "draft-list-select" }); $select.on("change", (event) => { event = event || window.event; const draftPostId = event.target.value; if (draftPostId === "0") { const customContent = { id: "", content: "", contentJson: "{}", title: "", cacheList: this.toolsStateDataConfig.customContentConfig[configKey].cacheList }; this.toolsStateDataConfig.customContentConfig[configKey] = customContent; this.saveDataToLocalStorage(); return; }; if (this.draftPostList && Array.isArray(this.draftPostList)) { this.draftPostList.map(draftPost => { if (draftPost.id === draftPostId) { const customContent = { id: draftPost.id, content: draftPost.content, contentJson: draftPost.contentJson, title: draftPost.title, cacheList: this.toolsStateDataConfig.customContentConfig[configKey].cacheList } this.toolsStateDataConfig.customContentConfig[configKey] = customContent; this.saveDataToLocalStorage(); return; } }) }; }); return $select; } // 创建追加到基础设置中特殊功能的自定义设置部分 createAppendBasicSpecialBody() { const $div = $("<div>").attr({ class: "basic-setting-container" }); const $button1 = this.createToolsButton({ id: "isDeleteMyAllPost", cls: "tools-button", text: "删除所有帖子", style: "", disabled: !this.toolsStateDataConfig.stateConfig.isDeleteMyAllPost }); this.bindToolsButtonClickEvent({ $button: $button1, id: "isDeleteMyAllPost", handler: "recursionQueryData", handlerType: 4 }); const $button2 = this.createToolsButton({ id: "isDeleteMyAllComment", cls: "tools-button", text: "删除所有评论", style: "", disabled: !this.toolsStateDataConfig.stateConfig.isDeleteMyAllComment }); this.bindToolsButtonClickEvent({ $button: $button2, id: "isDeleteMyAllComment", handler: "getUserSpaceAllComment", handlerType: 0 }); const $button3 = this.createToolsButton({ id: "isCancelMyAllLikeState", cls: "tools-button", text: "撤销所有点赞", style: "", disabled: !this.toolsStateDataConfig.stateConfig.isCancelMyAllLikeState }); this.bindToolsButtonClickEvent({ $button: $button3, id: "isCancelMyAllLikeState", handler: "recursionQueryData", handlerType: 5 }); const $button4 = this.createToolsButton({ id: "isClearUserLocalData", cls: "tools-button", text: "删除本地缓存", style: "", disabled: !this.toolsStateDataConfig.stateConfig.isClearUserLocalData }); $button4.on("click", (event) => { event = event || window.event; this.toolsLocalStorage({ handle: "removeItem" }); window.location.reload(); }); const $button5 = this.createToolsButton({ id: "isResetToolsDefaultState", cls: "tools-button", text: "重置工具状态", style: "", disabled: !this.toolsStateDataConfig.stateConfig.isResetToolsDefaultState }); $button5.on("click", (event) => { event = event || window.event; this.toolsStateDataConfig = this.toolsDefaultStateConfig; this.saveDataToLocalStorage(); window.location.reload(); }) $div.append($button1, $button2, $button3, $button4, $button5); return $div; } // 绑定特殊设置工具按钮点击事件 bindToolsButtonClickEvent({ $button, id, handler, handlerType }) { let timer = null; $button.on({ click: (event) => { event = event || window.event; event.preventDefault(); event.stopPropagation(); clearTimeout(timer); const str1 = "该功能会删除个人用户数据,数据无价,请谨慎操作!"; const str2 = "请确认无误后双击即可执行该脚本,执行进度请按F12打开控制台查看。"; timer = setTimeout(() => { alert(`${str1}\n${str2}`); }, 300); }, dblclick: (event) => { event = event || window.event; event.preventDefault(); event.stopPropagation(); clearTimeout(timer); const state = this.toolsStateDataConfig.stateConfig[id]; console.clear(); if (state && handler && handler === "recursionQueryData") { if (id === "isDeleteMyAllPost") { this.recursionQueryData(true, 0, handlerType, "deleteMyPagePost"); }; if (id === "isCancelMyAllLikeState") { this.recursionQueryData(true, 0, handlerType, "cancelLikeState"); }; }; if (state && handler && handler === "getUserSpaceAllComment") { if (id === "isDeleteMyAllComment") { this.getUserSpaceAllComment().then(resList => { const commetIdList = resList.map(itemMap => itemMap.reply.reply.id); this.deleteMyComment(commetIdList); }); }; }; } }); } // 创建追加到每日任务中自定义内容的模板 createDayTaskCustomBodyTemplate(params) { const { $select, button1Text, button1Func, button2Href, hrefParams, button2Text, selectId, configKey, centerText, description, } = params; const $containerDiv = $("<div>").attr({ class: "daytask-draft-container", "data-belong": configKey }); const $selectBox = $("<div>").attr({ class: "draft-select-list-box", "data-belong": configKey }); const $span = $("<span>").text("选择草稿内容:"); const $doTestContentButton = $("<button>").attr({ type: "button", role: "button", class: "ys4fun-tools-test-button", "data-belong": configKey }).text(button1Text); $doTestContentButton.on("click", (event) => { event = event || window.event; $(event.target).attr("disabled", "disabled"); $(event.target).hide("fast", "linear"); $(`.review-post-button-list-box[data-belong="${configKey}"]`).show("fast"); $(`.reviewPostButtonListBox-line[data-belong="${configKey}"]`).show("fast"); setTimeout(() => { $(event.target).show("fast", "linear"); $(event.target).removeAttr("disabled"); }, 15000); let promise = new Promise((resolve, reject) => { if (button1Func === "changePostReleaseState") { this.changePostReleaseState() .then(res => { resolve(res); }) .catch(err => reject(err)); }; if (button1Func === "changePostReviewState") { this.changePostReviewState() .then(res => { resolve(res) }) .catch(err => reject(err)); }; }); promise.then(res => { const $lookTestContetButton = $("<button>").attr({ type: "button", role: "button", class: "ys4fun-tools-test-button" }); const params = (hrefParams === "userId" ? this.userInfo.id : hrefParams) || res; if (!params) { const $listBox = $(`.review-post-button-list-box[data-belong="${configKey}"]`); const $listBoxLine = $(`.reviewPostButtonListBox-line[data-belong="${configKey}"]`); if (!$listBox.children().length) { $listBox.hide(); $listBoxLine.hide(); }; return; }; const lookText = hrefParams !== "userId" ? button2Text + "-" + params : button2Text; const $a = $("<a>").attr({ href: button2Href + params, target: "_blank" }).text(lookText); $lookTestContetButton.on("click", (event) => { event = event || window.event; $(event.delegateTarget).remove() }); $lookTestContetButton.append($a); $(`.review-post-button-list-box[data-belong="${configKey}"]`).append($lookTestContetButton); }).catch(err => { console.log(err); }); }); const $reviewPostButtonListBox = $("<div>").attr({ class: "review-post-button-list-box", "data-belong": configKey }).css("display", "none"); const $draftButtonListBox = $("<div>").attr({ class: "draft-button-list-box", "data-belong": configKey }); const $randomContentMapListBox = $("<div>").attr({ class: "random-content-list-box", "data-box-id": configKey, "data-belong": configKey }).css("display", "none"); if (this.toolsStateDataConfig.customContentConfig[configKey]["cacheList"].length > 0) { $randomContentMapListBox.css("display", "block"); }; const $randomContentListUl = this.createCustomContentDraftRandomListTemplate(configKey); const $refreshSelectButton = $("<button>").attr({ type: "button", role: "button", class: "ys4fun-tools-test-button" }).text("刷新选单"); $refreshSelectButton.on("click", () => { $(selectId).children().remove(); this.refreshDraftPostList(); }); const $addRandomContentForListButton = $("<button>").attr({ type: "button", role: "button", class: "ys4fun-tools-test-button" }).text("添加到随机内容列表"); $addRandomContentForListButton.on("click", (event) => { event = event || window.event; const draftId = $(selectId).val(); if (draftId === "0") return; $(`.random-content-list-box[data-belong="${configKey}"]`).show("fast"); $(`.randomContentMapListBox-line[data-belong="${configKey}"]`).show("fast"); if (Array.isArray(this.draftPostList) && this.draftPostList.length > 0) { const isExist = this.toolsStateDataConfig.customContentConfig[configKey]["cacheList"].find(item => item.id == draftId); if (!isExist) { this.draftPostList.map(draftPostMap => { if (draftPostMap.id == draftId) { const customContentMap = { id: draftPostMap.id, content: draftPostMap.content, contentJson: draftPostMap.contentJson, title: draftPostMap.title }; this.toolsStateDataConfig.customContentConfig[configKey]["cacheList"].push(customContentMap); this.saveDataToLocalStorage(); return; }; }); }; }; const $newRandomContentListUl = this.createCustomContentDraftRandomListTemplate(configKey); $(`.random-content-list-box[data-belong="${configKey}"]`).children().remove(); $(`.random-content-list-box[data-belong="${configKey}"]`).append($newRandomContentListUl); }) $draftButtonListBox.append( $refreshSelectButton, $addRandomContentForListButton, $doTestContentButton ); const $appendContainerDiv = $("<div>").css({ "width": "100%", "height": "100%", "padding": "5px" }).attr({ class: "daytask-setting-append-container" }); const $center = $("<center>").css({ "padding": "5px", "font-weight": "700" }).text(centerText); const $p = $("<p>").css({ "text-indent": "2em", "font-size": "12px", "line-height": "20px", "letter-spacing": "0.25em" }).html(description); const line = `<div style="border-top: 1px dashed #d8dadb;" data-belong="${configKey}"]>`; $selectBox.append($span, $select); $appendContainerDiv.append($center, $p); $randomContentMapListBox.append($randomContentListUl); $containerDiv.append( $selectBox, $(line), $draftButtonListBox, $(line), $reviewPostButtonListBox, $(line).attr("class", "reviewPostButtonListBox-line").css("display", "none"), $randomContentMapListBox, $(line).attr("class", "randomContentMapListBox-line").css("display", "none"), $appendContainerDiv ); return $containerDiv; } // 创建自定义内容草稿的随机列表 createCustomContentDraftRandomListTemplate(configKey) { $(`div[data-box-id="${configKey}"] .random-content-list`).children().remove(); const $randomContentListUl = $("<ul>").attr({ class: "random-content-list", "data-id": configKey }); this.toolsStateDataConfig.customContentConfig[configKey]["cacheList"].forEach(contentMap => { const $randomContentItemLi = $("<li>").attr({ class: "random-content-item", "data-post-id": contentMap.id }).css("display", "grid") const $idSpan = $("<span>").attr({ class: "random-content-item__id", title: "草稿帖子id" }).text(contentMap.id); const $titleSpan = $("<span>").attr({ class: "random-content-item__title", title: "草稿帖子标题" }).text(contentMap.title); const $handleSpan = $("<span>").attr({ class: "random-content-item__handle", title: "从列表中删除该草稿对象" }); const $handleIon = $("<ion-icon>").attr({ name: "close-circle-outline", }); $handleIon.on("click", (event) => { event = event || window.event; const $parentLi = $(event.target).parents("li.random-content-item"); const $parentUl = $parentLi.parents(`ul[data-id="${configKey}"]`); const id = $parentLi.attr("data-post-id"); if ($parentUl.length > 0 && $parentUl.children().length === 1) { const $box = $parentUl.parents("div.random-content-list-box"); const $line = $box.siblings(".randomContentMapListBox-line"); $parentUl.hide(); $box.hide("fast", "linear"); $line.hide(); } const fiterDataList = this.toolsStateDataConfig.customContentConfig[configKey]["cacheList"].filter(item => { return item.id !== id; }); this.toolsStateDataConfig.customContentConfig[configKey]["cacheList"] = fiterDataList; this.saveDataToLocalStorage(); $parentLi.remove(); }); $handleSpan.append($handleIon); $randomContentItemLi.append($idSpan, $titleSpan, $handleSpan); $randomContentListUl.append($randomContentItemLi); }); return $randomContentListUl; } // 创建追加到发帖设置中的自定义设置部分 createAppendPostedCustomBody() { const $select = this.createDraftSelect({ id: "draft-list-select_posted", configKey: "customPostContent" }); const $box = this.createDayTaskCustomBodyTemplate({ $select: $select, button1Text: "测试帖子", button1Func: "changePostReleaseState", button2Href: "https://bbs.ys4fun.com/posts/", hrefParams: "", button2Text: "查看帖子", selectId: "#draft-list-select_posted", configKey: "customPostContent", centerText: "开启自定义帖子内容说明", description: "在登录的情况下,点击首页的<<我要发布>>按钮, 即可创建帖子的内容,创建好后保存到草稿箱即可在选单列表中查看,选择相应的草稿即可。" }); return $box; } // 创建自定义评论设置中追加的内容结构 createAppendCommentCustomBody() { const $select = this.createDraftSelect({ id: "draft-list-select_comment", configKey: "customCommentContent" }); const $box = this.createDayTaskCustomBodyTemplate({ $select: $select, button1Text: "测试评论", button1Func: "changePostReviewState", button2Href: "https://bbs.ys4fun.com/space/", hrefParams: "userId", button2Text: "查看评论", selectId: "#draft-list-select_comment", configKey: "customCommentContent", centerText: "开启自定义评论内容说明", description: "在登录的情况下,点击首页的<<我要发布>>按钮, 即可创建帖子的内容,创建好后保存到草稿箱即可在选单列表中查看,选择相应的草稿即可。" }); return $box; } // 创建用户信息容器内容主体 createUserInfoContainerBody() { const $box = $("<div>").attr({ class: "ys4fun-tools-userInfo-container" }); const $ul = $("<ul>").attr({ class: "ys4fun-tools-userInfo-list" }); this.userInfoConfigList.map(itemMap => { const $li = $("<li>").attr({ class: "ys4fun-tools-userInfo-list__item", "data-index": itemMap.id }); const $div = $("<div>").attr({ class: "userInfo-item-box" }); const $spanTitle = $("<span>").attr({ class: "userInfo-item-box__title" }).text(itemMap.key); const $spanText = $("<span>").attr({ class: "userInfo-item-box__text" }).text(itemMap.value); $div.append($spanTitle, $spanText); $li.append($div); $ul.append($li); }); $box.append($ul); return $box; } // 创建更改状态的 label 内含span和input createChangeStateLabel(params) { const { inputId, spanText, inputClass, inputType, inputState, labelClass } = params; const $label = $("<label>").attr({ for: inputId, class: labelClass || "" }); const $span = $("<span>").text(spanText); const $input = $("<input>").attr({ id: inputId, class: inputClass, type: inputType, checked: inputState }); $input.on("click", (event) => { event = event || window.event; const id = $(event.target).attr("id"); const state = $(event.target).is(":checked"); this.toolsStateDataConfig.stateConfig[id] = state; this.saveDataToLocalStorage(); }); $label.append($span, $input); return $label; } // 创建工具所用按钮元素 createToolsButton(params) { const { id, cls, text, style, html, disabled } = params; const $button = $("<button>").attr({ id: id, class: cls, disabled: disabled }); style && $button.css({ ...style }); text && $button.text(text); html && $button.html(html); return $button; } // 创建设置选项菜单内容 createSettingOptionsMenu() { const $settingOptionMenu = $("<ul>").attr({ class: "ys4fun-tools-setting-container-menu" }); this.settingSubMenuList.forEach(itemMap => { const $optionItem = $("<li>").attr({ id: itemMap.attr.id, class: "ys4fun-tools-setting-container-item", "data-index": itemMap.id }); const $h4 = $("<h4>").attr({ class: "ys4fun-tools-setting-container-item__title" }).text(itemMap.text); $h4.on("click", (event) => { event = event || window.event; event.stopPropagation(); const $event = $(event.target); const $optionsLi = $event.parents(".ys4fun-tools-setting-container-item"); const $subitemUl = $optionsLi.find(".ys4fun-tools-setting-container-item-subitem-list"); const $optionMenu = $optionsLi.parents(".ys4fun-tools-setting-container-menu"); const index = $optionsLi.attr("data-index"); const id = $optionsLi.attr("id"); $optionMenu.find(".ys4fun-tools-setting-container-item-subitem__item").removeClass("active"); $optionsLi.toggleClass("active"); $optionsLi.siblings().removeClass("active"); $optionsLi.siblings().find(".ys4fun-tools-setting-container-item-subitem-list").hide("fast"); const $subitemLi = $subitemUl.find(".ys4fun-tools-setting-container-item-subitem__item"); const $optionsMenu = $subitemUl.parents(".ys4fun-tools-setting-container-menu"); const $optionsContainerUl = $optionsMenu.siblings(".ys4fun-tools-setting-container-item-content-list"); const $optionsContainerLi = $optionsContainerUl.find(`[data-index="${index}"][data-bind-id="${id}"]`); $optionsContainerLi.toggleClass("active"); $optionsContainerLi.siblings("li").removeClass("active"); $optionsContainerUl.find("li").hide(); $optionsContainerUl.find("li").removeClass("active"); $subitemUl.hide("fast"); $subitemLi.removeClass("active"); if ($optionsLi.hasClass("active")) { $subitemUl.show("fast", "linear").children("li").removeClass("active"); $optionsContainerLi.show("fast", "linear"); $optionsContainerLi.siblings("li").hide(); } else { $subitemUl.hide("fast", "linear").children("li").removeClass("active"); $optionsContainerLi.hide("fast", "linear").removeClass("active"); $optionsContainerLi.siblings("li").hide(); $optionsContainerLi.find(".ys4fun-tools-setting-container-item-content-item-subitem__item").hide(); }; }); const $subitemList = $("<ul>").attr({ class: "ys4fun-tools-setting-container-item-subitem-list" }); itemMap.subitemList.forEach(subitemMap => { const $li = $("<li>").attr({ id: subitemMap.attr.id, class: "ys4fun-tools-setting-container-item-subitem__item", "data-index": subitemMap.id }); $li.on("click", (event) => { event = event || window.event; event.stopPropagation(); const $li = $(event.delegateTarget); const $ul = $li.parents(".ys4fun-tools-setting-container-item-subitem-list"); const index = $li.attr("data-index"); $li.siblings().removeClass("active"); $li.toggleClass("active"); const $menuLi = $ul.parents(".ys4fun-tools-setting-container-item"); const $menuUl = $menuLi.parents(".ys4fun-tools-setting-container-menu"); const menuLiId = $menuLi.attr("id"); const menuLiIndex = $menuLi.attr("data-index"); const $containerUl = $menuUl.siblings(".ys4fun-tools-setting-container-item-content-list"); const $containerLi = $containerUl.find(`[data-index="${menuLiIndex}"][data-bind-id="${menuLiId}"]`); $containerLi.show("fast", "linear"); const $containerLiItemContent = $containerLi.find(`[data-index="${index}"]`); $containerLiItemContent.toggleClass("active"); $containerLiItemContent.siblings().removeClass("active"); if ($li.hasClass("active")) { $containerLiItemContent.siblings().hide(); $containerLiItemContent.show("fast", "linear"); } else { $containerLiItemContent.siblings().hide() $containerLiItemContent.hide("fast", "linear"); }; }); const $span = $("<span>").attr({ role: "button" }).text(subitemMap.text); $li.append($span); $subitemList.append($li); }) $optionItem.append($h4, $subitemList); $settingOptionMenu.append($optionItem); }); return $settingOptionMenu; } // 创建工具图标脚本标签 createToolsIconScriptTag() { const scriptTag1 = $("<script>").attr({ type: "module", src: "https://unpkg.com/[email protected]/dist/ionicons/ionicons.esm.js" }); const scriptTag2 = $("<script>").attr({ nomodule: "nomodule", src: "https://unpkg.com/[email protected]/dist/ionicons/ionicons.js" }); return [scriptTag1, scriptTag2]; } // 创建工具主面板 createToolsPanel(position) { const $toolsPanel = $("<div>").attr({ id: "ys4fun-tools-panel" // title: "ys4fun-tools" }); if (position) { $toolsPanel.css({ top: position.top + "px", left: position.left + "px" }); }; const $toolsMenuPanel = this.createToolsMenuPanel(); $toolsPanel.append($toolsMenuPanel); $toolsPanel.on({ mousedown: (event) => { event = event || window.event; event.stopPropagation(); const $button = $(event.target); const $panel = $(event.delegateTarget); const offset = $panel.offset(); const className = "ys4fun-tools-menu__button-icon"; if (!$button.hasClass(className)) { return; }; let ex = event.clientX; let ey = event.clientY; let bx = offset.left; let by = offset.top; let cx = ex - bx; let cy = ey - by; document.onmousemove = (event) => { event = event || window.event; const doc = document.documentElement; let mx = event.clientX; let my = event.clientY; let lx = mx - cx; let ly = my - cy; lx <= 0 ? lx = 0 : lx; ly <= 0 ? ly = 0 : ly; let cw = doc.clientWidth; let ch = doc.clientHeight; let bw = $panel.outerWidth(); let bh = $panel.outerHeight(); let rx = cw - bw; let ry = ch - bh; lx >= rx ? lx = rx : lx; ly >= ry ? ly = ry : ly; $panel.css("left", lx + "px"); $panel.css("top", ly + "px"); this.toolPanelPosition = { top: ly, left: lx }; this.saveToolPanelPositionToLocalStorage(); }; }, mouseleave: function (event) { const $panel = $(event.delegateTarget); const $menu = $panel.find(".ys4fun-tools-menu-panel"); $menu.removeClass("active"); } }); $toolsPanel.on("dblclick", ".ys4fun-tools-menu__open-button", (event) => { const $panel = $(event.delegateTarget); $panel.hide(); }); document.onmouseup = (event) => { document.onmousemove = null; }; return $toolsPanel; } } // 签名生成器 const SignatureGenerator = class { static key = "d9d973c01b3517aef6b9c2a7dacde323"; static str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; static len = 10; // 创建签名唯一的id static createNonce() { const str = this.str; let nonce = ""; for (let i = 0; i < this.len; i++) { const rand = Math.floor(Math.random() * str.length); nonce += str.charAt(rand) } return nonce; } // 构建签名 static signatureBuilder(t) { function e(D, k) { return D << k | D >>> 32 - k } function n(D, k) { var M, K, ee, le, ve; return ee = D & 2147483648, le = k & 2147483648, M = D & 1073741824, K = k & 1073741824, ve = (D & 1073741823) + (k & 1073741823), M & K ? ve ^ 2147483648 ^ ee ^ le : M | K ? ve & 1073741824 ? ve ^ 3221225472 ^ ee ^ le : ve ^ 1073741824 ^ ee ^ le : ve ^ ee ^ le } function r(D, k, M) { return D & k | ~D & M } function i(D, k, M) { return D & M | k & ~M } function a(D, k, M) { return D ^ k ^ M } function s(D, k, M) { return k ^ (D | ~M) } function l(D, k, M, K, ee, le, ve) { return D = n(D, n(n(r(k, M, K), ee), ve)), n(e(D, le), k) } function o(D, k, M, K, ee, le, ve) { return D = n(D, n(n(i(k, M, K), ee), ve)), n(e(D, le), k) } function c(D, k, M, K, ee, le, ve) { return D = n(D, n(n(a(k, M, K), ee), ve)), n(e(D, le), k) } function u(D, k, M, K, ee, le, ve) { return D = n(D, n(n(s(k, M, K), ee), ve)), n(e(D, le), k) } function d(D) { for (var k, M = D.length, K = M + 8, ee = (K - K % 64) / 64, le = (ee + 1) * 16, ve = Array(le - 1), we = 0, H = 0; H < M;) k = (H - H % 4) / 4, we = H % 4 * 8, ve[k] = ve[k] | D.charCodeAt(H) << we, H++; return k = (H - H % 4) / 4, we = H % 4 * 8, ve[k] = ve[k] | 128 << we, ve[le - 2] = M << 3, ve[le - 1] = M >>> 29, ve } function h(D) { var k = "", M = "", K, ee; for (ee = 0; ee <= 3; ee++) K = D >>> ee * 8 & 255, M = "0" + K.toString(16), k = k + M.substr(M.length - 2, 2); return k } function v(D) { D = D.replace(/\r\n/g, ` `); for (var k = "", M = 0; M < D.length; M++) { var K = D.charCodeAt(M); K < 128 ? k += String.fromCharCode(K) : K > 127 && K < 2048 ? (k += String.fromCharCode(K >> 6 | 192), k += String.fromCharCode(K & 63 | 128)) : (k += String.fromCharCode(K >> 12 | 224), k += String.fromCharCode(K >> 6 & 63 | 128), k += String.fromCharCode(K & 63 | 128)) } return k } var p = Array(), g, y, S, A, _, b, w, C, T, E = 7, P = 12, L = 17, I = 22, R = 5, B = 9, V = 14, Y = 20, F = 4, ie = 11, Z = 16, U = 23, ae = 6, te = 10, se = 15, X = 21; for (t = v(t), p = d(t), b = 1732584193, w = 4023233417, C = 2562383102, T = 271733878, g = 0; g < p.length; g += 16) y = b, S = w, A = C, _ = T, b = l(b, w, C, T, p[g + 0], E, 3614090360), T = l(T, b, w, C, p[g + 1], P, 3905402710), C = l(C, T, b, w, p[g + 2], L, 606105819), w = l(w, C, T, b, p[g + 3], I, 3250441966), b = l(b, w, C, T, p[g + 4], E, 4118548399), T = l(T, b, w, C, p[g + 5], P, 1200080426), C = l(C, T, b, w, p[g + 6], L, 2821735955), w = l(w, C, T, b, p[g + 7], I, 4249261313), b = l(b, w, C, T, p[g + 8], E, 1770035416), T = l(T, b, w, C, p[g + 9], P, 2336552879), C = l(C, T, b, w, p[g + 10], L, 4294925233), w = l(w, C, T, b, p[g + 11], I, 2304563134), b = l(b, w, C, T, p[g + 12], E, 1804603682), T = l(T, b, w, C, p[g + 13], P, 4254626195), C = l(C, T, b, w, p[g + 14], L, 2792965006), w = l(w, C, T, b, p[g + 15], I, 1236535329), b = o(b, w, C, T, p[g + 1], R, 4129170786), T = o(T, b, w, C, p[g + 6], B, 3225465664), C = o(C, T, b, w, p[g + 11], V, 643717713), w = o(w, C, T, b, p[g + 0], Y, 3921069994), b = o(b, w, C, T, p[g + 5], R, 3593408605), T = o(T, b, w, C, p[g + 10], B, 38016083), C = o(C, T, b, w, p[g + 15], V, 3634488961), w = o(w, C, T, b, p[g + 4], Y, 3889429448), b = o(b, w, C, T, p[g + 9], R, 568446438), T = o(T, b, w, C, p[g + 14], B, 3275163606), C = o(C, T, b, w, p[g + 3], V, 4107603335), w = o(w, C, T, b, p[g + 8], Y, 1163531501), b = o(b, w, C, T, p[g + 13], R, 2850285829), T = o(T, b, w, C, p[g + 2], B, 4243563512), C = o(C, T, b, w, p[g + 7], V, 1735328473), w = o(w, C, T, b, p[g + 12], Y, 2368359562), b = c(b, w, C, T, p[g + 5], F, 4294588738), T = c(T, b, w, C, p[g + 8], ie, 2272392833), C = c(C, T, b, w, p[g + 11], Z, 1839030562), w = c(w, C, T, b, p[g + 14], U, 4259657740), b = c(b, w, C, T, p[g + 1], F, 2763975236), T = c(T, b, w, C, p[g + 4], ie, 1272893353), C = c(C, T, b, w, p[g + 7], Z, 4139469664), w = c(w, C, T, b, p[g + 10], U, 3200236656), b = c(b, w, C, T, p[g + 13], F, 681279174), T = c(T, b, w, C, p[g + 0], ie, 3936430074), C = c(C, T, b, w, p[g + 3], Z, 3572445317), w = c(w, C, T, b, p[g + 6], U, 76029189), b = c(b, w, C, T, p[g + 9], F, 3654602809), T = c(T, b, w, C, p[g + 12], ie, 3873151461), C = c(C, T, b, w, p[g + 15], Z, 530742520), w = c(w, C, T, b, p[g + 2], U, 3299628645), b = u(b, w, C, T, p[g + 0], ae, 4096336452), T = u(T, b, w, C, p[g + 7], te, 1126891415), C = u(C, T, b, w, p[g + 14], se, 2878612391), w = u(w, C, T, b, p[g + 5], X, 4237533241), b = u(b, w, C, T, p[g + 12], ae, 1700485571), T = u(T, b, w, C, p[g + 3], te, 2399980690), C = u(C, T, b, w, p[g + 10], se, 4293915773), w = u(w, C, T, b, p[g + 1], X, 2240044497), b = u(b, w, C, T, p[g + 8], ae, 1873313359), T = u(T, b, w, C, p[g + 15], te, 4264355552), C = u(C, T, b, w, p[g + 6], se, 2734768916), w = u(w, C, T, b, p[g + 13], X, 1309151649), b = u(b, w, C, T, p[g + 4], ae, 4149444226), T = u(T, b, w, C, p[g + 11], te, 3174756917), C = u(C, T, b, w, p[g + 2], se, 718787259), w = u(w, C, T, b, p[g + 9], X, 3951481745), b = n(b, y), w = n(w, S), C = n(C, A), T = n(T, _); return (h(b) + h(w) + h(C) + h(T)).toLowerCase() } // 获取签名结果 static getSignatureResult(t, e, n, r) { let i = ""; const a = []; for (const s in t) a.push(s); a.sort(); for (const s of a) i = i + "&" + s + "=" + t[s]; return i = i.substring(1) + "&appSecret=" + n + "&nonce=" + e + "×tamp=" + r, this.signatureBuilder(i); } // 获取签名后的请求参数 static getSignaturedParams(t) { const e = new Date().getTime(), n = this.createNonce(), r = this.key; if (t.headers && ((t == null ? void 0 : t.headers["Content-Type"]) === "application/json" || (t == null ? void 0 : t.headers["content-type"]) === "application/json")) { const a = JSON.stringify(t.data) + "&appSecret=" + r + "&nonce=" + n + "×tamp=" + e; t.headers["X-API-TIMESTAMP"] = e, t.headers["X-API-NONCE"] = n, t.headers["X-API-SIGNATURE"] = this.signatureBuilder(a), t.headers["X-API-SIGNTYPE"] = "md5" } else t.headers = {}, t.headers["X-API-TIMESTAMP"] = e, t.headers["X-API-NONCE"] = n, t.headers["X-API-SIGNATURE"] = this.getSignatureResult(t.params || t.data, n, r, e), t.headers["X-API-SIGNTYPE"] = "md5"; return t } } // 工具类 const Ys4funForumTools = class extends ElementTemplate { constructor() { super() this.tokenKey = "bbs-token"; this.postTitle = "管理员每日签到贴"; this.clientType = "1"; this.gameId = "1"; this.toolsVersions = "V1.10.0"; this.apiConfig = { main: "https://bbs-api.ys4fun.com/bbs-api", post: { getPostListUrl: "/post/list", changeLikeStateUrl: "/post_like/add", getBrowseStateUrl: "/post/get/", addReviewPostUrl: "/reply/add", changeShareStateUrl: "/post_share/add", createPagePostUrl: "/post/add", deletePagePostUrl: "/post/delete_by_id", getDraftPostUrl: "/post_draft/page", cancelLikeStateUrl: "/post_like/cancel" }, dayTask: { url: "/user_coin/my_coin", myLevel: "/user_level/my_level" }, signIn: { url: "/user_sign_in/add" }, emoji: { url: "/emoji/list" }, topics: { url: "/topic/recommend_list/1/10" }, comment: { deleteUrl: "/reply/delete/", userSpaceUrl: "/reply/list_by_user_id" }, user: { address: "/user_address/list", info: "/user/get_user_info" }, commodity: { url: "/commodity/page", buy: "/commodity/buy" } }; this.message = { 100: "您处于未登录状态,请先登录!", 101: "获取页面帖子错误,请刷新页面!", 102: "弥弥尔提醒您:每日任务已完成", 103: "未登录状态: 该消息提示100次!", 104: "操作超时状态: 请重新刷新页面!", 105: "感谢您的登录:祝您生活愉快!", 106: "您当前处已经处于退出登录状态!", 107: "请重新检查您的登录状态!", 108: "获取页面帖子错误:请刷新!", 109: "您未选择草稿箱自定义内容!", 110: "您并未开启该任务功能!", 111: "您并未开启检查用户登录功能!", 112: "查询数据完成,3秒后开始删除!", 113: "您并未开启忽略任务完成进度执行脚本功能!", 114: "您并未设置帖子的标题无法创建帖子!" }; this.error = { 100: "bbs-token is not found", 101: "Get page post error", 102: "Get emoji list error", 103: "Get topic list error", 104: "Get daytask list error" }; this.toolExecutiveInformation = { toolsVersions: this.toolsVersions }; this.recursionQueryDataMap = {}; } // 检查客户端是pc还是手机 checkClientType() { const userAgent = navigator.userAgent.toLowerCase(); const isiPad = userAgent.match(/ipad/i) == "ipad"; const isiPhone = userAgent.match(/iphone os/i) == "iphone os"; const isAndroid = userAgent.match(/android/i) == "android"; if (isAndroid || isiPad || isiPhone) { this.clientType = "2"; }; } // 检查用户登录状态 checkUserLoginState() { const userInfo = this.toolsLocalStorage({ handle: "getItem", key: "userInfo", type: "parse" }); if (!userInfo || typeof userInfo !== 'object' || (typeof userInfo === "object" && Object.keys(userInfo).length == 0) ) { setTimeout(() => { alert(this.message[100]); }, 2000); return !1; } this.userInfo = userInfo; this.toolExecutiveInformation.uid = userInfo.id; return !0; } // 获取key为 bbs-token 的token值 getTokenByCookie() { return new Promise((resolve, reject) => { document.cookie.split(";").forEach(item => { const cookieKey = item.split("=")[0]; const cookieValue = item.split("=")[1]; if (cookieKey.trim() === this.tokenKey) { this.bbsToken = cookieValue; resolve(cookieValue); }; }) reject(new Error(this.error[100])); }); } // 获取页面最新发布的五个帖子数据 getPagePost() { this.postList = []; const url = this.apiConfig.main + this.apiConfig.post.getPostListUrl; const params = { gameId: 1, isFirstPage: true, lastId: 0, size: 5, sort: 1, listType: 1, postType: 0, _t: new Date().getTime() }; return new Promise((resolve, reject) => { fetch(this.convertUrlParams(url, params)) .then(res => res.json()) .then(res => { if (res && res.data && res.data.list) { this.postList = res.data.list; }; resolve(res.data.list); }) .catch(err => reject(new Error(this.error[101]))); }); } // 获取论坛表情包列表 getEmojiList() { this.emojiList = []; const url = this.apiConfig.main + this.apiConfig.emoji.url; const options = { method: "POST", mode: 'cors', headers: { "Authorization": this.bbsToken, "Content-Type": "application/x-www-form-urlencoded;charset=UTF-8", "Client-Type": this.clientType, "_t": new Date().getTime() }, body: "exclude=''" }; return new Promise((resolve, reject) => { fetch(url, options) .then(res => res.json()) .then(res => { if (res && res.data && Array.isArray(res.data)) { res.data.map((item, idx) => { item.emojiList.map(emoji => { if (emoji.groupId !== "1") { this.emojiList.push(emoji); }; }); if (idx === res.data.length - 1) { resolve(res.data); }; }); }; }) .catch(err => reject(new Error(this.error[102]))); }); } // 获取论坛主题标签 getTopicTag() { this.topicList = []; const url = this.apiConfig.main + this.apiConfig.topics.url; const params = { _t: new Date().getTime() }; return new Promise((resolve, reject) => { fetch(this.convertUrlParams(url, params), { method: "GET", mode: 'cors', headers: { "Authorization": this.bbsToken, "Client-Type": this.clientType } }) .then(res => res.json()) .then(res => { if (res && res.data && Array.isArray(res.data)) { this.topicList = res.data; resolve(res.data); }; reject(new Error(this.error[103])); }).catch(err => reject(err)); }); } // 获取勇士论坛弥弥尔频道每日任务列表 getDayTask() { const url = this.apiConfig.main + this.apiConfig.dayTask.myLevel; const params = { gameId: 1, _t: new Date().getTime() }; return new Promise((resolve, reject) => { fetch(this.convertUrlParams(url, params), { method: "GET", mode: 'cors', headers: { "Authorization": this.bbsToken, "Client-Type": this.clientType } }) .then(res => res.json()) .then(res => { if ( res && res.data && res.data.dayTaskList && Array.isArray(res.data.dayTaskList) ) { this.dayTaskList = res.data.dayTaskList; resolve(res.data.dayTaskList); }; throw new Error(this.error[104]); }) .catch(err => reject(err)); }); } // 每日任务:点赞帖子 changePostLikeState(postId = "", listType) { const url = this.apiConfig.main + this.apiConfig.post.changeLikeStateUrl; let stateArray = []; const options = { method: "POST", mode: 'cors', headers: { "Authorization": this.bbsToken, "Content-type": "application/x-www-form-urlencoded;charset=UTF-8", "Client-Type": this.clientType, "_t": new Date().getTime() } }; if (postId && typeof postId === "string") { options.body = "postId=" + postId; return new Promise((resolve, reject) => { fetch(url, options) .then(res => res.json()) .then(res => { console.log({ handle: "重新点赞", post: postId, state: res.message, data: res.data, response: res }); this.cancelLikeState({ _postList: "", isDefaultList: false, rerunParams: postId, isRerun: true, _listType: listType }) .then(response => { if (res.data && response.response && response.response.data && response._listType ) { const listData = this.recursionQueryDataMap[response._listType]["data"]; const filterData = listData.filter(map => map.id !== postId); this.recursionQueryDataMap[response._listType]["data"] = filterData; }; if (!response.response.data) { if (this.toolsStateDataConfig.stateConfig.isOpenCycleCancelLike) { this.changePostLikeState(postId, listType); }; }; }); resolve(res); }) .catch(err => reject(false)); }); }; this.postList.map(post => { options.body = "postId=" + post.id; let promise = new Promise((resolve, reject) => { fetch(url, options) .then(res => res.json()) .then(res => { console.log({ handle: "点赞任务", post: post.id, state: res.message, data: res.data, response: res }) resolve(true) }) .catch(err => reject(false)) }); stateArray.push(promise); }); return new Promise((resolve, reject) => { Promise.all(stateArray) .then(res => { if (this.toolsStateDataConfig.stateConfig.isCancelLike) { this.cancelLikeState({ _postList: "", isDefaultList: true, rerunParams: "", isRerun: false, _listType: "" }); }; resolve(true); }) .catch(err => reject(err)); }); } // 每日任务:每日签到 changeSignInState() { const url = this.apiConfig.main + this.apiConfig.signIn.url; const queryParams = { gameId: this.gameId, _t: new Date().getTime() }; const {headers: signatureHeaders } = SignatureGenerator.getSignaturedParams({params: {...queryParams}}); const params = { method: "GET", mode: 'cors', headers: { ...signatureHeaders, "Authorization": this.bbsToken, "Client-Type": this.clientType, "_t": new Date().getTime() } }; return new Promise((resolve, reject) => { console.log("sigin", this.convertUrlParams(url, queryParams), params); fetch(this.convertUrlParams(url, queryParams), params) .then(res => res.json()) .then(res => { console.log({ handle: "签到任务", post: "", state: res.message, data: res.data, response: res }); resolve(true); }) .catch(err => reject(false)); }); } // 每日任务:浏览帖子 changePostBrowseState() { const url = this.apiConfig.main + this.apiConfig.post.getBrowseStateUrl; let stateArray = []; let timeout = 0; if (this.postList && Array.isArray(this.postList)) { this.postList.map(post => { let promise = new Promise((resolve, reject) => { setTimeout(() => { fetch(url + post.id + "?_t=" + new Date().getTime(), { method: "GET", mode: "cors", headers: { "Authorization": this.bbsToken, "Client-Type": this.clientType } }) .then(res => res.json()) .then(res => { console.log({ handle: "浏览任务", post: post.id, state: res.message, data: res.data, response: res }); resolve(true); }) .catch(err => reject(false)); }, timeout) }); timeout += 500; stateArray.push(promise); }); timeout = null; }; return new Promise((resolve, reject) => { Promise.all(stateArray) .then(res => resolve(true)) .catch(err => reject(err)); }); } // 每日任务:分享帖子 changeShareState() { const url = this.apiConfig.main + this.apiConfig.post.changeShareStateUrl; let stateArray = []; if (this.postList && Array.isArray(this.postList)) { this.postList.map((post, index) => { if (index < 1) { const options = { method: "POST", mode: "cors", headers: { "Content-type": "application/x-www-form-urlencoded;charset=UTF-8", "Authorization": this.bbsToken, "Client-Type": this.clientType }, body: "postId=" + post.id }; let promise = new Promise((resolve, reject) => { fetch(url + "?_t=" + new Date().getTime(), options) .then(res => res.json()) .then(res => { console.log({ handle: "分享任务", post: post.id, state: res.message, data: res.data, response: res }); resolve(true); }) .catch(err => reject(false)); }); stateArray.push(promise); }; }); } return new Promise((resolve, reject) => { Promise.all(stateArray) .then(res => resolve(true)) .catch(err => reject(err)); }); } // 每日任务:发布帖子 changePostReleaseState() { const url = this.apiConfig.main + this.apiConfig.post.createPagePostUrl; const options = { method: 'POST', mode: "cors", headers: { "Authorization": this.bbsToken, 'Content-Type': 'application/json', "Client-Type": this.clientType } }; if (this.toolsStateDataConfig.stateConfig.isPostCustomContent) { const isOpenRandomDraft = this.toolsStateDataConfig.stateConfig.isOpenRandomPostCustomContentList; const cacheList = this.toolsStateDataConfig.customContentConfig.customPostContent.cacheList; const customData = isOpenRandomDraft ? cacheList[Math.floor(Math.random() * cacheList.length)] : this.toolsStateDataConfig.customContentConfig.customPostContent; if (!customData || !customData.hasOwnProperty("title") || (customData.title === "" && customData.id === "")) { alert(this.message[109]); return Promise.reject(this.message[109]); }; if (customData.title === "") { alert(this.message[114]); return Promise.reject(this.message[114]); }; const contentDataMap = this.checkCustomVariableForDraftContent(customData.contentJson); const contentObject = contentDataMap.contentObject; const contentJson = contentDataMap.contentJson; const queryBody = { title: contentObject.title, content: contentObject.content, categoryId: contentObject.categoryId, draftFlag: false, draftId: "0", originalFlag: false, topics: contentObject.topicList.map(item => item.id), mentionsUserIds: contentObject.mentionsUserIds, imageUrls: contentObject.imageUrls, wordNumber: 0, contentJson: contentJson }; if (contentObject.coverUrl) { queryBody.coverUrl = contentObject.coverUrl; queryBody.coverWidth = contentObject.coverWidth; queryBody.coverHeight = contentObject.coverHeight; queryBody.coverName = "弥弥尔"; }; options.body = JSON.stringify(queryBody); } else { const text = "今天是 " + this.getCurrentDate(); const content = `<p>${text}</p>`; const topic = this.topicList[Math.floor(Math.random() * this.topicList.length)].id; const contentJson = JSON.stringify({ type: "doc", content: [{ attrs: { textAlign: "left" }, type: "paragraph", content: [{ type: "text", text: content }] }] }); options.body = JSON.stringify({ title: this.postTitle, content: content, categoryId: "11", draftFlag: false, draftId: "0", originalFlag: false, topics: [topic], coverUrl: "", coverName: "", mentionsUserIds: [], imageUrls: [], wordNumber: 4, contentJson: contentJson }); }; const signatureParams = SignatureGenerator.getSignaturedParams({...options, data: JSON.parse(options.body)}); return new Promise((resolve, reject) => { fetch(url, signatureParams) .then(res => res.json()) .then(res => { console.log({ handle: "发帖任务", post: res.data, state: res.message, data: res.data, response: res }); this.delectPostId = res.data; resolve(res.data); }) .catch(err => reject(err)); }); } // 每日任务:评论帖子 changePostReviewState() { let stateArray = []; let timeout = 0; this.commentList = []; const url = this.apiConfig.main + this.apiConfig.post.addReviewPostUrl; if (this.postList && Array.isArray(this.postList)) { this.postList.map((post, index) => { if (index >= 2) return; const options = { method: 'POST', mode: "cors", headers: { "Authorization": this.bbsToken, 'Content-Type': 'application/json', "Client-Type": this.clientType, "_t": new Date().getTime() } }; if (this.toolsStateDataConfig.stateConfig.isPostCustomComment) { const isOpenRandomDraft = this.toolsStateDataConfig.stateConfig.isOpenRandomCustomCommentListContent; const cacheList = this.toolsStateDataConfig.customContentConfig.customCommentContent.cacheList; const customData = isOpenRandomDraft ? cacheList[Math.floor(Math.random() * cacheList.length)] : this.toolsStateDataConfig.customContentConfig.customCommentContent; if (!customData || !customData.hasOwnProperty("title") || (customData.title === "" && customData.id === "")) { alert(this.message[109]); return; }; const contentObject = JSON.parse(customData.contentJson); options.body = JSON.stringify({ content: contentObject.content, gameId: this.gameId, imageUrls: contentObject.imageUrls, mentionsUserIds: contentObject.mentionsUserIds, postId: post.id }); } else { const template = "<p>管理员不要水贴哦!<span data-emotion=\"{$id}\"><img src=\"{$src}\" class=\"emotion-image\"></span></p>"; const emoji = this.emojiList[Math.floor((Math.random() * this.emojiList.length))]; const content = template.replace("{$id}", emoji.id).replace("{$src}", emoji.url); options.body = JSON.stringify({ content: content, gameId: this.gameId, imageUrls: [], mentionsUserIds: [], postId: post.id }); }; const signatureParams = SignatureGenerator.getSignaturedParams({...options, data: JSON.parse(options.body)}); let promise = new Promise((resolve, reject) => { setTimeout(() => { fetch(url, signatureParams) .then(res => res.json()) .then(res => { console.log({ handle: "评论任务", post: post.id, state: res.message, data: res.data, response: res }); if (res.message === "SUCCESS" && res.data.id) { this.commentList.push(res.data.id); resolve(true); }; }) .catch(err => reject(err)); }, timeout); }); timeout += 500; stateArray.push(promise); }); timeout = null; }; return new Promise((resolve, reject) => { Promise.all(stateArray) .then(() => { resolve(true); }) .catch(err => reject(err)); }); } // 删除创建的帖子函数 deleteMyPagePost(_postId) { const url = this.apiConfig.main + this.apiConfig.post.deletePagePostUrl; const postId = _postId || this.delectPostId; const options = { method: "POST", mode: "cors", headers: { "Authorization": this.bbsToken, 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', "Client-Type": this.clientType, "_t": new Date().getTime() }, body: "id=" + postId }; return new Promise((resolve, reject) => { fetch(url, options) .then(res => res.json()) .then(res => { console.log({ handle: "删除帖子", post: postId, state: res.message, data: res.data, response: res }) resolve(true); }) .catch(err => reject(err)); }); } // 删除评论内容函数 deleteMyComment(_commentIdList) { let stateArray = []; let commentUrlList; const url = this.apiConfig.main + this.apiConfig.comment.deleteUrl; if (_commentIdList && Array.isArray(_commentIdList) && _commentIdList.length > 0) { commentUrlList = _commentIdList.map(item => url + item); } else { commentUrlList = this.commentList ? this.commentList.map(item => url + item) : []; }; const options = { method: "POST", mode: "cors", headers: { "Authorization": this.bbsToken, 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', "Client-Type": this.clientType, "_t": new Date().getTime() } }; commentUrlList.map(commentUrl => { let promise = new Promise((resolve, reject) => { setTimeout(() => { fetch(commentUrl, options) .then(res => res.json()) .then(res => { console.log({ handle: "删除评论", post: commentUrl.match(/(?<=\/)(\d+)/)[0], state: res.message, data: res.data, response: res }); resolve(true); }) .catch(err => reject(err)); }, 1500); }); stateArray.push(promise); }); return new Promise((resolve, reject) => { Promise.all(stateArray) .then(res => resolve(true)) .catch(err => reject(err)); }); } // 撤销帖子点赞状态 cancelLikeState(params) { const { _postList, isDefaultList, rerunParams, isRerun, _listType } = params; let stateArray = []; const postList = Array.isArray(_postList) && _postList.length > 0 ? _postList : isDefaultList ? this.postList ? this.postList : [] : []; if (postList.length === 0 && !rerunParams) return; const url = this.apiConfig.main + this.apiConfig.post.cancelLikeStateUrl; const options = { method: 'POST', mode: "cors", headers: { "Authorization": this.bbsToken, 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8', "Client-Type": this.clientType, "_t": new Date().getTime() } }; if (rerunParams && typeof rerunParams === "string" && isRerun === true) { return new Promise((resolve, reject) => { options.body = "postId=" + rerunParams; fetch(url, options) .then(res => res.json()) .then(res => { console.log({ handle: "重新撤销点赞", post: rerunParams, state: res.message, data: res.data, response: res }); resolve({ post: rerunParams, state: res.message, response: res, _listType: _listType }); }); }); }; postList.map(post => { options.body = "postId=" + post.id; let promise = new Promise((resolve, reject) => { fetch(url, options) .then(res => res.json()) .then(res => { console.log({ handle: "撤销点赞", post: post.id, state: res.message, data: res.data, response: res }); if (res && !res.data) { this.changePostLikeState(post.id, _listType); }; if (res && res.data && _listType) { const listData = this.recursionQueryDataMap[_listType]["data"]; const filterData = listData.filter(map => map.id !== post.id); this.recursionQueryDataMap[_listType]["data"] = filterData; } resolve(true); }) .catch(err => reject(err)); }); stateArray.push(promise); }); return new Promise((resolve, reject) => { Promise.all(stateArray) .then(res => resolve(true)) .catch(err => reject(err)); }); } // 获取草稿箱帖子列表 getDraftsPost() { this.draftPostList = []; const url = this.apiConfig.main + this.apiConfig.post.getDraftPostUrl; const params = { "current": "1", "order": "createDate:asc", "size": "100", "_t": new Date().getTime() }; const options = { method: "GET", mode: "cors", headers: { "Authorization": this.bbsToken, "Client-Type": this.clientType } }; return new Promise((resolve, reject) => { fetch(this.convertUrlParams(url, params), options) .then(res => res.json()) .then(res => { if (res && res.data && res.data.records) { this.draftPostList = res.data.records; }; resolve(res.data.records); }) .catch(err => reject(err)); }); } // 刷新草稿箱列表 refreshDraftPostList() { this.getDraftsPost().then(result => { const $option = $("<option>").attr({ value: "0" }).text("请选择草稿帖子"); $(".draft-list-select").children().remove(); $(".draft-list-select").append($option); const localData = this.toolsLocalStorage({ handle: "getItem", type: "parse" }); const isHasLocalKey = localData && localData.hasOwnProperty("customContentConfig"); let customPostContentId = isHasLocalKey ? localData.customContentConfig.customPostContent.id : ""; let customCommentContentId = isHasLocalKey ? localData.customContentConfig.customCommentContent.id : ""; result.map(item => { const $option1 = $("<option>").attr({ value: item.id }).text(item.id + "-" + item.title); const $option2 = $("<option>").attr({ value: item.id }).text(item.id + "-" + item.title); if (customPostContentId !== "" && customPostContentId === item.id) { $option1.attr("selected", "selected"); }; if (customCommentContentId !== "" && customCommentContentId === item.id) { $option2.attr("selected", "selected"); }; $("#draft-list-select_posted").append($option1); $("#draft-list-select_comment").append($option2); }); }); } // 查询用户个人空间下所有发送的评论 getUserSpaceAllComment() { const url = this.apiConfig.main + this.apiConfig.comment.userSpaceUrl; const params = { size: 10000, userId: this.userInfo.id, _t: new Date().getTime() }; const options = { method: 'GET', mode: "cors", headers: { "Authorization": this.bbsToken, 'Content-Type': 'application/json', "Client-Type": this.clientType } }; return new Promise((resolve, reject) => { fetch(this.convertUrlParams(url, params), options) .then(res => res.json()) .then(res => { if (res.data.size === 0 && res.message === "SUCCESS") { console.log(this.message[112]); console.log("[]"); this.userSpaceAllCommentList = []; resolve([]); }; if (res.data.size !== 0 && res.message === "SUCCESS") { console.log(this.message[112]); console.log(res.data.list); this.userSpaceAllCommentList = res.data.list; resolve(res.data.list); }; }) .catch(err => reject(err)); }) } // 递归查询用户空间下的数据 recursionQueryData(isFirstPage = true, lastId = 0, listType = 0, handler) { if (typeof this.recursionQueryDataMap === "object" && !this.recursionQueryDataMap.hasOwnProperty(listType) && isFirstPage ) { this.recursionQueryDataMap[listType] = {}; this.recursionQueryDataMap[listType].id = listType; this.recursionQueryDataMap[listType].state = false; this.recursionQueryDataMap[listType].data = []; this.recursionQueryDataMap[listType].timer = null; }; if (this.recursionQueryDataMap[listType].state) { if (handler === "deleteMyPagePost") { if (!this.recursionQueryDataMap[listType].timer) { this.recursionQueryDataMap[listType].timer = setTimeout(() => { this.recursionQueryDataMap[listType]["data"].map(itemMap => { this.deleteMyPagePost(itemMap.id); }); clearTimeout(this.recursionQueryDataMap[listType].timer); this.recursionQueryDataMap[listType].timer = null; }, 3000); }; return; }; if (handler === "cancelLikeState") { if (!this.recursionQueryDataMap[listType].timer) { this.recursionQueryDataMap[listType].timer = setTimeout(() => { console.log("执行数据列表:", this.recursionQueryDataMap[listType]["data"]) this.cancelLikeState({ _postList: this.recursionQueryDataMap[listType]["data"], isDefaultList: false, rerunParams: "", isRerun: false, _listType: listType }); clearTimeout(this.recursionQueryDataMap[listType].timer); this.recursionQueryDataMap[listType].timer = null; }, 3000); }; return; }; return; }; const url = this.apiConfig.main + this.apiConfig.post.getPostListUrl; const params = { gameId: this.gameId, isFirstPage: isFirstPage, lastId: lastId, size: 10, listType: listType, postType: 0, userId: this.userInfo.id, _t: new Date().getTime() }; const options = { method: 'GET', mode: "cors", headers: { "Authorization": this.bbsToken, 'Content-Type': 'application/json', "Client-Type": this.clientType } }; fetch(this.convertUrlParams(url, params), options) .then(res => res.json()) .then(res => { console.log(res.data.lastId, res); if (res.data && res.data.list) { res.data.list.forEach(item => { this.recursionQueryDataMap[listType]["data"].push(item); }); }; if (res.data.lastId === 0 || res.data.lastId === "0") { console.log(this.message[112]); console.log("查询数据列表:", this.recursionQueryDataMap[listType]["data"]); this.recursionQueryDataMap[listType]["state"] = true; this.recursionQueryData(false, 0, listType, handler); }; if (res.data.lastId !== 0 || res.data.lastId !== "0") { setTimeout(() => { this.recursionQueryData(false, res.data.lastId, listType, handler); }, 1050); }; }) .catch(err => console.log(err)); } // 获取用户设置的收货地址 getUserAddressList() { const url = this.apiConfig.main + this.apiConfig.user.address; const params = { _t: new Date().getTime() } const options = { method: 'GET', mode: "cors", headers: { "Authorization": this.bbsToken, "Client-Type": this.clientType } }; return new Promise((resolve, reject) => { fetch(this.convertUrlParams(url, params), options) .then(res => res.json()) .then(res => { if (res && !Array.isArray(res.data) || res.data.length === 0) { this.userAddressInfoMap = null; resolve(res.data); return; }; const userDefaultAddress = res.data.find(addressMap => { return addressMap.defaultFlag === true; }); if (!userDefaultAddress || userDefaultAddress === undefined) { this.userAddressInfoMap = undefined; resolve(res.data); return; } const { id, name, city, province, district, address, phone } = userDefaultAddress; const addressStr = `[${id}] ${name}-${city}${province}${district}${address}-${phone}`; this.userAddressInfoMap = { id: id, name: name, city: city, province: province, district: district, address: address, phone: phone, name: name, addressStr: addressStr }; resolve(res.data); }) .catch(err => reject(err)); }); } // 获取论坛商品列表 getCommodityList() { const url = this.apiConfig.main + this.apiConfig.commodity.url; const params = { current: 1, gameId: 1, size: 50, _t: new Date().getTime() }; const options = { method: 'GET', mode: "cors", headers: { "Authorization": this.bbsToken, "Client-Type": this.clientType } }; return new Promise((resolve, reject) => { fetch(this.convertUrlParams(url, params), options) .then(res => res.json()) .then(res => { if (res.data && res.data.records) { resolve(res.data.records); } else { reject(res); }; }) .catch(err => reject(err)); }); } // 抢购请求函数 snapUpQuery(params, timeout) { const url = this.apiConfig.main + this.apiConfig.commodity.buy; const options = { method: 'POST', mode: "cors", headers: { "Authorization": this.bbsToken, "Client-Type": this.clientType, "Content-type": "application/x-www-form-urlencoded;charset=UTF-8", "_t": new Date().getTime() }, body: params }; return new Promise((resolve, reject) => { setTimeout(() => { fetch(url, options) .then(res => res.json()) .then(res => { if (res && res.message === "SUCCESS") { resolve(res.message); } else { reject(res.message); }; }) .catch(err => reject(err)); }, timeout) }); } // 检查草稿内容中是否有自定义的变量 checkCustomVariableForDraftContent(contentJson) { const contentObject = JSON.parse(contentJson); const currentDate = this.getCurrentDate().toString(); this.setUserInfoCache(); const regxConfigList = [ { id: 0, reg: new RegExp(/\$CURRENTDATE\$/g), key: "当前日期xxxx年xx月xx日", value: currentDate.replace(/(\d{4})(\d{2})(\d{2})/, "$1年$2月$3日") }, { id: 1, reg: new RegExp(/\$MYGAMEUID\$/g), key: "我的游戏uid", value: this.userInfoCacheMap.gameUid }, { id: 2, reg: new RegExp(/\$MYGAMELEVEL\$/g), key: "我的游戏等级", value: this.userInfoCacheMap.gameLevel }, { id: 3, reg: new RegExp(/\$MYGAMENICKNAME\$/g), key: "我的游戏昵称", value: this.userInfoCacheMap.gameNickName }, { id: 4, reg: new RegExp(/\$MYGAMEDAYCOUNT\$/g), key: "我的游戏签到天数", value: this.userInfoCacheMap.gameDayCount }, { id: 5, reg: new RegExp(/\$MYFORUMUID\$/g), key: "我的论坛uid", value: this.userInfoCacheMap.bbsId }, { id: 6, reg: new RegExp(/\$MYFORUMCOIN\$/g), key: "我的论坛弥尔币数量", value: this.userInfoCacheMap.bbsCoin }, { id: 7, reg: new RegExp(/\$MYFORUMLEVEL\$/g), key: "我的论坛等级", value: this.userInfoCacheMap.bbsLevel }, { id: 8, reg: new RegExp(/\$MYFORUMNICKNAME\$/g), key: "我的论坛昵称", value: this.userInfoCacheMap.bbsNickName } ]; regxConfigList.forEach(regxConfigMap => { // title if (contentObject.title.match(regxConfigMap.reg)) { contentObject.title = contentObject.title.replaceAll( regxConfigMap.reg, regxConfigMap.value ); }; // content if (contentObject.content.match(regxConfigMap.reg)) { contentObject.content = contentObject.content.replaceAll( regxConfigMap.reg, regxConfigMap.value ); }; }); return { contentObject: contentObject, contentJson: JSON.stringify(contentObject) }; } // 将 url字符串和 params 对象转换为 fetch get 请求的 url 参数形式 convertUrlParams(url, params) { let paramsArray = []; if (!params || typeof params !== "object") return; Object.keys(params).forEach(key => { paramsArray.push(key + "=" + params[key]); }); return url + "?" + paramsArray.join("&"); } // 转换时间戳函数 convertDateByTimestamp(timestamp) { const date = new Date(timestamp); let year = date.getFullYear(); let month = date.getMonth() + 1; let day = date.getDate(); let hour = date.getHours(); let minute = date.getMinutes(); let second = date.getSeconds(); month = month < 10 ? "0" + month : month; day = day < 10 ? "0" + day : day; hour = hour < 10 ? "0" + hour : hour; minute = minute < 10 ? "0" + minute : minute; second = second < 10 ? "0" + second : second; return `${year}-${month}-${day} ${hour}:${minute}:${second}`; } // 获取当前日期年月日数字 YYYYMMDD getCurrentDate() { const date = new Date(); const year = date.getFullYear(); const month = date.getMonth() + 1; const day = date.getDate(); const times = `${year}${month < 10 ? "0" + month : month}${day < 10 ? "0" + day : day}`; return Number(times); } // 检查用户信息配置对象 checkUserInfoPropertyAndReturn(key1, key2) { const localUserInfoMap = this.toolsLocalStorage({ handle: "getItem", key: "userInfo", type: "parse" }); this.userInfo = localUserInfoMap; if (!this.userInfo || this.userInfo === null || this.userInfo === undefined || typeof this.userInfo !== "object" ) { console.log("userInfo is not defined"); return; }; if (typeof this.userInfo === "object" && Object.keys(this.userInfo).length === 0 ) { console.log("userInfo is nil object"); return; }; const isHasKey1 = key1 && this.userInfo.hasOwnProperty(key1) ? true : false; const isHasKey2 = isHasKey1 && key2 && this.userInfo[key1].hasOwnProperty(key2) ? true : false; return isHasKey1 && !key2 ? this.userInfo[key1] : isHasKey2 ? this.userInfo[key1][key2] : ""; } // 设置用户信息内容 setUserInfo() { const $userInfoUl = $(".ys4fun-tools-userInfo-list"); this.setUserInfoCache(); const { bbsId, bbsNickName, bbsLevel, bbsCoin, bbsUserCreateDate, gameServer, gameUid, gameNickName, gameLevel, gameUserCreateDate } = this.userInfoCacheMap; const userAddress = this.userAddressInfoMap ? this.userAddressInfoMap.addressStr : ""; const userInfoList = [ { id: 0, name: "论坛id", value: bbsId }, { id: 1, name: "论坛昵称", value: bbsNickName }, { id: 2, name: "论坛等级", value: bbsLevel }, { id: 3, name: "弥尔币数量", value: bbsCoin }, { id: 4, name: "用户创建日期", value: bbsUserCreateDate }, { id: 5, name: "游戏服务器", value: gameServer }, { id: 6, name: "游戏uid", value: gameUid }, { id: 7, name: "游戏昵称", value: gameNickName }, { id: 8, name: "游戏等级", value: gameLevel }, { id: 9, name: "游戏创建日期", value: gameUserCreateDate }, { id: 10, name: "我的地址", value: userAddress } ]; userInfoList.forEach(userInfoMap => { $userInfoUl.find(`li[data-index=${userInfoMap.id}] .userInfo-item-box__text`).text(userInfoMap.value); }); } // 设置 userInfoCache 数据 setUserInfoCache() { const bbsCreateDateTimestamp = this.checkUserInfoPropertyAndReturn("createDate"); const gameCreateDateTimestamp = this.checkUserInfoPropertyAndReturn("gameAetherGazerUserVO", "createDate"); const bbsUserCreateDate = bbsCreateDateTimestamp ? this.convertDateByTimestamp(bbsCreateDateTimestamp) + "(服务器时间)" : "未获取到论坛用户创建日期"; const gameUserCreateDate = gameCreateDateTimestamp ? this.convertDateByTimestamp(gameCreateDateTimestamp) + "(服务器时间)" : "未获取到游戏角色创建日期"; this.userInfoCacheMap = { bbsId: this.checkUserInfoPropertyAndReturn("id"), bbsNickName: this.checkUserInfoPropertyAndReturn("nickname"), bbsLevel: this.checkUserInfoPropertyAndReturn("gameUserCardVO", "level"), bbsCoin: this.checkUserInfoPropertyAndReturn("coin"), gameServer: this.checkUserInfoPropertyAndReturn("gameAetherGazerUserVO", "channelName"), gameUid: this.checkUserInfoPropertyAndReturn("gameAetherGazerUserVO", "uid"), gameNickName: this.checkUserInfoPropertyAndReturn("gameAetherGazerUserVO", "nickName"), gameLevel: this.checkUserInfoPropertyAndReturn("gameAetherGazerUserVO", "level"), gameDayCount: this.checkUserInfoPropertyAndReturn("gameAetherGazerUserVO", "gameDayCount"), bbsUserCreateDate: bbsUserCreateDate, gameUserCreateDate: gameUserCreateDate }; } // 检查论坛每日任务完成状态 checkDayTaskState() { console.log(this.dayTaskList); let stateArray = []; const date = this.getCurrentDate(); const stateConfig = this.toolsStateDataConfig.stateConfig; this.toolExecutiveInformation.date = date; this.dayTaskList.map(task => { switch (task.type) { case 1: // SignIn type=1 count=1 exp=6 coin=60 if (stateConfig["isIgnoreCheckState"] || task.percentage !== 100) { if (stateConfig["isRunSignInTask"]) { stateArray.push(this.changeSignInState()); }; } else { stateArray.push(Promise.resolve(true)); }; break; case 2: // Like type=2 count=5 exp=10 coin=50 if (stateConfig["isIgnoreCheckState"] || task.percentage !== 100) { if (stateConfig["isRunLikeTask"]) { this.changePostLikeState() .then(res => { stateArray.push(Promise.resolve(true)); if (this.toolsStateDataConfig.stateConfig.isCancelLike) { this.cancelLikeState({ _postList: "", isDefaultList: true, rerunParams: "", isRerun: false, _listType: "" }); }; }) .catch(err => console.log(err)) }; } else { stateArray.push(Promise.resolve(true)); }; break; case 3: // Browse type=3 count=5 exp=10 coin=50 if (stateConfig["isIgnoreCheckState"] || task.percentage !== 100) { if (stateConfig["isRunBrowseTask"]) { stateArray.push(this.changePostBrowseState()); }; } else { stateArray.push(Promise.resolve(true)); }; break; case 4: // Release type=4 count=1 exp=8 coin=0 if (stateConfig["isIgnoreCheckState"] || task.percentage !== 100) { if (stateConfig["isRunPostedTask"]) { this.changePostReleaseState() .then(res => { stateArray.push(Promise.resolve(true)); if (stateConfig["isDeletePost"]) { this.deleteMyPagePost(); }; }) }; // Share type=12 count=1 exp=0 coin=20 if (stateConfig["isRunShareTask"]) { // This task does not in daytask stateArray.push(this.changeShareState()); }; } else { stateArray.push(Promise.resolve(true)); }; break; case 5: // Review type=5 count=2 exp=6 coin=0 if (stateConfig["isIgnoreCheckState"] || task.percentage !== 100) { if (stateConfig["isRunCommentTask"]) { this.changePostReviewState().then(res => { stateArray.push(Promise.resolve(true)); if (stateConfig["isDeleteComment"]) { this.deleteMyComment(); }; }); }; } else { stateArray.push(Promise.resolve(true)); }; break; default: stateArray.push(Promise.resolve(task)); break; } }) Promise.all(stateArray).then(res => { setTimeout(() => { this.toolExecutiveInformation.state = true; this.saveDataToLocalStorage(); alert(this.message[102]); }, 2000); }).catch(err => { this.toolExecutiveInformation.state = false; this.saveDataToLocalStorage(); console.log(err); }) } // 获取最新的用户信息数据 getNewestUserInfoData() { const url = this.apiConfig.main + this.apiConfig.user.info; const params = { userId: this.userInfo.id, gameId: this.gameId, _t: new Date().getTime() }; const options = { method: 'GET', mode: "cors", headers: { "authorization": this.bbsToken, 'Content-Type': 'application/json', "Client-Type": this.clientType } }; return new Promise((resolve, reject) => { fetch(this.convertUrlParams(url, params), options) .then(res => res.json()) .then(res => { if (res.data && res.message === "SUCCESS") { this.toolsLocalStorage({ handle: "setItem", key: "userInfo", data: res.data, type: "stringify" }); this.setUserInfo(); } resolve(res) }) .catch(err => reject(err)); }) } // 初始化函数:获取相关请求数据 init(isRunGetDayTask = false) { const isGetToken = this.getTokenByCookie(); const isGetNewestUserInfoData = this.getNewestUserInfoData(); const isGetPagePost = this.getPagePost(); const isGetEmojiList = this.getEmojiList(); const isGetTopicList = this.getTopicTag(); const isGetUserAddressList = this.getUserAddressList(); return new Promise((resolve, reject) => { Promise.all([ isGetNewestUserInfoData, isGetToken, isGetPagePost, isGetEmojiList, isGetTopicList, isGetUserAddressList ]) .then(result => { if (isRunGetDayTask) { this.getDayTask().then(res => { resolve(); }); } else { resolve(); }; }) .catch(error => reject(error)); }); } // 工具处理本地存储的函数 toolsLocalStorage({ handle, key, data, type, uid }) { const localFunction = window.localStorage; const userId = this.userInfoCacheMap ? this.userInfoCacheMap.bbsId : this.userInfo ? this.userInfo.id : uid ? uid : ""; key = key ? key : userId ? "Ys4funForumToolsGlobalConfigMap_User_" + userId : "Ys4funForumToolsGlobalConfigMap"; // getItem if (handle === "getItem" && key) { return type === "parse" ? JSON.parse(localFunction[handle](key)) : localFunction[handle](key); }; // setItem if (handle === "setItem" && key && data) { return type === "stringify" ? localFunction[handle](key, JSON.stringify(data)) : localFunction[handle](key, data); }; // removeItem if (handle === "removeItem" && key) { return localFunction[handle](key); }; } // 保存工具全局状态等数据到本地存储中 saveDataToLocalStorage() { const _userInfo = this.toolsLocalStorage({ handle: "getItem", key: "userInfo", type: "parse" }); const localData = this.toolsLocalStorage({ handle: "getItem", type: "parse", uid: _userInfo }); const nowDate = this.getCurrentDate(); const executiveInformation = localData ? localData.hasOwnProperty("executiveInformation") ? localData.executiveInformation.hasOwnProperty("state") ? localData.executiveInformation : this.toolExecutiveInformation : this.toolExecutiveInformation : this.toolExecutiveInformation; if (executiveInformation && executiveInformation.hasOwnProperty("date")) { if (executiveInformation.date < nowDate) { executiveInformation.date = nowDate; }; } else { executiveInformation.date = nowDate; }; const saveData = { stateConfig: this.toolsStateDataConfig.stateConfig, customContentConfig: this.toolsStateDataConfig.customContentConfig, executiveInformation: executiveInformation }; this.toolsLocalStorage({ handle: "setItem", data: saveData, type: "stringify" }); } // 保存工具面板位置信息到本地存储中 saveToolPanelPositionToLocalStorage() { const localData = this.toolsLocalStorage({ handle: "getItem", type: "parse" }); const saveData = { ...localData, toolPanelPosition: this.toolPanelPosition }; this.toolsLocalStorage({ handle: "setItem", data: saveData, type: "stringify" }); } // 添加工具样式 addStyle() { const css = GM_getResourceText("css") GM_addStyle(css); } // 添加工具主面板节点 addToolsPanel() { const localData = this.toolsLocalStorage({ handle: "getItem", type: "parse" }); const position = (localData && localData.hasOwnProperty("toolPanelPosition")) ? localData.toolPanelPosition : ""; const toolsPanel = this.createToolsPanel(position); const containerPanel = this.createToolsContainerPanel(); toolsPanel.append(containerPanel); $("body").prepend(toolsPanel); if (this.clientType === "2") { const $container = $(".ys4fun-tools-container"); if ($container.length > 0) { $(".ys4fun-tools-container").css({ "width": "90vw", "height": "90vh" }); $(".ys4fun-tools-setting-container-item__title").css({ "font-size": "xx-small" }); }; }; } // 添加外部 ionicons 图标脚本 addScript() { const scriptElementList = this.createToolsIconScriptTag(); scriptElementList.forEach($script => { $("body").append($script); }); } // 脚本入口:执行脚本函数 executeScript() { this.checkClientType(); const isLogin = this.checkUserLoginState(); const isCheckLogin = this.toolsStateDataConfig.stateConfig.isGlobalCheckLogin; if (!isLogin && isCheckLogin) { let timerCount = 0; // 这个定时器用来检测用户登录状态的 let timer = setInterval(() => { timerCount++; const userInfo = this.toolsLocalStorage({ handle: "getItem", key: "userInfo", type: "parse" }); if ((userInfo === null || typeof userInfo !== 'object' || (typeof userInfo === "object" && Object.keys(userInfo).length === 0)) && timerCount <= 100 ) { console.log(this.message[103]); if (timerCount === 100) { alert(this.message[104]); clearInterval(timer); timer = null; return; }; } else { alert(this.message[105]); clearInterval(timer); timer = null; window.location.reload(); }; }, 1000) } else { this.init().then(res => { this.addStyle(); this.addScript(); this.addToolsPanel(); this.setUserInfo(); this.refreshDraftPostList(); }); const __userInfo = this.toolsLocalStorage({ handle: "getItem", key: "userInfo", type: "parse" }); const __localData = this.toolsLocalStorage({ handle: "getItem", type: "parse", uid: __userInfo.id || "" }); const isClearCache = __localData && __localData.hasOwnProperty("executiveInformation") ? __localData.executiveInformation.hasOwnProperty("toolsVersions") ? __localData.executiveInformation.toolsVersions !== this.toolsVersions ? false : true : false : false; if (!isClearCache) { this.toolsLocalStorage({ handle: "removeItem" }); this.saveDataToLocalStorage(); setTimeout(() => { window.location.reload(); }, 1500); }; if (this.toolsStateDataConfig.stateConfig.isGlobalCheckLogout) { let timeCount = 0; // 这个定时器用来检测用户退出登录的 let timer = setInterval(() => { timeCount++; if (timeCount === 1000) { clearInterval(timer); timer = null; timeCount = null; return; }; const userInfo = this.toolsLocalStorage({ handle: "getItem", key: "userInfo", type: "parse" }); if (userInfo === null || typeof userInfo !== 'object' || (typeof userInfo === "object" && Object.keys(userInfo).length === 0) ) { clearInterval(timer); timer = null; console.log(this.message[106]); window.location.reload(); }; }, 5000); }; if (this.toolsStateDataConfig.stateConfig.isGlobalDayTask) { const _userInfo = this.toolsLocalStorage({ handle: "getItem", key: "userInfo", type: "parse" }); const localData = this.toolsLocalStorage({ handle: "getItem", type: "parse", uid: _userInfo.id || "" }); const isHasLocalKey = localData !== null && typeof localData === "object" && Object.keys(localData).length !== 0 ? localData.hasOwnProperty("executiveInformation") : ""; const toolState = isHasLocalKey ? localData.executiveInformation : ""; const date = this.getCurrentDate(); const isHasProperty = ["date", "state", "uid"].map(item => { return toolState.hasOwnProperty(item); }); if (!toolState || (!isHasProperty[0] || toolState.date < date) || (!isHasProperty[1] || toolState.state === false) || toolState.uid !== _userInfo.id ) { this.init(true).then(res => { this.checkDayTaskState(); }).catch(error => { if (error.message === this.error[100]) { alert(`${this.message[107]}\n${error.message}`); return; }; if (error.message === this.error[101]) { alert(`${this.message[108]}\n${error.message}`); return; }; alert(error.message); }); }; }; }; } } const ys4funForumTools = new Ys4funForumTools(); ys4funForumTools.executeScript(); })();