您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
最终幻想14道具仓库批量领取
当前为
// ==UserScript== // @name FF14道具仓库批量领取 // @description 最终幻想14道具仓库批量领取 // @namespace http://greasyfork.icu/users/129402 // @match https://qu.sdo.com/* // @grant GM_setValue // @grant GM_getValue // @version 2.0.0 // @license GNU General Public License v3.0 or later // @compatible chrome // @compatible firefox // @compatible opera // @compatible safari // @run-at document-end // ==/UserScript== /* eslint-disable no-magic-numbers */ /* global moment, GM_setValue, GM_getValue */ "use strict"; (() => { $.ajax({ cache: true, dataType: "script", url: "https://qu.sdo.com/static/lib/moment-2.24.0.min.js", }); const button = $("<div/>"); button.css({ "background-color": "#fff", border: "gray solid 1px", "border-radius": "4px", bottom: "1rem", cursor: "pointer", "font-size": "14px", "font-weight": "700", "letter-spacing": ".5em", "line-height": "1.5", padding: ".5em 0 .5em .5em", position: "fixed", right: "1rem", width: "3em", "z-index": 73, }); button.text("批量领取"); button.appendTo("body"); button.on("click", () => { const container = $("<div/>"); container.css({ "background-color": "#fff", border: "gray solid 1px", "border-radius": "4px", bottom: "2rem", color: "#303133", "font-size": "14px", left: "calc(50vw - 600px)", "line-height": "1.5", position: "fixed", top: "2rem", width: "1200px", "z-index": 137, }); container.appendTo("body"); const closeButton = $("<button type=\"button\" aria-label=\"Close\" class=\"el-dialog__headerbtn\"><i class=\"el-dialog__close el-icon el-icon-close\"></i></button>"); closeButton.on("click", () => { if (closeButton.is(":not(:disabled)")) { container.remove(); } }); container.append(closeButton); const title = $("<div/>"); title.text("批量领取道具"); title.css({ "border-bottom": "gray solid 1px", "font-size": "20px", margin: ".5rem auto", "text-align": "center", width: "1100px", }); container.append(title); const chooseContainer = $("<div/>"); chooseContainer.text("选择仓库:"); chooseContainer.css({ "border-bottom": "gray solid 1px", left: "50px", margin: ".5rem auto", "padding-bottom": ".5rem", position: "sticky", "text-align": "center", top: ".5rem", width: "1100px", }); const paidWarehouseInput = $("<input/>"); paidWarehouseInput.attr({ id: "3a755830-cfd0-4999-a79b-9dcf62e6669f", type: "radio", }).css("margin", "0 .5rem"); const freeWarehouseInput = $("<input/>"); freeWarehouseInput.attr({ id: "005c8d3a-4594-4e7b-af4d-865498126a36", type: "radio", }).css("margin", "0 .5rem"); const paidWarehouseInputLabel = $("<label/>"); paidWarehouseInputLabel.attr("for", "3a755830-cfd0-4999-a79b-9dcf62e6669f").text("购买仓库").css("margin-right", ".5rem"); const freeWarehouseInputLabel = $("<label/>"); freeWarehouseInputLabel.attr("for", "3a755830-cfd0-4999-a79b-9dcf62e6669f").text("奖励仓库").css("margin-right", ".5rem"); paidWarehouseInput.data({ otherInput: freeWarehouseInput, sourceType: 0, }); freeWarehouseInput.data({ otherInput: paidWarehouseInput, sourceType: 1, }); chooseContainer.append(paidWarehouseInput).append(paidWarehouseInputLabel).append("·").append(freeWarehouseInput).append(freeWarehouseInputLabel); const submitContainer = $("<span/>"); submitContainer.css({ "border-left": "gray solid 1px", "margin-left": ".5rem", padding: "0 .5rem", }); chooseContainer.append(submitContainer); container.append(chooseContainer); const resultCotainer = $("<div/>"); resultCotainer.css({ margin: "0 auto", padding: ".5rem", "text-align": "center", }); container.append(resultCotainer); const count = $("<span/>"); count.text("道具数量:--"); submitContainer.append(count); const submitButton = $("<button/>"); submitButton.text("开始批量领取").css("margin", "0 .5rem"); submitContainer.append(submitButton); const selectAllButton = $("<button/>"); selectAllButton.text("全选"); selectAllButton.on("click", () => { if (selectAllButton.is(":not(:disabled)")) { resultCotainer.find("input").prop("checked", true); } }); submitContainer.append(selectAllButton); const selectNoneButton = $("<button/>"); selectNoneButton.text("全不选"); selectNoneButton.on("click", () => { if (selectNoneButton.is(":not(:disabled)")) { resultCotainer.find("input").prop("checked", false); } }); submitContainer.append(selectNoneButton); paidWarehouseInput.add(freeWarehouseInput).on("change", async ({ target }) => { const self = $(target); self.data("otherInput").prop("checked", false); resultCotainer.empty().text("加载中……"); try { const apiResult = await $.ajax({ data: { _: Math.random, appId: 100001900, keyword: "", order: 0, page: 1, pageSize: 100, sourceType: self.data("sourceType"), status: 0, }, type: "GET", url: "https://sqmallservice.u.sdo.com/api/us/gameItem/list", xhrFields: { withCredentials: true, }, }); resultCotainer.empty(); if (apiResult.resultCode !== 0) { resultCotainer.text(`请求发生错误!错误信息:[${apiResult.resultCode}] ${apiResult.resultMsg}`); return; } const { propsList, totalCount } = apiResult.data; if (totalCount > 100) { resultCotainer.append("<div>仓库中包含超过100件道具,为了避免出现问题,脚本只支持前100件道具的批量领取,请领取完前100件后刷新页面继续。</div>"); } const resultTable = $("<table/>"); resultTable.css("border-collapse", "collapse"); resultTable.append("<thead><tr><th>序号</th><th>名称</th><th>购买日期</th><th>是否批量领取</th></tr></thead><tbody></tbody>"); resultCotainer.append($("<div/>").css({ margin: "auto", width: "fit-content", }).append(resultTable)); const resultTableBody = resultTable.find("tbody"); propsList.forEach(({ propsWarehouseId, productName, purchaseDate, skuId, sourceType }, _index) => { const index = _index + 1; const row = $("<tr/>"); row.html('<td style="border: gray solid 1px; padding: .5rem;"></td>'.repeat(4)); row.find("td").eq(0).text(index); const textCol = row.find("td").eq(1); textCol.text(`${productName} `); const link = $("<a/>"); link.css({ color:"#3273dc", "text-decoration":"underline", }).attr({ href: `https://qu.sdo.com/product-detail/${skuId}`, target: "_blank", }).text("[商品页面](外链)"); textCol.append(link); row.find("td").eq(2).text(moment(purchaseDate).format("YYYY年M月D日HH点mm分")); const input = $("<input/>"); input.attr("type", "checkbox").data({ propsWarehouseId, sourceType }); row.find("td").eq(3).append(input); resultTableBody.append(row); }); count.text(`道具数量:${propsList.length}`); } catch (e) { resultCotainer.html(`<div style="text-align: center;">发生网络错误!错误信息:${e}</div>`); } }); submitButton.on("click", async () => { if (submitButton.is(":not(:disabled)")) { if (resultCotainer.find("input").length === 0) { alert("尚未加载数据!"); return; } const selected = resultCotainer.find("input:checked").toArray().map((ele) => $(ele).data()); if (selected.length === 0) { alert("尚未选择道具!"); return; } const choosed = { free: selected.filter(({ sourceType }) => sourceType === 1).map(({ propsWarehouseId }) => propsWarehouseId), paid: selected.filter(({ sourceType }) => sourceType === 0).map(({ propsWarehouseId }) => propsWarehouseId), }; let confirmText = ""; if (choosed.paid.length > 0) { confirmText += `${choosed.paid.length}个购买仓库的道具 和 `; } if (choosed.free.length > 0) { confirmText += `${choosed.free.length}个奖励仓库的道具`; } confirmText = confirmText.replace(/ 和 $/, ""); if (!confirm(`你选择了 ${confirmText} ,是否确认批量领取?`)) { return; } submitButton.add(selectAllButton).add(selectNoneButton).add(closeButton).add(resultCotainer.find("input")).attr("disabled", "disabled"); const characterSelectorContainer = $("<div/>"); characterSelectorContainer.css({ "background-color": "#fff", border: "gray solid 1px", "border-radius": "4px", "font-size": "14px", left: "calc(50vw - 300px)", "line-height": "1.5", padding: "25px 25px 30px", position: "fixed", "text-align": "center", top: "15vh", width: "600px", "z-index": 713, }); const area = $("<div/>"); area.css("margin", ".5rem 0"); const areaSelect = $("<select/>"); areaSelect.attr({ disabled: "disabled", id: "b5970252-6c7e-4603-928f-ae80b7ed1409", }).html('<option selected="selected">加载中……</option>'); const areaLabel = $("<label/>"); areaLabel.attr("for", "b5970252-6c7e-4603-928f-ae80b7ed1409").text("选择游戏大区:"); area.append(areaLabel).append(areaSelect).appendTo(characterSelectorContainer); const character = $("<div/>"); character.css("margin", ".5rem 0"); const characterSelect = $("<select/>"); characterSelect.attr({ disabled: "disabled", id: "f601bc1a-95c8-42ce-81b3-0081bec56f58", }).html('<option selected="selected">请先选择大区……</option>'); const characterLabel = $("<label/>"); characterLabel.attr("for", "f601bc1a-95c8-42ce-81b3-0081bec56f58").text("选择游戏角色:"); character.append(characterLabel).append(characterSelect).appendTo(characterSelectorContainer); const buttonRow = $("<div/>"); buttonRow.css("margin", ".5rem 0"); const confirmButton = $("<button/>"); confirmButton.css({ "background-color": "#ce0f30", border: "1px solid #ce0f30", "border-radius": "4px", "box-sizing": "border-box", color: "#FFF", cursor: "pointer", display: "inline-block", "font-family": "inherit", "font-size": "14px", "font-weight": "500", "line-height": "1", margin: "0", outline: "0", overflow: "visible", padding: "12px 20px", "text-align": "center", "text-transform": "none", transition: ".1s", "white-space": "nowrap", }).text("确认批量领取在此角色"); const cancelButton = $("<button/>"); cancelButton.css({ "background-color": "rgb(51, 51, 51)", border: "1px solid rgb(51, 51, 51)", "border-radius": "4px", "box-sizing": "border-box", color: "#FFF", cursor: "pointer", display: "inline-block", "font-family": "inherit", "font-size": "14px", "font-weight": "500", "line-height": "1", margin: "0 0 0 10px", outline: "0", overflow: "visible", padding: "12px 20px", "text-align": "center", "text-transform": "none", transition: ".1s", "white-space": "nowrap", }).text("取消"); cancelButton.on("click", () => { submitButton.add(selectAllButton).add(selectNoneButton).add(closeButton).add(resultCotainer.find("input")).removeAttr("disabled"); characterSelectorContainer.remove(); }); buttonRow.append(confirmButton).append(cancelButton).appendTo(characterSelectorContainer); characterSelectorContainer.appendTo("body"); try { const areaResult = await $.ajax({ data: { _: Math.random, appId: 100001900, }, type: "GET", url: "https://sqmallservice.u.sdo.com/api/us/accountInfo/getArea", xhrFields: { withCredentials: true, }, }); if (areaResult.resultCode !== 0) { alert(`请求发生错误!错误信息:[${areaResult.resultCode}] ${areaResult.resultMsg}`); cancelButton.click(); return; } const areas = JSON.parse(areaResult.data); const defaultArea = GM_getValue("areaSelected", "-1"); areaSelect.removeAttr("disabled").html(defaultArea === "-1" ? '<option value="-1">请选择大区……</option>' : ""); areas.forEach(({ areaId, areaName }) => { areaSelect.append(`<option value="${areaId}-${areaName}">${areaName}</option>`); }); areaSelect.on("change", async () => { const areaId = areaSelect.val(); if (areaId === "-1") { characterSelect.html('<option selected="selected">请先选择大区……</option>'); return; } try { const characterResult = await $.ajax({ data: { _: Math.random, appId: 100001900, areaId: areaId.replace(/-.+$/, ""), }, type: "GET", url: "https://sqmallservice.u.sdo.com/api/us/accountInfo/getCharacter", xhrFields: { withCredentials: true, }, }); if (characterResult.resultCode !== 0) { alert(`请求发生错误!错误信息:[${characterResult.resultCode}] ${characterResult.resultMsg}`); cancelButton.click(); return; } const defaultCharacter = GM_getValue("characterSelected", "-1"); const characters = characterResult.data.roleInfos; characterSelect.removeAttr("disabled").html(defaultCharacter === "-1" ? '<option value="-1">请选择角色……</option>' : ""); characters.forEach(({ characterId, groupId, groupName, roleName }) => { characterSelect.append(`<option value="${groupId}-${groupName}-${characterId}-${roleName}">[${groupName}]${roleName}</option>`); }); characterSelect.val(defaultCharacter); } catch (e) { alert(`发生网络错误!错误信息:${e}`); cancelButton.click(); return; } }); areaSelect.val(defaultArea).change(); confirmButton.on("click", async () => { const characterSelected = characterSelect.val(); const areaSelected = areaSelect.val(); if (!/([^-]+)-([^-]+)/.test(areaSelected)) { alert("请选择大区!"); return; } if (!/([^-]+)-([^-]+)-([^-]+)-([^-]+)/.test(characterSelected)) { alert("请选择角色!"); return; } const [, areaId, areaName] = Array.from(areaSelected.match(/([^-]+)-([^-]+)/)); const [, groupId, groupName, characterId, roleName] = Array.from(characterSelected.match(/([^-]+)-([^-]+)-([^-]+)-([^-]+)/)); if (!confirm(`确定要将 ${confirmText} 领取到 [${groupName}]${roleName} 上吗?`)) { return; } GM_setValue("characterSelected", characterSelected); GM_setValue("areaSelected", areaSelected); submitButton.add(selectAllButton).add(selectNoneButton).add(closeButton).remove().off(); let successCount = 0; let failedCount = 0; const target = choosed.paid.concat(choosed.free); count.text(`成功:0 失败:0 / ${target.length}`); let startFlag = true; for (const propsWarehouseId of target) { if (startFlag) { startFlag = false; await new Promise((res) => setTimeout(res, 1500)); } try { const apiResult = await $.ajax({ data: { _: Math.random(), appId: "100001900", areaId, areaName, characterId, groupId, groupName, propsWarehouseId, roleName, }, type: "GET", url: "https://sqmallservice.u.sdo.com/api/us/gameItem/spend", xhrFields: { withCredentials: true, }, }); if (apiResult.resultCode === 0 && apiResult.data.success) { successCount++; } else { failedCount++; } } catch { failedCount++; } count.text(`成功:${successCount} 失败:${failedCount} / ${target.length}`); } alert(`批量领取完成!共成功 ${successCount} 个,失败 ${failedCount} 个!`); location.reload(false); }); } catch (e) { alert(`发生网络错误!错误信息:${e}`); cancelButton.click(); return; } } }); }); })();