138 lines
3.5 KiB
Vue
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>
|