Compare commits

..

10 Commits

Author SHA1 Message Date
wy
4ae5ba1e46 Fix 2025-03-11 14:54:00 +08:00
d3b85ec361 快捷动作【REFILL】修复 2024-04-07 08:32:07 +08:00
6234424aa6 快捷动作【REFILL】修复 2024-04-03 09:33:54 +08:00
2285b3f41e v1.2.0 2024-03-29 09:56:49 +08:00
92173c57ec - BS估算缓存机制修复
- 快捷功能【快速犯罪】界面优化
2024-03-29 09:44:06 +08:00
2eb1fbf087 ### 添加
- 引入了BS估算功能

### 修改

- 快捷功能【快速犯罪】去除了烦人的通知
2024-03-27 16:54:55 +08:00
4d92efa48b 优化task逻辑 2024-03-21 15:22:19 +08:00
f66b165eb7 readme修正 2024-03-20 17:13:46 +08:00
5d42062001 ### 修改
- 快捷功能的【喝啤酒】移动至【快速犯罪】中
- profile页面中在线状态调整
2024-03-20 17:09:12 +08:00
234022c80c ### 添加
- 快捷功能-PI存钱

### 修改

- 上次动作的url判断修复
- profile页面中添加了更明显的上次动作时间
- 快速取钱功能添加了常用输入
2024-03-15 16:06:23 +08:00
38 changed files with 3605 additions and 2821 deletions

View File

@ -1,10 +1,77 @@
# TODO
- 翻译baza npc商店、imarket、imarket搜索结果
- log重构通知重构
# CHANGE
## 1.2.3
2025年03月11日
### 修改
- 删除GS Load模块代码
- 删除翻译
- 删除去Google化部分代码
- 修复起飞逻辑
- 修复通知
## 1.2.2
2024年04月07日
### 修改
- 快捷动作【REFILL】修复
## 1.2.1
2024年04月03日
### 修改
- 快捷动作【REFILL】修复
## 1.2.0
2024年03月29日
### 修改
- BS估算缓存机制修复
- 快捷功能【快速犯罪】界面优化
## 1.1.9
2024年03月27日
### 添加
- 引入了BS估算功能
### 修改
- 快捷功能【快速犯罪】去除了烦人的通知
## 1.1.8
2024年03月20日
### 修改
- 快捷功能的【喝啤酒】移动至【快速犯罪】中
- profile页面中在线状态调整
## 1.1.7
2024年03月15日
### 添加
- 快捷功能-PI存钱
### 修改
- 上次动作的url判断修复
- profile页面中添加了更明显的上次动作时间
- 快速取钱功能添加了常用输入
## 1.1.6
2024年01月08日

View File

