mirror of
https://github.com/Kvan7/Exiled-Exchange-2.git
synced 2026-09-26 22:55:42 +00:00
WIP, trade listing
This commit is contained in:
@@ -15,6 +15,7 @@
|
||||
"dependencies": {
|
||||
"core-js": "^2.6.5",
|
||||
"iohook": "^0.6.2",
|
||||
"luxon": "^1.21.3",
|
||||
"node-window-manager": "^2.0.1",
|
||||
"robotjs": "^0.6.0",
|
||||
"tailwindcss": "^1.1.4",
|
||||
|
||||
+5
-1
@@ -23,9 +23,13 @@ export default {
|
||||
</script>
|
||||
|
||||
<style lang="postcss">
|
||||
@import url('https://use.fontawesome.com/releases/v5.2.0/css/all.css');
|
||||
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.11.2/css/all.min.css');
|
||||
@import url('https://web.poecdn.com/css/font.css');
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
.table-stripped tbody tr:nth-child(odd) {
|
||||
background: theme('colors.gray.900');
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="p-2 border-b border-gray-700" v-if="price">
|
||||
<div class="p-4 border-b border-gray-700" v-if="price">
|
||||
<div class="bg-gray-900 mb-2 p-1 leading-none">{{ item.name }}</div>
|
||||
<rare-item v-if="item.rarity === 'Rare' && item.computed.type !== 'Map'" :item="item" />
|
||||
<div v-else class="flex items-center pb-4">
|
||||
@@ -31,6 +31,9 @@
|
||||
}]" padding="2" />
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<trade-listing :item="item" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -38,10 +41,11 @@
|
||||
import { Parser, parseClipboard } from './Parser'
|
||||
import { Prices } from './Prices'
|
||||
import RareItem from './RareItem'
|
||||
import TradeListing from './TradeListing'
|
||||
|
||||
export default {
|
||||
name: 'CheckedItem',
|
||||
components: { RareItem },
|
||||
components: { RareItem, TradeListing },
|
||||
props: {
|
||||
clipboard: String
|
||||
},
|
||||
|
||||
@@ -40,7 +40,7 @@ export interface ParsedItem {
|
||||
|
||||
const LATEST_MAP_VARIANT = 'Metamorph'
|
||||
|
||||
enum WellKnownType {
|
||||
export enum WellKnownType {
|
||||
Map = 'Map',
|
||||
UniqueFlask = 'Unique Flask',
|
||||
MetamorphPart = 'Metamorph Part'
|
||||
|
||||
+16
-10
@@ -56,16 +56,6 @@ export default {
|
||||
required: true
|
||||
}
|
||||
},
|
||||
async created () {
|
||||
try {
|
||||
this.loading = true
|
||||
this.price = await requestPoeprices(this.item)
|
||||
} catch (err) {
|
||||
this.error = err.message
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
price: null,
|
||||
@@ -73,6 +63,22 @@ export default {
|
||||
loading: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
item: {
|
||||
immediate: true,
|
||||
async handler (item) {
|
||||
try {
|
||||
this.loading = true
|
||||
this.price = null
|
||||
this.price = await requestPoeprices(this.item)
|
||||
} catch (err) {
|
||||
this.error = err.message
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
currency () {
|
||||
return Prices.findByDetailsId(this.price.currency)
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<template>
|
||||
<div v-if="loading">
|
||||
<i class="fas fa-exclamation-circle pr-1 text-gray-600"></i>
|
||||
<span>Requesting search results...</span>
|
||||
</div>
|
||||
<table v-else-if="results" class="table-stripped w-full">
|
||||
<thead>
|
||||
<tr class="text-left">
|
||||
<th class="px-2">Price</th>
|
||||
<th v-if="item.rarity === 'Gem'" class="px-2">Level</th>
|
||||
<th v-if="item.rarity === 'Gem'" class="px-2">Quality</th>
|
||||
<th class="px-2"></th>
|
||||
<th class="px-2 w-full">Listed</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr v-for="result in results" :key="result.id">
|
||||
<td class="px-2 whitespace-no-wrap">{{ result.priceAmount }} {{ result.priceCurrency }}</td>
|
||||
<td v-if="item.rarity === 'Gem'" class="px-2 whitespace-no-wrap">{{ result.level }}</td>
|
||||
<td v-if="item.rarity === 'Gem'" class="px-2 whitespace-no-wrap text-blue-400 text-right">{{ result.quality }}</td>
|
||||
<td class="px-2 whitespace-no-wrap text-red-500"><span v-if="result.corrupted">Corrupted</span></td>
|
||||
<td class="font-sans text-xs px-2">{{ getRelativeTime(result.listedAt) }}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div v-else-if="error">
|
||||
<i class="fas fa-exclamation-circle pr-1 text-red-600"></i>
|
||||
<span>{{ error }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { DateTime } from 'luxon'
|
||||
import { requestTradeResultList, requestResults } from './pathofexile-trade'
|
||||
|
||||
export default {
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
loading: false,
|
||||
error: null,
|
||||
results: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
item: {
|
||||
immediate: true,
|
||||
async handler (item) {
|
||||
try {
|
||||
// @TODO https://www.pathofexile.com/forum/view-thread/2079853#p15244273
|
||||
|
||||
this.loading = true
|
||||
this.results = []
|
||||
const list = await requestTradeResultList(item)
|
||||
this.results = await requestResults(list.id, list.result.slice(0, 10))
|
||||
this.loading = false
|
||||
|
||||
if (list.total > 10) {
|
||||
this.results.push(...await requestResults(list.id, list.result.slice(10, 20)))
|
||||
}
|
||||
} catch (err) {
|
||||
this.error = err.message
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getRelativeTime (iso) {
|
||||
return DateTime.fromISO(iso).toRelative()
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,172 @@
|
||||
import { ParsedItem } from './Parser'
|
||||
import { ItemRarity } from './parser-constants'
|
||||
import { Leagues } from './Leagues'
|
||||
|
||||
const TradeOpts = {
|
||||
GemLevel: 16,
|
||||
GemLevelRange: 0,
|
||||
GemQualityRange: 0
|
||||
}
|
||||
|
||||
const EXACT_GEM_LEVEL = ['Empower Support', 'Enlighten Support', 'Enhance Support']
|
||||
|
||||
interface TradeRequest { /* eslint-disable camelcase */
|
||||
query: {
|
||||
status: { option: 'online' }
|
||||
name?: string
|
||||
type?: string
|
||||
filters: {
|
||||
socket_filters: {
|
||||
filters: {
|
||||
links: {
|
||||
min?: number
|
||||
max?: number
|
||||
}
|
||||
}
|
||||
}
|
||||
misc_filters: {
|
||||
filters: {
|
||||
quality: {
|
||||
min?: number
|
||||
max?: number
|
||||
}
|
||||
gem_level: {
|
||||
min?: number
|
||||
max?: number
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
sort: {
|
||||
price: 'asc'
|
||||
}
|
||||
}
|
||||
|
||||
interface SearchResult {
|
||||
id: string
|
||||
result: string[]
|
||||
total: number
|
||||
}
|
||||
|
||||
interface FetchResult {
|
||||
id: string
|
||||
item: {
|
||||
corrupted?: boolean
|
||||
properties?: Array<{
|
||||
name: 'Quality' | 'Level'
|
||||
values: [[string, number]]
|
||||
}>
|
||||
}
|
||||
listing: {
|
||||
indexed: string
|
||||
price: {
|
||||
amount: number
|
||||
currency: string
|
||||
type: '~price'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
interface PricingResult {
|
||||
id: string
|
||||
corrupted?: boolean
|
||||
quality?: string
|
||||
level?: string
|
||||
listedAt: string
|
||||
priceAmount: number
|
||||
priceCurrency: string
|
||||
}
|
||||
|
||||
export async function requestTradeResultList (item: ParsedItem) {
|
||||
const body: TradeRequest = {
|
||||
query: {
|
||||
status: { option: 'online' },
|
||||
filters: {
|
||||
socket_filters: {
|
||||
filters: {
|
||||
links: {}
|
||||
}
|
||||
},
|
||||
misc_filters: {
|
||||
filters: {
|
||||
quality: {},
|
||||
gem_level: {}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
sort: {
|
||||
price: 'asc'
|
||||
}
|
||||
}
|
||||
const { query } = body
|
||||
|
||||
if (item.rarity === ItemRarity.Gem) {
|
||||
query.type = item.name
|
||||
|
||||
if (TradeOpts.GemQualityRange > 0) {
|
||||
query.filters.misc_filters.filters.quality.min = (item.quality || 0) - TradeOpts.GemQualityRange
|
||||
query.filters.misc_filters.filters.quality.max = (item.quality || 0) + TradeOpts.GemQualityRange
|
||||
} else {
|
||||
query.filters.misc_filters.filters.quality.min = item.quality
|
||||
}
|
||||
|
||||
if (EXACT_GEM_LEVEL.includes(item.name)) {
|
||||
query.filters.misc_filters.filters.gem_level.min = item.gemLevel
|
||||
query.filters.misc_filters.filters.gem_level.max = item.gemLevel
|
||||
} else if (item.gemLevel! >= TradeOpts.GemLevel) {
|
||||
if (TradeOpts.GemLevelRange > 0) {
|
||||
query.filters.misc_filters.filters.gem_level.min = item.gemLevel! - TradeOpts.GemLevelRange
|
||||
query.filters.misc_filters.filters.gem_level.max = item.gemLevel! + TradeOpts.GemLevelRange
|
||||
} else {
|
||||
query.filters.misc_filters.filters.gem_level.min = item.gemLevel!
|
||||
}
|
||||
}
|
||||
} else if (item.rarity === ItemRarity.DivinationCard) {
|
||||
query.type = item.name
|
||||
} else if (item.rarity === ItemRarity.Unique) {
|
||||
query.name = item.name
|
||||
query.type = item.baseType
|
||||
} else {
|
||||
// TODO
|
||||
if (item.rarity !== ItemRarity.Rare && item.rarity !== ItemRarity.Magic) {
|
||||
query.type = item.name
|
||||
}
|
||||
}
|
||||
|
||||
if (item.linkedSockets) {
|
||||
query.filters.socket_filters.filters.links.min = item.linkedSockets
|
||||
}
|
||||
|
||||
// console.log(body)
|
||||
|
||||
const response = await fetch(`https://www.pathofexile.com/api/trade/search/${Leagues.selected}`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(body)
|
||||
})
|
||||
const data: SearchResult = await response.json()
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
export async function requestResults (queryId: string, resultIds: string[]): Promise<PricingResult[]> {
|
||||
const response = await fetch(`https://www.pathofexile.com/api/trade/fetch/${resultIds.join(',')}?query=${queryId}`)
|
||||
const data: { result: FetchResult[] } = await response.json()
|
||||
|
||||
return data.result.map(result => {
|
||||
return {
|
||||
id: result.id,
|
||||
corrupted: result.item.corrupted,
|
||||
quality: result.item.properties?.find(prop => prop.name === 'Quality')?.values[0][0],
|
||||
level: result.item.properties?.find(prop => prop.name === 'Level')?.values[0][0],
|
||||
listedAt: result.listing.indexed,
|
||||
priceAmount: result.listing.price.amount,
|
||||
priceCurrency: result.listing.price.currency
|
||||
} as PricingResult
|
||||
})
|
||||
}
|
||||
@@ -1,9 +1,7 @@
|
||||
import { stringify } from 'querystring'
|
||||
import { ParsedItem, ItemRarity } from './Parser'
|
||||
import { ParsedItem, ItemRarity, WellKnownType } from './Parser'
|
||||
import { Leagues } from './Leagues'
|
||||
|
||||
let MAX_1 = false
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
interface PoepricesApiResponse {
|
||||
currency: 'chaos' | 'exalted'
|
||||
@@ -29,9 +27,7 @@ interface RareItemPrice {
|
||||
}
|
||||
|
||||
export async function requestPoeprices (item: ParsedItem): Promise<RareItemPrice | null> {
|
||||
console.assert(item.rarity === ItemRarity.Rare)
|
||||
if (MAX_1) return null
|
||||
// MAX_1 = true
|
||||
console.assert(item.rarity === ItemRarity.Rare && item.computed.type !== WellKnownType.Map)
|
||||
|
||||
const query = stringify({
|
||||
i: Buffer.from(item.rawText).toString('base64'),
|
||||
|
||||
@@ -6099,6 +6099,11 @@ lru-cache@^5.1.1:
|
||||
dependencies:
|
||||
yallist "^3.0.2"
|
||||
|
||||
luxon@^1.21.3:
|
||||
version "1.21.3"
|
||||
resolved "https://registry.yarnpkg.com/luxon/-/luxon-1.21.3.tgz#f1d5c2a7e855d039836cf4954f883ecac8fc4727"
|
||||
integrity sha512-lLRwNcNnkZLuv13A1FUuZRZmTWF7ro2ricYvb0L9cvBYHPvZhQdKwrYnZzi103D2XKmlVmxWpdn2wfIiOt2YEw==
|
||||
|
||||
make-dir@^1.0.0:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
|
||||
@@ -8322,13 +8327,20 @@ resolve-url@^0.2.1:
|
||||
resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
|
||||
integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
|
||||
|
||||
resolve@^1.10.0, resolve@^1.12.0, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.5.0, resolve@^1.8.1:
|
||||
resolve@^1.10.0, resolve@^1.12.0, resolve@^1.3.2, resolve@^1.4.0, resolve@^1.8.1:
|
||||
version "1.14.1"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.14.1.tgz#9e018c540fcf0c427d678b9931cbf45e984bcaff"
|
||||
integrity sha512-fn5Wobh4cxbLzuHaE+nphztHy43/b++4M6SsGFC2gB8uYwf0C8LcarfCz1un7UTW8OFQg9iNjZ4xpcFVGebDPg==
|
||||
dependencies:
|
||||
path-parse "^1.0.6"
|
||||
|
||||
resolve@^1.5.0:
|
||||
version "1.14.2"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.14.2.tgz#dbf31d0fa98b1f29aa5169783b9c290cb865fea2"
|
||||
integrity sha512-EjlOBLBO1kxsUxsKjLt7TAECyKW6fOh1VRkykQkKGzcBbjjPIxBqGh0jf7GJ3k/f5mxMqW3htMD3WdTUVtW8HQ==
|
||||
dependencies:
|
||||
path-parse "^1.0.6"
|
||||
|
||||
responselike@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/responselike/-/responselike-1.0.2.tgz#918720ef3b631c5642be068f15ade5a46f4ba1e7"
|
||||
|
||||
Reference in New Issue
Block a user