138 lines
3.5 KiB
Vue

<template>
<AppLayout>
<template #header>
<AppHeader
v-if="quote"
:quote="quote"
:ws-status="wsStatus"
:ws-in-session="wsInSession"
/>
</template>
<section class="quote-section">
<QuoteStats v-if="quote" :quote="quote" />
<div class="quote-grid">
<ChartPanel
v-if="quote"
:quote="quote"
:kline-loading="klineLoading"
:load-kline="loadKline"
/>
<aside class="side">
<OrderBook v-if="quote" :quote="quote" />
<TradeTape v-if="quote" :quote="quote" />
<LargeOrderAnalysis v-if="quote" :quote="quote" />
</aside>
</div>
</section>
<QuickAccessFab @open-news="newsOpen = true" @open-position="positionOpen = true" />
<el-dialog
v-model="newsOpen"
title="相关新闻"
width="720px"
top="8vh"
class="panel-dialog"
destroy-on-close
>
<NewsList
v-if="news"
:items="news"
:loading="newsLoading"
:error="newsError"
@refresh="refreshNews"
/>
</el-dialog>
<el-dialog
v-model="positionOpen"
title="机构持仓"
width="80%"
top="5vh"
class="panel-dialog position-dialog"
destroy-on-close
>
<PositionPanel v-if="positions" :data="positions" />
</el-dialog>
<template #ai>
<AiAdviceDrawer
v-if="advice"
:data="advice"
:loading="adviceLoading"
@refresh="refreshAdvice"
/>
</template>
</AppLayout>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import { storeToRefs } from 'pinia'
import AppLayout from './layout/AppLayout.vue'
import AppHeader from './components/header/AppHeader.vue'
import QuoteStats from './components/quote/QuoteStats.vue'
import ChartPanel from './components/quote/ChartPanel.vue'
import OrderBook from './components/quote/OrderBook.vue'
import TradeTape from './components/quote/TradeTape.vue'
import LargeOrderAnalysis from './components/quote/LargeOrderAnalysis.vue'
import QuickAccessFab from './components/common/QuickAccessFab.vue'
import NewsList from './components/news/NewsList.vue'
import PositionPanel from './components/position/PositionPanel.vue'
import AiAdviceDrawer from './components/ai/AiAdviceDrawer.vue'
import { useQuote } from './composables/useQuote'
import { useNews } from './composables/useNews'
import { usePositions } from './composables/usePositions'
import { useAiAdvice } from './composables/useAiAdvice'
import { useQuotaStore } from './stores/quota'
const { data: quote, klineLoading, loadKline } = useQuote()
const { wsStatus, wsInSession } = storeToRefs(useQuotaStore())
const { data: news, loading: newsLoading, error: newsError, refresh: refreshNews } = useNews()
const { data: positions } = usePositions()
const { data: advice, loading: adviceLoading, refresh: refreshAdvice } = useAiAdvice()
const newsOpen = ref(false)
const positionOpen = ref(false)
</script>
<style scoped>
.quote-grid {
display: grid;
grid-template-columns: minmax(0, 1fr) 280px;
gap: 12px;
align-items: start;
}
@media (max-width: 960px) {
.quote-grid {
grid-template-columns: 1fr;
}
}
</style>
<style>
.panel-dialog .el-dialog__body {
max-height: min(72vh, 780px);
overflow: auto;
padding-top: 8px;
}
.panel-dialog .news-list,
.panel-dialog .position-panel {
margin-top: 0;
border: none;
box-shadow: none;
padding: 0;
}
.panel-dialog .news-list .head .section-title {
display: none;
}
.position-dialog {
--el-dialog-width: min(1100px, 96vw);
}
</style>