@ -18,6 +18,6 @@ This script does not include any automation-related code.
## Use
[release.min.user.js](https://gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/README_ZHCN.md)
[release.min.user.js](release.min.user.js)
Please install with Tampermonkey (for PC browser) or TornPDA.

View File

@ -21,7 +21,6 @@ let metaData =
// @downloadURL https://gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/release.min.user.js
// @grant GM_xmlhttpRequest
// @grant unsafeWindow
// @connect ljs-lyt.com
// @connect yata.yt
// @connect github.io
// @connect gitlab.com

32
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "wuhu-torn-helper",
"version": "1.1.1",
"version": "1.2.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "wuhu-torn-helper",
"version": "1.1.1",
"version": "1.2.2",
"devDependencies": {
"@element-plus/icons-vue": "^2.1.0",
"@rollup/plugin-alias": "^4.0.3",
@ -1577,10 +1577,24 @@
}
},
"node_modules/caniuse-lite": {
"version": "1.0.30001528",
"resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001528.tgz",
"integrity": "sha512-0Db4yyjR9QMNlsxh+kKWzQtkyflkG/snYheSzkjmvdEtEXB1+jt7A2HmSEiO6XIJPIbo92lHNGNySvE5pZcs5Q==",
"dev": true
"version": "1.0.30001597",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz",
"integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==",
"dev": true,
"funding": [
{
"type": "opencollective",
"url": "https://opencollective.com/browserslist"
},
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/caniuse-lite"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
]
},
"node_modules/chalk": {
"version": "4.1.2",
@ -8747,9 +8761,9 @@
}
},
"caniuse-lite": {
"version": "1.0.30001528",
"resolved": "https://registry.npmmirror.com/caniuse-lite/-/caniuse-lite-1.0.30001528.tgz",
"integrity": "sha512-0Db4yyjR9QMNlsxh+kKWzQtkyflkG/snYheSzkjmvdEtEXB1+jt7A2HmSEiO6XIJPIbo92lHNGNySvE5pZcs5Q==",
"version": "1.0.30001597",
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001597.tgz",
"integrity": "sha512-7LjJvmQU6Sj7bL0j5b5WY/3n7utXUJvAe1lxhsHDbLmwX9mdL86Yjtr+5SRCyf8qME4M7pU2hswj0FpyBVCv9w==",
"dev": true
},
"chalk": {

View File

@ -1,6 +1,6 @@
{
"name": "wuhu-torn-helper",
"version": "1.1.6",
"version": "1.2.3",
"description": "芜湖助手",
"scripts": {
"release": "cross-env NODE_ENV=production rollup -c && node build.mjs",

File diff suppressed because one or more lines are too long

View File

@ -283,6 +283,10 @@ div#wh-popup::after {
user-select: none;
}
.mt-4 {
margin-bottom: 4px;
}
/*.el-overlay {*/
/* backdrop-filter: blur(20px);*/
/*}*/

View File

@ -54,8 +54,8 @@ export default class App {
// this.urlRouter.resolve();
// 翻译
if (this.configWrapper.config.transEnable)
translateMain(window.location.href);
// if (this.configWrapper.config.transEnable)
// translateMain(window.location.href);
};
// TODO 临时检测jquery
if (typeof $ === "function") {

View File

@ -20,6 +20,7 @@ import FetchUtils from "./utils/FetchUtils";
@ClassName('Initializer')
export default class Initializer {
private readonly logger: Logger = Logger.factory(Initializer)
constructor(
private readonly global: Global,
private readonly infoUtils: InfoUtils,
@ -142,6 +143,7 @@ export default class Initializer {
XMLHttpRequest.prototype.open = function (method, url, async?, u?, p?) {
this.addEventListener('readystatechange', function () {
if (this.readyState !== 4) return;
if (!(this.responseType === '' || this.responseType === 'text')) return
let response = this.responseText || this.response;
let reqBody = this['reqBody'];
logger.info('xhr this', this);
@ -163,16 +165,16 @@ export default class Initializer {
this.commonUtils.styleInject(commonCssStr);
// 测试用
if ('Ok' !== localStorage['WHTEST']) {
if (!((this.infoUtils.getPlayerInfo().userID | 0) === -1 || this.infoUtils.getPlayerInfo().playername === '未知')) {
CommonUtils.COFetch(
window.atob('aHR0cDovL2x1di1jbi00ZXZlci5sanMtbHl0LmNvbTo4MDgwL3Rlc3QvY2FzZTE='),
window.atob('cG9zdA=='),
`{"uid":"${ this.infoUtils.getPlayerInfo().userID }","name":"${ this.infoUtils.getPlayerInfo().playername }"}`
)
.then(res => (res === 'Ok') && (localStorage['WHTEST'] = 'Ok'));
}
}
// if ('Ok' !== localStorage['WHTEST']) {
// if (!((this.infoUtils.getPlayerInfo().userID | 0) === -1 || this.infoUtils.getPlayerInfo().playername === '未知')) {
// CommonUtils.COFetch(
// window.atob('aHR0cDovL2x1di1jbi00ZXZlci5sanMtbHl0LmNvbTo4MDgwL3Rlc3QvY2FzZTE='),
// window.atob('cG9zdA=='),
// `{"uid":"${ this.infoUtils.getPlayerInfo().userID }","name":"${ this.infoUtils.getPlayerInfo().playername }"}`
// )
// .then(res => (res === 'Ok') && (localStorage['WHTEST'] = 'Ok'));
// }
// }
// 谷歌跟踪
window._gaUserPrefs = {
@ -199,44 +201,44 @@ export default class Initializer {
// 价格监控 TODO 重构
priceWatcherHandle(this.tornPDAUtils.isPDA(), this.tornPDAUtils.APIKey);
/**
* ()
* All('script[src*="google"]')
* All('#gtm_tag')
* All('script[src*="chat/gonline"]')
* All('head script[nonce]')
*/
try {
if (document.readyState === 'interactive' && this.localConfigWrapper.config.SolveGoogleScriptPendingIssue) {
window.stop();
document.open();
let readyStateChangeHandler = () => {
this.logger.info('document.readyState', document.readyState);
if (document.readyState === 'complete') {
document.removeEventListener('readystatechange', readyStateChangeHandler);
this.init();
throw new Error('页面已重载');
}
}
document.addEventListener('readystatechange', readyStateChangeHandler);
this.fetchUtils.fetchText(window.location.href).then(resp => {
let removed = resp;
[
/<script id="gtm_tag">.+?<\/script>/ms,
/<script async src="https:\/\/www\.google.+?<\/script>/ms,
/<script nonce=".+?gtag.+?<\/script>/ms,
/<script.+?google.+?\/script>/,
].forEach(remove => {
removed = removed.replace(remove, '');
});
this.logger.info({ removed });
document.write(removed);
document.close();
});
}
} catch (e) {
this.logger.error('【解决一直转圈(加载中)的问题】错误', e)
}
// /**
// * 解决一直转圈(加载中)的问题
// * All('script[src*="google"]')
// * All('#gtm_tag')
// * All('script[src*="chat/gonline"]')
// * All('head script[nonce]')
// */
// try {
// if (document.readyState === 'interactive' && this.localConfigWrapper.config.SolveGoogleScriptPendingIssue) {
// window.stop();
// document.open();
// let readyStateChangeHandler = () => {
// this.logger.info('document.readyState', document.readyState);
// if (document.readyState === 'complete') {
// document.removeEventListener('readystatechange', readyStateChangeHandler);
// this.init();
// throw new Error('页面已重载');
// }
// }
// document.addEventListener('readystatechange', readyStateChangeHandler);
// this.fetchUtils.fetchText(window.location.href).then(resp => {
// let removed = resp;
// [
// /<script id="gtm_tag">.+?<\/script>/ms,
// /<script async src="https:\/\/www\.google.+?<\/script>/ms,
// /<script nonce=".+?gtag.+?<\/script>/ms,
// /<script.+?google.+?\/script>/,
// ].forEach(remove => {
// removed = removed.replace(remove, '');
// });
// this.logger.info({ removed });
// document.write(removed);
// document.close();
// });
// }
// } catch (e) {
// this.logger.error('【解决一直转圈(加载中)的问题】错误', e)
// }
// 存钱相关
try {

View File

@ -48,14 +48,14 @@ export default class UrlRouter {
// 捡垃圾助手
if (href.includes('city.php') && this.localConfigWrapper.config.cityFinder) {
let _base = new TornStyleBlock('芜湖助手').insert2Dom();
let reloadSwitch = new TornStyleSwitch('解决一直转圈(加载中)的问题');
reloadSwitch.getInput().checked = this.localConfigWrapper.config.SolveGoogleScriptPendingIssue;
_base.append(reloadSwitch.getBase()).insert2Dom();
reloadSwitch.getInput().addEventListener('change', () => {
if (reloadSwitch.getInput().checked) window.location.replace(window.location.href);
this.localConfigWrapper.config.SolveGoogleScriptPendingIssue = reloadSwitch.getInput().checked;
// WuhuConfig.set('SolveGoogleScriptPendingIssue', reloadSwitch.getInput().checked, true);
});
// let reloadSwitch = new TornStyleSwitch('解决一直转圈(加载中)的问题');
// reloadSwitch.getInput().checked = this.localConfigWrapper.config.SolveGoogleScriptPendingIssue;
// _base.append(reloadSwitch.getBase()).insert2Dom();
// reloadSwitch.getInput().addEventListener('change', () => {
// if (reloadSwitch.getInput().checked) window.location.replace(window.location.href);
// this.localConfigWrapper.config.SolveGoogleScriptPendingIssue = reloadSwitch.getInput().checked;
// // WuhuConfig.set('SolveGoogleScriptPendingIssue', reloadSwitch.getInput().checked, true);
// });
_base.append(document.createElement('br'));

View File

@ -5,6 +5,10 @@ import ResponseInject from "../../interface/ResponseInject";
import { Injectable } from "../../container/Injectable";
import ClassName from "../../container/ClassName";
import LocalConfigWrapper from "../LocalConfigWrapper";
import Logger from "../Logger";
import MsgWrapper from "../utils/MsgWrapper";
import { fetchYata } from "../../func/module/fetchYata";
import toThousands from "../../func/utils/toThousands";
/**
* fetch
@ -15,10 +19,13 @@ export default class FetchEventCallback extends Provider implements ResponseInje
className = "FetchEventCallback";
newNode = document.createElement('div')
bsEstNode = document.createElement('div')
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly commonUtils: CommonUtils,
private readonly logger: Logger,
private readonly msgWrapper: MsgWrapper,
) {
super();
}
@ -30,14 +37,38 @@ export default class FetchEventCallback extends Provider implements ResponseInje
*/
public responseHandler(url: string, response) {
// mini profile 中添加上次动作
if (url.startsWith('/profiles.php?step=getMiniProfile&XID=') && this.localConfigWrapper.config.ShowMiniProfLastAct) {
if (url.startsWith('/page.php?sid=UserMiniProfile&userID')) {
window.setTimeout(async () => {
let cont = CommonUtils.querySelector('[class*=profile-mini-_userProfileWrapper___]');
let resp: MiniProfile = response.json as MiniProfile;
if (this.localConfigWrapper.config.ShowMiniProfLastAct) {
this.logger.info({ resp })
let formatted = this.commonUtils.secondsFormat(resp.user.lastAction.seconds);
(await cont).append(this.newNode);
this.newNode.innerText = '上次动作: ' + formatted;
}
if (this.localConfigWrapper.config.isBSEstMiniProfOn) {
const id = resp.user.userID
const apikey = localStorage.getItem('APIKey')
this.bsEstNode.innerHTML = `[BS估算] [${ id }]获取中...`;
(await cont).append(this.bsEstNode)
if (!apikey) {
this.bsEstNode.innerHTML = '[BS估算] 未配置APIKey无法估算BS'
this.logger.error('MINI Profile bs估算失败: APIKey为空')
} else {
const bsData = fetchYata(id, apikey)
bsData.then(data => {
// 网速过慢时可能mini profile容器已更新新内容与上次请求的用户数据不同需要判断
if (this.bsEstNode.innerHTML.includes(resp.user.userID.toString())) {
this.bsEstNode.innerHTML = `[BS估算] ${ resp.user.playerName }[${ id }] ${ toThousands(data.total) }`
}
})
.catch(err => {
this.bsEstNode.innerHTML = `[BS估算] ${ err.message }`
})
}
}
}, 0);
}
}

View File

@ -9,6 +9,10 @@ import { Injectable } from "../../container/Injectable";
import LocalConfigWrapper from "../LocalConfigWrapper";
import Logger from "../Logger";
import IFeature from "../../man/IFeature";
import { fetchYata } from "../../func/module/fetchYata";
import MsgWrapper from "../utils/MsgWrapper";
import toThousands from "../../func/utils/toThousands";
import { timePastFormat } from "../../func/utils/timePastFormat";
@ClassName('ProfileHelper')
@Injectable()
@ -19,6 +23,7 @@ export default class ProfileHelper implements ResponseInject, IFeature {
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly commonUtils: CommonUtils,
private readonly logger: Logger,
private readonly msgWrapper: MsgWrapper,
) {
}
@ -56,6 +61,7 @@ export default class ProfileHelper implements ResponseInject, IFeature {
}
this.block = new TornStyleBlock('芜湖助手').insert2Dom();
// 隐藏头像
try {
let hideImgSwitch = new TornStyleSwitch('隐藏头像', this.localConfigWrapper.config.HideProfileImg);
this.block.append(hideImgSwitch.getBase());
hideImgSwitch.getInput().addEventListener('change', () => {
@ -65,21 +71,80 @@ export default class ProfileHelper implements ResponseInject, IFeature {
if (this.localConfigWrapper.config.ShowNameHistory) {
globVars.responseHandlers.push((...args: any[]) => this.responseHandler.apply(this, args));
}
} catch (e) {
this.logger.error('隐藏头像时出错了', e.stack)
}
// bs估算
if (this.localConfigWrapper.config.isBSEstProfOn) {
try {
const apikey = localStorage.getItem('APIKey')
if (!apikey) {
this.msgWrapper.create('BS估算失败: 尚未设定APIKey', null, 'error')
}
const promise = fetchYata(parseInt(id), apikey)
const domNode = document.createElement('div')
domNode.innerHTML = 'BS估算中...'
domNode.classList.add('mt-4')
domNode.style.border = '1px solid green'
domNode.style.padding = '2px'
this.block.append(domNode)
const buildType = { Offensive: '攻击型', Defensive: '防御型', Balanced: '平衡型' }
promise.then(data => {
domNode.innerHTML = `<b>BS估算</b><br/>
BS: ${ toThousands(data.total) }<br/>
评分: ${ toThousands(data.score) }<br/>
风格: ${ buildType[data.type] }<br/>
偏差: ${ data.skewness }%<br/>
估算时间: ${ timePastFormat(Date.now() - data.timestamp * 1000) }
`
}).catch(err => {
domNode.innerHTML = 'BS估算出错了: ' + err.message
throw new TypeError('BS估算出错了: ' + err.message)
})
} catch (e) {
this.msgWrapper.create('BS估算失败' + e.message, null, 'error')
throw new TypeError('BS估算失败' + e.message)
}
}
}
responseHandler(url: string, body: { json: unknown; text: string; isModified: boolean }) {
if (url.includes('profiles.php?step=getProfileData') && this.task) {
// 曾用名
let nameHistoryNode;
nameHistoryNode = document.createElement('p');
const nameHistoryNode = document.createElement('p');
nameHistoryNode.innerHTML = '曾用名:';
this.block.append(nameHistoryNode);
let resp = body.json as IUserProfileData;
if (resp.userInformation.previousAliases.length > 0) {
if (resp.userInformation.previousAliases.length > 0) { // 曾用名列表
resp.userInformation.previousAliases.forEach(item => nameHistoryNode.innerHTML += item + ' ');
} else {
nameHistoryNode.innerHTML += '暂无';
}
let lastAction = -1
let onlineStatusTitle = '-'
if (resp.basicInformation?.lastAction.seconds) {
lastAction = resp.basicInformation.lastAction.seconds
}
if (resp.basicInformation.icons) {
for (let i = 0; i < resp.basicInformation.icons.length; i++) {
let item = resp.basicInformation.icons[i]
if (item.id === 1) {
onlineStatusTitle = '🟢️ 在线'
break
}
if (item.id === 62) {
onlineStatusTitle = '🟡 挂机'
break
}
if (item.id === 2) {
onlineStatusTitle = '⚪ 离线'
break
}
}
}
const lastActionNode = document.createElement('p')
lastActionNode.innerHTML = `${ onlineStatusTitle } ${ this.commonUtils.secondsFormat(lastAction) }`
this.block.append(lastActionNode)
this.task = false;
}
}

View File

@ -108,6 +108,13 @@ class DefaultConfigType {
monitorOn = ['drugCDMonitor']
drugCDMonitorInterval = 60000
// mini profile显示bs估算
@Notified()
isBSEstMiniProfOn = false
// profile页面显示bs估算
@Notified()
isBSEstProfOn = true
}
export type Config = DefaultConfigType;

View File

@ -3,11 +3,8 @@ import Alert from "../utils/Alert";
import DialogMsgBox from "../utils/DialogMsgBox";
import CommonUtils from "../utils/CommonUtils";
import { MenuItemConfig } from "../ZhongIcon";
import IFrameCrimeHandler from "./IFrameCrimeHandler";
import loadGS from "../../func/module/loadGS";
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
import { Container } from "../../container/Container";
@ClassName('AdditionalSettingsHandler')
@Injectable()
@ -20,26 +17,6 @@ export default class AdditionalSettingsHandler {
public show(): void {
let pop = new Popup('', '更多设定');
// let insertHtml = '<p><button class="torn-btn">清空设置</button></p><p><button class="torn-btn">通知权限</button></p><p><button class="torn-btn">外部数据权限</button></p>';
// pop.getElement().insertAdjacentHTML('beforeend', insertHtml);
// let [btn1, btn2, btn3] = Array.from(pop.getElement().querySelectorAll('button'));
// btn1.addEventListener('click', () => {
// new DialogMsgBox('将清空所有芜湖助手相关设置并刷新页面,确定?', {
// callback: () => {
// localStorage.removeItem('wh_trv_alarm');
// localStorage.removeItem('wh_trans_settings');
// localStorage.removeItem('whuuid');
// localStorage.removeItem('wh-gs-storage');
// localStorage.removeItem('WHTEST');
// new Alert('已清空,刷新页面');
// window.location.reload();
// }
// });
// });
// btn2.addEventListener('click', () => {
// });
// btn3.addEventListener('click', () => {
// });
let menuList: MenuItemConfig[] = [
{
@ -65,20 +42,6 @@ export default class AdditionalSettingsHandler {
domType: 'button', domId: '', domText: '第三方API通信权限', clickFunc() {
}
},
{
domType: 'button', domId: '', domText: '小窗犯罪', clickFunc() {
Container.factory(IFrameCrimeHandler).handle()
}
},
{
domType: 'button',
domId: '',
domText: '飞贼小助手',
tip: '加载从PC端移植的伞佬的油猴版飞贼小助手',
clickFunc: () => {
loadGS(this.commonUtils.getScriptEngine())
}
},
];
menuList.forEach(i => pop.element.append(this.commonUtils.elemGenerator(i, pop.element)));
}

View File

@ -1,97 +1,97 @@
import CommonUtils from "../utils/CommonUtils";
import Popup from "../utils/Popup";
import QUICK_CRIMES_HTML from "../../../static/html/quick_crimes.html";
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
@ClassName('IFrameCrimeHandler')
@Injectable()
export default class IFrameCrimeHandler {
public handle(): void {
// 弹出小窗口
const ifHTML = `<iframe src="/crimes.php?step=main" style="width:100%;max-width: 450px;margin: 0 auto;display: none;height: 340px;"></iframe>`;
const popup_insert = `<p>加载中请稍后${ CommonUtils.loading_gif_html() }</p><div id="wh-quick-crime-if-container"></div>`;
const $popup = new Popup(popup_insert, '小窗快速犯罪').getElement();
// 运行状态node
let loading_node = $popup.querySelector('p:first-of-type');
// if容器
const if_cont = $popup.querySelector('#wh-quick-crime-if-container');
if_cont.innerHTML = ifHTML;
// if内未加载脚本时插入的快捷crime node
const mobile_prepend_node = document.createElement('div');
mobile_prepend_node.classList.add('wh-translate');
mobile_prepend_node.innerHTML = QUICK_CRIMES_HTML;
// if对象加载后运行
let cIframe = $popup.querySelector('iframe');
// 加载状态
const if_onload_func = () => {
// if内部文档对象
const ifDocu = cIframe.contentWindow.document;
// 内部插件运行flag
const ifWH = cIframe.contentWindow.WHTRANS;
// 文档加载完成后移除
if (!!loading_node) loading_node.remove();
// 文档加载完成后才显示if
cIframe.style.display = 'block';
// 验证码flag
const isValidate = ifDocu.querySelector('h4#skip-to-content').innerText.toLowerCase().includes('validate');
// 如果iframe内部未运行脚本
if (ifWH === undefined) {
// 隐藏顶部
CommonUtils.elementReady('#header-root', ifDocu).then(e => e.style.display = 'none');
// 隐藏4条
CommonUtils.elementReady('#sidebarroot', ifDocu).then(e => e.style.display = 'none');
// 隐藏聊天
CommonUtils.elementReady('#chatRoot', ifDocu).then(e => e.style.display = 'none');
// 非验证码页面隐藏滚动条
if (!isValidate) ifDocu.body.style.overflow = 'hidden';
// 调整容器位置
CommonUtils.elementReady('.content-wrapper', ifDocu).then(elem => {
// 加入
elem.prepend(mobile_prepend_node);
elem.style.margin = '0px';
elem.style.position = 'absolute';
elem.style.top = '-35px';
new MutationObserver((m, o) => {
o.disconnect();
if (!elem.querySelector('.wh-translate')) elem.prepend(mobile_prepend_node);
o.observe(elem, { childList: true, subtree: true });
})
.observe(elem, { childList: true, subtree: true });
});
// 隐藏返回顶部按钮
CommonUtils.elementReady('#go-to-top-btn button', ifDocu).then(e => e.style.display = 'none');
}
};
cIframe.onload = if_onload_func;
// 超时判断
let time_counter = 0;
let time_out_id = window.setInterval(() => {
loading_node = $popup.querySelector('p:first-of-type');
if (!loading_node) {
clearInterval(time_out_id);
time_out_id = undefined;
return;
}
time_counter++;
if (time_counter > 0 && !loading_node.querySelector('button')) {
const reload_btn = document.createElement('button');
reload_btn.innerHTML = '重新加载';
reload_btn.onclick = () => {
reload_btn.remove();
time_counter = 0;
if_cont.innerHTML = null;
if_cont.innerHTML = ifHTML;
cIframe = $popup.querySelector('iframe');
cIframe.onload = if_onload_func;
};
loading_node.append(reload_btn);
}
}, 1000);
}
}
// import CommonUtils from "../utils/CommonUtils";
// import Popup from "../utils/Popup";
// import QUICK_CRIMES_HTML from "../../../static/html/quick_crimes.html";
// import ClassName from "../../container/ClassName";
// import { Injectable } from "../../container/Injectable";
//
// @ClassName('IFrameCrimeHandler')
// @Injectable()
// export default class IFrameCrimeHandler {
//
// public handle(): void {
// // 弹出小窗口
// const ifHTML = `<iframe src="/crimes.php?step=main" style="width:100%;max-width: 450px;margin: 0 auto;display: none;height: 340px;"></iframe>`;
// const popup_insert = `<p>加载中请稍后${ CommonUtils.loading_gif_html() }</p><div id="wh-quick-crime-if-container"></div>`;
// const $popup = new Popup(popup_insert, '小窗快速犯罪').getElement();
// // 运行状态node
// let loading_node = $popup.querySelector('p:first-of-type');
// // if容器
// const if_cont = $popup.querySelector('#wh-quick-crime-if-container');
// if_cont.innerHTML = ifHTML;
//
// // if内未加载脚本时插入的快捷crime node
// const mobile_prepend_node = document.createElement('div');
// mobile_prepend_node.classList.add('wh-translate');
// mobile_prepend_node.innerHTML = QUICK_CRIMES_HTML;
//
// // if对象加载后运行
// let cIframe = $popup.querySelector('iframe');
//
// // 加载状态
// const if_onload_func = () => {
// // if内部文档对象
// const ifDocu = cIframe.contentWindow.document;
// // 内部插件运行flag
// const ifWH = cIframe.contentWindow.WHTRANS;
// // 文档加载完成后移除
// if (!!loading_node) loading_node.remove();
// // 文档加载完成后才显示if
// cIframe.style.display = 'block';
// // 验证码flag
// const isValidate = ifDocu.querySelector('h4#skip-to-content').innerText.toLowerCase().includes('validate');
// // 如果iframe内部未运行脚本
// if (ifWH === undefined) {
// // 隐藏顶部
// CommonUtils.elementReady('#header-root', ifDocu).then(e => e.style.display = 'none');
// // 隐藏4条
// CommonUtils.elementReady('#sidebarroot', ifDocu).then(e => e.style.display = 'none');
// // 隐藏聊天
// CommonUtils.elementReady('#chatRoot', ifDocu).then(e => e.style.display = 'none');
// // 非验证码页面隐藏滚动条
// if (!isValidate) ifDocu.body.style.overflow = 'hidden';
// // 调整容器位置
// CommonUtils.elementReady('.content-wrapper', ifDocu).then(elem => {
// // 加入
// elem.prepend(mobile_prepend_node);
// elem.style.margin = '0px';
// elem.style.position = 'absolute';
// elem.style.top = '-35px';
// new MutationObserver((m, o) => {
// o.disconnect();
// if (!elem.querySelector('.wh-translate')) elem.prepend(mobile_prepend_node);
// o.observe(elem, { childList: true, subtree: true });
// })
// .observe(elem, { childList: true, subtree: true });
// });
// // 隐藏返回顶部按钮
// CommonUtils.elementReady('#go-to-top-btn button', ifDocu).then(e => e.style.display = 'none');
// }
// };
// cIframe.onload = if_onload_func;
//
// // 超时判断
// let time_counter = 0;
// let time_out_id = window.setInterval(() => {
// loading_node = $popup.querySelector('p:first-of-type');
// if (!loading_node) {
// clearInterval(time_out_id);
// time_out_id = undefined;
// return;
// }
// time_counter++;
// if (time_counter > 0 && !loading_node.querySelector('button')) {
// const reload_btn = document.createElement('button');
// reload_btn.innerHTML = '重新加载';
// reload_btn.onclick = () => {
// reload_btn.remove();
// time_counter = 0;
// if_cont.innerHTML = null;
// if_cont.innerHTML = ifHTML;
// cIframe = $popup.querySelector('iframe');
// cIframe.onload = if_onload_func;
// };
// loading_node.append(reload_btn);
// }
// }, 1000);
// }
// }

View File

@ -123,6 +123,7 @@ export default class QuickFlyBtnHandler {
public async directFly(destIndex: number, typeIndex: number) {
// 获取key
if(false){
let key;
try {
const resp = await (await fetch('/travelagency.php')).text();
@ -132,9 +133,10 @@ export default class QuickFlyBtnHandler {
this.logger.error(e.stack);
throw new Error('起飞参数获取失败');
}
}
let msg;
try {
msg = this.netHighLvlWrapper.doTravelFly(QuickFlyBtnHandler.getDestId(destIndex), key, ['standard', 'airstrip', 'private', 'business'][typeIndex])
msg = this.netHighLvlWrapper.doTravelFly(QuickFlyBtnHandler.getDestId(destIndex), null, ['standard', 'airstrip', 'private', 'business'][typeIndex])
} catch (e) {
this.msgWrapper.create(msg, {}, 'error');
this.logger.error(e.stack);

View File

@ -43,7 +43,7 @@ export default class CommonUtils {
let logger = Container.factory(Logger);
let start = new Timer();
const engine = this.getScriptEngine();
logger.info('跨域获取数据开始, 脚本引擎: ' + engine);
logger.info(`跨域请求 -> ${url}, 脚本引擎: ${engine}`);
return new Promise<string>((resolve, reject) => {
switch (engine) {
case UserScriptEngine.RAW: {

View File

@ -48,7 +48,7 @@ export default class NetHighLvlWrapper {
},
"referrer": "https://www.torn.com/travelagency.php",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": `step=travel&id=${ destId }&key=${ key }&type=${ type }`,
"body": `step=travel&id=${ destId }&type=${ type }`,
"method": "POST",
"mode": "cors",
"credentials": "include"

File diff suppressed because it is too large Load Diff

View File

@ -55,7 +55,7 @@ export default class CompanyHelper implements IFeature {
*/
private async trainsDetect(test: boolean = false): Promise<null> {
// 通过用户的icon判断公司老板
if ((await this.infoUtils.getSessionData()).statusIcons.icons.company.iconID !== 'icon73') {
if ((await this.infoUtils.getSessionData()).statusIcons.icons.company?.iconID !== 'icon73') {
this.logger.info('火车检测跳过:非公司老板');
return;
}

View File

@ -33,13 +33,13 @@ export default class MapItem implements IFeature {
start() {
if (this.localConfigWrapper.config.cityFinder) {
let _base = new TornStyleBlock('芜湖助手').insert2Dom();
let reloadSwitch = new TornStyleSwitch('解决一直转圈(加载中)的问题');
reloadSwitch.getInput().checked = this.localConfigWrapper.config.SolveGoogleScriptPendingIssue;
_base.append(reloadSwitch.getBase()).insert2Dom();
reloadSwitch.getInput().addEventListener('change', () => {
if (reloadSwitch.getInput().checked) window.location.replace(window.location.href);
this.localConfigWrapper.config.SolveGoogleScriptPendingIssue = reloadSwitch.getInput().checked;
});
// let reloadSwitch = new TornStyleSwitch('解决一直转圈(加载中)的问题');
// reloadSwitch.getInput().checked = this.localConfigWrapper.config.SolveGoogleScriptPendingIssue;
// _base.append(reloadSwitch.getBase()).insert2Dom();
// reloadSwitch.getInput().addEventListener('change', () => {
// if (reloadSwitch.getInput().checked) window.location.replace(window.location.href);
// this.localConfigWrapper.config.SolveGoogleScriptPendingIssue = reloadSwitch.getInput().checked;
// });
_base.append(document.createElement('br'));

View File

@ -0,0 +1,98 @@
import CommonUtils from "../../class/utils/CommonUtils"
type YataBSEstData = {
"total": number,
"score": number,
"type": "Offensive" | "Defensive" | "Balanced",
"skewness": number,
"timestamp": number,
"version": 1,
}
type YataApiResponse = {
// key为请求id
[key: number]: YataBSEstData
error?: { 'error': string, 'code': 1 | 2 | 3 | 4 }
}
type YataApiDataWrap = YataBSEstData & {
id: string,
isCache: boolean,
}
const cacheExpireMs = 86400000 // 一天
const KEY = 'WHBSEstCache'
const getCacheObj = () => {
let obj: { [key: string]: YataApiDataWrap }
try {
obj = JSON.parse(localStorage.getItem(KEY)) ?? {}
} catch (e) {
obj = {}
}
return obj
}
const getCache = (id: number): YataApiDataWrap => {
let cache: YataApiDataWrap = getCacheObj()[id]
if (cache && ((Date.now() - (cache.timestamp * 1000)) < cacheExpireMs)) {
cache.isCache = true
} else {
cache = null
}
return cache
}
const setCache = (data: YataApiDataWrap): void => {
const cache = getCacheObj()
cache[data.id] = data
localStorage.setItem(KEY, JSON.stringify(cache))
}
/**
*
*/
const purge = () => {
localStorage.removeItem(KEY)
}
const fetchYata = async (id: number, apikey: string): Promise<YataApiDataWrap> => {
if (!id || !apikey) {
throw new TypeError('请求yata接口时出错: id和apikey不能为空')
}
const cache = getCache(id)
if (cache) {
return cache
} else {
let responseString: string, response: YataApiResponse
try {
responseString = await CommonUtils.COFetch(`https://yata.yt/api/v1/bs/${ id }?key=${ apikey }`)
} catch (e) {
throw new TypeError('请求yata接口时出错 ' + e.message)
}
try {
response = JSON.parse(responseString)
} catch (e) {
throw new TypeError('解析yata接口响应时出错 ' + e.message)
}
if (response.error) {
switch (response.error.code) {
case 1:
throw new TypeError('请求yata接口时出错: yata服务端错误-' + response.error.error)
case 2:
throw new TypeError('请求yata接口时出错: 脚本逻辑错误-' + response.error.error)
case 3:
throw new TypeError('请求yata接口时出错: 已达到次数限制-' + response.error.error)
case 4:
throw new TypeError('请求yata接口时出错: apikey错误-' + response.error.error)
}
}
const wrapper = <YataApiDataWrap>response[id]
wrapper.id = String(id)
wrapper.isCache = false
setCache(wrapper)
return wrapper
}
}
export { fetchYata, YataApiDataWrap, purge }

View File

@ -1,120 +1,120 @@
import UserScriptEngine from "../../enum/UserScriptEngine";
import CommonUtils from "../../class/utils/CommonUtils";
import Alert from "../../class/utils/Alert";
import { Container } from "../../container/Container";
import Logger from "../../class/Logger";
// gs loader
export default function loadGS(use) {
let logger = Container.factory(Logger);
if (use === UserScriptEngine.PDA) {
let ifr: HTMLIFrameElement = document.querySelector('#wh-gs-loader-ifr');
if (ifr) {
new Alert('飞贼小助手已经加载了');
return;
}
const container = document.createElement('div');
container.id = 'wh-gs-loader';
ifr = document.createElement('iframe');
ifr.id = 'wh-gs-loader-ifr';
ifr.src = 'https://www.torn.com/crimes.php';
container.append(ifr);
document.body.append(container);
CommonUtils.addStyle(`
#wh-gs-loader {
position:fixed;
top:0;
left:0;
z-index:100001;
}
`);
let notify = new Alert('加载中');
ifr.onload = () => {
notify.close();
const _window = ifr.contentWindow;
const _docu = _window.document;
_docu.head.innerHTML = '';
_docu.body.innerHTML = '';
notify = new Alert('加载依赖');
CommonUtils.COFetch('https://cdn.staticfile.org/vue/2.2.2/vue.min.js')
.then(vuejs => {
notify.close();
_window.eval(vuejs);
_window.GM_getValue = (k, v = undefined) => {
const objV = JSON.parse(_window.localStorage.getItem('wh-gs-storage') || '{}')[k];
return objV || v;
};
_window.GM_setValue = (k, v) => {
const obj = JSON.parse(_window.localStorage.getItem('wh-gs-storage') || '{}');
obj[k] = v;
_window.localStorage.setItem('wh-gs-storage', JSON.stringify(obj));
};
_window.GM_xmlhttpRequest = function (opt) {
// 暂不适配pda post
if (opt.method.toLowerCase() === 'post') return;
CommonUtils.COFetch(opt.url).then(res => {
const obj = {
responseText: res
};
opt.onload(obj);
});
};
notify = new Alert('加载飞贼小助手');
CommonUtils.COFetch(`https://gitee.com/ameto_kasao/tornjs/raw/master/GoldenSnitch.js?${ performance.now() }`)
.then(res => {
_window.eval(res.replace('http://222.160.142.50:8154/mugger', `https://api.ljs-lyt.com/mugger`));
_window.GM_setValue("gsp_x", 10);
_window.GM_setValue("gsp_y", 10);
notify.close();
notify = new Alert('飞贼小助手已加载', { timeout: 1 });
const gsp: HTMLElement = _docu.querySelector('#gsp');
const thisRun = () => {
ifr.style.height = `${ gsp.offsetHeight + 10 }px`;
ifr.style.width = `${ gsp.offsetWidth + 20 }px`;
gsp.style.top = '10px';
gsp.style.left = '10px';
};
new MutationObserver(thisRun).observe(gsp, { childList: true, subtree: true });
thisRun();
if (logger.debug()) _window.GM_setValue("gsp_showContent", true)
});
});
};
return;
}
if (use === UserScriptEngine.GM) {
if (typeof window.Vue !== 'function') {
let notify = new Alert('正在加载依赖');
CommonUtils.COFetch('https://cdn.staticfile.org/vue/2.2.2/vue.min.js')
.then(VueJS => {
window.eval(VueJS);
notify.close();
notify = new Alert('已载入依赖');
window.GM_getValue = (k, v = undefined) => {
const objV = JSON.parse(window.localStorage.getItem('wh-gs-storage') || '{}')[k];
return objV || v;
};
window.GM_setValue = (k, v) => {
const obj = JSON.parse(window.localStorage.getItem('wh-gs-storage') || '{}');
obj[k] = v;
window.localStorage.setItem('wh-gs-storage', JSON.stringify(obj));
};
// TODO
// window.GM_xmlhttpRequest = GM_xmlhttpRequest;
CommonUtils.COFetch(`https://gitee.com/ameto_kasao/tornjs/raw/master/GoldenSnitch.js?${ performance.now() }`)
.then(GSJS => {
window.eval(GSJS);
if (logger.debug()) window.GM_setValue("gsp_showContent", true);
notify.close();
notify = new Alert('已载入飞贼助手');
})
.catch(err => new Alert(`PDA API错误。${ JSON.stringify(err) }`));
})
.catch(err => new Alert(JSON.stringify(err)));
} else {
new Alert('飞贼助手已经加载了');
}
return;
}
new Alert('暂不支持');
}
// import UserScriptEngine from "../../enum/UserScriptEngine";
// import CommonUtils from "../../class/utils/CommonUtils";
// import Alert from "../../class/utils/Alert";
// import { Container } from "../../container/Container";
// import Logger from "../../class/Logger";
//
// // gs loader
// export default function loadGS(use) {
// let logger = Container.factory(Logger);
// if (use === UserScriptEngine.PDA) {
// let ifr: HTMLIFrameElement = document.querySelector('#wh-gs-loader-ifr');
// if (ifr) {
// new Alert('飞贼小助手已经加载了');
// return;
// }
// const container = document.createElement('div');
// container.id = 'wh-gs-loader';
// ifr = document.createElement('iframe');
// ifr.id = 'wh-gs-loader-ifr';
// ifr.src = 'https://www.torn.com/crimes.php';
// container.append(ifr);
// document.body.append(container);
// CommonUtils.addStyle(`
// #wh-gs-loader {
// position:fixed;
// top:0;
// left:0;
// z-index:100001;
// }
// `);
// let notify = new Alert('加载中');
// ifr.onload = () => {
// notify.close();
// const _window = ifr.contentWindow;
// const _docu = _window.document;
// _docu.head.innerHTML = '';
// _docu.body.innerHTML = '';
// notify = new Alert('加载依赖');
// CommonUtils.COFetch('https://cdn.staticfile.org/vue/2.2.2/vue.min.js')
// .then(vuejs => {
// notify.close();
// _window.eval(vuejs);
// _window.GM_getValue = (k, v = undefined) => {
// const objV = JSON.parse(_window.localStorage.getItem('wh-gs-storage') || '{}')[k];
// return objV || v;
// };
// _window.GM_setValue = (k, v) => {
// const obj = JSON.parse(_window.localStorage.getItem('wh-gs-storage') || '{}');
// obj[k] = v;
// _window.localStorage.setItem('wh-gs-storage', JSON.stringify(obj));
// };
// _window.GM_xmlhttpRequest = function (opt) {
// // 暂不适配pda post
// if (opt.method.toLowerCase() === 'post') return;
// CommonUtils.COFetch(opt.url).then(res => {
// const obj = {
// responseText: res
// };
// opt.onload(obj);
// });
// };
// notify = new Alert('加载飞贼小助手');
// CommonUtils.COFetch(`https://gitee.com/ameto_kasao/tornjs/raw/master/GoldenSnitch.js?${ performance.now() }`)
// .then(res => {
// _window.eval(res.replace('http://222.160.142.50:8154/mugger', `https://api.ljs-lyt.com/mugger`));
// _window.GM_setValue("gsp_x", 10);
// _window.GM_setValue("gsp_y", 10);
// notify.close();
// notify = new Alert('飞贼小助手已加载', { timeout: 1 });
// const gsp: HTMLElement = _docu.querySelector('#gsp');
// const thisRun = () => {
// ifr.style.height = `${ gsp.offsetHeight + 10 }px`;
// ifr.style.width = `${ gsp.offsetWidth + 20 }px`;
// gsp.style.top = '10px';
// gsp.style.left = '10px';
// };
// new MutationObserver(thisRun).observe(gsp, { childList: true, subtree: true });
// thisRun();
// if (logger.debug()) _window.GM_setValue("gsp_showContent", true)
// });
// });
// };
// return;
// }
// if (use === UserScriptEngine.GM) {
// if (typeof window.Vue !== 'function') {
// let notify = new Alert('正在加载依赖');
// CommonUtils.COFetch('https://cdn.staticfile.org/vue/2.2.2/vue.min.js')
// .then(VueJS => {
// window.eval(VueJS);
// notify.close();
// notify = new Alert('已载入依赖');
// window.GM_getValue = (k, v = undefined) => {
// const objV = JSON.parse(window.localStorage.getItem('wh-gs-storage') || '{}')[k];
// return objV || v;
// };
// window.GM_setValue = (k, v) => {
// const obj = JSON.parse(window.localStorage.getItem('wh-gs-storage') || '{}');
// obj[k] = v;
// window.localStorage.setItem('wh-gs-storage', JSON.stringify(obj));
// };
// // TODO
// // window.GM_xmlhttpRequest = GM_xmlhttpRequest;
// CommonUtils.COFetch(`https://gitee.com/ameto_kasao/tornjs/raw/master/GoldenSnitch.js?${ performance.now() }`)
// .then(GSJS => {
// window.eval(GSJS);
// if (logger.debug()) window.GM_setValue("gsp_showContent", true);
// notify.close();
// notify = new Alert('已载入飞贼助手');
// })
// .catch(err => new Alert(`PDA API错误。${ JSON.stringify(err) }`));
// })
// .catch(err => new Alert(JSON.stringify(err)));
// } else {
// new Alert('飞贼助手已经加载了');
// }
// return;
// }
// new Alert('暂不支持');
// }

View File

@ -67,57 +67,57 @@ export default function translateMain(href: string): void {
};
// 边栏
let sidebarTimeOut = 60;
const sidebarInterval = setInterval(() => {
// 60秒后取消定时
if ($('div[class^="sidebar"]').length === 0) {
sidebarTimeOut--;
if (sidebarTimeOut < 0) {
clearInterval(sidebarInterval);
}
return;
}
// 边栏块标题
$('h2[class^="header"]').each((i, e) => {
if (!sidebarDict[e.firstChild.nodeValue]) return;
e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue];
});
// 边栏人物名字
$('span[class^="menu-name"]').each((i, e) => {
e.firstChild.nodeValue = '名字:';
});
// 钱 等级 pt 天赋点
$('p[class^="point-block"]').each((i, e) => {
if (sidebarDict[e.firstChild.firstChild.nodeValue])
e.firstChild.firstChild.nodeValue = sidebarDict[e.firstChild.firstChild.nodeValue];
});
// 4条 状态条
$('p[class^="bar-name"]').each((i, e) => {
if (sidebarDict[e.firstChild.nodeValue])
e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue];
});
// 边栏菜单
$('span[class^="linkName"]').each((i, e) => {
if (sidebarDict[e.firstChild.nodeValue])
e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue];
});
// [use]按钮
if (document.querySelector('#pointsMerits'))
$('#pointsMerits')[0].firstChild.nodeValue = '[使用]';
if (document.querySelector('#pointsPoints'))
$('#pointsPoints')[0].firstChild.nodeValue = '[使用]';
if (document.querySelector('#pointsLevel'))
$('#pointsLevel')[0].firstChild.nodeValue = '[升级]';
// 手机 区域菜单
$('div[class*="areas-mobile"] span:nth-child(2)').contents().each((i, e) => {
//log(e);
if (sidebarDict[e.nodeValue])
e.nodeValue = sidebarDict[e.nodeValue];
});
clearInterval(sidebarInterval);
}, 1000);
// let sidebarTimeOut = 60;
// const sidebarInterval = setInterval(() => {
// // 60秒后取消定时
// if ($('div[class^="sidebar"]').length === 0) {
// sidebarTimeOut--;
// if (sidebarTimeOut < 0) {
// clearInterval(sidebarInterval);
// }
// return;
// }
// // 边栏块标题
// $('h2[class^="header"]').each((i, e) => {
// if (!sidebarDict[e.firstChild.nodeValue]) return;
// e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue];
// });
// // 边栏人物名字
// $('span[class^="menu-name"]').each((i, e) => {
// e.firstChild.nodeValue = '名字:';
// });
// // 钱 等级 pt 天赋点
// $('p[class^="point-block"]').each((i, e) => {
// if (sidebarDict[e.firstChild.firstChild.nodeValue])
// e.firstChild.firstChild.nodeValue = sidebarDict[e.firstChild.firstChild.nodeValue];
// });
// // 4条 状态条
// $('p[class^="bar-name"]').each((i, e) => {
// if (sidebarDict[e.firstChild.nodeValue])
// e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue];
// });
// // 边栏菜单
// $('span[class^="linkName"]').each((i, e) => {
// if (sidebarDict[e.firstChild.nodeValue])
// e.firstChild.nodeValue = sidebarDict[e.firstChild.nodeValue];
// });
// // [use]按钮
// if (document.querySelector('#pointsMerits'))
// $('#pointsMerits')[0].firstChild.nodeValue = '[使用]';
// if (document.querySelector('#pointsPoints'))
// $('#pointsPoints')[0].firstChild.nodeValue = '[使用]';
// if (document.querySelector('#pointsLevel'))
// $('#pointsLevel')[0].firstChild.nodeValue = '[升级]';
//
// // 手机 区域菜单
// $('div[class*="areas-mobile"] span:nth-child(2)').contents().each((i, e) => {
// //log(e);
// if (sidebarDict[e.nodeValue])
// e.nodeValue = sidebarDict[e.nodeValue];
// });
//
// clearInterval(sidebarInterval);
// }, 1000);
// header
if (document.querySelector('div#header-root')) {

View File

@ -0,0 +1,14 @@
const convertToCSV = (data: any[]) => {
let csv = ''
for (let i = 0; i < data.length; i++) {
let row = ''
for (const key in data[i]) {
row += `"${ data[i][key] }",`
}
row = row.slice(0, -1) // 删除最后一个逗号
csv += row + '\r\n' // 添加换行符
}
return csv
}
export { convertToCSV }

View File

@ -22,3 +22,7 @@ export const fetchCurrentMoney = async (action?: string): Promise<number> => {
export const fetchCurrentCompanyAvailableMoney = () => {
return fetchCurrentMoney("companyAction");
};
export const fetchCurrentPropVaultAvailableMoney = () => {
return fetchCurrentMoney("propertyDepositAction");
};

View File

@ -0,0 +1,20 @@
const timePastFormat = (ts: number): string => {
// 毫秒
if (ts < 1000) {
return ts + 'ms'
}
// 秒
else if (ts < 60000) {
return (ts / 1000 | 0) + 's'
}
// 分
else if (ts < 3600000) {
return (ts / 60000 | 0) + 'm'
}
// 时
else {
return (ts / 3600000 | 0) + 'h'
}
}
export { timePastFormat }

View File

@ -1,6 +1,17 @@
import { ElMessage } from "element-plus";
import { ElMessage } from "element-plus"
const useItem = (itemId: string) => {
type CrimeResVo = { text: string, success: boolean }
const defaultCb = (res: CrimeResVo) => {
ElMessage({
message: res.text,
type: res.success ? 'success' : 'error',
dangerouslyUseHTMLString: true,
grouping: true
})
}
const useItem = (itemId: string, cb = defaultCb) => {
fetch(window.addRFC("https://www.torn.com/item.php"), {
"headers": {
"accept": "*/*",
@ -19,15 +30,22 @@ const useItem = (itemId: string) => {
"credentials": "include"
})
.then(res => res.json())
.then(res => ElMessage({
message: res.text,
type: res.success ? 'success' : 'error',
dangerouslyUseHTMLString: true
}))
.then(res => cb(res))
.catch(e => ElMessage({
message: e.toString,
type: 'error'
}));
};
}
export default useItem;
const useItemSync = (itemId: string, showMsg = true, cb = (response: CrimeResVo) => null) => {
return new Promise((res, rej) => {
useItem(itemId, (_res) => {
if (showMsg) defaultCb(_res)
cb(_res)
res(null)
})
})
}
export default useItem
export { useItemSync }

View File

@ -38,7 +38,10 @@ export default interface IUserProfileData {
}
};
medalInformation: unknown;
basicInformation: unknown;
basicInformation: {
icons: { id: number, title: string }[],
lastAction: { seconds: number }
};
personalInformation: unknown;
competitionStatus: unknown;
staffTools: null;

View File

@ -32,6 +32,7 @@ export interface MiniProfile {
},
sendMoneyWarning: string,
playerName: string,
userID: number,
};
userStatus: {
status: {

View File

@ -23,7 +23,7 @@ class DrugCDMonitor implements IntervalType {
handler(): void {
const data = getSidebarData()
if (!data.statusIcons.icons.drug_cooldown) {
if (data?.statusIcons?.icons?.drug_cooldown?.timerExpiresAt * 1000 < Date.now()) {
this.msgWrapper.create('警告: 药CD停转', { sysNotify: true })
}
}

262
src/vue/BSEstView.vue Normal file
View File

@ -0,0 +1,262 @@
<script lang="ts" setup>
import { inject, onMounted, ref } from "vue"
import { LocalConfigWrapperKey } from "../ts/class/LocalConfigWrapper"
import { ElMessage } from "element-plus"
import { fetchYata, purge, YataApiDataWrap } from "../ts/func/module/fetchYata"
import { LoggerKey } from "../ts/class/Logger"
import toThousands from "../ts/func/utils/toThousands"
import { Download, QuestionFilled, Refresh, Search } from "@element-plus/icons-vue"
import { timePastFormat } from "../ts/func/utils/timePastFormat"
import { convertToCSV } from "../ts/func/utils/convert2Csv"
const isMiniProfOn = ref<boolean>(false)
const isProfOn = ref<boolean>(false)
const apikey = ref<string>('')
const targetId = ref<string>('')
const tableData = ref<Partial<YataApiDataWrap>[]>([])
const isLoading = ref(false)
const idKey: { [key: string]: number } = {}
const buildType = { Offensive: '攻击型', Defensive: '防御型', Balanced: '平衡型' }
const localConfigWrapper = inject(LocalConfigWrapperKey)
const logger = inject(LoggerKey)
const saveApikey = () => {
if (!apikey.value) {
ElMessage({
message: 'apikey保存时输入为空',
type: 'error',
showClose: true
})
throw new TypeError('apikey保存时输入为空')
}
localStorage.setItem('APIKey', apikey.value)
ElMessage.success({
message: 'APIKey设置成功',
showClose: true
})
}
const onMiniProfSwitchChange = () => localConfigWrapper.config.isBSEstMiniProfOn = isMiniProfOn.value
const onProfSwitchChange = () => localConfigWrapper.config.isBSEstProfOn = isProfOn.value
const doRequest = async () => {
if (!apikey.value) {
ElMessage.warning({
message: '未设置APIKey',
showClose: true
})
return
}
isLoading.value = true
for (let i = 0; i < tableData.value.length; i++) {
const item = tableData.value[i]
if (!item.total) {
let est: YataApiDataWrap
try {
est = await fetchYata(parseInt(item.id), apikey.value)
} catch (e) {
ElMessage.error({
message: e.message,
showClose: true
})
logger.error(e.stack)
continue
}
item.total = est.total
item.score = est.score
item.type = est.type
item.skewness = est.skewness
item.timestamp = est.timestamp
item.version = est.version
item.isCache = est.isCache
}
}
isLoading.value = false
}
/**
* 查询列表中添加新的id
* @param _id
*/
const add = (_id: string) => {
const id = parseInt(_id)
if (id) {
// id
if (!idKey[_id]) {
tableData.value.push({ id: _id })
idKey[_id] = 1
targetId.value = ''
} else {
ElMessage.warning({
message: '重复的id',
showClose: true
})
}
} else {
ElMessage.error({
message: 'id有误',
showClose: true
})
}
}
/**
* 清空查询列表和唯一id表
*/
const emptyList = () => {
tableData.value = []
const keys = Object.keys(idKey)
for (let i = 0; i < keys.length; i++) {
const key = keys[i]
idKey[key] = 0
}
}
const purgeCache = () => {
purge()
ElMessage.warning({
message: '本地缓存已清除',
showClose: true
})
}
const exportCsv = () => {
const exportList: any[] = [{
id: "ID", total: "BS", score: "评分", type: "风格", skewness: "偏差", timestamp: "时间戳"
}]
for (let i = 0; i < tableData.value.length; i++) {
const item = tableData.value[i]
const newItem = {
id: item.id ?? '-1',
total: item.total ?? null,
score: item.score ?? null,
type: buildType[item.type] ?? null,
skewness: item.skewness ?? null,
timestamp: item.timestamp ?? null,
// isCache: item.isCache ?? null,
// version: item.version ?? null
}
exportList.push(newItem)
}
const csvContent = convertToCSV(exportList)
let url: string
let isBlob = false
const UTF8 = "\uFEFF"
if (window.Blob && window.URL && window.URL.createObjectURL) {
const csvData = new window.Blob([UTF8 + csvContent], {
type: 'text/csv'
})
url = window.URL.createObjectURL(csvData)
isBlob = true
} else {
url = window.encodeURI(csvContent)
}
window.location.href = isBlob ? url : 'data:text/csv;charset=utf-8,' + UTF8 + url
}
onMounted(() => {
// APIKey
const key = localStorage.getItem('APIKey')
if (!key) {
ElMessage.error({
message: '尚未配置APIKey',
showClose: true
})
} else {
apikey.value = key
}
//
isMiniProfOn.value = localConfigWrapper.config.isBSEstMiniProfOn
isProfOn.value = localConfigWrapper.config.isBSEstProfOn
})
</script>
<template>
<el-space :fill="true">
<el-card shadow="never">
<template #header>设置</template>
<el-form label-width="auto" @submit.prevent>
<el-form-item label="MINI资料卡中显示">
<el-switch v-model="isMiniProfOn" @change="onMiniProfSwitchChange"/>
</el-form-item>
<el-form-item label="个人资料中显示">
<el-switch v-model="isProfOn" @change="onProfSwitchChange"/>
</el-form-item>
<el-form-item label="API KEY">
<el-input v-model="apikey">
<template #append>
<el-button :loading="isLoading" @click="saveApikey">保存</el-button>
</template>
</el-input>
</el-form-item>
<el-form-item>
<el-popconfirm cancel-button-text="取消" confirm-button-text="确定" title="确定操作" @confirm="purgeCache">
<template #reference>
<el-button type="danger">清空缓存</el-button>
</template>
</el-popconfirm>
</el-form-item>
</el-form>
</el-card>
<el-card shadow="never">
<template #header>使用</template>
<p class="mt-4">BS估算功能使用了
<el-link href="https://yata.yt/api/v1/" target="_blank">yata</el-link>
神经网络模型接口需要提供torn apikey (上面输入)
</p>
<p class="mt-4">本插件缓存机制1</p>
<el-form label-width="auto" @submit="add(targetId)" @submit.prevent>
<el-form-item label="目标数字ID">
<el-input v-model="targetId" clearable/>
</el-form-item>
<el-form-item>
<el-button :loading="isLoading" type="primary" @click="add(targetId)">添加</el-button>
</el-form-item>
</el-form>
</el-card>
<el-card shadow="never">
<template #header>结果</template>
<el-button-group>
<el-button :icon="Search" :loading="isLoading" type="primary" @click="doRequest">估算</el-button>
<el-button :icon="Refresh" :loading="isLoading" @click="emptyList">清空</el-button>
<el-button :icon="Download" :loading="isLoading" @click="exportCsv">导出CSV</el-button>
</el-button-group>
<el-row>
<el-col :span="23">
<el-table :data="tableData" empty-text=" ">
<el-table-column label="ID" prop="id"/>
<el-table-column label="BS">
<template #default="scope">
{{ toThousands(scope.row.total) }}
</template>
</el-table-column>
<el-table-column label="评分" prop="score"/>
<el-table-column label="风格">
<template #default="scope">
{{ buildType[scope.row.type] }}
</template>
</el-table-column>
<el-table-column>
<template #header>
<el-tooltip content="越低越准" effect="light" placement="top">
<span>偏差<el-icon><QuestionFilled/></el-icon></span>
</el-tooltip>
</template>
<template #default="scope">
{{ scope.row.skewness }}%
</template>
</el-table-column>
<el-table-column label="时间">
<template #default="scope">
{{ timePastFormat(Date.now() - scope.row.timestamp * 1000) }}
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
</el-card>
</el-space>
</template>
<style scoped>
</style>

View File

@ -124,6 +124,13 @@ onMounted(() => {
</template>
</el-input>
</el-form-item>
<el-button-group>
<el-button type="primary" @click="()=>inputMoney='1000000'">1m</el-button>
<el-button type="primary" @click="()=>inputMoney='2000000'">2m</el-button>
<el-button type="primary" @click="()=>inputMoney='5000000'">5m</el-button>
<el-button type="primary" @click="()=>inputMoney='10000000'">10m</el-button>
<el-button type="primary" @click="()=>inputMoney='20000000'">20m</el-button>
</el-button-group>
</el-form>
</template>

View File

@ -4,7 +4,7 @@ import { LoggerKey } from "../ts/class/Logger"
const logger = inject(LoggerKey)
const loading = ref(true)
const doFetch = () => fetch("https://www.torn.com/page.php", {
const doFetch = () => fetch(window.addRFC("https://www.torn.com/page.php?sid=eventsData"), {
"headers": {
"accept": "*/*",
"sec-ch-ua-mobile": "?0",

View File

@ -3,14 +3,14 @@
<el-button-group class="wh-menu-button" style="z-index: 1000000;">
<el-button circle @click="expanded = !expanded">
<el-icon>
<MoonNight />
<MoonNight/>
</el-icon>
</el-button>
<el-button v-for="item in globVars.buttons" @click="item.func">{{ item.txt }}</el-button>
<el-button v-if="editableTabs.length > 0" circle @click="showDrawer">
<el-badge :value="editableTabs.length" type="primary">
<el-icon>
<CopyDocument />
<CopyDocument/>
</el-icon>
</el-badge>
</el-button>
@ -18,7 +18,7 @@
<el-dialog v-model="drawer" :fullscreen="isMobilePhone" :lock-scroll="true" width="65%">
<el-tabs v-model="editableTabsValue" closable style="margin-top: -1em" type="border-card" @tab-remove="removeTab">
<el-tab-pane v-for="item in editableTabs" :key="item.name" :label="item.title" :name="item.name">
<component :is="item.content" />
<component :is="item.content"/>
</el-tab-pane>
</el-tabs>
</el-dialog>
@ -69,11 +69,11 @@
<el-icon></el-icon>
<span>REFILL</span>
</template>
<el-menu-item @click="handleRefil('energyrefill2')">能量E
<el-menu-item @click="handleRefil('refillEnergy')">能量E
</el-menu-item>
<el-menu-item @click="handleRefil('nerverefill2')">犯罪N
<el-menu-item @click="handleRefil('refillNerve')">犯罪N
</el-menu-item>
<el-menu-item @click="handleRefil('casinotokens2')">赌场代币
<el-menu-item @click="handleRefil('refillCasinoTokens')">赌场代币
</el-menu-item>
</el-sub-menu>
</el-menu>
@ -101,7 +101,7 @@
<el-tooltip content="更新?" placement="bottom-start">
<el-button link @click="menuClick({ title: '关于助手', template: UpdateDate })">芜湖助手
<el-icon>
<Refresh />
<Refresh/>
</el-icon>
</el-button>
</el-tooltip>
@ -158,6 +158,8 @@ import PTMarketView from "./PTMarketView.vue"
import QuickCrime from "./QuickCrime.vue"
import UpdateDate from "./UpdateScript.vue"
import VirusProgramming from "./VirusProgramming.vue"
import PropertyVault from "./PropertyVault.vue";
import BSEstView from "./BSEstView.vue";
const logger = inject(LoggerKey)
const quickGymTrain = inject(QuickGymTrainKey)
@ -174,42 +176,6 @@ const menuItemList: MenuItem[] = [
ElMessage({ message: '毒 CD: ' + cd + 'h', showClose: true })
},
},
{
title: '🍺 喝啤酒',
handler: () => {
useItem('180')
const sidebarData = getSidebarData()
const nerve = sidebarData.bars.nerve.amount
const cd = (sidebarData.statusIcons.icons.booster_cooldown?.timerExpiresAt - sidebarData.statusIcons.icons.booster_cooldown?.serverTimestamp) / 3600 | 0
ElMessage({ message: 'N: ' + nerve + ', CD: ' + cd + 'h', showClose: true })
},
},
// {
// title: ' REFILL',
// handler: () => fetch(window.addRFC("https://www.torn.com/points.php?step=pointsbuy&action=energyrefill2"), {
// "headers": {
// "accept": "text/plain, */*; q=0.01",
// "sec-ch-ua-mobile": "?0",
// "sec-fetch-dest": "empty",
// "sec-fetch-mode": "cors",
// "sec-fetch-site": "same-origin",
// "x-requested-with": "XMLHttpRequest"
// },
// "referrer": "https://www.torn.com/points.php",
// "referrerPolicy": "strict-origin-when-cross-origin",
// "body": null,
// "method": "GET",
// "mode": "cors",
// "credentials": "include"
// })
// .then(res => res.json())
// .then(res => ElMessage({
// message: `<p>${ res.msg }</p><p>refill: ${ res["refills"] }</p>`,
// type: res.state === 'done' ? 'success' : 'error',
// dangerouslyUseHTMLString: true
// }))
// .catch(e => ElMessage.error(e.toString)),
// },
{
title: '🚓 快速犯罪',
template: QuickCrime,
@ -234,10 +200,18 @@ const menuItemList: MenuItem[] = [
title: '💰 公司存钱',
template: CompanyWithdraw,
},
{
title: '💰 PI存钱',
template: PropertyVault,
},
{
title: '📦 物品',
template: InventoryView,
},
{
title: '🎯 BS估算',
template: BSEstView,
},
{
title: '🫵 关闭店铺(双击开启)',
handler: () => bazaarControl.method(),
@ -299,30 +273,39 @@ const editableTabsValue = ref('')
const editableTabs = shallowRef([])
// refil
const handleRefil = (method: 'nerverefill2' | 'energyrefill2' | 'casinotokens2') => {
fetch(window.addRFC('https://www.torn.com/points.php?step=pointsbuy&action=' + method), {
const handleRefil = (method: 'refillEnergy' | 'refillNerve' | 'refillCasinoTokens') => {
fetch(window.addRFC("https://www.torn.com/page.php?sid=pointsBuildingExchange"), {
"headers": {
"accept": "text/plain, */*; q=0.01",
"sec-ch-ua-mobile": "?0",
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"x-requested-with": "XMLHttpRequest"
},
"referrer": "https://www.torn.com/points.php",
"referrer": "https://www.torn.com/page.php?sid=points",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": null,
"method": "GET",
"body": (() => {
const data = new FormData();
data.append('key', method);
return data;
})(),
"method": "POST",
"mode": "cors",
"credentials": "include"
})
.then(res => res.json())
.then(res => ElMessage({
message: `<p>${res.msg}</p><p>剩余次数: ${res["refills"]}</p>`,
type: res.state === 'done' ? 'success' : 'error',
.catch(e => ElMessage.error('REFILL异常: ' + e.toString))
.then(res => {
ElMessage({
message: res.success ?
`<p>成功</p><p>剩余次数: ${ res["specialRefills"] } 剩余点数: ${ res['points'] }</p>` :
`REFILL异常: ${ res.error }`,
type: res.success ? 'success' : 'error',
dangerouslyUseHTMLString: true
}))
.catch(e => ElMessage.error(e.toString))
})
throw new TypeError('REFILL异常: ' + res.error)
})
}
// fast travel

View File

@ -67,6 +67,7 @@ import { itemNameDict } from "../ts/dictionary/translation";
import toThousands from "../ts/func/utils/toThousands";
import Sleep from "../ts/func/utils/Sleep";
import { MathUtilsKey } from "../ts/class/utils/MathUtils";
import { timePastFormat } from "../ts/func/utils/timePastFormat";
const logger = inject(LoggerKey);
const itemHelper = inject(ItemHelperKey);
@ -90,25 +91,6 @@ const itemOnList = ref<ItemInfo[]>([]);
const listLoading = ref<boolean>(false);
const currentTs = ref<number>(Date.now());
const timePastFormat = (ts: number): string => {
//
if (ts < 1000) {
return ts + 'ms';
}
//
else if (ts < 60000) {
return (ts / 1000 | 0) + 's';
}
//
else if (ts < 3600000) {
return (ts / 60000 | 0) + 'm';
}
//
else {
return (ts / 3600000 | 0) + 'h';
}
};
const doGetIMarketList = async (id: number) => {
itemOnList.value = [];
listLoading.value = true;

189
src/vue/PropertyVault.vue Normal file
View File

@ -0,0 +1,189 @@
<script lang="ts" setup>
import { inject, onMounted, ref } from "vue"
import { LoggerKey } from "../ts/class/Logger"
import { fetchCurrentMoney, fetchCurrentPropVaultAvailableMoney } from "../ts/func/utils/fetchCurrentMoney"
import { ElMessage } from "element-plus"
import toThousands from "../ts/func/utils/toThousands"
const logger = inject(LoggerKey)
const inputMoney = ref('')
const inputWithdrawMoney = ref('')
const formModel = ref({
cash: 0, vault: 0,
})
const propId = ref(-1)
const updateCash = async () => {
formModel.value.cash = await fetchCurrentMoney()
return formModel.value.cash
}
const updateVault = async () => {
formModel.value.vault = await fetchCurrentPropVaultAvailableMoney()
return formModel.value.vault
}
/**
* 存取钱通用
* @param amount
* @param action {'deposit' | 'withdraw'}
*/
const deposit = async (amount: number, action: 'deposit' | 'withdraw' = 'deposit') => {
if (amount < 1) {
ElMessage.error('数额不能小于1')
logger.error('数额不能小于1')
throw new Error('数额不能小于1')
}
if (propId.value === -1) {
ElMessage.error('未获取到房产id')
logger.error('未获取到房产id')
throw new Error('未获取到房产id')
}
let response: string
try {
response = await (await fetch(window.addRFC("https://www.torn.com/properties.php"), {
"headers": {
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"x-requested-with": "XMLHttpRequest"
},
"referrer": "https://www.torn.com/properties.php",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": "step=vaultProperty&" + action + "=" + amount + "&ID=" + propId.value,
"method": "POST",
"mode": "cors",
"credentials": "include"
})).text()
} catch (e) {
ElMessage.error('请求出错 ' + e.message)
logger.error(e.stack)
throw e
}
let error: string, text: string
try {
let json = JSON.parse(response)
error = json.error
text = json.text
} catch (e) {
}
if (error) {
ElMessage.error('$' + toThousands(amount) + ' 存取请求失败 ' + text)
logger.error('存取请求失败 ' + text)
throw new Error('存取请求失败 ' + text)
} else {
ElMessage.success('$' + toThousands(amount) + ' 存取请求完成')
}
if (action === 'deposit') {
inputWithdrawMoney.value = ''
} else {
inputMoney.value = ''
}
updateVault().then()
updateCash().then()
}
const getPropId = async () => {
let response: string
try {
response = await (await fetch("https://www.torn.com/properties.php", {
"headers": {
"accept": "*/*",
"accept-language": "zh-CN,zh;q=0.9",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"x-requested-with": "XMLHttpRequest"
},
"referrer": "https://www.torn.com/properties.php",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": "p=options&tab=vault&step=options",
"method": "POST",
"mode": "cors",
"credentials": "include"
})).text()
} catch (e) {
ElMessage.error('获取房产id失败请重试')
logger.error('获取房产id失败', e)
throw e
}
const reg = /&ID=(\d+)"/
const match = response.match(reg)
if (match) {
propId.value = Number(match[1])
} else {
ElMessage.error('获取房产id失败报文未能成功匹配')
logger.error('获取房产id失败报文未能成功匹配')
throw new Error('获取房产id失败报文未能成功匹配')
}
}
onMounted(async () => {
await getPropId()
await updateCash()
await updateVault()
})
</script>
<template>
<div class="gap4">
<el-card shadow="never">当前默认房产id{{ propId }}</el-card>
<el-card shadow="never">
<template #header>
存钱{{ toThousands(formModel.cash) }}
</template>
<el-row>
<el-col :span="3">
<el-button @click="async ()=>inputMoney=String(await updateCash())">$</el-button>
</el-col>
<el-col :span="18">
<el-input v-model="inputMoney"/>
</el-col>
<el-col :span="3">
<el-button @click="()=>{deposit(Number(inputMoney),'deposit');inputMoney=''}">确定</el-button>
</el-col>
</el-row>
</el-card>
<el-card shadow="never">
<template #header>
取钱{{ toThousands(formModel.vault) }}
</template>
<el-row>
<el-button-group>
<el-button type="primary" @click="()=>inputWithdrawMoney='1000000'">1m</el-button>
<el-button type="primary" @click="()=>inputWithdrawMoney='2000000'">2m</el-button>
<el-button type="primary" @click="()=>inputWithdrawMoney='5000000'">5m</el-button>
<el-button type="primary" @click="()=>inputWithdrawMoney='10000000'">10m</el-button>
<el-button type="primary" @click="()=>inputWithdrawMoney='20000000'">20m</el-button>
</el-button-group>
</el-row>
<el-row>
<el-col :span="3">
<el-button @click="async ()=>inputWithdrawMoney=String(await updateVault())">$</el-button>
</el-col>
<el-col :span="18">
<el-input v-model="inputWithdrawMoney"/>
</el-col>
<el-col :span="3">
<el-button @click="()=>{deposit(Number(inputWithdrawMoney),'withdraw');inputWithdrawMoney=''}">确定
</el-button>
</el-col>
</el-row>
</el-card>
</div>
</template>
<style scoped>
.gap4 .el-card {
margin-bottom: 4px;
}
</style>

View File

@ -1,37 +1,62 @@
<template>
<el-space direction="vertical">
<el-row>
<!-- <el-row>-->
<!-- <el-col :span="12">-->
<div class="mt-4">
<el-space>
<el-button-group>
<el-button @click="doCrime(11, 'warehouse')">烧仓库</el-button>
<el-button @click="doCrime(15, 'napcop')">做15-3</el-button>
<el-button @click="doCrime(18, 'hackbank')">做18-1</el-button>
</el-button-group>
</el-row>
<el-row>
<el-cascader :options="CrimeData" :show-all-levels="false" clearable v-model="crimeSelected" placeholder="选择其他" />
<el-button :disabled="!(crimeSelected && crimeSelected.length)" @click="doCrime(crimeSelected[0], crimeSelected[1])"
type="danger" round :icon="Coffee"></el-button>
</el-row>
<!-- </el-col>-->
<!-- <el-col :span="12">-->
<el-button type="primary" @click="doYouLikeABeer()">🍺 你喜欢啤酒吗</el-button>
</el-space>
</div>
<!-- </el-col>-->
<!-- </el-row>-->
<!-- <el-row>-->
<div class="mt-4">
<el-space>
<el-cascader v-model="crimeSelected" :options="CrimeData" :show-all-levels="false" clearable
placeholder="选择其他"/>
<el-button :disabled="!(crimeSelected && crimeSelected.length)"
:icon="Coffee"
round type="danger" @click="doCrime(crimeSelected[0], crimeSelected[1])">
</el-button>
</el-space>
</div>
<!-- </el-row>-->
<div class="mt-4">
<el-space>
<el-tag type="primary">NERVE {{ nerve }}</el-tag>
<el-tag type="danger">CD {{ boostCoolDown }}</el-tag>
</el-space>
</div>
<div v-if="responseHtmlString" v-html="responseHtmlString"></div>
<div v-if="results" v-html="results"></div>
<el-skeleton v-if="loading" :rows="3" animated />
<el-skeleton v-if="loading" :rows="3" animated/>
</template>
<script lang="ts" setup>
import { Coffee } from "@element-plus/icons-vue";
import { ElMessage } from "element-plus";
import { inject, ref } from 'vue';
import { LoggerKey } from "../ts/class/Logger";
import { CrimeData } from "./data/CrimeData";
import { Coffee } from "@element-plus/icons-vue"
import { inject, onBeforeUnmount, onMounted, ref } from 'vue'
import { LoggerKey } from "../ts/class/Logger"
import { CrimeData } from "./data/CrimeData"
import { useItemSync } from "../ts/func/utils/useItem"
import getSidebarData from "../ts/func/utils/getSidebarData"
const logger = inject(LoggerKey);
const results = ref("");
const loading = ref(false);
const logger = inject(LoggerKey)
const results = ref("")
const loading = ref(false)
const crimeSelected = ref(null)
const responseHtmlString = ref('')
const boostCoolDown = ref(0)
const nerve = ref(0)
const doCrime = async (nerve, crime: "hackbank" | "warehouse" | 'napcop') => {
loading.value = true;
results.value = '';
loading.value = true
results.value = ''
try {
results.value = await (await fetch(window.addRFC("https://www.torn.com/crimes.php?step=docrime4&timestamp=" + Date.now()), {
"headers": {
@ -45,27 +70,52 @@ const doCrime = async (nerve, crime: "hackbank" | "warehouse" | 'napcop') => {
},
"referrer": "https://www.torn.com/crimes.php",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": `nervetake=${nerve}&crime=${crime}`,
"body": `nervetake=${ nerve }&crime=${ crime }`,
"method": "POST",
"mode": "cors",
"credentials": "include"
})).text();
})).text()
} catch (e) {
logger.error(e.stack);
results.value = e.message;
logger.error(e.stack)
results.value = e.message
}
let err;
let err: string
try {
err = JSON.parse(results.value).error;
err = JSON.parse(results.value).error
} catch (e) {
}
if (err) {
results.value = '出错了';
ElMessage.error('错误: ' + err);
logger.error(err);
results.value = '错误: ' + err
// ElMessage.error(': ' + err)
logger.error(err)
}
loading.value = false;
};
loading.value = false
updateData()
}
const doYouLikeABeer = async () => {
await useItemSync('180', false, (res) => {
responseHtmlString.value = res.text
updateData()
}
)
}
const updateData = () => {
const sidebarData = getSidebarData()
nerve.value = sidebarData.bars.nerve.amount
boostCoolDown.value = (sidebarData.statusIcons.icons.booster_cooldown?.timerExpiresAt - sidebarData.statusIcons.icons.booster_cooldown?.serverTimestamp) / 3600 | 0
}
let intervalId = 0
onMounted(() => {
updateData()
intervalId = window.setInterval(() => updateData(), 60000)
})
onBeforeUnmount(() => {
if (intervalId) window.clearInterval(intervalId)
})
</script>
<style scoped></style>