This commit is contained in:
Liwanyi 2023-06-12 17:47:44 +08:00
parent 0c6ab02e8d
commit 3104ea2b53
6 changed files with 250 additions and 96 deletions

View File

@ -5,6 +5,14 @@
# CHANGE
## 1.0.0
2023年06月12日
### 添加
- PT购买
## 0.9.9
2023年06月07日

File diff suppressed because one or more lines are too long

View File

@ -30,22 +30,22 @@
<template #dropdown>
<template v-for="travel in travelData">
<el-dropdown-item>
<el-dropdown placement="bottom-end" size="small" style="width: 100%"
trigger="click">
<div style="width: 100%">{{ travel.cName }} ></div>
<template #dropdown>
<el-dropdown-item @click="travelConfirm(travel.index,0)">
普通飞机
</el-dropdown-item>
<el-dropdown-item @click="travelConfirm(travel.index,1)">
PI飞机
</el-dropdown-item>
<el-dropdown-item @click="travelConfirm(travel.index,2)">
股票飞机
</el-dropdown-item>
<el-dropdown-item @click="travelConfirm(travel.index,3)">
商务飞机(机票或内衣店)
</el-dropdown-item>
<el-dropdown placement="bottom-end" size="small" style="width: 100%"
trigger="click">
<div style="width: 100%">{{ travel.cName }} ></div>
<template #dropdown>
<el-dropdown-item @click="travelConfirm(travel.index, 0)">
普通飞机
</el-dropdown-item>
<el-dropdown-item @click="travelConfirm(travel.index, 1)">
PI飞机
</el-dropdown-item>
<el-dropdown-item @click="travelConfirm(travel.index, 2)">
股票飞机
</el-dropdown-item>
<el-dropdown-item @click="travelConfirm(travel.index, 3)">
商务飞机(机票或内衣店)
</el-dropdown-item>
</template>
</el-dropdown>
</el-dropdown-item>
@ -54,70 +54,66 @@
</el-dropdown>
</el-dropdown-item>
<template v-for="(item, i) in menuItemList">
<el-dropdown-item v-if="i===0" divided @click="menuClick(item)">
{{ item.title }}
</el-dropdown-item>
<el-dropdown-item v-else @click="menuClick(item)">
{{ item.title }}
</el-dropdown-item>
<el-dropdown-item v-if="i === 0" divided @click="menuClick(item)">
{{ item.title }}
</el-dropdown-item>
<el-dropdown-item v-else @click="menuClick(item)">
{{ item.title }}
</el-dropdown-item>
</template>
<el-dropdown-item @click="bazaarControl.method()">🫵 关闭店铺(双击开启)
</el-dropdown-item>
<el-dropdown-item @click="bazaarControl.method()">🫵 关闭店铺(双击开启)
</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<el-dialog
v-model="drawer"
:destroy-on-close="true"
:title="drawerTitle"
:fullscreen="isMobilePhone"
:lock-scroll="true"
width="65%"
>
<component :is="drawerContent"/>
</el-dialog>
<el-dialog v-model="drawer" :destroy-on-close="true" :fullscreen="isMobilePhone" :lock-scroll="true"
:title="drawerTitle" width="65%">
<component :is="drawerContent"/>
</el-dialog>
</el-config-provider>
</template>
<script lang="ts" setup>
import { MoonNight } from "@element-plus/icons-vue";
import { ElMessage, ElMessageBox } from "element-plus";
import { inject, onMounted, ref, shallowRef } from 'vue';
import { LoggerKey } from "../ts/class/Logger";
import ForeignStock from "./ForeignStock.vue";
import { MoonNight } from "@element-plus/icons-vue";
import Config from "./Config.vue";
import { QuickGymTrainKey } from "../ts/class/action/QuickGymTrain";
import { BATTLE_STAT } from "../ts/class/utils/NetHighLvlWrapper";
import { QuickFlyBtnHandlerKey } from "../ts/class/handler/QuickFlyBtnHandler";
import { ElMessage, ElMessageBox } from "element-plus";
import QuickCrime from "./QuickCrime.vue";
import EventsViewer from "./EventsViewer.vue";
import CityUItems from "./CityUItems.vue";
import { BATTLE_STAT } from "../ts/class/utils/NetHighLvlWrapper";
import AutoLoginForm from "./AutoLoginForm.vue";
import VirusProgramming from "./VirusProgramming.vue";
import CityUItems from "./CityUItems.vue";
import Config from "./Config.vue";
import EventsViewer from "./EventsViewer.vue";
import ForeignStock from "./ForeignStock.vue";
import MarketHelper from "./MarketHelper.vue";
import PTMarketView from "./PTMarketView.vue";
import QuickCrime from "./QuickCrime.vue";
import VirusProgramming from "./VirusProgramming.vue";
const logger = inject(LoggerKey);
const quickGymTrain = inject(QuickGymTrainKey);
const quickFlyBtnHandler = inject(QuickFlyBtnHandlerKey);
const useItem = (itemId) => {
fetch(window.addRFC("https://www.torn.com/item.php"), {
"headers": {
"accept": "*/*",
"content-type": "application/x-www-form-urlencoded;charset=UTF-8",
"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/item.php",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": `step=useItem&id=${ itemId }&itemID=${ itemId }`,
"method": "POST",
"mode": "cors",
"credentials": "include"
})
const useItem = (itemId: string) => {
fetch(window.addRFC("https://www.torn.com/item.php"), {
"headers": {
"accept": "*/*",
"content-type": "application/x-www-form-urlencoded;charset=UTF-8",
"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/item.php",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": `step=useItem&id=${ itemId }&itemID=${ itemId }`,
"method": "POST",
"mode": "cors",
"credentials": "include"
})
.then(res => res.json())
.then(res => ElMessage({
message: res.text,
@ -131,21 +127,19 @@ const useItem = (itemId) => {
};
const menuItemList = [
{
title: '💊 吃 XAN',
template: () => useItem(206),
},
{
title: '🍺 喝啤酒',
template: () => useItem(180),
},
{
title: '💊 吃 XAN',
template: () => useItem('206'),
},
{
title: '🍺 喝啤酒',
template: () => useItem('180'),
},
{
title: '♻️ REFILL',
template: () => fetch(window.addRFC("https://www.torn.com/points.php?step=pointsbuy&action=energyrefill2"), {
"headers": {
"accept": "text/plain, */*; q=0.01",
"accept-language": "zh-CN,zh;q=0.9",
"sec-ch-ua": "\" Not A;Brand\";v=\"99\", \"Chromium\";v=\"92\"",
"sec-ch-ua-mobile": "?0",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
@ -161,9 +155,9 @@ const menuItemList = [
})
.then(res => res.json())
.then(res => ElMessage({
message: res.msg,
type: res.success ? 'success' : 'error',
dangerouslyUseHTMLString: true
message: `<p>${ res.msg }</p><p>剩余refill: ${ res.refills }</p>`,
type: res.state === 'done' ? 'success' : 'error',
dangerouslyUseHTMLString: true
}))
.catch(e => ElMessage({
message: e.toString,
@ -190,18 +184,22 @@ const menuItemList = [
title: '🩼 配置自动登陆',
template: AutoLoginForm,
},
{
title: '💻 PC',
template: VirusProgramming,
},
{
title: '🛒 购物助手',
template: MarketHelper,
},
{
title: '⚙️ 插件配置',
template: Config,
},
{
title: '💻 PC',
template: VirusProgramming,
},
{
title: '🛒 购物助手',
template: MarketHelper,
},
{
title: '🅿️ PT购买',
template: PTMarketView,
},
{
title: '⚙️ 插件配置',
template: Config,
},
];
const drawer = ref(false);
const drawerTitle = ref('');
@ -246,9 +244,9 @@ const travelConfirm = (destIndex, typeIndex) => {
.then(async () => {
await quickFlyBtnHandler.directFly(destIndex, typeIndex);
ElMessageBox.confirm('是否转跳页面?', '确认', {
confirmButtonText: '好',
cancelButtonText: '算了',
type: 'info'
confirmButtonText: '好',
cancelButtonText: '算了',
type: 'info'
}
).then(() => window.location.href = 'https://www.torn.com')
.catch(() => null);

View File

@ -13,7 +13,7 @@
</select>
</div>
<div v-if="itemInfo.id !== -1">
<p><img :alt="itemInfo.id" :src="`/images/items/${itemInfo.id}/medium.png`"/></p>
<p><img :alt="itemInfo.id.toString()" :src="`/images/items/${itemInfo.id}/medium.png`"/></p>
<p>
物品名{{ itemInfo.name }}{{ itemNameDict[itemInfo.name] ? '(' + itemNameDict[itemInfo.name] + ')' : '' }}
</p>

View File

@ -80,7 +80,6 @@ type ItemInfo = {
price: number,
amount: number,
inputAmount: number,
// index: number,
onBuying: boolean,
itemId: string,
};

149
src/vue/PTMarketView.vue Normal file
View File

@ -0,0 +1,149 @@
<script lang="ts" setup>
import { Refresh, ShoppingCart } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';
import { inject, onMounted, ref } from 'vue';
import { LoggerKey } from '../ts/class/Logger';
const logger = inject(LoggerKey);
type TableData = {
player: string,
amount: string,
each: string,
totalPrice: string,
id: string,
onBuying: boolean,
afterBought: boolean,
};
const tableData = ref<TableData[]>([]);
const fetchingList = ref(false);
const buy = async (tableRowData: TableData): Promise<void> => {
tableRowData.onBuying = true;
let res: string;
let resJson: { color: 'red' | 'green', msg: string };
try {
res = await (await fetch(window.addRFC("https://www.torn.com/pmarket.php"), {
"headers": {
"accept": "*/*",
"content-type": "application/x-www-form-urlencoded; charset=UTF-8",
"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/pmarket.php",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": "ajax_action=buy1&ID=" + tableRowData.id,
"method": "POST",
"mode": "cors",
"credentials": "include"
})).text();
resJson = JSON.parse(res);
} catch (error) {
tableRowData.onBuying = false;
ElMessage.error('购买失败 ' + error.message);
logger.error(error.stack);
throw error;
}
if (resJson.color === 'green') {
ElMessage.success('成功 ' + resJson.msg);
tableRowData.afterBought = true;
} else {
ElMessage.error('失败 ' + resJson.msg);
}
tableRowData.onBuying = false;
};
const fetchList = async (): Promise<void> => {
tableData.value = [];
fetchingList.value = true;
let fetchRes: string;
try {
fetchRes = await (await fetch(window.addRFC("https://www.torn.com/pmarket.php?ajax_action=refresh"), {
"headers": {
"accept": "text/plain, */*; q=0.01",
"sec-ch-ua-mobile": "?0",
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"x-requested-with": "XMLHttpRequest"
},
"referrer": "https://www.torn.com/pmarket.php",
"referrerPolicy": "strict-origin-when-cross-origin",
"body": null,
"method": "GET",
"mode": "cors",
"credentials": "include"
})).text();
} catch (e) {
fetchingList.value = false;
logger.error('PT出售列表获取错误', e.stack);
throw e;
}
let tmpNode = document.createElement('div');
tmpNode.innerHTML = fetchRes;
let itemNodeList = tmpNode.querySelectorAll('li .expander');
if (!itemNodeList.length) {
tmpNode = null;
itemNodeList = null;
fetchingList.value = false;
logger.error('无法获取PT出售列表数据, 状态是否为Torn OK?');
ElMessage.error('无法获取PT出售列表数据, 状态是否为Torn OK?');
throw new Error('无法获取PT出售列表数据, 状态是否为Torn OK?');
}
for (let i = 0; i < itemNodeList.length; i++) {
const node = itemNodeList[i];
const tableRowData: TableData = {
player: '',
amount: '',
each: '',
totalPrice: '',
id: '',
onBuying: false,
afterBought: false
};
let href = node.getAttribute('href').trim();
tableRowData.amount = href.split('points=')[1];
tableRowData.player = node.querySelector('.user-info span[title]').getAttribute('title').trim().replaceAll(' ', '');
tableRowData.each = node.querySelector('.cost-each').innerText?.split('Cost each')[1].trim();
tableRowData.totalPrice = node.querySelector('.total-price').innerText?.split('Total price')[1].trim();
let hrefSplit = href.split('&');
for (let index = 0; index < hrefSplit.length; index++) {
const element = hrefSplit[index];
if (element.startsWith('ID=')) {
tableRowData.id = element.replace('ID=', '');
break;
}
}
tableData.value.push(tableRowData);
}
fetchingList.value = false;
itemNodeList = null;
tmpNode = null;
};
onMounted(() => {
fetchList();
});
</script>
<template>
<el-table :data="tableData" style="width: 100%">
<el-table-column label="玩家" prop="player"/>
<el-table-column label="数量" prop="amount"/>
<el-table-column label="单价" prop="each"/>
<el-table-column label="共计" prop="totalPrice"/>
<el-table-column>
<template #default="scope">
<el-button :disabled="scope.row.afterBought" :icon="ShoppingCart" :loading="scope.row.onBuying"
@click="buy(scope.row)"/>
</template>
<template #header>
<el-button :icon="Refresh" :loading="fetchingList" circle @click="fetchList"/>
</template>
</el-table-column>
</el-table>
</template>
<style scoped></style>