mirror of
https://github.com/Kvan7/Exiled-Exchange-2.git
synced 2026-09-24 21:55:41 +00:00
vue3
This commit is contained in:
Vendored
+3
-10
@@ -1,14 +1,7 @@
|
||||
declare module 'vue-trend-chart' {
|
||||
export default function install(): void
|
||||
}
|
||||
|
||||
declare module 'vue-virtual-scroller' {
|
||||
export default function install(): void
|
||||
}
|
||||
|
||||
declare module 'vue-popperjs' {
|
||||
import Vue from 'vue'
|
||||
export default Vue
|
||||
import type { Plugin, Plugin, DefineComponent } from 'vue'
|
||||
const plugin: Plugin
|
||||
export default plugin
|
||||
}
|
||||
|
||||
declare module '*.json' {
|
||||
|
||||
Vendored
+3
-2
@@ -1,4 +1,5 @@
|
||||
declare module '*.vue' {
|
||||
import Vue from 'vue'
|
||||
export default Vue
|
||||
import type { DefineComponent } from 'vue'
|
||||
const component: DefineComponent<{}, {}, any>
|
||||
export default component
|
||||
}
|
||||
|
||||
@@ -31,10 +31,25 @@ export interface WidgetManager {
|
||||
hide (wmId: number): void
|
||||
remove (wmId: number): void
|
||||
bringToTop (wmId: number): void
|
||||
create (wmType: string): void
|
||||
create (wmType: string): void
|
||||
showBrowser (wmId: number, url: string): void
|
||||
}
|
||||
|
||||
export interface WidgetMenu extends Widget {
|
||||
anchor: Anchor
|
||||
alwaysShow: boolean
|
||||
}
|
||||
|
||||
export interface PriceCheckWidget extends Widget {
|
||||
chaosPriceThreshold: number
|
||||
}
|
||||
|
||||
export interface MapCheckWidget extends Widget {
|
||||
selectedStats: Array<{
|
||||
matcher: string
|
||||
invert: boolean
|
||||
valueWarning: string
|
||||
valueDanger: string
|
||||
valueDesirable: string
|
||||
}>
|
||||
}
|
||||
|
||||
@@ -16,13 +16,15 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from 'vue'
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
position: {
|
||||
type: Object,
|
||||
type: Object as PropType<{ x: number, y: number }>,
|
||||
required: true
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -14,24 +14,24 @@
|
||||
<div class="flex">
|
||||
<ui-input-debounced class="search-num-input rounded-tl mr-px" :placeholder="$t('min')" :min="filter.boundMin" :max="filter.boundMax" step="any" type="number" :class="{ 'rounded-bl': !showQ20Notice }"
|
||||
v-if="showMinmaxInput" ref="inputMin"
|
||||
v-model.number="filter.min" @focus.native="inputFocus($event, 'min')" :delay="0" />
|
||||
v-model.number="filter.min" @focus="inputFocus($event, 'min')" :delay="0" />
|
||||
<ui-input-debounced class="search-num-input rounded-tr" :placeholder="$t('max')" :min="filter.boundMin" :max="filter.boundMax" step="any" type="number" :class="{ 'rounded-br': !showQ20Notice }"
|
||||
v-if="showMinmaxInput" ref="inputMax"
|
||||
v-model.number="filter.max" @focus.native="inputFocus($event, 'max')" :delay="0" />
|
||||
v-model.number="filter.max" @focus="inputFocus($event, 'max')" :delay="0" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex">
|
||||
<div class="w-5 flex items-start">
|
||||
<ui-popper v-if="filter.hidden" tag-name="div" class="flex" :options="{ placement: 'right-start' }" boundaries-selector="#price-window">
|
||||
<template slot="reference">
|
||||
<ui-popover v-if="filter.hidden" placement="right-start" boundary="#price-window">
|
||||
<template #target>
|
||||
<span class="text-xs leading-none text-gray-600 cursor-pointer">
|
||||
<i class="fas fa-eye-slash" :class="{ 'faa-ring': !filter.disabled }"></i>
|
||||
</span>
|
||||
</template>
|
||||
<div class="popper">
|
||||
<template #content>
|
||||
<div style="max-width: 18.5rem;">{{ $t(filter.hidden) }}</div>
|
||||
</div>
|
||||
</ui-popper>
|
||||
</template>
|
||||
</ui-popover>
|
||||
</div>
|
||||
<div class="flex-1 flex items-start">
|
||||
<span v-if="showTypeTags"
|
||||
@@ -73,98 +73,117 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import ItemModifierText from '../../ui/ItemModifierText'
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, computed, ref, nextTick, ComponentPublicInstance } from 'vue'
|
||||
import ItemModifierText from '../../ui/ItemModifierText.vue'
|
||||
import { Config } from '@/web/Config'
|
||||
import { ParsedItem } from '@/parser'
|
||||
import { StatFilter } from './interfaces'
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
components: { ItemModifierText },
|
||||
emits: ['submit'],
|
||||
props: {
|
||||
filter: {
|
||||
type: Object,
|
||||
type: Object as PropType<StatFilter>,
|
||||
required: true
|
||||
},
|
||||
item: {
|
||||
type: Object,
|
||||
type: Object as PropType<ParsedItem>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
showMinmaxInput () {
|
||||
setup (props, ctx) {
|
||||
const showMinmaxInput = computed(() => {
|
||||
if (
|
||||
this.filter.option != null ||
|
||||
(this.filter.roll == null && this.filter.min == null && this.filter.max == null)
|
||||
props.filter.option != null ||
|
||||
(props.filter.roll == null && props.filter.min == null && props.filter.max == null)
|
||||
) return false
|
||||
|
||||
return true
|
||||
},
|
||||
showTypeTags () {
|
||||
if (this.filter.boundMin !== undefined || this.filter.variant) {
|
||||
})
|
||||
|
||||
const showTypeTags = computed(() => {
|
||||
if (props.filter.boundMin !== undefined || props.filter.variant) {
|
||||
return false
|
||||
}
|
||||
return this.filter.type !== 'armour' &&
|
||||
this.filter.type !== 'weapon'
|
||||
},
|
||||
showQ20Notice () {
|
||||
return props.filter.type !== 'armour' &&
|
||||
props.filter.type !== 'weapon'
|
||||
})
|
||||
|
||||
const showQ20Notice = computed(() => {
|
||||
return [
|
||||
'armour.armour',
|
||||
'armour.evasion_rating',
|
||||
'armour.energy_shield',
|
||||
'weapon.total_dps',
|
||||
'weapon.physical_dps'
|
||||
].includes(this.filter.tradeId[0])
|
||||
},
|
||||
sliderValue: {
|
||||
].includes(props.filter.tradeId[0])
|
||||
})
|
||||
|
||||
const inputMin = ref<ComponentPublicInstance | null>(null)
|
||||
const inputMax = ref<ComponentPublicInstance | null>(null)
|
||||
|
||||
const sliderValue = computed<Array<number>>({
|
||||
get () {
|
||||
return [
|
||||
typeof this.filter.min === 'number' ? this.filter.min : this.filter.boundMin,
|
||||
typeof this.filter.max === 'number' ? this.filter.max : this.filter.boundMax
|
||||
typeof props.filter.min === 'number' ? props.filter.min : props.filter.boundMin!,
|
||||
typeof props.filter.max === 'number' ? props.filter.max : props.filter.boundMax!
|
||||
]
|
||||
},
|
||||
set (value) {
|
||||
if (this.filter.min !== value[0]) {
|
||||
this.filter.min = value[0]
|
||||
this.$nextTick(() => {
|
||||
this.$refs.inputMin.$el.focus()
|
||||
if (props.filter.min !== value[0]) {
|
||||
props.filter.min = value[0]
|
||||
nextTick(() => {
|
||||
(inputMin.value!.$el as HTMLInputElement).focus()
|
||||
})
|
||||
} else if (this.filter.max !== value[1]) {
|
||||
this.filter.max = value[1]
|
||||
this.$nextTick(() => {
|
||||
this.$refs.inputMax.$el.focus()
|
||||
} else if (props.filter.max !== value[1]) {
|
||||
props.filter.max = value[1]
|
||||
nextTick(() => {
|
||||
(inputMax.value!.$el as HTMLInputElement).focus()
|
||||
})
|
||||
}
|
||||
this.filter.disabled = false
|
||||
props.filter.disabled = false
|
||||
}
|
||||
},
|
||||
fontSize () {
|
||||
return Config.store.fontSize
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
inputFocus (e, type) {
|
||||
if (e.target.value === '') {
|
||||
})
|
||||
|
||||
function inputFocus (e: FocusEvent, type: 'min' | 'max') {
|
||||
const target = e.target as HTMLInputElement
|
||||
if (target.value === '') {
|
||||
if (type === 'max') {
|
||||
this.filter.max = this.filter.defaultMax
|
||||
props.filter.max = props.filter.defaultMax
|
||||
} else if (type === 'min') {
|
||||
this.filter.min = this.filter.defaultMin
|
||||
props.filter.min = props.filter.defaultMin
|
||||
}
|
||||
this.$nextTick(() => {
|
||||
e.target.select()
|
||||
nextTick(() => {
|
||||
target.select()
|
||||
})
|
||||
} else {
|
||||
e.target.select()
|
||||
target.select()
|
||||
}
|
||||
this.filter.disabled = false
|
||||
},
|
||||
toggleFilter (e) {
|
||||
props.filter.disabled = false
|
||||
}
|
||||
|
||||
function toggleFilter (e: MouseEvent) {
|
||||
if (e.detail === 0) {
|
||||
this.$emit('submit')
|
||||
ctx.emit('submit')
|
||||
} else {
|
||||
this.filter.disabled = !this.filter.disabled
|
||||
props.filter.disabled = !props.filter.disabled
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
showMinmaxInput,
|
||||
showTypeTags,
|
||||
showQ20Notice,
|
||||
inputMin,
|
||||
inputMax,
|
||||
sliderValue,
|
||||
fontSize: computed(() => Config.store.fontSize),
|
||||
inputFocus
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="postcss">
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<template>
|
||||
<ui-popper trigger="clickToToggle" boundaries-selector="#price-window" tag-name="div">
|
||||
<template slot="reference">
|
||||
<ui-popover trigger="click" boundary="#price-window">
|
||||
<template #target>
|
||||
<button class="bg-gray-700 px-2 opacity-25" :class="{ 'rounded-l': option === 'low', 'rounded-r': option === 'high' }"
|
||||
>{{ option }}</button>
|
||||
</template>
|
||||
<div class="popper">
|
||||
<form @submit.prevent="submit" class="w-64 text-left p-2">
|
||||
<template #content>
|
||||
<form @submit.prevent="submit" class="w-64 p-2">
|
||||
<div>{{ text }}</div>
|
||||
<textarea v-if="option !== 'fair'"
|
||||
v-model="feedbackText"
|
||||
@@ -13,52 +13,57 @@
|
||||
rows="5" class="w-full bg-gray-700 text-gray-100 p-1"></textarea>
|
||||
<button class="btn" type="submit">Send feedback</button>
|
||||
</form>
|
||||
</div>
|
||||
</ui-popper>
|
||||
</template>
|
||||
</ui-popover>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType, ref } from 'vue'
|
||||
import { ParsedItem } from '@/parser'
|
||||
import { sendFeedback } from './poeprices'
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
emits: ['sent'],
|
||||
props: {
|
||||
option: {
|
||||
type: String,
|
||||
type: String as PropType<'fair' | 'low' | 'high'>,
|
||||
required: true
|
||||
},
|
||||
prediction: {
|
||||
type: Object,
|
||||
type: Object as PropType<{ min: number, max: number, currency: 'chaos' | 'exalt' }>,
|
||||
required: true
|
||||
},
|
||||
item: {
|
||||
type: Object,
|
||||
type: Object as PropType<ParsedItem>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
feedbackText: ''
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
text () {
|
||||
if (this.option === 'low') {
|
||||
setup (props, ctx) {
|
||||
const feedbackText = ref('')
|
||||
|
||||
const text = computed(() => {
|
||||
if (props.option === 'low') {
|
||||
return 'Predicted price is too low.'
|
||||
} else if (this.option === 'high') {
|
||||
} else if (props.option === 'high') {
|
||||
return 'Predicted price is too high.'
|
||||
} else {
|
||||
return 'Predicted price is fair.'
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submit () {
|
||||
this.$emit('sent')
|
||||
})
|
||||
|
||||
function submit () {
|
||||
ctx.emit('sent')
|
||||
sendFeedback({
|
||||
text: this.feedbackText,
|
||||
option: this.option
|
||||
}, this.prediction, this.item)
|
||||
text: feedbackText.value,
|
||||
option: props.option
|
||||
}, props.prediction, props.item)
|
||||
}
|
||||
|
||||
return {
|
||||
feedbackText,
|
||||
text,
|
||||
submit
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -56,47 +56,51 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { requestPoeprices } from './poeprices'
|
||||
import FeedbackOption from './FeedbackOption'
|
||||
import ItemQuickPrice from '@/web/ui/ItemQuickPrice'
|
||||
<script lang="ts">
|
||||
import { defineComponent, watch, ref, PropType } from 'vue'
|
||||
import { RareItemPrice, requestPoeprices } from './poeprices'
|
||||
import FeedbackOption from './FeedbackOption.vue'
|
||||
import ItemQuickPrice from '@/web/ui/ItemQuickPrice.vue'
|
||||
import { ParsedItem } from '@/parser'
|
||||
|
||||
export default {
|
||||
export default defineComponent({
|
||||
name: 'PricePrediction',
|
||||
components: { FeedbackOption, ItemQuickPrice },
|
||||
props: {
|
||||
item: {
|
||||
type: Object,
|
||||
type: Object as PropType<ParsedItem>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
price: null,
|
||||
error: null,
|
||||
loading: false,
|
||||
showContrib: false,
|
||||
feedbackSent: false
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
item: {
|
||||
immediate: true,
|
||||
async handler (item) {
|
||||
try {
|
||||
this.loading = true
|
||||
this.error = null
|
||||
this.price = null
|
||||
this.showContrib = false
|
||||
this.feedbackSent = false
|
||||
this.price = await requestPoeprices(this.item)
|
||||
} catch (err) {
|
||||
this.error = err.message
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
setup (props) {
|
||||
const price = ref<RareItemPrice | null>(null)
|
||||
const error = ref<string | null>(null)
|
||||
const loading = ref(false)
|
||||
const showContrib = ref(false)
|
||||
const feedbackSent = ref(false)
|
||||
|
||||
watch(props.item, async (item) => {
|
||||
try {
|
||||
loading.value = true
|
||||
error.value = null
|
||||
price.value = null
|
||||
showContrib.value = false
|
||||
feedbackSent.value = false
|
||||
price.value = await requestPoeprices(props.item)
|
||||
} catch (err) {
|
||||
error.value = err.message
|
||||
} finally {
|
||||
loading.value = false
|
||||
}
|
||||
}, { immediate: true })
|
||||
|
||||
return {
|
||||
price,
|
||||
error,
|
||||
loading,
|
||||
showContrib,
|
||||
feedbackSent
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
@@ -14,7 +14,7 @@ interface PoepricesApiResponse { /* eslint-disable camelcase */
|
||||
pred_explanation: Array<[string, number]>
|
||||
}
|
||||
|
||||
interface RareItemPrice {
|
||||
export interface RareItemPrice {
|
||||
max: number
|
||||
min: number
|
||||
confidence: number
|
||||
|
||||
@@ -86,88 +86,104 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, inject, ref, computed, watch } from 'vue'
|
||||
import { DateTime } from 'luxon'
|
||||
import { MainProcess } from '@/ipc/main-process-bindings'
|
||||
import { execBulkSearch } from './pathofexile-bulk'
|
||||
import { BulkSearch, execBulkSearch } from './pathofexile-bulk'
|
||||
import { tradeTag, getTradeEndpoint } from './common'
|
||||
import { TRADE_TAG_BY_NAME } from '@/assets/data'
|
||||
import { Leagues } from '../Leagues'
|
||||
import { Config } from '@/web/Config'
|
||||
import { ItemFilters } from '../filters/interfaces'
|
||||
import { ParsedItem } from '@/parser'
|
||||
import { PriceCheckWidget, WidgetManager } from '@/web/overlay/interfaces'
|
||||
|
||||
export default {
|
||||
function useBulkApi () {
|
||||
let searchId = 0
|
||||
const error = ref<string | null>(null)
|
||||
const result = ref<BulkSearch | null>(null)
|
||||
|
||||
async function search (item: ParsedItem, filters: ItemFilters) {
|
||||
try {
|
||||
searchId += 1
|
||||
error.value = null
|
||||
result.value = null
|
||||
|
||||
const _searchId = searchId
|
||||
const _result = await execBulkSearch(item, filters)
|
||||
if (_searchId === searchId) {
|
||||
result.value = _result
|
||||
}
|
||||
} catch (err) {
|
||||
error.value = err.message
|
||||
}
|
||||
}
|
||||
|
||||
return { error, result, search }
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
filters: {
|
||||
type: Object,
|
||||
type: Object as PropType<ItemFilters>,
|
||||
required: true
|
||||
},
|
||||
item: {
|
||||
type: Object,
|
||||
type: Object as PropType<ParsedItem>,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
inject: ['wm', 'widget'],
|
||||
data () {
|
||||
return {
|
||||
searchId: 0,
|
||||
loading: false,
|
||||
error: null,
|
||||
result: null,
|
||||
selectedCurr: 'chaos'
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
selectedResults () {
|
||||
const arr = Array(20)
|
||||
if (!this.result) return arr
|
||||
setup (props) {
|
||||
const wm = inject<WidgetManager>('wm')!
|
||||
const widget = inject<{ config: PriceCheckWidget }>('widget')!
|
||||
const { error, result, search } = useBulkApi()
|
||||
|
||||
const listed = this.result[this.selectedCurr].listed
|
||||
const selectedCurr = ref<'chaos' | 'exa'>('chaos')
|
||||
|
||||
const selectedResults = computed(() => {
|
||||
const arr = Array(20)
|
||||
if (!result.value) return arr
|
||||
|
||||
const listed = result.value[selectedCurr.value].listed
|
||||
arr.splice(0, listed.length, ...listed)
|
||||
return arr
|
||||
},
|
||||
config () {
|
||||
return Config.store
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async execSearch () {
|
||||
try {
|
||||
this.searchId += 1
|
||||
const searchId = this.searchId
|
||||
})
|
||||
|
||||
this.loading = true
|
||||
this.error = null
|
||||
this.result = null
|
||||
|
||||
const result = await execBulkSearch(this.item, this.filters)
|
||||
if (this.searchId !== searchId) return
|
||||
this.result = result
|
||||
this.selectedCurr = (result.exa.total > result.chaos.total) ? 'exa' : 'chaos'
|
||||
watch(result, () => {
|
||||
if (result.value) {
|
||||
const { exa, chaos } = result.value
|
||||
selectedCurr.value = (exa.total > chaos.total) ? 'exa' : 'chaos'
|
||||
// override, because at league start many players set wrong price, and this breaks auto-detection
|
||||
if (tradeTag(this.item) === TRADE_TAG_BY_NAME.get('Chaos Orb')) {
|
||||
this.selectedCurr = 'exa'
|
||||
} else if (tradeTag(this.item) === TRADE_TAG_BY_NAME.get('Exalted Orb')) {
|
||||
this.selectedCurr = 'chaos'
|
||||
if (tradeTag(props.item) === TRADE_TAG_BY_NAME.get('Chaos Orb')) {
|
||||
selectedCurr.value = 'exa'
|
||||
} else if (tradeTag(props.item) === TRADE_TAG_BY_NAME.get('Exalted Orb')) {
|
||||
selectedCurr.value = 'chaos'
|
||||
}
|
||||
} catch (err) {
|
||||
this.error = err.message
|
||||
} finally {
|
||||
this.loading = false
|
||||
}
|
||||
},
|
||||
getRelativeTime (iso) {
|
||||
return DateTime.fromISO(iso).toRelative({ style: 'short' })
|
||||
},
|
||||
openTradeLink (isExternal) {
|
||||
const link = `https://${getTradeEndpoint()}/trade/exchange/${Leagues.selected}/${this.result[this.selectedCurr].queryId}`
|
||||
if (isExternal) {
|
||||
MainProcess.openSystemBrowser(link)
|
||||
} else {
|
||||
this.wm.showBrowser(this.widget.config.wmId, link)
|
||||
})
|
||||
|
||||
return {
|
||||
error,
|
||||
result,
|
||||
selectedResults,
|
||||
selectedCurr,
|
||||
execSearch: () => { search(props.item, props.filters) },
|
||||
config: computed(() => Config.store),
|
||||
openTradeLink (isExternal: boolean) {
|
||||
const link = `https://${getTradeEndpoint()}/trade/exchange/${Leagues.selected}/${result.value![selectedCurr.value].queryId}`
|
||||
if (isExternal) {
|
||||
MainProcess.openSystemBrowser(link)
|
||||
} else {
|
||||
wm.showBrowser(widget.config.wmId, link)
|
||||
}
|
||||
},
|
||||
getRelativeTime (iso: string) {
|
||||
return DateTime.fromISO(iso).toRelative({ style: 'short' })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
<style lang="postcss">
|
||||
|
||||
@@ -91,7 +91,7 @@ async function requestResults (queryId: string, resultIds: string[]): Promise<Pr
|
||||
})
|
||||
}
|
||||
|
||||
interface BulkSearch {
|
||||
export interface BulkSearch {
|
||||
exa: {
|
||||
queryId: string
|
||||
total: number
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div
|
||||
ref="el"
|
||||
style="position: relative; overflow: auto;"
|
||||
style="position: relative; overflow-y: auto;"
|
||||
@scroll.passive="handleScroll"
|
||||
>
|
||||
<div :style="{ height: `${fullHeight}px` }">
|
||||
|
||||
Reference in New Issue
Block a user