This commit is contained in:
Liwanyi 2023-03-24 18:23:41 +08:00
parent 220b2b87a6
commit dfde341070
38 changed files with 715 additions and 157 deletions

View File

@ -3,13 +3,16 @@
* 并生成日期时间与版本号
*/
import rollupConfig from "./rollup-prod.config.js";
import { readFileSync, rmSync, writeFileSync } from "fs";
let startTime = Date.now();
let fs = require('fs');
let date = new Date();
let version = process.env.npm_package_version;
let formattedDateTime = `${ date.getFullYear() }${ ('0' + (date.getMonth() + 1)).slice(-2) }${ ('0' + date.getDate()).slice(-2) }${ ('0' + date.getHours()).slice(-2) }${ ('0' + date.getMinutes()).slice(-2) }`;
let metaData = `// ==UserScript==
let metaData =
`// ==UserScript==
// @lastmodified ${ formattedDateTime }
// @name 芜湖助手
// @namespace WOOH
@ -29,6 +32,11 @@ let metaData = `// ==UserScript==
// ==/UserScript==
`
const data = fs.readFileSync('./dist/bundle.min.js', 'utf8');
fs.writeFileSync('./release.min.user.js', metaData + data.replace('$$WUHU_DEV_VERSION$$', version), 'utf8');
console.log(`版本 ${ version } 构建完成, build.js耗时${ Date.now() - startTime }ms`);
const data = readFileSync('./' + rollupConfig.output.file, 'utf8');
writeFileSync(
'./release.min.user.js',
metaData + data.replace('$$WUHU_DEV_VERSION$$', version),
'utf8'
);
rmSync('./' + rollupConfig.output.file);
console.log(`版本 ${ version } 构建完成, build.mjs耗时${ Date.now() - startTime }ms`);

9
global.d.ts vendored
View File

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

