This commit is contained in:
Liwanyi 2023-09-19 10:54:30 +08:00
parent ad36cba92e
commit 201dcb9ba5
65 changed files with 2203 additions and 1121 deletions

10
global.d.ts vendored
View File

@ -122,10 +122,8 @@ declare module "*.module.css" {
declare function GM_xmlhttpRequest(init: any): void;
declare var unsafeWindow: Window & typeof globalThis;
declare interface UnknownFields {
// any property
[key: string]: any
}
declare type Constructor<T = any> = new (...args: any[]) => T;
declare interface ClassType<T> {
new(...args: unknown[]): T
}

18
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "wuhu-torn-helper",
"version": "1.0.8",
"version": "1.1.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "wuhu-torn-helper",
"version": "1.0.8",
"version": "1.1.1",
"devDependencies": {
"@element-plus/icons-vue": "^2.1.0",
"@rollup/plugin-alias": "^4.0.3",
@ -17,7 +17,7 @@
"@rollup/plugin-terser": "^0.4.0",
"@rollup/plugin-typescript": "^8.5.0",
"@types/jquery": "^3.5.14",
"@types/node": "^18.0.6",
"@types/node": "^20.6.0",
"@vitejs/plugin-vue": "^4.0.0",
"@vue/tsconfig": "^0.1.3",
"cross-env": "^7.0.3",
@ -1150,9 +1150,9 @@
}
},
"node_modules/@types/node": {
"version": "18.0.6",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-18.0.6.tgz",
"integrity": "sha512-/xUq6H2aQm261exT6iZTMifUySEt4GR5KX8eYyY+C4MSNPqSh9oNIP7tz2GLKTlFaiBbgZNxffoR3CVRG+cljw==",
"version": "20.6.0",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-20.6.0.tgz",
"integrity": "sha512-najjVq5KN2vsH2U/xyh2opaSEz6cZMR2SetLIlxlj08nOcmPOemJmUK2o4kUzfLqfrWE0PIrNeE16XhYDd3nqg==",
"dev": true
},
"node_modules/@types/parse-json": {
@ -8390,9 +8390,9 @@
}
},
"@types/node": {
"version": "18.0.6",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-18.0.6.tgz",
"integrity": "sha512-/xUq6H2aQm261exT6iZTMifUySEt4GR5KX8eYyY+C4MSNPqSh9oNIP7tz2GLKTlFaiBbgZNxffoR3CVRG+cljw==",
"version": "20.6.0",
"resolved": "https://registry.npmmirror.com/@types/node/-/node-20.6.0.tgz",
"integrity": "sha512-najjVq5KN2vsH2U/xyh2opaSEz6cZMR2SetLIlxlj08nOcmPOemJmUK2o4kUzfLqfrWE0PIrNeE16XhYDd3nqg==",
"dev": true
},
"@types/parse-json": {

View File

@ -17,7 +17,7 @@
"@rollup/plugin-terser": "^0.4.0",
"@rollup/plugin-typescript": "^8.5.0",
"@types/jquery": "^3.5.14",
"@types/node": "^18.0.6",
"@types/node": "^20.6.0",
"@vitejs/plugin-vue": "^4.0.0",
"@vue/tsconfig": "^0.1.3",
"cross-env": "^7.0.3",

View File

@ -1,68 +1,71 @@
<div class="acc-title">
<span class="item-desc" style="display: inline-block;">
<span class="item Alcohol" itemid="180" loaded="0">
<span class="item-plate">
<img alt="Bottle of Beer" class="torn-item large" src="/images/items/180/large.png">
</span>
<span class="item-hover">
<button aria-labelledby="Show info: 180-name 180-price 180-stock" class="view-info wai-btn" i-data="i_871_346_51_52"
value="100"></button>
<button aria-label="Buy: Bottle of Beer" class="buy-info wai-btn" i-data="i_922_346_51_52" value="100"></button>
</span>
</span>
<span class="desc">
<span id="180-name" class="name t-overflow bold">Bottle of Beer</span>
<span id="180-price" class="price t-gray-6" data-sell="$5">$10</span>
<span id="180-stock" class="stock t-gray-6 t-overflow">Alcohol (<span class="instock">800</span> in stock)</span>
</span>
<span class="buy-act-wrap">
<button aria-label="Close" class="close-icon p0 wai-btn" value="100"></button>
<label class="wai" for="180">Amount
of Bottle of Beer</label>
<input id="180" autocomplete="new-amount" maxlength="3" name="buyAmount[]" type="text" value="100">
<span class="buy-act bold">
<button class="wai-support t-blue h" i-data="i_1076_375_53_34" value="100">Buy<br></button>
</span>
</span>
</span>
<span class="item-desc tt-buy">
<span class="item Alcohol" itemid="180" loaded="0">
<span class="item-plate">
<img alt="Bottle of Beer" class="torn-item large"
src="/images/items/180/large.png"
srcset="/images/items/180/large.png 1x, /images/items/180/large@2x.png 2x, /images/items/180/large@3x.png 3x, /images/items/180/large@4x.png 4x">
</span>
<span class="item-hover">
<button aria-labelledby="Show info: 180-name 180-price 180-stock" class="view-info wai-btn"
value="100"></button>
<button aria-label="Buy: Bottle of Beer" class="buy-info wai-btn" value="100"></button>
</span>
</span>
<span class="desc">
<input name="shoparea" type="hidden" value="100">
<span id="180-name" class="name t-overflow bold">Bottle of Beer</span>
<span id="180-price" class="price t-gray-6 tt-modified" data-sell="$5">$10<span
class="tt-profit positive"><i class="fas fa-caret-up"></i>$1,636</span></span>
<span id="180-stock" class="stock t-gray-6 t-overflow">Alcohol (<span class="instock">5,000</span> in
stock)</span>
</span>
<span class="buy-act-wrap">
<button aria-label="Close" class="close-icon p0 wai-btn" value="100"></button>
<label class="wai" for="180">Amount
of Bottle of Beer</label>
<input id="180" autocomplete="new-amount" maxlength="3" name="buyAmount[]" type="text" value="100">
<span class="buy-act bold">
<button class="wai-support t-blue h" value="100">Buy<br><span class="tt-max-buy">fill
max</span></button>
<div class="tt-max-buy-overlay"></div>
</span>
</span>
</span>
<div class="torn-divider divider-right"></div>
<div class="confirm-wrap" style="display: none;" tabindex="0">
<span class="confirm">
<span>
Are you sure you would like to buy
</span>
<span>
<span class="count">100</span>
x Bottle of Beer for
$<span class="total">1,000</span>
</span>
<span class="confirm-act m-top5">
<a class="wai-support yes m-right10 bold t-blue h" data-id="180" href="#" i-data="i_966_379_24_14">
Yes
</a>
<span class="no bold">
<a class="wai-support t-blue h" href="#" i-data="i_1001_379_16_14">
No
</a>
</span>
</span>
</span>
<div class="confirm-wrap" tabindex="0">
<span class="confirm">
<span>
Are you sure you would like to buy
</span>
<span>
<span class="count"></span>
x Bottle of Beer for
$<span class="total"></span>
</span>
<span class="confirm-act m-top5">
<a class="wai-support yes m-right10 bold t-blue h" data-id="180" href="#">
Yes
</a>
<span class="no bold">
<a class="wai-support t-blue h" href="#">
No
</a>
</span>
</span>
</span>
</div>
<div class="success-wrap" style="display: none;">
<span class="success"><span class="t-green bold"></span>
<span class="confirm-act m-top5"></span></span>
<button aria-label="Close" class="close-icon p0 wai-btn" i-data="i_1101_344_10_11" value="100"></button>
<div class="success-wrap">
<span class="success">
<span class="t-green bold">
<span class="ajax-preloader"></span>
</span>
</span>
<button aria-label="Close" class="close-icon p0 wai-btn" value="100"></button>
</div>
<div class="msg-wrap">
<span class="t-green bold">
<span class="ajax-preloader"></span>
</span>
</div>
</div>
<div class="view-item-info">
<div class="item-cont">
<div class="item-wrap">
<span class="ajax-preloader m-top10 m-bottom10"></span>
</div>
<span class="t-green bold">
<span class="ajax-preloader"></span>
</span>
</div>
</div>

View File

@ -1,47 +1,57 @@
import WuhuBase from "./class/WuhuBase";
import WuHuTornHelper from "./class/WuhuTornHelper";
import { Common } from "./class/Common";
import UrlRouter from "./class/UrlRouter";
import translateMain from "./func/translate/translateMain";
import CommonUtils from "./class/utils/CommonUtils";
import LocalConfigWrapper from "./class/LocalConfigWrapper";
import ClassName from "./container/ClassName";
import { Injectable } from "./container/Injectable";
import Interrupt from "./class/Interrupt"
import Initializer from "./class/Initializer"
// import { Common } from "./class/Common"
// import UrlRouter from "./class/UrlRouter"
import translateMain from "./func/translate/translateMain"
import CommonUtils from "./class/utils/CommonUtils"
import LocalConfigWrapper from "./class/LocalConfigWrapper"
import ClassName from "./container/ClassName"
import { Injectable } from "./container/Injectable"
import FeatureMan from "./man/FeatureMan"
import Logger from "./class/Logger"
@ClassName('Application')
@Injectable()
export default class App {
private readonly logger = Logger.factory(App)
constructor(
// private readonly icon: ZhongIcon,
private readonly wuhuBase: WuhuBase,
private readonly tornHelper: WuHuTornHelper,
private readonly common: Common,
private readonly urlRouter: UrlRouter,
private readonly interrupt: Interrupt,
private readonly initializer: Initializer,
// private readonly common: Common,
// private readonly urlRouter: UrlRouter,
private readonly configWrapper: LocalConfigWrapper,
private readonly utils: CommonUtils,
private readonly featureMan: FeatureMan,
) {
}
public run() {
this.wuhuBase.conditionInterrupt();
this.interrupt.conditionInterrupt();
// 初始化
this.tornHelper.init();
this.initializer.init();
// this.featureMan.fStart().then(() => this.featureMan.printTable());
// 插件图标和设置菜单
// this.icon.init();
let tmp = () => {
// 所有页面通用
try {
// this.common.resolve.apply(this.common, this.run);
this.common.resolve(() => this.run());
} catch (e) {
}
// // 所有页面通用
// try {
// // this.common.resolve.apply(this.common, this.run);
// // this.common.resolve(() => this.run());
// } catch (e) {
// }
(async function (self: App) {
await self.featureMan.fStart()
self.featureMan.printTable()
})(this)
// URL匹配
this.urlRouter.resolve();
// this.urlRouter.resolve();
// 翻译
if (this.configWrapper.config.transEnable)

View File

@ -1,152 +1,160 @@
import depoHelper from "../func/module/depoHelper";
import TravelHelper from "../func/module/travelHelper";
import priceWatcherHandle from "../func/module/priceWatcherHandle";
import CompanyHelper from "./action/CompanyHelper";
import AttackHelper from "./action/AttackHelper";
import SidebarHelper from "./action/SidebarHelper";
import CommonUtils from "./utils/CommonUtils";
import FetchUtils from "./utils/FetchUtils";
import FetchEventCallback from "./action/FetchEventCallback";
import globVars from "../globVars";
import TranslateNew from "./action/TranslateNew";
import ClassName from "../container/ClassName";
import { Injectable } from "../container/Injectable";
import LocalConfigWrapper from "./LocalConfigWrapper";
import Logger from "./Logger";
import BuyBeerHelper from "./action/BuyBeerHelper";
import ModuleLoader from "./ModuleLoader";
import TornPDAUtils from "./utils/TornPDAUtils";
import TravelItem from "./action/TravelItem";
import IconHelper from "./IconHelper";
import MsgWrapper from "./utils/MsgWrapper";
import toThousands from "../func/utils/toThousands";
import { WHIntervalLoader } from "./interval/IntervalUnit";
/**
*
*/
@Injectable()
@ClassName('Common')
export class Common {
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly fetchEventCallback: FetchEventCallback,
private readonly translateNew: TranslateNew,
private readonly tornPDAUtils: TornPDAUtils,
private readonly logger: Logger,
private readonly buyBeerHelper: BuyBeerHelper,
private readonly fetchUtils: FetchUtils,
private readonly moduleLoader: ModuleLoader,
private readonly msgWrapper: MsgWrapper,
) {
}
public resolve(mainMethod) {
// window.setInterval(()=>this.msgWrapper.create('test',{sysNotify:true},'info'),2000);
// fetch方法处理
globVars.responseHandlers.push(
(...args: any[]) => this.fetchEventCallback.responseHandler.apply(this.fetchEventCallback, args)
);
// fetch方法处理-翻译
globVars.responseHandlers.push(
(...args: any[]) => this.translateNew.responseHandler.apply(this.translateNew, args)
);
// 价格监控
priceWatcherHandle(this.tornPDAUtils.isPDA(), this.tornPDAUtils.APIKey);
// 啤酒提醒
if (this.localConfigWrapper.config._15Alarm) this.buyBeerHelper.start();
this.moduleLoader.push(SidebarHelper);
this.moduleLoader.push(TravelItem);
this.moduleLoader.push(WHIntervalLoader)
/**
* ()
* All('script[src*="google"]')
* All('#gtm_tag')
* All('script[src*="chat/gonline"]')
* All('head script[nonce]')
*/
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);
mainMethod();
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();
});
}
// 存钱相关
depoHelper();
// 飞行相关
this.moduleLoader.push(TravelHelper);
// 战斗相关
this.moduleLoader.push(AttackHelper);
// 公司助手
this.moduleLoader.push(CompanyHelper);
// TODO 新菜单
this.moduleLoader.push(IconHelper);
this.moduleLoader.load().then();
// 自定义CSS
if (this.localConfigWrapper.config.CustomCss) {
this.logger.info('应用自定义CSS');
CommonUtils.addStyle(this.localConfigWrapper.config.CustomCss);
}
// 现金变动提醒
if (this.localConfigWrapper.config.CashChangeAlert) CommonUtils.elementReady("#user-money").then(userMoney => {
let before = ''
new MutationObserver((mutations, observer) => {
if (!this.localConfigWrapper.config.CashChangeAlert) {
observer.disconnect();
this.msgWrapper.create('现金变动提醒已关闭', { sysNotify: true });
return;
}
this.logger.info("现金变动提醒", mutations);
mutations.forEach(item => {
if (item.attributeName === 'data-money') {
let change = userMoney.innerText
.trim()
.replaceAll(/[,$]/g, '')
if (change !== before) {
this.msgWrapper.create(
'现金变动 ' + item.oldValue + ' --> ' + toThousands(change),
{ sysNotify: true }
);
before = change
}
}
});
}).observe(userMoney, { attributes: true, attributeOldValue: true })
});
}
}
// import depoHelper from "../func/module/depoHelper";
// import TravelHelper from "../feature/TravelHelper";
// import priceWatcherHandle from "../func/module/priceWatcherHandle";
// import CompanyHelper from "../feature/CompanyHelper";
// import AttackHelper from "./action/AttackHelper";
// import SidebarHelper from "../feature/SidebarHelper";
// import CommonUtils from "./utils/CommonUtils";
// import FetchUtils from "./utils/FetchUtils";
// import FetchEventCallback from "./action/FetchEventCallback";
// import globVars from "../globVars";
// import TranslateNew from "./action/TranslateNew";
// import ClassName from "../container/ClassName";
// import { Injectable } from "../container/Injectable";
// import LocalConfigWrapper from "./LocalConfigWrapper";
// import Logger from "./Logger";
// import BuyBeerHelper from "../feature/BuyBeerHelper";
// import ModuleLoader from "./ModuleLoader";
// import TornPDAUtils from "./utils/TornPDAUtils";
// import TravelItem from "../feature/TravelItem";
// import IconHelper from "../feature/IconHelper";
// import MsgWrapper from "./utils/MsgWrapper";
// import toThousands from "../func/utils/toThousands";
// import { WHIntervalLoader } from "../monitor/WHIntervalLoader";
//
// /**
// * 脚本不区分页面的通用功能入口
// */
// @Injectable()
// @ClassName('Common')
// export class Common {
// private readonly logger = Logger.factory(Common)
//
// constructor(
// private readonly localConfigWrapper: LocalConfigWrapper,
// // private readonly fetchEventCallback: FetchEventCallback,
// // private readonly translateNew: TranslateNew,
// // private readonly tornPDAUtils: TornPDAUtils,
// // private readonly buyBeerHelper: BuyBeerHelper,
// // private readonly fetchUtils: FetchUtils,
// // private readonly moduleLoader: ModuleLoader,
// private readonly msgWrapper: MsgWrapper,
// ) {
// }
//
// public resolve(mainMethod) {
// // window.setInterval(()=>this.msgWrapper.create('test',{sysNotify:true},'info'),2000);
//
// // // fetch方法处理
// // globVars.responseHandlers.push(
// // (...args: any[]) => this.fetchEventCallback.responseHandler.apply(this.fetchEventCallback, args)
// // );
// // // fetch方法处理-翻译
// // globVars.responseHandlers.push(
// // (...args: any[]) => this.translateNew.responseHandler.apply(this.translateNew, args)
// // );
//
// // // 价格监控
// // priceWatcherHandle(this.tornPDAUtils.isPDA(), this.tornPDAUtils.APIKey);
//
// // 啤酒提醒
// // if (this.localConfigWrapper.config._15Alarm) this.buyBeerHelper.start();
//
// // this.moduleLoader.push(SidebarHelper);
// // this.moduleLoader.push(TravelItem);
// // this.moduleLoader.push(WHIntervalLoader)
//
// /**
// * 解决一直转圈(加载中)的问题
// * 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);
// // mainMethod();
// // 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 {
// // depoHelper();
// // } catch (e) {
// // this.logger.error('【存钱相关】错误',e)
// // }
//
// // // 飞行相关
// // this.moduleLoader.push(TravelHelper);
//
// // 战斗相关
// // this.moduleLoader.push(AttackHelper);
//
// // 公司助手
// // this.moduleLoader.push(CompanyHelper);
//
// // // 菜单
// // this.moduleLoader.push(IconHelper);
//
// // this.moduleLoader.load().then();
//
// // // 自定义CSS
// // if (this.localConfigWrapper.config.CustomCss) {
// // this.logger.info('应用自定义CSS');
// // CommonUtils.addStyle(this.localConfigWrapper.config.CustomCss);
// // }
// //
// // // 现金变动提醒
// // if (this.localConfigWrapper.config.CashChangeAlert) CommonUtils.elementReady("#user-money").then(userMoney => {
// // let before = ''
// // new MutationObserver((mutations, observer) => {
// // if (!this.localConfigWrapper.config.CashChangeAlert) {
// // observer.disconnect();
// // this.msgWrapper.create('现金变动提醒已关闭', { sysNotify: true });
// // return;
// // }
// // this.logger.info("现金变动提醒", mutations);
// // mutations.forEach(item => {
// // if (item.attributeName === 'data-money') {
// // let change = userMoney.innerText
// // .trim()
// // .replaceAll(/[,$]/g, '')
// // if (change !== before) {
// // this.msgWrapper.create(
// // '现金变动 ' + item.oldValue + ' --> ' + toThousands(change),
// // { sysNotify: true }
// // );
// // before = change
// // }
// // }
// // });
// // }).observe(userMoney, { attributes: true, attributeOldValue: true })
// // });
// }
// }

