515 lines
15 KiB
Vue
515 lines
15 KiB
Vue
<template>
|
|
<el-config-provider :size="'default'" :z-index="1000000">
|
|
<el-button-group class="wh-menu-button" style="z-index: 1000000;">
|
|
<el-button circle @click="expanded = !expanded">
|
|
<el-icon>
|
|
<MoonNight/>
|
|
</el-icon>
|
|
</el-button>
|
|
<el-button v-for="item in globVars.buttons" @click="item.func">{{ item.txt }}</el-button>
|
|
<el-button v-if="editableTabs.length > 0" circle @click="showDrawer">
|
|
<el-badge :value="editableTabs.length" type="primary">
|
|
<el-icon>
|
|
<CopyDocument/>
|
|
</el-icon>
|
|
</el-badge>
|
|
</el-button>
|
|
</el-button-group>
|
|
<el-dialog v-model="drawer" :fullscreen="isMobilePhone" :lock-scroll="true" width="65%">
|
|
<el-tabs v-model="editableTabsValue" closable style="margin-top: -1em" type="border-card" @tab-remove="removeTab">
|
|
<el-tab-pane v-for="item in editableTabs" :key="item.name" :label="item.title" :name="item.name">
|
|
<component :is="item.content"/>
|
|
</el-tab-pane>
|
|
</el-tabs>
|
|
</el-dialog>
|
|
<el-drawer v-model="expanded" :show-close="false" :size="isMobilePhone ? '85%' : '30%'" class="whDrawer"
|
|
:with-header="false" direction="rtl">
|
|
<el-card :body-style="{ 'padding': '0' }" class="innerCard" style="margin-bottom: 0.5em">
|
|
<template #header>
|
|
<div>快捷动作</div>
|
|
</template>
|
|
<el-menu :unique-opened="true">
|
|
<el-sub-menu index="1">
|
|
<template #title>
|
|
<el-icon>✈️</el-icon>
|
|
<span>起飞</span>
|
|
</template>
|
|
<el-sub-menu v-for="(item, i) in travelData" :index="'1-' + (i + 1)">
|
|
<template #title>{{ item.cName }}</template>
|
|
<el-menu-item :index="'1-' + (i + 1) + '1'" @click="travelConfirm(item.index, 0)">
|
|
❌ 普通飞机
|
|
</el-menu-item>
|
|
<el-menu-item :index="'1-' + (i + 1) + '2'" @click="travelConfirm(item.index, 1)">
|
|
✅ PI飞机
|
|
</el-menu-item>
|
|
<el-menu-item :index="'1-' + (i + 1) + '3'" @click="travelConfirm(item.index, 2)">
|
|
👍 股票飞机
|
|
</el-menu-item>
|
|
<el-menu-item :index="'1-' + (i + 1) + '4'" @click="travelConfirm(item.index, 3)">
|
|
🥵 商务飞机(机票或内衣店)
|
|
</el-menu-item>
|
|
</el-sub-menu>
|
|
</el-sub-menu>
|
|
<el-sub-menu index="2">
|
|
<template #title>
|
|
<el-icon>💪</el-icon>
|
|
<span>锻炼</span>
|
|
</template>
|
|
<el-menu-item @click="quickGymTrain.doTrain(BATTLE_STAT.STR)">力量 STR
|
|
</el-menu-item>
|
|
<el-menu-item @click="quickGymTrain.doTrain(BATTLE_STAT.DEF)">防御 DEF
|
|
</el-menu-item>
|
|
<el-menu-item @click="quickGymTrain.doTrain(BATTLE_STAT.SPD)">速度 SPD
|
|
</el-menu-item>
|
|
<el-menu-item @click="quickGymTrain.doTrain(BATTLE_STAT.DEX)">闪避 DEX
|
|
</el-menu-item>
|
|
</el-sub-menu>
|
|
<el-sub-menu index="3">
|
|
<template #title>
|
|
<el-icon>♻️</el-icon>
|
|
<span>REFILL</span>
|
|
</template>
|
|
<el-menu-item @click="handleRefil('refillEnergy')">能量E
|
|
</el-menu-item>
|
|
<el-menu-item @click="handleRefil('refillNerve')">犯罪N
|
|
</el-menu-item>
|
|
<el-menu-item @click="handleRefil('refillCasinoTokens')">赌场代币
|
|
</el-menu-item>
|
|
</el-sub-menu>
|
|
</el-menu>
|
|
</el-card>
|
|
<el-card :body-style="{ 'padding': '4px' }" class="innerCard">
|
|
<template #header>
|
|
<div>快捷功能</div>
|
|
</template>
|
|
<el-row style="display: flex;">
|
|
<el-col v-for="item in menuItemList" class="featureCol">
|
|
<el-card :body-class="'featureMenuBody'" class="featureMenu" shadow="never" @click="menuClick(item)">
|
|
<div>
|
|
<el-icon class="icon">{{ item.title.slice(0, 2) }}</el-icon>
|
|
</div>
|
|
<div class="title">
|
|
<span>{{ item.title.slice(2, item.title.length) }}</span>
|
|
</div>
|
|
</el-card>
|
|
</el-col>
|
|
</el-row>
|
|
</el-card>
|
|
<div style="margin-top: 1em; text-align: center">
|
|
<el-row>
|
|
<el-col :span="24">
|
|
<el-tooltip content="更新?" placement="bottom-start">
|
|
<el-button link @click="menuClick({ title: '关于助手', template: UpdateDate })">芜湖助手
|
|
<el-icon>
|
|
<Refresh/>
|
|
</el-icon>
|
|
</el-button>
|
|
</el-tooltip>
|
|
<el-tag size="small" type="info">{{
|
|
globVars.version.startsWith('$') ? 'dev' : 'v' + globVars.version
|
|
}}
|
|
</el-tag>
|
|
</el-col>
|
|
</el-row>
|
|
<el-row>
|
|
<el-col :span="24">
|
|
<el-text v-if="_globVars.loadTime" size="small">
|
|
{{ _globVars.loadTime }}ms
|
|
</el-text>
|
|
</el-col>
|
|
</el-row>
|
|
<el-row>
|
|
<el-col :span="24">
|
|
<el-text size="small">
|
|
2021-{{ new Date().getFullYear() }}
|
|
</el-text>
|
|
</el-col>
|
|
</el-row>
|
|
</div>
|
|
</el-drawer>
|
|
</el-config-provider>
|
|
</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 getSidebarData from "../ts/func/utils/getSidebarData"
|
|
import useItem from "../ts/func/utils/useItem"
|
|
import globVars from "../ts/globVars"
|
|
import AutoLoginForm from "./AutoLoginForm.vue"
|
|
import ChangeLogView from "./ChangeLogView.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 MonitorMgrView from "./MonitorMgrView.vue"
|
|
import PTMarketView from "./PTMarketView.vue"
|
|
import QuickCrime from "./QuickCrime.vue"
|
|
import UpdateDate from "./UpdateScript.vue"
|
|
import VirusProgramming from "./VirusProgramming.vue"
|
|
import PropertyVault from "./PropertyVault.vue";
|
|
import BSEstView from "./BSEstView.vue";
|
|
|
|
const logger = inject(LoggerKey)
|
|
const quickGymTrain = inject(QuickGymTrainKey)
|
|
const quickFlyBtnHandler = inject(QuickFlyBtnHandlerKey)
|
|
|
|
type MenuItem = { title: string, template?: Component, handler?: Function }
|
|
const menuItemList: MenuItem[] = [
|
|
{
|
|
title: '💊 吃 XAN',
|
|
handler: () => {
|
|
useItem('206')
|
|
const sidebarData = getSidebarData()
|
|
const cd = ((sidebarData.statusIcons.icons.drug_cooldown?.timerExpiresAt - sidebarData.statusIcons.icons.drug_cooldown?.serverTimestamp) / 36 | 0) / 100
|
|
ElMessage({ message: '毒 CD: ' + cd + 'h', showClose: true })
|
|
},
|
|
},
|
|
{
|
|
title: '🚓 快速犯罪',
|
|
template: QuickCrime,
|
|
},
|
|
{
|
|
title: '📢 浏览通知',
|
|
template: EventsViewer,
|
|
},
|
|
{
|
|
title: '🚮 地图垃圾',
|
|
template: CityUItems,
|
|
},
|
|
{
|
|
title: '🛒 购物助手',
|
|
template: MarketHelper,
|
|
},
|
|
{
|
|
title: '🅿️ PT购买',
|
|
template: PTMarketView,
|
|
},
|
|
{
|
|
title: '💰 公司存钱',
|
|
template: CompanyWithdraw,
|
|
},
|
|
{
|
|
title: '💰 PI存钱',
|
|
template: PropertyVault,
|
|
},
|
|
{
|
|
title: '📦 物品',
|
|
template: InventoryView,
|
|
},
|
|
{
|
|
title: '🎯 BS估算',
|
|
template: BSEstView,
|
|
},
|
|
{
|
|
title: '🫵 关闭店铺(双击开启)',
|
|
handler: () => bazaarControl.method(),
|
|
},
|
|
{
|
|
title: '🌸 飞花库存',
|
|
template: ForeignStock,
|
|
},
|
|
{
|
|
title: '💻 PC',
|
|
template: VirusProgramming,
|
|
},
|
|
{
|
|
title: '🩼 配置自动登陆',
|
|
template: AutoLoginForm,
|
|
},
|
|
{
|
|
title: '🖥 监控',
|
|
template: MonitorMgrView,
|
|
},
|
|
{
|
|
title: '📜️ 传单助手',
|
|
handler: () => {
|
|
expanded.value = false
|
|
adHelper()
|
|
},
|
|
},
|
|
{
|
|
title: '🛡️ 守望者',
|
|
handler: () => {
|
|
expanded.value = false
|
|
safeKeeper()
|
|
},
|
|
},
|
|
{
|
|
title: '🌲 寻找木桩',
|
|
handler: () => window.location.replace('https://www.torn.com/item.php?temp=4#xunzhaomuzhuang'),
|
|
},
|
|
{
|
|
title: '🚀 更新历史',
|
|
template: ChangeLogView
|
|
},
|
|
{
|
|
title: '⚙️ 助手设置',
|
|
handler: () => {
|
|
expanded.value = false
|
|
SettingsHandler.clickFunc()
|
|
},
|
|
},
|
|
]
|
|
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([])
|
|
|
|
// refil
|
|
const handleRefil = (method: 'refillEnergy' | 'refillNerve' | 'refillCasinoTokens') => {
|
|
fetch(window.addRFC("https://www.torn.com/page.php?sid=pointsBuildingExchange"), {
|
|
"headers": {
|
|
"accept": "*/*",
|
|
"accept-language": "zh-CN,zh;q=0.9",
|
|
"sec-fetch-dest": "empty",
|
|
"sec-fetch-mode": "cors",
|
|
"sec-fetch-site": "same-origin",
|
|
"x-requested-with": "XMLHttpRequest"
|
|
},
|
|
"referrer": "https://www.torn.com/page.php?sid=points",
|
|
"referrerPolicy": "strict-origin-when-cross-origin",
|
|
"body": (() => {
|
|
const data = new FormData();
|
|
data.append('key', method);
|
|
return data;
|
|
})(),
|
|
"method": "POST",
|
|
"mode": "cors",
|
|
"credentials": "include"
|
|
})
|
|
.then(res => res.json())
|
|
.catch(e => ElMessage.error('REFILL异常: ' + e.toString))
|
|
.then(res => {
|
|
ElMessage({
|
|
message: res.success ?
|
|
`<p>成功</p><p>剩余次数: ${ res["specialRefills"] } 剩余点数: ${ res['points'] }</p>` :
|
|
`REFILL异常: ${ res.error }`,
|
|
type: res.success ? 'success' : 'error',
|
|
dangerouslyUseHTMLString: true
|
|
})
|
|
throw new TypeError('REFILL异常: ' + res.error)
|
|
})
|
|
}
|
|
|
|
// fast travel
|
|
const travelData = [
|
|
{ cName: "🇲🇽 墨西哥", index: 0 },
|
|
{ cName: "🇰🇾 开曼", index: 1 },
|
|
{ cName: "🇨🇦 加拿大", index: 2 },
|
|
{ cName: "🌺 夏威夷", index: 3 },
|
|
{ cName: "🇬🇧 嘤国", index: 4 },
|
|
{ cName: "🇦🇷 阿根廷", index: 5 },
|
|
{ cName: "🇨🇭 瑞士 (解毒)", index: 6 },
|
|
{ cName: "🇯🇵 立本", index: 7 },
|
|
{ cName: "🇨🇳 祖国", index: 8 },
|
|
{ cName: "🇦🇪 阿联酋 (UAE)", index: 9 },
|
|
{ cName: "🇿🇦 南非", index: 10 },
|
|
]
|
|
|
|
const menuClick = (menuItem: MenuItem) => {
|
|
if (menuItem.handler) {
|
|
menuItem.handler();
|
|
} else if (menuItem.template) {
|
|
drawer.value = true;
|
|
addTab(menuItem);
|
|
}
|
|
}
|
|
|
|
const showDrawer = () => {
|
|
if (editableTabs.value.length < 1) {
|
|
logger.error('页面还没有打开任何功能标签');
|
|
throw new Error('页面还没有打开任何功能标签');
|
|
}
|
|
|
|
drawer.value = true;
|
|
};
|
|
|
|
const addTab = (menuItem: MenuItem) => {
|
|
for (let i = 0; i < editableTabs.value.length; i++) {
|
|
if (editableTabs.value[i].name === menuItem.title) {
|
|
editableTabsValue.value = menuItem.title;
|
|
// drawerTitle.value = menuItem.title;
|
|
return;
|
|
}
|
|
}
|
|
editableTabs.value.push({
|
|
title: menuItem.title,
|
|
name: menuItem.title,
|
|
content: menuItem.template!,
|
|
});
|
|
triggerRef(editableTabs);
|
|
editableTabsValue.value = menuItem.title;
|
|
};
|
|
|
|
const removeTab = (targetName: string) => {
|
|
const tabs = editableTabs.value
|
|
let activeName = editableTabsValue.value
|
|
logger.info({
|
|
activeName,
|
|
targetName
|
|
})
|
|
if (activeName === targetName) {
|
|
tabs.forEach((tab, index) => {
|
|
if (tab.name === targetName) {
|
|
const nextTab = tabs[index + 1] || tabs[index - 1]
|
|
if (nextTab) {
|
|
activeName = nextTab.name
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
editableTabsValue.value = activeName
|
|
editableTabs.value = tabs.filter((tab) => tab.name !== targetName)
|
|
logger.info({
|
|
activeName,
|
|
targetName
|
|
})
|
|
|
|
if (editableTabs.value.length < 1) {
|
|
drawer.value = false;
|
|
}
|
|
};
|
|
|
|
const travelConfirm = (destIndex: number, typeIndex: number) => {
|
|
const destName = travelData[destIndex].cName;
|
|
const typeName = ['普通飞机', 'PI飞机', '股票飞机', '商务飞机(机票或内衣店)'][typeIndex];
|
|
ElMessageBox.confirm(
|
|
'即将使用「' + typeName + '」飞往「' + destName + '」',
|
|
'确认',
|
|
{
|
|
confirmButtonText: '好',
|
|
cancelButtonText: '算了',
|
|
type: 'info',
|
|
}
|
|
)
|
|
.then(async () => {
|
|
await quickFlyBtnHandler.directFly(destIndex, typeIndex);
|
|
ElMessageBox.confirm('是否转跳页面?', '确认', {
|
|
confirmButtonText: '好',
|
|
cancelButtonText: '算了',
|
|
type: 'info'
|
|
}
|
|
).then(() => window.location.href = 'https://www.torn.com')
|
|
.catch(() => null);
|
|
})
|
|
.catch(() => null);
|
|
};
|
|
|
|
const bazaarControl = {
|
|
wait: (t: number) => new Promise(resolve => window.setTimeout(() => resolve(null), t)),
|
|
count: 0,
|
|
doGet: async (isClose: boolean) => {
|
|
let response;
|
|
try {
|
|
response = await (await fetch(
|
|
"https://www.torn.com/bazaar.php?sid=bazaarData&step=" + (isClose ? "closeBazaar" : "openBazaar"),
|
|
{
|
|
"headers": {
|
|
"accept": "*/*",
|
|
"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/bazaar.php",
|
|
"referrerPolicy": "strict-origin-when-cross-origin",
|
|
"body": null,
|
|
"method": "GET",
|
|
"mode": "cors",
|
|
"credentials": "include"
|
|
}
|
|
)).json();
|
|
} catch (e) {
|
|
logger.error(e.stack);
|
|
ElMessage.error(e.message);
|
|
throw e;
|
|
}
|
|
if (response.success) {
|
|
ElMessage.success({
|
|
dangerouslyUseHTMLString: true,
|
|
message: response.text,
|
|
});
|
|
} else {
|
|
ElMessage.error(response.text);
|
|
}
|
|
},
|
|
method: async () => {
|
|
bazaarControl.count++;
|
|
if (bazaarControl.count === 1) await bazaarControl.wait(600);
|
|
if (bazaarControl.count === 1) {
|
|
bazaarControl.count = 0;
|
|
await bazaarControl.doGet(true);
|
|
}
|
|
if (bazaarControl.count === 2) {
|
|
bazaarControl.count = 0;
|
|
await bazaarControl.doGet(false);
|
|
}
|
|
},
|
|
};
|
|
|
|
onMounted(() => {
|
|
if (document.documentElement.scrollWidth < 600) {
|
|
isMobilePhone.value = true;
|
|
}
|
|
documentHeight.value = document.documentElement.scrollHeight;
|
|
});
|
|
|
|
</script>
|
|
|
|
<style scoped>
|
|
.wh-menu-button {
|
|
position: fixed;
|
|
top: 32px;
|
|
left: 10px;
|
|
}
|
|
|
|
.featureCol {
|
|
max-width: 33.33%;
|
|
}
|
|
|
|
.featureMenu {
|
|
cursor: pointer;
|
|
margin: 4px;
|
|
border: none;
|
|
background-color: transparent;
|
|
}
|
|
|
|
.featureMenu div {
|
|
text-align: center;
|
|
}
|
|
|
|
.featureMenu .icon {
|
|
font-size: 28px;
|
|
}
|
|
|
|
.featureMenu .title {
|
|
font-size: 14px;
|
|
height: 32px;
|
|
margin-left: -0.5em;
|
|
margin-right: -0.5em;
|
|
}
|
|
|
|
.featureMenu:hover {
|
|
background-color: #E9EEF6;
|
|
}
|
|
</style>
|