17
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "wuhu-torn-helper",
"version": "0.8.2",
"version": "0.8.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "wuhu-torn-helper",
"version": "0.8.2",
"version": "0.8.4",
"devDependencies": {
"@rollup/plugin-alias": "^4.0.3",
"@rollup/plugin-json": "^4.1.0",
@ -20,6 +20,7 @@
"@vue/tsconfig": "^0.1.3",
"cross-env": "^7.0.3",
"npm": "^8.19.2",
"reflect-metadata": "^0.1.13",
"rollup": "^2.79.0",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-string-html": "^1.0.0",
@ -4982,6 +4983,12 @@
"safe-buffer": "^5.1.0"
}
},
"node_modules/reflect-metadata": {
"version": "0.1.13",
"resolved": "https://registry.npmmirror.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==",
"dev": true
},
"node_modules/relateurl": {
"version": "0.2.7",
"resolved": "https://registry.npmmirror.com/relateurl/-/relateurl-0.2.7.tgz",
@ -8966,6 +8973,12 @@
"safe-buffer": "^5.1.0"
}
},
"reflect-metadata": {
"version": "0.1.13",
"resolved": "https://registry.npmmirror.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz",
"integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==",
"dev": true
},
"relateurl": {
"version": "0.2.7",
"resolved": "https://registry.npmmirror.com/relateurl/-/relateurl-0.2.7.tgz",

View File

@ -3,7 +3,7 @@
"version": "0.8.4",
"description": "芜湖助手",
"scripts": {
"release": "cross-env NODE_ENV=production rollup -c rollup-prod.config.js && node build.js",
"release": "cross-env NODE_ENV=production rollup -c rollup-prod.config.js && node build.mjs",
"watch": "cross-env NODE_ENV=development rollup -c -w",
"rollup": "cross-env NODE_ENV=development rollup -c"
},
@ -20,6 +20,7 @@
"@vue/tsconfig": "^0.1.3",
"cross-env": "^7.0.3",
"npm": "^8.19.2",
"reflect-metadata": "^0.1.13",
"rollup": "^2.79.0",
"rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-string-html": "^1.0.0",

View File

@ -2,7 +2,6 @@ import depoHelper from "../func/module/depoHelper";
import travelHelper from "../func/module/travelHelper";
import priceWatcherHandle from "../func/module/priceWatcherHandle";
import WuhuBase from "./WuhuBase";
import WuhuConfig from "./WuhuConfig";
import CompanyHelper from "./action/CompanyHelper";
import AttackHelper from "./action/AttackHelper";
import SidebarHelper from "./action/SidebarHelper";
@ -14,12 +13,22 @@ import Alert from "./utils/Alert";
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";
/**
*
*/
@Injectable()
@ClassName('Common')
export class Common extends WuhuBase {
className = 'Common';
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
) {
super();
}
public resolve(mainMethod) {
let glob = Common.glob;
@ -27,7 +36,7 @@ export class Common extends WuhuBase {
priceWatcherHandle(glob.isPDA, glob.PDA_APIKey);
// 啤酒提醒
if (WuhuConfig.get('_15Alarm')) glob.beer.start();
if (this.localConfigWrapper.config._15Alarm) glob.beer.start();
SidebarHelper.getInstance();
@ -38,7 +47,7 @@ export class Common extends WuhuBase {
* All('script[src*="chat/gonline"]')
* All('head script[nonce]')
*/
if (document.readyState === 'interactive' && WuhuConfig.get('SolveGoogleScriptPendingIssue')) {
if (document.readyState === 'interactive' && this.localConfigWrapper.config.SolveGoogleScriptPendingIssue) {
window.stop();
document.open();
document.addEventListener('readystatechange', function readyStateChangeHandler() {
@ -83,15 +92,15 @@ export class Common extends WuhuBase {
CompanyHelper.getInstance();
// 自定义CSS
if (WuhuConfig.get('CustomCss')) {
if (this.localConfigWrapper.config.CustomCss) {
Log.info('应用自定义CSS');
CommonUtils.addStyle(WuhuConfig.get('CustomCss'));
CommonUtils.addStyle(this.localConfigWrapper.config.CustomCss);
}
// 现金变动提醒
if (WuhuConfig.get('CashChangeAlert')) CommonUtils.elementReady("#user-money").then(userMoney => {
if (this.localConfigWrapper.config.CashChangeAlert) CommonUtils.elementReady("#user-money").then(userMoney => {
new MutationObserver((mutations, observer) => {
if (!WuhuConfig.get('CashChangeAlert')) {
if (!this.localConfigWrapper.config.CashChangeAlert) {
observer.disconnect();
new Alert('现金变动提醒已关闭', { sysNotify: true });
return;

View File

@ -4,10 +4,14 @@ import IGlobal from "../interface/IGlobal";
import Log from "./Log";
import InfoUtils from "./utils/InfoUtils";
import BuyBeerHelper from "./action/BuyBeerHelper";
import { Injectable } from "../container/Injectable";
import ClassName from "../container/ClassName";
/**
*
*/
@Injectable()
@ClassName('Global')
export default class Global extends WuhuBase implements IGlobal {
className = 'Global';

View File

@ -0,0 +1,51 @@
import { Injectable } from "../container/Injectable";
import ClassName from "../container/ClassName";
import Logger from "./Logger";
import defaultConfig from "./config/defaultConfig";
type Config = typeof defaultConfig;
@Injectable()
@ClassName('LocalConfigWrapper')
export default class LocalConfigWrapper {
constructor(
private readonly logger: Logger,
) {
}
public get config(): Config {
let setLocal = this.setLocal;
return new Proxy(this.Local, {
get(target: Config, prop: string) {
return target[prop];
},
set(target: Config, prop: string, value: any): boolean {
let config = target;
config[prop] = value;
setLocal(config);
return true;
}
})
}
/**
* localstorage解析返回配置对象
* @private
*/
private get Local(): Config {
let config: Config;
try {
config = JSON.parse(localStorage.getItem('wh_trans_settings'))
} catch (e) {
this.logger.error('配置获取失败, 载入默认');
config = defaultConfig;
localStorage.setItem('wh_trans_settings', JSON.stringify(defaultConfig));
}
return config;
}
private setLocal(config: Config) {
localStorage.setItem('wh_trans_settings', JSON.stringify(config));
}
}

19
src/ts/class/Logger.ts Normal file
View File

@ -0,0 +1,19 @@
import ClassName from "../container/ClassName";
import { Injectable } from "../container/Injectable";
import Log from "./Log";
@Injectable()
@ClassName('Logger')
export default class Logger {
info(...o: any): void {
return Log.info(...o);
}
warn(...o: any): void {
return Log.warn(...o);
}
error(...o: any): void {
return Log.error(...o);
}
}

View File

@ -0,0 +1,11 @@
import Logger from "./Logger";
export default class ModuleLoader {
constructor(
private readonly logger: Logger,
) {
}
public async load(modules: any[]): Promise<void> {
}
}

View File

@ -21,22 +21,31 @@ import SearchHelper from "./action/SearchHelper";
import TornStyleSwitch from "./utils/TornStyleSwitch";
import SlotsHelper from "./action/SlotsHelper";
import globVars from "../globVars";
import { Injectable } from "../container/Injectable";
import ClassName from "../container/ClassName";
import LocalConfigWrapper from "./LocalConfigWrapper";
/**
*
*
* TODO jq
*/
@Injectable()
@ClassName('UrlPattern')
export default class UrlPattern extends WuhuBase {
className = 'UrlPattern';
constructor(
private readonly localConfigWrapper: LocalConfigWrapper,
) {
super();
}
public resolve(): void {
let href = window.location.href;
// 捡垃圾助手
if (href.includes('city.php') && WuhuConfig.get('cityFinder')) {
if (href.includes('city.php') && this.localConfigWrapper.config.cityFinder) {
let _base = new TornStyleBlock('芜湖助手').insert2Dom();
let reloadSwitch = new TornStyleSwitch('解决一直转圈(加载中)的问题');
reloadSwitch.getInput().checked = WuhuConfig.get('SolveGoogleScriptPendingIssue');
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);

View File

@ -38,7 +38,6 @@ export default class WuhuConfig extends WuhuBase {
*
*/
public static setDefaults(): void {
Log.info('设置默认值开始');
let count = 0;
[
// 开启翻译
@ -139,6 +138,6 @@ export default class WuhuConfig extends WuhuBase {
count++;
}
});
Log.info('设置默认值结束,新:' + count);
Log.info('设置默认值,新:' + count);
}
}

View File

@ -5,22 +5,27 @@ import Global from "./Global";
import Log from "./Log";
import COMMON_CSS from "../../static/css/common.css";
import globVars from "../globVars";
import { Injectable } from "../container/Injectable";
import ClassName from "../container/ClassName";
/**
*
*/
@Injectable()
@ClassName('WuHuTornHelper')
export default class WuHuTornHelper extends WuhuBase {
className = 'WuHuTornHelper';
constructor() {
constructor(
private readonly travelItem: TravelItem,
private readonly global: Global
) {
super();
}
public init() {
Log.info('WuHuTornHelper初始化');
WuhuBase.glob = Global.getInstance();
WuhuBase.glob = this.global;
let glob = WuHuTornHelper.glob;
glob.fStock = TravelItem.getInstance();
glob.fStock = this.travelItem;
// 请求通知权限
if (window.Notification) {
@ -80,8 +85,8 @@ export default class WuHuTornHelper extends WuhuBase {
(function (fetch0, window) {
let originFetch = fetch0;
// 引用解决与其他脚本接管fetch方法引起的兼容性问题
if (Global.getInstance().unsafeWindow) {
originFetch = Global.getInstance().unsafeWindow.fetch;
if (glob.unsafeWindow) {
originFetch = glob.unsafeWindow.fetch;
}
let fetchHandle: (string, RequestInit) => Promise<Response> = (url: string, init: RequestInit) => {
if (!init) init = { method: 'GET' };
@ -112,7 +117,7 @@ export default class WuHuTornHelper extends WuhuBase {
window.fetch = fetchHandle;
// @ts-ignore
fetch = fetchHandle;
})(fetch || window.fetch, Global.getInstance().unsafeWindow || window);
})(fetch || window.fetch, glob.unsafeWindow || window);
// 监听xhr
(function (xhr) {

View File

@ -20,10 +20,15 @@ import NNB from "./handler/NNB";
import QuickLinksHandler from "./handler/QuickLinksHandler";
import ItemPriceWatcherHandler from "./handler/ItemPriceWatcherHandler";
import ChangeLogHandler from "./handler/ChangeLogHandler";
import SettingsHandler from "./handler/SettingsHandler";
import WuhuConfig from "./WuhuConfig";
import ItemPriceHandler from "./handler/ItemPriceHandler";
import SettingsHandler from "./handler/SettingsHandler";
import { MENU_ITEM_TYPE } from "../interface/MenuItem";
import { Injectable } from "../container/Injectable";
import ClassName from "../container/ClassName";
@Injectable()
@ClassName('ZhongIcon')
export default class ZhongIcon extends WuhuBase {
className = 'ZhongIcon';
public static ZhongNode: MyHTMLElement = null;
@ -32,7 +37,10 @@ export default class ZhongIcon extends WuhuBase {
// private settingItemList: MenuItemConfig[] = null;
public constructor() {
public constructor(
private readonly global: Global,
private readonly commonUtils: CommonUtils
) {
super();
}
@ -68,8 +76,7 @@ export default class ZhongIcon extends WuhuBase {
*/
private insert2Dom(): ZhongIcon {
let zhongNode: MyHTMLElement = document.querySelector('div#wh-trans-icon');
let settings = this.menuItemList;
let { version } = WuhuBase.glob;
let { version } = this.global;
if ((self !== top) || !!zhongNode) return null;
zhongNode = document.createElement('div');
ZhongIcon.ZhongNode = zhongNode;
@ -79,7 +86,7 @@ export default class ZhongIcon extends WuhuBase {
// 助手菜单
const menu_cont = zhongNode.querySelector('#wh-gSettings');
// 遍历菜单node设置、生成node、插入dom
this.menuItemList.forEach(setting => CommonUtils.getInstance().elemGenerator(setting, menu_cont));
this.menuItemList.forEach(setting => this.commonUtils.elemGenerator(setting, menu_cont));
Log.info('生成元素插入完成');
// 计时node
zhongNode.initTimer = zhongNode.querySelector('#wh-inittimer');
@ -405,45 +412,13 @@ export default class ZhongIcon extends WuhuBase {
}
});
// 物品查价
list.push({
domType: 'button',
domId: '',
domText: '🍺 物品查价',
clickFunc() {
ItemPriceHandler.show();
}
});
list.push(ItemPriceHandler);
// 更新历史
list.push({
domType: 'button',
domId: '',
domText: '🐞 更新历史',
clickFunc: async () => ChangeLogHandler.getInstance().handle()
});
list.push(ChangeLogHandler);
// 助手设置
list.push({
domType: 'button',
domId: '',
domText: '⚙️ 助手设置',
clickFunc: () => SettingsHandler.getInstance().handler(),
});
list.push(SettingsHandler);
// 测试
if (Log.debug()) list.push({
domType: 'button',
domId: '',
domText: '📐️ 测试',
clickFunc: async function () {
let startTime = performance.now();
Log.info('测试开始');
try {
Test.getInstance().test();
} catch (e) {
Log.error('测试异常,' + JSON.stringify(e));
}
Log.info('测试结束 ' + ((performance.now() - startTime) | 0) + 'ms');
},
});
if (Log.debug()) list.push(Test);
this.menuItemList = list;
Log.info('构造展开菜单列表结束' + timer.getTimeMs());
@ -452,7 +427,7 @@ export default class ZhongIcon extends WuhuBase {
}
export interface MenuItemConfig {
domType: 'button' | 'plain' | 'checkbox' | 'select';
domType: 'button' | 'plain' | 'checkbox' | 'select' | MENU_ITEM_TYPE;
tagName?: string;
domId?: string;
domText?: string;

View File

@ -19,7 +19,8 @@ export default class ProfileHelper extends WuhuBase implements ResponseInject {
constructor() {
super();
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 = document.querySelector('link[rel="canonical"]').getAttribute('href').split('=')[1];
let id = (new URL(window.location.href)).searchParams.get('XID');
// id获取格式判断
if (!CommonUtils.getInstance().isValidUid(id)) {
Log.error('[ProfileHelper] id格式错误');

View File

@ -0,0 +1,39 @@
import ClassName from "../../container/ClassName";
import { Injectable } from "../../container/Injectable";
import Logger from "../Logger";
import NetHighLvlWrapper, { BATTLE_STAT } from "../utils/NetHighLvlWrapper";
import Alert from "../utils/Alert";
type GymResponse = {
success: boolean,
// 成功才有 You gained 689,636.71 strength
gainMessage?: string,
message: string,
text?: string,
error?: string,
};
@ClassName("QuickGymTrain")
@Injectable()
export default class QuickGymTrain {
constructor(
private readonly logger: Logger,
private readonly netHighLvlWrapper: NetHighLvlWrapper,
) {
}
doTrain() {
window.setTimeout(async () => {
let resObj: GymResponse;
try {
resObj = JSON.parse(await this.netHighLvlWrapper.doGymTrain(BATTLE_STAT.STR, 199))
} catch (e) {
resObj = { success: false, message: '解析失败' };
this.logger.error(e.stack || e.message || e);
}
let msgRs = resObj.success ? '成功' : '失败';
let msgMsg = resObj.message || resObj.text || resObj.error;
new Alert('锻炼结果: ' + msgRs + '<br/>提示: ' + (resObj.gainMessage || msgMsg));
}, 0);
}
}

View File

@ -6,7 +6,11 @@ import Popup from "../utils/Popup";
import STOCK_IMG_HTML from "../../../static/html/stock_img.html";
import * as FILTER from "../../../static/json/for_stock_item_filter.json";
import WindowActiveState from "./WindowActiveState";
import { Injectable } from "../../container/Injectable";
import ClassName from "../../container/ClassName";
@Injectable()
@ClassName('TravelItem')
export default class TravelItem extends WuhuBase {
className = 'TravelItem';
private readonly apiUrl: string = 'https://yata.yt/api/v1/travel/export/';
@ -58,4 +62,4 @@ export default class TravelItem extends WuhuBase {
private async get() {
return this.foreignStockInfo ||= JSON.parse(await CommonUtils.COFetch(this.apiUrl));
}
}
}

View File

@ -0,0 +1,86 @@
const defaultConfig = {
// 开启翻译
transEnable: false,
transNew: true,
// 快速犯罪
quickCrime: true,
// 任务助手
missionHint: true,
// 小镇攻略
xmasTownWT: true,
// 小镇提醒
xmasTownNotify: true,
// 起飞爆e
energyAlert: true,
// 飞行闹钟
trvAlarm: true,
// 啤酒提醒
_15Alarm: true,
// 捡垃圾助手
cityFinder: false,
// 叠E保护
SEProtect: false,
// PT一键购买
ptQuickBuy: false,
// 光速拔刀 6-关闭
quickAttIndex: 2,
// 光速跑路 0-leave 1-mug 2-hos 3-关闭
quickFinishAtt: 3,
// 自动开打和结束
autoStartFinish: false,
// 攻击自刷新 0-无间隔 1-5s 6-关闭
attReload: 6,
// 价格监视
priceWatcher: { xan: -1, pt: -1 },
// 开发者模式
isDev: false,
// 啤酒提醒时间
_15AlarmTime: 50,
// 4条转跳
barsRedirect: true,
// 浮动存钱框
floatDepo: true,
// 公司转跳存钱
companyRedirect: true,
// 收起公司冰蛙效率表
companyBWCollapse: true,
// 海外警告
abroadWarning: true,
// 落地转跳
landedRedirect: '',
// 任何位置一键存钱
companyDepositAnywhere: false,
// 火车提醒时间
CHTrainsDetect: 0,
// 火车提醒开关
CHTrainsDetectSwitch: true,
// 隐藏个人资料头像
HideProfileImg: false,
// 显示曾用名
ShowNameHistory: true,
// 盯梢模式强度 0-550 1-950 2-1450 ms
WatchTargetFreq: 1,
// 隐藏侧边栏
HideSidebar: false,
// 添加隐藏边栏按钮
HideSidebarBtn: true,
// 搜索页占位区
SearchPagePlaceholder: true,
// 解决一直转圈(加载中)的问题
SolveGoogleScriptPendingIssue: false,
// 图标坐标
IconPosition: {},
// 记住图标位置
SaveIconPosition: false,
// 现金变动提醒
CashChangeAlert: false,
// 收集数据以改进翻译质量
CollectPlayerData: true,
// 迷你资料卡显示上次行动时间
ShowMiniProfLastAct: true,
// 自定义css
CustomCss: '',
};
// } as const;
export default defaultConfig;

View File

@ -10,7 +10,7 @@ import loadGS from "../../func/module/loadGS";
export default class AdditionalSettingsHandler extends WuhuBase {
className = 'AdditionalSettingsHandler';
public handle(): void {
public show(): void {
let pop = new Popup('', '更多设定');
// let insertHtml = '<p><button class="torn-btn">清空设置</button></p><p><button class="torn-btn">通知权限</button></p><p><button class="torn-btn">外部数据权限</button></p>';
// pop.getElement().insertAdjacentHTML('beforeend', insertHtml);
@ -74,4 +74,4 @@ export default class AdditionalSettingsHandler extends WuhuBase {
];
menuList.forEach(i => pop.getElement().append(CommonUtils.getInstance().elemGenerator(i, pop.getElement())));
}
}
}

View File

@ -1,13 +1,14 @@
import WuhuBase from "../WuhuBase";
import Popup from "../utils/Popup";
import CommonUtils from "../utils/CommonUtils";
import MDUtils from "../utils/MDUtils";
import Log from "../Log";
import { MENU_ITEM_TYPE } from "../../interface/MenuItem";
import Provider from "../provider/Provider";
export default class ChangeLogHandler extends WuhuBase {
class ChangeLogHandler extends Provider {
className = 'ChangeLogHandler';
public handle(): void {
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/>',
'更新历史'
@ -46,4 +47,11 @@ export default class ChangeLogHandler extends WuhuBase {
progressText.innerText = '无法加载';
});
}
}
}
export default {
domType: MENU_ITEM_TYPE.BUTTON,
domText: '🐞 更新历史',
clickFunc: () => ChangeLogHandler.getInstance().show()
};

View File

@ -1,14 +1,18 @@
import MenuHandler from "../../interface/MenuHandler";
import Popup from "../utils/Popup";
import { createApp } from "vue";
import ItemPrice from "../../../vue/ItemPrice.vue";
import { MENU_ITEM_TYPE } from "../../interface/MenuItem";
// 物品查价
export default <MenuHandler>{
show(): void {
createApp(ItemPrice).mount(
new Popup('', '物品查价', () => createApp(ItemPrice).unmount())
.getElement()
export default {
domType: MENU_ITEM_TYPE.BUTTON,
domId: '',
domText: '🍺 物品查价',
clickFunc: () => {
let app = createApp(ItemPrice);
app.mount(
new Popup('', '物品查价', () => app.unmount())
.element
);
}
}

View File

@ -1,4 +1,3 @@
import WuhuBase from "../WuhuBase";
import { MenuItemConfig } from "../ZhongIcon";
import Log from "../Log";
import Timer from "../utils/Timer";
@ -11,8 +10,10 @@ import AdditionalSettingsHandler from "./AdditionalSettingsHandler";
import Popup from "../utils/Popup";
import CommonUtils from "../utils/CommonUtils";
import CustomCssHandler from "./CustomCssHandler";
import Provider from "../provider/Provider";
import { MENU_ITEM_TYPE } from "../../interface/MenuItem";
export default class SettingsHandler extends WuhuBase {
class SettingsHandler extends Provider {
className = 'SettingsHandler';
private list: MenuItemConfig[] = [];
@ -22,7 +23,7 @@ export default class SettingsHandler extends WuhuBase {
this.constructWuhuSettingList();
}
public handler(): void {
public show(): void {
let startTime = new Timer();
Log.info('构造设置开始');
let pop = new Popup(CommonUtils.loading_gif_html(), '芜湖助手设置');
@ -556,10 +557,16 @@ export default class SettingsHandler extends WuhuBase {
list.push({
domType: 'button', domId: 'wh-otherBtn', domText: '更多设定',
isTornBtn: true,
clickFunc: () => AdditionalSettingsHandler.getInstance().handle()
clickFunc: () => AdditionalSettingsHandler.getInstance().show()
});
Log.info('构造设置列表结束' + timer.getTimeMs());
return this;
}
}
export default {
domType: MENU_ITEM_TYPE.BUTTON,
domText: '⚙️ 助手设置',
clickFunc: () => SettingsHandler.getInstance().show()
};

View File

@ -0,0 +1,12 @@
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

@ -0,0 +1,27 @@
import Log from "../Log";
/**
*
* @param target
* @param propertyKey
* @param descriptor
*/
export default function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {
const original = descriptor.value;
descriptor.value = function (...args) {
Log.info('[debug] 参数 ', JSON.stringify({
class: target.className || target.name,
method: propertyKey,
args
}));
let result;
try {
result = original.call(this, ...args) || null;
} catch (err) {
Log.error('[debug] 异常 ', err.stack || err.message || err);
}
result && Log.info('[debug] 结果 ', { result });
return result;
}
}

View File

@ -7,7 +7,7 @@ import ClassWithName from "../../interface/ClassWithName";
*/
export default class Provider implements ClassWithName {
readonly className: string = 'Provider';
private static instance;
private static _instance;
private static readonly pool = {};
@ -16,14 +16,14 @@ export default class Provider implements ClassWithName {
// 返回继承类的实例
public static getInstance<T extends typeof Provider>(this: T, ...args: unknown[]): InstanceType<T> {
if (!this.instance) {
if (!this._instance) {
let startTime = new Timer();
this.instance = new this(...args);
let thatName = this.instance.getClassName() || this.name;
Log.info('实例已创建,', thatName, this.instance, '耗时' + startTime.getTimeMs());
Provider.pool[thatName] = this.instance;
this._instance = new this(...args);
let thatName = this._instance.getClassName() || this.name;
Log.info('实例已创建,', thatName, this._instance, '耗时' + startTime.getTimeMs());
Provider.pool[thatName] = this._instance;
}
return this.instance;
return this._instance;
}
public static getPool() {

View File

@ -1,21 +0,0 @@
// import Log from "../Log";
// import ZhongIcon from "../ZhongIcon";
//
// export default class Starter {
// public static run(T): void {
//
// if (window.WHTRANS) throw '退出, 已运行次数' + window.WHTRANS;
// window.WHTRANS = window.WHTRANS === undefined ? 1 : window.WHTRANS++;
//
// let started = performance.now();
// try {
// T.main();
// } catch (e) {
// Log.error('[Starter]加载出错信息: ' + e.stack || e.message);
// }
// let runTime: number = (performance.now() - started) | 0;
// Log.info(`芜湖脚本完成加载, 耗时${ runTime }ms`);
// if (ZhongIcon.ZhongNode && ZhongIcon.ZhongNode.initTimer)
// ZhongIcon.ZhongNode.initTimer.innerHTML = `加载时间 ${ runTime }ms`;
// }
// }

View File

@ -10,7 +10,11 @@ import WuhuConfig from "../WuhuConfig";
import { MenuItemConfig } from "../ZhongIcon";
import TRAVEL_STATE from "../../enum/TravelState";
import InventoryItemInfo from "../../interface/responseType/InventoryItemInfo";
import { Injectable } from "../../container/Injectable";
import ClassName from "../../container/ClassName";
@Injectable()
@ClassName('CommonUtils')
export default class CommonUtils extends WuhuBase {
className = 'CommonUtils';

View File

@ -0,0 +1,44 @@
import { Injectable } from "../../container/Injectable";
import ClassName from "../../container/ClassName";
import Debug from "../provider/Debug";
@Injectable()
@ClassName('NetHighLvlWrapper')
export default class NetHighLvlWrapper {
@Debug
public async doGymTrain(type: BATTLE_STAT, count: number): Promise<string> {
let rs: string;
try {
rs = await (await window.fetch(
window.addRFC("https://www.torn.com/gym.php?step=train"),
{
"headers": {
"accept": "*/*",
"content-type": "application/json",
"sec-ch-ua-mobile": "?0",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"x-requested-with": "XMLHttpRequest"
},
"referrer": "https://www.torn.com/gym.php",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": `{\"step\":\"train\",\"stat\":\"${ type }\",\"repeats\":${ count }}`,
"method": "POST",
"mode": "cors",
"credentials": "include"
}
)).text();
} catch (e) {
rs = e.message;
}
return rs;
}
}
export enum BATTLE_STAT {
STR = 'strength',
DEF = 'defense',
SPD = 'speed',
DEX = 'dexterity'
}

View File

@ -46,8 +46,13 @@ export default class Popup extends WuhuBase {
this.showChat();
}
public get element(): HTMLElement {
return this.node;
}
/**
* @return {HTMLElement} id=wh-popup-cont
* @deprecated
*/
public getElement(): HTMLElement {
return this.node;

View File

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

View File

@ -0,0 +1,53 @@
import { assertInjectable } from "./Injectable";
import { GetClassName } from "./ClassName";
/**
*
*/
export class Container {
static _container = new Map();
private static logger;
static set(k: any, v: any): void {
if (Container._container.has(k)) {
Container._container.set(k, v);
}
}
static get(k: any): any {
return Container._container.get(k);
}
static factory<T>(target: Constructor<T>): T {
assertInjectable(target);
if (Container.get(target))
return Container.get(target);
return Container.initParam(target);
}
static setLogger(logger: { info(...o: any[]), error(...o: any[]), warn(...o: any[]) }): void {
this.logger = logger;
}
private static initParam<T>(target: Constructor<T>): T {
// 获取所有注入的服务
const providers = Reflect.getMetadata('design:paramtypes', target);
const args = providers ? providers.map((provider: Constructor) => {
assertInjectable(provider);
let inject;
if (Container.get(provider)) {
inject = Container.get(provider)
} else {
inject = Container.initParam(provider);
Container.set(provider, inject)
}
return inject;
}) : [];
let _target = new target(...args);
this.logger?.info(
`[${ GetClassName(target) || target.name }] 实例化`
);
Container.set(target, _target);
return _target;
}
}

View File

@ -0,0 +1,24 @@
import { GetClassName } from "./ClassName";
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 {
return function (target: any) {
Reflect.defineMetadata(INJECTABLE_METADATA_KEY, injectMode, target);
return target;
};
}
export function assertInjectable(target: any) {
if (!Reflect.getMetadata(INJECTABLE_METADATA_KEY, target)) {
throw new TypeError(
`[${ GetClassName(target) || target.constructor?.name || target.name }] not injectable`
);
}
}

View File

@ -7,35 +7,39 @@ import WuhuConfig from "./class/WuhuConfig";
import translateMain from "./func/translate/translateMain";
import CommonUtils from "./class/utils/CommonUtils";
import EntryPoint from "./class/provider/EntryPoint";
import { Container } from "./container/Container";
import Log from "./class/Log";
import LocalConfigWrapper from "./class/LocalConfigWrapper";
@EntryPoint
export default class Application {
public static main(): void {
Container.setLogger(Log);
WuhuBase.conditionInterrupt();
// 初始化
WuHuTornHelper.getInstance().init();
Container.factory(WuHuTornHelper).init();
// 插件设置默认值
WuhuConfig.setDefaults();
// 插件图标和设置菜单
ZhongIcon.getInstance().init();
Container.factory(ZhongIcon).init();
let tmp = () => {
// 所有页面通用
try {
Common.getInstance().resolve(Application.main);
Container.factory(Common).resolve(Application.main);
} catch (e) {
// if (e.message === '重载') Common.getInstance().resolve(null);
}
// URL匹配
UrlPattern.getInstance().resolve();
Container.factory(UrlPattern).resolve();
// 翻译
if (WuhuConfig.get('transEnable')) translateMain(window.location.href);
if (Container.factory(LocalConfigWrapper).config.transEnable)
translateMain(window.location.href);
};
// TODO 临时检测jquery
if (typeof $ === "function") {

View File

@ -1,3 +0,0 @@
export default interface MenuHandler {
show(): void
}

View File

@ -0,0 +1,12 @@
import { MenuItemConfig } from "../class/ZhongIcon";
export default interface MenuItem extends MenuItemConfig {
domType: MENU_ITEM_TYPE
}
export enum MENU_ITEM_TYPE {
BUTTON = 'button',
PLAIN = 'plain',
CHECKBOX = 'checkbox',
SELECT = 'select',
}

View File

@ -1,19 +1,37 @@
import WuhuBase from "../class/WuhuBase";
import Log from "../class/Log";
import Popup from "../class/utils/Popup";
import CompanyHelper from "../class/action/CompanyHelper";
import globVars from "../globVars";
import { MENU_ITEM_TYPE } from "../interface/MenuItem";
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";
import QuickGymTrain from "../class/action/QuickGymTrain";
import LocalConfigWrapper from "../class/LocalConfigWrapper";
export default class Test extends WuhuBase {
className = 'Test';
@ButtonHandler
@ClassName('Test')
@Injectable()
class Test {
constructor(
private readonly logger: Logger,
private readonly netHighLvlWrapper: NetHighLvlWrapper,
private readonly quickGymTrain: QuickGymTrain,
private readonly localConfigWrapper: LocalConfigWrapper,
) {
}
public test(): void {
let popup = new Popup('');
popup.getElement()['__POOL__'] = Test.getPool();
Log.info({ NET: globVars.WH_NET_LOG });
// let vueApp = createApp(ItemPrice);
// vueApp.mount('#wh-popup-cont');
// popup.setOnClosing(() => vueApp.unmount());
public show(): void {
this.test();
}
@Debug
private test() {
this.quickGymTrain.doTrain();
return 0;
}
private case1() {
@ -36,4 +54,74 @@ export default class Test extends WuhuBase {
private async case3() {
CompanyHelper.getInstance().detectNow();
}
private case4() {
Log.info('case4()');
}
}
export default {
domType: MENU_ITEM_TYPE.BUTTON,
domText: '🐞 测试2',
clickFunc: () => Container.factory(Test).show(),
}
// const Injectable = (): ClassDecorator => target => {
// };
@Injectable()
class OtherServiceC {
c = 3;
}
@Injectable()
class OtherServiceB {
b = 2;
constructor(private otherServiceC: OtherServiceC) {
}
printC() {
Log.info(this.otherServiceC.c)
}
}
@Injectable()
class OtherService {
a = 1;
constructor(private otherServiceB: OtherServiceB) {
}
testB() {
Log.info(this.otherServiceB.b);
this.otherServiceB.printC();
}
}
// // @Injectable(INJECT_MODE.Multi)
// @Injectable()
// class Logger {
// constructor(private readonly targetClass: string) {
// }
//
// info(str = 'test') {
// Log.info(str)
// }
// }
@Injectable()
@ClassName('TestService')
class TestService {
constructor(
public readonly otherService: OtherService,
) {
}
testMethod() {
Log.info(this.otherService.a);
this.otherService.testB();
// this.logger.info()
// Log.info(this.test);
}
}

49
src/vue/FloatMenu.vue Normal file
View File

@ -0,0 +1,49 @@
<template>
<div>
<button @click=""></button>
</div>
<div class="container">
<div class="main">
<div><b>芜湖助手</b></div>
<div id="itemList">
<div v-for="item in menuItemList">
<button v-if="item.domType === 'button'" @click="itemHandle(item.domId)">{{ item.domText }}</button>
<div v-if="item.domType === 'plain'" v-html="item.domHTML"></div>
</div>
</div>
<div>
<p>当前版本: {{ version }}
<button id="wh-update-btn">更新</button>
</p>
</div>
<div><p>最新版本: <span id="wh-latest-version"></span></p></div>
<div><p id="loadTime"></p></div>
</div>
</div>
</template>
<script lang="ts">
import MenuItem from "../ts/interface/MenuItem"
import Global from "../ts/class/Global";
import Log from "../ts/class/Log";
import { defineComponent } from "vue";
export default defineComponent({
name: "Hello",
data() {
return {
version: Global.getInstance().version,
menuItemList: <MenuItem[]>[],
}
},
methods: {
itemHandle(id: string) {
Log.info(id);
}
}
})
</script>
<style scoped>
</style>

View File

@ -1,13 +0,0 @@
<template>
</template>
<script>
export default {
name: "Hello"
}
</script>
<style scoped>
</style>

View File

@ -15,10 +15,7 @@
"experimentalDecorators": true,
"strictNullChecks": false,
"strictFunctionTypes": false,
"noImplicitThis": true
"noImplicitThis": true,
"emitDecoratorMetadata": true
}
// "exclude": [
// "./node_modules/*",
// "./node_modules",
// ]
}