优化:对多市场显示的优化

This commit is contained in:
ivan 2026-02-14 12:25:19 +08:00
parent 0aa04471f1
commit f15e40d74c

View File

@ -101,8 +101,8 @@
</v-card> </v-card>
</v-col> </v-col>
<!-- 右侧购买组件点击 Yes/No 时传入当前市场数据 --> <!-- 右侧购买组件桌面端显示移动端用底部栏+弹窗 -->
<v-col cols="12" class="trade-col"> <v-col v-if="!isMobile" cols="12" class="trade-col">
<div v-if="markets.length > 0" class="trade-sidebar"> <div v-if="markets.length > 0" class="trade-sidebar">
<TradeComponent <TradeComponent
:market="tradeMarketPayload" :market="tradeMarketPayload"
@ -112,6 +112,45 @@
</div> </div>
</v-col> </v-col>
</v-row> </v-row>
<!-- 移动端 market 时显示固定底部 Buy Yes/No market 时仅通过列表点击弹出 -->
<template v-if="isMobile && markets.length === 1">
<div class="mobile-trade-bar-spacer" aria-hidden="true"></div>
<div class="mobile-trade-bar">
<v-btn
class="mobile-bar-btn mobile-bar-yes"
variant="flat"
color="success"
rounded="pill"
block
@click="openSheetWithOption('yes')"
>
Buy Yes {{ barMarket ? yesPrice(barMarket) : '0¢' }}
</v-btn>
<v-btn
class="mobile-bar-btn mobile-bar-no"
variant="flat"
color="error"
rounded="pill"
block
@click="openSheetWithOption('no')"
>
Buy No {{ barMarket ? noPrice(barMarket) : '0¢' }}
</v-btn>
</div>
</template>
<!-- 移动端交易弹窗 market 与多 market 均需 market 时通过列表 Buy Yes/No 打开 -->
<template v-if="isMobile && markets.length > 0">
<v-bottom-sheet v-model="tradeSheetOpen" content-class="event-markets-trade-sheet">
<TradeComponent
:key="`trade-${selectedMarketIndex}-${tradeInitialOption}`"
:market="tradeMarketPayload"
:initial-option="tradeInitialOption"
embedded-in-sheet
@submit="onTradeSubmit"
/>
</v-bottom-sheet>
</template>
</template> </template>
</v-container> </v-container>
</template> </template>
@ -120,6 +159,7 @@
defineOptions({ name: 'EventMarkets' }) defineOptions({ name: 'EventMarkets' })
import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue' import { ref, computed, onMounted, onUnmounted, watch, nextTick } from 'vue'
import { useRoute, useRouter } from 'vue-router' import { useRoute, useRouter } from 'vue-router'
import { useDisplay } from 'vuetify'
import * as echarts from 'echarts' import * as echarts from 'echarts'
import type { ECharts } from 'echarts' import type { ECharts } from 'echarts'
import TradeComponent from '../components/TradeComponent.vue' import TradeComponent from '../components/TradeComponent.vue'
@ -136,6 +176,8 @@ import { useUserStore } from '../stores/user'
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
const userStore = useUserStore() const userStore = useUserStore()
const { mobile } = useDisplay()
const isMobile = computed(() => mobile.value)
const eventDetail = ref<PmEventListItem | null>(null) const eventDetail = ref<PmEventListItem | null>(null)
const detailLoading = ref(false) const detailLoading = ref(false)
@ -144,11 +186,15 @@ const detailError = ref<string | null>(null)
const selectedMarketIndex = ref(0) const selectedMarketIndex = ref(0)
/** 点击 Buy Yes/No 时传给购买组件的初始方向,不点击则为 undefined 使用组件默认 */ /** 点击 Buy Yes/No 时传给购买组件的初始方向,不点击则为 undefined 使用组件默认 */
const tradeInitialOption = ref<'yes' | 'no' | undefined>(undefined) const tradeInitialOption = ref<'yes' | 'no' | undefined>(undefined)
/** 移动端交易弹窗开关 */
const tradeSheetOpen = ref(false)
const markets = computed(() => { const markets = computed(() => {
const list = eventDetail.value?.markets ?? [] const list = eventDetail.value?.markets ?? []
return list.length > 0 ? list : [] return list.length > 0 ? list : []
}) })
const selectedMarket = computed(() => markets.value[selectedMarketIndex.value] ?? null) const selectedMarket = computed(() => markets.value[selectedMarketIndex.value] ?? null)
/** 移动端底部栏显示的市场(选中项或首个),仅在 markets.length > 0 时使用 */
const barMarket = computed(() => selectedMarket.value ?? markets.value[0])
/** 传给购买组件的市场数据(当前选中的市场) */ /** 传给购买组件的市场数据(当前选中的市场) */
const tradeMarketPayload = computed(() => { const tradeMarketPayload = computed(() => {
const m = selectedMarket.value const m = selectedMarket.value
@ -436,10 +482,19 @@ function selectMarket(index: number) {
selectedMarketIndex.value = index selectedMarketIndex.value = index
} }
/** 点击 Buy Yes/No选中该市场并把数据和方向传给购买组件,不跳转 */ /** 点击 Buy Yes/No选中该市场并把数据和方向传给购买组件;移动端直接弹出交易弹窗 */
function openTrade(market: PmEventMarketItem, index: number, side: 'yes' | 'no') { function openTrade(market: PmEventMarketItem, index: number, side: 'yes' | 'no') {
selectedMarketIndex.value = index selectedMarketIndex.value = index
tradeInitialOption.value = side tradeInitialOption.value = side
if (isMobile.value) {
tradeSheetOpen.value = true
}
}
/** 移动端底部栏:点击 Buy Yes/No 时打开交易弹窗 */
function openSheetWithOption(side: 'yes' | 'no') {
tradeInitialOption.value = side
tradeSheetOpen.value = true
} }
function onTradeSubmit(payload: { function onTradeSubmit(payload: {
@ -860,4 +915,51 @@ watch(
text-transform: none; text-transform: none;
font-weight: 500; font-weight: 500;
} }
/* 移动端底部交易栏 */
.mobile-trade-bar-spacer {
height: 72px;
}
.mobile-trade-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
z-index: 100;
display: flex;
align-items: stretch;
gap: 8px;
width: 100%;
padding: 12px 16px;
padding-bottom: max(12px, env(safe-area-inset-bottom));
background: #fff;
border-top: 1px solid #eee;
}
.mobile-bar-btn {
border: none;
border-radius: 9999px;
font-size: 15px;
font-weight: 600;
cursor: pointer;
flex-shrink: 0;
text-transform: none;
}
.mobile-bar-yes {
flex: 1;
min-width: 0;
background: #16a34a !important;
color: #fff !important;
padding: 14px 16px;
}
.mobile-bar-no {
flex: 1;
min-width: 0;
background: #dc2626 !important;
color: #fff !important;
padding: 14px 16px;
}
</style> </style>