View File

@ -1,62 +0,0 @@
import Logger, { LoggerKey } from "./Logger";
import ClassName from "../container/ClassName";
import { Injectable } from "../container/Injectable";
import CommonUtils, { CommonUtilsKey } from "./utils/CommonUtils";
import LocalConfigWrapper, { LocalConfigWrapperKey } from "./LocalConfigWrapper";
import NNB from "./handler/NNB";
import ItemPriceWatcherHandler from "./handler/ItemPriceWatcherHandler";
import { createApp } from "vue";
import FloatMenu from "../../vue/FloatMenu.vue";
import PopupWrapper, { PopupWrapperKey } from "./utils/PopupWrapper";
import InfoUtils from "./utils/InfoUtils";
import TravelItem, { TravelItemKey } from "./action/TravelItem";
import QuickGymTrain, { QuickGymTrainKey } from "./action/QuickGymTrain";
import QuickFlyBtnHandler, { QuickFlyBtnHandlerKey } from "./handler/QuickFlyBtnHandler";
import ItemHelper, { ItemHelperKey } from "./utils/ItemHelper";
import MathUtils, { MathUtilsKey } from "./utils/MathUtils";
@ClassName("IconHelper")
@Injectable()
export default class IconHelper {
private readonly _element: HTMLElement;
constructor(
private readonly logger: Logger,
private readonly commonUtils: CommonUtils,
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly nnb: NNB,
private readonly itemPriceWatcherHandler: ItemPriceWatcherHandler,
private readonly popupWrapper: PopupWrapper,
private readonly infoUtils: InfoUtils,
private readonly travelItem: TravelItem,
private readonly quickGymTrain: QuickGymTrain,
private readonly quickFlyBtnHandler: QuickFlyBtnHandler,
private readonly itemHelper: ItemHelper,
private readonly mathUtils: MathUtils,
) {
this._element = document.createElement('div');
}
get element() {
return this._element;
}
init() {
this._element.id = 'WHMenu2023';
document.body.append(this._element);
let app = createApp(FloatMenu);
app.config.errorHandler = (err) => this.logger.error('[VUE错误]', err);
app.config.warnHandler = (err) => this.logger.warn('[VUE警告]', err);
app.provide(LoggerKey, this.logger);
app.provide(CommonUtilsKey, this.commonUtils);
app.provide(MathUtilsKey, this.mathUtils);
app.provide(TravelItemKey, this.travelItem);
app.provide(PopupWrapperKey, this.popupWrapper);
app.provide(LocalConfigWrapperKey, this.localConfigWrapper);
app.provide(QuickGymTrainKey, this.quickGymTrain);
app.provide(QuickFlyBtnHandlerKey, this.quickFlyBtnHandler);
app.provide(ItemHelperKey, this.itemHelper);
app.mount(this._element);
}
}

View File

@ -6,24 +6,35 @@ import { Injectable } from "../container/Injectable";
import ClassName from "../container/ClassName";
import Logger from "./Logger";
import InfoUtils from "./utils/InfoUtils";
import FetchEventCallback from "./action/FetchEventCallback";
import TranslateNew from "./action/TranslateNew";
import priceWatcherHandle from "../func/module/priceWatcherHandle";
import TornPDAUtils from "./utils/TornPDAUtils";
import LocalConfigWrapper from "./LocalConfigWrapper";
import depoHelper from "../func/module/depoHelper";
import toThousands from "../func/utils/toThousands";
import MsgWrapper from "./utils/MsgWrapper";
import FetchUtils from "./utils/FetchUtils";
@Injectable()
@ClassName('WuHuTornHelper')
export default class WuHuTornHelper {
@ClassName('Initializer')
export default class Initializer {
private readonly logger: Logger = Logger.factory(Initializer)
constructor(
// private readonly travelItem: TravelItem,
private readonly global: Global,
private readonly logger: Logger,
private readonly infoUtils: InfoUtils,
private readonly commonUtils: CommonUtils,
private readonly fetchEventCallback: FetchEventCallback,
private readonly translateNew: TranslateNew,
private readonly tornPDAUtils: TornPDAUtils,
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly msgWrapper: MsgWrapper,
private readonly fetchUtils: FetchUtils,
) {
}
public init() {
// this.logger.info('WuHuTornHelper初始化');
// WuhuBase.glob = this.global;
let glob = this.global;
// glob.fStock = this.travelItem;
// 请求通知权限
if (window.Notification) {
@ -176,6 +187,97 @@ export default class WuHuTornHelper {
document.documentElement.classList.add("d");
document.body.classList.add("scrollbar-transparent");
// fetch方法处理
globVars.responseHandlers.push(
(...args: any[]) => this.fetchEventCallback.responseHandler.apply(this.fetchEventCallback, args)
);
// fetch方法处理-翻译
globVars.responseHandlers.push(
(...args: any[]) => this.translateNew.responseHandler.apply(this.translateNew, args)
);
// 价格监控 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)
}
// 存钱相关
try {
depoHelper();
} catch (e) {
this.logger.error('【存钱相关】错误', e)
}
// 自定义CSS
if (this.localConfigWrapper.config.CustomCss) {
this.logger.info('应用自定义CSS');
CommonUtils.addStyle(this.localConfigWrapper.config.CustomCss);
}
// 现金变动提醒
if (this.localConfigWrapper.config.CashChangeAlert) CommonUtils.elementReady("#user-money").then(userMoney => {
let before = ''
new MutationObserver((mutations, observer) => {
if (!this.localConfigWrapper.config.CashChangeAlert) {
observer.disconnect();
this.msgWrapper.create('现金变动提醒已关闭', { sysNotify: true });
return;
}
this.logger.info("现金变动提醒", mutations);
mutations.forEach(item => {
if (item.attributeName === 'data-money') {
let change = userMoney.innerText
.trim()
.replaceAll(/[,$]/g, '')
if (change !== before) {
this.msgWrapper.create(
'现金变动 ' + item.oldValue + ' --> ' + toThousands(change),
{ sysNotify: true }
);
before = change
}
}
});
}).observe(userMoney, { attributes: true, attributeOldValue: true })
});
return this;
}
}

View File

@ -2,12 +2,9 @@ import ClassName from "../container/ClassName";
import { Injectable } from "../container/Injectable";
@ClassName('WuhuBase')
@ClassName('Interrupt')
@Injectable()
export default class WuhuBase {
constructor() {
}
export default class Interrupt {
public conditionInterrupt() {
let title: HTMLElement | { innerText: string } = (document.querySelector('#skip-to-content') ||
@ -17,6 +14,6 @@ export default class WuhuBase {
title.innerText.toLowerCase().includes('please validate') ||
document.querySelector('div.container div.cf .iAmUnderAttack') !== null
);
if (condition) throw '芜湖';
if (condition) throw new Error('芜湖');
}
}

View File

@ -1,3 +1,4 @@
import "reflect-metadata";
import ClassName, { GetClassName } from "../container/ClassName";
import { Injectable } from "../container/Injectable";
import Log from "./Log";
@ -30,7 +31,7 @@ export default class Logger {
return Log.getTime()
}
static factory(classT: new(...args) => any): Logger {
static factory<T>(classT: ClassType<T>): Logger {
let className = GetClassName(classT);
return new class extends Logger {
info(...o: any): void {

View File

@ -6,23 +6,24 @@ import { Injectable } from "../container/Injectable";
@ClassName('ModuleLoader')
@Injectable()
export default class ModuleLoader {
private readonly classes: any[] = [];
private readonly classes: (new(...arg: any) => { init: () => void })[] = [];
private readonly logger = Logger.factory(ModuleLoader)
constructor(
private readonly logger: Logger,
) {
}
// constructor() {
// }
/**
*
* @param method 'init'
*/
public async load(method: string = 'init'): Promise<void> {
this.classes.forEach(clas => {
this.logger.info('即将加载: ', this.classes)
this.classes.forEach(clazz => {
try {
Container.factory(clas)[method]();
this.logger.info('正在加载' + GetClassName(clazz))
Container.factory(clazz)[method]();
} catch (e) {
this.logger.error('ModuleLoader 加载[' + GetClassName(clas) + ']时出错', e.message, e.stack);
this.logger.error('加载[' + GetClassName(clazz) + ']时出错', e.message, e.stack);
}
});
this.classes.length = 0;

View File

@ -7,11 +7,11 @@ import ADD_BEER_HEAD_HTML from "../../static/html/buyBeer/add_beer_head.html";
import QUICK_CRIMES_HTML from "../../static/html/quick_crimes.html";
import RW_RIDER_HTML from "../../static/html/rw_rider.html";
import christmasTownHelper from "../func/module/christmasTownHelper";
import LotteryHelper from "./action/LotteryHelper";
import LotteryHelper from "../feature/LotteryHelper";
import TornStyleBlock from "./utils/TornStyleBlock";
import PTHelper from "./action/PTHelper";
import StackHelper from "./action/StackHelper";
import BuyBeerHelper from "./action/BuyBeerHelper";
import StackHelper from "../feature/StackHelper";
import BuyBeerHelper from "../feature/BuyBeerHelper";
import XZMZ from "./action/XZMZ";
import ProfileHelper from "./action/ProfileHelper";
import SearchHelper from "./action/SearchHelper";

View File

@ -5,7 +5,7 @@ import CommonUtils from "./utils/CommonUtils";
import * as EVENTS from "../../static/json/event.json";
import * as FEST from "../../static/json/fest.json";
import Popup from "./utils/Popup";
import TravelItem from "./action/TravelItem";
import TravelItem from "../feature/TravelItem";
import ZHONG_MENU_HTML from "../../static/html/zhong/zhong_menu.html";
import ZHONG_UPDATE_HTML from "../../static/html/zhong/zhong_update.html";
import ZHONG_LOOT_HTML from "../../static/html/zhong/zhong_loot.html";
@ -15,7 +15,7 @@ import QuickFlyBtnHandler from "./handler/QuickFlyBtnHandler";
import NNB from "./handler/NNB";
import QuickLinksHandler from "./handler/QuickLinksHandler";
import ItemPriceWatcherHandler from "./handler/ItemPriceWatcherHandler";
import ChangeLogHandler from "./handler/ChangeLogHandler";
// import ChangeLogHandler from "./handler/ChangeLogHandler";
import ItemPriceHandler from "./handler/ItemPriceHandler";
import SettingsHandler from "./handler/SettingsHandler";
import { MENU_ITEM_TYPE } from "../interface/MenuItem";
@ -417,7 +417,7 @@ export default class ZhongIcon {
// 物品查价
list.push(ItemPriceHandler);
// 更新历史
list.push(ChangeLogHandler);
// list.push(ChangeLogHandler);
// 助手设置
list.push(SettingsHandler);
// 测试

View File

@ -1,358 +1,352 @@
import CommonUtils from "../utils/CommonUtils";
import Alert from "../utils/Alert";
import Global from "../Global";
import Device from "../../enum/Device";
import ATTACK_HELPER_CSS from "../../../static/css/attack_helper.module.css";
import ActionButtonUtils from "../utils/ActionButtonUtils";
import TornStyleBlock from "../utils/TornStyleBlock";
import TornStyleSwitch from "../utils/TornStyleSwitch";
import DialogMsgBox from "../utils/DialogMsgBox";
import FetchUtils from "../utils/FetchUtils";
import MathUtils from "../utils/MathUtils";
import LoopHelper from "../utils/LoopHelper";
import TRAVEL_STATE from "../../enum/TravelState";
import { Injectable } from "../../container/Injectable";
import ClassName from "../../container/ClassName";
import LocalConfigWrapper from "../LocalConfigWrapper";
import Logger from "../Logger";
enum FIGHT_STAGE {
READY = 'ready',
IN_PROGRESS_OR_ERROR = 'in_progress_or_error',
FINISHED = 'finished',
END = 'end',
OTHER = 'other'
}
/**
*
* TODO
*/
@Injectable()
@ClassName('AttackHelper')
export default class AttackHelper {
private currentStage: FIGHT_STAGE = FIGHT_STAGE.OTHER;
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly commonUtils: CommonUtils,
private readonly global: Global,
private readonly mathUtils: MathUtils,
private readonly actionButtonUtils: ActionButtonUtils,
private readonly fetchUtils: FetchUtils,
private readonly logger: Logger,
) {
}
init(): void {
window.setTimeout(() => this._init(), 0);
}
private _init() {
if (window.location.href.contains(/loader\.php\?sid=attack/)) {
this.fightingPageHandle();
}
// 错误的攻击页面转跳
else if (window.location.href.includes('loader2.php') && this.localConfigWrapper.config.attRelocate) {
const spl = window.location.href.trim().split('=');
const uid = spl[spl.length - 1];
if (this.commonUtils.isValidUid(uid)) {
window.location.href = 'https://www.torn.com/loader.php?sid=attack&user2ID=' + uid;
} else {
this.logger.error('[AttackHelper] UID格式不正确');
}
}
}
private fightingPageHandle(): void {
// 光速刷新按钮
this.actionButtonUtils.add('光速刷新', () => this.doAttackReload());
// 盯梢
this.watchTarget();
new MutationObserver((_, observer) => {
let btnList = document.querySelectorAll('div[class^="dialogButtons___"] button') as NodeListOf<HTMLButtonElement>;
if (btnList.length === 0) {
if (this.currentStage === FIGHT_STAGE.READY && this.localConfigWrapper.config.quickFinishAtt === 3) {
document.body.classList.remove('wh-move-btn');
this.logger.info('移除body class wh-move-btn');
observer.disconnect();
}
// 错误或正在打
this.currentStage = FIGHT_STAGE.IN_PROGRESS_OR_ERROR;
this.logger.info('[attackHelper] currentStage', this.currentStage);
return;
}
btnList.forEach(btn => {
let btnText = btn.innerText.toLowerCase();
if (btnText.includes('start') || btnText.includes('join')) {
// 开始
this.quickStartFight();
} else if (btnText.includes('continue')) {
// 结束end
this.currentStage = FIGHT_STAGE.END;
observer.disconnect();
} else if (btnText.includes('leave')) {
// 无意识状态FINISHED
this.quickFinishFight(btnList);
}
this.logger.info('[attackHelper] currentStage', this.currentStage);
})
})
.observe(document.querySelector('#react-root'), { childList: true, subtree: true });
}
// 战斗页面快速刷新
private doAttackReload(): void {
if (!window.ReactDOM) {
new Alert('光速刷新失败未找到React对象');
this.logger.error('光速刷新失败未找到React对象');
return;
}
if (!document.querySelector('#react-root #attacker')) {
this.logger.error('dom元素未找到selector: [#react-root #attacker]');
return;
}
let script = document.querySelector('script[src*="/builds/attack/"]');
let url = script.src;
if (!url.contains(/runtime\..+\.js/)) {
this.logger.error('脚本源[' + url + '] 不匹配规则');
return;
}
window.ReactDOM.unmountComponentAtNode(document.querySelector('#react-root'));
script.remove();
let node = document.createElement('script');
node.src = url;
node.type = 'text/javascript';
document.head.appendChild(node);
}
// 光速拔刀
private quickStartFight(): void {
if (this.currentStage === FIGHT_STAGE.READY) {
return;
} else {
this.currentStage = FIGHT_STAGE.READY;
}
if (this.localConfigWrapper.config.quickAttIndex === 6) return;
/**
* pc #defender
* mobile #attacker
*/
const btn = <HTMLInputElement>(document.querySelector('#attacker button') || document.querySelector('#defender button'));
this.logger.info('操作按钮', { btn });
if (!btn.innerText.toLowerCase().includes('fight')) {
this.logger.info('未找到攻击按钮, 光速拔刀跳过');
new Alert('未找到攻击按钮, 光速拔刀跳过');
} else {
// 判断是否存在脚踢
const hasKick = !!document.querySelector('#weapon_boots');
// modal层
// const modal: HTMLElement = document.querySelector('div[class^="modal___"]');
let device = this.global.device;
this.logger.info(`当前设备类型是${ device }`);
// 区分设备
switch (device) {
case Device.PC: {
this.logger.info(`开始调整按钮位置`);
// 隐藏modal层
// modal.style.display = 'none';
// 根据选择的武器调整css
let css_top = '0';
switch (this.localConfigWrapper.config.quickAttIndex) {
// weapon_second
case 1: {
css_top = '97px';
break;
}
// weapon_melee
case 2: {
css_top = '194px';
break;
}
// weapon_temp
case 3: {
css_top = '291px';
break;
}
// weapon_fists
case 4:
// weapon_boots
case 5: {
css_top = '375px';
break;
}
}
this.commonUtils.styleInject(ATTACK_HELPER_CSS);
CommonUtils.addStyle(`.wh-move-btn #defender div[class^="modal___"]{top: ${ css_top };}`);
document.body.classList.add('wh-move-btn');
break;
}
case Device.MOBILE: {
this.logger.info(`开始调整按钮位置`);
// 加入css
let css_top = '0';
let slot_height = '76px';
// 判断有没有脚踢
if (hasKick) {
// 根据选择的武器调整
switch (this.localConfigWrapper.config.quickAttIndex) {
case 1: { // weapon_second
css_top = '76px';
break;
}
case 2: { // weapon_melee
css_top = '152px';
break;
}
case 3: { // weapon_temp
css_top = '228px';
break;
}
case 4: { // weapon_fists
css_top = '304px';
break;
}
case 5: { // weapon_boots
css_top = '380px';
break;
}
}
} else {
const slot = document.querySelector('#weapon_main') as HTMLElement;
const height = slot.offsetHeight + 1;
// TODO 待验证
slot_height = height + 'px';
// 根据选择的武器调整
switch (this.localConfigWrapper.config.quickAttIndex) {
case 1: { // weapon_second
css_top = `${ height }px`;
break;
}
case 2: { // weapon_melee
css_top = `${ height * 2 }px`;
break;
}
case 3: { // weapon_temp
css_top = `${ height * 3 }px`;
break;
}
case 4: { // weapon_fists
css_top = `${ height * 4 }px`;
break;
}
case 5: { // weapon_boots
css_top = `${ height * 5 }px`;
break;
}
}
}
const css_rule = ATTACK_HELPER_CSS.replace('CSSVAR', css_top).replace('CSSVAR', slot_height);
// `
// .wh-move-btn #attacker div[class^="modal___"]{display: block;width: 0;top: ${ css_top };left:0;height:0;}
// .wh-move-btn #attacker div[class^="dialog___"]{border:0;width:80px;height:${ slot_height };}
// .wh-move-btn #attacker div[class^="colored___"]{display:block;padding:0;}
// .wh-move-btn #attacker div[class^="title___"]{height:0;}
// .wh-move-btn #attacker button{width:100%;margin:0;height:63px;white-space:normal;}
// `;
this.commonUtils.styleInject(css_rule);
document.body.classList.toggle('wh-move-btn');
btn.onclick = () => {
if (this.localConfigWrapper.config.quickFinishAtt !== 3) {
btn.remove();
// 停止自动刷新
// stop_reload = true;
} else {
document.body.classList.toggle('wh-move-btn');
}
};
break;
}
case Device.TABLET: {
break;
}
}
}
}
// 光速跑路
private quickFinishFight(btnList: NodeListOf<HTMLButtonElement>): void {
if (this.currentStage === FIGHT_STAGE.FINISHED) {
return;
} else {
this.currentStage = FIGHT_STAGE.FINISHED;
}
if (this.localConfigWrapper.config.quickFinishAtt === 3) {
document.body.classList.remove('wh-move-btn');
this.logger.info('移除body class wh-move-btn');
return;
}
const user_btn_select = ['leave', 'mug', 'hosp'][this.localConfigWrapper.config.quickFinishAtt];
// const wrap = document.querySelector('#react-root');
this.logger.info('光速跑路选项选中:', user_btn_select);
// const btn_arr: HTMLButtonElement[] = document.querySelectorAll('div[class^="dialogButtons___"] button') as unknown as HTMLButtonElement[];
if (btnList.length > 1) btnList.forEach(btn => {
const flag = btn.innerText.toLowerCase().includes(user_btn_select);
this.logger.info('按钮内容:', btn.innerText, ',是否包含选中:', flag);
if (!flag) btn.style.display = 'none';
});
}
// 盯梢模式
private watchTarget(): void {
this.logger.info('获取目标id');
let targetId = window.location.href.split('user2ID=')[1];
if (!this.commonUtils.isValidUid(targetId)) {
this.logger.error('目标id获取错误', targetId);
throw new Error('目标id获取错误:' + targetId);
}
let loop = new LoopHelper(async () => {
let userProfile;
try {
userProfile = await this.fetchUtils.getProfile(targetId);
} catch {
this.logger.error('盯梢模式无法获取目标id');
throw new Error('盯梢模式无法获取目标id');
}
await this.commonUtils.sleep(this.mathUtils.getRandomInt(20, 50));
if ((userProfile.userStatus.status === 'ok' && this.commonUtils.getTravelStage() === TRAVEL_STATE.IN_TORN) ||
(userProfile.userStatus.status === 'abroad' && this.commonUtils.getTravelStage() === TRAVEL_STATE.ABROAD)) {
watchSwitch.getInput().checked = false;
window.setTimeout(async () => {
new Alert('目标已落地/出院/出狱!', { timeout: 10, force: true, sysNotify: true });
await this.commonUtils.audioPlay();
await this.commonUtils.sleep(300);
await this.commonUtils.audioPlay();
await this.commonUtils.sleep(300);
await this.commonUtils.audioPlay();
await this.commonUtils.sleep(300);
}, 0);
}
});
let block = new TornStyleBlock('盯梢模式').insert2Dom();
let watchSwitch = new TornStyleSwitch('开启');
block.append(watchSwitch.getBase());
watchSwitch.getInput().addEventListener('change', () => {
if (watchSwitch.getInput().checked) {
new DialogMsgBox('检测玩家状态,当目标状态变成(海外)落地、出院或出狱时通知并播放声音提醒,后可搭配光速刷新食用<br/>确定开启?', {
callback: () => {
if (this.commonUtils.getTravelStage() === TRAVEL_STATE.FLYING) {
new Alert('失败!已取消');
watchSwitch.getInput().checked = false;
return;
}
this.logger.info('盯梢开启, 目标id' + targetId);
loop.start(this.localConfigWrapper.config.WatchTargetFreq | 0);
},
cancel: () => watchSwitch.getInput().checked = false
});
} else {
loop.stop();
this.logger.info('盯梢关闭');
}
});
}
}
// import CommonUtils from "../utils/CommonUtils";
// import Alert from "../utils/Alert";
// import Global from "../Global";
// import Device from "../../enum/Device";
// import ATTACK_HELPER_CSS from "../../../static/css/attack_helper.module.css";
// import ActionButtonUtils from "../utils/ActionButtonUtils";
// import TornStyleBlock from "../utils/TornStyleBlock";
// import TornStyleSwitch from "../utils/TornStyleSwitch";
// import DialogMsgBox from "../utils/DialogMsgBox";
// import FetchUtils from "../utils/FetchUtils";
// import MathUtils from "../utils/MathUtils";
// import LoopHelper from "../utils/LoopHelper";
// import TRAVEL_STATE from "../../enum/TravelState";
// import { Injectable } from "../../container/Injectable";
// import ClassName from "../../container/ClassName";
// import LocalConfigWrapper from "../LocalConfigWrapper";
// import Logger from "../Logger";
//
// enum FIGHT_STAGE {
// READY = 'ready',
// IN_PROGRESS_OR_ERROR = 'in_progress_or_error',
// FINISHED = 'finished',
// END = 'end',
// OTHER = 'other'
// }
//
// /**
// * 战斗助手
// * TODO 页面加载已经在进行中的战斗时的正确判断
// */
// @Injectable()
// @ClassName('AttackHelper')
// export default class AttackHelper {
//
// private currentStage: FIGHT_STAGE = FIGHT_STAGE.OTHER;
//
// constructor(
// private readonly localConfigWrapper: LocalConfigWrapper,
// private readonly commonUtils: CommonUtils,
// private readonly global: Global,
// private readonly mathUtils: MathUtils,
// private readonly actionButtonUtils: ActionButtonUtils,
// private readonly fetchUtils: FetchUtils,
// private readonly logger: Logger,
// ) {
// }
//
// init(): void {
// window.setTimeout(() => this._init(), 0);
// }
//
// private _init() {
// if (window.location.href.contains(/loader\.php\?sid=attack/)) {
// this.fightingPageHandle();
// }
// // 错误的攻击页面转跳
// // else if (window.location.href.includes('loader2.php') && this.localConfigWrapper.config.attRelocate) {
// // const spl = window.location.href.trim().split('=');
// // const uid = spl[spl.length - 1];
// // if (this.commonUtils.isValidUid(uid)) {
// // window.location.href = 'https://www.torn.com/loader.php?sid=attack&user2ID=' + uid;
// // } else {
// // this.logger.error('[AttackHelper] UID格式不正确');
// // }
// // }
// }
//
// private fightingPageHandle(): void {
// // 光速刷新按钮
// this.actionButtonUtils.add('光速刷新', () => this.doAttackReload());
//
// // 盯梢
// this.watchTarget();
//
// new MutationObserver((_, observer) => {
// let btnList = document.querySelectorAll('div[class^="dialogButtons___"] button') as NodeListOf<HTMLButtonElement>;
//
// if (btnList.length === 0) {
// if (this.currentStage === FIGHT_STAGE.READY && this.localConfigWrapper.config.quickFinishAtt === 3) {
// document.body.classList.remove('wh-move-btn');
// this.logger.info('移除body class wh-move-btn');
// observer.disconnect();
// }
// // 错误或正在打
// this.currentStage = FIGHT_STAGE.IN_PROGRESS_OR_ERROR;
// this.logger.info('[attackHelper] currentStage', this.currentStage);
// return;
// }
// btnList.forEach(btn => {
// let btnText = btn.innerText.toLowerCase();
// if (btnText.includes('start') || btnText.includes('join')) {
// // 开始
// this.quickStartFight();
// } else if (btnText.includes('continue')) {
// // 结束end
// this.currentStage = FIGHT_STAGE.END;
// observer.disconnect();
// } else if (btnText.includes('leave')) {
// // 无意识状态FINISHED
// this.quickFinishFight(btnList);
// }
// this.logger.info('[attackHelper] currentStage', this.currentStage);
// })
// })
// .observe(document.querySelector('#react-root'), { childList: true, subtree: true });
// }
//
// // 战斗页面快速刷新
// private doAttackReload(): void {
// if (!window.ReactDOM) {
// new Alert('光速刷新失败未找到React对象');
// this.logger.error('光速刷新失败未找到React对象');
// return;
// }
// if (!document.querySelector('#react-root #attacker')) {
// this.logger.error('dom元素未找到selector: [#react-root #attacker]');
// return;
// }
// let script = document.querySelector('script[src*="/builds/attack/"]');
// let url = script.src;
// if (!url.contains(/runtime\..+\.js/)) {
// this.logger.error('脚本源[' + url + '] 不匹配规则');
// return;
// }
// window.ReactDOM.unmountComponentAtNode(document.querySelector('#react-root'));
// script.remove();
// let node = document.createElement('script');
// node.src = url;
// node.type = 'text/javascript';
// document.head.appendChild(node);
// }
//
// // 光速拔刀
// private quickStartFight(): void {
// if (this.currentStage === FIGHT_STAGE.READY) {
// return;
// } else {
// this.currentStage = FIGHT_STAGE.READY;
// }
// if (this.localConfigWrapper.config.quickAttIndex === 6) return;
// /**
// * pc #defender
// * mobile #attacker
// */
// const btn = <HTMLInputElement>(document.querySelector('#attacker button') || document.querySelector('#defender button'));
// this.logger.info('操作按钮', { btn });
// if (!btn.innerText.toLowerCase().includes('fight')) {
// this.logger.info('未找到攻击按钮, 光速拔刀跳过');
// new Alert('未找到攻击按钮, 光速拔刀跳过');
// } else {
// // 判断是否存在脚踢
// const hasKick = !!document.querySelector('#weapon_boots');
// // modal层
// // const modal: HTMLElement = document.querySelector('div[class^="modal___"]');
// let device = this.global.device;
// this.logger.info(`当前设备类型是${ device }`);
// // 区分设备
// switch (device) {
// case Device.PC: {
// this.logger.info(`开始调整按钮位置`);
// // 隐藏modal层
// // modal.style.display = 'none';
// // 根据选择的武器调整css
// let css_top = '0';
// switch (this.localConfigWrapper.config.quickAttIndex) {
// // weapon_second
// case 1: {
// css_top = '97px';
// break;
// }
// // weapon_melee
// case 2: {
// css_top = '194px';
// break;
// }
// // weapon_temp
// case 3: {
// css_top = '291px';
// break;
// }
// // weapon_fists
// case 4:
// // weapon_boots
// case 5: {
// css_top = '375px';
// break;
// }
// }
// this.commonUtils.styleInject(ATTACK_HELPER_CSS);
// CommonUtils.addStyle(`.wh-move-btn #defender div[class^="modal___"]{top: ${ css_top };}`);
// document.body.classList.add('wh-move-btn');
// break;
// }
// case Device.MOBILE: {
// this.logger.info(`开始调整按钮位置`);
// // 加入css
// let css_top = '0';
// let slot_height = '76px';
// // 判断有没有脚踢
// if (hasKick) {
// // 根据选择的武器调整
// switch (this.localConfigWrapper.config.quickAttIndex) {
// case 1: { // weapon_second
// css_top = '76px';
// break;
// }
// case 2: { // weapon_melee
// css_top = '152px';
// break;
// }
// case 3: { // weapon_temp
// css_top = '228px';
// break;
// }
// case 4: { // weapon_fists
// css_top = '304px';
// break;
// }
// case 5: { // weapon_boots
// css_top = '380px';
// break;
// }
// }
// } else {
// const slot = document.querySelector('#weapon_main') as HTMLElement;
// const height = slot.offsetHeight + 1;
// // TODO 待验证
// slot_height = height + 'px';
// // 根据选择的武器调整
// switch (this.localConfigWrapper.config.quickAttIndex) {
// case 1: { // weapon_second
// css_top = `${ height }px`;
// break;
// }
// case 2: { // weapon_melee
// css_top = `${ height * 2 }px`;
// break;
// }
// case 3: { // weapon_temp
// css_top = `${ height * 3 }px`;
// break;
// }
// case 4: { // weapon_fists
// css_top = `${ height * 4 }px`;
// break;
// }
// case 5: { // weapon_boots
// css_top = `${ height * 5 }px`;
// break;
// }
// }
// }
// const css_rule = ATTACK_HELPER_CSS.replace('CSSVAR', css_top).replace('CSSVAR', slot_height);
//
// this.commonUtils.styleInject(css_rule);
// document.body.classList.toggle('wh-move-btn');
// btn.onclick = () => {
// if (this.localConfigWrapper.config.quickFinishAtt !== 3) {
// btn.remove();
// // 停止自动刷新
// // stop_reload = true;
// } else {
// document.body.classList.toggle('wh-move-btn');
// }
// };
// break;
// }
// case Device.TABLET: {
// break;
// }
// }
// }
// }
//
// // 光速跑路
// private quickFinishFight(btnList: NodeListOf<HTMLButtonElement>): void {
// if (this.currentStage === FIGHT_STAGE.FINISHED) {
// return;
// } else {
// this.currentStage = FIGHT_STAGE.FINISHED;
// }
// if (this.localConfigWrapper.config.quickFinishAtt === 3) {
// document.body.classList.remove('wh-move-btn');
// this.logger.info('移除body class wh-move-btn');
// return;
// }
// const user_btn_select = ['leave', 'mug', 'hosp'][this.localConfigWrapper.config.quickFinishAtt];
// // const wrap = document.querySelector('#react-root');
// this.logger.info('光速跑路选项选中:', user_btn_select);
// // const btn_arr: HTMLButtonElement[] = document.querySelectorAll('div[class^="dialogButtons___"] button') as unknown as HTMLButtonElement[];
// if (btnList.length > 1) btnList.forEach(btn => {
// const flag = btn.innerText.toLowerCase().includes(user_btn_select);
// this.logger.info('按钮内容:', btn.innerText, ',是否包含选中:', flag);
// if (!flag) btn.style.display = 'none';
// });
// }
//
// // 盯梢模式
// private watchTarget(): void {
// this.logger.info('获取目标id');
// let targetId = window.location.href.split('user2ID=')[1];
// if (!this.commonUtils.isValidUid(targetId)) {
// this.logger.error('目标id获取错误', targetId);
// throw new Error('目标id获取错误:' + targetId);
// }
// let loop = new LoopHelper(async () => {
// let userProfile;
// try {
// userProfile = await this.fetchUtils.getProfile(targetId);
// } catch {
// this.logger.error('盯梢模式无法获取目标id');
// throw new Error('盯梢模式无法获取目标id');
// }
// await this.commonUtils.sleep(this.mathUtils.getRandomInt(20, 50));
// if ((userProfile.userStatus.status === 'ok' && this.commonUtils.getTravelStage() === TRAVEL_STATE.IN_TORN) ||
// (userProfile.userStatus.status === 'abroad' && this.commonUtils.getTravelStage() === TRAVEL_STATE.ABROAD)) {
// watchSwitch.getInput().checked = false;
// window.setTimeout(async () => {
// new Alert('目标已落地/出院/出狱!', { timeout: 10, force: true, sysNotify: true });
// await this.commonUtils.audioPlay();
// await this.commonUtils.sleep(300);
// await this.commonUtils.audioPlay();
// await this.commonUtils.sleep(300);
// await this.commonUtils.audioPlay();
// await this.commonUtils.sleep(300);
// }, 0);
// }
// });
// let block = new TornStyleBlock('盯梢模式').insert2Dom();
// let watchSwitch = new TornStyleSwitch('开启');
// block.append(watchSwitch.getBase());
// watchSwitch.getInput().addEventListener('change', () => {
// if (watchSwitch.getInput().checked) {
// new DialogMsgBox('检测玩家状态,当目标状态变成(海外)落地、出院或出狱时通知并播放声音提醒,后可搭配光速刷新食用<br/>确定开启?', {
// callback: () => {
// if (this.commonUtils.getTravelStage() === TRAVEL_STATE.FLYING) {
// new Alert('失败!已取消');
// watchSwitch.getInput().checked = false;
// return;
// }
// this.logger.info('盯梢开启, 目标id' + targetId);
// loop.start(this.localConfigWrapper.config.WatchTargetFreq | 0);
// },
// cancel: () => watchSwitch.getInput().checked = false
// });
// } else {
// loop.stop();
// this.logger.info('盯梢关闭');
// }
// });
// }
// }

View File

@ -1,25 +1,47 @@
import TornStyleBlock from "../utils/TornStyleBlock";
import Alert from "../utils/Alert";
import TornStyleSwitch from "../utils/TornStyleSwitch";
import { Injectable } from "../../container/Injectable";
import ClassName from "../../container/ClassName";
import LocalConfigWrapper from "../LocalConfigWrapper";
import IFeature from "../../man/IFeature";
import MsgWrapper from "../utils/MsgWrapper";
@Injectable()
@ClassName('PTHelper')
export default class PTHelper {
private readonly observer;
private readonly usersPointSell;
export default class PTHelper implements IFeature {
private observer: MutationObserver;
private usersPointSell: HTMLDivElement;
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly msgWrapper: MsgWrapper,
) {
}
description(): string {
return "pt一键购买";
}
iStart(): void | Promise<void> {
this.start()
}
urlExcludes(): RegExp[] {
return [];
}
urlIncludes(): RegExp[] {
return [/pmarket\.php/];
}
start() {
this.observer = new MutationObserver(e => {
for (const t of e) {
t.addedNodes.forEach(e => 'LI' === (e as HTMLElement).tagName && this.removeConfirm(e))
}
});
this.usersPointSell = document.querySelector('.users-point-sell');
this.usersPointSell = document.querySelector<HTMLDivElement>('.users-point-sell');
let block = new TornStyleBlock('PT一键购买').insert2Dom();
let switcher = new TornStyleSwitch('开启');
@ -27,7 +49,7 @@ export default class PTHelper {
let toggle = switcher.getInput();
toggle.checked = this.localConfigWrapper.config.ptQuickBuy;
if (toggle.checked) {
new Alert('一键购买已开启');
this.msgWrapper.create('一键购买已开启');
for (const index in this.usersPointSell.children) {
'LI' === this.usersPointSell.children[index].tagName && this.removeConfirm(this.usersPointSell.children[index])
}
@ -40,13 +62,13 @@ export default class PTHelper {
'LI' === this.usersPointSell.children[index].tagName && this.removeConfirm(this.usersPointSell.children[index])
}
this.observer.observe(this.usersPointSell, { childList: true });
new Alert('一键购买已开启');
this.msgWrapper.create('一键购买已开启');
} else {
for (const index in this.usersPointSell.children) {
'LI' === this.usersPointSell.children[index].tagName && this.rollbackConfirm(this.usersPointSell.children[index])
}
this.observer.disconnect();
new Alert('一键购买已关闭');
this.msgWrapper.create('一键购买已关闭');
}
});
}

View File

@ -8,21 +8,41 @@ import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
import LocalConfigWrapper from "../LocalConfigWrapper";
import Logger from "../Logger";
import IFeature from "../../man/IFeature";
@ClassName('ProfileHelper')
@Injectable()
export default class ProfileHelper implements ResponseInject {
private readonly block;
// 曾用名已检测过标记
private task = true;
export default class ProfileHelper implements ResponseInject, IFeature {
private block: TornStyleBlock;
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly commonUtils: CommonUtils,
private readonly logger: Logger,
) {
}
description(): string {
return "个人资料页面辅助";
}
iStart(): void | Promise<void> {
this.start()
}
urlExcludes(): RegExp[] {
return [];
}
// 曾用名已检测过标记
private task = true;
urlIncludes(): RegExp[] {
return [/profiles\.php\?XID=/];
}
start() {
CommonUtils.addStyle('body.wh-hide_profile_img .profile-image a.profile-image-wrapper .img-wrap img{display:none;}');
// let id = document.querySelector('link[rel="canonical"]').getAttribute('href').split('=')[1];
let id = (new URL(window.location.href)).searchParams.get('XID');

View File

@ -4,10 +4,26 @@ import CommonUtils from "../utils/CommonUtils";
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
import LocalConfigWrapper from "../LocalConfigWrapper";
import IFeature from "../../man/IFeature";
@ClassName('SearchHelper')
@Injectable()
export default class SearchHelper {
export default class SearchHelper implements IFeature {
description(): string {
return "搜索助手";
}
iStart(): void | Promise<void> {
this.init()
}
urlExcludes(): RegExp[] {
return [];
}
urlIncludes(): RegExp[] {
return [/page\.php\?sid=UserList/];
}
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,

View File

@ -6,13 +6,29 @@ import MathUtils from "../utils/MathUtils";
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
import Logger from "../Logger";
import IFeature from "../../man/IFeature";
/**
*
*/
@ClassName("SlotsHelper")
@Injectable()
export default class SlotsHelper {
export default class SlotsHelper implements IFeature {
description(): string {
return "老虎机批量购买助手";
}
iStart(): void | Promise<void> {
this.init()
}
urlExcludes(): RegExp[] {
return [];
}
urlIncludes(): RegExp[] {
return [/loader\.php\?sid=slots/];
}
constructor(
private readonly mathUtils: MathUtils,

View File

@ -7,6 +7,7 @@ import MathUtils from "../utils/MathUtils";
import FetchUtils from "../utils/FetchUtils";
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
import IFeature from "../../man/IFeature";
/**
*
@ -14,8 +15,35 @@ import { Injectable } from "../../container/Injectable";
*/
@ClassName('XZMZ')
@Injectable()
export default class XZMZ {
className = 'XZMZ';
export default class XZMZ implements IFeature {
description(): string {
return "寻找木桩";
}
iStart(): void | Promise<void> {
this.start()
}
urlExcludes(): RegExp[] {
return [];
}
urlIncludes(): RegExp[] {
return [/item.php\?temp=4/];
}
start() {
let hasInit: boolean = false
let handle = () => {
if (!hasInit && window.location.hash === '#xunzhaomuzhuang') {
this.init()
hasInit = true
}
}
window.addEventListener('hashchange', handle)
handle()
}
private mainRoleContainer: HTMLElement;
private IDList: number[];
private btn: HTMLButtonElement;

View File

@ -1,70 +1,70 @@
import Popup from "../utils/Popup";
import CommonUtils from "../utils/CommonUtils";
import MDUtils from "../utils/MDUtils";
import { MENU_ITEM_TYPE } from "../../interface/MenuItem";
import Provider from "../provider/Provider";
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
import { Container } from "../../container/Container";
import Logger from "../Logger";
/**
* @deprecated
*/
@ClassName('ChangeLogHandler')
@Injectable()
export class ChangeLogHandler extends Provider {
constructor(
private readonly mdUtils: MDUtils,
private readonly logger: Logger,
) {
super();
}
public show(): void {
let popup = new Popup(
'更新历史:<br/><a target="_blank" href="https://gitlab.com/JJins/wuhu-torn-helper/-/blob/dev/CHANGELOG.md">https://gitlab.com/JJins/wuhu-torn-helper/-/blob/dev/CHANGELOG.md</a><br/>',
'更新历史'
).element;
popup.classList.add('wh-changeLog');
let progressBar = document.createElement('div');
progressBar.style.height = '2px';
progressBar.style.width = '1%';
progressBar.style.backgroundColor = 'red';
let progressText = document.createElement('p');
progressText.innerText = '加载更新文件……';
progressText.style.textAlign = 'center';
let style = document.createElement('style');
style.innerHTML = `.wh-changeLog h2,.wh-changeLog h3,.wh-changeLog h4 {margin:8px 0;}.wh-changeLog li{list-style: inside;}`;
popup.append(progressBar, progressText, style);
CommonUtils
.COFetch('https://gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/CHANGELOG.md?' + performance.now())
.then(update => {
progressBar.style.width = '60%';
progressText.innerText = '解析中……';
let md = this.mdUtils.parse(update);
popup.append(md);
progressBar.style.width = '100%';
progressText.innerText = '加载完成';
window.setTimeout(() => {
progressBar.remove();
progressText.remove()
}, 3000);
})
.catch(e => {
this.logger.error(e);
progressBar.remove();
progressText.innerText = '无法加载';
});
}
}
export default {
domType: MENU_ITEM_TYPE.BUTTON,
domText: '🐞 更新历史',
clickFunc: () => Container.factory(ChangeLogHandler).show()
};
// import Popup from "../utils/Popup";
// import CommonUtils from "../utils/CommonUtils";
// import MDUtils from "../utils/MDUtils";
// import { MENU_ITEM_TYPE } from "../../interface/MenuItem";
// import Provider from "../provider/Provider";
// import ClassName from "../../container/ClassName";
// import { Injectable } from "../../container/Injectable";
// import { Container } from "../../container/Container";
// import Logger from "../Logger";
//
// /**
// * @deprecated
// */
// @ClassName('ChangeLogHandler')
// @Injectable()
// export class ChangeLogHandler extends Provider {
// constructor(
// private readonly mdUtils: MDUtils,
// private readonly logger: Logger,
// ) {
// super();
// }
//
// public show(): void {
// let popup = new Popup(
// '更新历史:<br/><a target="_blank" href="https://gitlab.com/JJins/wuhu-torn-helper/-/blob/dev/CHANGELOG.md">https://gitlab.com/JJins/wuhu-torn-helper/-/blob/dev/CHANGELOG.md</a><br/>',
// '更新历史'
// ).element;
// popup.classList.add('wh-changeLog');
// let progressBar = document.createElement('div');
// progressBar.style.height = '2px';
// progressBar.style.width = '1%';
// progressBar.style.backgroundColor = 'red';
// let progressText = document.createElement('p');
// progressText.innerText = '加载更新文件……';
// progressText.style.textAlign = 'center';
// let style = document.createElement('style');
// style.innerHTML = `.wh-changeLog h2,.wh-changeLog h3,.wh-changeLog h4 {margin:8px 0;}.wh-changeLog li{list-style: inside;}`;
//
// popup.append(progressBar, progressText, style);
//
// CommonUtils
// .COFetch('https://gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/CHANGELOG.md?' + performance.now())
// .then(update => {
// progressBar.style.width = '60%';
// progressText.innerText = '解析中……';
// let md = this.mdUtils.parse(update);
// popup.append(md);
// progressBar.style.width = '100%';
// progressText.innerText = '加载完成';
//
// window.setTimeout(() => {
// progressBar.remove();
// progressText.remove()
// }, 3000);
// })
// .catch(e => {
// this.logger.error(e);
// progressBar.remove();
// progressText.innerText = '无法加载';
// });
// }
//
// }
//
// export default {
// domType: MENU_ITEM_TYPE.BUTTON,
// domText: '🐞 更新历史',
// clickFunc: () => Container.factory(ChangeLogHandler).show()
// };

View File

@ -2,7 +2,7 @@ import CommonUtils from "../utils/CommonUtils";
import QUICK_FLY_CSS from "../../../static/css/quick_fly.module.css";
import QUICK_FLY_HTML from "../../../static/html/quick_fly.html";
import Alert from "../utils/Alert";
import TravelItem from "../action/TravelItem";
import TravelItem from "../../feature/TravelItem";
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
import Logger from "../Logger";

View File

@ -1,6 +1,6 @@
import { MenuItemConfig } from "../ZhongIcon";
import Timer from "../utils/Timer";
import BuyBeerHelper from "../action/BuyBeerHelper";
import BuyBeerHelper from "../../feature/BuyBeerHelper";
import UpdateTranslateDict from "./UpdateTranslateDict";
import landedRedirect from "../../func/module/landedRedirect";
import Alert from "../utils/Alert";

View File

@ -1,34 +0,0 @@
import drugCDMonitor from "./DrugCDMonitor";
import { Injectable } from "../../container/Injectable";
import ClassName from "../../container/ClassName";
import LocalConfigWrapper from "../LocalConfigWrapper";
import IntervalSwitch from "./IntervalSwitch";
export default interface IntervalType {
handler: () => void
switcher: (s: IntervalSwitch) => void
getId: () => number
setId: (id: number) => void
getMs: () => number
setMs: (ms: number) => void
}
export const intervalUnits: { [key: string]: IntervalType } = {
drugCDMonitor,
}
@Injectable()
@ClassName('WHIntervalLoader')
export class WHIntervalLoader {
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
) {
}
init() {
const list = this.localConfigWrapper.config.monitorOn
for (let i = 0; i < list.length; i++) {
intervalUnits[list[i]].switcher(IntervalSwitch.ON)
}
}
}

View File

@ -1,12 +0,0 @@
import { MENU_ITEM_TYPE } from "../../interface/MenuItem";
const BUTTON_HANDLE_METADATA_KEY = Symbol("BUTTON_HANDLE_KEY")
/**
* @ButtonHandler
*
* @param target
*/
export function ButtonHandler<T>(target: T): void {
Reflect.defineMetadata(BUTTON_HANDLE_METADATA_KEY, MENU_ITEM_TYPE.BUTTON, target);
}

View File

@ -1,26 +0,0 @@
export default class Elem {
private readonly elem: HTMLElement;
constructor(tagName) {
this.elem = document.createElement(tagName);
}
public html(htmlString): Elem {
this.elem.innerHTML = htmlString;
return this;
}
public id(id): Elem {
this.elem.id = id;
return this;
}
public class(className): Elem {
this.elem.classList.add(className);
return this;
}
public el(): HTMLElement {
return this.elem;
}
}

View File

@ -2,6 +2,7 @@ import ClassWithName from "../../interface/ClassWithName";
/**
*
* @deprecated
*/
export default class Provider implements ClassWithName {
readonly className: string = 'Provider';

View File

@ -7,30 +7,14 @@ import globVars from "../../globVars";
@Injectable()
export default class ActionButtonUtils {
private hasAdded: boolean = false;
constructor(
private readonly logger: Logger,
) {
}
private readonly logger = Logger.factory(ActionButtonUtils)
public add(txt: string, func: (ev: Event) => void = () => null): void {
if (!this.hasAdded) this.handle(txt, func);
else this.logger.warn('ActionButton已存在');
globVars.actionList.push({
txt,
func
});
let added = { txt, func }
globVars.buttons.push(added)
this.logger.info({ globVars })
}
private handle(txt, func): void {
let btn = document.createElement('button');
btn.style.padding = '8px 13px 8px 0';
btn.style.verticalAlign = 'bottom';
btn.style.color = '#4CAF50';
btn.innerHTML = txt;
btn.addEventListener('click', func);
// ZhongIcon.ZhongNode.querySelector('button').after(btn);
this.hasAdded = true;
this.logger.info('ActionButton已添加', { txt, func, btn });
}
}

View File

@ -3,13 +3,13 @@ const CLASSNAME_METADATA_KEY = Symbol("CLASSNAME_KEY");
/**
*
*/
export default function ClassName(className?: string): ClassDecorator {
export default function ClassName(className: string): ClassDecorator {
return function <TFunction extends Function>(target: TFunction): TFunction {
Reflect.defineMetadata(CLASSNAME_METADATA_KEY, className || target.name, target);
Reflect.defineMetadata(CLASSNAME_METADATA_KEY, className, target);
return target;
};
}
export function GetClassName(target: any) {
export function GetClassName(target: ClassType<{}>): string {
return Reflect.getMetadata(CLASSNAME_METADATA_KEY, target);
}

View File

@ -1,40 +1,38 @@
import "reflect-metadata";
import { assertInjectable } from "./Injectable";
import { GetClassName } from "./ClassName";
import ClassName, { GetClassName } from "./ClassName";
import Logger from "../class/Logger";
/**
*
*/
@ClassName('Container')
export class Container {
static _container = new Map();
private static logger;
static set(k: any, v: any): void {
static set<T>(k: Constructor<T>, v: T): void {
if (!this._container.has(k)) {
this._container.set(k, v);
}
}
static get(k: any): any {
static get<T>(k: Constructor<T>): T {
return this._container.get(k);
}
static factory<T>(target: Constructor<T>): T {
static factory<T>(target: ClassType<T>): T {
assertInjectable(target);
// if (Container.get(target))
// return Container.get(target);
return this.get(target) || this.initParam(target);
}
static setLogger(logger: { info(...o: any[]), error(...o: any[]), warn(...o: any[]) }): void {
static setLogger(logger: Logger): void {
this.logger = logger;
}
private static initParam<T>(target: Constructor<T>): T {
// 获取所有注入的服务
const providers = Reflect.getMetadata('design:paramtypes', target);
// this.logger.info({providers})
// this.logger.info('原型名'+Object.getPrototypeOf(target).constructor.name)
// this.logger.info('直接名'+target.name)
const args = providers ? providers.map((provider: Constructor) => {
return this.factory(provider);
}) : [];

View File

@ -5,7 +5,6 @@ const INJECTABLE_METADATA_KEY = Symbol("INJECTABLE_KEY");
// TODO 实现非单例注入
export enum INJECT_MODE {
Singleton = 1,
Multi = 2,
}
export function Injectable(injectMode: INJECT_MODE = INJECT_MODE.Singleton): ClassDecorator {

278
src/ts/feature/Atk.ts Normal file
View File

@ -0,0 +1,278 @@
import ClassName from "../container/ClassName"
import { Injectable } from "../container/Injectable"
import IFeature from "../man/IFeature"
import LocalConfigWrapper from "../class/LocalConfigWrapper"
import CommonUtils from "../class/utils/CommonUtils"
import Global from "../class/Global"
import ActionButtonUtils from "../class/utils/ActionButtonUtils"
import Logger from "../class/Logger"
import Alert from "../class/utils/Alert"
import Device from "../enum/Device"
import ATTACK_HELPER_CSS from "../../static/css/attack_helper.module.css"
import ATK_PAGE_REG from "./url/ATK_PAGE_REG";
enum FIGHT_STAGE {
READY = 'ready',
IN_PROGRESS_OR_ERROR = 'in_progress_or_error',
FINISHED = 'finished',
END = 'end',
OTHER = 'other'
}
@ClassName('Atk')
@Injectable()
export default class Atk implements IFeature {
private currentStage: FIGHT_STAGE = FIGHT_STAGE.OTHER;
constructor(
private readonly actionButtonUtils: ActionButtonUtils,
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly commonUtils: CommonUtils,
private readonly global: Global,
// private readonly mathUtils: MathUtils,
// private readonly fetchUtils: FetchUtils,
private readonly logger: Logger,
) {
}
urlIncludes(): RegExp[] {
return [ATK_PAGE_REG]
}
urlExcludes(): RegExp[] {
return []
}
description(): string {
return '攻击助手'
}
iStart(): void | Promise<void> {
// 光速刷新按钮
this.actionButtonUtils.add('光速刷新', () => this.doAttackReload());
new MutationObserver((_, observer) => {
let btnList = document.querySelectorAll('div[class^="dialogButtons___"] button') as NodeListOf<HTMLButtonElement>;
if (btnList.length === 0) {
if (this.currentStage === FIGHT_STAGE.READY && this.localConfigWrapper.config.quickFinishAtt === 3) {
document.body.classList.remove('wh-move-btn');
this.logger.info('移除body class wh-move-btn');
observer.disconnect();
}
// 错误或正在打
this.currentStage = FIGHT_STAGE.IN_PROGRESS_OR_ERROR;
this.logger.info('[attackHelper] currentStage', this.currentStage);
return;
}
btnList.forEach(btn => {
let btnText = btn.innerText.toLowerCase();
if (btnText.includes('start') || btnText.includes('join')) {
// 开始
this.quickStartFight();
} else if (btnText.includes('continue')) {
// 结束end
this.currentStage = FIGHT_STAGE.END;
observer.disconnect();
} else if (btnText.includes('leave')) {
// 无意识状态FINISHED
this.quickFinishFight(btnList);
}
this.logger.info('[attackHelper] currentStage', this.currentStage);
})
})
.observe(document.querySelector('#react-root'), { childList: true, subtree: true });
}
// 战斗页面快速刷新
private doAttackReload(): void {
if (!window.ReactDOM) {
new Alert('光速刷新失败未找到React对象');
this.logger.error('光速刷新失败未找到React对象');
return;
}
if (!document.querySelector('#react-root #attacker')) {
this.logger.error('dom元素未找到selector: [#react-root #attacker]');
return;
}
let script = document.querySelector('script[src*="/builds/attack/"]');
let url = script.src;
if (!url.contains(/runtime\..+\.js/)) {
this.logger.error('脚本源[' + url + '] 不匹配规则');
return;
}
window.ReactDOM.unmountComponentAtNode(document.querySelector('#react-root'));
script.remove();
let node = document.createElement('script');
node.src = url;
node.type = 'text/javascript';
document.head.appendChild(node);
}
// 光速拔刀
private quickStartFight(): void {
if (this.currentStage === FIGHT_STAGE.READY) {
return;
} else {
this.currentStage = FIGHT_STAGE.READY;
}
if (this.localConfigWrapper.config.quickAttIndex === 6) return;
/**
* pc #defender
* mobile #attacker
*/
const btn = <HTMLInputElement>(document.querySelector('#attacker button') || document.querySelector('#defender button'));
this.logger.info('操作按钮', { btn });
if (!btn.innerText.toLowerCase().includes('fight')) {
this.logger.info('未找到攻击按钮, 光速拔刀跳过');
new Alert('未找到攻击按钮, 光速拔刀跳过');
} else {
// 判断是否存在脚踢
const hasKick = !!document.querySelector('#weapon_boots');
// modal层
// const modal: HTMLElement = document.querySelector('div[class^="modal___"]');
let device = this.global.device;
this.logger.info(`当前设备类型是${ device }`);
// 区分设备
switch (device) {
case Device.PC: {
this.logger.info(`开始调整按钮位置`);
// 隐藏modal层
// modal.style.display = 'none';
// 根据选择的武器调整css
let css_top = '0';
switch (this.localConfigWrapper.config.quickAttIndex) {
// weapon_second
case 1: {
css_top = '97px';
break;
}
// weapon_melee
case 2: {
css_top = '194px';
break;
}
// weapon_temp
case 3: {
css_top = '291px';
break;
}
// weapon_fists
case 4:
// weapon_boots
case 5: {
css_top = '375px';
break;
}
}
this.commonUtils.styleInject(ATTACK_HELPER_CSS);
CommonUtils.addStyle(`.wh-move-btn #defender div[class^="modal___"]{top: ${ css_top };}`);
document.body.classList.add('wh-move-btn');
break;
}
case Device.MOBILE: {
this.logger.info(`开始调整按钮位置`);
// 加入css
let css_top = '0';
let slot_height = '76px';
// 判断有没有脚踢
if (hasKick) {
// 根据选择的武器调整
switch (this.localConfigWrapper.config.quickAttIndex) {
case 1: { // weapon_second
css_top = '76px';
break;
}
case 2: { // weapon_melee
css_top = '152px';
break;
}
case 3: { // weapon_temp
css_top = '228px';
break;
}
case 4: { // weapon_fists
css_top = '304px';
break;
}
case 5: { // weapon_boots
css_top = '380px';
break;
}
}
} else {
const slot = document.querySelector('#weapon_main') as HTMLElement;
const height = slot.offsetHeight + 1;
// TODO 待验证
slot_height = height + 'px';
// 根据选择的武器调整
switch (this.localConfigWrapper.config.quickAttIndex) {
case 1: { // weapon_second
css_top = `${ height }px`;
break;
}
case 2: { // weapon_melee
css_top = `${ height * 2 }px`;
break;
}
case 3: { // weapon_temp
css_top = `${ height * 3 }px`;
break;
}
case 4: { // weapon_fists
css_top = `${ height * 4 }px`;
break;
}
case 5: { // weapon_boots
css_top = `${ height * 5 }px`;
break;
}
}
}
const css_rule = ATTACK_HELPER_CSS.replace('CSSVAR', css_top).replace('CSSVAR', slot_height);
this.commonUtils.styleInject(css_rule);
document.body.classList.toggle('wh-move-btn');
btn.onclick = () => {
if (this.localConfigWrapper.config.quickFinishAtt !== 3) {
btn.remove();
// 停止自动刷新
// stop_reload = true;
} else {
document.body.classList.toggle('wh-move-btn');
}
};
break;
}
case Device.TABLET: {
break;
}
}
}
}
// 光速跑路
private quickFinishFight(btnList: NodeListOf<HTMLButtonElement>): void {
if (this.currentStage === FIGHT_STAGE.FINISHED) {
return;
} else {
this.currentStage = FIGHT_STAGE.FINISHED;
}
if (this.localConfigWrapper.config.quickFinishAtt === 3) {
document.body.classList.remove('wh-move-btn');
this.logger.info('移除body class wh-move-btn');
return;
}
const user_btn_select = ['leave', 'mug', 'hosp'][this.localConfigWrapper.config.quickFinishAtt];
// const wrap = document.querySelector('#react-root');
this.logger.info('光速跑路选项选中:', user_btn_select);
// const btn_arr: HTMLButtonElement[] = document.querySelectorAll('div[class^="dialogButtons___"] button') as unknown as HTMLButtonElement[];
if (btnList.length > 1) btnList.forEach(btn => {
const flag = btn.innerText.toLowerCase().includes(user_btn_select);
this.logger.info('按钮内容:', btn.innerText, ',是否包含选中:', flag);
if (!flag) btn.style.display = 'none';
});
}
}

View File

@ -0,0 +1,68 @@
import ClassName from "../container/ClassName"
import { Injectable } from "../container/Injectable"
import IFeature from "../man/IFeature"
import TornStyleBlock from "../class/utils/TornStyleBlock"
import ADD_BEER_HEAD_HTML from "../../static/html/buyBeer/add_beer_head.html"
import SHOP_BEER_STATIC_ITEM_HTML from "../../static/html/buyBeer/shop_beer_static_item.html"
import globVars from "../globVars"
import Logger from "../class/Logger";
import BuyBeerHelper from "./BuyBeerHelper";
@ClassName('BeerShopModifier')
@Injectable()
export default class BeerShopModifier implements IFeature {
private readonly logger = Logger.factory(BeerShopModifier)
constructor(
private readonly buyBeerHelper: BuyBeerHelper,
) {
}
description(): string {
return "啤酒店页面修改";
}
iStart(): void | Promise<void> {
this.start()
}
urlExcludes(): RegExp[] {
return [];
}
urlIncludes(): RegExp[] {
return [/shops.php\?step=bitsnbobs/];
}
start() {
let block = new TornStyleBlock('啤酒助手').insert2Dom();
block.setContent(ADD_BEER_HEAD_HTML);
const msg_node = block.querySelector('#wh-msg');
// 加入啤酒
block.querySelector('button').addEventListener('click', e => {
let node = document.querySelector('ul.items-list');
if (!node) {
msg_node.innerHTML = '❌ 商品未加载完';
this.logger.error('商品未加载完');
return;
}
if (node.querySelector('span[id="180-name"]')) {
msg_node.innerHTML = '❌ 页面已经有啤酒了';
this.logger.warn('商店页面已有啤酒');
return;
}
const clear_node = node.querySelector('li.clear');
const beer = document.createElement('li');
beer.classList.add('torn-divider', 'divider-vertical');
beer.style.backgroundColor = '#c8c8c8';
beer.innerHTML = SHOP_BEER_STATIC_ITEM_HTML;
if (clear_node) clear_node.before(beer);
else node.append(beer);
(<HTMLInputElement>e.target).disabled = true;
msg_node.innerHTML = '添加成功';
});
// 监听啤酒购买
globVars.responseHandlers.push((...args: any[]) => this.buyBeerHelper.responseHandler.apply(this.buyBeerHelper, args));
}
}

View File

@ -1,18 +1,37 @@
import InfoUtils from "../utils/InfoUtils";
import MathUtils from "../utils/MathUtils";
import NOTIFY_HTML from "../../../static/html/buyBeer/notify.html";
import CommonUtils from "../utils/CommonUtils";
import Popup from "../utils/Popup";
import ResponseInject from "../../interface/ResponseInject";
import LocalConfigWrapper from "../LocalConfigWrapper";
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
import Logger from "../Logger";
import MsgWrapper from "../utils/MsgWrapper";
import InfoUtils from "../class/utils/InfoUtils";
import MathUtils from "../class/utils/MathUtils";
import NOTIFY_HTML from "../../static/html/buyBeer/notify.html";
import CommonUtils from "../class/utils/CommonUtils";
import Popup from "../class/utils/Popup";
import ResponseInject from "../interface/ResponseInject";
import LocalConfigWrapper from "../class/LocalConfigWrapper";
import ClassName from "../container/ClassName";
import { Injectable } from "../container/Injectable";
import Logger from "../class/Logger";
import MsgWrapper from "../class/utils/MsgWrapper";
import IFeature from "../man/IFeature";
import ATK_PAGE_REG from "./url/ATK_PAGE_REG";
import ALL_PAGE_REG from "./url/ALL_PAGE_REG";
@ClassName('BuyBeerHelper')
@Injectable()
export default class BuyBeerHelper implements BeerMonitorLoop, ResponseInject {
export default class BuyBeerHelper implements BeerMonitorLoop, ResponseInject, IFeature {
urlIncludes(): RegExp[] {
return [ALL_PAGE_REG]
}
urlExcludes(): RegExp[] {
return [ATK_PAGE_REG]
}
description(): string {
return '啤酒助手'
}
iStart(): void | Promise<void> {
(this.localConfigWrapper.config._15Alarm) && this.start()
}
private isNotifying = false;
private loopId: number = null;

View File

@ -0,0 +1,25 @@
import ClassName from "../container/ClassName";
import { Injectable } from "../container/Injectable";
import IFeature from "../man/IFeature";
import christmasTownHelper from "../func/module/christmasTownHelper";
@ClassName('ChristmasTown')
@Injectable()
export default class ChristmasTown implements IFeature {
urlIncludes(): RegExp[] {
return [/christmas_town\.php/]
}
urlExcludes(): RegExp[] {
return []
}
description(): string {
return '圣诞小镇助手'
}
iStart(): void | Promise<void> {
christmasTownHelper()
}
}

View File

@ -1,26 +1,44 @@
import CommonUtils from "../utils/CommonUtils";
import FetchUtils from "../utils/FetchUtils";
import InfoUtils from "../utils/InfoUtils";
import TRAVEL_STATE from "../../enum/TravelState";
import LocalConfigWrapper from "../LocalConfigWrapper";
import { Injectable } from "../../container/Injectable";
import ClassName from "../../container/ClassName";
import Logger from "../Logger";
import MsgWrapper from "../utils/MsgWrapper";
import CommonUtils from "../class/utils/CommonUtils";
import FetchUtils from "../class/utils/FetchUtils";
import InfoUtils from "../class/utils/InfoUtils";
import TRAVEL_STATE from "../enum/TravelState";
import LocalConfigWrapper from "../class/LocalConfigWrapper";
import { Injectable } from "../container/Injectable";
import ClassName from "../container/ClassName";
import Logger from "../class/Logger";
import MsgWrapper from "../class/utils/MsgWrapper";
import IFeature from "../man/IFeature";
import ATK_PAGE_REG from "./url/ATK_PAGE_REG";
import ALL_PAGE_REG from "./url/ALL_PAGE_REG";
/**
*
*/
@Injectable()
@ClassName('CompanyHelper')
export default class CompanyHelper {
className = 'CompanyHelper';
export default class CompanyHelper implements IFeature {
private readonly logger: Logger = Logger.factory(CompanyHelper)
description(): string {
return "公司助手、火车爆仓检测";
}
iStart(): void | Promise<void> {
this.init()
}
urlExcludes(): RegExp[] {
return [ATK_PAGE_REG];
}
urlIncludes(): RegExp[] {
return [ALL_PAGE_REG];
}
public constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly commonUtils: CommonUtils,
private readonly fetchUtils: FetchUtils,
private readonly logger: Logger,
private readonly infoUtils: InfoUtils,
private readonly msgWrapper: MsgWrapper,
) {
@ -30,10 +48,6 @@ export default class CompanyHelper {
this.localConfigWrapper.config.CHTrainsDetectSwitch && this.trainsDetect().then();
}
// public detectNow(): void {
// this.trainsDetect(true).then();
// }
/**
*
*
@ -56,7 +70,7 @@ export default class CompanyHelper {
this.fetchUtils.fetchText('/companies.php')
.then(res => {
let tmp: HTMLElement = document.createElement('div');
let bodyTagStart = this.commonUtils.matchOne(res, /<body.+>/);
let bodyTagStart = this.commonUtils.matchOne(res, /<body.+/);
if (!bodyTagStart) {
this.logger.warn('火车检测: 无法获取数据');
throw new Error('火车检测: 无法获取数据');

View File

@ -0,0 +1,78 @@
import ClassName from "../container/ClassName";
import { Injectable } from "../container/Injectable";
import IFeature from "../man/IFeature";
import LocalConfigWrapper from "../class/LocalConfigWrapper";
import CommonUtils from "../class/utils/CommonUtils";
import QUICK_CRIMES_HTML from "../../static/html/quick_crimes.html";
@ClassName('CrimePageModifier')
@Injectable()
export default class CrimePageModifier implements IFeature {
constructor(
private readonly localConfigWrapper: LocalConfigWrapper
) {
}
description(): string {
return "页面快速crime";
}
iStart(): void | Promise<void> {
this.start()
}
urlExcludes(): RegExp[] {
return [];
}
urlIncludes(): RegExp[] {
return [/crimes\.php/];
}
start() { // TODO 重构、与翻译解藕
if (this.localConfigWrapper.config.quickCrime) {
// iframe
if (self !== top) {
const isValidate = document.querySelector('h4#skip-to-content').innerText.toLowerCase().includes('validate');
CommonUtils.elementReady('#header-root').then(e => e.style.display = 'none');
CommonUtils.elementReady('#sidebarroot').then(e => e.style.display = 'none');
CommonUtils.elementReady('#chatRoot').then(e => e.style.display = 'none');
if (!isValidate) document.body.style.overflow = 'hidden';
CommonUtils.elementReady('.content-wrapper').then(e => {
e.style.margin = '0px';
e.style.position = 'absolute';
e.style.top = '-35px';
});
CommonUtils.elementReady('#go-to-top-btn button').then(e => e.style.display = 'none');
}
const element = document.querySelector('.content-wrapper');
const OB = new MutationObserver(() => {
OB.disconnect();
trans();
OB.observe(element, {
characterData: true,
attributes: true,
subtree: true,
childList: true
});
});
const trans = () => {
const dom = QUICK_CRIMES_HTML;
const hasInserted = element.querySelector('.wh-translate') !== null;
const $title = document.querySelector('div.content-title');
const $info = document.querySelector('.info-msg-cont');
if (!hasInserted) {
if ($title) $title.insertAdjacentHTML('beforebegin', dom);
else if ($info) $info.insertAdjacentHTML('beforebegin', dom);
}
};
trans();
OB.observe(element, {
characterData: true,
attributes: true,
subtree: true,
childList: true
});
}
}
}

View File

@ -0,0 +1,76 @@
import Logger, { LoggerKey } from "../class/Logger"
import ClassName from "../container/ClassName"
import { Injectable } from "../container/Injectable"
import CommonUtils, { CommonUtilsKey } from "../class/utils/CommonUtils"
import LocalConfigWrapper, { LocalConfigWrapperKey } from "../class/LocalConfigWrapper"
import { createApp } from "vue"
import FloatMenu from "../../vue/FloatMenu.vue"
import PopupWrapper, { PopupWrapperKey } from "../class/utils/PopupWrapper"
import TravelItem from "./TravelItem"
import QuickGymTrain, { QuickGymTrainKey } from "../class/action/QuickGymTrain"
import QuickFlyBtnHandler, { QuickFlyBtnHandlerKey } from "../class/handler/QuickFlyBtnHandler"
import ItemHelper, { ItemHelperKey } from "../class/utils/ItemHelper"
import MathUtils, { MathUtilsKey } from "../class/utils/MathUtils"
import IFeature from "../man/IFeature"
import ALL_PAGE_REG from "./url/ALL_PAGE_REG"
@ClassName("IconHelper")
@Injectable()
export default class IconHelper implements IFeature {
private readonly _element: HTMLElement = document.createElement('div');
private readonly logger = Logger.factory(IconHelper)
description(): string {
return "浮动图标、侧边菜单、标签式便携功能";
}
iStart(): void | Promise<void> {
this.init()
}
urlExcludes(): RegExp[] {
return [];
}
urlIncludes(): RegExp[] {
return [ALL_PAGE_REG];
}
constructor(
private readonly commonUtils: CommonUtils,
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly popupWrapper: PopupWrapper,
private readonly travelItem: TravelItem,
private readonly quickGymTrain: QuickGymTrain,
private readonly quickFlyBtnHandler: QuickFlyBtnHandler,
private readonly itemHelper: ItemHelper,
private readonly mathUtils: MathUtils,
) {
}
get element() {
return this._element;
}
init() {
this._element.id = 'WHMenu2023';
document.body.append(this._element);
let app = createApp(FloatMenu);
this.logger.info('Vue实例已创建', { app })
app.config.errorHandler = (err) => this.logger.error('[VUE错误]', err);
app.config.warnHandler = (err) => this.logger.warn('[VUE警告]', err);
app.provide(LoggerKey, this.logger);
app.provide(CommonUtilsKey, this.commonUtils);
app.provide(MathUtilsKey, this.mathUtils);
// app.provide(TravelItemKey, this.travelItem);
app.provide(PopupWrapperKey, this.popupWrapper);
app.provide(LocalConfigWrapperKey, this.localConfigWrapper);
app.provide(QuickGymTrainKey, this.quickGymTrain);
app.provide(QuickFlyBtnHandlerKey, this.quickFlyBtnHandler);
app.provide(ItemHelperKey, this.itemHelper);
app.mount(this._element);
this.logger.info('Vue实例已挂载')
}
}

View File

@ -1,19 +1,34 @@
import InfoUtils from "../utils/InfoUtils";
import MathUtils from "../utils/MathUtils";
import CommonUtils from "../utils/CommonUtils";
import TornStyleBlock from "../utils/TornStyleBlock";
import Timer from "../utils/Timer";
import FetchUtils from "../utils/FetchUtils";
import { Injectable } from "../../container/Injectable";
import ClassName from "../../container/ClassName";
import Logger from "../Logger";
import InfoUtils from "../class/utils/InfoUtils";
import MathUtils from "../class/utils/MathUtils";
import CommonUtils from "../class/utils/CommonUtils";
import TornStyleBlock from "../class/utils/TornStyleBlock";
import Timer from "../class/utils/Timer";
import FetchUtils from "../class/utils/FetchUtils";
import { Injectable } from "../container/Injectable";
import ClassName from "../container/ClassName";
import Logger from "../class/Logger";
import IFeature from "../man/IFeature";
/**
*
*/
@Injectable()
@ClassName('LotteryHelper')
export default class LotteryHelper {
export default class LotteryHelper implements IFeature {
private readonly logger: Logger = Logger.factory(LotteryHelper)
description(): string {
return "彩票助手";
}
iStart(): void | Promise<void> {
this.init()
}
urlExcludes(): RegExp[] {
return [];
}
private loopFlag = true;
private radioDaily: HTMLInputElement = null;
@ -26,12 +41,15 @@ export default class LotteryHelper {
private status: HTMLElement = null;
private desc: HTMLElement = null;
urlIncludes(): RegExp[] {
return [/loader\.php\?sid=lottery/];
}
constructor(
private readonly mathUtils: MathUtils,
private readonly commonUtils: CommonUtils,
private readonly fetchUtils: FetchUtils,
private readonly infoUtils: InfoUtils,
private readonly logger: Logger,
) {
}

50
src/ts/feature/MapItem.ts Normal file
View File

@ -0,0 +1,50 @@
import IFeature from "../man/IFeature";
import ClassName from "../container/ClassName";
import { Injectable } from "../container/Injectable";
import TornStyleBlock from "../class/utils/TornStyleBlock";
import TornStyleSwitch from "../class/utils/TornStyleSwitch";
import cityFinder from "../func/module/cityFinder";
import LocalConfigWrapper from "../class/LocalConfigWrapper";
@ClassName('MapItem')
@Injectable()
export default class MapItem implements IFeature {
constructor(
private readonly localConfigWrapper: LocalConfigWrapper
) {
}
description(): string {
return "捡垃圾助手";
}
iStart(): void | Promise<void> {
this.start()
}
urlExcludes(): RegExp[] {
return [];
}
urlIncludes(): RegExp[] {
return [/city\.php/];
}
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;
});
_base.append(document.createElement('br'));
cityFinder(_base);
}
}
}

View File

@ -0,0 +1,77 @@
import ClassName from "../container/ClassName";
import { Injectable } from "../container/Injectable";
import IFeature from "../man/IFeature";
import LocalConfigWrapper from "../class/LocalConfigWrapper";
import getTaskHint from "../func/translate/getTaskHint";
import { missionDict } from "../dictionary/translation";
@ClassName('MissionPageModifier')
@Injectable()
export default class MissionPageModifier implements IFeature {
constructor(
private readonly localConfigWrapper: LocalConfigWrapper
) {
}
description(): string {
return "页面快速crime";
}
iStart(): void | Promise<void> {
this.start()
}
urlExcludes(): RegExp[] {
return [];
}
urlIncludes(): RegExp[] {
return [/crimes\.php/];
}
start() {
const anchor = document.querySelector('.content-wrapper');
const OB = new MutationObserver(() => {
OB.disconnect();
trans();
OB.observe(anchor, {
characterData: true,
attributes: true,
subtree: true,
childList: true
});
});
const taskList = {};
const trans = () => {
$('ul#giver-tabs a.ui-tabs-anchor').each((i, e) => {
let $e = $(e);
if ($e.children().hasClass('mission-complete-icon')) {
taskList[i] = e.innerText.trim();
} else {
taskList[i] = $e.clone().children().remove().end().text().trim();
}
});
// 助手注入
$('div.max-height-fix.info').each((i, e) => {
let $e = $(e);
if ($e.find('.wh-translated').length !== 0) return;
$e.append(`<div class="wh-translated"><h6 style="color:green"><b>任务助手</b></h6><p>${ getTaskHint(taskList[i]) }</p></div>`);
});
// 任务目标
$('ul.tasks-list span.title-wrap').contents().each((i, e) => {
if (e.nodeType === 3) {
if (missionDict[e.nodeValue.trim()]) {
e.nodeValue = missionDict[e.nodeValue.trim()];
}
}
});
};
trans();
OB.observe(anchor, {
characterData: true,
attributes: true,
subtree: true,
childList: true
});
}
}

View File

@ -1,10 +1,13 @@
import CommonUtils from "../utils/CommonUtils";
import Global from "../Global";
import Device from "../../enum/Device";
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
import LocalConfigWrapper from "../LocalConfigWrapper";
import Logger from "../Logger";
import CommonUtils from "../class/utils/CommonUtils";
import Global from "../class/Global";
import Device from "../enum/Device";
import ClassName from "../container/ClassName";
import { Injectable } from "../container/Injectable";
import LocalConfigWrapper from "../class/LocalConfigWrapper";
import Logger from "../class/Logger";
import IFeature from "../man/IFeature";
import ATK_PAGE_REG from "./url/ATK_PAGE_REG";
import ALL_PAGE_REG from "./url/ALL_PAGE_REG";
/**
* ###
@ -13,16 +16,32 @@ import Logger from "../Logger";
*/
@ClassName('SidebarHelper')
@Injectable()
export default class SidebarHelper {
export default class SidebarHelper implements IFeature {
private readonly logger: Logger = Logger.factory(SidebarHelper)
description(): string {
return "边栏助手";
}
iStart(): void | Promise<void> {
this.init()
}
urlExcludes(): RegExp[] {
return [ATK_PAGE_REG];
}
private readonly sidebarRootNode: HTMLElement;
private readonly toggleBtn: HTMLButtonElement;
private isHide: boolean;
urlIncludes(): RegExp[] {
return [ALL_PAGE_REG];
}
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
private readonly global: Global,
private readonly logger: Logger,
) {
this.sidebarRootNode = document.querySelector('#sidebarroot');
this.toggleBtn = document.createElement('button');
@ -35,7 +54,7 @@ export default class SidebarHelper {
this.initToggleBtn();
this.barRedirect();
} else {
this.logger.warn('[SidebarHelper] 页面未开启边栏,边栏助手退出');
this.logger.warn('页面未开启边栏,边栏助手退出');
}
}
@ -73,10 +92,10 @@ export default class SidebarHelper {
// 4条转跳
private barRedirect(): void {
if (this.localConfigWrapper.config.barsRedirect) {
const eb = document.getElementById('barEnergy') as HTMLAnchorElement;
const nb = document.getElementById('barNerve') as HTMLAnchorElement;
const hb = document.getElementById('barHappy') as HTMLAnchorElement;
const lb = document.getElementById('barLife') as HTMLAnchorElement;
const eb = document.querySelector<HTMLAnchorElement>('#barEnergy');
const nb = document.querySelector<HTMLAnchorElement>('#barNerve');
const hb = document.querySelector<HTMLAnchorElement>('#barHappy');
const lb = document.querySelector<HTMLAnchorElement>('#barLife');
if (eb) {
eb.addEventListener('click', () => location.href = '/gym.php');
eb.href = '/gym.php';

View File

@ -1,15 +1,36 @@
import TornStyleBlock from "../utils/TornStyleBlock";
import TornStyleSwitch from "../utils/TornStyleSwitch";
import { Injectable } from "../../container/Injectable";
import ClassName from "../../container/ClassName";
import LocalConfigWrapper from "../LocalConfigWrapper";
import TornStyleBlock from "../class/utils/TornStyleBlock";
import TornStyleSwitch from "../class/utils/TornStyleSwitch";
import { Injectable } from "../container/Injectable";
import ClassName from "../container/ClassName";
import LocalConfigWrapper from "../class/LocalConfigWrapper";
import IFeature from "../man/IFeature";
@Injectable()
@ClassName('StackHelper')
export default class StackHelper {
export default class StackHelper implements IFeature {
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
) {
}
description(): string {
return "叠e助手";
}
iStart(): void | Promise<void> {
this.start()
}
urlExcludes(): RegExp[] {
return [];
}
urlIncludes(): RegExp[] {
return [/gym\.php/];
}
start() {
let block = new TornStyleBlock('叠E保护').insert2Dom();
let switcher = new TornStyleSwitch('启用');
let input = switcher.getInput();
@ -23,5 +44,4 @@ export default class StackHelper {
this.localConfigWrapper.config.SEProtect = target.checked;
};
}
}

View File

@ -1,18 +1,20 @@
import titleTrans from "../translate/titleTrans";
import contentTitleLinksTrans from "../translate/contentTitleLinksTrans";
import Device from "../../enum/Device";
import ActionButtonUtils from "../../class/utils/ActionButtonUtils";
import CommonUtils from "../../class/utils/CommonUtils";
import TRAVEL_ALARM_CSS from "../../../static/css/travel_alarm.module.css";
import TRAVEL_ALARM_HTML from "../../../static/html/travel_alarm.html";
import TornStyleBlock from "../../class/utils/TornStyleBlock";
import QuickFlyBtnHandler from "../../class/handler/QuickFlyBtnHandler";
import TRAVEL_STATE from "../../enum/TravelState";
import Global from "../../class/Global";
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
import LocalConfigWrapper from "../../class/LocalConfigWrapper";
import MsgWrapper from "../../class/utils/MsgWrapper";
import titleTrans from "../func/translate/titleTrans";
import contentTitleLinksTrans from "../func/translate/contentTitleLinksTrans";
import Device from "../enum/Device";
import ActionButtonUtils from "../class/utils/ActionButtonUtils";
import CommonUtils from "../class/utils/CommonUtils";
import TRAVEL_ALARM_CSS from "../../static/css/travel_alarm.module.css";
import TRAVEL_ALARM_HTML from "../../static/html/travel_alarm.html";
import TornStyleBlock from "../class/utils/TornStyleBlock";
import QuickFlyBtnHandler from "../class/handler/QuickFlyBtnHandler";
import TRAVEL_STATE from "../enum/TravelState";
import Global from "../class/Global";
import ClassName from "../container/ClassName";
import { Injectable } from "../container/Injectable";
import LocalConfigWrapper from "../class/LocalConfigWrapper";
import MsgWrapper from "../class/utils/MsgWrapper";
import IFeature from "../man/IFeature";
import INDEX_PAGE_REG from "./url/INDEX_PAGE_REG";
/**
*
@ -24,7 +26,23 @@ import MsgWrapper from "../../class/utils/MsgWrapper";
*/
@ClassName('TravelHelper')
@Injectable()
export default class TravelHelper {
export default class TravelHelper implements IFeature {
description(): string {
return "飞行助手";
}
iStart(): void | Promise<void> {
this.init()
}
urlExcludes(): RegExp[] {
return [];
}
urlIncludes(): RegExp[] {
return [INDEX_PAGE_REG, /travelagency\.php/];
}
constructor(
private readonly global: Global,
private readonly commonUtils: CommonUtils,
@ -153,7 +171,7 @@ export default class TravelHelper {
// 响铃的方法
let audio_play_handle = () => {
if (user_stop_alert) {
clearInterval(audio_play_id);
window.clearInterval(audio_play_id);
audio_play_id = null;
return;
}
@ -194,7 +212,7 @@ export default class TravelHelper {
} else {
// flying_status.innerHTML = `飞行中...`;
if (wh_trv_alarm.enable) {
clearInterval(audio_play_id);
window.clearInterval(audio_play_id);
audio_play_id = null;
stop_node.parentElement.classList.add('wh-trv-alarm-stop-hide');
}
@ -266,6 +284,7 @@ export default class TravelHelper {
});
const trans = () => {
// 当前能量e
// @ts-ignore
const energyBarStr = $('#barEnergy p[class^="bar-value__"]').text().trim();
const [curE, maxE] = energyBarStr.split('/').length === 2
? [parseInt(energyBarStr.split('/')[0]), parseInt(energyBarStr.split('/')[1])]
@ -274,6 +293,7 @@ export default class TravelHelper {
const fullEnergyTime = !(isNaN(curE) || isNaN(maxE)) ? (maxE - 5 - curE) / 5 * incTime
+ (incTime - new Date().getMinutes() % incTime) : NaN;
// 起飞前提示
// @ts-ignore
$('.travel-confirm .travel-question .q-wrap span:nth-of-type(2)').each((i, e) => {
if (isNaN(fullEnergyTime)) return;
const spl = e.innerText.trim().split(' ');
@ -304,10 +324,6 @@ export default class TravelHelper {
}
}
/** TODO */
inTravelPage() {
}
async doTravelBack(): Promise<void> {
if (typeof window['getAction'] !== 'function') return;
let backHomeAction = function (): Promise<string> {

View File

@ -1,22 +1,41 @@
import CommonUtils from "../utils/CommonUtils";
import UserScriptEngine from "../../enum/UserScriptEngine";
import Popup from "../utils/Popup";
import STOCK_IMG_HTML from "../../../static/html/stock_img.html";
import WindowActiveState from "./WindowActiveState";
import { Injectable } from "../../container/Injectable";
import ClassName from "../../container/ClassName";
import Logger from "../Logger";
import { InjectionKey } from "vue";
import CommonUtils from "../class/utils/CommonUtils";
import UserScriptEngine from "../enum/UserScriptEngine";
import Popup from "../class/utils/Popup";
import STOCK_IMG_HTML from "../../static/html/stock_img.html";
import WindowActiveState from "../class/action/WindowActiveState";
import { Injectable } from "../container/Injectable";
import ClassName from "../container/ClassName";
import Logger from "../class/Logger";
import IFeature from "../man/IFeature";
import ATK_PAGE_REG from "./url/ATK_PAGE_REG";
import ALL_PAGE_REG from "./url/ALL_PAGE_REG";
@Injectable()
@ClassName('TravelItem')
export default class TravelItem {
export default class TravelItem implements IFeature {
private readonly logger: Logger = Logger.factory(TravelItem)
description(): string {
return "海外货物存量静默获取";
}
iStart(): void | Promise<void> {
this.init()
}
urlExcludes(): RegExp[] {
return [ATK_PAGE_REG];
}
private readonly apiUrl: string = 'https://yata.yt/api/v1/travel/export/';
private foreignStockInfo: any = null;
urlIncludes(): RegExp[] {
return [ALL_PAGE_REG];
}
public constructor(
private readonly windowActiveState: WindowActiveState,
private readonly logger: Logger,
private readonly commonUtils: CommonUtils,
) {
}
@ -174,4 +193,4 @@ export default class TravelItem {
}
}
export const TravelItemKey = Symbol('TravelItemKey') as InjectionKey<TravelItem>
// export const TravelItemKey = Symbol('TravelItemKey') as InjectionKey<TravelItem>

View File

@ -0,0 +1,2 @@
const ALL_PAGE_REG = /^/
export default ALL_PAGE_REG

View File

@ -0,0 +1,2 @@
const ATK_PAGE_REG = /\/loader.php\?sid=attack&user2ID=/
export default ATK_PAGE_REG

View File

@ -0,0 +1,2 @@
const INDEX_PAGE_REG = /index\.php/
export default INDEX_PAGE_REG

View File

@ -1,5 +1,6 @@
import Popup from "./class/utils/Popup";
import { reactive } from 'vue'
import IFeatureResult from "./man/IFeatureResult";
type ResponseHandlers = ((url: string, responseBody: {
json: unknown,
@ -20,11 +21,14 @@ class GlobVars {
responseHandlers: ResponseHandlers = [];
version = '$$WUHU_DEV_VERSION$$';
popup_node: MyHTMLElement | Popup = null;
actionList: {
txt: string,
func: (ev: Event) => void
}[] = [];
loadTime: number = 0;
buttons = reactive<FloatButtonData[]>([])
featureStatus = reactive<IFeatureResult[]>([])
}
export default new GlobVars();
interface FloatButtonData {
txt: string,
func: (ev: Event) => void
}

View File

@ -1,13 +1,15 @@
import "reflect-metadata";
import { Container } from "./container/Container";
import App from "./App";
import Logger from "./class/Logger";
import EntryPoint from "./class/provider/EntryPoint";
import EntryPoint from "./starter/EntryPoint";
import { Injectable } from "./container/Injectable";
import ClassName from "./container/ClassName";
import { Container } from "./container/Container";
@EntryPoint
class _ {
static main() {
Container.setLogger(new Logger());
Container.factory(App).run();
@ClassName('Index')
@Injectable()
class Index {
public static main() {
Container.factory(App).run()
}
}

View File

@ -1,7 +1,7 @@
import Device from "../enum/Device";
import { BeerMonitorLoop } from "../class/action/BuyBeerHelper";
import { BeerMonitorLoop } from "../feature/BuyBeerHelper";
import Popup from "../class/utils/Popup";
import TravelItem from "../class/action/TravelItem";
import TravelItem from "../feature/TravelItem";
export default interface IGlobal {
GM_xmlhttpRequest?: Function;

116
src/ts/man/FeatureMan.ts Normal file
View File

@ -0,0 +1,116 @@
import IFeature from "./IFeature"
import { Container } from "../container/Container"
import ClassName, { GetClassName } from "../container/ClassName"
import Atk from "../feature/Atk"
import { Injectable } from "../container/Injectable"
import Logger from "../class/Logger"
import BuyBeerHelper from "../feature/BuyBeerHelper"
import SidebarHelper from "../feature/SidebarHelper"
import TravelItem from "../feature/TravelItem"
import TravelHelper from "../feature/TravelHelper"
import CompanyHelper from "../feature/CompanyHelper"
import IconHelper from "../feature/IconHelper"
import MapItem from "../feature/MapItem"
import PTHelper from "../class/action/PTHelper"
import StackHelper from "../feature/StackHelper"
import XZMZ from "../class/action/XZMZ"
import BeerShopModifier from "../feature/BeerShopModifier"
import CrimePageModifier from "../feature/CrimePageModifier"
import ProfileHelper from "../class/action/ProfileHelper"
import ChristmasTown from "../feature/ChristmasTown"
import LotteryHelper from "../feature/LotteryHelper"
import SlotsHelper from "../class/action/SlotsHelper"
import SearchHelper from "../class/action/SearchHelper"
import { WHIntervalLoader } from "../monitor/WHIntervalLoader"
import IFeatureResult from "./IFeatureResult"
import FeatureStatus from "./const/FeatureStatus"
import globVars from "../globVars";
@ClassName('FeatureMan')
@Injectable()
export default class FeatureMan {
private readonly features: ClassType<IFeature>[] = [
/* 通配 */
BuyBeerHelper,
SidebarHelper,
TravelItem,
CompanyHelper,
IconHelper,
WHIntervalLoader,
/* 页面匹配 */
Atk,
TravelHelper,
MapItem,
PTHelper,
StackHelper,
XZMZ,
BeerShopModifier,
CrimePageModifier,
ProfileHelper,
ChristmasTown,
LotteryHelper,
SlotsHelper,
SearchHelper,
]
private result: IFeatureResult[] = null
private readonly logger = Logger.factory(FeatureMan)
async fStart() {
const manResult: IFeatureResult[] = []
for (let i = 0; i < this.features.length; i++) {
const className = GetClassName(this.features[i])
const instant = Container.factory(this.features[i])
const description = instant.description()
const urlPath = location.href.replace(/^.+\/\/.+?\/(?!\/)?/, '/')
let status = FeatureStatus.ADDED
let isMatch = false
const urlIncludes = instant.urlIncludes()
let load = 0
for (let j = 0; j < urlIncludes.length; j++) {
if (urlIncludes[j].test(urlPath)) {
isMatch = true
const urlExcludes = instant.urlExcludes() ?? []
for (let k = 0; k < urlExcludes.length; k++) {
if (urlExcludes[k].test(urlPath)) {
isMatch = false
status = FeatureStatus.EXCLUDED
break
}
}
break
}
}
if (isMatch) {
try {
const start = performance.now()
let run = instant.iStart()
if (run instanceof Promise) {
run = await run
}
status = FeatureStatus.RUNNING
load = ((performance.now() - start) * 10 | 0) / 10
} catch (e) {
this.logger.error(e.message)
status = FeatureStatus.EXCEPTION
}
}
// else {
// status = FeatureStatus.EXCLUDED
// }
const result = {
desc: description,
status: status,
clazz: className,
load
}
manResult.push(result)
globVars.featureStatus.push(result)
}
this.result = manResult
}
printTable() {
console.table(this.result)
this.logger.info(this.result)
}
}

15
src/ts/man/IFeature.ts Normal file
View File

@ -0,0 +1,15 @@
export default interface IFeature {
iStart(): void | Promise<void>
/**
* urlnull
*/
urlIncludes(): RegExp[]
/**
* url
*/
urlExcludes(): RegExp[]
description(): string
}

View File

@ -0,0 +1,8 @@
import FeatureStatus from "./const/FeatureStatus";
export default interface IFeatureResult {
desc: string
status: FeatureStatus
clazz: string
load: number
}

View File

@ -0,0 +1,8 @@
enum FeatureStatus {
ADDED = '已添加',
RUNNING = '正常',
EXCLUDED = '页面排除',
EXCEPTION = '异常',
}
export default FeatureStatus

View File

@ -1,11 +1,11 @@
import IntervalType from "./IntervalUnit";
import ClassName from "../../container/ClassName";
import IntervalType from "./WHIntervalLoader";
import ClassName from "../container/ClassName";
import IntervalSwitch from "./IntervalSwitch";
import { SWITCHER } from "./SWITCHER";
import getSidebarData from "../../func/utils/getSidebarData";
import { Container } from "../../container/Container";
import MsgWrapper from "../utils/MsgWrapper";
import LocalConfigWrapper from "../LocalConfigWrapper";
import getSidebarData from "../func/utils/getSidebarData";
import { Container } from "../container/Container";
import MsgWrapper from "../class/utils/MsgWrapper";
import LocalConfigWrapper from "../class/LocalConfigWrapper";
@ClassName('DrugCDMonitor')
class DrugCDMonitor implements IntervalType {

View File

@ -1,5 +1,5 @@
import { GetClassName } from "../../container/ClassName";
import IntervalType from "./IntervalUnit";
import { GetClassName } from "../container/ClassName";
import IntervalType from "./WHIntervalLoader";
import IntervalSwitch from "./IntervalSwitch";
export function SWITCHER(self: IntervalType, clazz: new () => IntervalType, s: IntervalSwitch) {

View File

@ -0,0 +1,57 @@
/**
*
*/
import drugCDMonitor from "./DrugCDMonitor";
import { Injectable } from "../container/Injectable";
import ClassName from "../container/ClassName";
import LocalConfigWrapper from "../class/LocalConfigWrapper";
import IntervalSwitch from "./IntervalSwitch";
import IFeature from "../man/IFeature";
import ATK_PAGE_REG from "../feature/url/ATK_PAGE_REG";
import ALL_PAGE_REG from "../feature/url/ALL_PAGE_REG";
export default interface IntervalType {
handler: () => void
switcher: (s: IntervalSwitch) => void
getId: () => number
setId: (id: number) => void
getMs: () => number
setMs: (ms: number) => void
}
const intervalUnits: { [key: string]: IntervalType } = {
drugCDMonitor,
}
@Injectable()
@ClassName('WHIntervalLoader')
export class WHIntervalLoader implements IFeature {
description(): string {
return "新监控模块";
}
iStart(): void | Promise<void> {
this.init()
}
urlExcludes(): RegExp[] {
return [ATK_PAGE_REG];
}
urlIncludes(): RegExp[] {
return [ALL_PAGE_REG];
}
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
) {
}
init() {
const list = this.localConfigWrapper.config.monitorOn
for (let i = 0; i < list.length; i++) {
intervalUnits[list[i]].switcher(IntervalSwitch.ON)
}
}
}

View File

@ -1,32 +1,30 @@
import "reflect-metadata";
import { Container } from "../../container/Container";
import Logger from "../Logger";
import globVars from "../../globVars";
import Logger from "../class/Logger";
import globVars from "../globVars";
import { Container } from "../container/Container";
export default function EntryPoint(T: { main: () => void }) {
export default function EntryPoint(Index: ClassType<{}> & { main: () => void }) {
const logger = Logger.factory(Index);
if (window.WHTRANS) {
console.log('退出, 已运行次数' + window.WHTRANS)
logger.warn('退出, 已运行次数' + window.WHTRANS)
} else {
window.WHTRANS = window.WHTRANS === undefined ? 1 : window.WHTRANS++;
const logger = Container.factory(Logger);
let started = false;
const starter = () => {
console.log('starter init...');
let started = performance.now();
try {
T.main();
Container.setLogger(Container.factory(Logger))
Index.main()
} catch (e) {
logger.error('[Starter]加载出错信息: ' + e.stack || e.message);
logger.error('加载出错: ' + e.stack || e.message);
}
let runTime: number = (performance.now() - started) | 0;
globVars.loadTime = runTime;
logger.info(`芜湖脚本完成加载, 耗时${ runTime }ms`);
// if (ZhongIcon.ZhongNode && ZhongIcon.ZhongNode.initTimer)
// ZhongIcon.ZhongNode.initTimer.innerHTML = `加载时间 ${ runTime }ms`;
};
const evHandler = () => {
// console.log('document.readyState: ' + document.readyState);
if (!started && (document.readyState === 'complete' || document.readyState === 'interactive')) {
document.removeEventListener('readystatechange', evHandler);
started = !started;

View File

@ -4,7 +4,6 @@ import ClassName from "../container/ClassName";
import Debug from "../class/provider/Debug";
import "reflect-metadata";
import { Injectable } from "../container/Injectable";
import { ButtonHandler } from "../class/provider/ButtonHandler";
import { Container } from "../container/Container";
import NetHighLvlWrapper from "../class/utils/NetHighLvlWrapper";
import Logger from "../class/Logger";
@ -12,7 +11,6 @@ import QuickGymTrain from "../class/action/QuickGymTrain";
import LocalConfigWrapper from "../class/LocalConfigWrapper";
import { ElMessage } from "element-plus";
@ButtonHandler
@ClassName('Test')
@Injectable()
class Test {

View File

@ -6,7 +6,7 @@
<MoonNight/>
</el-icon>
</el-button>
<el-button v-for="item in _globVars.actionList" @click="item.func">{{ item.txt }}</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>
@ -102,7 +102,7 @@
<el-row>
<el-col :span="24">
<el-tooltip content="更新?" placement="bottom-start">
<el-button link @click="menuClick({ title: '更新', template: UpdateDate })">芜湖助手
<el-button link @click="menuClick({ title: '关于助手', template: UpdateDate })">芜湖助手
<el-icon>
<Refresh/>
</el-icon>
@ -131,42 +131,44 @@
</div>
</el-drawer>
</el-config-provider>
<!-- <div id="wh123">{{ sessionObject }}</div>-->
<!-- <div id="wh1234">{{ session }}</div>-->
</template>
<script lang="ts" setup>
import { CopyDocument, MoonNight, Refresh } from "@element-plus/icons-vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { Component, inject, onMounted, ref, shallowRef, triggerRef } from 'vue';
import { LoggerKey } from "../ts/class/Logger";
import { QuickGymTrainKey } from "../ts/class/action/QuickGymTrain";
import { QuickFlyBtnHandlerKey } from "../ts/class/handler/QuickFlyBtnHandler";
import SettingsHandler from "../ts/class/handler/SettingsHandler";
import { BATTLE_STAT } from "../ts/class/utils/NetHighLvlWrapper";
import adHelper from "../ts/func/module/adHelper";
import safeKeeper from "../ts/func/module/safeKeeper";
import useItem from "../ts/func/utils/useItem";
import globVars from "../ts/globVars";
import AutoLoginForm from "./AutoLoginForm.vue";
import CityUItems from "./CityUItems.vue";
import CompanyWithdraw from "./CompanyWithdraw.vue";
import EventsViewer from "./EventsViewer.vue";
import ForeignStock from "./ForeignStock.vue";
import InventoryView from "./InventoryView.vue";
import MarketHelper from "./MarketHelper.vue";
import PTMarketView from "./PTMarketView.vue";
import QuickCrime from "./QuickCrime.vue";
import UpdateDate from "./UpdateScript.vue";
import VirusProgramming from "./VirusProgramming.vue";
import getSidebarData from "../ts/func/utils/getSidebarData";
import MonitorMgrView from "./MonitorMgrView.vue";
import ChangeLogView from "./ChangeLogView.vue";
import { CopyDocument, MoonNight, Refresh } from "@element-plus/icons-vue"
import { ElMessage, ElMessageBox } from "element-plus"
import { Component, inject, onMounted, ref, shallowRef, triggerRef } from 'vue'
import { LoggerKey } from "../ts/class/Logger"
import { QuickGymTrainKey } from "../ts/class/action/QuickGymTrain"
import { QuickFlyBtnHandlerKey } from "../ts/class/handler/QuickFlyBtnHandler"
import SettingsHandler from "../ts/class/handler/SettingsHandler"
import { BATTLE_STAT } from "../ts/class/utils/NetHighLvlWrapper"
import adHelper from "../ts/func/module/adHelper"
import safeKeeper from "../ts/func/module/safeKeeper"
import useItem from "../ts/func/utils/useItem"
import globVars from "../ts/globVars"
import AutoLoginForm from "./AutoLoginForm.vue"
import CityUItems from "./CityUItems.vue"
import CompanyWithdraw from "./CompanyWithdraw.vue"
import EventsViewer from "./EventsViewer.vue"
import ForeignStock from "./ForeignStock.vue"
import InventoryView from "./InventoryView.vue"
import MarketHelper from "./MarketHelper.vue"
import PTMarketView from "./PTMarketView.vue"
import QuickCrime from "./QuickCrime.vue"
import UpdateDate from "./UpdateScript.vue"
import VirusProgramming from "./VirusProgramming.vue"
import getSidebarData from "../ts/func/utils/getSidebarData"
import MonitorMgrView from "./MonitorMgrView.vue"
import ChangeLogView from "./ChangeLogView.vue"
const logger = inject(LoggerKey);
const quickGymTrain = inject(QuickGymTrainKey);
const quickFlyBtnHandler = inject(QuickFlyBtnHandlerKey);
const logger = inject(LoggerKey)
const quickGymTrain = inject(QuickGymTrainKey)
const quickFlyBtnHandler = inject(QuickFlyBtnHandlerKey)
type MenuItem = { title: string, template?: Component, handler?: Function };
type MenuItem = { title: string, template?: Component, handler?: Function }
const menuItemList: MenuItem[] = [
{
title: '💊 吃 XAN',
@ -290,16 +292,16 @@ const menuItemList: MenuItem[] = [
SettingsHandler.clickFunc()
},
},
];
const drawer = ref(false);
const isMobilePhone = ref(false);
const documentHeight = ref(0);
const expanded = ref(false);
const _globVars = ref(globVars);
logger.info({ _globVars })
]
const drawer = ref(false)
const isMobilePhone = ref(false)
const documentHeight = ref(0)
const expanded = ref(false)
const _globVars = ref(globVars)
// tabs
const editableTabsValue = ref('');
const editableTabs = shallowRef([]);
const editableTabsValue = ref('')
const editableTabs = shallowRef([])
// fast travel
const travelData = [
@ -314,7 +316,7 @@ const travelData = [
{ cName: "🇨🇳 祖国", index: 8 },
{ cName: "🇦🇪 阿联酋 (UAE)", index: 9 },
{ cName: "🇿🇦 南非", index: 10 },
];
]
const menuClick = (menuItem: MenuItem) => {
if (menuItem.handler) {
@ -323,7 +325,7 @@ const menuClick = (menuItem: MenuItem) => {
drawer.value = true;
addTab(menuItem);
}
};
}
const showDrawer = () => {
if (editableTabs.value.length < 1) {
@ -381,10 +383,6 @@ const removeTab = (targetName: string) => {
}
};
// const tabClick = (pane: TabsPaneContext) => {
// drawerTitle.value = <string>pane.paneName;
// }
const travelConfirm = (destIndex: number, typeIndex: number) => {
const destName = travelData[destIndex].cName;
const typeName = ['普通飞机', 'PI飞机', '股票飞机', '商务飞机(机票或内衣店)'][typeIndex];
@ -469,6 +467,15 @@ onMounted(() => {
}
documentHeight.value = document.documentElement.scrollHeight;
});
// watch(_globVars, (_globVars, pre) => {
// logger.info({ _globVars, pre })
// _buttons.value = []
// let keys = Object(globVars.buttons).keys()
// for (let i = 0; i < keys.length; i++) {
// _buttons.value.push(globVars.buttons[keys[i]])
// }
// }, { deep: true })
</script>
<style scoped>

View File

@ -14,11 +14,12 @@
import { CommonUtilsKey } from "../ts/class/utils/CommonUtils";
import { inject, onMounted, ref } from "vue";
import UserScriptEngine from "../ts/enum/UserScriptEngine.js";
import { TravelItemKey } from "../ts/class/action/TravelItem";
import TravelItem from "../ts/feature/TravelItem";
import { LoggerKey } from "../ts/class/Logger";
import { Container } from "../ts/container/Container";
const commonUtils = inject(CommonUtilsKey);
const travelItem = inject(TravelItemKey);
const travelItem = Container.factory(TravelItem)
const logger = inject(LoggerKey);
const loading = ref(true);
const staticImageSrc = 'https://jjins.github.io/t2i/stock.png?' + Date.now();

View File

@ -23,8 +23,8 @@
<script lang="ts" setup>
import { onMounted, ref, watch } from "vue";
import drugCDMonitor from "../ts/class/interval/DrugCDMonitor";
import IntervalSwitch from "../ts/class/interval/IntervalSwitch";
import drugCDMonitor from "../ts/monitor/DrugCDMonitor";
import IntervalSwitch from "../ts/monitor/IntervalSwitch";
import { Container } from "../ts/container/Container";
import LocalConfigWrapper from "../ts/class/LocalConfigWrapper";
import Logger from "../ts/class/Logger";

View File

@ -1,13 +1,15 @@
<script lang="ts" setup>
import { ElMessage } from "element-plus";
import { inject, ref } from "vue";
import { inject, onMounted, ref } from "vue";
import { LoggerKey } from "../ts/class/Logger";
import CommonUtils from "../ts/class/utils/CommonUtils";
import globVars from "../ts/globVars";
const logger = inject(LoggerKey)
const loading = ref(false)
const featureStatus = ref(globVars.featureStatus)
const now = performance.now()
const loadAndCopy = async () => {
@ -31,53 +33,72 @@ const loadAndCopy = async () => {
loading.value = false
}
onMounted(() => logger.info({ featureStatus }))
</script>
<template>
<el-space direction="vertical" style="width: 100%">
<el-row>
<el-text>最新版本:
<el-image :src="'https://jjins.github.io/t2i/version.png?' + now" alt="latest"
style="width: 80px;height: 16px"/>
<el-card class="card" shadow="never">
<template #header>更新</template>
<el-space direction="vertical" style="width: 100%">
<el-row>
<el-text>最新版本:
<el-image :src="'https://jjins.github.io/t2i/version.png?' + now" alt="latest"
style="width: 80px;height: 16px"/>
</el-text>
</el-row>
<el-row>
<el-text size="large">电脑</el-text>
</el-row>
<el-text>浏览器运行油猴等用户脚本扩展
<el-image alt="tm.png" src="//jjins.github.io/tm.png"/>
<el-image alt="vm.png"
src="//jjins.github.io/vm.png"/>
时可以使用链接安装自动更新:
<el-link
href="//gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/release.min.user.js" target="_blank"
type="primary">点此安装
</el-link>
</el-text>
</el-row>
<el-row>
<el-text size="large">电脑</el-text>
</el-row>
<el-text>浏览器运行油猴等用户脚本扩展
<el-image alt="tm.png" src="//jjins.github.io/tm.png"/>
<el-image alt="vm.png"
src="//jjins.github.io/vm.png"/>
时可以使用链接安装自动更新:
<el-link
href="//gitlab.com/JJins/wuhu-torn-helper/-/raw/dev/release.min.user.js" target="_blank"
type="primary">点此安装
</el-link>
</el-text>
<el-divider/>
<el-col>
<el-text size="large">手机</el-text>
</el-col>
<el-text>安卓 ( KIWI) 等可以用油猴脚本的浏览器也可以点上面的链接安装</el-text>
<el-text>Torn PDA app Alook 用户可打开
<el-link href="//jjins.github.io/fyfuzhi/" target="_blank"
type="primary">此页面
</el-link>
快捷复制粘贴
</el-text>
<el-text>Torn PDA Injection time 请选择 Start 达到最好效果</el-text>
<el-divider/>
<el-col>
<el-text size="large">直接复制</el-text>
</el-col>
<el-text>加载脚本后复制粘贴到用户脚本处</el-text>
<el-button :loading="loading" @click="loadAndCopy">加载</el-button>
</el-space>
<el-divider/>
<el-col>
<el-text size="large">手机</el-text>
</el-col>
<el-text>安卓 ( KIWI) 等可以用油猴脚本的浏览器也可以点上面的链接安装</el-text>
<el-text>Torn PDA app Alook 用户可打开
<el-link href="//jjins.github.io/fyfuzhi/" target="_blank"
type="primary">此页面
</el-link>
快捷复制粘贴
</el-text>
<el-text>Torn PDA Injection time 请选择 Start 达到最好效果</el-text>
<el-divider/>
<el-col>
<el-text size="large">直接复制</el-text>
</el-col>
<el-text>加载脚本后复制粘贴到用户脚本处</el-text>
<el-button :loading="loading" @click="loadAndCopy">加载</el-button>
</el-space>
</el-card>
<el-card class="card" shadow="never">
<template #header>功能状况</template>
<el-table :data="featureStatus" border style="width: 100%">
<el-table-column label="描述" prop="desc"/>
<el-table-column label="状态" prop="status"/>
<el-table-column label="类名" prop="clazz"/>
<el-table-column label="加载(ms)" prop="load"/>
</el-table>
</el-card>
</template>
<style scoped>
.el-image {
width: 20px;
}
.card {
margin-bottom: 10px;
}
</style>